Unify grow mode and stub kind
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Mar 2013 21:51:07 +0000 (21:51 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 6 Mar 2013 21:51:07 +0000 (21:51 +0000)
In the process, ensure that transition-causing element stores handle all cases of the transitioned receiver map.

Review URL: https://codereview.chromium.org/12390031

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

15 files changed:
src/arm/stub-cache-arm.cc
src/code-stubs.cc
src/code-stubs.h
src/heap.h
src/ia32/stub-cache-ia32.cc
src/ic.cc
src/ic.h
src/mips/stub-cache-mips.cc
src/objects.h
src/stub-cache.cc
src/stub-cache.h
src/type-info.cc
src/type-info.h
src/x64/stub-cache-x64.cc
test/mjsunit/elements-kind.js

index a01b81b4a37090fffcf60809f09a3727699ae072..f30706ea889e27ab81e38824bcbaefef7014050e 100644 (file)
@@ -3064,7 +3064,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
   Handle<Code> stub =
       KeyedStoreElementStub(is_js_array,
                             elements_kind,
-                            grow_mode_).GetCode(isolate());
+                            store_mode_).GetCode(isolate());
 
   __ DispatchMap(r2, r3, receiver_map, stub, DO_SMI_CHECK);
 
@@ -3722,7 +3722,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
     MacroAssembler* masm,
     bool is_js_array,
     ElementsKind elements_kind,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- r0    : value
   //  -- r1    : key
@@ -3762,7 +3762,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
   }
   // Compare smis.
   __ cmp(key_reg, scratch);
-  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (is_js_array && IsGrowStoreMode(store_mode)) {
     __ b(hs, &grow);
   } else {
     __ b(hs, &miss_force_generic);
@@ -3815,7 +3815,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   __ Jump(ic_miss, RelocInfo::CODE_TARGET);
 
-  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (is_js_array && IsGrowStoreMode(store_mode)) {
     // Grow the array by a single element if possible.
     __ bind(&grow);
 
@@ -3887,7 +3887,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
     MacroAssembler* masm,
     bool is_js_array,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- r0    : value
   //  -- r1    : key
@@ -3933,7 +3933,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
   // Compare smis, unsigned compare catches both negative and out-of-bound
   // indexes.
   __ cmp(key_reg, scratch1);
-  if (grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (IsGrowStoreMode(store_mode)) {
     __ b(hs, &grow);
   } else {
     __ b(hs, &miss_force_generic);
@@ -3961,7 +3961,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   __ Jump(ic_miss, RelocInfo::CODE_TARGET);
 
-  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (is_js_array && IsGrowStoreMode(store_mode)) {
     // Grow the array by a single element if possible.
     __ bind(&grow);
 
index 52d463f3a00b0493afd94d61b9b9a221565f5dea..95bc1e99cc9f29789f2a36812c8253cff9c150ab 100644 (file)
@@ -442,14 +442,14 @@ void KeyedStoreElementStub::Generate(MacroAssembler* masm) {
       KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
                                                        is_js_array_,
                                                        elements_kind_,
-                                                       grow_mode_);
+                                                       store_mode_);
     }
       break;
     case FAST_DOUBLE_ELEMENTS:
     case FAST_HOLEY_DOUBLE_ELEMENTS:
       KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
                                                              is_js_array_,
-                                                             grow_mode_);
+                                                             store_mode_);
       break;
     case EXTERNAL_BYTE_ELEMENTS:
     case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
@@ -593,13 +593,13 @@ void ElementsTransitionAndStoreStub::Generate(MacroAssembler* masm) {
       KeyedStoreStubCompiler::GenerateStoreFastElement(masm,
                                                        is_jsarray_,
                                                        to_,
-                                                       grow_mode_);
+                                                       store_mode_);
     } else if (IsFastSmiElementsKind(from_) &&
                IsFastDoubleElementsKind(to_)) {
       ElementsTransitionGenerator::GenerateSmiToDouble(masm, mode, &fail);
       KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(masm,
                                                              is_jsarray_,
-                                                             grow_mode_);
+                                                             store_mode_);
     } else if (IsFastDoubleElementsKind(from_)) {
       ASSERT(to_ == FAST_HOLEY_DOUBLE_ELEMENTS);
       ElementsTransitionGenerator::
index 9c8225ea459d449fa6809a13253425671e3af984..8591adbea0d3c3c8322f52d7740c331cd88abd08 100644 (file)
@@ -1400,31 +1400,31 @@ class KeyedStoreElementStub : public PlatformCodeStub {
  public:
   KeyedStoreElementStub(bool is_js_array,
                         ElementsKind elements_kind,
-                        KeyedAccessGrowMode grow_mode)
+                        KeyedAccessStoreMode store_mode)
       : is_js_array_(is_js_array),
         elements_kind_(elements_kind),
-        grow_mode_(grow_mode),
+        store_mode_(store_mode),
         fp_registers_(CanUseFPRegisters()) { }
 
   Major MajorKey() { return KeyedStoreElement; }
   int MinorKey() {
     return ElementsKindBits::encode(elements_kind_) |
         IsJSArrayBits::encode(is_js_array_) |
-        GrowModeBits::encode(grow_mode_) |
+        StoreModeBits::encode(store_mode_) |
         FPRegisters::encode(fp_registers_);
   }
 
   void Generate(MacroAssembler* masm);
 
  private:
-  class ElementsKindBits: public BitField<ElementsKind,    0, 8> {};
-  class GrowModeBits: public BitField<KeyedAccessGrowMode, 8, 1> {};
-  class IsJSArrayBits: public BitField<bool,               9, 1> {};
-  class FPRegisters: public BitField<bool,                10, 1> {};
+  class ElementsKindBits: public BitField<ElementsKind,      0, 8> {};
+  class StoreModeBits: public BitField<KeyedAccessStoreMode, 8, 4> {};
+  class IsJSArrayBits: public BitField<bool,                12, 1> {};
+  class FPRegisters: public BitField<bool,                  13, 1> {};
 
   bool is_js_array_;
   ElementsKind elements_kind_;
-  KeyedAccessGrowMode grow_mode_;
+  KeyedAccessStoreMode store_mode_;
   bool fp_registers_;
 
   DISALLOW_COPY_AND_ASSIGN(KeyedStoreElementStub);
@@ -1507,19 +1507,19 @@ class ElementsTransitionAndStoreStub : public PlatformCodeStub {
                                  ElementsKind to,
                                  bool is_jsarray,
                                  StrictModeFlag strict_mode,
-                                 KeyedAccessGrowMode grow_mode)
+                                 KeyedAccessStoreMode store_mode)
       : from_(from),
         to_(to),
         is_jsarray_(is_jsarray),
         strict_mode_(strict_mode),
