From 0d2c81584bbd892f8c7de8c6b761730e0281c293 Mon Sep 17 00:00:00 2001 From: "antonm@chromium.org" Date: Wed, 29 Jul 2009 12:34:21 +0000 Subject: [PATCH] Compile precanned answers for the case of failed interceptor for some combinations. Review URL: http://codereview.chromium.org/140069 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@2577 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/arm/stub-cache-arm.cc | 16 +- src/heap.cc | 6 + src/heap.h | 1 + src/ia32/stub-cache-ia32.cc | 425 ++++++++++++++++++++++++++++++------ src/ic.h | 24 +- src/objects-debug.cc | 2 +- src/objects-inl.h | 18 -- src/objects.h | 4 - src/stub-cache.cc | 139 +++++++----- src/stub-cache.h | 20 +- 10 files changed, 482 insertions(+), 173 deletions(-) diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc index 5d206a8f93..393db59e49 100644 --- a/src/arm/stub-cache-arm.cc +++ b/src/arm/stub-cache-arm.cc @@ -483,7 +483,7 @@ void StubCompiler::GenerateLoadCallback(JSObject* object, void StubCompiler::GenerateLoadInterceptor(JSObject* object, JSObject* holder, - Smi* lookup_hint, + LookupResult* lookup, Register receiver, Register name_reg, Register scratch1, @@ -502,8 +502,6 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, __ push(receiver); // receiver __ push(reg); // holder __ push(name_reg); // name - __ mov(scratch1, Operand(lookup_hint)); - __ push(scratch1); InterceptorInfo* interceptor = holder->GetNamedInterceptor(); ASSERT(!Heap::InNewSpace(interceptor)); @@ -514,8 +512,8 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, // Do tail-call to the runtime system. ExternalReference load_ic_property = - ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); - __ TailCallRuntime(load_ic_property, 6); + ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); + __ TailCallRuntime(load_ic_property, 5); } @@ -1059,9 +1057,11 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* object, __ ldr(r0, MemOperand(sp, 0)); + LookupResult lookup; + holder->LocalLookupRealNamedProperty(name, &lookup); GenerateLoadInterceptor(object, holder, - holder->InterceptorPropertyLookupHint(name), + &lookup, r0, r2, r3, @@ -1218,9 +1218,11 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, __ cmp(r2, Operand(Handle(name))); __ b(ne, &miss); + LookupResult lookup; + holder->LocalLookupRealNamedProperty(name, &lookup); GenerateLoadInterceptor(receiver, holder, - Smi::FromInt(JSObject::kLookupInHolder), + &lookup, r0, r2, r3, diff --git a/src/heap.cc b/src/heap.cc index feb01202b6..2f4a2e64fa 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -1411,6 +1411,12 @@ bool Heap::CreateInitialObjects() { if (obj->IsFailure()) return false; set_the_hole_value(obj); + obj = CreateOddball( + oddball_map(), "no_interceptor_result_sentinel", Smi::FromInt(-2)); + if (obj->IsFailure()) return false; + set_no_interceptor_result_sentinel(obj); + + // Allocate the empty string. obj = AllocateRawAsciiString(0, TENURED); if (obj->IsFailure()) return false; diff --git a/src/heap.h b/src/heap.h index 634c21aaf3..69d9ff0013 100644 --- a/src/heap.h +++ b/src/heap.h @@ -110,6 +110,7 @@ namespace internal { V(Map, two_pointer_filler_map, TwoPointerFillerMap) \ V(Object, nan_value, NanValue) \ V(Object, undefined_value, UndefinedValue) \ + V(Object, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \ V(Object, minus_zero_value, MinusZeroValue) \ V(Object, null_value, NullValue) \ V(Object, true_value, TrueValue) \ diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc index a9e2b663a3..a626377e4f 100644 --- a/src/ia32/stub-cache-ia32.cc +++ b/src/ia32/stub-cache-ia32.cc @@ -157,15 +157,10 @@ static void PushInterceptorArguments(MacroAssembler* masm, Register receiver, Register holder, Pushable name, - JSObject* holder_obj, - Smi* lookup_hint) { + JSObject* holder_obj) { __ push(receiver); __ push(holder); __ push(name); - // TODO(367): Maybe don't push lookup_hint for LOOKUP_IN_HOLDER and/or - // LOOKUP_IN_PROTOTYPE, but use a special version of lookup method? - __ push(Immediate(lookup_hint)); - InterceptorInfo* interceptor = holder_obj->GetNamedInterceptor(); __ mov(receiver, Immediate(Handle(interceptor))); __ push(receiver); @@ -294,6 +289,322 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm, } +template +static void CompileCallLoadPropertyWithInterceptor(MacroAssembler* masm, + Register receiver, + Register holder, + Pushable name, + JSObject* holder_obj) { + PushInterceptorArguments(masm, receiver, holder, name, holder_obj); + + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadPropertyWithInterceptorOnly)); + __ mov(eax, Immediate(5)); + __ mov(ebx, Immediate(ref)); + + CEntryStub stub; + __ CallStub(&stub); +} + + +template +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->IsValid() && lookup->IsCacheable()) { + compiler->CompileCacheable(masm, + stub_compiler, + receiver, + reg, + scratch1, + scratch2, + holder, + lookup, + name, + miss); + } else { + compiler->CompileRegular(masm, + receiver, + reg, + scratch2, + holder, + miss); + } +} + + +static void LookupPostInterceptor(JSObject* holder, + String* name, + LookupResult* lookup) { + holder->LocalLookupRealNamedProperty(name, lookup); + if (lookup->IsNotFound()) { + Object* proto = holder->GetPrototype(); + if (proto != Heap::null_value()) { + proto->Lookup(name, lookup); + } + } +} + + +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* holder_obj, + LookupResult* lookup, + String* name, + Label* miss_label) { + AccessorInfo* callback = 0; + 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, holder_obj, miss_label); + return; + } + + // Note: starting a frame here makes GC aware of pointers pushed below. + __ EnterInternalFrame(); + + if (lookup->type() == CALLBACKS) { + __ push(receiver); + } + __ push(holder); + __ push(name_); + + CompileCallLoadPropertyWithInterceptor(masm, + receiver, + holder, + name_, + holder_obj); + + 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) { + __ pop(receiver); + } + + __ LeaveInternalFrame(); + + if (lookup->type() == FIELD) { + holder = stub_compiler->CheckPrototypes(holder_obj, holder, + lookup->holder(), scratch1, + scratch2, + name, + miss_label); + stub_compiler->GenerateFastPropertyLoad(masm, eax, + holder, lookup->holder(), + lookup->GetFieldIndex()); + __ ret(0); + } else { + ASSERT(lookup->type() == CALLBACKS); + ASSERT(lookup->GetCallbackObject()->IsAccessorInfo()); + ASSERT(callback != NULL); + ASSERT(callback->getter() != NULL); + + Label cleanup; + __ pop(scratch2); + __ push(receiver); + __ push(scratch2); + + holder = stub_compiler->CheckPrototypes(holder_obj, holder, + lookup->holder(), scratch1, + scratch2, + name, + &cleanup); + + __ pop(scratch2); // save old return address + __ push(holder); + __ mov(holder, Immediate(Handle(callback))); + __ push(holder); + __ push(FieldOperand(holder, AccessorInfo::kDataOffset)); + __ push(name_); + __ push(scratch2); // restore old return address + + ExternalReference ref = + ExternalReference(IC_Utility(IC::kLoadCallbackProperty)); + __ TailCallRuntime(ref, 5); + + __ bind(&cleanup); + __ pop(scratch1); + __ pop(scratch2); + __ push(scratch1); + } + } + + + void CompileRegular(MacroAssembler* masm, + Register receiver, + Register holder, + Register scratch, + JSObject* holder_obj, + Label* miss_label) { + __ pop(scratch); // save old return address + PushInterceptorArguments(masm, receiver, holder, name_, holder_obj); + __ push(scratch); // restore old return address + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptorForLoad)); + __ TailCallRuntime(ref, 5); + } + + private: + Register name_; +}; + + +class CallInterceptorCompiler BASE_EMBEDDED { + public: + explicit CallInterceptorCompiler(const ParameterCount& arguments) + : arguments_(arguments), argc_(arguments.immediate()) {} + + void CompileCacheable(MacroAssembler* masm, + StubCompiler* stub_compiler, + Register receiver, + Register holder, + Register scratch1, + Register scratch2, + JSObject* holder_obj, + LookupResult* lookup, + String* name, + Label* miss_label) { + JSFunction* function = 0; + bool optimize = false; + // So far the most popular case for failed interceptor is + // CONSTANT_FUNCTION sitting below. + if (lookup->type() == CONSTANT_FUNCTION) { + function = lookup->GetConstantFunction(); + // JSArray holder is a special case for call constant function + // (see the corresponding code). + if (function->is_compiled() && !holder_obj->IsJSArray()) { + optimize = true; + } + } + + if (!optimize) { + CompileRegular(masm, receiver, holder, scratch2, holder_obj, miss_label); + return; + } + + __ EnterInternalFrame(); + __ push(holder); // save the holder + + CompileCallLoadPropertyWithInterceptor( + masm, + receiver, + holder, + // Under EnterInternalFrame this refers to name. + Operand(ebp, (argc_ + 3) * kPointerSize), + holder_obj); + + __ pop(receiver); // restore holder + __ LeaveInternalFrame(); + + __ cmp(eax, Factory::no_interceptor_result_sentinel()); + Label invoke; + __ j(not_equal, &invoke); + + stub_compiler->CheckPrototypes(holder_obj, receiver, + lookup->holder(), scratch1, + scratch2, + name, + miss_label); + if (lookup->holder()->IsGlobalObject()) { + __ mov(edx, Operand(esp, (argc_ + 1) * kPointerSize)); + __ mov(edx, FieldOperand(edx, GlobalObject::kGlobalReceiverOffset)); + __ mov(Operand(esp, (argc_ + 1) * kPointerSize), edx); + } + + ASSERT(function->is_compiled()); + // Get the function and setup the context. + __ mov(edi, Immediate(Handle(function))); + __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); + + // Jump to the cached code (tail call). + ASSERT(function->is_compiled()); + Handle code(function->code()); + ParameterCount expected(function->shared()->formal_parameter_count()); + __ InvokeCode(code, expected, arguments_, + RelocInfo::CODE_TARGET, JUMP_FUNCTION); + + __ bind(&invoke); + } + + void CompileRegular(MacroAssembler* masm, + Register receiver, + Register holder, + Register scratch, + JSObject* holder_obj, + Label* miss_label) { + __ EnterInternalFrame(); + + PushInterceptorArguments(masm, + receiver, + holder, + Operand(ebp, (argc_ + 3) * kPointerSize), + holder_obj); + + ExternalReference ref = ExternalReference( + IC_Utility(IC::kLoadPropertyWithInterceptorForCall)); + __ mov(eax, Immediate(5)); + __ mov(ebx, Immediate(ref)); + + CEntryStub stub; + __ CallStub(&stub); + + __ LeaveInternalFrame(); + } + + private: + const ParameterCount& arguments_; + int argc_; +}; + + void StubCompiler::GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind) { ASSERT(kind == Code::LOAD_IC || kind == Code::KEYED_LOAD_IC); Code* code = NULL; @@ -507,36 +818,25 @@ void StubCompiler::GenerateLoadConstant(JSObject* object, void StubCompiler::GenerateLoadInterceptor(JSObject* object, JSObject* holder, - Smi* lookup_hint, + LookupResult* lookup, Register receiver, Register name_reg, Register scratch1, Register scratch2, String* name, Label* miss) { - // 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 = - CheckPrototypes(object, receiver, holder, - scratch1, scratch2, name, miss); - - // Push the arguments on the JS stack of the caller. - __ pop(scratch2); // remove return address - PushInterceptorArguments(masm(), - receiver, - reg, - name_reg, - holder, - lookup_hint); - __ push(scratch2); // restore return address - - // Do tail-call to the runtime system. - ExternalReference load_ic_property = - ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); - __ TailCallRuntime(load_ic_property, 6); + LoadInterceptorCompiler compiler(name_reg); + CompileLoadInterceptor(&compiler, + this, + masm(), + object, + holder, + name, + lookup, + receiver, + scratch1, + scratch2, + miss); } @@ -749,49 +1049,32 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, // Get the number of arguments. const int argc = arguments().immediate(); + LookupResult lookup; + LookupPostInterceptor(holder, name, &lookup); + // Get the receiver from the stack. __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); - // Check that the receiver isn't a smi. - __ test(edx, Immediate(kSmiTagMask)); - __ j(zero, &miss, not_taken); + CallInterceptorCompiler compiler(arguments()); + CompileLoadInterceptor(&compiler, + this, + masm(), + JSObject::cast(object), + holder, + name, + &lookup, + edx, + ebx, + ecx, + &miss); - // Check that maps have not changed and compute the holder register. - Register reg = - CheckPrototypes(JSObject::cast(object), edx, holder, - ebx, ecx, name, &miss); - - // Enter an internal frame. - __ EnterInternalFrame(); - - // Push arguments on the expression stack. - PushInterceptorArguments(masm(), - edx, - reg, - Operand(ebp, (argc + 3) * kPointerSize), - holder, - holder->InterceptorPropertyLookupHint(name)); - - // Perform call. - ExternalReference load_interceptor = - ExternalReference(IC_Utility(IC::kLoadInterceptorProperty)); - __ mov(eax, Immediate(6)); - __ mov(ebx, Immediate(load_interceptor)); - - CEntryStub stub; - __ CallStub(&stub); - - // Move result to edi and restore receiver. - __ mov(edi, eax); - __ mov(edx, Operand(ebp, (argc + 2) * kPointerSize)); // receiver - - // Exit frame. - __ LeaveInternalFrame(); + // Restore receiver. + __ mov(edx, Operand(esp, (argc + 1) * kPointerSize)); // Check that the function really is a function. - __ test(edi, Immediate(kSmiTagMask)); + __ test(eax, Immediate(kSmiTagMask)); __ j(zero, &miss, not_taken); - __ CmpObjectType(edi, JS_FUNCTION_TYPE, ebx); + __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx); __ j(not_equal, &miss, not_taken); // Patch the receiver on the stack with the global proxy if @@ -802,6 +1085,7 @@ Object* CallStubCompiler::CompileCallInterceptor(Object* object, } // Invoke the function. + __ mov(edi, eax); __ InvokeFunction(edi, arguments(), JUMP_FUNCTION); // Handle load cache miss. @@ -1173,12 +1457,15 @@ Object* LoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, // ----------------------------------- Label miss; + LookupResult lookup; + LookupPostInterceptor(holder, name, &lookup); + __ mov(eax, Operand(esp, kPointerSize)); // TODO(368): Compile in the whole chain: all the interceptors in // prototypes and ultimate answer. GenerateLoadInterceptor(receiver, holder, - holder->InterceptorPropertyLookupHint(name), + &lookup, eax, ecx, edx, @@ -1353,9 +1640,11 @@ Object* KeyedLoadStubCompiler::CompileLoadInterceptor(JSObject* receiver, __ cmp(Operand(eax), Immediate(Handle(name))); __ j(not_equal, &miss, not_taken); + LookupResult lookup; + LookupPostInterceptor(holder, name, &lookup); GenerateLoadInterceptor(receiver, holder, - Smi::FromInt(JSObject::kLookupInHolder), + &lookup, ecx, eax, edx, diff --git a/src/ic.h b/src/ic.h index 593519b420..d19a0e90d2 100644 --- a/src/ic.h +++ b/src/ic.h @@ -35,17 +35,19 @@ namespace internal { // IC_UTIL_LIST defines all utility functions called from generated // inline caching code. The argument for the macro, ICU, is the function name. -#define IC_UTIL_LIST(ICU) \ - ICU(LoadIC_Miss) \ - ICU(KeyedLoadIC_Miss) \ - ICU(CallIC_Miss) \ - ICU(StoreIC_Miss) \ - ICU(SharedStoreIC_ExtendStorage) \ - ICU(KeyedStoreIC_Miss) \ - /* Utilities for IC stubs. */ \ - ICU(LoadCallbackProperty) \ - ICU(StoreCallbackProperty) \ - ICU(LoadInterceptorProperty) \ +#define IC_UTIL_LIST(ICU) \ + ICU(LoadIC_Miss) \ + ICU(KeyedLoadIC_Miss) \ + ICU(CallIC_Miss) \ + ICU(StoreIC_Miss) \ + ICU(SharedStoreIC_ExtendStorage) \ + ICU(KeyedStoreIC_Miss) \ + /* Utilities for IC stubs. */ \ + ICU(LoadCallbackProperty) \ + ICU(StoreCallbackProperty) \ + ICU(LoadPropertyWithInterceptorOnly) \ + ICU(LoadPropertyWithInterceptorForLoad) \ + ICU(LoadPropertyWithInterceptorForCall) \ ICU(StoreInterceptorProperty) // diff --git a/src/objects-debug.cc b/src/objects-debug.cc index cf6aa3c0af..40001f9619 100644 --- a/src/objects-debug.cc +++ b/src/objects-debug.cc @@ -698,7 +698,7 @@ void Oddball::OddballVerify() { } else { ASSERT(number->IsSmi()); int value = Smi::cast(number)->value(); - ASSERT(value == 0 || value == 1 || value == -1); + ASSERT(value == 0 || value == 1 || value == -1 || value == -2); } } diff --git a/src/objects-inl.h b/src/objects-inl.h index b000dcf73f..c7f791cab4 100644 --- a/src/objects-inl.h +++ b/src/objects-inl.h @@ -2729,24 +2729,6 @@ bool JSObject::HasElement(uint32_t index) { } -Smi* JSObject::InterceptorPropertyLookupHint(String* name) { - // TODO(antonm): Do we want to do any shortcuts for global object? - if (HasFastProperties()) { - LookupResult lookup; - LocalLookupRealNamedProperty(name, &lookup); - if (lookup.IsValid()) { - if (lookup.type() == FIELD && lookup.IsCacheable()) { - return Smi::FromInt(lookup.GetFieldIndex()); - } - } else { - return Smi::FromInt(kLookupInPrototype); - } - } - - return Smi::FromInt(kLookupInHolder); -} - - bool AccessorInfo::all_can_read() { return BooleanBit::get(flag(), kAllCanReadBit); } diff --git a/src/objects.h b/src/objects.h index 7c30517e8e..b5c4024ccb 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1507,10 +1507,6 @@ class JSObject: public HeapObject { Object* LookupCallbackSetterInPrototypes(uint32_t index); void LookupCallback(String* name, LookupResult* result); - inline Smi* InterceptorPropertyLookupHint(String* name); - static const int kLookupInHolder = -1; - static const int kLookupInPrototype = -2; - // Returns the number of properties on this object filtering out properties // with the specified attributes (ignoring interceptors). int NumberOfLocalProperties(PropertyAttributes filter); diff --git a/src/stub-cache.cc b/src/stub-cache.cc index 06abc999bb..b25f5b4bb5 100644 --- a/src/stub-cache.cc +++ b/src/stub-cache.cc @@ -787,23 +787,25 @@ Object* StoreCallbackProperty(Arguments args) { return *value; } - -Object* LoadInterceptorProperty(Arguments args) { +/** + * Attempts to load a property with an interceptor (which must be present), + * but doesn't search the prototype chain. + * + * Returns |Heap::no_interceptor_result_sentinel()| if interceptor doesn't + * provide any value for the given name. + */ +Object* LoadPropertyWithInterceptorOnly(Arguments args) { Handle receiver_handle = args.at(0); Handle holder_handle = args.at(1); Handle name_handle = args.at(2); - Smi* lookup_hint = Smi::cast(args[3]); - Handle interceptor_info = args.at(4); - Handle data_handle = args.at(5); + Handle interceptor_info = args.at(3); + Handle data_handle = args.at(4); Address getter_address = v8::ToCData
(interceptor_info->getter()); v8::NamedPropertyGetter getter = FUNCTION_CAST(getter_address); ASSERT(getter != NULL); - PropertyAttributes attributes = ABSENT; - Object* result = Heap::undefined_value(); - { // Use the interceptor getter. v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle), @@ -822,65 +824,92 @@ Object* LoadInterceptorProperty(Arguments args) { } } - int property_index = lookup_hint->value(); - if (property_index >= 0) { - result = holder_handle->FastPropertyAt(property_index); - } else { - switch (property_index) { - case JSObject::kLookupInPrototype: { - Object* pt = holder_handle->GetPrototype(); - if (pt == Heap::null_value()) return Heap::undefined_value(); - result = pt->GetPropertyWithReceiver( - *receiver_handle, - *name_handle, - &attributes); - RETURN_IF_SCHEDULED_EXCEPTION(); - } - break; + return Heap::no_interceptor_result_sentinel(); +} - case JSObject::kLookupInHolder: - result = holder_handle->GetPropertyPostInterceptor( - *receiver_handle, - *name_handle, - &attributes); - RETURN_IF_SCHEDULED_EXCEPTION(); - break; - - default: - UNREACHABLE(); - } - } - - if (result->IsFailure()) return result; - if (attributes != ABSENT) return result; - - // If the top frame is an internal frame, this is really a call - // IC. In this case, we simply return the undefined result which - // will lead to an exception when trying to invoke the result as a - // function. - StackFrameIterator it; - it.Advance(); // skip exit frame - if (it.frame()->is_internal()) return result; +static Object* ThrowReferenceError(String* name) { // If the load is non-contextual, just return the undefined result. // Note that both keyed and non-keyed loads may end up here, so we // can't use either LoadIC or KeyedLoadIC constructors. IC ic(IC::NO_EXTRA_FRAME); ASSERT(ic.target()->is_load_stub() || ic.target()->is_keyed_load_stub()); - if (!ic.is_contextual()) return result; + if (!ic.is_contextual()) return Heap::undefined_value(); // Throw a reference error. + HandleScope scope; + Handle name_handle(name); + Handle error = + Factory::NewReferenceError("not_defined", + HandleVector(&name_handle, 1)); + return Top::Throw(*error); +} + + +static Object* LoadWithInterceptor(Arguments* args, + PropertyAttributes* attrs) { + Handle receiver_handle = args->at(0); + Handle holder_handle = args->at(1); + Handle name_handle = args->at(2); + Handle interceptor_info = args->at(3); + Handle data_handle = args->at(4); + + Address getter_address = v8::ToCData
(interceptor_info->getter()); + v8::NamedPropertyGetter getter = + FUNCTION_CAST(getter_address); + ASSERT(getter != NULL); + { + // Use the interceptor getter. + v8::AccessorInfo info(v8::Utils::ToLocal(receiver_handle), + v8::Utils::ToLocal(data_handle), + v8::Utils::ToLocal(holder_handle)); HandleScope scope; - // We cannot use the raw name pointer here since getting the - // property might cause a GC. However, we can get the name from - // the stack using the arguments object. - Handle name_handle = args.at(2); - Handle error = - Factory::NewReferenceError("not_defined", - HandleVector(&name_handle, 1)); - return Top::Throw(*error); + v8::Handle r; + { + // Leaving JavaScript. + VMState state(EXTERNAL); + r = getter(v8::Utils::ToLocal(name_handle), info); + } + RETURN_IF_SCHEDULED_EXCEPTION(); + if (!r.IsEmpty()) { + *attrs = NONE; + return *v8::Utils::OpenHandle(*r); + } } + + Object* result = holder_handle->GetPropertyPostInterceptor( + *receiver_handle, + *name_handle, + attrs); + RETURN_IF_SCHEDULED_EXCEPTION(); + return result; +} + + +/** + * Loads a property with an interceptor performing post interceptor + * lookup if interceptor failed. + */ +Object* LoadPropertyWithInterceptorForLoad(Arguments args) { + PropertyAttributes attr = NONE; + Object* result = LoadWithInterceptor(&args, &attr); + if (result->IsFailure()) return result; + + // If the property is present, return it. + if (attr != ABSENT) return result; + return ThrowReferenceError(String::cast(args[2])); +} + + +Object* LoadPropertyWithInterceptorForCall(Arguments args) { + PropertyAttributes attr; + Object* result = LoadWithInterceptor(&args, &attr); + RETURN_IF_SCHEDULED_EXCEPTION(); + // This is call IC. In this case, we simply return the undefined result which + // will lead to an exception when trying to invoke the result as a + // function. + return result; } diff --git a/src/stub-cache.h b/src/stub-cache.h index c6b002bf63..3b3caad56c 100644 --- a/src/stub-cache.h +++ b/src/stub-cache.h @@ -307,7 +307,9 @@ Object* StoreCallbackProperty(Arguments args); // Support functions for IC stubs for interceptors. -Object* LoadInterceptorProperty(Arguments args); +Object* LoadPropertyWithInterceptorOnly(Arguments args); +Object* LoadPropertyWithInterceptorForLoad(Arguments args); +Object* LoadPropertyWithInterceptorForCall(Arguments args); Object* StoreInterceptorProperty(Arguments args); Object* CallInterceptorProperty(Arguments args); @@ -377,13 +379,6 @@ class StubCompiler BASE_EMBEDDED { Label* miss_label); static void GenerateLoadMiss(MacroAssembler* masm, Code::Kind kind); - protected: - Object* GetCodeWithFlags(Code::Flags flags, const char* name); - Object* GetCodeWithFlags(Code::Flags flags, String* name); - - MacroAssembler* masm() { return &masm_; } - void set_failure(Failure* failure) { failure_ = failure; } - // Check the integrity of the prototype chain to make sure that the // current IC is still valid. Register CheckPrototypes(JSObject* object, @@ -394,6 +389,13 @@ class StubCompiler BASE_EMBEDDED { String* name, Label* miss); + protected: + Object* GetCodeWithFlags(Code::Flags flags, const char* name); + Object* GetCodeWithFlags(Code::Flags flags, String* name); + + MacroAssembler* masm() { return &masm_; } + void set_failure(Failure* failure) { failure_ = failure; } + void GenerateLoadField(JSObject* object, JSObject* holder, Register receiver, @@ -424,7 +426,7 @@ class StubCompiler BASE_EMBEDDED { void GenerateLoadInterceptor(JSObject* object, JSObject* holder, - Smi* lookup_hint, + LookupResult* lookup, Register receiver, Register name_reg, Register scratch1,