Commit aa881856 authored by ager@chromium.org's avatar ager@chromium.org

Add inline caches for loading non-existing properties.

Review URL: http://codereview.chromium.org/1539034

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4401 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6e8c85dc
......@@ -1389,6 +1389,36 @@ Object* StoreStubCompiler::CompileStoreGlobal(GlobalObject* object,
}
Object* LoadStubCompiler::CompileLoadNonexistent(JSObject* object) {
// ----------- S t a t e -------------
// -- r2 : name
// -- lr : return address
// -- [sp] : receiver
// -----------------------------------
Label miss;
// Load receiver.
__ ldr(r0, MemOperand(sp, 0));
// Check the maps of the full prototype chain.
JSObject* last = object;
while (last->GetPrototype() != Heap::null_value()) {
last = JSObject::cast(last->GetPrototype());
}
CheckPrototypes(object, r0, last, r3, r1, Heap::empty_string(), &miss);
// Return undefined if maps of the full prototype chain is still the same.
__ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
__ Ret();
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(NONEXISTENT, Heap::empty_string());
}
Object* LoadStubCompiler::CompileLoadField(JSObject* object,
JSObject* holder,
int index,
......
......@@ -428,7 +428,11 @@ enum PropertyType {
CONSTANT_TRANSITION = 6, // only in fast mode
NULL_DESCRIPTOR = 7, // only in fast mode
// All properties before MAP_TRANSITION are real.
FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION
FIRST_PHANTOM_PROPERTY_TYPE = MAP_TRANSITION,
// There are no IC stubs for NULL_DESCRIPTORS. Therefore,
// NULL_DESCRIPTOR can be used as the type flag for IC stubs for
// nonexistent properties.
NONEXISTENT = NULL_DESCRIPTOR
};
......
......@@ -1948,6 +1948,32 @@ Object* KeyedStoreStubCompiler::CompileStoreField(JSObject* object,
}
Object* LoadStubCompiler::CompileLoadNonexistent(JSObject* object) {
// ----------- S t a t e -------------
// -- eax : receiver
// -- ecx : name
// -- esp[0] : return address
// -----------------------------------
Label miss;
// Check the maps of the full prototype chain.
JSObject* last = object;
while (last->GetPrototype() != Heap::null_value()) {
last = JSObject::cast(last->GetPrototype());
}
CheckPrototypes(object, eax, last, ebx, edx, Heap::empty_string(), &miss);
// Return undefined if maps of the full prototype chain is still the same.
__ mov(eax, Factory::undefined_value());
__ ret(0);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(NONEXISTENT, Heap::empty_string());
}
Object* LoadStubCompiler::CompileLoadField(JSObject* object,
JSObject* holder,
......
......@@ -694,8 +694,8 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
State state,
Handle<Object> object,
Handle<String> name) {
// Bail out if we didn't find a result.
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
// Bail out if the result is not cachable.
if (!lookup->IsCacheable()) return;
// Loading properties from values is not common, so don't try to
// deal with non-JS objects here.
......@@ -709,6 +709,9 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
// Set the target to the pre monomorphic stub to delay
// setting the monomorphic state.
code = pre_monomorphic_stub();
} else if (!lookup->IsProperty()) {
// Nonexistent property. The result is undefined.
code = StubCache::ComputeLoadNonexistent(*name, *receiver);
} else {
// Compute monomorphic stub.
switch (lookup->type()) {
......
......@@ -93,6 +93,28 @@ Code* StubCache::Set(String* name, Map* map, Code* code) {
}
Object* StubCache::ComputeLoadNonexistent(String* name, JSObject* receiver) {
// The code stub for loading nonexistent properties can be reused
// for all names, so we use the empty_string as the name in the map
// code cache.
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, NONEXISTENT);
Object* code = receiver->map()->FindInCodeCache(Heap::empty_string(), flags);
if (code->IsUndefined()) {
LoadStubCompiler compiler;
code = compiler.CompileLoadNonexistent(receiver);
if (code->IsFailure()) return code;
PROFILE(CodeCreateEvent(Logger::LOAD_IC_TAG,
Code::cast(code),
Heap::empty_string()));
Object* result = receiver->map()->UpdateCodeCache(Heap::empty_string(),
Code::cast(code));
if (result->IsFailure()) return result;
}
return Set(name, receiver->map(), Code::cast(code));
}
Object* StubCache::ComputeLoadField(String* name,
JSObject* receiver,
JSObject* holder,
......
......@@ -56,6 +56,8 @@ class StubCache : public AllStatic {
// Computes the right stub matching. Inserts the result in the
// cache before returning. This might compile a stub if needed.
static Object* ComputeLoadNonexistent(String* name, JSObject* receiver);
static Object* ComputeLoadField(String* name,
JSObject* receiver,
JSObject* holder,
......@@ -461,18 +463,23 @@ class StubCompiler BASE_EMBEDDED {
class LoadStubCompiler: public StubCompiler {
public:
Object* CompileLoadNonexistent(JSObject* object);
Object* CompileLoadField(JSObject* object,
JSObject* holder,
int index,
String* name);
Object* CompileLoadCallback(String* name,
JSObject* object,
JSObject* holder,
AccessorInfo* callback);
Object* CompileLoadConstant(JSObject* object,
JSObject* holder,
Object* value,
String* name);
Object* CompileLoadInterceptor(JSObject* object,
JSObject* holder,
String* name);
......@@ -494,17 +501,21 @@ class KeyedLoadStubCompiler: public StubCompiler {
JSObject* object,
JSObject* holder,
int index);
Object* CompileLoadCallback(String* name,
JSObject* object,
JSObject* holder,
AccessorInfo* callback);
Object* CompileLoadConstant(String* name,
JSObject* object,
JSObject* holder,
Object* value);
Object* CompileLoadInterceptor(JSObject* object,
JSObject* holder,
String* name);
Object* CompileLoadArrayLength(String* name);
Object* CompileLoadStringLength(String* name);
Object* CompileLoadFunctionPrototype(String* name);
......
......@@ -1144,6 +1144,36 @@ Object* LoadStubCompiler::CompileLoadConstant(JSObject* object,
}
Object* LoadStubCompiler::CompileLoadNonexistent(JSObject* object) {
// ----------- S t a t e -------------
// -- rcx : name
// -- rsp[0] : return address
// -- rsp[8] : receiver
// -----------------------------------
Label miss;
// Load receiver.
__ movq(rax, Operand(rsp, kPointerSize));
// Check the maps of the full prototype chain.
JSObject* last = object;
while (last->GetPrototype() != Heap::null_value()) {
last = JSObject::cast(last->GetPrototype());
}
CheckPrototypes(object, rax, last, rbx, rdx, Heap::empty_string(), &miss);
// Return undefined if maps of the full prototype chain is still the same.
__ LoadRoot(rax, Heap::kUndefinedValueRootIndex);
__ ret(0);
__ bind(&miss);
GenerateLoadMiss(masm(), Code::LOAD_IC);
// Return the generated code.
return GetCode(NONEXISTENT, Heap::empty_string());
}
Object* LoadStubCompiler::CompileLoadField(JSObject* object,
JSObject* holder,
int index,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment