Chromium Code Reviews| Index: src/ic.cc |
| diff --git a/src/ic.cc b/src/ic.cc |
| index e0ebdddf018c0046d83d15f8ab1c0916a84e47ad..c0e5ebf55c9dba02225907c5bb57a7eaa5abafc4 100644 |
| --- a/src/ic.cc |
| +++ b/src/ic.cc |
| @@ -182,6 +182,13 @@ Address IC::OriginalCodeAddress() const { |
| static bool TryRemoveInvalidPrototypeDependentStub(Code* target, |
| Object* receiver, |
| Object* name) { |
| + if (target->type() != Code::NORMAL) { |
|
danno
2013/04/24 15:23:00
Can you please add a comment here why this compare
Toon Verwaest
2013/04/25 10:59:38
Done.
|
| + Map* map = target->FindFirstMap(); |
| + if (map != NULL && map->is_invalid_transition()) { |
| + return true; |
| + } |
| + } |
| + |
| InlineCacheHolderFlag cache_holder = |
| Code::ExtractCacheHolderFromFlags(target->flags()); |
| @@ -505,6 +512,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_invalid_transition()) { |
|
danno
2013/04/24 15:23:00
is_invalid_transition_target or is_invalid. is_dep
Toon Verwaest
2013/04/25 10:59:38
Done.
|
| + 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 +790,13 @@ MaybeObject* KeyedCallIC::LoadFunction(State state, |
| Handle<String>::cast(key)); |
| } |
| + if (object->IsJSObject()) { |
| + Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| + if (receiver->map()->is_invalid_transition()) { |
| + JSObject::MigrateInstance(receiver); |
| + } |
| + } |
| + |
| if (object->IsUndefined() || object->IsNull()) { |
| return TypeError("non_object_property_call", object, key); |
| } |
| @@ -890,6 +911,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_invalid_transition()) { |
| + JSObject::MigrateInstance(receiver); |
| + } |
| + } |
| + |
| // Named lookup in the object. |
| LookupResult lookup(isolate()); |
| LookupForRead(object, name, &lookup); |
| @@ -954,11 +982,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_invalid_transition()) { |
| + 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 +1011,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 +1102,23 @@ void IC::PatchCache(State state, |
| if (target()->type() != Code::NORMAL) { |
| if (target()->is_load_stub()) { |
| CopyICToMegamorphicCache(name); |
| + } else if (target()->is_store_stub()) { |
| + MapHandleList maps; |
|
danno
2013/04/24 15:23:00
Comment that this is special handling that is only
Toon Verwaest
2013/04/25 10:59:38
Done.
|
| + Code* handler = target(); |
| + handler->FindAllMaps(&maps); |
| + for (int i = 0; i < Min(1, maps.length()); i++) { |
| + if (maps.at(i)->is_invalid_transition()) { |
| + 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(); |
| @@ -1158,6 +1211,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup, |
| if (!object->IsJSObject()) return; |
| Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| + |
|
danno
2013/04/24 15:23:00
extraneous whitespace change
Toon Verwaest
2013/04/25 10:59:38
Done.
|
| Handle<Code> code; |
| if (state == UNINITIALIZED) { |
| // This is the first time we execute this inline cache. |
| @@ -1365,6 +1419,10 @@ MaybeObject* KeyedLoadIC::Load(State state, |
| } |
| } else if (object->IsJSObject()) { |
| Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| + if (receiver->map()->is_invalid_transition()) { |
| + JSObject::MigrateInstance(receiver); |
| + } |
| + |
| if (receiver->elements()->map() == |
| isolate()->heap()->non_strict_arguments_elements_map()) { |
| stub = non_strict_arguments_stub(); |
| @@ -1431,6 +1489,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 +1502,10 @@ static bool LookupForWrite(Handle<JSObject> receiver, |
| receiver->LocalLookupRealNamedProperty(*name, lookup); |
| return lookup->IsFound() && |
| !lookup->IsReadOnly() && |
| + lookup->CanStore(value) && |
| lookup->IsCacheable(); |
| } |
| - return true; |
| + return lookup->CanStore(value); |
|
danno
2013/04/24 15:23:00
CanHoldValue?
Toon Verwaest
2013/04/25 10:59:38
Done.
|
| } |
| if (lookup->IsPropertyCallbacks()) return true; |
| @@ -1463,8 +1523,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 +1561,10 @@ MaybeObject* StoreIC::Store(State state, |
| Handle<JSObject> receiver = Handle<JSObject>::cast(object); |
| + if (receiver->map()->is_invalid_transition()) { |
| + JSObject::MigrateInstance(receiver); |
| + } |
| + |
| // Check if the given name is an array index. |
| uint32_t index; |
| if (name->AsArrayIndex(&index)) { |
| @@ -1544,7 +1611,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 +2020,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_invalid_transition()) { |
| + JSObject::MigrateInstance(receiver); |
| + } |
| bool key_is_smi_like = key->IsSmi() || |
| (FLAG_compiled_keyed_stores && !key->ToSmi()->IsFailure()); |
| if (receiver->elements()->map() == |