-        grow_mode_(grow_mode) {}
+        store_mode_(store_mode) {}
 
  private:
-  class FromBits:       public BitField<ElementsKind,      0, 8> {};
-  class ToBits:         public BitField<ElementsKind,      8, 8> {};
-  class IsJSArrayBits:  public BitField<bool,              16, 1> {};
-  class StrictModeBits: public BitField<StrictModeFlag,    17, 1> {};
-  class GrowModeBits: public BitField<KeyedAccessGrowMode, 18, 1> {};
+  class FromBits:       public BitField<ElementsKind,        0, 8> {};
+  class ToBits:         public BitField<ElementsKind,        8, 8> {};
+  class IsJSArrayBits:  public BitField<bool,                16, 1> {};
+  class StrictModeBits: public BitField<StrictModeFlag,      17, 1> {};
+  class StoreModeBits: public BitField<KeyedAccessStoreMode, 18, 4> {};
 
   Major MajorKey() { return ElementsTransitionAndStore; }
   int MinorKey() {
@@ -1527,7 +1527,7 @@ class ElementsTransitionAndStoreStub : public PlatformCodeStub {
         ToBits::encode(to_) |
         IsJSArrayBits::encode(is_jsarray_) |
         StrictModeBits::encode(strict_mode_) |
-        GrowModeBits::encode(grow_mode_);
+        StoreModeBits::encode(store_mode_);
   }
 
   void Generate(MacroAssembler* masm);
@@ -1536,7 +1536,7 @@ class ElementsTransitionAndStoreStub : public PlatformCodeStub {
   ElementsKind to_;
   bool is_jsarray_;
   StrictModeFlag strict_mode_;
-  KeyedAccessGrowMode grow_mode_;
+  KeyedAccessStoreMode store_mode_;
 
   DISALLOW_COPY_AND_ASSIGN(ElementsTransitionAndStoreStub);
 };
index f79b0eabb71132bbcda0ce10439e53e41bbc16f7..5b4c55c3a78a252502419ac979cf36dca969e0bc 100644 (file)
@@ -226,8 +226,6 @@ namespace internal {
     "KeyedLoadElementMonomorphic")                                       \
   V(KeyedStoreElementMonomorphic_string,                                 \
     "KeyedStoreElementMonomorphic")                                      \
-  V(KeyedStoreAndGrowElementMonomorphic_string,                          \
-    "KeyedStoreAndGrowElementMonomorphic")                               \
   V(stack_overflow_string, "kStackOverflowBoilerplate")                  \
   V(illegal_access_string, "illegal access")                             \
   V(out_of_memory_string, "out-of-memory")                               \
@@ -266,7 +264,7 @@ namespace internal {
   V(infinity_string, "Infinity")                                         \
   V(minus_infinity_string, "-Infinity")                                  \
   V(hidden_stack_trace_string, "v8::hidden_stack_trace")                 \
-  V(query_colon_string, "(?:)")                                          \
+  V(query_colon_string, "(?:)")
 
 // Forward declarations.
 class GCTracer;
index af433a4242c0d38187a29b6e9c194a3246f2027f..d0b7881496ef0f3c80b78be9f7e41dab1b97163a 100644 (file)
@@ -2883,7 +2883,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
   Handle<Code> stub =
       KeyedStoreElementStub(is_jsarray,
                             elements_kind,
-                            grow_mode_).GetCode(isolate());
+                            store_mode_).GetCode(isolate());
 
   __ DispatchMap(edx, receiver_map, stub, DO_SMI_CHECK);
 
@@ -3538,7 +3538,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
     MacroAssembler* masm,
     bool is_js_array,
     ElementsKind elements_kind,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- eax    : value
   //  -- ecx    : key
@@ -3563,7 +3563,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
   if (is_js_array) {
     // Check that the key is within bounds.
     __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // smis.
-    if (grow_mode == ALLOW_JSARRAY_GROWTH) {
+    if (IsGrowStoreMode(store_mode)) {
       __ j(above_equal, &grow);
     } else {
       __ j(above_equal, &miss_force_generic);
@@ -3615,7 +3615,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   __ jmp(ic_miss, RelocInfo::CODE_TARGET);
 
-  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (is_js_array && IsGrowStoreMode(store_mode)) {
     // Handle transition requiring the array to grow.
     __ bind(&grow);
 
@@ -3693,7 +3693,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
     MacroAssembler* masm,
     bool is_js_array,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- eax    : value
   //  -- ecx    : key
@@ -3716,7 +3716,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
   if (is_js_array) {
     // Check that the key is within bounds.
     __ cmp(ecx, FieldOperand(edx, JSArray::kLengthOffset));  // smis.
-    if (grow_mode == ALLOW_JSARRAY_GROWTH) {
+    if (IsGrowStoreMode(store_mode)) {
       __ j(above_equal, &grow);
     } else {
       __ j(above_equal, &miss_force_generic);
@@ -3743,7 +3743,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   __ jmp(ic_miss, RelocInfo::CODE_TARGET);
 
-  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (is_js_array && IsGrowStoreMode(store_mode)) {
     // Handle transition requiring the array to grow.
     __ bind(&grow);
 
index 866fcce0c690ded60456f6c5afb3ad8660924a73..f69d79a9ab70d2ef72d3552d124523d299359b45 100644 (file)
--- a/src/ic.cc
+++ b/src/ic.cc
@@ -59,6 +59,17 @@ char IC::TransitionMarkFromState(IC::State state) {
   return 0;
 }
 
+
+const char* GetTransitionMarkModifier(KeyedAccessStoreMode mode) {
+  if (mode == STORE_NO_TRANSITION_HANDLE_COW) return ".COW";
+  if (mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
+    return ".IGNORE_OOB";
+  }
+  if (IsGrowStoreMode(mode)) return ".GROW";
+  return "";
+}
+
+
 void IC::TraceIC(const char* type,
                  Handle<Object> name,
                  State old_state,
@@ -81,13 +92,13 @@ void IC::TraceIC(const char* type,
       }
     }
     JavaScriptFrame::PrintTop(isolate, stdout, false, true);
-    bool new_can_grow =
-        Code::GetKeyedAccessGrowMode(new_target->extra_ic_state()) ==
-        ALLOW_JSARRAY_GROWTH;
+    Code::ExtraICState state = new_target->extra_ic_state();
+    const char* modifier =
+        GetTransitionMarkModifier(Code::GetKeyedAccessStoreMode(state));
     PrintF(" (%c->%c%s)",
            TransitionMarkFromState(old_state),
            TransitionMarkFromState(new_state),
-           new_can_grow ? ".GROW" : "");
+           modifier);
     name->Print();
     PrintF("]\n");
   }
@@ -1634,13 +1645,8 @@ Handle<Code> StoreIC::ComputeStoreMonomorphic(LookupResult* lookup,
 
 
 Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
-                                            StubKind stub_kind,
+                                            KeyedAccessStoreMode store_mode,
                                             StrictModeFlag strict_mode) {
-  State ic_state = target()->ic_state();
-  KeyedAccessGrowMode grow_mode = IsGrowStubKind(stub_kind)
-      ? ALLOW_JSARRAY_GROWTH
-      : DO_NOT_ALLOW_JSARRAY_GROWTH;
-
   // 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.
@@ -1649,42 +1655,76 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
     return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
   }
 
+  if ((store_mode == STORE_NO_TRANSITION_HANDLE_COW ||
+       store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS)) {
+    // TODO(danno): We'll soon handle MONOMORPHIC ICs that also support
+    // copying COW arrays and silently ignoring some OOB stores into external
+    // arrays, but for now use the generic.
+    TRACE_GENERIC_IC(isolate(), "KeyedIC", "COW/OOB external array");
+    return strict_mode == kStrictMode
+        ? generic_stub_strict()
+        : generic_stub();
+  }
+
+  State ic_state = target()->ic_state();
   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.
-    Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, stub_kind);
-    stub_kind = GetNoTransitionStubKind(stub_kind);
+    Handle<Map> monomorphic_map = ComputeTransitionedMap(receiver, store_mode);
+    store_mode = GetNonTransitioningStoreMode(store_mode);
     return isolate()->stub_cache()->ComputeKeyedStoreElement(
-        monomorphic_map, stub_kind, strict_mode, grow_mode);
+        monomorphic_map, strict_mode, store_mode);
   }
 
-  GetReceiverMapsForStub(Handle<Code>(target()), &target_receiver_maps);
+  MapHandleList target_receiver_maps;
+  target()->FindAllMaps(&target_receiver_maps);
   if (target_receiver_maps.length() == 0) {
-    // Optimistically assume that ICs that haven't reached the MONOMORPHIC state
-    // yet will do so and stay there.
-    stub_kind = GetNoTransitionStubKind(stub_kind);
-    return isolate()->stub_cache()->ComputeKeyedStoreElement(
-        receiver_map, stub_kind, strict_mode, grow_mode);
+    // In the case that there is a non-map-specific IC is installed (e.g. keyed
+    // stores into properties in dictionary mode), then there will be not
+    // receiver maps in the target.
+    return strict_mode == kStrictMode
+        ? generic_stub_strict()
+        : generic_stub();
   }
-  // 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())) {
-    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);
+
+  // There are several special cases where an IC that is MONOMORPHIC can still
+  // transition to a different GetNonTransitioningStoreMode IC that handles a
+  // superset of the original IC. Handle those here if the receiver map hasn't
+  // changed or it has transitioned to a more general kind.
+  KeyedAccessStoreMode old_store_mode =
+      Code::GetKeyedAccessStoreMode(target()->extra_ic_state());
+  Handle<Map> previous_receiver_map = target_receiver_maps.at(0);
+  if (ic_state == MONOMORPHIC && old_store_mode == STANDARD_STORE) {
+      // If the "old" and "new" maps are in the same elements map family, stay
+      // MONOMORPHIC and use the map for the most generic ElementsKind.
+    Handle<Map> transitioned_receiver_map = receiver_map;
+    if (IsTransitionStoreMode(store_mode)) {
+      transitioned_receiver_map =
+          ComputeTransitionedMap(receiver, store_mode);
+    }
+    ElementsKind transitioned_kind =
+        transitioned_receiver_map->elements_kind();
+    bool more_general_transition =
+        IsMoreGeneralElementsKindTransition(
+            previous_receiver_map->elements_kind(),
+            transitioned_kind);
+    Map* transitioned_previous_map = more_general_transition
+        ? previous_receiver_map->LookupElementsTransitionMap(transitioned_kind)
+        : NULL;
+    if (transitioned_previous_map == *transitioned_receiver_map) {
+      // Element family is the same, use the "worst" case map.
+      store_mode = GetNonTransitioningStoreMode(store_mode);
+      return isolate()->stub_cache()->ComputeKeyedStoreElement(
+          transitioned_receiver_map, strict_mode, store_mode);
+    } else if (*previous_receiver_map == receiver->map()) {
+      if (IsGrowStoreMode(store_mode)) {
+        // A "normal" IC that handles stores can switch to a version that can
+        // grow at the end of the array and still stay MONOMORPHIC.
+        return isolate()->stub_cache()->ComputeKeyedStoreElement(
+            receiver_map, strict_mode, store_mode);
+      }
+    }
   }
 
   ASSERT(ic_state != GENERIC);
@@ -1692,9 +1732,11 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
   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 (IsTransitionStoreMode(store_mode)) {
+    Handle<Map> transitioned_receiver_map =
+        ComputeTransitionedMap(receiver, store_mode);
+    map_added |= AddOneReceiverMapIfMissing(&target_receiver_maps,
+                                            transitioned_receiver_map);
   }
 
   if (!map_added) {
@@ -1711,19 +1753,29 @@ Handle<Code> KeyedStoreIC::StoreElementStub(Handle<JSObject> receiver,
     return strict_mode == kStrictMode ? generic_stub_strict() : generic_stub();
   }
 
-  if ((Code::GetKeyedAccessGrowMode(target()->extra_ic_state()) ==
-       ALLOW_JSARRAY_GROWTH)) {
-    grow_mode = ALLOW_JSARRAY_GROWTH;
+  // Make sure all polymorphic handlers have the same store mode, otherwise the
+  // generic stub must be used.
+  store_mode = GetNonTransitioningStoreMode(store_mode);
+  if (old_store_mode != STANDARD_STORE) {
+    if (store_mode == STANDARD_STORE) {
+      store_mode = old_store_mode;
+    } else if (store_mode != old_store_mode) {
+      TRACE_GENERIC_IC(isolate(), "KeyedIC", "store mode mismatch");
+      return strict_mode == kStrictMode
+          ? generic_stub_strict()
+          : generic_stub();
+    }
   }
 
   return isolate()->stub_cache()->ComputeStoreElementPolymorphic(
-      &target_receiver_maps, grow_mode, strict_mode);
+      &target_receiver_maps, store_mode, strict_mode);
 }
 
 
-Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
-                                                 StubKind stub_kind) {
-  switch (stub_kind) {
+Handle<Map> KeyedStoreIC::ComputeTransitionedMap(
+    Handle<JSObject> receiver,
+    KeyedAccessStoreMode store_mode) {
+  switch (store_mode) {
     case STORE_TRANSITION_SMI_TO_OBJECT:
     case STORE_TRANSITION_DOUBLE_TO_OBJECT:
     case STORE_AND_GROW_TRANSITION_SMI_TO_OBJECT:
@@ -1742,7 +1794,11 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
     case STORE_AND_GROW_TRANSITION_HOLEY_SMI_TO_DOUBLE:
       return JSObject::GetElementsTransitionMap(receiver,
                                                 FAST_HOLEY_DOUBLE_ELEMENTS);
-    case STORE_NO_TRANSITION:
+    case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
+      ASSERT(receiver->map()->has_external_array_elements());
+      // Fall through
+    case STORE_NO_TRANSITION_HANDLE_COW:
+    case STANDARD_STORE:
     case STORE_AND_GROW_NO_TRANSITION:
       return Handle<Map>(receiver->map());
   }
@@ -1750,15 +1806,23 @@ Handle<Map> KeyedStoreIC::ComputeTransitionedMap(Handle<JSObject> receiver,
 }
 
 
-KeyedStoreIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver,
-                                                 Handle<Object> key,
-                                                 Handle<Object> value) {
+bool IsOutOfBoundsAccess(Handle<JSObject> receiver,
+                         int index) {
+  if (receiver->IsJSArray()) {
+    return JSArray::cast(*receiver)->length()->IsSmi() &&
+        index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
+  }
+  return index >= receiver->elements()->length();
+}
+
+
+KeyedAccessStoreMode KeyedStoreIC::GetStoreMode(Handle<JSObject> receiver,
+                                                Handle<Object> key,
+                                                Handle<Object> value) {
   ASSERT(key->IsSmi());
   int index = Smi::cast(*key)->value();
-  bool allow_growth = receiver->IsJSArray() &&
-      JSArray::cast(*receiver)->length()->IsSmi() &&
-      index >= Smi::cast(JSArray::cast(*receiver)->length())->value();
-
+  bool oob_access = IsOutOfBoundsAccess(receiver, index);
+  bool allow_growth = receiver->IsJSArray() && oob_access;
   if (allow_growth) {
     // Handle growing array in stub if necessary.
     if (receiver->HasFastSmiElements()) {
@@ -1811,7 +1875,12 @@ KeyedStoreIC::StubKind KeyedStoreIC::GetStubKind(Handle<JSObject> receiver,
         }
       }
     }
-    return STORE_NO_TRANSITION;
+    if (!FLAG_trace_external_array_abuse &&
+        receiver->map()->has_external_array_elements() && oob_access) {
+      return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
+    } else {
+      return STANDARD_STORE;
+    }
   }
 }
 
@@ -1851,8 +1920,8 @@ MaybeObject* KeyedStoreIC::Store(State state,
             isolate()->heap()->non_strict_arguments_elements_map()) {
           stub = non_strict_arguments_stub();
         } else if (key->IsSmi() && (target() != *non_strict_arguments_stub())) {
-          StubKind stub_kind = GetStubKind(receiver, key, value);
-          stub = StoreElementStub(receiver, stub_kind, strict_mode);
+          KeyedAccessStoreMode store_mode = GetStoreMode(receiver, key, value);
+          stub = StoreElementStub(receiver, store_mode, strict_mode);
         }
       }
     } else {
index 78c364229ffcf67a0d78306698138b7c95e8e9f5..f5f822b7e5f8e9a89e6f896794b7203c43e09e4e 100644 (file)
--- a/src/ic.h
+++ b/src/ic.h
@@ -584,43 +584,6 @@ enum KeyedStoreIncrementLength {
 
 class KeyedStoreIC: public StoreIC {
  public:
-  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());
   }
@@ -662,7 +625,7 @@ class KeyedStoreIC: public StoreIC {
   }
 
   Handle<Code> StoreElementStub(Handle<JSObject> receiver,
-                                StubKind stub_kind,
+                                KeyedAccessStoreMode store_mode,
                                 StrictModeFlag strict_mode);
 
  private:
@@ -692,27 +655,12 @@ class KeyedStoreIC: public StoreIC {
 
   static void Clear(Address address, Code* target);
 
-  StubKind GetStubKind(Handle<JSObject> receiver,
-                       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;
-  }
+  KeyedAccessStoreMode GetStoreMode(Handle<JSObject> receiver,
+                                    Handle<Object> key,
+                                    Handle<Object> value);
 
   Handle<Map> ComputeTransitionedMap(Handle<JSObject> receiver,
-                                     StubKind stub_kind);
+                                     KeyedAccessStoreMode store_mode);
 
   friend class IC;
 };
@@ -836,7 +784,6 @@ class ToBooleanIC: public IC {
 enum InlinedSmiCheck { ENABLE_INLINED_SMI_CHECK, DISABLE_INLINED_SMI_CHECK };
 void PatchInlinedSmiCode(Address address, InlinedSmiCheck check);
 
-DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_Miss);
 DECLARE_RUNTIME_FUNCTION(MaybeObject*, KeyedLoadIC_MissFromStubFailure);
 
 } }  // namespace v8::internal
