Comment the code for loading and calling with interceptor.

Review URL: http://codereview.chromium.org/2124021

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4717 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
antonm@chromium.org 2010-05-25 14:59:11 +00:00
parent 22e4847fde
commit f6ec1b4f26
3 changed files with 165 additions and 69 deletions

View File

@ -436,7 +436,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
Register holder, Register holder,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
JSObject* holder_obj, JSObject* interceptor_holder,
LookupResult* lookup, LookupResult* lookup,
String* name, String* name,
Label* miss_label) { Label* miss_label) {
@ -456,7 +456,8 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
} }
if (!optimize) { if (!optimize) {
CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); CompileRegular(masm, receiver, holder, scratch2, interceptor_holder,
miss_label);
return; return;
} }
@ -466,14 +467,18 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
__ push(receiver); __ push(receiver);
__ Push(holder, name_); __ 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, CompileCallLoadPropertyWithInterceptor(masm,
receiver, receiver,
holder, holder,
name_, name_,
holder_obj); interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed; Label interceptor_failed;
// Compare with no_interceptor_result_sentinel.
__ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex); __ LoadRoot(scratch1, Heap::kNoInterceptorResultSentinelRootIndex);
__ cmp(r0, scratch1); __ cmp(r0, scratch1);
__ b(eq, &interceptor_failed); __ b(eq, &interceptor_failed);
@ -488,13 +493,17 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
__ LeaveInternalFrame(); __ LeaveInternalFrame();
if (lookup->type() == FIELD) { 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, holder,
lookup->holder(), lookup->holder(),
scratch1, scratch1,
scratch2, scratch2,
name, name,
miss_label); miss_label);
// ... and retrieve a field from field's holder.
stub_compiler->GenerateFastPropertyLoad(masm, stub_compiler->GenerateFastPropertyLoad(masm,
r0, r0,
holder, holder,
@ -502,30 +511,38 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
lookup->GetFieldIndex()); lookup->GetFieldIndex());
__ Ret(); __ Ret();
} else { } else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS); ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
ASSERT(callback != NULL); ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL); ASSERT(callback->getter() != NULL);
// Prepare for tail call: push receiver to stack.
Label cleanup; Label cleanup;
__ push(receiver); __ 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, lookup->holder(), scratch1,
scratch2, scratch2,
name, name,
&cleanup); &cleanup);
// Continue tail call preparation: push remaining parameters.
__ push(holder); __ push(holder);
__ Move(holder, Handle<AccessorInfo>(callback)); __ Move(holder, Handle<AccessorInfo>(callback));
__ push(holder); __ push(holder);
__ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset)); __ ldr(scratch1, FieldMemOperand(holder, AccessorInfo::kDataOffset));
__ Push(scratch1, name_); __ Push(scratch1, name_);
// Tail call to runtime.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1); __ TailCallExternalReference(ref, 5, 1);
// Clean up code: we pushed receiver and need to remove it.
__ bind(&cleanup); __ bind(&cleanup);
__ pop(scratch2); __ pop(scratch2);
} }
@ -536,9 +553,9 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
Register receiver, Register receiver,
Register holder, Register holder,
Register scratch, Register scratch,
JSObject* holder_obj, JSObject* interceptor_holder,
Label* miss_label) { Label* miss_label) {
PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder);
ExternalReference ref = ExternalReference( ExternalReference ref = ExternalReference(
IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); IC_Utility(IC::kLoadPropertyWithInterceptorForLoad));
@ -714,7 +731,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register receiver, Register receiver,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
JSObject* holder_obj, JSObject* interceptor_holder,
LookupResult* lookup, LookupResult* lookup,
String* name, String* name,
const CallOptimization& optimization, const CallOptimization& optimization,
@ -727,9 +744,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
bool can_do_fast_api_call = false; bool can_do_fast_api_call = false;
if (optimization.is_simple_api_call() && if (optimization.is_simple_api_call() &&
!lookup->holder()->IsGlobalObject()) { !lookup->holder()->IsGlobalObject()) {
depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); depth1 =
optimization.GetPrototypeDepthOfExpectedType(object,
interceptor_holder);
if (depth1 == kInvalidProtoDepth) { if (depth1 == kInvalidProtoDepth) {
depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, depth2 =
optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
lookup->holder()); lookup->holder());
} }
can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
@ -745,23 +765,31 @@ class CallInterceptorCompiler BASE_EMBEDDED {
ReserveSpaceForFastApiCall(masm, scratch1); 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_cleanup;
Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
Register holder = Register holder =
stub_compiler_->CheckPrototypes(object, receiver, holder_obj, scratch1, stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch2, name, depth1, miss); scratch1, scratch2, name,
depth1, miss);
// Invoke an interceptor and if it provides a value,
// branch to |regular_invoke|.
Label regular_invoke; Label regular_invoke;
LoadWithInterceptor(masm, receiver, holder, holder_obj, scratch2, LoadWithInterceptor(masm, receiver, holder, interceptor_holder, scratch2,
&regular_invoke); &regular_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. // Check that the maps from interceptor's holder to constant function's
stub_compiler_->CheckPrototypes(holder_obj, receiver, // holder haven't changed and thus we can use cached constant function.
stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
lookup->holder(), scratch1, lookup->holder(), scratch1,
scratch2, name, depth2, miss); scratch2, name, depth2, miss);
// Invoke function.
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
GenerateFastApiCall(masm, optimization, arguments_.immediate()); GenerateFastApiCall(masm, optimization, arguments_.immediate());
} else { } else {
@ -769,12 +797,14 @@ class CallInterceptorCompiler BASE_EMBEDDED {
JUMP_FUNCTION); JUMP_FUNCTION);
} }
// Deferred code for fast API call case---clean preallocated space.
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
__ bind(&miss_cleanup); __ bind(&miss_cleanup);
FreeSpaceForFastApiCall(masm); FreeSpaceForFastApiCall(masm);
__ b(miss_label); __ b(miss_label);
} }
// Invoke a regular function.
__ bind(&regular_invoke); __ bind(&regular_invoke);
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
FreeSpaceForFastApiCall(masm); FreeSpaceForFastApiCall(masm);
@ -787,10 +817,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
String* name, String* name,
JSObject* holder_obj, JSObject* interceptor_holder,
Label* miss_label) { Label* miss_label) {
Register holder = Register holder =
stub_compiler_->CheckPrototypes(object, receiver, holder_obj, stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, scratch1, scratch2, name,
miss_label); miss_label);
@ -803,7 +833,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
receiver, receiver,
holder, holder,
name_, name_,
holder_obj); interceptor_holder);
__ CallExternalReference( __ CallExternalReference(
ExternalReference( ExternalReference(

View File

@ -356,7 +356,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
Register holder, Register holder,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
JSObject* holder_obj, JSObject* interceptor_holder,
LookupResult* lookup, LookupResult* lookup,
String* name, String* name,
Label* miss_label) { Label* miss_label) {
@ -376,7 +376,8 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
} }
if (!optimize) { if (!optimize) {
CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); CompileRegular(masm, receiver, holder, scratch2, interceptor_holder,
miss_label);
return; return;
} }
@ -389,12 +390,17 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
__ push(holder); __ push(holder);
__ push(name_); __ 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, CompileCallLoadPropertyWithInterceptor(masm,
receiver, receiver,
holder, holder,
name_, name_,
holder_obj); interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed; Label interceptor_failed;
__ cmp(eax, Factory::no_interceptor_result_sentinel()); __ cmp(eax, Factory::no_interceptor_result_sentinel());
__ j(equal, &interceptor_failed); __ j(equal, &interceptor_failed);
@ -411,47 +417,61 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
__ LeaveInternalFrame(); __ LeaveInternalFrame();
if (lookup->type() == FIELD) { if (lookup->type() == FIELD) {
holder = stub_compiler->CheckPrototypes(holder_obj, holder, // 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, lookup->holder(), scratch1,
scratch2, scratch2,
name, name,
miss_label); miss_label);
// ... and retrieve a field from field's holder.
stub_compiler->GenerateFastPropertyLoad(masm, eax, stub_compiler->GenerateFastPropertyLoad(masm, eax,
holder, lookup->holder(), holder, lookup->holder(),
lookup->GetFieldIndex()); lookup->GetFieldIndex());
__ ret(0); __ ret(0);
} else { } else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS); ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
ASSERT(callback != NULL); ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL); ASSERT(callback->getter() != NULL);
// Prepare for tail call: push receiver to stack after return address.
Label cleanup; Label cleanup;
__ pop(scratch2); __ pop(scratch2); // return address
__ push(receiver); __ push(receiver);
__ push(scratch2); __ 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, lookup->holder(), scratch1,
scratch2, scratch2,
name, name,
&cleanup); &cleanup);
__ pop(scratch2); // save old return address // Continue tail call preparation: push remaining parameters after
// return address.
__ pop(scratch2); // return address
__ push(holder); __ push(holder);
__ mov(holder, Immediate(Handle<AccessorInfo>(callback))); __ mov(holder, Immediate(Handle<AccessorInfo>(callback)));
__ push(holder); __ push(holder);
__ push(FieldOperand(holder, AccessorInfo::kDataOffset)); __ push(FieldOperand(holder, AccessorInfo::kDataOffset));
__ push(name_); __ push(name_);
__ push(scratch2); // restore old return address __ push(scratch2); // restore return address
// Tail call to runtime.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1); __ TailCallExternalReference(ref, 5, 1);
// Clean up code: we pushed receiver after return address and
// need to remove it from there.
__ bind(&cleanup); __ bind(&cleanup);
__ pop(scratch1); __ pop(scratch1); // return address.
__ pop(scratch2); __ pop(scratch2); // receiver.
__ push(scratch1); __ push(scratch1);
} }
} }
@ -461,10 +481,10 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
Register receiver, Register receiver,
Register holder, Register holder,
Register scratch, Register scratch,
JSObject* holder_obj, JSObject* interceptor_holder,
Label* miss_label) { Label* miss_label) {
__ pop(scratch); // save old return address __ 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 __ push(scratch); // restore old return address
ExternalReference ref = ExternalReference( ExternalReference ref = ExternalReference(
@ -626,7 +646,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register receiver, Register receiver,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
JSObject* holder_obj, JSObject* interceptor_holder,
LookupResult* lookup, LookupResult* lookup,
String* name, String* name,
const CallOptimization& optimization, const CallOptimization& optimization,
@ -639,9 +659,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
bool can_do_fast_api_call = false; bool can_do_fast_api_call = false;
if (optimization.is_simple_api_call() && if (optimization.is_simple_api_call() &&
!lookup->holder()->IsGlobalObject()) { !lookup->holder()->IsGlobalObject()) {
depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); depth1 =
optimization.GetPrototypeDepthOfExpectedType(object,
interceptor_holder);
if (depth1 == kInvalidProtoDepth) { if (depth1 == kInvalidProtoDepth) {
depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, depth2 =
optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
lookup->holder()); lookup->holder());
} }
can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
@ -655,24 +678,32 @@ class CallInterceptorCompiler BASE_EMBEDDED {
ReserveSpaceForFastApiCall(masm, scratch1); 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_cleanup;
Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
Register holder = Register holder =
stub_compiler_->CheckPrototypes(object, receiver, holder_obj, stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, scratch1, scratch2, name,
depth1, miss); depth1, miss);
// Invoke an interceptor and if it provides a value,
// branch to |regular_invoke|.
Label regular_invoke; Label regular_invoke;
LoadWithInterceptor(masm, receiver, holder, holder_obj, &regular_invoke); LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
&regular_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. // Check that the maps from interceptor's holder to constant function's
stub_compiler_->CheckPrototypes(holder_obj, receiver, // holder haven't changed and thus we can use cached constant function.
stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
lookup->holder(), lookup->holder(),
scratch1, scratch2, name, scratch1, scratch2, name,
depth2, miss); depth2, miss);
// Invoke function.
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
GenerateFastApiCall(masm, optimization, arguments_.immediate()); GenerateFastApiCall(masm, optimization, arguments_.immediate());
} else { } else {
@ -680,12 +711,14 @@ class CallInterceptorCompiler BASE_EMBEDDED {
JUMP_FUNCTION); JUMP_FUNCTION);
} }
// Deferred code for fast API call case---clean preallocated space.
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
__ bind(&miss_cleanup); __ bind(&miss_cleanup);
FreeSpaceForFastApiCall(masm, scratch1); FreeSpaceForFastApiCall(masm, scratch1);
__ jmp(miss_label); __ jmp(miss_label);
} }
// Invoke a regular function.
__ bind(&regular_invoke); __ bind(&regular_invoke);
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
FreeSpaceForFastApiCall(masm, scratch1); FreeSpaceForFastApiCall(masm, scratch1);
@ -698,10 +731,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
String* name, String* name,
JSObject* holder_obj, JSObject* interceptor_holder,
Label* miss_label) { Label* miss_label) {
Register holder = Register holder =
stub_compiler_->CheckPrototypes(object, receiver, holder_obj, stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, scratch1, scratch2, name,
miss_label); miss_label);
@ -713,7 +746,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
receiver, receiver,
holder, holder,
name_, name_,
holder_obj); interceptor_holder);
__ CallExternalReference( __ CallExternalReference(
ExternalReference( ExternalReference(

View File

@ -430,7 +430,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
Register holder, Register holder,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
JSObject* holder_obj, JSObject* interceptor_holder,
LookupResult* lookup, LookupResult* lookup,
String* name, String* name,
Label* miss_label) { Label* miss_label) {
@ -450,7 +450,8 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
} }
if (!optimize) { if (!optimize) {
CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); CompileRegular(masm, receiver, holder, scratch2, interceptor_holder,
miss_label);
return; return;
} }
@ -463,12 +464,17 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
__ push(holder); __ push(holder);
__ push(name_); __ 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, CompileCallLoadPropertyWithInterceptor(masm,
receiver, receiver,
holder, holder,
name_, name_,
holder_obj); interceptor_holder);
// Check if interceptor provided a value for property. If it's
// the case, return immediately.
Label interceptor_failed; Label interceptor_failed;
__ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex); __ CompareRoot(rax, Heap::kNoInterceptorResultSentinelRootIndex);
__ j(equal, &interceptor_failed); __ j(equal, &interceptor_failed);
@ -485,13 +491,17 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
__ LeaveInternalFrame(); __ LeaveInternalFrame();
if (lookup->type() == FIELD) { 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, holder,
lookup->holder(), lookup->holder(),
scratch1, scratch1,
scratch2, scratch2,
name, name,
miss_label); miss_label);
// ... and retrieve a field from field's holder.
stub_compiler->GenerateFastPropertyLoad(masm, stub_compiler->GenerateFastPropertyLoad(masm,
rax, rax,
holder, holder,
@ -499,37 +509,47 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
lookup->GetFieldIndex()); lookup->GetFieldIndex());
__ ret(0); __ ret(0);
} else { } else {
// We found CALLBACKS property in prototype chain of interceptor's
// holder.
ASSERT(lookup->type() == CALLBACKS); ASSERT(lookup->type() == CALLBACKS);
ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); ASSERT(lookup->GetCallbackObject()->IsAccessorInfo());
ASSERT(callback != NULL); ASSERT(callback != NULL);
ASSERT(callback->getter() != NULL); ASSERT(callback->getter() != NULL);
// Prepare for tail call. Push receiver to stack after return address.
Label cleanup; Label cleanup;
__ pop(scratch2); __ pop(scratch2); // return address
__ push(receiver); __ push(receiver);
__ push(scratch2); __ 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, lookup->holder(), scratch1,
scratch2, scratch2,
name, name,
&cleanup); &cleanup);
__ pop(scratch2); // save old return address // Continue tail call preparation: push remaining parameters after
// return address.
__ pop(scratch2); // return address
__ push(holder); __ push(holder);
__ Move(holder, Handle<AccessorInfo>(callback)); __ Move(holder, Handle<AccessorInfo>(callback));
__ push(holder); __ push(holder);
__ push(FieldOperand(holder, AccessorInfo::kDataOffset)); __ push(FieldOperand(holder, AccessorInfo::kDataOffset));
__ push(name_); __ push(name_);
__ push(scratch2); // restore old return address __ push(scratch2); // restore return address
// Tail call to runtime.
ExternalReference ref = ExternalReference ref =
ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); ExternalReference(IC_Utility(IC::kLoadCallbackProperty));
__ TailCallExternalReference(ref, 5, 1); __ TailCallExternalReference(ref, 5, 1);
// Clean up code: we pushed receiver after return address and
// need to remove it from there.
__ bind(&cleanup); __ bind(&cleanup);
__ pop(scratch1); __ pop(scratch1); // return address
__ pop(scratch2); __ pop(scratch2); // receiver
__ push(scratch1); __ push(scratch1);
} }
} }
@ -539,10 +559,10 @@ class LoadInterceptorCompiler BASE_EMBEDDED {
Register receiver, Register receiver,
Register holder, Register holder,
Register scratch, Register scratch,
JSObject* holder_obj, JSObject* interceptor_holder,
Label* miss_label) { Label* miss_label) {
__ pop(scratch); // save old return address __ 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 __ push(scratch); // restore old return address
ExternalReference ref = ExternalReference( ExternalReference ref = ExternalReference(
@ -704,7 +724,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register receiver, Register receiver,
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
JSObject* holder_obj, JSObject* interceptor_holder,
LookupResult* lookup, LookupResult* lookup,
String* name, String* name,
const CallOptimization& optimization, const CallOptimization& optimization,
@ -717,9 +737,12 @@ class CallInterceptorCompiler BASE_EMBEDDED {
bool can_do_fast_api_call = false; bool can_do_fast_api_call = false;
if (optimization.is_simple_api_call() && if (optimization.is_simple_api_call() &&
!lookup->holder()->IsGlobalObject()) { !lookup->holder()->IsGlobalObject()) {
depth1 = optimization.GetPrototypeDepthOfExpectedType(object, holder_obj); depth1 =
optimization.GetPrototypeDepthOfExpectedType(object,
interceptor_holder);
if (depth1 == kInvalidProtoDepth) { if (depth1 == kInvalidProtoDepth) {
depth2 = optimization.GetPrototypeDepthOfExpectedType(holder_obj, depth2 =
optimization.GetPrototypeDepthOfExpectedType(interceptor_holder,
lookup->holder()); lookup->holder());
} }
can_do_fast_api_call = (depth1 != kInvalidProtoDepth) || can_do_fast_api_call = (depth1 != kInvalidProtoDepth) ||
@ -733,24 +756,32 @@ class CallInterceptorCompiler BASE_EMBEDDED {
ReserveSpaceForFastApiCall(masm, scratch1); 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_cleanup;
Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label; Label* miss = can_do_fast_api_call ? &miss_cleanup : miss_label;
Register holder = Register holder =
stub_compiler_->CheckPrototypes(object, receiver, holder_obj, stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, scratch1, scratch2, name,
depth1, miss); depth1, miss);
// Invoke an interceptor and if it provides a value,
// branch to |regular_invoke|.
Label regular_invoke; Label regular_invoke;
LoadWithInterceptor(masm, receiver, holder, holder_obj, &regular_invoke); LoadWithInterceptor(masm, receiver, holder, interceptor_holder,
&regular_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. // Check that the maps from interceptor's holder to constant function's
stub_compiler_->CheckPrototypes(holder_obj, receiver, // holder haven't changed and thus we can use cached constant function.
stub_compiler_->CheckPrototypes(interceptor_holder, receiver,
lookup->holder(), lookup->holder(),
scratch1, scratch2, name, scratch1, scratch2, name,
depth2, miss); depth2, miss);
// Invoke function.
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
GenerateFastApiCall(masm, optimization, arguments_.immediate()); GenerateFastApiCall(masm, optimization, arguments_.immediate());
} else { } else {
@ -758,12 +789,14 @@ class CallInterceptorCompiler BASE_EMBEDDED {
JUMP_FUNCTION); JUMP_FUNCTION);
} }
// Deferred code for fast API call case---clean preallocated space.
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
__ bind(&miss_cleanup); __ bind(&miss_cleanup);
FreeSpaceForFastApiCall(masm, scratch1); FreeSpaceForFastApiCall(masm, scratch1);
__ jmp(miss_label); __ jmp(miss_label);
} }
// Invoke a regular function.
__ bind(&regular_invoke); __ bind(&regular_invoke);
if (can_do_fast_api_call) { if (can_do_fast_api_call) {
FreeSpaceForFastApiCall(masm, scratch1); FreeSpaceForFastApiCall(masm, scratch1);
@ -776,10 +809,10 @@ class CallInterceptorCompiler BASE_EMBEDDED {
Register scratch1, Register scratch1,
Register scratch2, Register scratch2,
String* name, String* name,
JSObject* holder_obj, JSObject* interceptor_holder,
Label* miss_label) { Label* miss_label) {
Register holder = Register holder =
stub_compiler_->CheckPrototypes(object, receiver, holder_obj, stub_compiler_->CheckPrototypes(object, receiver, interceptor_holder,
scratch1, scratch2, name, scratch1, scratch2, name,
miss_label); miss_label);
@ -791,7 +824,7 @@ class CallInterceptorCompiler BASE_EMBEDDED {
receiver, receiver,
holder, holder,
name_, name_,
holder_obj); interceptor_holder);
__ CallExternalReference( __ CallExternalReference(
ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)), ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForCall)),