Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index e0ebdddf018c0046d83d15f8ab1c0916a84e47ad..56877a5eae5ab836cb4b57a1a4e3f45d74f9fea1 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -182,6 +182,15 @@ 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; |
+ } |
+ } |
+ |
InlineCacheHolderFlag cache_holder = |
Code::ExtractCacheHolderFromFlags(target->flags()); |
@@ -505,6 +514,13 @@ MaybeObject* CallICBase::LoadFunction(State state, |
Code::ExtraICState extra_ic_state, |
Handle<Object> object, |
Handle<String> name) { |
+ if (object->IsJSObject()) { |
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (receiver->map()->is_deprecated()) { |
+ JSObject::MigrateInstance(receiver); |
+ } |
+ } |
+ |
// If the object is undefined or null it's illegal to try to get any |
// of its properties; throw a TypeError in that case. |
if (object->IsUndefined() || object->IsNull()) { |
@@ -776,6 +792,13 @@ MaybeObject* KeyedCallIC::LoadFunction(State state, |
Handle<String>::cast(key)); |
} |
+ if (object->IsJSObject()) { |
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (receiver->map()->is_deprecated()) { |
+ JSObject::MigrateInstance(receiver); |
+ } |
+ } |
+ |
if (object->IsUndefined() || object->IsNull()) { |
return TypeError("non_object_property_call", object, key); |
} |
@@ -890,6 +913,13 @@ MaybeObject* LoadIC::Load(State state, |
return Runtime::GetElementOrCharAtOrFail(isolate(), object, index); |
} |
+ if (object->IsJSObject()) { |
+ Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (receiver->map()->is_deprecated()) { |
+ JSObject::MigrateInstance(receiver); |
+ } |
+ } |
+ |
// Named lookup in the object. |
LookupResult lookup(isolate()); |
LookupForRead(object, name, &lookup); |
@@ -954,11 +984,19 @@ bool IC::UpdatePolymorphicIC(State state, |
MapHandleList receiver_maps; |
CodeHandleList handlers; |
+ int number_of_valid_maps; |
{ |
AssertNoAllocation no_gc; |
target()->FindAllMaps(&receiver_maps); |
int number_of_maps = receiver_maps.length(); |
- if (number_of_maps >= 4) return false; |
+ number_of_valid_maps = number_of_maps; |
+ for (int i = 0; i < number_of_maps; i++) { |
+ if (receiver_maps.at(i)->is_deprecated()) { |
+ number_of_valid_maps--; |
+ } |
+ } |
+ |
+ if (number_of_valid_maps >= 4) return false; |
// Only allow 0 maps in case target() was reset to UNINITIALIZED by the GC. |
// In that case, allow the IC to go back monomorphic. |
@@ -975,7 +1013,7 @@ bool IC::UpdatePolymorphicIC(State state, |
handlers.Add(code); |
Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( |
- &receiver_maps, &handlers, name); |
+ &receiver_maps, &handlers, number_of_valid_maps + 1, name); |
set_target(*ic); |
return true; |
} |
@@ -1066,6 +1104,28 @@ void IC::PatchCache(State state, |
if (target()->type() != Code::NORMAL) { |
if (target()->is_load_stub()) { |
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(); |
@@ -1365,6 +1425,10 @@ MaybeObject* KeyedLoadIC::Load(State state, |
} |
} else if (object->IsJSObject()) { |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (receiver->map()->is_deprecated()) { |
+ JSObject::MigrateInstance(receiver); |
+ } |
+ |
if (receiver->elements()->map() == |
isolate()->heap()->non_strict_arguments_elements_map()) { |
stub = non_strict_arguments_stub(); |
@@ -1431,6 +1495,7 @@ Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, |
static bool LookupForWrite(Handle<JSObject> receiver, |
Handle<String> name, |
+ Handle<Object> value, |
LookupResult* lookup) { |
Handle<JSObject> holder = receiver; |
receiver->Lookup(*name, lookup); |
@@ -1443,9 +1508,10 @@ static bool LookupForWrite(Handle<JSObject> receiver, |
receiver->LocalLookupRealNamedProperty(*name, lookup); |
return lookup->IsFound() && |
!lookup->IsReadOnly() && |
+ lookup->CanHoldValue(value) && |
lookup->IsCacheable(); |
} |
- return true; |
+ return lookup->CanHoldValue(value); |
} |
if (lookup->IsPropertyCallbacks()) return true; |
@@ -1463,8 +1529,11 @@ static bool LookupForWrite(Handle<JSObject> receiver, |
// chain check. This avoids a double lookup, but requires us to pass in the |
// receiver when trying to fetch extra information from the transition. |
receiver->map()->LookupTransition(*holder, *name, lookup); |
- return lookup->IsTransition() && |
- !lookup->GetTransitionDetails(receiver->map()).IsReadOnly(); |
+ if (!lookup->IsTransition()) return false; |
+ PropertyDetails target_details = |
+ lookup->GetTransitionDetails(receiver->map()); |
+ if (target_details.IsReadOnly()) return false; |
+ return value->FitsRepresentation(target_details.representation()); |
} |
@@ -1498,6 +1567,10 @@ MaybeObject* StoreIC::Store(State state, |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (receiver->map()->is_deprecated()) { |
+ JSObject::MigrateInstance(receiver); |
+ } |
+ |
// Check if the given name is an array index. |
uint32_t index; |
if (name->AsArrayIndex(&index)) { |
@@ -1544,7 +1617,7 @@ MaybeObject* StoreIC::Store(State state, |
} |
LookupResult lookup(isolate()); |
- if (LookupForWrite(receiver, name, &lookup)) { |
+ if (LookupForWrite(receiver, name, value, &lookup)) { |
if (FLAG_use_ic) { |
UpdateCaches(&lookup, state, strict_mode, receiver, name, value); |
} |
@@ -1953,6 +2026,9 @@ MaybeObject* KeyedStoreIC::Store(State state, |
if (miss_mode != MISS_FORCE_GENERIC) { |
if (object->IsJSObject()) { |
Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
+ if (receiver->map()->is_deprecated()) { |
+ JSObject::MigrateInstance(receiver); |
+ } |
bool key_is_smi_like = key->IsSmi() || |
(FLAG_compiled_keyed_stores && !key->ToSmi()->IsFailure()); |
if (receiver->elements()->map() == |