 Chromium Code Reviews
 Chromium Code Reviews Issue 172523002:
  Create a function call IC  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
    
  
    Issue 172523002:
  Create a function call IC  (Closed) 
  Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge| Index: src/ic.cc | 
| diff --git a/src/ic.cc b/src/ic.cc | 
| index 2607bb3b68d53405be03865fe60538dea4e8b9e0..8a352f0b85e384549eb078b72c851180ad172ae3 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::CALL_IC) { | 
| 
Toon Verwaest
2014/03/10 13:50:44
Isn't this only relevant for KEYED_STORE_IC?
 
mvstanton
2014/03/20 15:51:53
Done.
 | 
| + modifier = GetTransitionMarkModifier( | 
| + KeyedStoreIC::GetKeyedAccessStoreMode(extra_state)); | 
| + } | 
| PrintF(" (%c->%c%s)", | 
| TransitionMarkFromState(state()), | 
| TransitionMarkFromState(new_state), | 
| @@ -422,6 +424,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(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 +437,11 @@ void IC::Clear(Isolate* isolate, Address address) { | 
| } | 
| +void CallIC::Clear(Address address, Code* target) { | 
| + // TODO(mvstanton): What does it mean to clear this hybrid? | 
| +} | 
| + | 
| + | 
| 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 +1272,37 @@ MaybeObject* StoreIC::Store(Handle<Object> object, | 
| } | 
| +void CallIC::State::Print(StringStream* stream) const { | 
| + stream->Add("(args(%d), ", | 
| + argc_); | 
| + stream->Add("%s, ", | 
| + call_as_method_ ? "METHOD" : "FUNCTION"); | 
| + stream->Add("%s, ", | 
| + monomorphic_ ? "MONOMORPHIC" : "NOT_MONOMORPHIC"); | 
| + stream->Add("%s, ", | 
| + args_match_ ? "args_match" : "args_dont_match"); | 
| + stream->Add("%s)", | 
| + strict_native_ ? "strict_or_native" : "not_strict_or_native"); | 
| +} | 
| + | 
| + | 
| +void CallIC::GenerateNormal(MacroAssembler* masm, int argc, | 
| + bool call_as_method) { | 
| + CallICStub stub(State(argc, call_as_method, false, true, false)); | 
| + stub.GetCode(masm->isolate()); | 
| +} | 
| + | 
| + | 
| +Handle<Code> CallIC::initialize_stub(Isolate* isolate, | 
| + int argc, | 
| + bool call_as_method) { | 
| + CallICStub stub(State(argc, call_as_method, false, true, false)); | 
| + ASSERT(stub.call_as_method() == call_as_method); | 
| + Handle<Code> code = stub.GetCode(isolate); | 
| + return code; | 
| +} | 
| + | 
| + | 
| Handle<Code> StoreIC::initialize_stub(Isolate* isolate, | 
| StrictModeFlag strict_mode) { | 
| ExtraICState extra_state = ComputeExtraICState(strict_mode); | 
| @@ -1725,6 +1764,111 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object, | 
| } | 
| +CallIC::State::State(ExtraICState extra_ic_state) { | 
| + argc_ = ArgBits::decode(extra_ic_state); | 
| + call_as_method_ = CallAsMethodBits::decode(extra_ic_state); | 
| + monomorphic_ = MonomorphicBits::decode(extra_ic_state); | 
| + args_match_ = ArgsMatchBits::decode(extra_ic_state); | 
| + strict_native_ = StrictNativeBits::decode(extra_ic_state); | 
| +} | 
| + | 
| + | 
| +ExtraICState CallIC::State::GetExtraICState() const { | 
| + ExtraICState extra_ic_state = | 
| + ArgBits::encode(argc_) | | 
| + CallAsMethodBits::encode(call_as_method_) | | 
| + MonomorphicBits::encode(monomorphic_) | | 
| + ArgsMatchBits::encode(args_match_) | | 
| + StrictNativeBits::encode(strict_native_); | 
| + return extra_ic_state; | 
| +} | 
| + | 
| + | 
| +void CallIC::PatchMegamorphic(int arg_count, bool call_as_method) { | 
| + CallICStub stub(State(arg_count, call_as_method)); | 
| + 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 (feedback->IsJSFunction()) { | 
| 
Toon Verwaest
2014/03/10 13:50:44
Shouldn't this be feedback->IsJSFunction() && func
 
mvstanton
2014/03/20 15:51:53
I went ahead and just returned without changing an
 | 
| + // We are going megamorphic, only if we were given a real function, | 
| + // otherwise the slow path will be taken. | 
| 
Toon Verwaest
2014/03/10 13:50:44
Weird sentence
 
mvstanton
2014/03/20 15:51:53
Removed.
 | 
| + vector->set(slot->value(), | 
| + *TypeFeedbackInfo::MegamorphicSentinel(isolate())); | 
| + // Do we need to patch? Only if we currently don't have the default stub | 
| 
Toon Verwaest
2014/03/10 13:50:44
We only need to patch if ...
 
mvstanton
2014/03/20 15:51:53
Done.
 | 
| + // in place. | 
| + if (state.monomorphic()) { | 
| + PatchMegamorphic(state.arg_count(), state.call_as_method()); | 
| + } | 
| + } else { | 
| + // If we came here feedback must be the uninitialized sentinel, | 
| + // and we are going monomorphic. | 
| + ASSERT(feedback == *TypeFeedbackInfo::UninitializedSentinel(isolate())); | 
| + | 
| + // Ugh. Do nothing if the function isn't a function, the slow path is taken. | 
| 
Toon Verwaest
2014/03/10 13:50:44
Remove ugh.
 
mvstanton
2014/03/20 15:51:53
Done.
 | 
| + if (!function->IsJSFunction()) { | 
| + // If we don't have a function, just go megamorphic. | 
| + vector->set(slot->value(), | 
| + *TypeFeedbackInfo::MegamorphicSentinel(isolate())); | 
| + if (state.monomorphic()) { | 
| + PatchMegamorphic(state.arg_count(), state.call_as_method()); | 
| + } | 
| + } else { | 
| + vector->set(slot->value(), *function); | 
| + SharedFunctionInfo* shared = Handle<JSFunction>::cast(function)->shared(); | 
| + // Choose the right monomorphic handler | 
| + bool arg_count_match = | 
| + shared->formal_parameter_count() == state.arg_count(); | 
| + bool strict_or_native = shared->language_mode() == STRICT_MODE || | 
| + shared->native(); | 
| + | 
| + bool must_patch = false; | 
| + if (state.monomorphic()) { | 
| + // We are here because we are in snapshot code that went monomorphic but | 
| + // now our cell is cleared because we are running an application. | 
| + // Ideally we can just patch the cell and return. | 
| 
Toon Verwaest
2014/03/10 13:50:44
Are we sure that we can only get here because of s
 
mvstanton
2014/03/20 15:51:53
I went to objects-visiting-inl.h and make sure tha
 | 
| + must_patch = arg_count_match != state.args_match() || | 
| + strict_or_native != state.strict_native(); | 
| + } else { | 
| + // We need to patch only if attributes differ from the monomorphic case | 
| + // built into the generic stub (with arg_count_match = true and | 
| + // !strict_or_native) | 
| + must_patch = !arg_count_match || strict_or_native; | 
| + } | 
| + | 
| + Handle<String> name; | 
| 
Toon Verwaest
2014/03/10 13:50:44
Don't you want to initialize this to something lik
 
mvstanton
2014/03/20 15:51:53
Yes, I could simplify that even more.
 | 
| + Handle<JSFunction> js_function = Handle<JSFunction>::cast(function); | 
| + if (js_function->shared()->name()->IsString()) { | 
| + name = Handle<String>(String::cast(js_function->shared()->name()), | 
| + isolate()); | 
| + } | 
| + | 
| + if (must_patch) { | 
| + CallICStub stub(State(state.arg_count(), | 
| + state.call_as_method(), | 
| + true, | 
| + arg_count_match, | 
| + strict_or_native)); | 
| + set_target(*stub.GetCode(isolate())); | 
| +#ifdef DEBUG | 
| + const char *str = state.monomorphic() | 
| + ? "CallIC (snapshot miss)" | 
| + : "CallIC"; | 
| +#endif | 
| + TRACE_IC(str, name); | 
| + } | 
| + } | 
| + } | 
| +} | 
| + | 
| + | 
| #undef TRACE_IC | 
| @@ -1733,6 +1877,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); |