Index: src/arm/stub-cache-arm.cc |
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc |
index 8001cd842a944d1c99acae742c4932a75c7ec28a..d82ef21ce02399c44ed960e76af583c0548f4eac 100644 |
--- a/src/arm/stub-cache-arm.cc |
+++ b/src/arm/stub-cache-arm.cc |
@@ -436,7 +436,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
Register holder, |
Register scratch1, |
Register scratch2, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
LookupResult* lookup, |
String* name, |
Label* miss_label) { |
@@ -456,7 +456,8 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
} |
if (!optimize) { |
- CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); |
+ CompileRegular(masm, receiver, holder, scratch2, interceptor_holder, |
+ miss_label); |
return; |
} |
@@ -466,14 +467,18 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
__ push(receiver); |
__ Push(holder, name_); |
+ // Invoke an interceptor. Note: map checks from receiver to |
+ // interceptor's holder has been compiled before (see a caller |
+ // of this method.) |
CompileCallLoadPropertyWithInterceptor(masm, |
receiver, |
holder, |
name_, |
- holder_obj); |
+ interceptor_holder); |
+ // Check if interceptor provided a value for property. If it's |
+ // the case, return immediately. |
Label interceptor_failed; |
- // Compare with no_interceptor_result_sentinel. |
__ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); |
__ cmp(r0, scratch1); |
__ b(eq, &interceptor_failed); |
@@ -488,13 +493,17 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
__ LeaveInternalFrame(); |
if (lookup->type() == FIELD) { |
- holder = stub_compiler->CheckPrototypes(holder_obj, |
+ // 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, |
scratch2, |
name, |
miss_label); |
+ // ... and retrieve a field from field's holder. |
stub_compiler->GenerateFastPropertyLoad(masm, |
r0, |
holder, |
@@ -502,30 +511,38 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
lookup->GetFieldIndex()); |
__ Ret(); |
} else { |
+ // We found CALLBACKS property in prototype chain of interceptor's |
+ // holder. |
ASSERT(lookup->type() == CALLBACKS); |
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); |
ASSERT(callback != NULL); |
ASSERT(callback->getter() != NULL); |
+ // Prepare for tail call: push receiver to stack. |
Label cleanup; |
__ push(receiver); |
- holder = stub_compiler->CheckPrototypes(holder_obj, holder, |
+ // 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. |
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); |
} |
@@ -536,9 +553,9 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
Register receiver, |
Register holder, |
Register scratch, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
Label* miss_label) { |
- PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); |
+ PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); |
ExternalReference ref = ExternalReference( |
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
@@ -714,7 +731,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
Register receiver, |
Register scratch1, |
Register scratch2, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
LookupResult* lookup, |
String* name, |
const CallOptimization& optimization, |
@@ -727,10 +744,13 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
bool can_do_fast_api_call = false; |
if (optimization.is_simple_api_call() && |
!lookup->holder()->IsGlobalObject()) { |
- depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); |
+ depth1 = |
+ optimization.GetPrototypeDepthOfExpectedType(object, |
+ interceptor_holder); |
if (depth1 == kInvalidProtoDepth) { |
- depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, |
- lookup->holder()); |
+ depth2 = |
+ optimization.GetPrototypeDepthOfExpectedType(interceptor_holder, |
+ lookup->holder()); |
} |
can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || |
(depth2 != kInvalidProtoDepth); |
@@ -745,23 +765,31 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
ReserveSpaceForFastApiCall(masm, scratch1); |
} |
+ // Check that the maps from receiver to interceptor's holder |
+ // haven't changed and thus we can invoke interceptor. |
Label miss_cleanup; |
Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; |
Register holder = |
- stub_compiler_->CheckPrototypes(object, receiver, holder_obj, 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|. |
Label regular_invoke; |
- LoadWithInterceptor(masm, receiver, holder, holder_obj, scratch2, |
+ LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2, |
®ular_invoke); |
- // Generate code for the failed interceptor case. |
+ // Interceptor returned nothing for this property. Try to use cached |
+ // constant function. |
- // Check the lookup is still valid. |
- stub_compiler_->CheckPrototypes(holder_obj, receiver, |
+ // Check that the maps from interceptor's holder to constant function's |
+ // holder haven't changed and thus we can use cached constant function. |
Søren Thygesen Gjesse
2010/05/25 14:07:29
I am wondering whether this check can be skipped i
antonm
2010/05/25 14:15:10
That's a good point and it indeed could happen. L
|
+ stub_compiler_->CheckPrototypes(interceptor_holder, receiver, |
lookup->holder(), scratch1, |
scratch2, name, depth2, miss); |
+ // Invoke function. |
if (can_do_fast_api_call) { |
GenerateFastApiCall(masm, optimization, arguments_.immediate()); |
} else { |
@@ -769,12 +797,14 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
JUMP_FUNCTION); |
} |
+ // Deferred code for fast API call case---clean preallocated space. |
if (can_do_fast_api_call) { |
__ bind(&miss_cleanup); |
FreeSpaceForFastApiCall(masm); |
__ b(miss_label); |
} |
+ // Invoke a regular function. |
__ bind(®ular_invoke); |
if (can_do_fast_api_call) { |
FreeSpaceForFastApiCall(masm); |
@@ -787,10 +817,10 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
Register scratch1, |
Register scratch2, |
String* name, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
Label* miss_label) { |
Register holder = |
- stub_compiler_->CheckPrototypes(object, receiver, holder_obj, |
+ stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder, |
scratch1, scratch2, name, |
miss_label); |
@@ -803,7 +833,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
receiver, |
holder, |
name_, |
- holder_obj); |
+ interceptor_holder); |
__ CallExternalReference( |
ExternalReference( |