Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Unified Diff: src/ic.cc

Issue 14611006: Cleanup IC heuristics. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed nit Created 7 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/ic.h ('k') | src/objects.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/ic.cc
diff --git a/src/ic.cc b/src/ic.cc
index 080c7bf1b723f87b1449d4d9da58567ddf6ea9fb..83677bdbcca48abe77358cde401c493920216943 100644
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -182,13 +182,13 @@ 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() ||
+ target->is_keyed_call_stub() ||
+ target->is_keyed_store_stub()) {
+ // Determine whether the failure is due to a name failure.
+ if (!name->IsName()) return false;
+ Name* stub_name = target->FindFirstName();
+ if (Name::cast(name) != stub_name) return false;
}
InlineCacheHolderFlag cache_holder =
@@ -217,10 +217,30 @@ static bool TryRemoveInvalidPrototypeDependentStub(Code* target,
int index = map->IndexInCodeCache(name, target);
if (index >= 0) {
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 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) {
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 +735,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 +758,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: {
@@ -986,14 +988,25 @@ bool IC::UpdatePolymorphicIC(State state,
CodeHandleList handlers;
int number_of_valid_maps;
+ int handler_to_overwrite = -1;
+ Handle<Map> new_receiver_map(receiver->map());
{
AssertNoAllocation no_gc;
target()->FindAllMaps(&receiver_maps);
int number_of_maps = receiver_maps.length();
number_of_valid_maps = number_of_maps;
+
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--;
+ handler_to_overwrite = i;
}
}
@@ -1007,14 +1020,16 @@ bool IC::UpdatePolymorphicIC(State state,
target()->FindAllCode(&handlers, receiver_maps.length());
}
- if (!AddOneReceiverMapIfMissing(&receiver_maps,
- Handle<Map>(receiver->map()))) {
- return false;
+ number_of_valid_maps++;
+ if (handler_to_overwrite >= 0) {
+ 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(
- &receiver_maps, &handlers, number_of_valid_maps + 1, name);
+ &receiver_maps, &handlers, number_of_valid_maps, name);
set_target(*ic);
return true;
}
@@ -1101,38 +1116,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 +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
// GenerateMonomorphicCacheProbe.
isolate()->stub_cache()->Set(name, map, code);
@@ -1497,7 +1483,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 +1521,21 @@ 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 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,
}
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);
}
« no previous file with comments | « src/ic.h ('k') | src/objects.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698