Chromium Code Reviews| Index: src/ic.cc |
| diff --git a/src/ic.cc b/src/ic.cc |
| index a5a7ba2a965939b51328aa524c7c9768601d0118..7c956a28c00a175bf162d48c40000b9c66af0a55 100644 |
| --- a/src/ic.cc |
| +++ b/src/ic.cc |
| @@ -91,9 +91,11 @@ void IC::TraceIC(const char* type, |
| } |
| JavaScriptFrame::PrintTop(isolate(), stdout, false, true); |
| ExtraICState extra_state = new_target->extra_ic_state(); |
| - const char* modifier = |
| - GetTransitionMarkModifier( |
| - KeyedStoreIC::GetKeyedAccessStoreMode(extra_state)); |
| + const char* modifier = ""; |
| + if (new_target->kind() == Code::KEYED_STORE_IC) { |
| + modifier = GetTransitionMarkModifier( |
| + KeyedStoreIC::GetKeyedAccessStoreMode(extra_state)); |
| + } |
| PrintF(" (%c->%c%s)", |
| TransitionMarkFromState(state()), |
| TransitionMarkFromState(new_state), |
| @@ -389,6 +391,10 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) { |
| target->is_inline_cache_stub()) { |
| int delta = ComputeTypeInfoCountDelta(old_target->ic_state(), |
| target->ic_state()); |
| + // Call ICs don't have interesting state changes from this point |
| + // of view. |
| + ASSERT(target->kind() != Code::CALL_IC || delta == 0); |
| + |
| // Not all Code objects have TypeFeedbackInfo. |
| if (host->type_feedback_info()->IsTypeFeedbackInfo() && delta != 0) { |
| TypeFeedbackInfo* info = |
| @@ -422,6 +428,7 @@ void IC::Clear(Isolate* isolate, Address address) { |
| case Code::STORE_IC: return StoreIC::Clear(isolate, address, target); |
| case Code::KEYED_STORE_IC: |
| return KeyedStoreIC::Clear(isolate, address, target); |
| + case Code::CALL_IC: return CallIC::Clear(isolate, address, target); |
| case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target); |
| case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target); |
| case Code::BINARY_OP_IC: |
| @@ -434,6 +441,22 @@ void IC::Clear(Isolate* isolate, Address address) { |
| } |
| +void CallIC::Clear(Isolate* isolate, Address address, Code* target) { |
| + // CallIC just has a generic stub and a monomorphic stub. Only clear if we |
| + // are monomorphic |
| + if (target->ic_state() != ::v8::internal::MONOMORPHIC) return; |
| + |
| + CallIC::State existing_state(target->extra_ic_state()); |
| + |
| + // Install default stub with the immutable parts of existing state. |
| + HandleScope scope(isolate); |
| + CallICStub stub(State(existing_state.arg_count(), |
| + existing_state.call_type())); |
| + Code* code = *stub.GetCode(isolate); |
| + SetTargetAtAddress(address, code); |
| +} |
| + |
| + |
| void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) { |
| if (IsCleared(target)) return; |
| // Make sure to also clear the map used in inline fast cases. If we |
| @@ -1264,6 +1287,48 @@ MaybeObject* StoreIC::Store(Handle<Object> object, |
| } |
| +void CallIC::State::Print(StringStream* stream) const { |
| + stream->Add("(args(%d), ", |
| + argc_); |
| + stream->Add("%s, ", |
| + call_type_ == CallIC::METHOD ? "METHOD" : "FUNCTION"); |
| + stream->Add("%s, ", |
| + stub_type_ == CallIC::MONOMORPHIC ? |
| + "MONOMORPHIC" : "NOT_MONOMORPHIC"); |
| + stream->Add("%s, ", |
| + argument_check_ == CallIC::ARGUMENTS_MATCH ? |
| + "args_match" : "args_dont_match"); |
| + stream->Add("%s)", |
| + function_attributes_ == CallIC::STRICT_OR_NATIVE ? |
| + "strict_or_native" : "not_strict_or_native"); |
| +} |
| + |
| + |
| +void CallIC::GenerateNormal(MacroAssembler* masm, |
| + int argc, |
| + CallType call_type) { |
| + CallICStub stub(State(argc, |
| + call_type, |
| + CallIC::GENERIC, |
| + CallIC::ARGUMENTS_MATCH, |
| + CallIC::NOT_STRICT_OR_NATIVE)); |
| + stub.GetCode(masm->isolate()); |
| +} |
| + |
| + |
| +Handle<Code> CallIC::initialize_stub(Isolate* isolate, |
| + int argc, |
| + CallType call_type) { |
| + CallICStub stub(State(argc, |
| + call_type, |
| + CallIC::GENERIC, |
| + CallIC::ARGUMENTS_MATCH, |
| + CallIC::NOT_STRICT_OR_NATIVE)); |
| + Handle<Code> code = stub.GetCode(isolate); |
| + return code; |
| +} |
| + |
| + |
| Handle<Code> StoreIC::initialize_stub(Isolate* isolate, |
| StrictModeFlag strict_mode) { |
| ExtraICState extra_state = ComputeExtraICState(strict_mode); |
| @@ -1732,6 +1797,93 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object, |
| } |
| +CallIC::State::State(ExtraICState extra_ic_state) { |
| + argc_ = ArgBits::decode(extra_ic_state); |
| + call_type_ = CallTypeBits::decode(extra_ic_state); |
| + stub_type_ = StubTypeBits::decode(extra_ic_state); |
| + argument_check_ = ArgumentCheckBits::decode(extra_ic_state); |
| + function_attributes_ = FunctionAttributeBits::decode(extra_ic_state); |
| +} |
| + |
| + |
| +ExtraICState CallIC::State::GetExtraICState() const { |
| + ExtraICState extra_ic_state = |
| + ArgBits::encode(argc_) | |
| + CallTypeBits::encode(call_type_) | |
| + StubTypeBits::encode(stub_type_) | |
| + ArgumentCheckBits::encode(argument_check_) | |
| + FunctionAttributeBits::encode(function_attributes_); |
| + return extra_ic_state; |
| +} |
| + |
| + |
| +void CallIC::PatchMegamorphic(int arg_count, CallType call_type) { |
| + CallICStub stub(State(arg_count, call_type)); |
| + set_target(*stub.GetCode(isolate())); |
| + TRACE_GENERIC_IC(isolate(), "CallIC", "megamorphic"); |
| +} |
| + |
| + |
| +void CallIC::HandleMiss(Handle<Object> receiver, |
| + Handle<Object> function, |
| + Handle<FixedArray> vector, |
| + Handle<Smi> slot) { |
| + State state(target()->extra_ic_state()); |
| + Object* feedback = vector->get(slot->value()); |
| + |
| + // If we weren't called with a JSFunction, just return. |
| + if (!function->IsJSFunction()) { |
| + return; |
|
Toon Verwaest
2014/03/24 10:25:44
Patch in the generic case, which doesn't record an
mvstanton
2014/03/25 15:34:50
I fixed this to patch to megamorphic in this case,
|
| + } |
| + |
| + if (feedback->IsJSFunction()) { |
| + // We are going megamorphic |
| + ASSERT(*function != feedback); |
| + |
| + vector->set(slot->value(), |
| + *TypeFeedbackInfo::MegamorphicSentinel(isolate())); |
| + |
| + // We only need to patch if we currently don't have the default stub in |
| + // place. |
| + if (state.stub_type() == CallIC::MONOMORPHIC) { |
| + PatchMegamorphic(state.arg_count(), state.call_type()); |
| + } |
| + } else { |
| + // If we came here feedback must be the uninitialized sentinel, |
| + // and we are going monomorphic. |
| + ASSERT(feedback == *TypeFeedbackInfo::UninitializedSentinel(isolate())); |
| + ASSERT(state.stub_type() != CallIC::MONOMORPHIC); |
| + |
| + vector->set(slot->value(), *function); |
| + |
| + // Choose the right monomorphic handler |
| + Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); |
| + SharedFunctionInfo* shared = js_function->shared(); |
| + ArgumentCheck argument_check = |
| + shared->formal_parameter_count() == state.arg_count() |
| + ? CallIC::ARGUMENTS_MATCH |
| + : CallIC::ARGUMENTS_DONT_MATCH; |
| + FunctionAttributes function_attributes = |
| + (shared->language_mode() == STRICT_MODE || shared->native()) |
| + ? CallIC::STRICT_OR_NATIVE |
| + : CallIC::NOT_STRICT_OR_NATIVE; |
| + |
| + bool must_patch = (argument_check == CallIC::ARGUMENTS_DONT_MATCH) || |
| + (function_attributes == CallIC::STRICT_OR_NATIVE); |
| + if (must_patch) { |
| + CallICStub stub(State(state.arg_count(), |
| + state.call_type(), |
| + CallIC::MONOMORPHIC, |
| + argument_check, |
| + function_attributes)); |
| + set_target(*stub.GetCode(isolate())); |
| + TRACE_IC("CallIC", Handle<Object>(js_function->shared()->name(), |
| + isolate())); |
| + } |
| + } |
| +} |
| + |
| + |
| #undef TRACE_IC |
| @@ -1740,6 +1892,19 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object, |
| // |
| // Used from ic-<arch>.cc. |
| +RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) { |
| + HandleScope scope(isolate); |
| + ASSERT(args.length() == 4); |
| + CallIC ic(isolate); |
| + Handle<Object> receiver = args.at<Object>(0); |
| + Handle<Object> function = args.at<Object>(1); |
| + Handle<FixedArray> vector = args.at<FixedArray>(2); |
| + Handle<Smi> slot = args.at<Smi>(3); |
| + ic.HandleMiss(receiver, function, vector, slot); |
| + return *function; |
| +} |
| + |
| + |
| // Used from ic-<arch>.cc. |
| RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) { |
| HandleScope scope(isolate); |