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