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