Index: src/ia32/stub-cache-ia32.cc |
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc |
index d7b05cf40bf9965f43194c9f18dcf42ed321a8e2..eb555d705d10a1b5ab48f89e708661bdaa7c11cd 100644 |
--- a/src/ia32/stub-cache-ia32.cc |
+++ b/src/ia32/stub-cache-ia32.cc |
@@ -356,7 +356,7 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
Register holder, |
Register scratch1, |
Register scratch2, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
LookupResult* lookup, |
String* name, |
Label* miss_label) { |
@@ -376,7 +376,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; |
} |
@@ -389,12 +390,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; |
__ cmp(eax, Factory::no_interceptor_result_sentinel()); |
__ j(equal, &interceptor_failed); |
@@ -411,47 +417,61 @@ class LoadInterceptorCompiler BASE_EMBEDDED { |
__ LeaveInternalFrame(); |
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, |
scratch2, |
name, |
miss_label); |
+ // ... and retrieve a field from field's holder. |
stub_compiler->GenerateFastPropertyLoad(masm, eax, |
holder, lookup->holder(), |
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); |
__ mov(holder, Immediate(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); |
} |
} |
@@ -461,10 +481,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( |
@@ -626,7 +646,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
Register receiver, |
Register scratch1, |
Register scratch2, |
- JSObject* holder_obj, |
+ JSObject* interceptor_holder, |
LookupResult* lookup, |
String* name, |
const CallOptimization& optimization, |
@@ -639,10 +659,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); |
@@ -655,24 +678,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 { |
@@ -680,12 +711,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); |
@@ -698,10 +731,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); |
@@ -713,7 +746,7 @@ class CallInterceptorCompiler BASE_EMBEDDED { |
receiver, |
holder, |
name_, |
- holder_obj); |
+ interceptor_holder); |
__ CallExternalReference( |
ExternalReference( |