Move polymorphic stub computation and compilation to stub cache
authorverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Jan 2013 15:35:43 +0000 (15:35 +0000)
committerverwaest@chromium.org <verwaest@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 23 Jan 2013 15:35:43 +0000 (15:35 +0000)
Review URL: https://chromiumcodereview.appspot.com/11953025

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@13478 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/ic.cc
src/ic.h
src/stub-cache.cc
src/stub-cache.h

index b90436a..b759878 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -830,9 +830,9 @@ MaybeObject* KeyedCallIC::LoadFunction(State state,
 }
 
 
-MaybeObject* IC::Load(State state,
-                      Handle<Object> object,
-                      Handle<String> name) {
+MaybeObject* LoadIC::Load(State state,
+                          Handle<Object> object,
+                          Handle<String> name) {
   // 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()) {
@@ -1086,42 +1086,6 @@ void LoadIC::UpdateLoadCaches(LookupResult* lookup,
 }
 
 
-Handle<Code> KeyedLoadIC::GetElementStubWithoutMapCheck(
-    bool is_js_array,
-    ElementsKind elements_kind,
-    KeyedAccessGrowMode grow_mode) {
-  ASSERT(grow_mode == DO_NOT_ALLOW_JSARRAY_GROWTH);
-  if (IsFastElementsKind(elements_kind) ||
-      IsExternalArrayElementsKind(elements_kind)) {
-    return KeyedLoadFastElementStub(is_js_array, elements_kind).GetCode();
-  } else {
-    ASSERT(elements_kind == DICTIONARY_ELEMENTS);
-    return KeyedLoadDictionaryElementStub().GetCode();
-  }
-}
-
-
-Handle<Code> KeyedLoadIC::ComputePolymorphicStub(
-    MapHandleList* receiver_maps,
-    StrictModeFlag strict_mode,
-    KeyedAccessGrowMode growth_mode) {
-  CodeHandleList handler_ics(receiver_maps->length());
-  for (int i = 0; i < receiver_maps->length(); ++i) {
-    Handle<Map> receiver_map = receiver_maps->at(i);
-    Handle<Code> cached_stub = ComputeMonomorphicStubWithoutMapCheck(
-        receiver_map, strict_mode, growth_mode);
-    handler_ics.Add(cached_stub);
-  }
-  KeyedLoadStubCompiler compiler(isolate());
-  Handle<Code> code = compiler.CompileLoadPolymorphic(
-      receiver_maps, &handler_ics);
-  isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
-  PROFILE(isolate(),
-          CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
-  return code;
-}
-
-
 static Handle<Object> TryConvertKey(Handle<Object> key, Isolate* isolate) {
   // This helper implements a few common fast cases for converting
   // non-smi keys of keyed loads/stores to a smi or a string.
@@ -1142,6 +1106,115 @@ 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());
+  if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
+    switch (stub->ic_state()) {
+      case MONOMORPHIC:
+        result->Add(Handle<Map>(stub->FindFirstMap()));
+        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());
+          ASSERT(object->IsMap());
+          AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
+        }
+        break;
+      }
+      case MEGAMORPHIC:
+      case GENERIC:
+        break;
+      case UNINITIALIZED:
+      case PREMONOMORPHIC:
+      case MONOMORPHIC_PROTOTYPE_FAILURE:
+      case DEBUG_STUB:
+        UNREACHABLE();
+        break;
+    }
+  }
+}
+
+
+Handle<Code> KeyedLoadIC::LoadElementStub(Handle<JSObject> receiver) {
+  State ic_state = target()->ic_state();
+
+  // Don't handle megamorphic property accesses for INTERCEPTORS or CALLBACKS
+  // via megamorphic stubs, since they don't have a map in their relocation info
+  // and so the stubs can't be harvested for the object needed for a map check.
+  if (target()->type() != Code::NORMAL) {
+    TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type");
+    return generic_stub();
+  }
+
+  Handle<Map> receiver_map(receiver->map());
+  MapHandleList target_receiver_maps;
+  if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
+    // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
+    // yet will do so and stay there.
+    return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
+  }
+
+  if (target() == *string_stub()) {
+    target_receiver_maps.Add(isolate()->factory()->string_map());
+  } else {
+    GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
+  }
+
+  // The first time a receiver is seen that is a transitioned version of the
+  // previous monomorphic receiver type, assume the new ElementsKind is the
+  // monomorphic type. This benefits global arrays that only transition
+  // once, and all call sites accessing them are faster if they remain
+  // monomorphic. If this optimistic assumption is not true, the IC will
+  // miss again and it will become polymorphic and support both the
+  // untransitioned and transitioned maps.
+  if (ic_state == MONOMORPHIC &&
+      IsMoreGeneralElementsKindTransition(
+          target_receiver_maps.at(0)->elements_kind(),
+          receiver->GetElementsKind())) {
+    return isolate()->stub_cache()->ComputeKeyedLoadElement(receiver_map);
+  }
+
+  ASSERT(target() != *generic_stub());
+
+  // Determine the list of receiver maps that this call site has seen,
+  // adding the map that was just encountered.
+  if (!AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map)) {
+    // If the miss wasn't due to an unseen map, a polymorphic stub
+    // won't help, use the generic stub.
+    TRACE_GENERIC_IC("KeyedIC", "same map added twice");
+    return generic_stub();
+  }
+
+  // If the maximum number of receiver maps has been exceeded, use the generic
+  // version of the IC.
+  if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
+    TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded");
+    return generic_stub();
+  }
+
+  return isolate()->stub_cache()->ComputeLoadElementPolymorphic(
+      &target_receiver_maps);
+}
+
+
 MaybeObject* KeyedLoadIC::Load(State state,
                                Handle<Object> object,
                                Handle<Object> key,
@@ -1151,7 +1224,7 @@ MaybeObject* KeyedLoadIC::Load(State state,
   key = TryConvertKey(key, isolate());
 
   if (key->IsSymbol()) {
-    return IC::Load(state, object, Handle<String>::cast(key));
+    return LoadIC::Load(state, object, Handle<String>::cast(key));
   }
 
   // Do not use ICs for objects that require access checks (including
@@ -1173,7 +1246,7 @@ MaybeObject* KeyedLoadIC::Load(State state,
         } else if (receiver->HasIndexedInterceptor()) {
           stub = indexed_interceptor_stub();
         } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
-          stub = ComputeStub(receiver, KeyedIC::LOAD, kNonStrictMode, stub);
+          stub = LoadElementStub(receiver);
         }
       }
     } else {
@@ -1311,12 +1384,12 @@ static bool LookupForWrite(Handle<JSObject> receiver,
 }
 
 
-MaybeObject* IC::Store(State state,
-                       StrictModeFlag strict_mode,
-                       Handle<Object> object,
-                       Handle<String> name,
-                       Handle<Object> value,
-                       JSReceiver::StoreFromKeyed store_mode) {
+MaybeObject* StoreIC::Store(State state,
+                            StrictModeFlag strict_mode,
+                            Handle<Object> object,
+                            Handle<String> name,
+                            Handle<Object> value,
+                            JSReceiver::StoreFromKeyed store_mode) {
   // Handle proxies.
   if (object->IsJSProxy()) {
     return JSProxy::cast(*object)->
@@ -1537,59 +1610,9 @@ void StoreIC::UpdateStoreCaches(LookupResult* lookup,
 }
 
 
-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;
-}
-
-
-void KeyedIC::GetReceiverMapsForStub(Handle<Code> stub,
-                                     MapHandleList* result) {
-  ASSERT(stub->is_inline_cache_stub());
-  if (!string_stub().is_null() && stub.is_identical_to(string_stub())) {
-    return result->Add(isolate()->factory()->string_map());
-  } else if (stub->is_keyed_load_stub() || stub->is_keyed_store_stub()) {
-    switch (stub->ic_state()) {
-      case MONOMORPHIC:
-        result->Add(Handle<Map>(stub->FindFirstMap()));
-        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());
-          ASSERT(object->IsMap());
-          AddOneReceiverMapIfMissing(result, Handle<Map>::cast(object));
-        }
-        break;
-      }
-      case MEGAMORPHIC:
-      case GENERIC:
-        break;
-      case UNINITIALIZED:
-      case PREMONOMORPHIC:
-      case MONOMORPHIC_PROTOTYPE_FAILURE:
-      case DEBUG_STUB:
-        UNREACHABLE();
-        break;
-    }
-  }
-}
-
-
-Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver,
-                                  StubKind stub_kind,
-                                  StrictModeFlag strict_mode,
-                                  Handle<Code> generic_stub) {
+Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
+                                            StubKind stub_kind,
+                                            StrictModeFlag strict_mode) {
   State ic_state = target()->ic_state();
   KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind)
       ? ALLOW_JSARRAY_GROWTH
