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:
parent
22e4847fde
commit
f6ec1b4f26
@ -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,
|
||||||
®ular_invoke);
|
®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.
|
// 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(®ular_invoke);
|
__ bind(®ular_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(
|
||||||
|
@ -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, ®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.
|
// 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(®ular_invoke);
|
__ bind(®ular_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(
|
||||||
|
@ -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, ®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.
|
// 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(®ular_invoke);
|
__ bind(®ular_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)),
|
||||||
|
Loading…
Reference in New Issue
Block a user