Index: src/x64/stub-cache-x64.cc |
=================================================================== |
--- src/x64/stub-cache-x64.cc (revision 4738) |
+++ src/x64/stub-cache-x64.cc (working copy) |
@@ -375,189 +375,6 @@ |
} |
-template <class Compiler> |
-static void CompileLoadInterceptor(Compiler* compiler, |
- StubCompiler* stub_compiler, |
- MacroAssembler* masm, |
- JSObject* object, |
- JSObject* holder, |
- String* name, |
- LookupResult* lookup, |
- Register receiver, |
- Register scratch1, |
- Register scratch2, |
- Label* miss) { |
- ASSERT(holder->HasNamedInterceptor()); |
- ASSERT(!holder->GetNamedInterceptor()->getter()->IsUndefined()); |
- |
- // Check that the receiver isn't a smi. |
- __ JumpIfSmi(receiver, miss); |
- |
- // Check that the maps haven't changed. |
- Register reg = |
- stub_compiler->CheckPrototypes(object, receiver, holder, |
- scratch1, scratch2, name, miss); |
- |
- if (lookup->IsProperty() && lookup->IsCacheable()) { |
- compiler->CompileCacheable(masm, |
- stub_compiler, |
- receiver, |
- reg, |
- scratch1, |
- scratch2, |
- holder, |
- lookup, |
- name, |
- miss); |
- } else { |
- compiler->CompileRegular(masm, |
- receiver, |
- reg, |
- scratch2, |
- holder, |
- miss); |
- } |
-} |
- |
- |
-class LoadInterceptorCompiler BASE_EMBEDDED { |
- public: |
- explicit LoadInterceptorCompiler(Register name) : name_(name) {} |
- |
- void CompileCacheable(MacroAssembler* masm, |
- StubCompiler* stub_compiler, |
- Register receiver, |
- Register holder, |
- Register scratch1, |
- Register scratch2, |
- JSObject* interceptor_holder, |
- LookupResult* lookup, |
- String* name, |
- Label* miss_label) { |
- AccessorInfo* callback = NULL; |
- bool optimize = false; |
- // So far the most popular follow ups for interceptor loads are FIELD |
- // and CALLBACKS, so inline only them, other cases may be added |
- // later. |
- if (lookup->type() == FIELD) { |
- optimize = true; |
- } else if (lookup->type() == CALLBACKS) { |
- Object* callback_object = lookup->GetCallbackObject(); |
- if (callback_object->IsAccessorInfo()) { |
- callback = AccessorInfo::cast(callback_object); |
- optimize = callback->getter() != NULL; |
- } |
- } |
- |
- if (!optimize) { |
- CompileRegular(masm, receiver, holder, scratch2, interceptor_holder, |
- miss_label); |
- return; |
- } |
- |
- // Save necessary data before invoking an interceptor. |
- // Requires a frame to make GC aware of pushed pointers. |
- __ EnterInternalFrame(); |
- |
- if (lookup->type() == CALLBACKS && !receiver.is(holder)) { |
- // CALLBACKS case needs a receiver to be passed into C++ callback. |
- __ push(receiver); |
- } |
- __ 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_, |
- 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); |
- __ LeaveInternalFrame(); |
- __ ret(0); |
- |
- __ bind(&interceptor_failed); |
- __ pop(name_); |
- __ pop(holder); |
- if (lookup->type() == CALLBACKS && !receiver.is(holder)) { |
- __ pop(receiver); |
- } |
- |
- __ LeaveInternalFrame(); |
- |
- // Check that the maps from interceptor's holder to lookup's holder |
- // haven't changed. And load lookup's holder into |holder| register. |
- if (interceptor_holder != lookup->holder()) { |
- holder = stub_compiler->CheckPrototypes(interceptor_holder, holder, |
- lookup->holder(), scratch1, |
- scratch2, |
- name, |
- miss_label); |
- } |
- |
- if (lookup->type() == FIELD) { |
- // We found FIELD property in prototype chain of interceptor's holder. |
- // Retrieve a field from field's holder. |
- stub_compiler->GenerateFastPropertyLoad(masm, |
- rax, |
- 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); |
- |
- // Tail call to runtime. |
- // Important invariant in CALLBACKS case: the code above must be |
- // structured to never clobber |receiver| register. |
- __ pop(scratch2); // return address |
- __ push(receiver); |
- __ push(holder); |
- __ Move(holder, Handle<AccessorInfo>(callback)); |
- __ push(holder); |
- __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); |
- __ push(name_); |
- __ push(scratch2); // restore return address |
- |
- ExternalReference ref = |
- ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
- __ TailCallExternalReference(ref, 5, 1); |
- } |
- } |
- |
- |
- void CompileRegular(MacroAssembler* masm, |
- Register receiver, |
- Register holder, |
- Register scratch, |
- JSObject* interceptor_holder, |
- Label* miss_label) { |
- __ pop(scratch); // save old return address |
- PushInterceptorArguments(masm, receiver, holder, name_, interceptor_holder); |
- __ push(scratch); // restore old return address |
- |
- ExternalReference ref = ExternalReference( |
- IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
- __ TailCallExternalReference(ref, 5, 1); |
- } |
- |
- private: |
- Register name_; |
-}; |
- |
- |
// Reserves space for the extra arguments to FastHandleApiCall in the |
// caller's frame. |
// |
@@ -2125,9 +1942,8 @@ |
} |
- |
void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
- JSObject* holder, |
+ JSObject* interceptor_holder, |
LookupResult* lookup, |
Register receiver, |
Register name_reg, |
@@ -2135,18 +1951,128 @@ |
Register scratch2, |
String* name, |
Label* miss) { |
- LoadInterceptorCompiler compiler(name_reg); |
- CompileLoadInterceptor(&compiler, |
- this, |
- masm(), |
- object, |
- holder, |
- name, |
- lookup, |
- receiver, |
- scratch1, |
- scratch2, |
- miss); |
+ ASSERT(interceptor_holder->HasNamedInterceptor()); |
+ ASSERT(!interceptor_holder->GetNamedInterceptor()->getter()->IsUndefined()); |
+ |
+ // Check that the receiver isn't a smi. |
+ __ JumpIfSmi(receiver, miss); |
+ |
+ // So far the most popular follow ups for interceptor loads are FIELD |
+ // and CALLBACKS, so inline only them, other cases may be added |
+ // later. |
+ bool compile_followup_inline = false; |
+ if (lookup->IsProperty() && lookup->IsCacheable()) { |
+ if (lookup->type() == FIELD) { |
+ compile_followup_inline = true; |
+ } else if (lookup->type() == CALLBACKS && |
+ lookup->GetCallbackObject()->IsAccessorInfo() && |
+ AccessorInfo::cast(lookup->GetCallbackObject())->getter() != NULL) { |
+ compile_followup_inline = true; |
+ } |
+ } |
+ |
+ if (compile_followup_inline) { |
+ // Compile the interceptor call, followed by inline code to load the |
+ // property from further up the prototype chain if the call fails. |
+ // Check that the maps haven't changed. |
+ Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
+ scratch1, scratch2, name, miss); |
+ ASSERT(holder_reg.is(receiver) || holder_reg.is(scratch1)); |
+ |
+ // Save necessary data before invoking an interceptor. |
+ // Requires a frame to make GC aware of pushed pointers. |
+ __ EnterInternalFrame(); |
+ |
+ if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
+ // CALLBACKS case needs a receiver to be passed into C++ callback. |
+ __ push(receiver); |
+ } |
+ __ push(holder_reg); |
+ __ push(name_reg); |
+ |
+ // 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_reg, |
+ name_reg, |
+ 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); |
+ __ LeaveInternalFrame(); |
+ __ ret(0); |
+ |
+ __ bind(&interceptor_failed); |
+ __ pop(name_reg); |
+ __ pop(holder_reg); |
+ if (lookup->type() == CALLBACKS && !receiver.is(holder_reg)) { |
+ __ pop(receiver); |
+ } |
+ |
+ __ LeaveInternalFrame(); |
+ |
+ // Check that the maps from interceptor's holder to lookup's holder |
+ // haven't changed. And load lookup's holder into |holder| register. |
+ if (interceptor_holder != lookup->holder()) { |
+ holder_reg = CheckPrototypes(interceptor_holder, |
+ holder_reg, |
+ lookup->holder(), |
+ scratch1, |
+ scratch2, |
+ name, |
+ miss); |
+ } |
+ |
+ if (lookup->type() == FIELD) { |
+ // We found FIELD property in prototype chain of interceptor's holder. |
+ // Retrieve a field from field's holder. |
+ GenerateFastPropertyLoad(masm(), rax, holder_reg, |
+ 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()); |
+ AccessorInfo* callback = AccessorInfo::cast(lookup->GetCallbackObject()); |
+ ASSERT(callback != NULL); |
+ ASSERT(callback->getter() != NULL); |
+ |
+ // Tail call to runtime. |
+ // Important invariant in CALLBACKS case: the code above must be |
+ // structured to never clobber |receiver| register. |
+ __ pop(scratch2); // return address |
+ __ push(receiver); |
+ __ push(holder_reg); |
+ __ Move(holder_reg, Handle<AccessorInfo>(callback)); |
+ __ push(holder_reg); |
+ __ push(FieldOperand(holder_reg, AccessorInfo::kDataOffset)); |
+ __ push(name_reg); |
+ __ push(scratch2); // restore return address |
+ |
+ ExternalReference ref = |
+ ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); |
+ __ TailCallExternalReference(ref, 5, 1); |
+ } |
+ } else { // !compile_followup_inline |
+ // Call the runtime system to load the interceptor. |
+ // Check that the maps haven't changed. |
+ Register holder_reg = CheckPrototypes(object, receiver, interceptor_holder, |
+ scratch1, scratch2, name, miss); |
+ __ pop(scratch2); // save old return address |
+ PushInterceptorArguments(masm(), receiver, holder_reg, |
+ name_reg, interceptor_holder); |
+ __ push(scratch2); // restore old return address |
+ |
+ ExternalReference ref = ExternalReference( |
+ IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); |
+ __ TailCallExternalReference(ref, 5, 1); |
+ } |
} |