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
This commit is contained in:
antonm@chromium.org 2009-07-29 12:34:21 +00:00
parent cd16b5be95
commit 0d2c81584b
10 changed files with 482 additions and 173 deletions

View File

@ -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<String>(name)));
__ b(ne, &miss);
LookupResult lookup;
holder->LocalLookupRealNamedProperty(name, &lookup);
GenerateLoadInterceptor(receiver,
holder,
Smi::FromInt(JSObject::kLookupInHolder),
&lookup,
r0,
r2,
r3,

View File

@ -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;

View File

@ -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) \

View File

@ -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<Object>(interceptor)));
__ push(receiver);
@ -294,6 +289,322 @@ void StubCompiler::GenerateFastPropertyLoad(MacroAssembler* masm,
}
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) {
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<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,

View File

@ -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)
//

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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<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 @@ 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<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;
}

View File

@ -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,