Index: src/ic.cc |
=================================================================== |
--- src/ic.cc (revision 4791) |
+++ src/ic.cc (working copy) |
@@ -152,11 +152,13 @@ |
// to prototype check failure. |
int index = map->IndexInCodeCache(name, target); |
if (index >= 0) { |
- // For keyed load/store, the most likely cause of cache failure is |
+ // For keyed load/store/call, the most likely cause of cache failure is |
// that the key has changed. We do not distinguish between |
// prototype and non-prototype failures for keyed access. |
Code::Kind kind = target->kind(); |
- if (kind == Code::KEYED_LOAD_IC || kind == Code::KEYED_STORE_IC) { |
+ if (kind == Code::KEYED_LOAD_IC || |
+ kind == Code::KEYED_STORE_IC || |
+ kind == Code::KEYED_CALL_IC) { |
return MONOMORPHIC; |
} |
@@ -196,9 +198,9 @@ |
Failure* IC::TypeError(const char* type, |
Handle<Object> object, |
- Handle<String> name) { |
+ Handle<Object> key) { |
HandleScope scope; |
- Handle<Object> args[2] = { name, object }; |
+ Handle<Object> args[2] = { key, object }; |
Handle<Object> error = Factory::NewTypeError(type, HandleVector(args, 2)); |
return Top::Throw(*error); |
} |
@@ -224,6 +226,7 @@ |
case Code::STORE_IC: return StoreIC::Clear(address, target); |
case Code::KEYED_STORE_IC: return KeyedStoreIC::Clear(address, target); |
case Code::CALL_IC: return CallIC::Clear(address, target); |
+ case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target); |
case Code::BINARY_OP_IC: return; // Clearing these is tricky and does not |
// make any performance difference. |
default: UNREACHABLE(); |
@@ -231,12 +234,13 @@ |
} |
-void CallIC::Clear(Address address, Code* target) { |
+void CallICBase::Clear(Address address, Code* target) { |
State state = target->ic_state(); |
- InLoopFlag in_loop = target->ic_in_loop(); |
if (state == UNINITIALIZED) return; |
Code* code = |
- StubCache::FindCallInitialize(target->arguments_count(), in_loop); |
+ StubCache::FindCallInitialize(target->arguments_count(), |
+ target->ic_in_loop(), |
+ target->kind()); |
SetTargetAtAddress(address, code); |
} |
@@ -364,7 +368,7 @@ |
} |
-Object* CallIC::TryCallAsFunction(Object* object) { |
+Object* CallICBase::TryCallAsFunction(Object* object) { |
HandleScope scope; |
Handle<Object> target(object); |
Handle<Object> delegate = Execution::GetFunctionDelegate(target); |
@@ -383,7 +387,7 @@ |
return *delegate; |
} |
-void CallIC::ReceiverToObject(Handle<Object> object) { |
+void CallICBase::ReceiverToObject(Handle<Object> object) { |
HandleScope scope; |
Handle<Object> receiver(object); |
@@ -396,9 +400,9 @@ |
} |
-Object* CallIC::LoadFunction(State state, |
- Handle<Object> object, |
- Handle<String> name) { |
+Object* CallICBase::LoadFunction(State state, |
+ Handle<Object> object, |
+ Handle<String> name) { |
// If the object is undefined or null it's illegal to try to get any |
// of its properties; throw a TypeError in that case. |
if (object->IsUndefined() || object->IsNull()) { |
@@ -481,7 +485,7 @@ |
} |
-void CallIC::UpdateCaches(LookupResult* lookup, |
+void CallICBase::UpdateCaches(LookupResult* lookup, |
State state, |
Handle<Object> object, |
Handle<String> name) { |
@@ -497,16 +501,21 @@ |
// This is the first time we execute this inline cache. |
// Set the target to the pre monomorphic stub to delay |
// setting the monomorphic state. |
- code = StubCache::ComputeCallPreMonomorphic(argc, in_loop); |
+ code = StubCache::ComputeCallPreMonomorphic(argc, in_loop, kind_); |
} else if (state == MONOMORPHIC) { |
- code = StubCache::ComputeCallMegamorphic(argc, in_loop); |
+ code = StubCache::ComputeCallMegamorphic(argc, in_loop, kind_); |
} else { |
// Compute monomorphic stub. |
switch (lookup->type()) { |
case FIELD: { |
int index = lookup->GetFieldIndex(); |
- code = StubCache::ComputeCallField(argc, in_loop, *name, *object, |
- lookup->holder(), index); |
+ code = StubCache::ComputeCallField(argc, |
+ in_loop, |
+ kind_, |
+ *name, |
+ *object, |
+ lookup->holder(), |
+ index); |
break; |
} |
case CONSTANT_FUNCTION: { |
@@ -514,8 +523,13 @@ |
// call; used for rewriting to monomorphic state and making sure |
// that the code stub is in the stub cache. |
JSFunction* function = lookup->GetConstantFunction(); |
- code = StubCache::ComputeCallConstant(argc, in_loop, *name, *object, |
- lookup->holder(), function); |
+ code = StubCache::ComputeCallConstant(argc, |
+ in_loop, |
+ kind_, |
+ *name, |
+ *object, |
+ lookup->holder(), |
+ function); |
break; |
} |
case NORMAL: { |
@@ -530,6 +544,7 @@ |
JSFunction* function = JSFunction::cast(cell->value()); |
code = StubCache::ComputeCallGlobal(argc, |
in_loop, |
+ kind_, |
*name, |
*receiver, |
global, |
@@ -541,13 +556,20 @@ |
// property must be found in the receiver for the stub to be |
// applicable. |
if (lookup->holder() != *receiver) return; |
- code = StubCache::ComputeCallNormal(argc, in_loop, *name, *receiver); |
+ code = StubCache::ComputeCallNormal(argc, |
+ in_loop, |
+ kind_, |
+ *name, |
+ *receiver); |
} |
break; |
} |
case INTERCEPTOR: { |
ASSERT(HasInterceptorGetter(lookup->holder())); |
- code = StubCache::ComputeCallInterceptor(argc, *name, *object, |
+ code = StubCache::ComputeCallInterceptor(argc, |
+ kind_, |
+ *name, |
+ *object, |
lookup->holder()); |
break; |
} |
@@ -569,11 +591,44 @@ |
} |
#ifdef DEBUG |
- TraceIC("CallIC", name, state, target(), in_loop ? " (in-loop)" : ""); |
+ TraceIC(kind_ == Code::CALL_IC ? "CallIC" : "KeyedCallIC", |
+ name, state, target(), in_loop ? " (in-loop)" : ""); |
#endif |
} |
+Object* KeyedCallIC::LoadFunction(State state, |
+ Handle<Object> object, |
+ Handle<Object> key) { |
+ if (key->IsSymbol()) { |
+ return CallICBase::LoadFunction(state, object, Handle<String>::cast(key)); |
+ } |
+ |
+ if (object->IsUndefined() || object->IsNull()) { |
+ return TypeError("non_object_property_call", object, key); |
+ } |
+ |
+ if (object->IsString() || object->IsNumber() || object->IsBoolean()) { |
+ ReceiverToObject(object); |
+ } else { |
+ if (FLAG_use_ic && state != MEGAMORPHIC && !object->IsAccessCheckNeeded()) { |
+ int argc = target()->arguments_count(); |
+ InLoopFlag in_loop = target()->ic_in_loop(); |
+ Object* code = StubCache::ComputeCallMegamorphic( |
+ argc, in_loop, Code::KEYED_CALL_IC); |
+ if (!code->IsFailure()) { |
+ set_target(Code::cast(code)); |
+ } |
+ } |
+ } |
+ Object* result = Runtime::GetObjectProperty(object, key); |
+ if (result->IsJSFunction()) return result; |
+ result = TryCallAsFunction(result); |
+ return result->IsJSFunction() ? |
+ result : TypeError("property_not_function", object, key); |
+} |
+ |
+ |
Object* LoadIC::Load(State state, Handle<Object> object, Handle<String> name) { |
// If the object is undefined or null it's illegal to try to get any |
// of its properties; throw a TypeError in that case. |
@@ -1293,7 +1348,22 @@ |
// Static IC stub generators. |
// |
-// Used from ic_<arch>.cc. |
+static Object* CompileFunction(Object* result, |
+ Handle<Object> object, |
+ InLoopFlag in_loop) { |
+ // Compile now with optimization. |
+ HandleScope scope; |
+ Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); |
+ if (in_loop == IN_LOOP) { |
+ CompileLazyInLoop(function, object, CLEAR_EXCEPTION); |
+ } else { |
+ CompileLazy(function, object, CLEAR_EXCEPTION); |
+ } |
+ return *function; |
+} |
+ |
+ |
+// Used from ic-<arch>.cc. |
Object* CallIC_Miss(Arguments args) { |
NoHandleAllocation na; |
ASSERT(args.length() == 2); |
@@ -1312,21 +1382,27 @@ |
if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
return result; |
} |
+ return CompileFunction(result, args.at<Object>(0), ic.target()->ic_in_loop()); |
+} |
- // Compile now with optimization. |
- HandleScope scope; |
- Handle<JSFunction> function = Handle<JSFunction>(JSFunction::cast(result)); |
- InLoopFlag in_loop = ic.target()->ic_in_loop(); |
- if (in_loop == IN_LOOP) { |
- CompileLazyInLoop(function, args.at<Object>(0), CLEAR_EXCEPTION); |
- } else { |
- CompileLazy(function, args.at<Object>(0), CLEAR_EXCEPTION); |
+ |
+// Used from ic-<arch>.cc. |
+Object* KeyedCallIC_Miss(Arguments args) { |
+ NoHandleAllocation na; |
+ ASSERT(args.length() == 2); |
+ KeyedCallIC ic; |
+ IC::State state = IC::StateFrom(ic.target(), args[0], args[1]); |
+ Object* result = |
+ ic.LoadFunction(state, args.at<Object>(0), args.at<Object>(1)); |
+ |
+ if (!result->IsJSFunction() || JSFunction::cast(result)->is_compiled()) { |
+ return result; |
} |
- return *function; |
+ return CompileFunction(result, args.at<Object>(0), ic.target()->ic_in_loop()); |
} |
-// Used from ic_<arch>.cc. |
+// Used from ic-<arch>.cc. |
Object* LoadIC_Miss(Arguments args) { |
NoHandleAllocation na; |
ASSERT(args.length() == 2); |
@@ -1336,7 +1412,7 @@ |
} |
-// Used from ic_<arch>.cc |
+// Used from ic-<arch>.cc |
Object* KeyedLoadIC_Miss(Arguments args) { |
NoHandleAllocation na; |
ASSERT(args.length() == 2); |
@@ -1346,7 +1422,7 @@ |
} |
-// Used from ic_<arch>.cc. |
+// Used from ic-<arch>.cc. |
Object* StoreIC_Miss(Arguments args) { |
NoHandleAllocation na; |
ASSERT(args.length() == 3); |
@@ -1404,7 +1480,7 @@ |
} |
-// Used from ic_<arch>.cc. |
+// Used from ic-<arch>.cc. |
Object* KeyedStoreIC_Miss(Arguments args) { |
NoHandleAllocation na; |
ASSERT(args.length() == 3); |