index 6247510afb30a52a059cdf95e8d8dafc368c5238..192c7bfb3fde6b6f652aa948539c1bcdd7d65fa8 100644 (file)
@@ -3788,7 +3788,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
     MacroAssembler* masm,
     bool is_js_array,
     ElementsKind elements_kind,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- a0    : value
   //  -- a1    : key
@@ -3950,7 +3950,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
     MacroAssembler* masm,
     bool is_js_array,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- a0    : value
   //  -- a1    : key
index c24f981bc8ea63361f61cb1e632f66c2f46e21ea..d90e703f1b29212f0ae2619070e3075439c97ae6 100644 (file)
@@ -152,10 +152,74 @@ enum CompareMapMode {
   ALLOW_ELEMENT_TRANSITION_MAPS
 };
 
-enum KeyedAccessGrowMode {
-  DO_NOT_ALLOW_JSARRAY_GROWTH,
-  ALLOW_JSARRAY_GROWTH
-};
+enum KeyedAccessStoreMode {
+  STANDARD_STORE,
+  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,
+  STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS,
+  STORE_NO_TRANSITION_HANDLE_COW
+};
+
+
+static const int kGrowICDelta = STORE_AND_GROW_NO_TRANSITION -
+    STANDARD_STORE;
+STATIC_ASSERT(STANDARD_STORE == 0);
+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 KeyedAccessStoreMode GetGrowStoreMode(
+    KeyedAccessStoreMode store_mode) {
+  if (store_mode < STORE_AND_GROW_NO_TRANSITION) {
+    store_mode = static_cast<KeyedAccessStoreMode>(
+        static_cast<int>(store_mode) + kGrowICDelta);
+  }
+  return store_mode;
+}
+
+
+static inline bool IsTransitionStoreMode(KeyedAccessStoreMode store_mode) {
+  return store_mode > STANDARD_STORE &&
+      store_mode <= STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT &&
+      store_mode != STORE_AND_GROW_NO_TRANSITION;
+}
+
+
+static inline KeyedAccessStoreMode GetNonTransitioningStoreMode(
+    KeyedAccessStoreMode store_mode) {
+  if (store_mode >= STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) {
+    return store_mode;
+  }
+  if (store_mode >= STORE_AND_GROW_NO_TRANSITION) {
+    return STORE_AND_GROW_NO_TRANSITION;
+  }
+  return STANDARD_STORE;
+}
+
+
+static inline bool IsGrowStoreMode(KeyedAccessStoreMode store_mode) {
+  return store_mode >= STORE_AND_GROW_NO_TRANSITION &&
+      store_mode <= STORE_AND_GROW_TRANSITION_HOLEY_DOUBLE_TO_OBJECT;
+}
+
 
 // Setter that skips the write barrier if mode is SKIP_WRITE_BARRIER.
 enum WriteBarrierMode { SKIP_WRITE_BARRIER, UPDATE_WRITE_BARRIER };
