Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index 080c7bf1b723f87b1449d4d9da58567ddf6ea9fb..024ce18326c888930810ee9827d6bf92a35341ca 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -182,13 +182,12 @@ Address IC::OriginalCodeAddress() const { |
static bool TryRemoveInvalidPrototypeDependentStub(Code* target, |
Object* receiver, |
Object* name) { |
- // If the code is NORMAL, it handles dictionary mode objects. Such stubs do |
- // not check maps, but do positive/negative lookups. |
- if (target->type() != Code::NORMAL) { |
- Map* map = target->FindFirstMap(); |
- if (map != NULL && map->is_deprecated()) { |
- return true; |
- } |
+ if (target->is_keyed_load_stub() || |
danno
2013/05/02 11:36:06
// Determine whether the failure is due to a name
Toon Verwaest
2013/05/02 12:27:20
Done.
|
+ target->is_keyed_call_stub() || |
+ target->is_keyed_store_stub()) { |
+ if (!name->IsName()) return false; |
+ Name* stub_name = target->FindFirstName(); |
+ if (Name::cast(name) != stub_name) return false; |
} |
InlineCacheHolderFlag cache_holder = |
@@ -217,10 +216,22 @@ static bool TryRemoveInvalidPrototypeDependentStub(Code* target, |
int index = map->IndexInCodeCache(name, target); |
if (index >= 0) { |
map->RemoveFromCodeCache(String::cast(name), target, index); |
+ if (target->is_load_stub() || target->is_keyed_load_stub()) { |
danno
2013/05/02 11:36:06
// For loads, handlers are stored in addition to t
Toon Verwaest
2013/05/02 12:27:20
Done.
|
+ Code* handler = target->FindFirstCode(); |
+ index = map->IndexInCodeCache(name, handler); |
+ if (index >= 0) { |
+ map->RemoveFromCodeCache(String::cast(name), handler, index); |
+ } |
+ } |
return true; |
} |
- return false; |
+ if (cache_holder != OWN_MAP) return false; |
danno
2013/05/02 11:36:06
// If the IC is shared between multiple receivers
Toon Verwaest
2013/05/02 12:27:20
Done.
|
+ |
+ // Also flag monomorphic prototype failure if the old map was deprecated. |
+ Map* old_map = target->FindFirstMap(); |
+ if (old_map == NULL) return false; |
+ return old_map == map || old_map->is_deprecated(); |
danno
2013/05/02 11:36:06
// The stub is not in the cache. We've ruled out a
Toon Verwaest
2013/05/02 12:27:20
Done.
|
} |
@@ -230,22 +241,13 @@ IC::State IC::StateFrom(Code* target, Object* receiver, Object* name) { |
if (state != MONOMORPHIC || !name->IsString()) 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(); |
- 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 |
// because of changes in the prototype chain to avoid hitting it |
// again. |
// Call stubs handle this later to allow extra IC state |
// transitions. |
- if (kind != Code::CALL_IC && |
+ if (kind != Code::CALL_IC && kind != Code::KEYED_CALL_IC && |
TryRemoveInvalidPrototypeDependentStub(target, receiver, name)) { |
return MONOMORPHIC_PROTOTYPE_FAILURE; |
} |
@@ -724,8 +726,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup, |
TryUpdateExtraICState(lookup, object, &extra_ic_state)) { |
code = ComputeMonomorphicStub(lookup, state, extra_ic_state, |
object, name); |
- } else if (kind_ == Code::CALL_IC && |
- TryRemoveInvalidPrototypeDependentStub(target(), |
+ } else if (TryRemoveInvalidPrototypeDependentStub(target(), |
*object, |
*name)) { |
state = MONOMORPHIC_PROTOTYPE_FAILURE; |
@@ -748,15 +749,7 @@ void CallICBase::UpdateCaches(LookupResult* lookup, |
case UNINITIALIZED: |
case MONOMORPHIC_PROTOTYPE_FAILURE: |
case PREMONOMORPHIC: |
- set_target(*code); |
- break; |
case MONOMORPHIC: |
- if (code->ic_state() != MONOMORPHIC) { |
- Map* map = target()->FindFirstMap(); |
- if (map != NULL) { |
- UpdateMegamorphicCache(map, *name, target()); |
- } |
- } |
set_target(*code); |
break; |
case MEGAMORPHIC: { |
@@ -1007,14 +1000,25 @@ bool IC::UpdatePolymorphicIC(State state, |
target()->FindAllCode(&handlers, receiver_maps.length()); |
} |
- if (!AddOneReceiverMapIfMissing(&receiver_maps, |
- Handle<Map>(receiver->map()))) { |
- return false; |
+ bool overwrote = false; |
danno
2013/05/02 11:36:06
// If the name doesn't match, go generic. Otherwis
Toon Verwaest
2013/05/02 12:27:20
Done.
|
+ Handle<Map> new_receiver_map(receiver->map()); |
+ for (int current = 0; current < receiver_maps.length(); ++current) { |
+ if (!receiver_maps.at(current).is_null() && |
+ receiver_maps.at(current).is_identical_to(new_receiver_map)) { |
+ overwrote = true; |
+ handlers.InsertAt(current, code); |
+ break; |
+ } |
+ } |
danno
2013/05/02 11:36:06
Move this loop about the code above to get the map
Toon Verwaest
2013/05/02 12:27:20
Done.
|
+ |
+ if (!overwrote) { |
+ receiver_maps.Add(new_receiver_map); |
+ handlers.Add(code); |
+ number_of_valid_maps++; |
} |
- handlers.Add(code); |
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); |
return true; |
} |
@@ -1049,6 +1053,7 @@ void IC::CopyICToMegamorphicCache(Handle<String> name) { |
target()->FindAllCode(&handlers, receiver_maps.length()); |
} |
for (int i = 0; i < receiver_maps.length(); i++) { |
+ if (receiver_maps.at(i)->is_deprecated()) continue; |
danno
2013/05/02 11:36:06
Maybe defer this to Crankshaft? Don't throw away t
Toon Verwaest
2013/05/02 12:27:20
Done.
|
UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); |
} |
} |
@@ -1101,38 +1106,9 @@ void IC::PatchCache(State state, |
if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { |
break; |
} |
- } |
- if (target()->type() != Code::NORMAL) { |
- if (target()->is_load_stub()) { |
+ |
+ if (target()->type() != Code::NORMAL) { |
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 +1211,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 |
// GenerateMonomorphicCacheProbe. |
isolate()->stub_cache()->Set(name, map, code); |
@@ -1497,7 +1473,8 @@ Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, |
static bool LookupForWrite(Handle<JSObject> receiver, |
Handle<String> name, |
Handle<Object> value, |
- LookupResult* lookup) { |
+ LookupResult* lookup, |
+ IC::State* state) { |
Handle<JSObject> holder = receiver; |
receiver->Lookup(*name, lookup); |
if (lookup->IsFound()) { |
@@ -1534,7 +1511,13 @@ static bool LookupForWrite(Handle<JSObject> receiver, |
PropertyDetails target_details = |
lookup->GetTransitionDetails(receiver->map()); |
if (target_details.IsReadOnly()) return false; |
- return value->FitsRepresentation(target_details.representation()); |
+ if (!value->FitsRepresentation(target_details.representation())) { |
danno
2013/05/02 11:36:06
Comment this.
Toon Verwaest
2013/05/02 12:27:20
Done.
|
+ Handle<Map> target(lookup->GetTransitionMapFromMap(receiver->map())); |
+ Map::GeneralizeRepresentation( |
+ target, target->LastAdded(), value->OptimalRepresentation()); |
+ *state = MONOMORPHIC_PROTOTYPE_FAILURE; |
danno
2013/05/02 11:36:06
Check for already deprecated maps? Deprecated maps
Toon Verwaest
2013/05/02 12:27:20
Done.
|
+ } |
+ return true; |
} |
@@ -1618,7 +1601,7 @@ MaybeObject* StoreIC::Store(State state, |
} |
LookupResult lookup(isolate()); |
- if (LookupForWrite(receiver, name, value, &lookup)) { |
+ if (LookupForWrite(receiver, name, value, &lookup, &state)) { |
if (FLAG_use_ic) { |
UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
} |