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:
parent
cd16b5be95
commit
0d2c81584b
@ -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,
|
||||
|
@ -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;
|
||||
|
@ -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) \
|
||||
|
@ -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,
|
||||
|
24
src/ic.h
24
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)
|
||||
|
||||
//
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user