Revision: 2577 Author: [email protected] Date: Wed Jul 29 05:34:21 2009 Log: Compile precanned answers for the case of failed interceptor for some combinations.
Review URL: http://codereview.chromium.org/140069 http://code.google.com/p/v8/source/detail?r=2577 Modified: /branches/bleeding_edge/src/arm/stub-cache-arm.cc /branches/bleeding_edge/src/heap.cc /branches/bleeding_edge/src/heap.h /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc /branches/bleeding_edge/src/ic.h /branches/bleeding_edge/src/objects-debug.cc /branches/bleeding_edge/src/objects-inl.h /branches/bleeding_edge/src/objects.h /branches/bleeding_edge/src/stub-cache.cc /branches/bleeding_edge/src/stub-cache.h ======================================= --- /branches/bleeding_edge/src/arm/stub-cache-arm.cc Tue Jul 28 07:46:06 2009 +++ /branches/bleeding_edge/src/arm/stub-cache-arm.cc Wed Jul 29 05:34:21 2009 @@ -483,7 +483,7 @@ void StubCompiler::GenerateLoadInterceptor(JSObject* object, JSObject* holder, - Smi* lookup_hint, + LookupResult* lookup, Register receiver, Register name_reg, Register scratch1, @@ -502,8 +502,6 @@ __ 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 @@ // 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 @@ __ 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 @@ __ cmp(r2, Operand(Handle<String>(name))); __ b(ne, &miss); + LookupResult lookup; + holder->LocalLookupRealNamedProperty(name, &lookup); GenerateLoadInterceptor(receiver, holder, - Smi::FromInt(JSObject::kLookupInHolder), + &lookup, r0, r2, r3, ======================================= --- /branches/bleeding_edge/src/heap.cc Wed Jul 29 01:10:19 2009 +++ /branches/bleeding_edge/src/heap.cc Wed Jul 29 05:34:21 2009 @@ -1411,6 +1411,12 @@ 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; ======================================= --- /branches/bleeding_edge/src/heap.h Tue Jul 28 01:43:51 2009 +++ /branches/bleeding_edge/src/heap.h Wed Jul 29 05:34:21 2009 @@ -110,6 +110,7 @@ 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) \ ======================================= --- /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Tue Jul 28 07:46:06 2009 +++ /branches/bleeding_edge/src/ia32/stub-cache-ia32.cc Wed Jul 29 05:34:21 2009 @@ -157,15 +157,10 @@ 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<Object>(interceptor))); __ push(receiver); @@ -292,6 +287,322 @@ __ mov(dst, FieldOperand(dst, offset)); } } + + +template <class Pushable> +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 <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->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<AccessorInfo>(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<JSFunction>(function))); + __ mov(esi, FieldOperand(edi, JSFunction::kContextOffset)); + + // Jump to the cached code (tail call). + ASSERT(function->is_compiled()); + Handle<Code> 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) { @@ -507,36 +818,25 @@ 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 @@ // 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); - - // 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(); + CallInterceptorCompiler compiler(arguments()); + CompileLoadInterceptor(&compiler, + this, + masm(), + JSObject::cast(object), + holder, + name, + &lookup, + edx, + ebx, + ecx, + &miss); + + // 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 @@ } // Invoke the function. + __ mov(edi, eax); __ InvokeFunction(edi, arguments(), JUMP_FUNCTION); // Handle load cache miss. @@ -1173,12 +1457,15 @@ // ----------------------------------- 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 @@ __ cmp(Operand(eax), Immediate(Handle<String>(name))); __ j(not_equal, &miss, not_taken); + LookupResult lookup; + LookupPostInterceptor(holder, name, &lookup); GenerateLoadInterceptor(receiver, holder, - Smi::FromInt(JSObject::kLookupInHolder), + &lookup, ecx, eax, edx, ======================================= --- /branches/bleeding_edge/src/ic.h Thu Jul 16 01:38:52 2009 +++ /branches/bleeding_edge/src/ic.h Wed Jul 29 05:34:21 2009 @@ -35,17 +35,19 @@ // 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) // ======================================= --- /branches/bleeding_edge/src/objects-debug.cc Tue Jul 28 01:43:51 2009 +++ /branches/bleeding_edge/src/objects-debug.cc Wed Jul 29 05:34:21 2009 @@ -698,7 +698,7 @@ } 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); } } ======================================= --- /branches/bleeding_edge/src/objects-inl.h Wed Jul 29 02:51:41 2009 +++ /branches/bleeding_edge/src/objects-inl.h Wed Jul 29 05:34:21 2009 @@ -2727,24 +2727,6 @@ bool JSObject::HasElement(uint32_t index) { return HasElementWithReceiver(this, 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() { ======================================= --- /branches/bleeding_edge/src/objects.h Wed Jul 29 02:51:41 2009 +++ /branches/bleeding_edge/src/objects.h Wed Jul 29 05:34:21 2009 @@ -1507,10 +1507,6 @@ 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); ======================================= --- /branches/bleeding_edge/src/stub-cache.cc Tue Jul 28 07:46:06 2009 +++ /branches/bleeding_edge/src/stub-cache.cc Wed Jul 29 05:34:21 2009 @@ -787,23 +787,25 @@ 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<JSObject> receiver_handle = args.at<JSObject>(0); Handle<JSObject> holder_handle = args.at<JSObject>(1); Handle<String> name_handle = args.at<String>(2); - Smi* lookup_hint = Smi::cast(args[3]); - Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(4); - Handle<Object> data_handle = args.at<Object>(5); + Handle<InterceptorInfo> interceptor_info = args.at<InterceptorInfo>(3); + Handle<Object> data_handle = args.at<Object>(4); Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); v8::NamedPropertyGetter getter = FUNCTION_CAST<v8::NamedPropertyGetter>(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 @@ } } - 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; - - 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; - + return Heap::no_interceptor_result_sentinel(); +} + + +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<String> name_handle(name); + Handle<Object> error = + Factory::NewReferenceError("not_defined", + HandleVector(&name_handle, 1)); + return Top::Throw(*error); +} + + +static Object* LoadWithInterceptor(Arguments* args, + PropertyAttributes* attrs) { + Handle<JSObject> receiver_handle = args->at<JSObject>(0); + Handle<JSObject> holder_handle = args->at<JSObject>(1); + Handle<String> name_handle = args->at<String>(2); + Handle<InterceptorInfo> interceptor_info = args->at<InterceptorInfo>(3); + Handle<Object> data_handle = args->at<Object>(4); + + Address getter_address = v8::ToCData<Address>(interceptor_info->getter()); + v8::NamedPropertyGetter getter = + FUNCTION_CAST<v8::NamedPropertyGetter>(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<String> name_handle = args.at<String>(2); - Handle<Object> error = - Factory::NewReferenceError("not_defined", - HandleVector(&name_handle, 1)); - return Top::Throw(*error); - } + v8::Handle<v8::Value> 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; } ======================================= --- /branches/bleeding_edge/src/stub-cache.h Tue Jul 21 06:30:46 2009 +++ /branches/bleeding_edge/src/stub-cache.h Wed Jul 29 05:34:21 2009 @@ -307,7 +307,9 @@ // 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); @@ -376,13 +378,6 @@ Register scratch, 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. @@ -393,6 +388,13 @@ Register scratch, 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, @@ -424,7 +426,7 @@ void GenerateLoadInterceptor(JSObject* object, JSObject* holder, - Smi* lookup_hint, + LookupResult* lookup, Register receiver, Register name_reg, Register scratch1, --~--~---------~--~----~------------~-------~--~----~ v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev -~----------~----~----~----~------~----~------~--~---
