Commit 84fd96e4 authored by verwaest@chromium.org's avatar verwaest@chromium.org

Cleanup IC heuristics.

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

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@14524 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 063ada20
...@@ -182,13 +182,13 @@ Address IC::OriginalCodeAddress() const { ...@@ -182,13 +182,13 @@ Address IC::OriginalCodeAddress() const {
static bool TryRemoveInvalidPrototypeDependentStub(Code* target, static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
Object* receiver, Object* receiver,
Object* name) { Object* name) {
// If the code is NORMAL, it handles dictionary mode objects. Such stubs do if (target->is_keyed_load_stub() ||
// not check maps, but do positive/negative lookups. target->is_keyed_call_stub() ||
if (target->type() != Code::NORMAL) { target->is_keyed_store_stub()) {
Map* map = target->FindFirstMap(); // Determine whether the failure is due to a name failure.
if (map != NULL && map->is_deprecated()) { if (!name->IsName()) return false;
return true; Name* stub_name = target->FindFirstName();
} if (Name::cast(name) != stub_name) return false;
} }
InlineCacheHolderFlag cache_holder = InlineCacheHolderFlag cache_holder =
...@@ -217,10 +217,30 @@ static bool TryRemoveInvalidPrototypeDependentStub(Code* target, ...@@ -217,10 +217,30 @@ static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
int index = map->IndexInCodeCache(name, target); int index = map->IndexInCodeCache(name, target);
if (index >= 0) { if (index >= 0) {
map->RemoveFromCodeCache(String::cast(name), target, index); map->RemoveFromCodeCache(String::cast(name), target, index);
// For loads, handlers are stored in addition to the ICs on the map. Remove
// those, too.
if (target->is_load_stub() || target->is_keyed_load_stub()) {
Code* handler = target->FindFirstCode();
index = map->IndexInCodeCache(name, handler);
if (index >= 0) {
map->RemoveFromCodeCache(String::cast(name), handler, index);
}
}
return true; return true;
} }
return false; // If the IC is shared between multiple receivers (slow dictionary mode), then
// the map cannot be deprecated and the stub invalidated.
if (cache_holder != OWN_MAP) return false;
// The stub is not in the cache. We've ruled out all other kinds of failure
// except for proptotype chain changes, a deprecated map, or a map that's
// different from the one that the stub expects. If the map hasn't changed,
// assume it's a prototype failure. Treat deprecated maps in the same way as
// prototype failures (stay monomorphic if possible).
Map* old_map = target->FindFirstMap();
if (old_map == NULL) return false;
return old_map == map || old_map->is_deprecated();
} }
...@@ -230,22 +250,13 @@ IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { ...@@ -230,22 +250,13 @@ IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) {
if (state != MONOMORPHIC || !name->IsString()) return state; if (state != MONOMORPHIC || !name->IsString()) return state;
if (receiver->IsUndefined() || receiver->IsNull()) return state; if (receiver->IsUndefined() || receiver->IsNull()) return state;
// For keyed load/store/call, the most likely cause of cache failure is
// that the key has changed. We do not distinguish between
// prototype and non-prototype failures for keyed access.
Code::Kind kind = target->kind(); Code::Kind kind = target->kind();
if (kind == Code::KEYED_LOAD_IC ||
kind == Code::KEYED_STORE_IC ||
kind == Code::KEYED_CALL_IC) {
return MONOMORPHIC;
}
// Remove the target from the code cache if it became invalid // Remove the target from the code cache if it became invalid
// because of changes in the prototype chain to avoid hitting it // because of changes in the prototype chain to avoid hitting it
// again. // again.
// Call stubs handle this later to allow extra IC state // Call stubs handle this later to allow extra IC state
// transitions. // transitions.
if (kind != Code::CALL_IC && if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC &&
TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) {
return MONOMORPHIC_PROTOTYPE_FAILURE; return MONOMORPHIC_PROTOTYPE_FAILURE;
} }
...@@ -724,8 +735,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup, ...@@ -724,8 +735,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
TryUpdateExtraICState(lookup, object, &extra_ic_state)) { TryUpdateExtraICState(lookup, object, &extra_ic_state)) {
code = ComputeMonomorphicStub(lookup, state, extra_ic_state, code = ComputeMonomorphicStub(lookup, state, extra_ic_state,
object, name); object, name);
} else if (kind_ == Code::CALL_IC && } else if (TryRemoveInvalidPrototypeDependentStub(target(),
TryRemoveInvalidPrototypeDependentStub(target(),
*object, *object,
*name)) { *name)) {
state = MONOMORPHIC_PROTOTYPE_FAILURE; state = MONOMORPHIC_PROTOTYPE_FAILURE;
...@@ -748,15 +758,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup, ...@@ -748,15 +758,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup,
case UNINITIALIZED: case UNINITIALIZED:
case MONOMORPHIC_PROTOTYPE_FAILURE: case MONOMORPHIC_PROTOTYPE_FAILURE:
case PREMONOMORPHIC: case PREMONOMORPHIC:
set_target(*code);
break;
case MONOMORPHIC: case MONOMORPHIC:
if (code->ic_state() != MONOMORPHIC) {
Map* map = target()->FindFirstMap();
if (map != NULL) {
UpdateMegamorphicCache(map, *name, target());
}
}
set_target(*code); set_target(*code);
break; break;
case MEGAMORPHIC: { case MEGAMORPHIC: {
...@@ -986,14 +988,25 @@ bool IC::UpdatePolymorphicIC(State state, ...@@ -986,14 +988,25 @@ bool IC::UpdatePolymorphicIC(State state,
CodeHandleList handlers; CodeHandleList handlers;
int number_of_valid_maps; int number_of_valid_maps;
int handler_to_overwrite = -1;
Handle<Map> new_receiver_map(receiver->map());
{ {
AssertNoAllocation no_gc; AssertNoAllocation no_gc;
target()->FindAllMaps(&receiver_maps); target()->FindAllMaps(&receiver_maps);
int number_of_maps = receiver_maps.length(); int number_of_maps = receiver_maps.length();
number_of_valid_maps = number_of_maps; number_of_valid_maps = number_of_maps;
for (int i = 0; i < number_of_maps; i++) { for (int i = 0; i < number_of_maps; i++) {
if (receiver_maps.at(i)->is_deprecated()) { Handle<Map> map = receiver_maps.at(i);
// Filter out deprecated maps to ensure its instances get migrated.
if (map->is_deprecated()) {
number_of_valid_maps--;
// If the receiver map is already in the polymorphic IC, this indicates
// there was a prototoype chain failure. In that case, just overwrite the
// handler.
} else if (map.is_identical_to(new_receiver_map)) {
number_of_valid_maps--; number_of_valid_maps--;
handler_to_overwrite = i;
} }
} }
...@@ -1007,14 +1020,16 @@ bool IC::UpdatePolymorphicIC(State state, ...@@ -1007,14 +1020,16 @@ bool IC::UpdatePolymorphicIC(State state,
target()->FindAllCode(&handlers, receiver_maps.length()); target()->FindAllCode(&handlers, receiver_maps.length());
} }
if (!AddOneReceiverMapIfMissing(&receiver_maps, number_of_valid_maps++;
Handle<Map>(receiver->map()))) { if (handler_to_overwrite >= 0) {
return false; handlers.InsertAt(handler_to_overwrite, code);
} else {
receiver_maps.Add(new_receiver_map);
handlers.Add(code);
} }
handlers.Add(code);
Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC(
&receiver_maps, &handlers, number_of_valid_maps + 1, name); &receiver_maps, &handlers, number_of_valid_maps, name);
set_target(*ic); set_target(*ic);
return true; return true;
} }
...@@ -1101,38 +1116,9 @@ void IC::PatchCache(State state, ...@@ -1101,38 +1116,9 @@ void IC::PatchCache(State state,
if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) {
break; break;
} }
}
if (target()->type() != Code::NORMAL) { if (target()->type() != Code::NORMAL) {
if (target()->is_load_stub()) {
CopyICToMegamorphicCache(name); CopyICToMegamorphicCache(name);
} else if (target()->is_store_stub()) {
// Ensure that the IC stays monomorphic when replacing a monomorphic
// IC for a deprecated map.
// TODO(verwaest): Remove this code once polymorphic store ICs are
// implemented. Updating the polymorphic IC will keep it monomorphic
// by filtering deprecated maps.
MapHandleList maps;
Code* handler = target();
handler->FindAllMaps(&maps);
for (int i = 0; i < Min(1, maps.length()); i++) {
if (maps.at(i)->is_deprecated()) {
UpdateMonomorphicIC(receiver, code, name);
return;
}
}
if (maps.length() > 0) {
if (receiver->map() == *maps.at(0)) {
UpdateMonomorphicIC(receiver, code, name);
return;
}
UpdateMegamorphicCache(*maps.at(0), *name, handler);
}
} else {
Code* handler = target();
Map* map = handler->FindFirstMap();
if (map != NULL) {
UpdateMegamorphicCache(map, *name, handler);
}
} }
} }
...@@ -1235,7 +1221,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup, ...@@ -1235,7 +1221,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup,
} }
void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { void IC::UpdateMegamorphicCache(Map* map, Name* name, Code* code) {
// Cache code holding map should be consistent with // Cache code holding map should be consistent with
// GenerateMonomorphicCacheProbe. // GenerateMonomorphicCacheProbe.
isolate()->stub_cache()->Set(name, map, code); isolate()->stub_cache()->Set(name, map, code);
...@@ -1497,7 +1483,8 @@ Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, ...@@ -1497,7 +1483,8 @@ Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup,
static bool LookupForWrite(Handle<JSObject> receiver, static bool LookupForWrite(Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Object> value, Handle<Object> value,
LookupResult* lookup) { LookupResult* lookup,
IC::State* state) {
Handle<JSObject> holder = receiver; Handle<JSObject> holder = receiver;
receiver->Lookup(*name, lookup); receiver->Lookup(*name, lookup);
if (lookup->IsFound()) { if (lookup->IsFound()) {
...@@ -1534,7 +1521,21 @@ static bool LookupForWrite(Handle<JSObject> receiver, ...@@ -1534,7 +1521,21 @@ static bool LookupForWrite(Handle<JSObject> receiver,
PropertyDetails target_details = PropertyDetails target_details =
lookup->GetTransitionDetails(receiver->map()); lookup->GetTransitionDetails(receiver->map());
if (target_details.IsReadOnly()) return false; if (target_details.IsReadOnly()) return false;
return value->FitsRepresentation(target_details.representation());
// If the value that's being stored does not fit in the field that the
// instance would transition to, create a new transition that fits the value.
// This has to be done before generating the IC, since that IC will embed the
// transition target.
// Ensure the instance and its map were migrated before trying to update the
// transition target.
ASSERT(!receiver->map()->is_deprecated());
if (!value->FitsRepresentation(target_details.representation())) {
Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map()));
Map::GeneralizeRepresentation(
target, target->LastAdded(), value->OptimalRepresentation());
*state = MONOMORPHIC_PROTOTYPE_FAILURE;
}
return true;
} }
...@@ -1618,7 +1619,7 @@ MaybeObject* StoreIC::Store(State state, ...@@ -1618,7 +1619,7 @@ MaybeObject* StoreIC::Store(State state,
} }
LookupResult lookup(isolate()); LookupResult lookup(isolate());
if (LookupForWrite(receiver, name, value, &lookup)) { if (LookupForWrite(receiver, name, value, &lookup, &state)) {
if (FLAG_use_ic) { if (FLAG_use_ic) {
UpdateCaches(&lookup, state, strict_mode, receiver, name, value); UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
} }
......
...@@ -184,7 +184,7 @@ class IC { ...@@ -184,7 +184,7 @@ class IC {
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name, Handle<String> name,
Handle<Code> code); Handle<Code> code);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code); virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code);
virtual Handle<Code> megamorphic_stub() { virtual Handle<Code> megamorphic_stub() {
UNREACHABLE(); UNREACHABLE();
return Handle<Code>::null(); return Handle<Code>::null();
...@@ -471,7 +471,7 @@ class KeyedLoadIC: public LoadIC { ...@@ -471,7 +471,7 @@ class KeyedLoadIC: public LoadIC {
virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup, virtual Handle<Code> ComputeLoadHandler(LookupResult* lookup,
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name); Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { } virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
private: private:
// Stub accessors. // Stub accessors.
...@@ -620,7 +620,7 @@ class KeyedStoreIC: public StoreIC { ...@@ -620,7 +620,7 @@ class KeyedStoreIC: public StoreIC {
StrictModeFlag strict_mode, StrictModeFlag strict_mode,
Handle<JSObject> receiver, Handle<JSObject> receiver,
Handle<String> name); Handle<String> name);
virtual void UpdateMegamorphicCache(Map* map, String* name, Code* code) { } virtual void UpdateMegamorphicCache(Map* map, Name* name, Code* code) { }
virtual Handle<Code> megamorphic_stub() { virtual Handle<Code> megamorphic_stub() {
return isolate()->builtins()->KeyedStoreIC_Generic(); return isolate()->builtins()->KeyedStoreIC_Generic();
......
...@@ -9783,6 +9783,19 @@ void Code::FindAllCode(CodeHandleList* code_list, int length) { ...@@ -9783,6 +9783,19 @@ void Code::FindAllCode(CodeHandleList* code_list, int length) {
} }
Name* Code::FindFirstName() {
ASSERT(is_inline_cache_stub());
AssertNoAllocation no_allocation;
int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
for (RelocIterator it(this, mask); !it.done(); it.next()) {
RelocInfo* info = it.rinfo();
Object* object = info->target_object();
if (object->IsName()) return Name::cast(object);
}
return NULL;
}
void Code::ClearInlineCaches() { void Code::ClearInlineCaches() {
int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) | int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) | RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
......
...@@ -4629,6 +4629,9 @@ class Code: public HeapObject { ...@@ -4629,6 +4629,9 @@ class Code: public HeapObject {
Code* FindFirstCode(); Code* FindFirstCode();
void FindAllCode(CodeHandleList* code_list, int length); void FindAllCode(CodeHandleList* code_list, int length);
// Find the first name in an IC stub.
Name* FindFirstName();
class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {}; class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {};
class ExtraICStateKeyedAccessStoreMode: class ExtraICStateKeyedAccessStoreMode:
public BitField<KeyedAccessStoreMode, 1, 4> {}; // NOLINT public BitField<KeyedAccessStoreMode, 1, 4> {}; // NOLINT
......
...@@ -431,15 +431,7 @@ Handle<Code> StubCache::ComputeStoreTransition(Handle<Name> name, ...@@ -431,15 +431,7 @@ Handle<Code> StubCache::ComputeStoreTransition(Handle<Name> name,
StrictModeFlag strict_mode) { StrictModeFlag strict_mode) {
Handle<Code> stub = FindIC( Handle<Code> stub = FindIC(
name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode); name, receiver, Code::STORE_IC, Code::MAP_TRANSITION, strict_mode);
if (!stub.is_null()) { if (!stub.is_null()) return stub;
MapHandleList embedded_maps;
stub->FindAllMaps(&embedded_maps);
for (int i = 0; i < embedded_maps.length(); i++) {
if (embedded_maps.at(i).is_identical_to(transition)) {
return stub;
}
}
}
StoreStubCompiler compiler(isolate_, strict_mode); StoreStubCompiler compiler(isolate_, strict_mode);
Handle<Code> code = Handle<Code> code =
...@@ -589,15 +581,7 @@ Handle<Code> StubCache::ComputeKeyedStoreTransition( ...@@ -589,15 +581,7 @@ Handle<Code> StubCache::ComputeKeyedStoreTransition(
StrictModeFlag strict_mode) { StrictModeFlag strict_mode) {
Handle<Code> stub = FindIC( Handle<Code> stub = FindIC(
name, receiver, Code::KEYED_STORE_IC, Code::MAP_TRANSITION, strict_mode); name, receiver, Code::KEYED_STORE_IC, Code::MAP_TRANSITION, strict_mode);
if (!stub.is_null()) { if (!stub.is_null()) return stub;
MapHandleList embedded_maps;
stub->FindAllMaps(&embedded_maps);
for (int i = 0; i < embedded_maps.length(); i++) {
if (embedded_maps.at(i).is_identical_to(transition)) {
return stub;
}
}
}
KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE); KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
Handle<Code> code = Handle<Code> code =
......
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