Index: src/ic.cc |
diff --git a/src/ic.cc b/src/ic.cc |
index f54f0d79ed3acc7bf53e9de9988d81a285be3e76..d5056a9ce8ce3a12c5160ade1fe317383835c3b3 100644 |
--- a/src/ic.cc |
+++ b/src/ic.cc |
@@ -1084,14 +1084,22 @@ MaybeObject* KeyedLoadIC::GetElementStubWithoutMapCheck( |
} |
-MaybeObject* KeyedLoadIC::ConstructMegamorphicStub( |
+MaybeObject* KeyedLoadIC::ComputePolymorphicStub( |
MapList* receiver_maps, |
- CodeList* targets, |
StrictModeFlag strict_mode) { |
+ CodeList handler_ics(receiver_maps->length()); |
+ for (int i = 0; i < receiver_maps->length(); ++i) { |
+ Map* receiver_map(receiver_maps->at(i)); |
+ MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( |
+ receiver_map, strict_mode); |
+ Code* cached_stub; |
+ if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; |
+ handler_ics.Add(cached_stub); |
+ } |
Object* object; |
KeyedLoadStubCompiler compiler; |
- MaybeObject* maybe_code = compiler.CompileLoadMegamorphic(receiver_maps, |
- targets); |
+ MaybeObject* maybe_code = compiler.CompileLoadPolymorphic(receiver_maps, |
+ &handler_ics); |
if (!maybe_code->ToObject(&object)) return maybe_code; |
isolate()->counters()->keyed_load_polymorphic_stubs()->Increment(); |
PROFILE(isolate(), CodeCreateEvent( |
@@ -1625,13 +1633,16 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, |
} else { |
GetReceiverMapsForStub(target(), &target_receiver_maps); |
} |
- Map* new_map = receiver->map(); |
+ bool map_added = |
+ AddOneReceiverMapIfMissing(&target_receiver_maps, receiver->map()); |
if (IsTransitionStubKind(stub_kind)) { |
MaybeObject* maybe_map = ComputeTransitionedMap(receiver, stub_kind); |
+ Map* new_map = NULL; |
if (!maybe_map->To(&new_map)) return maybe_map; |
+ map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map); |
} |
- if (!AddOneReceiverMapIfMissing(&target_receiver_maps, new_map)) { |
- // If the miss wasn't due to an unseen map, a MEGAMORPHIC stub |
+ if (!map_added) { |
+ // If the miss wasn't due to an unseen map, a polymorphic stub |
// won't help, use the generic stub. |
return generic_stub; |
} |
@@ -1652,13 +1663,8 @@ MaybeObject* KeyedIC::ComputeStub(JSObject* receiver, |
ASSERT(maybe_cached_stub->IsCode()); |
return Code::cast(maybe_cached_stub); |
} |
- MaybeObject* maybe_stub = NULL; |
- if (IsTransitionStubKind(stub_kind)) { |
- maybe_stub = ComputePolymorphicStubWithTransition( |
- receiver, &target_receiver_maps, new_map, strict_mode); |
- } else { |
- maybe_stub = ComputePolymorphicStub(&target_receiver_maps, strict_mode); |
- } |
+ MaybeObject* maybe_stub = |
+ ComputePolymorphicStub(&target_receiver_maps, strict_mode); |
Code* stub; |
if (!maybe_stub->To(&stub)) return maybe_stub; |
MaybeObject* maybe_update = cache->Update(&target_receiver_maps, flags, stub); |
@@ -1707,45 +1713,6 @@ MaybeObject* KeyedIC::ComputeMonomorphicStub(JSObject* receiver, |
} |
-MaybeObject* KeyedIC::ComputePolymorphicStubWithTransition( |
- JSObject* receiver, |
- MapList* receiver_maps, |
- Map* new_map, |
- StrictModeFlag strict_mode) { |
- Map* existing_transitionable_map = NULL; |
- for (int i = 0; i < receiver_maps->length(); ++i) { |
- Map* map = receiver_maps->at(i); |
- if (map != receiver->map() && map != new_map) { |
- existing_transitionable_map = map; |
- break; |
- } |
- } |
- KeyedStoreStubCompiler compiler(strict_mode); |
- return compiler.CompileStoreElementWithTransition( |
- new_map, |
- receiver->map(), |
- existing_transitionable_map); |
-} |
- |
- |
-MaybeObject* KeyedIC::ComputePolymorphicStub( |
- MapList* receiver_maps, |
- StrictModeFlag strict_mode) { |
- // Collect MONOMORPHIC stubs for all target_receiver_maps. |
- CodeList handler_ics(receiver_maps->length()); |
- for (int i = 0; i < receiver_maps->length(); ++i) { |
- Map* receiver_map(receiver_maps->at(i)); |
- MaybeObject* maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( |
- receiver_map, strict_mode); |
- Code* cached_stub; |
- if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; |
- handler_ics.Add(cached_stub); |
- } |
- // Build the MEGAMORPHIC stub. |
- return ConstructMegamorphicStub(receiver_maps, &handler_ics, strict_mode); |
-} |
- |
- |
MaybeObject* KeyedIC::ComputeTransitionedMap(JSObject* receiver, |
StubKind stub_kind) { |
switch (stub_kind) { |
@@ -1768,14 +1735,88 @@ MaybeObject* KeyedStoreIC::GetElementStubWithoutMapCheck( |
} |
-MaybeObject* KeyedStoreIC::ConstructMegamorphicStub( |
+// If |map| is contained in |maps_list|, returns |map|; otherwise returns NULL. |
+Map* GetMapIfPresent(Map* map, MapList* maps_list) { |
+ for (int i = 0; i < maps_list->length(); ++i) { |
+ if (maps_list->at(i) == map) return map; |
+ } |
+ return NULL; |
+} |
+ |
+ |
+// Returns the most generic transitioned map for |map| that's found in |
+// |maps_list|, or NULL if no transitioned map for |map| is found at all. |
+Map* GetTransitionedMap(Map* map, MapList* maps_list) { |
+ ElementsKind elements_kind = map->elements_kind(); |
+ if (elements_kind == FAST_ELEMENTS) { |
+ return NULL; |
+ } |
+ if (elements_kind == FAST_DOUBLE_ELEMENTS) { |
+ bool dummy = true; |
+ Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy); |
+ if (fast_map == NULL) return NULL; |
+ return GetMapIfPresent(fast_map, maps_list); |
+ } |
+ if (elements_kind == FAST_SMI_ONLY_ELEMENTS) { |
+ bool dummy = true; |
+ Map* double_map = map->LookupElementsTransitionMap(FAST_DOUBLE_ELEMENTS, |
+ &dummy); |
+ // In the current implementation, if the DOUBLE map doesn't exist, the |
+ // FAST map can't exist either. |
+ if (double_map == NULL) return NULL; |
+ Map* fast_map = map->LookupElementsTransitionMap(FAST_ELEMENTS, &dummy); |
+ if (fast_map == NULL) { |
+ return GetMapIfPresent(double_map, maps_list); |
+ } |
+ // Both double_map and fast_map are non-NULL. Return fast_map if it's in |
+ // maps_list, double_map otherwise. |
+ Map* fast_map_present = GetMapIfPresent(fast_map, maps_list); |
+ if (fast_map_present != NULL) return fast_map_present; |
+ return GetMapIfPresent(double_map, maps_list); |
+ } |
+ return NULL; |
+} |
+ |
+ |
+MaybeObject* KeyedStoreIC::ComputePolymorphicStub( |
MapList* receiver_maps, |
- CodeList* targets, |
StrictModeFlag strict_mode) { |
+ // TODO(yangguo): <remove> |
+ Code* generic_stub = (strict_mode == kStrictMode) |
+ ? isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic_Strict) |
+ : isolate()->builtins()->builtin(Builtins::kKeyedStoreIC_Generic); |
+ // </remove> |
+ |
+ // Collect MONOMORPHIC stubs for all target_receiver_maps. |
+ CodeList handler_ics(receiver_maps->length()); |
+ MapList transitioned_maps(receiver_maps->length()); |
+ for (int i = 0; i < receiver_maps->length(); ++i) { |
+ Map* receiver_map(receiver_maps->at(i)); |
+ MaybeObject* maybe_cached_stub = NULL; |
+ Map* transitioned_map = GetTransitionedMap(receiver_map, receiver_maps); |
+ if (transitioned_map != NULL) { |
+ // TODO(yangguo): Enable this code! |
+ // maybe_cached_stub = FastElementsConversionStub( |
+ // receiver_map->elements_kind(), // original elements_kind |
+ // transitioned_map->elements_kind(), |
+ // receiver_map->instance_type() == JS_ARRAY_TYPE, // is_js_array |
+ // strict_mode_).TryGetCode(); |
+ // TODO(yangguo): <remove> |
+ maybe_cached_stub = generic_stub; |
+ // </remove> |
+ } else { |
+ maybe_cached_stub = ComputeMonomorphicStubWithoutMapCheck( |
+ receiver_map, strict_mode); |
+ } |
+ Code* cached_stub; |
+ if (!maybe_cached_stub->To(&cached_stub)) return maybe_cached_stub; |
+ handler_ics.Add(cached_stub); |
+ transitioned_maps.Add(transitioned_map); |
+ } |
Object* object; |
KeyedStoreStubCompiler compiler(strict_mode); |
- MaybeObject* maybe_code = compiler.CompileStoreMegamorphic(receiver_maps, |
- targets); |
+ MaybeObject* maybe_code = compiler.CompileStorePolymorphic( |
+ receiver_maps, &handler_ics, &transitioned_maps); |
if (!maybe_code->ToObject(&object)) return maybe_code; |
isolate()->counters()->keyed_store_polymorphic_stubs()->Increment(); |
PROFILE(isolate(), CodeCreateEvent( |