@@ -4469,24 +4533,22 @@ class Code: public HeapObject {
   void FindAllCode(CodeHandleList* code_list, int length);
 
   class ExtraICStateStrictMode: public BitField<StrictModeFlag, 0, 1> {};
-  class ExtraICStateKeyedAccessGrowMode:
-      public BitField<KeyedAccessGrowMode, 1, 1> {};  // NOLINT
-
-  static const int kExtraICStateGrowModeShift = 1;
+  class ExtraICStateKeyedAccessStoreMode:
+      public BitField<KeyedAccessStoreMode, 1, 4> {};  // NOLINT
 
   static inline StrictModeFlag GetStrictMode(ExtraICState extra_ic_state) {
     return ExtraICStateStrictMode::decode(extra_ic_state);
   }
 
-  static inline KeyedAccessGrowMode GetKeyedAccessGrowMode(
+  static inline KeyedAccessStoreMode GetKeyedAccessStoreMode(
       ExtraICState extra_ic_state) {
-    return ExtraICStateKeyedAccessGrowMode::decode(extra_ic_state);
+    return ExtraICStateKeyedAccessStoreMode::decode(extra_ic_state);
   }
 
   static inline ExtraICState ComputeExtraICState(
-      KeyedAccessGrowMode grow_mode,
+      KeyedAccessStoreMode store_mode,
       StrictModeFlag strict_mode) {
-    return ExtraICStateKeyedAccessGrowMode::encode(grow_mode) |
+    return ExtraICStateKeyedAccessStoreMode::encode(store_mode) |
         ExtraICStateStrictMode::encode(strict_mode);
   }
 
@@ -4650,8 +4712,8 @@ class Code: public HeapObject {
   class TypeField: public BitField<StubType, 3, 3> {};
   class CacheHolderField: public BitField<InlineCacheHolderFlag, 6, 1> {};
   class KindField: public BitField<Kind, 7, 4> {};
-  class ExtraICStateField: public BitField<ExtraICState, 11, 2> {};
-  class IsPregeneratedField: public BitField<bool, 13, 1> {};
+  class ExtraICStateField: public BitField<ExtraICState, 11, 5> {};
+  class IsPregeneratedField: public BitField<bool, 16, 1> {};
 
   // KindSpecificFlags1 layout (STUB and OPTIMIZED_FUNCTION)
   static const int kStackSlotsFirstBit = 0;
@@ -4708,7 +4770,7 @@ class Code: public HeapObject {
   class StackCheckTableOffsetField: public BitField<int, 0, 31> {};
 
   // Signed field cannot be encoded using the BitField class.
-  static const int kArgumentsCountShift = 14;
+  static const int kArgumentsCountShift = 17;
   static const int kArgumentsCountMask = ~((1 << kArgumentsCountShift) - 1);
 
   // This constant should be encodable in an ARM instruction.
index 1bf39b5b4daf56cab8e4f60279540085b5c3fe52..ac94fffebd0553b34a3fdf315d1220506178b833 100644 (file)
@@ -438,28 +438,26 @@ Handle<Code> StubCache::ComputeKeyedLoadElement(Handle<Map> receiver_map) {
 
 Handle<Code> StubCache::ComputeKeyedStoreElement(
     Handle<Map> receiver_map,
-    KeyedStoreIC::StubKind stub_kind,
     StrictModeFlag strict_mode,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   Code::ExtraICState extra_state =
-      Code::ComputeExtraICState(grow_mode, strict_mode);
+      Code::ComputeExtraICState(store_mode, strict_mode);
   Code::Flags flags = Code::ComputeMonomorphicFlags(
       Code::KEYED_STORE_IC, extra_state);
 
-  ASSERT(stub_kind == KeyedStoreIC::STORE_NO_TRANSITION ||
-         stub_kind == KeyedStoreIC::STORE_AND_GROW_NO_TRANSITION);
-
-  Handle<Name> name = stub_kind == KeyedStoreIC::STORE_NO_TRANSITION
-      ? isolate()->factory()->KeyedStoreElementMonomorphic_string()
-      : isolate()->factory()->KeyedStoreAndGrowElementMonomorphic_string();
+  ASSERT(store_mode == STANDARD_STORE ||
+         store_mode == STORE_AND_GROW_NO_TRANSITION);
 
+  Handle<String> name =
+      isolate()->factory()->KeyedStoreElementMonomorphic_string();
   Handle<Object> probe(receiver_map->FindInCodeCache(*name, flags), isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
-  KeyedStoreStubCompiler compiler(isolate(), strict_mode, grow_mode);
+  KeyedStoreStubCompiler compiler(isolate(), strict_mode, store_mode);
   Handle<Code> code = compiler.CompileStoreElement(receiver_map);
 
   Map::UpdateCodeCache(receiver_map, name, code);
+  ASSERT(Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == store_mode);
   return code;
 }
 
@@ -556,8 +554,7 @@ Handle<Code> StubCache::ComputeKeyedStoreField(Handle<Name> name,
                        isolate_);
   if (probe->IsCode()) return Handle<Code>::cast(probe);
 
-  KeyedStoreStubCompiler compiler(isolate(), strict_mode,
-                                  DO_NOT_ALLOW_JSARRAY_GROWTH);
+  KeyedStoreStubCompiler compiler(isolate(), strict_mode, STANDARD_STORE);
   Handle<Code> code =
       compiler.CompileStoreField(receiver, field_index, transition, name);
   JSObject::UpdateMapCodeCache(receiver, name, code);
@@ -914,18 +911,20 @@ Handle<Code> StubCache::ComputePolymorphicIC(MapHandleList* receiver_maps,
 
 Handle<Code> StubCache::ComputeStoreElementPolymorphic(
     MapHandleList* receiver_maps,
-    KeyedAccessGrowMode grow_mode,
+    KeyedAccessStoreMode store_mode,
     StrictModeFlag strict_mode) {
+  ASSERT(store_mode == STANDARD_STORE ||
+         store_mode == STORE_AND_GROW_NO_TRANSITION);
   Handle<PolymorphicCodeCache> cache =
       isolate_->factory()->polymorphic_code_cache();
-  Code::ExtraICState extra_state = Code::ComputeExtraICState(grow_mode,
+  Code::ExtraICState extra_state = Code::ComputeExtraICState(store_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);
+  KeyedStoreStubCompiler compiler(isolate_, strict_mode, store_mode);
   Handle<Code> code = compiler.CompileStoreElementPolymorphic(receiver_maps);
   PolymorphicCodeCache::Update(cache, receiver_maps, flags, code);
   return code;
@@ -1664,7 +1663,7 @@ Handle<Code> KeyedStoreStubCompiler::GetCode(Code::StubType type,
                                              Handle<Name> name,
                                              InlineCacheState state) {
   Code::ExtraICState extra_state =
-      Code::ComputeExtraICState(grow_mode_, strict_mode_);
+      Code::ComputeExtraICState(store_mode_, strict_mode_);
   Code::Flags flags =
       Code::ComputeFlags(Code::KEYED_STORE_IC, state, extra_state, type);
   Handle<Code> code = GetCodeWithFlags(flags, name);
@@ -1698,12 +1697,12 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElementPolymorphic(
           transitioned_map->elements_kind(),
           is_js_array,
           strict_mode_,
-          grow_mode_).GetCode(isolate());
+          store_mode_).GetCode(isolate());
     } else {
       cached_stub = KeyedStoreElementStub(
           is_js_array,
           elements_kind,
-          grow_mode_).GetCode(isolate());
+          store_mode_).GetCode(isolate());
     }
     ASSERT(!cached_stub.is_null());
     handlers.Add(cached_stub);
index b76e33a4887161872afc81c6f84b7150dc265bcc..56e3d4ff743de3d6ef8cc165daed661fbce1c73f 100644 (file)
@@ -196,9 +196,8 @@ class StubCache {
   Handle<Code> ComputeKeyedLoadElement(Handle<Map> receiver_map);
 
   Handle<Code> ComputeKeyedStoreElement(Handle<Map> receiver_map,
-                                        KeyedStoreIC::StubKind stub_kind,
                                         StrictModeFlag strict_mode,
-                                        KeyedAccessGrowMode grow_mode);
+                                        KeyedAccessStoreMode store_mode);
 
   // ---
 
@@ -262,7 +261,7 @@ class StubCache {
 
   Handle<Code> ComputeLoadElementPolymorphic(MapHandleList* receiver_maps);
   Handle<Code> ComputeStoreElementPolymorphic(MapHandleList* receiver_maps,
-                                              KeyedAccessGrowMode grow_mode,
+                                              KeyedAccessStoreMode store_mode,
                                               StrictModeFlag strict_mode);
 
   Handle<Code> ComputePolymorphicIC(MapHandleList* receiver_maps,
@@ -803,10 +802,10 @@ class KeyedStoreStubCompiler: public StubCompiler {
  public:
   KeyedStoreStubCompiler(Isolate* isolate,
                          StrictModeFlag strict_mode,
-                         KeyedAccessGrowMode grow_mode)
+                         KeyedAccessStoreMode store_mode)
     : StubCompiler(isolate),
       strict_mode_(strict_mode),
-      grow_mode_(grow_mode) { }
+      store_mode_(store_mode) { }
 
   Handle<Code> CompileStoreField(Handle<JSObject> object,
                                  int index,
@@ -824,11 +823,11 @@ class KeyedStoreStubCompiler: public StubCompiler {
   static void GenerateStoreFastElement(MacroAssembler* masm,
                                        bool is_js_array,
                                        ElementsKind element_kind,
-                                       KeyedAccessGrowMode grow_mode);
+                                       KeyedAccessStoreMode store_mode);
 
   static void GenerateStoreFastDoubleElement(MacroAssembler* masm,
                                              bool is_js_array,
-                                             KeyedAccessGrowMode grow_mode);
+                                             KeyedAccessStoreMode store_mode);
 
   static void GenerateStoreExternalArray(MacroAssembler* masm,
                                          ElementsKind elements_kind);
@@ -841,7 +840,7 @@ class KeyedStoreStubCompiler: public StubCompiler {
                        InlineCacheState state = MONOMORPHIC);
 
   StrictModeFlag strict_mode_;
-  KeyedAccessGrowMode grow_mode_;
+  KeyedAccessStoreMode store_mode_;
 };
 
 
index 62ca32479d9747b48f8c63d6cbb369af778e2253..857a55dac56f878da46eac87c75c57fcc3bb462f 100644 (file)
@@ -126,12 +126,12 @@ bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) {
   if (map_or_code->IsMap()) return true;
   if (map_or_code->IsCode()) {
     Handle<Code> code = Handle<Code>::cast(map_or_code);
-    bool allow_growth =
-        Code::GetKeyedAccessGrowMode(code->extra_ic_state()) ==
-        ALLOW_JSARRAY_GROWTH;
+    bool standard_store =
+        Code::GetKeyedAccessStoreMode(code->extra_ic_state()) ==
+        STANDARD_STORE;
     bool preliminary_checks =
         code->is_keyed_store_stub() &&
-        !allow_growth &&
+        standard_store &&
         code->ic_state() == MONOMORPHIC &&
         Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL;
     if (!preliminary_checks) return false;
@@ -146,10 +146,10 @@ bool TypeFeedbackOracle::StoreIsPolymorphic(TypeFeedbackId ast_id) {
   Handle<Object> map_or_code = GetInfo(ast_id);
   if (map_or_code->IsCode()) {
     Handle<Code> code = Handle<Code>::cast(map_or_code);
-    bool allow_growth =
-        Code::GetKeyedAccessGrowMode(code->extra_ic_state()) ==
-        ALLOW_JSARRAY_GROWTH;
-    return code->is_keyed_store_stub() && !allow_growth &&
+    bool standard_store =
+        Code::GetKeyedAccessStoreMode(code->extra_ic_state()) ==
+        STANDARD_STORE;
+    return code->is_keyed_store_stub() && standard_store  &&
         code->ic_state() == POLYMORPHIC;
   }
   return false;
@@ -218,6 +218,19 @@ Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(
 }
 
 
+KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode(
+    TypeFeedbackId ast_id) {
+  Handle<Object> map_or_code = GetInfo(ast_id);
+  if (map_or_code->IsCode()) {
+    Handle<Code> code = Handle<Code>::cast(map_or_code);
+    if (code->kind() == Code::KEYED_STORE_IC) {
+      return Code::GetKeyedAccessStoreMode(code->extra_ic_state());
+    }
+  }
+  return STANDARD_STORE;
+}
+
+
 void TypeFeedbackOracle::LoadReceiverTypes(Property* expr,
                                            Handle<String> name,
                                            SmallMapList* types) {
index 2b50bf483f429212cc050cb47336dab6218ee68a..1e9064517af1059e9707a7cd975f75dfc2a46deb 100644 (file)
@@ -255,6 +255,8 @@ class TypeFeedbackOracle: public ZoneObject {
   Handle<Map> LoadMonomorphicReceiverType(Property* expr);
   Handle<Map> StoreMonomorphicReceiverType(TypeFeedbackId ast_id);
 
+  KeyedAccessStoreMode GetStoreMode(TypeFeedbackId ast_id);
+
   void LoadReceiverTypes(Property* expr,
                          Handle<String> name,
                          SmallMapList* types);
index 186ab6b868d85933b6e2d2cc1588451bbeba326d..0e8e74ed60de3dcfbcad660823d2850dfb3fbdf1 100644 (file)
@@ -2705,7 +2705,7 @@ Handle<Code> KeyedStoreStubCompiler::CompileStoreElement(
   Handle<Code> stub =
       KeyedStoreElementStub(is_js_array,
                             elements_kind,
-                            grow_mode_).GetCode(isolate());
+                            store_mode_).GetCode(isolate());
 
   __ DispatchMap(rdx, receiver_map, stub, DO_SMI_CHECK);
 
@@ -3335,7 +3335,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
     MacroAssembler* masm,
     bool is_js_array,
     ElementsKind elements_kind,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- rax    : value
   //  -- rcx    : key
@@ -3360,7 +3360,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
   // Check that the key is within bounds.
   if (is_js_array) {
     __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
-    if (grow_mode == ALLOW_JSARRAY_GROWTH) {
+    if (IsGrowStoreMode(store_mode)) {
       __ j(above_equal, &grow);
     } else {
       __ j(above_equal, &miss_force_generic);
@@ -3404,7 +3404,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   __ jmp(ic_miss, RelocInfo::CODE_TARGET);
 
-  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (is_js_array && IsGrowStoreMode(store_mode)) {
     // Grow the array by a single element if possible.
     __ bind(&grow);
 
@@ -3477,7 +3477,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastElement(
 void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
     MacroAssembler* masm,
     bool is_js_array,
-    KeyedAccessGrowMode grow_mode) {
+    KeyedAccessStoreMode store_mode) {
   // ----------- S t a t e -------------
   //  -- rax    : value
   //  -- rcx    : key
@@ -3500,7 +3500,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
   // Check that the key is within bounds.
   if (is_js_array) {
       __ SmiCompare(rcx, FieldOperand(rdx, JSArray::kLengthOffset));
-      if (grow_mode == ALLOW_JSARRAY_GROWTH) {
+      if (IsGrowStoreMode(store_mode)) {
         __ j(above_equal, &grow);
       } else {
         __ j(above_equal, &miss_force_generic);
@@ -3530,7 +3530,7 @@ void KeyedStoreStubCompiler::GenerateStoreFastDoubleElement(
   Handle<Code> ic_miss = masm->isolate()->builtins()->KeyedStoreIC_Miss();
   __ jmp(ic_miss, RelocInfo::CODE_TARGET);
 
-  if (is_js_array && grow_mode == ALLOW_JSARRAY_GROWTH) {
+  if (is_js_array && IsGrowStoreMode(store_mode)) {
     // Grow the array by a single element if possible.
     __ bind(&grow);
 
index 92bdac740dddde0c5750100368cac4394bffb5ca..d95255605d45abda3880e3a79f9f8e32e135aeea 100644 (file)
 // Flags: --allow-natives-syntax --smi-only-arrays --expose-gc
 // Flags: --notrack_allocation_sites
 
+// Limit the number of stress runs to reduce polymorphism it defeats some of
+// they assumptions made about how elements transitions work because transition
+// stubs end up going generic.  Flags: --stress-runs=2
+
 // Test element kind of objects.
 // Since --smi-only-arrays affects builtins, its default setting at compile
 // time sticks if built with snapshot.  If --smi-only-arrays is deactivated