@@ -1600,65 +1623,61 @@ Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver,
   // and so the stubs can't be harvested for the object needed for a map check.
   if (target()->type() != Code::NORMAL) {
     TRACE_GENERIC_IC("KeyedIC", "non-NORMAL target type");
-    return generic_stub;
+    return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
   }
 
-  bool monomorphic = false;
-  bool is_transition_stub = IsTransitionStubKind(stub_kind);
   Handle<Map> receiver_map(receiver->map());
-  Handle<Map> monomorphic_map = receiver_map;
   MapHandleList target_receiver_maps;
   if (ic_state == UNINITIALIZED || ic_state == PREMONOMORPHIC) {
     // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
     // yet will do so and stay there.
-    monomorphic = true;
-  } else {
-    GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
-    if (ic_state == MONOMORPHIC && (is_transition_stub || stub_kind == LOAD)) {
-      // The first time a receiver is seen that is a transitioned version of the
-      // previous monomorphic receiver type, assume the new ElementsKind is the
-      // monomorphic type. This benefits global arrays that only transition
-      // once, and all call sites accessing them are faster if they remain
-      // monomorphic. If this optimistic assumption is not true, the IC will
-      // miss again and it will become polymorphic and support both the
-      // untransitioned and transitioned maps.
-      monomorphic = IsMoreGeneralElementsKindTransition(
+    stub_kind = GetNoTransitionStubKind(stub_kind);
+    return isolate()->stub_cache()->ComputeKeyedStoreElement(
+        receiver_map, stub_kind, strict_mode, grow_mode);
+  }
+
+  GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
+  // The first time a receiver is seen that is a transitioned version of the
+  // previous monomorphic receiver type, assume the new ElementsKind is the
+  // monomorphic type. This benefits global arrays that only transition
+  // once, and all call sites accessing them are faster if they remain
+  // monomorphic. If this optimistic assumption is not true, the IC will
+  // miss again and it will become polymorphic and support both the
+  // untransitioned and transitioned maps.
+  if (ic_state == MONOMORPHIC &&
+      IsTransitionStubKind(stub_kind) &&
+      IsMoreGeneralElementsKindTransition(
           target_receiver_maps.at(0)->elements_kind(),
-          receiver->GetElementsKind());
-    }
+          receiver->GetElementsKind())) {
+    Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, stub_kind);
+    ASSERT(*monomorphic_map != *receiver_map);
+    stub_kind = GetNoTransitionStubKind(stub_kind);
+    return isolate()->stub_cache()->ComputeKeyedStoreElement(
+        monomorphic_map, stub_kind, strict_mode, grow_mode);
   }
 
-  if (monomorphic) {
-    if (is_transition_stub) {
-      monomorphic_map = ComputeTransitionedMap(receiver, stub_kind);
-      ASSERT(*monomorphic_map != *receiver_map);
-      stub_kind = GetNoTransitionStubKind(stub_kind);
-    }
-    return ComputeMonomorphicStub(
-        monomorphic_map, stub_kind, strict_mode, generic_stub);
-  }
-  ASSERT(target() != *generic_stub);
+  ASSERT(target() != *generic_stub() && target() != *generic_stub_strict());
 
