| Index: src/ia32/stub-cache-ia32.cc
|
| diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
|
| index 6fbb0ea8275dace05e9bd45832923fab71593cf4..19990c6eccb8393e62fc781f0a2ef55340e43237 100644
|
| --- a/src/ia32/stub-cache-ia32.cc
|
| +++ b/src/ia32/stub-cache-ia32.cc
|
| @@ -381,10 +381,12 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
|
| return;
|
| }
|
|
|
| - // Note: starting a frame here makes GC aware of pointers pushed below.
|
| + // Save necessary data before invoking an interceptor.
|
| + // Requires a frame to make GC aware of pushed pointers.
|
| __ EnterInternalFrame();
|
|
|
| - if (lookup->type() == CALLBACKS) {
|
| + if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
|
| + // CALLBACKS case needs a receiver to be passed into C++ callback.
|
| __ push(receiver);
|
| }
|
| __ push(holder);
|
| @@ -410,22 +412,25 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
|
| __ bind(&interceptor_failed);
|
| __ pop(name_);
|
| __ pop(holder);
|
| - if (lookup->type() == CALLBACKS) {
|
| + if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
|
| __ pop(receiver);
|
| }
|
|
|
| __ LeaveInternalFrame();
|
|
|
| - if (lookup->type() == FIELD) {
|
| - // We found FIELD property in prototype chain of interceptor's holder.
|
| - // Check that the maps from interceptor's holder to field's holder
|
| - // haven't changed...
|
| + // Check that the maps from interceptor's holder to lookup's holder
|
| + // haven't changed. And load lookup's holder into |holder| register.
|
| + if (interceptor_holder != lookup->holder()) {
|
| holder = stub_compiler->CheckPrototypes(interceptor_holder, holder,
|
| lookup->holder(), scratch1,
|
| scratch2,
|
| name,
|
| miss_label);
|
| - // ... and retrieve a field from field's holder.
|
| + }
|
| +
|
| + if (lookup->type() == FIELD) {
|
| + // We found FIELD property in prototype chain of interceptor's holder.
|
| + // Retrieve a field from field's holder.
|
| stub_compiler->GenerateFastPropertyLoad(masm, eax,
|
| holder, lookup->holder(),
|
| lookup->GetFieldIndex());
|
| @@ -438,23 +443,11 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
|
| ASSERT(callback != NULL);
|
| ASSERT(callback->getter() != NULL);
|
|
|
| - // Prepare for tail call: push receiver to stack after return address.
|
| - Label cleanup;
|
| + // Tail call to runtime.
|
| + // Important invariant in CALLBACKS case: the code above must be
|
| + // structured to never clobber |receiver| register.
|
| __ pop(scratch2); // return address
|
| __ push(receiver);
|
| - __ push(scratch2);
|
| -
|
| - // Check that the maps from interceptor's holder to callback's holder
|
| - // haven't changed.
|
| - holder = stub_compiler->CheckPrototypes(interceptor_holder, holder,
|
| - lookup->holder(), scratch1,
|
| - scratch2,
|
| - name,
|
| - &cleanup);
|
| -
|
| - // Continue tail call preparation: push remaining parameters after
|
| - // return address.
|
| - __ pop(scratch2); // return address
|
| __ push(holder);
|
| __ mov(holder, Immediate(Handle<AccessorInfo>(callback)));
|
| __ push(holder);
|
| @@ -462,17 +455,9 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
|
| __ push(name_);
|
| __ push(scratch2); // restore return address
|
|
|
| - // Tail call to runtime.
|
| ExternalReference ref =
|
| ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
|
| __ TailCallExternalReference(ref, 5, 1);
|
| -
|
| - // Clean up code: we pushed receiver after return address and
|
| - // need to remove it from there.
|
| - __ bind(&cleanup);
|
| - __ pop(scratch1); // return address.
|
| - __ pop(scratch2); // receiver.
|
| - __ push(scratch1);
|
| }
|
| }
|
|
|
| @@ -683,9 +668,9 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
| Label miss_cleanup;
|
| Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
|
| Register holder =
|
| - stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
|
| - scratch1, scratch2, name,
|
| - depth1, miss);
|
| + stub_compiler_->CheckPrototypes(object, receiver,
|
| + interceptor_holder, scratch1,
|
| + scratch2, name, depth1, miss);
|
|
|
| // Invoke an interceptor and if it provides a value,
|
| // branch to |regular_invoke|.
|
| @@ -698,10 +683,16 @@ class CallInterceptorCompiler BASE_EMBEDDED {
|
|
|
| // Check that the maps from interceptor's holder to constant function's
|
| // holder haven't changed and thus we can use cached constant function.
|
| - stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
|
| - lookup->holder(),
|
| - scratch1, scratch2, name,
|
| - depth2, miss);
|
| + if (interceptor_holder != lookup->holder()) {
|
| + stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
|
| + lookup->holder(), scratch1,
|
| + scratch2, name, depth2, miss);
|
| + // CheckPrototypes has a side effect of fetching a 'holder'
|
| + // for API (object which is instanceof for the signature). It's
|
| + // safe to omit it here, as if present, it should be fetched
|
| + // by the previous CheckPrototypes.
|
| + ASSERT((depth2 == kInvalidProtoDepth) || (depth1 != kInvalidProtoDepth));
|
| + }
|
|
|
| // Invoke function.
|
| if (can_do_fast_api_call) {
|
|
|