Support slow-mode prototypes for load and call ICs.

This changes LoadNonExistent to handle negative lookups as well.

Review URL: https://chromiumcodereview.appspot.com/12092043

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13571 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
verwaest@chromium.org 2013-01-31 16:18:18 +00:00
parent 1c1fdc7da2
commit b1e5157e7b
6 changed files with 120 additions and 91 deletions

View File

@ -2894,9 +2894,11 @@ Handle<Code> StoreStubCompiler::CompileStoreGlobal(
}
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last) {
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last,
Handle<GlobalObject> global) {
// ----------- S t a t e -------------
// -- r0 : receiver
// -- lr : return address
@ -2906,14 +2908,24 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
// Check that receiver is not a smi.
__ JumpIfSmi(r0, &miss);
Register scratch = r1;
// Check the maps of the full prototype chain.
CheckPrototypes(object, r0, last, r3, r1, r4, name, &miss);
Register result =
CheckPrototypes(object, r0, last, r3, scratch, r4, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (last->IsGlobalObject()) {
GenerateCheckPropertyCell(
masm(), Handle<GlobalObject>::cast(last), name, r1, &miss);
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch, &miss);
}
if (!last->HasFastProperties()) {
__ ldr(scratch, FieldMemOperand(result, HeapObject::kMapOffset));
__ ldr(scratch, FieldMemOperand(scratch, Map::kPrototypeOffset));
__ cmp(scratch, Operand(isolate()->factory()->null_value()));
__ b(ne, &miss);
}
// Return undefined if maps of the full prototype chain are still the

View File

@ -2964,9 +2964,11 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
}
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last) {
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last,
Handle<GlobalObject> global) {
// ----------- S t a t e -------------
// -- ecx : name
// -- edx : receiver
@ -2977,18 +2979,25 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
// Check that the receiver isn't a smi.
__ JumpIfSmi(edx, &miss);
ASSERT(last->IsGlobalObject() || last->HasFastProperties());
Register scratch = eax;
// Check the maps of the full prototype chain. Also check that
// global property cells up to (but not including) the last object
// in the prototype chain are empty.
CheckPrototypes(object, edx, last, ebx, eax, edi, name, &miss);
Register result =
CheckPrototypes(object, edx, last, ebx, scratch, edi, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (last->IsGlobalObject()) {
GenerateCheckPropertyCell(
masm(), Handle<GlobalObject>::cast(last), name, eax, &miss);
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch, &miss);
}
if (!last->HasFastProperties()) {
__ mov(scratch, FieldOperand(result, HeapObject::kMapOffset));
__ mov(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
__ cmp(scratch, isolate()->factory()->null_value());
__ j(not_equal, &miss);
}
// Return undefined if maps of the full prototype chain are still the

View File

@ -169,26 +169,6 @@ Address IC::OriginalCodeAddress() const {
#endif
static bool HasNormalObjectsInPrototypeChain(Isolate* isolate,
LookupResult* lookup,
Object* receiver) {
Object* end = lookup->IsProperty()
? lookup->holder() : Object::cast(isolate->heap()->null_value());
for (Object* current = receiver;
current != end;
current = current->GetPrototype()) {
if (current->IsJSObject() &&
!JSObject::cast(current)->HasFastProperties() &&
!current->IsJSGlobalProxy() &&
!current->IsJSGlobalObject()) {
return true;
}
}
return false;
}
static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
Object* receiver,
Object* name) {
@ -700,14 +680,6 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
// Bail out if we didn't find a result.
if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
if (lookup->holder() != *object &&
HasNormalObjectsInPrototypeChain(
isolate(), lookup, object->GetPrototype())) {
// Suppress optimization for prototype chains with slow properties objects
// in the middle.
return;
}
// Compute the number of arguments.
int argc = target()->arguments_count();
Handle<Code> code;
@ -1023,8 +995,6 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
// deal with non-JS objects here.
if (!object->IsJSObject()) return;
if (HasNormalObjectsInPrototypeChain(isolate(), lookup, *object)) return;
Handle<JSObject> receiver = Handle<JSObject>::cast(object);
Handle<Code> code;
if (state == UNINITIALIZED) {

View File

@ -102,7 +102,6 @@ Code* StubCache::Set(String* name, Map* map, Code* code) {
Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
Handle<JSObject> receiver) {
ASSERT(receiver->IsGlobalObject() || receiver->HasFastProperties());
// If no global objects are present in the prototype chain, the load
// nonexistent IC stub can be shared for all names for a given map
// and we use the empty string for the map cache in that case. If
@ -110,12 +109,20 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
// property cells in the stub and therefore the stub will be
// specific to the name.
Handle<String> cache_name = factory()->empty_string();
if (receiver->IsGlobalObject()) cache_name = name;
Handle<JSObject> last = receiver;
while (last->GetPrototype() != heap()->null_value()) {
last = Handle<JSObject>(JSObject::cast(last->GetPrototype()));
if (last->IsGlobalObject()) cache_name = name;
}
Handle<JSObject> current;
Handle<Object> next = receiver;
Handle<GlobalObject> global;
do {
current = Handle<JSObject>::cast(next);
next = Handle<Object>(current->GetPrototype());
if (current->IsGlobalObject()) {
global = Handle<GlobalObject>::cast(current);
cache_name = name;
} else if (!current->HasFastProperties()) {
cache_name = name;
}
} while (!next->IsNull());
// Compile the stub that is either shared for all names or
// name specific if there are global objects involved.
Code::Flags flags =
@ -126,7 +133,7 @@ Handle<Code> StubCache::ComputeLoadNonexistent(Handle<String> name,
LoadStubCompiler compiler(isolate_);
Handle<Code> code =
compiler.CompileLoadNonexistent(cache_name, receiver, last);
compiler.CompileLoadNonexistent(cache_name, receiver, current, global);
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *cache_name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *cache_name, *code));
JSObject::UpdateMapCodeCache(receiver, cache_name, code);
@ -138,9 +145,11 @@ Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
PropertyIndex field_index) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::FIELD);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -149,7 +158,7 @@ Handle<Code> StubCache::ComputeLoadField(Handle<String> name,
compiler.CompileLoadField(receiver, holder, field_index, name);
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -159,10 +168,12 @@ Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name,
Handle<JSObject> holder,
Handle<AccessorInfo> callback) {
ASSERT(v8::ToCData<Address>(callback->getter()) != 0);
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -171,7 +182,7 @@ Handle<Code> StubCache::ComputeLoadCallback(Handle<String> name,
compiler.CompileLoadCallback(name, receiver, holder, callback);
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -180,10 +191,12 @@ Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> getter) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CALLBACKS);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -192,7 +205,7 @@ Handle<Code> StubCache::ComputeLoadViaGetter(Handle<String> name,
compiler.CompileLoadViaGetter(name, receiver, holder, getter);
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -201,10 +214,12 @@ Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> value) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::CONSTANT_FUNCTION);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -213,7 +228,7 @@ Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
compiler.CompileLoadConstant(receiver, holder, value, name);
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -221,10 +236,12 @@ Handle<Code> StubCache::ComputeLoadConstant(Handle<String> name,
Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::INTERCEPTOR);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -233,7 +250,7 @@ Handle<Code> StubCache::ComputeLoadInterceptor(Handle<String> name,
compiler.CompileLoadInterceptor(receiver, holder, name);
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -248,10 +265,12 @@ Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
Handle<GlobalObject> holder,
Handle<JSGlobalPropertyCell> cell,
bool is_dont_delete) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::LOAD_IC, Code::NORMAL);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -260,7 +279,7 @@ Handle<Code> StubCache::ComputeLoadGlobal(Handle<String> name,
compiler.CompileLoadGlobal(receiver, holder, cell, name, is_dont_delete);
PROFILE(isolate_, CodeCreateEvent(Logger::LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -269,10 +288,12 @@ Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
PropertyIndex field_index) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::FIELD);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -281,7 +302,7 @@ Handle<Code> StubCache::ComputeKeyedLoadField(Handle<String> name,
compiler.CompileLoadField(name, receiver, holder, field_index);
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -290,10 +311,12 @@ Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<JSFunction> value) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags = Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC,
Code::CONSTANT_FUNCTION);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -302,7 +325,7 @@ Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
compiler.CompileLoadConstant(name, receiver, holder, value);
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -310,10 +333,12 @@ Handle<Code> StubCache::ComputeKeyedLoadConstant(Handle<String> name,
Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
Handle<JSObject> receiver,
Handle<JSObject> holder) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::INTERCEPTOR);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -321,7 +346,7 @@ Handle<Code> StubCache::ComputeKeyedLoadInterceptor(Handle<String> name,
Handle<Code> code = compiler.CompileLoadInterceptor(receiver, holder, name);
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}
@ -331,10 +356,12 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback(
Handle<JSObject> receiver,
Handle<JSObject> holder,
Handle<AccessorInfo> callback) {
ASSERT(IC::GetCodeCacheForObject(*receiver, *holder) == OWN_MAP);
InlineCacheHolderFlag cache_holder =
IC::GetCodeCacheForObject(*receiver, *holder);
Handle<JSObject> map_holder(IC::GetCodeCacheHolder(*receiver, cache_holder));
Code::Flags flags =
Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::CALLBACKS);
Handle<Object> probe(receiver->map()->FindInCodeCache(*name, flags),
Handle<Object> probe(map_holder->map()->FindInCodeCache(*name, flags),
isolate_);
if (probe->IsCode()) return Handle<Code>::cast(probe);
@ -343,7 +370,7 @@ Handle<Code> StubCache::ComputeKeyedLoadCallback(
compiler.CompileLoadCallback(name, receiver, holder, callback);
PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, *name));
GDBJIT(AddCode(GDBJITInterface::KEYED_LOAD_IC, *name, *code));
JSObject::UpdateMapCodeCache(receiver, name, code);
JSObject::UpdateMapCodeCache(map_holder, name, code);
return code;
}

