Chromium Code Reviews| Index: src/ia32/stub-cache-ia32.cc |
| =================================================================== |
| --- src/ia32/stub-cache-ia32.cc (revision 4738) |
| +++ src/ia32/stub-cache-ia32.cc (working copy) |
| @@ -300,188 +300,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. |
| - __ test(receiver, Immediate(kSmiTagMask)); |
| - __ j(zero, miss, not_taken); |
| - |
| - // 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; |
| - __ cmp(eax, Factory::no_interceptor_result_sentinel()); |
| - __ 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, 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); |
| - |
| - // 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); |
| - __ mov(holder, Immediate(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. |
| // |
| @@ -1051,7 +869,7 @@ |
| void StubCompiler::GenerateLoadInterceptor(JSObject* object, |
| - JSObject* holder, |
| + JSObject* interceptor_holder, |
| LookupResult* lookup, |
| Register receiver, |
| Register name_reg, |
| @@ -1059,18 +877,130 @@ |
| 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. |
| + __ test(receiver, Immediate(kSmiTagMask)); |
| + __ j(zero, miss, not_taken); |
| + |
| + // 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; |
| + __ cmp(eax, Factory::no_interceptor_result_sentinel()); |
| + __ 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_reg. |
| + if (interceptor_holder != lookup->holder()) { |
| + holder_reg = CheckPrototypes(interceptor_holder, |
| + holder_reg, |
| + lookup->holder(), |
| + scratch1, |
| + scratch2, |
| + name, |
| + miss); |
| + } |
|
antonm
2010/05/27 13:39:40
ditto for ia32 and x64
|
| + |
| + if (lookup->type() == FIELD) { |
| + // We found FIELD property in prototype chain of interceptor's holder. |
| + // Retrieve a field from field's holder. |
| + GenerateFastPropertyLoad(masm(), eax, 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); |
| + __ mov(holder_reg, Immediate(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); |
| + } |
| } |