| Index: src/arm/stub-cache-arm.cc
|
| diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
|
| index d82ef21ce02399c44ed960e76af583c0548f4eac..7d03775aad65a8b66bad908de02942b956e83b07 100644
|
| --- a/src/arm/stub-cache-arm.cc
|
| +++ b/src/arm/stub-cache-arm.cc
|
| @@ -461,11 +461,16 @@ 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();
|
|
|
| - __ push(receiver);
|
| - __ Push(holder, name_);
|
| + if (lookup->type() == CALLBACKS && !receiver.is(holder)) {
|
| + // CALLBACKS case needs a receiver to be passed into C++ callback.
|
| + __ Push(receiver, holder, name_);
|
| + } else {
|
| + __ Push(holder, name_);
|
| + }
|
|
|
| // Invoke an interceptor. Note: map checks from receiver to
|
| // interceptor's holder has been compiled before (see a caller
|
| @@ -488,22 +493,25 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
|
| __ bind(&interceptor_failed);
|
| __ pop(name_);
|
| __ pop(holder);
|
| - __ pop(receiver);
|
| + 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...
|
| - holder = stub_compiler->CheckPrototypes(interceptor_holder,
|
| - holder,
|
| - lookup->holder(),
|
| - scratch1,
|
| + // 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,
|
| r0,
|
| holder,
|
| @@ -518,33 +526,25 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
|
| ASSERT(callback != NULL);
|
| ASSERT(callback->getter() != NULL);
|
|
|
| - // Prepare for tail call: push receiver to stack.
|
| - Label cleanup;
|
| - __ push(receiver);
|
| -
|
| - // 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.
|
| - __ push(holder);
|
| - __ Move(holder, Handle<AccessorInfo>(callback));
|
| - __ push(holder);
|
| - __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
|
| - __ Push(scratch1, name_);
|
| -
|
| // Tail call to runtime.
|
| + // Important invariant in CALLBACKS case: the code above must be
|
| + // structured to never clobber |receiver| register.
|
| + __ Move(scratch2, Handle<AccessorInfo>(callback));
|
| + // holder is either receiver or scratch1.
|
| + if (!receiver.is(holder)) {
|
| + ASSERT(scratch1.is(holder));
|
| + __ Push(receiver, holder, scratch2);
|
| + __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
|
| + __ Push(scratch1, name_);
|
| + } else {
|
| + __ push(receiver);
|
| + __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
|
| + __ Push(holder, scratch2, scratch1, name_);
|
| + }
|
| +
|
| ExternalReference ref =
|
| ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
|
| __ TailCallExternalReference(ref, 5, 1);
|
| -
|
| - // Clean up code: we pushed receiver and need to remove it.
|
| - __ bind(&cleanup);
|
| - __ pop(scratch2);
|
| }
|
| }
|
|
|
| @@ -770,9 +770,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|.
|
| @@ -785,9 +785,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) {
|
|
|