Index: src/x64/stub-cache-x64.cc |
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc |
index 25361b367f2ff7022100c3afe98cc528eabea8ec..8b095cbbe68bd6d84b131638c057305453152308 100644 |
--- a/src/x64/stub-cache-x64.cc |
+++ b/src/x64/stub-cache-x64.cc |
@@ -430,7 +430,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
Register holder, |
Register scratch1, |
Register scratch2, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
LookupResult* lookup, |
String* name, |
Label* miss_label) { |
@@ -450,7 +450,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; |
} |
@@ -463,12 +464,17 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
__ push(holder); |
__ push(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; |
__ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); |
__ j(equal, &interceptor_failed); |
@@ -485,13 +491,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, |
rax, |
holder, |
@@ -499,37 +509,47 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
lookup->GetFieldIndex()); |
__ ret(0); |
} 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 after return address. |
Label cleanup; |
- __ pop(scratch2); |
+ __ pop(scratch2); // return address |
__ push(receiver); |
__ push(scratch2); |
- 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); |
- __ pop(scratch2); // save old return address |
+ // Continue tail call preparation: push remaining parameters after |
+ // return address. |
+ __ pop(scratch2); // return address |
__ push(holder); |
__ Move(holder, Handle<AccessorInfo>(callback)); |
__ push(holder); |
__ push(FieldOperand(holder, AccessorInfo::kDataOffset)); |
__ push(name_); |
- __ push(scratch2); // restore old return address |
+ __ 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); |
- __ pop(scratch2); |
+ __ pop(scratch1); // return address |
+ __ pop(scratch2); // receiver |
__ push(scratch1); |
} |
} |
@@ -539,10 +559,10 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
Register receiver, |
Register holder, |
Register scratch, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
Label* miss_label) { |
__ pop(scratch); // save old return address |
- PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); |
+ PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); |
__ push(scratch); // restore old return address |
ExternalReference ref = ExternalReference( |
@@ -704,7 +724,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
Register receiver, |
Register scratch1, |
Register scratch2, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
LookupResult* lookup, |
String* name, |
const CallOptimization& optimization, |
@@ -717,10 +737,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); |
@@ -733,24 +756,32 @@ 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, |
+ 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, ®ular_invoke); |
+ LoadWithInterceptor(masm, receiver, holder, interceptor_holder, |
+ ®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. |
+ 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 { |
@@ -758,12 +789,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, scratch1); |
__ jmp(miss_label); |
} |
+ // Invoke a regular function. |
__ bind(®ular_invoke); |
if (can_do_fast_api_call) { |
FreeSpaceForFastApiCall(masm, scratch1); |
@@ -776,10 +809,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); |
@@ -791,7 +824,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
receiver, |
holder, |
name_, |
- holder_obj); |
+ interceptor_holder); |
__ CallExternalReference( |
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), |