-  // Determine the list of receiver maps that this call site has seen,
-  // adding the map that was just encountered.
   bool map_added =
       AddOneReceiverMapIfMissing(&target_receiver_maps, receiver_map);
+
   if (IsTransitionStubKind(stub_kind)) {
     Handle<Map> new_map = ComputeTransitionedMap(receiver, stub_kind);
     map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps, new_map);
   }
+
   if (!map_added) {
     // If the miss wasn't due to an unseen map, a polymorphic stub
     // won't help, use the generic stub.
     TRACE_GENERIC_IC("KeyedIC", "same map added twice");
-    return generic_stub;
+    return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
   }
 
   // If the maximum number of receiver maps has been exceeded, use the generic
   // version of the IC.
   if (target_receiver_maps.length() > kMaxKeyedPolymorphism) {
     TRACE_GENERIC_IC("KeyedIC", "max polymorph exceeded");
-    return generic_stub;
+    return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
   }
 
   if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) ==
@@ -1666,81 +1685,34 @@ Handle<Code> KeyedIC::ComputeStub(Handle<JSObject> receiver,
     grow_mode = ALLOW_JSARRAY_GROWTH;
   }
 
-  Handle<PolymorphicCodeCache> cache =
-      isolate()->factory()->polymorphic_code_cache();
-  Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode,
-                                                             strict_mode);
-  Code::Flags flags = Code::ComputeFlags(kind(), POLYMORPHIC, extra_state);
-  Handle<Object> probe = cache->Lookup(&target_receiver_maps, flags);
-  if (probe->IsCode()) return Handle<Code>::cast(probe);
-
-  Handle<Code> stub =
-      ComputePolymorphicStub(&target_receiver_maps, strict_mode, grow_mode);
-  PolymorphicCodeCache::Update(cache, &target_receiver_maps, flags, stub);
-  return stub;
-}
-
-
-Handle<Code> KeyedIC::ComputeMonomorphicStubWithoutMapCheck(
-    Handle<Map> receiver_map,
-    StrictModeFlag strict_mode,
-    KeyedAccessGrowMode grow_mode) {
-  if ((receiver_map->instance_type() & kNotStringTag) == 0) {
-    ASSERT(!string_stub().is_null());
-    return string_stub();
-  } else {
-    ASSERT(receiver_map->has_dictionary_elements() ||
-           receiver_map->has_fast_smi_or_object_elements() ||
-           receiver_map->has_fast_double_elements() ||
-           receiver_map->has_external_array_elements());
-    bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
-    return GetElementStubWithoutMapCheck(is_js_array,
-                                         receiver_map->elements_kind(),
-                                         grow_mode);
-  }
-}
-
-
-Handle<Code> KeyedIC::ComputeMonomorphicStub(Handle<Map> receiver_map,
-                                             StubKind stub_kind,
-                                             StrictModeFlag strict_mode,
-                                             Handle<Code> generic_stub) {
-  ElementsKind elements_kind = receiver_map->elements_kind();
-  if (IsFastElementsKind(elements_kind) ||
-      IsExternalArrayElementsKind(elements_kind) ||
-      IsDictionaryElementsKind(elements_kind)) {
-    return isolate()->stub_cache()->ComputeKeyedLoadOrStoreElement(
-        receiver_map, stub_kind, strict_mode);
-  } else {
-    return generic_stub;
-  }
+  return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
+      &target_receiver_maps, grow_mode, strict_mode);
 }
 
 
-Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver,
-                                            StubKind stub_kind) {
+Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
+                                                 StubKind stub_kind) {
   switch (stub_kind) {
-    case KeyedIC::STORE_TRANSITION_SMI_TO_OBJECT:
-    case KeyedIC::STORE_TRANSITION_DOUBLE_TO_OBJECT:
-    case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
-    case KeyedIC::STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
+    case STORE_TRANSITION_SMI_TO_OBJECT:
+    case STORE_TRANSITION_DOUBLE_TO_OBJECT:
+    case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
+    case STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT:
       return JSObject::GetElementsTransitionMap(receiver, FAST_ELEMENTS);
-    case KeyedIC::STORE_TRANSITION_SMI_TO_DOUBLE:
-    case KeyedIC::STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
+    case STORE_TRANSITION_SMI_TO_DOUBLE:
+    case STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE:
       return JSObject::GetElementsTransitionMap(receiver, FAST_DOUBLE_ELEMENTS);
-    case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
-    case KeyedIC::STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
-    case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
-    case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
+    case STORE_TRANSITION_HOLEY_SMI_TO_OBJECT:
+    case STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
+    case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT:
+    case STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT:
       return JSObject::GetElementsTransitionMap(receiver,
                                                 FAST_HOLEY_ELEMENTS);
-    case KeyedIC::STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
-    case KeyedIC::STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
+    case STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE:
+    case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
       return JSObject::GetElementsTransitionMap(receiver,
                                                 FAST_HOLEY_DOUBLE_ELEMENTS);
-    case KeyedIC::LOAD:
-    case KeyedIC::STORE_NO_TRANSITION:
-    case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
+    case STORE_NO_TRANSITION:
+    case STORE_AND_GROW_NO_TRANSITION:
       UNREACHABLE();
       break;
   }
@@ -1748,60 +1720,9 @@ Handle<Map> KeyedIC::ComputeTransitionedMap(Handle<JSObject> receiver,
 }
 
 
-Handle<Code> KeyedStoreIC::GetElementStubWithoutMapCheck(
-    bool is_js_array,
-    ElementsKind elements_kind,
-    KeyedAccessGrowMode grow_mode) {
-  return KeyedStoreElementStub(is_js_array, elements_kind, grow_mode).GetCode();
-}
-
-
-Handle<Code> KeyedStoreIC::ComputePolymorphicStub(
-    MapHandleList* receiver_maps,
-    StrictModeFlag strict_mode,
-    KeyedAccessGrowMode grow_mode) {
-  // Collect MONOMORPHIC stubs for all target_receiver_maps.
-  CodeHandleList handler_ics(receiver_maps->length());
-  MapHandleList transitioned_maps(receiver_maps->length());
-  for (int i = 0; i < receiver_maps->length(); ++i) {
-    Handle<Map> receiver_map(receiver_maps->at(i));
-    Handle<Code> cached_stub;
-    Handle<Map> transitioned_map =
-        receiver_map->FindTransitionedMap(receiver_maps);
-
-    // TODO(mvstanton): The code below is doing pessimistic elements
-    // transitions. I would like to stop doing that and rely on Allocation Site
-    // Tracking to do a better job of ensuring the data types are what they need
-    // to be. Not all the elements are in place yet, pessimistic elements
-    // transitions are still important for performance.
-    if (!transitioned_map.is_null()) {
-      cached_stub = ElementsTransitionAndStoreStub(
-          receiver_map->elements_kind(),  // original elements_kind
-          transitioned_map->elements_kind(),
-          receiver_map->instance_type() == JS_ARRAY_TYPE,  // is_js_array
-          strict_mode, grow_mode).GetCode();
-    } else {
-      cached_stub = ComputeMonomorphicStubWithoutMapCheck(receiver_map,
-                                                          strict_mode,
-                                                          grow_mode);
-    }
-    ASSERT(!cached_stub.is_null());
-    handler_ics.Add(cached_stub);
-    transitioned_maps.Add(transitioned_map);
-  }
-  KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
-  Handle<Code> code = compiler.CompileStorePolymorphic(
-      receiver_maps, &handler_ics, &transitioned_maps);
-  isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
-  PROFILE(isolate(),
-          CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
-  return code;
-}
-
-
-KeyedIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver,
-                                            Handle<Object> key,
-                                            Handle<Object> value) {
+KeyedStoreIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver,
+                                                 Handle<Object> key,
+                                                 Handle<Object> value) {
   ASSERT(key->IsSmi());
   int index = Smi::cast(*key)->value();
   bool allow_growth = receiver->IsJSArray() &&
@@ -1877,12 +1798,12 @@ MaybeObject* KeyedStoreIC::Store(State state,
 
   if (key->IsSymbol()) {
     Handle<String> name = Handle<String>::cast(key);
-    return IC::Store(state,
-                     strict_mode,
-                     object,
-                     name,
-                     value,
-                     JSReceiver::MAY_BE_STORE_FROM_KEYED);
+    return StoreIC::Store(state,
+                          strict_mode,
+                          object,
+                          name,
+                          value,
+                          JSReceiver::MAY_BE_STORE_FROM_KEYED);
   }
 
   // Do not use ICs for objects that require access checks (including
@@ -1904,7 +1825,7 @@ MaybeObject* KeyedStoreIC::Store(State state,
       } else if (miss_mode != MISS_FORCE_GENERIC) {
         if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
           StubKind stub_kind = GetStubKind(receiver, key, value);
-          stub = ComputeStub(receiver, stub_kind, strict_mode, stub);
+          stub = StoreElementStub(receiver, stub_kind, strict_mode);
         }
       } else {
         TRACE_GENERIC_IC("KeyedStoreIC", "force generic");
index 784512a..aeb58bf 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -132,63 +132,7 @@ class IC {
   static inline JSObject* GetCodeCacheHolder(Object* object,
                                              InlineCacheHolderFlag holder);
 
-  MUST_USE_RESULT MaybeObject* Load(State state,
-                                    Handle<Object> object,
-                                    Handle<String> name);
-
-  MUST_USE_RESULT MaybeObject* Store(
-      State state,
-      StrictModeFlag strict_mode,
-      Handle<Object> object,
-      Handle<String> name,
-      Handle<Object> value,
-      JSReceiver::StoreFromKeyed store_mode =
-          JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
-
  protected:
-  virtual Handle<Code> pre_monomorphic_stub() {
-    UNREACHABLE();
-    return Handle<Code>::null();
-  }
-  virtual Handle<Code> megamorphic_stub() {
-    UNREACHABLE();
-    return Handle<Code>::null();
-  }
-  virtual Handle<Code> megamorphic_stub_strict() {
-    UNREACHABLE();
-    return Handle<Code>::null();
-  }
-  virtual Handle<Code> generic_stub() const {
-    UNREACHABLE();
-    return Handle<Code>::null();
-  }
-  virtual Code::Kind kind() const {
-    UNREACHABLE();
-    return Code::STUB;
-  }
-  virtual Handle<Code> global_proxy_stub() {
-    UNREACHABLE();
-    return Handle<Code>::null();
-  }
-  virtual Handle<Code> global_proxy_stub_strict() {
-    UNREACHABLE();
-    return Handle<Code>::null();
-  }
-
-  virtual void UpdateLoadCaches(LookupResult* lookup,
-                                State state,
-                                Handle<Object> object,
-                                Handle<String> name) {
-    UNREACHABLE();
-  }
-  virtual void UpdateStoreCaches(LookupResult* lookup,
-                                 State state,
-                                 StrictModeFlag strict_mode,
-                                 Handle<JSObject> receiver,
-                                 Handle<String> name,
-                                 Handle<Object> value) {
-    UNREACHABLE();
-  }
   Address fp() const { return fp_; }
   Address pc() const { return *pc_address_; }
   Isolate* isolate() const { return isolate_; }
@@ -376,7 +320,7 @@ class KeyedCallIC: public CallICBase {
 class LoadIC: public IC {
  public:
   explicit LoadIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
-    ASSERT(target()->is_load_stub());
+    ASSERT(target()->is_load_stub() || target()->is_keyed_load_stub());
   }
 
   // Code generator routines.
@@ -392,9 +336,18 @@ class LoadIC: public IC {
   static void GenerateArrayLength(MacroAssembler* masm);
   static void GenerateFunctionPrototype(MacroAssembler* masm);
 
+  MUST_USE_RESULT MaybeObject* Load(State state,
+                                    Handle<Object> object,
+                                    Handle<String> name);
+
  protected:
   virtual Code::Kind kind() const { return Code::LOAD_IC; }
 
+  virtual Handle<Code> generic_stub() const {
+    UNREACHABLE();
+    return Handle<Code>::null();
+  }
+
   virtual Handle<Code> megamorphic_stub() {
     return isolate()->builtins()->LoadIC_Megamorphic();
   }
@@ -421,119 +374,15 @@ class LoadIC: public IC {
 };
 
 
-class KeyedIC: public IC {
- public:
-  enum StubKind {
-    LOAD,
-    STORE_NO_TRANSITION,
-    STORE_TRANSITION_SMI_TO_OBJECT,
-    STORE_TRANSITION_SMI_TO_DOUBLE,
-    STORE_TRANSITION_DOUBLE_TO_OBJECT,
-    STORE_TRANSITION_HOLEY_SMI_TO_OBJECT,
-    STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE,
-    STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT,
-    STORE_AND_GROW_NO_TRANSITION,
-    STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT,
-    STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE,
-    STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT,
-    STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT,
-    STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE,
-    STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT
-  };
-
-  static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
-      STORE_NO_TRANSITION;
-  STATIC_ASSERT(kGrowICDelta ==
-                STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT -
-                STORE_TRANSITION_SMI_TO_OBJECT);
-  STATIC_ASSERT(kGrowICDelta ==
-                STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE -
-                STORE_TRANSITION_SMI_TO_DOUBLE);
-  STATIC_ASSERT(kGrowICDelta ==
-                STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT -
-                STORE_TRANSITION_DOUBLE_TO_OBJECT);
-
-  explicit KeyedIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {}
-  virtual ~KeyedIC() {}
-
-  static inline KeyedAccessGrowMode GetGrowModeFromStubKind(
-      StubKind stub_kind) {
-    return (stub_kind >= STORE_AND_GROW_NO_TRANSITION)
-        ? ALLOW_JSARRAY_GROWTH
-        : DO_NOT_ALLOW_JSARRAY_GROWTH;
-  }
-
-  static inline StubKind GetGrowStubKind(StubKind stub_kind) {
-    ASSERT(stub_kind != LOAD);
-    if (stub_kind < STORE_AND_GROW_NO_TRANSITION) {
-      stub_kind = static_cast<StubKind>(static_cast<int>(stub_kind) +
-                                        kGrowICDelta);
-    }
-    return stub_kind;
-  }
-
-  virtual Handle<Code> GetElementStubWithoutMapCheck(
-      bool is_js_array,
-      ElementsKind elements_kind,
-      KeyedAccessGrowMode grow_mode) = 0;
-
- protected:
-  virtual Handle<Code> string_stub() {
-    return Handle<Code>::null();
-  }
-
-  Handle<Code> ComputeStub(Handle<JSObject> receiver,
-                           StubKind stub_kind,
-                           StrictModeFlag strict_mode,
-                           Handle<Code> default_stub);
-
-  virtual Handle<Code> ComputePolymorphicStub(
-      MapHandleList* receiver_maps,
-      StrictModeFlag strict_mode,
-      KeyedAccessGrowMode grow_mode) = 0;
-
-  Handle<Code> ComputeMonomorphicStubWithoutMapCheck(
-      Handle<Map> receiver_map,
-      StrictModeFlag strict_mode,
-      KeyedAccessGrowMode grow_mode);
-
- private:
-  void GetReceiverMapsForStub(Handle<Code> stub, MapHandleList* result);
-
-  Handle<Code> ComputeMonomorphicStub(Handle<Map> receiver_map,
-                                      StubKind stub_kind,
-                                      StrictModeFlag strict_mode,
-                                      Handle<Code> default_stub);
-
-  Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
-                                     StubKind stub_kind);
-
-  static bool IsTransitionStubKind(StubKind stub_kind) {
-    return stub_kind > STORE_NO_TRANSITION &&
-        stub_kind != STORE_AND_GROW_NO_TRANSITION;
-  }
-
-  static bool IsGrowStubKind(StubKind stub_kind) {
-    return stub_kind >= STORE_AND_GROW_NO_TRANSITION;
-  }
-
-  static StubKind GetNoTransitionStubKind(StubKind stub_kind) {
-    if (!IsTransitionStubKind(stub_kind)) return stub_kind;
-    if (IsGrowStubKind(stub_kind)) return STORE_AND_GROW_NO_TRANSITION;
-    return STORE_NO_TRANSITION;
-  }
-};
-
-
 enum ICMissMode {
   MISS_FORCE_GENERIC,
   MISS
 };
 
 
-class KeyedLoadIC: public KeyedIC {
+class KeyedLoadIC: public LoadIC {
  public:
-  explicit KeyedLoadIC(Isolate* isolate) : KeyedIC(isolate) {
+  explicit KeyedLoadIC(Isolate* isolate) : LoadIC(isolate) {
     ASSERT(target()->is_keyed_load_stub());
   }
 
@@ -563,14 +412,11 @@ class KeyedLoadIC: public KeyedIC {
   static const int kSlowCaseBitFieldMask =
       (1 << Map::kIsAccessCheckNeeded) | (1 << Map::kHasIndexedInterceptor);
 
-  virtual Handle<Code> GetElementStubWithoutMapCheck(
-      bool is_js_array,
-      ElementsKind elements_kind,
-      KeyedAccessGrowMode grow_mode);
-
  protected:
   virtual Code::Kind kind() const { return Code::KEYED_LOAD_IC; }
 
+  Handle<Code> LoadElementStub(Handle<JSObject> receiver);
+
   virtual Handle<Code> megamorphic_stub() {
     return isolate()->builtins()->KeyedLoadIC_Generic();
   }
@@ -578,14 +424,6 @@ class KeyedLoadIC: public KeyedIC {
     return isolate()->builtins()->KeyedLoadIC_Generic();
   }
 
-  virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
-                                              StrictModeFlag strict_mode,
-                                              KeyedAccessGrowMode grow_mode);
-
-  virtual Handle<Code> string_stub() {
-    return isolate()->builtins()->KeyedLoadIC_String();
-  }
-
   // Update the inline cache.
   virtual void UpdateLoadCaches(LookupResult* lookup,
                                 State state,
@@ -606,6 +444,9 @@ class KeyedLoadIC: public KeyedIC {
   Handle<Code> non_strict_arguments_stub() {
     return isolate()->builtins()->KeyedLoadIC_NonStrictArguments();
   }
+  Handle<Code> string_stub() {
+    return isolate()->builtins()->KeyedLoadIC_String();
+  }
 
   static void Clear(Address address, Code* target);
 
@@ -616,7 +457,7 @@ class KeyedLoadIC: public KeyedIC {
 class StoreIC: public IC {
  public:
   explicit StoreIC(Isolate* isolate) : IC(NO_EXTRA_FRAME, isolate) {
-    ASSERT(target()->is_store_stub());
+    ASSERT(target()->is_store_stub() || target()->is_keyed_store_stub());
   }
 
   // Code generators for stub routines. Only called once at startup.
@@ -629,6 +470,15 @@ class StoreIC: public IC {
   static void GenerateGlobalProxy(MacroAssembler* masm,
                                   StrictModeFlag strict_mode);
 
+  MUST_USE_RESULT MaybeObject* Store(
+      State state,
+      StrictModeFlag strict_mode,
+      Handle<Object> object,
+      Handle<String> name,
+      Handle<Object> value,
+      JSReceiver::StoreFromKeyed store_mode =
+          JSReceiver::CERTAINLY_NOT_STORE_FROM_KEYED);
+
  protected:
   virtual Code::Kind kind() const { return Code::STORE_IC; }
   virtual Handle<Code> megamorphic_stub() {
@@ -687,9 +537,46 @@ enum KeyedStoreIncrementLength {
 };
 
 
-class KeyedStoreIC: public KeyedIC {
+class KeyedStoreIC: public StoreIC {
  public:
-  explicit KeyedStoreIC(Isolate* isolate) : KeyedIC(isolate) {
+  enum StubKind {
+    STORE_NO_TRANSITION,
+    STORE_TRANSITION_SMI_TO_OBJECT,
+    STORE_TRANSITION_SMI_TO_DOUBLE,
+    STORE_TRANSITION_DOUBLE_TO_OBJECT,
+    STORE_TRANSITION_HOLEY_SMI_TO_OBJECT,
+    STORE_TRANSITION_HOLEY_SMI_TO_DOUBLE,
+    STORE_TRANSITION_HOLEY_DOUBLE_TO_OBJECT,
+    STORE_AND_GROW_NO_TRANSITION,
+    STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT,
+    STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE,
+    STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT,
+    STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_OBJECT,
+    STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE,
+    STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT
+  };
+
+  static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
+      STORE_NO_TRANSITION;
+  STATIC_ASSERT(kGrowICDelta ==
+                STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT -
+                STORE_TRANSITION_SMI_TO_OBJECT);
+  STATIC_ASSERT(kGrowICDelta ==
+                STORE_AND_GROW_TRANSITION_SMI_TO_DOUBLE -
+                STORE_TRANSITION_SMI_TO_DOUBLE);
+  STATIC_ASSERT(kGrowICDelta ==
+                STORE_AND_GROW_TRANSITION_DOUBLE_TO_OBJECT -
+                STORE_TRANSITION_DOUBLE_TO_OBJECT);
+
+  static inline StubKind GetGrowStubKind(StubKind stub_kind) {
+    if (stub_kind < STORE_AND_GROW_NO_TRANSITION) {
+      stub_kind = static_cast<StubKind>(static_cast<int>(stub_kind) +
+                                        kGrowICDelta);
+    }
+    return stub_kind;
+  }
+
+  explicit KeyedStoreIC(Isolate* isolate) : StoreIC(isolate) {
     ASSERT(target()->is_keyed_store_stub());
   }
 
@@ -713,18 +600,9 @@ class KeyedStoreIC: public KeyedIC {
   static void GenerateTransitionElementsSmiToDouble(MacroAssembler* masm);
   static void GenerateTransitionElementsDoubleToObject(MacroAssembler* masm);
 
-  virtual Handle<Code> GetElementStubWithoutMapCheck(
-      bool is_js_array,
-      ElementsKind elements_kind,
-      KeyedAccessGrowMode grow_mode);
-
  protected:
   virtual Code::Kind kind() const { return Code::KEYED_STORE_IC; }
 
-  virtual Handle<Code> ComputePolymorphicStub(MapHandleList* receiver_maps,
-                                              StrictModeFlag strict_mode,
-                                              KeyedAccessGrowMode grow_mode);
-
   // Update the inline cache.
   virtual void UpdateStoreCaches(LookupResult* lookup,
                                  State state,
@@ -740,6 +618,10 @@ class KeyedStoreIC: public KeyedIC {
     return isolate()->builtins()->KeyedStoreIC_Generic_Strict();
   }
 
+  Handle<Code> StoreElementStub(Handle<JSObject> receiver,
+                                StubKind stub_kind,
+                                StrictModeFlag strict_mode);
+
  private:
   void set_target(Code* code) {
     // Strict mode must be preserved across IC patching.
@@ -771,6 +653,24 @@ class KeyedStoreIC: public KeyedIC {
                        Handle<Object> key,
                        Handle<Object> value);
 
+  static bool IsTransitionStubKind(StubKind stub_kind) {
+    return stub_kind > STORE_NO_TRANSITION &&
+        stub_kind != STORE_AND_GROW_NO_TRANSITION;
+  }
+
+  static bool IsGrowStubKind(StubKind stub_kind) {
+    return stub_kind >= STORE_AND_GROW_NO_TRANSITION;
+  }
+
+  static StubKind GetNoTransitionStubKind(StubKind stub_kind) {
+    if (!IsTransitionStubKind(stub_kind)) return stub_kind;
+    if (IsGrowStubKind(stub_kind)) return STORE_AND_GROW_NO_TRANSITION;
+    return STORE_NO_TRANSITION;
+  }
+
+  Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
+                                     StubKind stub_kind);
+
   friend class IC;
 };
 
index 08954ba..73272a2 100644 (file)
@@ -371,69 +371,48 @@ Handle<Code> StubCache::ComputeStoreField(Handle<String> name,
 }
 
 
-Handle<Code> StubCache::ComputeKeyedLoadOrStoreElement(
+Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
+  Code::Flags flags =
+      Code::ComputeMonomorphicFlags(Code::KEYED_LOAD_IC, Code::NORMAL);
+  Handle<String> name =
+      isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
+
+  Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
+  if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+  KeyedLoadStubCompiler compiler(isolate());
+  Handle<Code> code = compiler.CompileLoadElement(receiver_map);
+
+  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
+  Map::UpdateCodeCache(receiver_map, name, code);
+  return code;
+}
+
+
+Handle<Code> StubCache::ComputeKeyedStoreElement(
     Handle<Map> receiver_map,
-    KeyedIC::StubKind stub_kind,
-    StrictModeFlag strict_mode) {
-  KeyedAccessGrowMode grow_mode =
-      KeyedIC::GetGrowModeFromStubKind(stub_kind);
+    KeyedStoreIC::StubKind stub_kind,
+    StrictModeFlag strict_mode,
+    KeyedAccessGrowMode grow_mode) {
   Code::ExtraICState extra_state =
       Code::ComputeExtraICState(grow_mode, strict_mode);
-  Code::Flags flags =
-      Code::ComputeMonomorphicFlags(
-          stub_kind == KeyedIC::LOAD ? Code::KEYED_LOAD_IC
-                                     : Code::KEYED_STORE_IC,
-          Code::NORMAL,
-          extra_state);
-  Handle<String> name;
-  switch (stub_kind) {
-    case KeyedIC::LOAD:
-      name = isolate()->factory()->KeyedLoadElementMonomorphic_symbol();
-      break;
-    case KeyedIC::STORE_NO_TRANSITION:
-      name = isolate()->factory()->KeyedStoreElementMonomorphic_symbol();
-      break;
-    case KeyedIC::STORE_AND_GROW_NO_TRANSITION:
-      name = isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
-      break;
-    default:
-      UNREACHABLE();
-      break;
-  }
+  Code::Flags flags = Code::ComputeMonomorphicFlags(
+      Code::KEYED_STORE_IC, Code::NORMAL, extra_state);
+
+  ASSERT(stub_kind == KeyedStoreIC::STORE_NO_TRANSITION ||
+         stub_kind == KeyedStoreIC::STORE_AND_GROW_NO_TRANSITION);
+
+  Handle<String> name = stub_kind == KeyedStoreIC::STORE_NO_TRANSITION
+      ? isolate()->factory()->KeyedStoreElementMonomorphic_symbol()
+      : isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_symbol();
+
   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
-  Handle<Code> code;
-  switch (stub_kind) {
-    case KeyedIC::LOAD: {
-      KeyedLoadStubCompiler compiler(isolate_);
-      code = compiler.CompileLoadElement(receiver_map);
-      break;
-    }
-    case KeyedIC::STORE_AND_GROW_NO_TRANSITION: {
-      KeyedStoreStubCompiler compiler(isolate_, strict_mode,
-                                      ALLOW_JSARRAY_GROWTH);
-      code = compiler.CompileStoreElement(receiver_map);
-      break;
-    }
-    case KeyedIC::STORE_NO_TRANSITION: {
-      KeyedStoreStubCompiler compiler(isolate_, strict_mode,
-                                      DO_NOT_ALLOW_JSARRAY_GROWTH);
-      code = compiler.CompileStoreElement(receiver_map);
-      break;
-    }
-    default:
-      UNREACHABLE();
-      break;
-  }
-
-  ASSERT(!code.is_null());
+  KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
+  Handle<Code> code = compiler.CompileStoreElement(receiver_map);
 
-  if (stub_kind == KeyedIC::LOAD) {
-    PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_LOAD_IC_TAG, *code, 0));
-  } else {
-    PROFILE(isolate_, CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
-  }
+  PROFILE(isolate(), CodeCreateEvent(Logger::KEYED_STORE_IC_TAG, *code, 0));
   Map::UpdateCodeCache(receiver_map, name, code);
   return code;
 }
@@ -851,6 +830,41 @@ Handle<Code> StubCache::ComputeCallMiss(int argc,
 }
 
 
+Handle<Code> StubCache::ComputeLoadElementPolymorphic(
+    MapHandleList* receiver_maps) {
+  Code::Flags flags = Code::ComputeFlags(Code::KEYED_LOAD_IC, POLYMORPHIC);
+  Handle<PolymorphicCodeCache> cache =
+      isolate_->factory()->polymorphic_code_cache();
+  Handle<Object> probe = cache->Lookup(receiver_maps, flags);
+  if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+  KeyedLoadStubCompiler compiler(isolate_);
+  Handle<Code> code = compiler.CompileLoadElementPolymorphic(receiver_maps);
+  PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
+  return code;
+}
+
+
+Handle<Code> StubCache::ComputeStoreElementPolymorphic(
+    MapHandleList* receiver_maps,
+    KeyedAccessGrowMode grow_mode,
+    StrictModeFlag strict_mode) {
+  Handle<PolymorphicCodeCache> cache =
+      isolate_->factory()->polymorphic_code_cache();
+  Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode,
+                                                             strict_mode);
+  Code::Flags flags =
+      Code::ComputeFlags(Code::KEYED_STORE_IC, POLYMORPHIC, extra_state);
+  Handle<Object> probe = cache->Lookup(receiver_maps, flags);
+  if (probe->IsCode()) return Handle<Code>::cast(probe);
+
+  KeyedStoreStubCompiler compiler(isolate_, strict_mode, grow_mode);
+  Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
+  PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
+  return code;
+}
+
+
 #ifdef ENABLE_DEBUGGER_SUPPORT
 Handle<Code> StubCache::ComputeCallDebugBreak(int argc,
                                               Code::Kind kind) {
@@ -1366,6 +1380,40 @@ Handle<Code> KeyedLoadStubCompiler::GetCode(Code::StubType type,
 }
 
 
+Handle<Code> KeyedLoadStubCompiler::CompileLoadElementPolymorphic(
+    MapHandleList* receiver_maps) {
+  CodeHandleList handler_ics(receiver_maps->length());
+  for (int i = 0; i < receiver_maps->length(); ++i) {
+    Handle<Map> receiver_map = receiver_maps->at(i);
+    Handle<Code> cached_stub;
+
+    if ((receiver_map->instance_type() & kNotStringTag) == 0) {
+      cached_stub = isolate()->builtins()->KeyedLoadIC_String();
+    } else {
+      bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+      ElementsKind elements_kind = receiver_map->elements_kind();
+
+      if (IsFastElementsKind(elements_kind) ||
+          IsExternalArrayElementsKind(elements_kind)) {
+        cached_stub =
+            KeyedLoadFastElementStub(is_js_array, elements_kind).GetCode();
+      } else {
+        ASSERT(elements_kind == DICTIONARY_ELEMENTS);
+        cached_stub = KeyedLoadDictionaryElementStub().GetCode();
+      }
+    }
+
+    handler_ics.Add(cached_stub);
+  }
+  Handle<Code> code = CompileLoadPolymorphic(receiver_maps, &handler_ics);
+  isolate()->counters()->keyed_load_polymorphic_stubs()->Increment();
+  PROFILE(isolate(),
+          CodeCreateEvent(Logger::KEYED_LOAD_POLYMORPHIC_IC_TAG, *code, 0));
+  return code;
+}
+
+
+
 Handle<Code> StoreStubCompiler::GetCode(Code::StubType type,
                                         Handle<String> name) {
   Code::Flags flags =
@@ -1391,6 +1439,50 @@ Handle<Code> KeyedStoreStubCompiler::GetCode(Code::StubType type,
 }
 
 
+Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
+    MapHandleList* receiver_maps) {
+  // Collect MONOMORPHIC stubs for all |receiver_maps|.
+  CodeHandleList handler_ics(receiver_maps->length());
+  MapHandleList transitioned_maps(receiver_maps->length());
+  for (int i = 0; i < receiver_maps->length(); ++i) {
+    Handle<Map> receiver_map(receiver_maps->at(i));
+    Handle<Code> cached_stub;
+    Handle<Map> transitioned_map =
+        receiver_map->FindTransitionedMap(receiver_maps);
+
+    // TODO(mvstanton): The code below is doing pessimistic elements
+    // transitions. I would like to stop doing that and rely on Allocation Site
+    // Tracking to do a better job of ensuring the data types are what they need
+    // to be. Not all the elements are in place yet, pessimistic elements
+    // transitions are still important for performance.
+    bool is_js_array = receiver_map->instance_type() == JS_ARRAY_TYPE;
+    ElementsKind elements_kind = receiver_map->elements_kind();
+    if (!transitioned_map.is_null()) {
+      cached_stub = ElementsTransitionAndStoreStub(
+          elements_kind,
+          transitioned_map->elements_kind(),
+          is_js_array,
+          strict_mode_,
+          grow_mode_).GetCode();
+    } else {
+      cached_stub = KeyedStoreElementStub(
+          is_js_array,
+          elements_kind,
+          grow_mode_).GetCode();
+    }
+    ASSERT(!cached_stub.is_null());
+    handler_ics.Add(cached_stub);
+    transitioned_maps.Add(transitioned_map);
+  }
+  Handle<Code> code =
+      CompileStorePolymorphic(receiver_maps, &handler_ics, &transitioned_maps);
+  isolate()->counters()->keyed_store_polymorphic_stubs()->Increment();
+  PROFILE(isolate(),
+          CodeCreateEvent(Logger::KEYED_STORE_POLYMORPHIC_IC_TAG, *code, 0));
+  return code;
+}
+
+
 void KeyedStoreStubCompiler::GenerateStoreDictionaryElement(
     MacroAssembler* masm) {
   KeyedStoreIC::GenerateSlow(masm);
index 2b12321..b26519c 100644 (file)
@@ -172,9 +172,12 @@ class StubCache {
                                       Handle<Map> transition,
                                       StrictModeFlag strict_mode);
 
-  Handle<Code> ComputeKeyedLoadOrStoreElement(Handle<Map> receiver_map,
-                                              KeyedIC::StubKind stub_kind,
-                                              StrictModeFlag strict_mode);
+  Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
+
+  Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
+                                        KeyedStoreIC::StubKind stub_kind,
+                                        StrictModeFlag strict_mode,
+                                        KeyedAccessGrowMode grow_mode);
 
   // ---
 
@@ -234,6 +237,13 @@ class StubCache {
                                Code::Kind kind,
                                Code::ExtraICState state);
 
+  // ---
+
+  Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
+  Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
+                                              KeyedAccessGrowMode grow_mode,
+                                              StrictModeFlag strict_mode);
+
   // Finds the Code object stored in the Heap::non_monomorphic_cache().
   Code* FindCallInitialize(int argc, RelocInfo::Mode mode, Code::Kind kind);
 
@@ -666,6 +676,8 @@ class KeyedLoadStubCompiler: public StubCompiler {
   Handle<Code> CompileLoadPolymorphic(MapHandleList* receiver_maps,
                                       CodeHandleList* handler_ics);
 
+  Handle<Code> CompileLoadElementPolymorphic(MapHandleList* receiver_maps);
+
   static void GenerateLoadDictionaryElement(MacroAssembler* masm);
 
  private:
@@ -733,6 +745,8 @@ class KeyedStoreStubCompiler: public StubCompiler {
                                        CodeHandleList* handler_stubs,
                                        MapHandleList* transitioned_maps);
 
+  Handle<Code> CompileStoreElementPolymorphic(MapHandleList* receiver_maps);
+
   static void GenerateStoreFastElement(MacroAssembler* masm,
                                        bool is_js_array,
                                        ElementsKind element_kind,