| 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);
|
|
|