View File

@ -608,7 +608,8 @@ class LoadStubCompiler: public StubCompiler {
Handle<Code> CompileLoadNonexistent(Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last);
Handle<JSObject> last,
Handle<GlobalObject> global);
Handle<Code> CompileLoadField(Handle<JSObject> object,
Handle<JSObject> holder,

View File

@ -2789,9 +2789,11 @@ Handle<Code> KeyedStoreStubCompiler::CompileStorePolymorphic(
}
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last) {
Handle<Code> LoadStubCompiler::CompileLoadNonexistent(
Handle<String> name,
Handle<JSObject> object,
Handle<JSObject> last,
Handle<GlobalObject> global) {
// ----------- S t a t e -------------
// -- rax : receiver
// -- rcx : name
@ -2805,13 +2807,21 @@ Handle<Code> LoadStubCompiler::CompileLoadNonexistent(Handle<String> name,
// Check the maps of the full prototype chain. Also check that
// global property cells up to (but not including) the last object
// in the prototype chain are empty.
CheckPrototypes(object, rax, last, rbx, rdx, rdi, name, &miss);
Register scratch = rdx;
Register result =
CheckPrototypes(object, rax, last, rbx, scratch, rdi, name, &miss);
// If the last object in the prototype chain is a global object,
// check that the global property cell is empty.
if (last->IsGlobalObject()) {
GenerateCheckPropertyCell(
masm(), Handle<GlobalObject>::cast(last), name, rdx, &miss);
if (!global.is_null()) {
GenerateCheckPropertyCell(masm(), global, name, scratch, &miss);
}
if (!last->HasFastProperties()) {
__ movq(scratch, FieldOperand(result, HeapObject::kMapOffset));
__ movq(scratch, FieldOperand(scratch, Map::kPrototypeOffset));
__ Cmp(scratch, isolate()->factory()->null_value());
__ j(not_equal, &miss);
}
// Return undefined if maps of the full prototype chain are still the