Chromium Code Reviews| Index: src/ic.cc |
| diff --git a/src/ic.cc b/src/ic.cc |
| index c15b76fcea188878a42ae7f502790daa0929dde3..9962eb424ad750dc0b73bfa2ba6877dc2292eb1d 100644 |
| --- a/src/ic.cc |
| +++ b/src/ic.cc |
| @@ -935,6 +935,71 @@ MaybeObject* LoadIC::Load(State state, |
| } |
| +static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
| + Handle<Map> new_receiver_map) { |
| + ASSERT(!new_receiver_map.is_null()); |
| + 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)) { |
| + return false; |
| + } |
| + } |
| + receiver_maps->Add(new_receiver_map); |
| + return true; |
| +} |
| + |
| + |
| +bool IC::UpdatePolymorphicIC(State state, |
| + StrictModeFlag strict_mode, |
| + Handle<JSObject> receiver, |
| + Handle<String> name, |
| + Handle<Code> code) { |
| + if (code->type() == Code::NORMAL) return false; |
| + if (target()->ic_state() == MONOMORPHIC && |
| + target()->type() == Code::NORMAL) { |
| + return false; |
| + } |
| + MapHandleList receiver_maps; |
| + CodeHandleList handlers; |
| + target()->FindAllMaps(&receiver_maps); |
| + int number_of_maps = receiver_maps.length(); |
| + if (number_of_maps == 0 || number_of_maps >= 4) return false; |
| + |
| + target()->FindAllCode(&handlers, receiver_maps.length()); |
| + |
| + if (!AddOneReceiverMapIfMissing(&receiver_maps, |
| + Handle<Map>(receiver->map()))) { |
| + return false; |
| + } |
| + |
| + handlers.Add(code); |
| + Handle<Code> ic = isolate()->stub_cache()->ComputePolymorphicIC( |
| + &receiver_maps, &handlers, name); |
| + set_target(*ic); |
| + return true; |
| +} |
| + |
| + |
| +void LoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, |
| + Handle<Code> handler, |
| + Handle<String> name) { |
| + if (handler->type() == Code::NORMAL) return set_target(*handler); |
| + Handle<Code> ic = isolate()->stub_cache()->ComputeMonomorphicIC( |
| + receiver, handler, name); |
| + set_target(*ic); |
| +} |
| + |
| + |
| +void KeyedLoadIC::UpdateMonomorphicIC(Handle<JSObject> receiver, |
| + Handle<Code> handler, |
| + Handle<String> name) { |
| + if (handler->type() == Code::NORMAL) return set_target(*handler); |
| + Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedMonomorphicIC( |
| + receiver, handler, name); |
| + set_target(*ic); |
| +} |
| + |
| + |
| void IC::PatchCache(State state, |
| StrictModeFlag strict_mode, |
| Handle<JSObject> receiver, |
| @@ -944,17 +1009,23 @@ void IC::PatchCache(State state, |
| case UNINITIALIZED: |
| case PREMONOMORPHIC: |
| case MONOMORPHIC_PROTOTYPE_FAILURE: |
| - set_target(*code); |
| + UpdateMonomorphicIC(receiver, code, name); |
| break; |
| case MONOMORPHIC: |
| // Only move to megamorphic if the target changes. |
| if (target() != *code) { |
| - // We are transitioning from monomorphic to megamorphic case. |
| - // Place the current monomorphic stub and stub compiled for |
| - // the receiver into stub cache. |
| - Map* map = target()->FindFirstMap(); |
| - if (map != NULL) { |
| - UpdateMegamorphicCache(map, *name, target()); |
| + if (target()->is_load_stub()) { |
| + if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { |
| + break; |
| + } |
| + } |
| + // We are transitioning from monomorphic to megamorphic case. Place the |
| + // stub compiled for the receiver into stub cache. |
| + if (target()->is_store_stub()) { |
| + Map* map = target()->FindFirstMap(); |
| + if (map != NULL) { |
| + UpdateMegamorphicCache(map, *name, target()); |
|
Jakob Kummerow
2013/03/01 22:21:04
Don't you want to do this for load stubs too when
Toon Verwaest
2013/03/04 10:54:08
Done.
|
| + } |
| } |
| UpdateMegamorphicCache(receiver->map(), *name, *code); |
| set_target((strict_mode == kStrictMode) |
| @@ -967,14 +1038,26 @@ void IC::PatchCache(State state, |
| UpdateMegamorphicCache(receiver->map(), *name, *code); |
| break; |
| case POLYMORPHIC: |
| - // When trying to patch a polymorphic stub with anything other than |
| - // another polymorphic stub, go generic. |
| - // TODO(verwaest): Currently we always go generic since no polymorphic |
| - // stubs enter this code path. Replace with proper updating once named |
| - // load/store can also be polymorphic. |
| - set_target((strict_mode == kStrictMode) |
| - ? *generic_stub_strict() |
| - : *generic_stub()); |
| + if (target()->is_load_stub()) { |
| + if (UpdatePolymorphicIC(state, strict_mode, receiver, name, code)) { |
| + break; |
| + } |
| + MapHandleList receiver_maps; |
| + CodeHandleList handlers; |
| + target()->FindAllMaps(&receiver_maps); |
| + target()->FindAllCode(&handlers, receiver_maps.length()); |
| + for (int i = 0; i < receiver_maps.length(); i++) { |
| + UpdateMegamorphicCache(*receiver_maps.at(i), *name, *handlers.at(i)); |
| + } |
| + UpdateMegamorphicCache(receiver->map(), *name, *code); |
| + set_target(*megamorphic_stub()); |
| + } else { |
| + // When trying to patch a polymorphic keyed load/store element stub |
|
Jakob Kummerow
2013/03/01 22:21:04
Comment seems inaccurate: We end up here when we t
Toon Verwaest
2013/03/04 10:54:08
The polymorphic stubs that are not load stubs are
|
| + // with anything other than another polymorphic stub, go generic. |
| + set_target((strict_mode == kStrictMode) |
| + ? *generic_stub_strict() |
| + : *generic_stub()); |
| + } |
| break; |
| case DEBUG_STUB: |
| break; |
| @@ -985,6 +1068,42 @@ void IC::PatchCache(State state, |
| } |
| +static void GetReceiverMapsForStub(Handle<Code> stub, |
| + MapHandleList* result) { |
| + ASSERT(stub->is_inline_cache_stub()); |
| + switch (stub->ic_state()) { |
| + case MONOMORPHIC: { |
| + Map* map = stub->FindFirstMap(); |
| + if (map != NULL) { |
| + result->Add(Handle<Map>(map)); |
| + } |
| + break; |
| + } |
| + case POLYMORPHIC: { |
| + AssertNoAllocation no_allocation; |
| + int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| + for (RelocIterator it(*stub, mask); !it.done(); it.next()) { |
| + RelocInfo* info = it.rinfo(); |
| + Handle<Object> object(info->target_object(), stub->GetIsolate()); |
| + if (object->IsString()) break; |
| + ASSERT(object->IsMap()); |
| + AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); |
| + } |
| + break; |
| + } |
| + case MEGAMORPHIC: |
| + break; |
| + case UNINITIALIZED: |
| + case PREMONOMORPHIC: |
| + case MONOMORPHIC_PROTOTYPE_FAILURE: |
| + case GENERIC: |
| + case DEBUG_STUB: |
| + UNREACHABLE(); |
| + break; |
| + } |
| +} |
| + |
| + |
| void LoadIC::UpdateCaches(LookupResult* lookup, |
| State state, |
| Handle<Object> object, |
| @@ -1004,7 +1123,7 @@ void LoadIC::UpdateCaches(LookupResult* lookup, |
| // setting the monomorphic state. |
| code = pre_monomorphic_stub(); |
| } else { |
| - code = ComputeLoadMonomorphic(lookup, receiver, name); |
| + code = ComputeLoadHandler(lookup, receiver, name); |
| if (code.is_null()) return; |
| } |
| @@ -1020,9 +1139,9 @@ void IC::UpdateMegamorphicCache(Map* map, String* name, Code* code) { |
| } |
| -Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup, |
| - Handle<JSObject> receiver, |
| - Handle<String> name) { |
| +Handle<Code> LoadIC::ComputeLoadHandler(LookupResult* lookup, |
| + Handle<JSObject> receiver, |
| + Handle<String> name) { |
| if (!lookup->IsProperty()) { |
| // Nonexistent property. The result is undefined. |
| return isolate()->stub_cache()->ComputeLoadNonexistent(name, receiver); |
| @@ -1051,7 +1170,7 @@ Handle<Code> LoadIC::ComputeLoadMonomorphic(LookupResult* lookup, |
| // property must be found in the receiver for the stub to be |
| // applicable. |
| if (!holder.is_identical_to(receiver)) break; |
| - return isolate()->stub_cache()->ComputeLoadNormal(); |
| + return isolate()->stub_cache()->ComputeLoadNormal(name, receiver); |
| case CALLBACKS: { |
| Handle<Object> callback(lookup->GetCallbackObject(), isolate()); |
| if (callback->IsExecutableAccessorInfo()) { |
| @@ -1107,56 +1226,6 @@ static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) { |
| } |
| -static bool AddOneReceiverMapIfMissing(MapHandleList* receiver_maps, |
| - Handle<Map> new_receiver_map) { |
| - ASSERT(!new_receiver_map.is_null()); |
| - 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)) { |
| - return false; |
| - } |
| - } |
| - receiver_maps->Add(new_receiver_map); |
| - return true; |
| -} |
| - |
| - |
| -static void GetReceiverMapsForStub(Handle<Code> stub, |
| - MapHandleList* result) { |
| - ASSERT(stub->is_inline_cache_stub()); |
| - ASSERT(stub->is_keyed_load_stub() || stub->is_keyed_store_stub()); |
| - switch (stub->ic_state()) { |
| - case MONOMORPHIC: { |
| - Map* map = stub->FindFirstMap(); |
| - if (map != NULL) { |
| - result->Add(Handle<Map>(map)); |
| - } |
| - break; |
| - } |
| - case POLYMORPHIC: { |
| - AssertNoAllocation no_allocation; |
| - int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| - for (RelocIterator it(*stub, mask); !it.done(); it.next()) { |
| - RelocInfo* info = it.rinfo(); |
| - Handle<Object> object(info->target_object(), stub->GetIsolate()); |
| - ASSERT(object->IsMap()); |
| - AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object)); |
| - } |
| - break; |
| - } |
| - case MEGAMORPHIC: |
| - break; |
| - case UNINITIALIZED: |
| - case PREMONOMORPHIC: |
| - case MONOMORPHIC_PROTOTYPE_FAILURE: |
| - case GENERIC: |
| - case DEBUG_STUB: |
| - UNREACHABLE(); |
| - break; |
| - } |
| -} |
| - |
| - |
| Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) { |
| State ic_state = target()->ic_state(); |
| @@ -1268,9 +1337,9 @@ MaybeObject* KeyedLoadIC::Load(State state, |
| } |
| -Handle<Code> KeyedLoadIC::ComputeLoadMonomorphic(LookupResult* lookup, |
| - Handle<JSObject> receiver, |
| - Handle<String> name) { |
| +Handle<Code> KeyedLoadIC::ComputeLoadHandler(LookupResult* lookup, |
| + Handle<JSObject> receiver, |
| + Handle<String> name) { |
| // Bail out if we didn't find a result. |
| if (!lookup->IsProperty()) return Handle<Code>::null(); |