Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index b330038c704a50d8e744835ab8394cc3ba030615..7fdf6be31fbe5f36f53a22182371963d5e212be1 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,14 +1009,18 @@ 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. |
+ 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. |
Map* map = target()->FindFirstMap(); |
if (map != NULL) { |
UpdateMegamorphicCache(map, *name, target()); |
@@ -967,14 +1036,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 |
+ // 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 +1066,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 +1121,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 +1137,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 +1168,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 +1224,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 +1335,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(); |