Upgrade V8 to version 4.9.385.28

https://chromium.googlesource.com/v8/v8/+/4.9.385.28

FPIIM-449

Change-Id: I4b2e74289d4bf3667f2f3dc8aa2e541f63e26eb4
diff --git a/src/elements.cc b/src/elements.cc
index 4e9a052..d4d80db 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -2,12 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
+#include "src/elements.h"
 
 #include "src/arguments.h"
 #include "src/conversions.h"
-#include "src/elements.h"
-#include "src/objects.h"
+#include "src/factory.h"
+#include "src/messages.h"
+#include "src/objects-inl.h"
 #include "src/utils.h"
 
 // Each concrete ElementsAccessor can handle exactly one ElementsKind,
@@ -26,15 +27,6 @@
 //       - FastPackedDoubleElementsAccessor
 //       - FastHoleyDoubleElementsAccessor
 //   - TypedElementsAccessor: template, with instantiations:
-//     - ExternalInt8ElementsAccessor
-//     - ExternalUint8ElementsAccessor
-//     - ExternalInt16ElementsAccessor
-//     - ExternalUint16ElementsAccessor
-//     - ExternalInt32ElementsAccessor
-//     - ExternalUint32ElementsAccessor
-//     - ExternalFloat32ElementsAccessor
-//     - ExternalFloat64ElementsAccessor
-//     - ExternalUint8ClampedElementsAccessor
 //     - FixedUint8ElementsAccessor
 //     - FixedInt8ElementsAccessor
 //     - FixedUint16ElementsAccessor
@@ -46,62 +38,49 @@
 //     - FixedUint8ClampedElementsAccessor
 //   - DictionaryElementsAccessor
 //   - SloppyArgumentsElementsAccessor
+//     - FastSloppyArgumentsElementsAccessor
+//     - SlowSloppyArgumentsElementsAccessor
 
 
 namespace v8 {
 namespace internal {
 
 
+namespace {
+
+
 static const int kPackedSizeNotKnown = -1;
 
+enum Where { AT_START, AT_END };
+
 
 // First argument in list is the accessor class, the second argument is the
 // accessor ElementsKind, and the third is the backing store class.  Use the
 // fast element handler for smi-only arrays.  The implementation is currently
 // identical.  Note that the order must match that of the ElementsKind enum for
 // the |accessor_array[]| below to work.
-#define ELEMENTS_LIST(V)                                                \
-  V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray)       \
-  V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS,              \
-    FixedArray)                                                         \
-  V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray)        \
-  V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray)   \
-  V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS,             \
-    FixedDoubleArray)                                                   \
-  V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS,        \
-    FixedDoubleArray)                                                   \
-  V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS,                    \
-    SeededNumberDictionary)                                             \
-  V(SloppyArgumentsElementsAccessor, SLOPPY_ARGUMENTS_ELEMENTS,         \
-    FixedArray)                                                         \
-  V(ExternalInt8ElementsAccessor, EXTERNAL_INT8_ELEMENTS,               \
-    ExternalInt8Array)                                                  \
-  V(ExternalUint8ElementsAccessor,                                      \
-    EXTERNAL_UINT8_ELEMENTS, ExternalUint8Array)                        \
-  V(ExternalInt16ElementsAccessor, EXTERNAL_INT16_ELEMENTS,             \
-    ExternalInt16Array)                                                 \
-  V(ExternalUint16ElementsAccessor,                                     \
-    EXTERNAL_UINT16_ELEMENTS, ExternalUint16Array)                      \
-  V(ExternalInt32ElementsAccessor, EXTERNAL_INT32_ELEMENTS,             \
-    ExternalInt32Array)                                                 \
-  V(ExternalUint32ElementsAccessor,                                     \
-    EXTERNAL_UINT32_ELEMENTS, ExternalUint32Array)                      \
-  V(ExternalFloat32ElementsAccessor,                                    \
-    EXTERNAL_FLOAT32_ELEMENTS, ExternalFloat32Array)                    \
-  V(ExternalFloat64ElementsAccessor,                                    \
-    EXTERNAL_FLOAT64_ELEMENTS, ExternalFloat64Array)                    \
-  V(ExternalUint8ClampedElementsAccessor,                               \
-    EXTERNAL_UINT8_CLAMPED_ELEMENTS,                                    \
-    ExternalUint8ClampedArray)                                          \
-  V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array)        \
-  V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array)           \
-  V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array)     \
-  V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array)        \
-  V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array)     \
-  V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array)        \
-  V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array)  \
-  V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array)  \
-  V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS,          \
+#define ELEMENTS_LIST(V)                                                      \
+  V(FastPackedSmiElementsAccessor, FAST_SMI_ELEMENTS, FixedArray)             \
+  V(FastHoleySmiElementsAccessor, FAST_HOLEY_SMI_ELEMENTS, FixedArray)        \
+  V(FastPackedObjectElementsAccessor, FAST_ELEMENTS, FixedArray)              \
+  V(FastHoleyObjectElementsAccessor, FAST_HOLEY_ELEMENTS, FixedArray)         \
+  V(FastPackedDoubleElementsAccessor, FAST_DOUBLE_ELEMENTS, FixedDoubleArray) \
+  V(FastHoleyDoubleElementsAccessor, FAST_HOLEY_DOUBLE_ELEMENTS,              \
+    FixedDoubleArray)                                                         \
+  V(DictionaryElementsAccessor, DICTIONARY_ELEMENTS, SeededNumberDictionary)  \
+  V(FastSloppyArgumentsElementsAccessor, FAST_SLOPPY_ARGUMENTS_ELEMENTS,      \
+    FixedArray)                                                               \
+  V(SlowSloppyArgumentsElementsAccessor, SLOW_SLOPPY_ARGUMENTS_ELEMENTS,      \
+    FixedArray)                                                               \
+  V(FixedUint8ElementsAccessor, UINT8_ELEMENTS, FixedUint8Array)              \
+  V(FixedInt8ElementsAccessor, INT8_ELEMENTS, FixedInt8Array)                 \
+  V(FixedUint16ElementsAccessor, UINT16_ELEMENTS, FixedUint16Array)           \
+  V(FixedInt16ElementsAccessor, INT16_ELEMENTS, FixedInt16Array)              \
+  V(FixedUint32ElementsAccessor, UINT32_ELEMENTS, FixedUint32Array)           \
+  V(FixedInt32ElementsAccessor, INT32_ELEMENTS, FixedInt32Array)              \
+  V(FixedFloat32ElementsAccessor, FLOAT32_ELEMENTS, FixedFloat32Array)        \
+  V(FixedFloat64ElementsAccessor, FLOAT64_ELEMENTS, FixedFloat64Array)        \
+  V(FixedUint8ClampedElementsAccessor, UINT8_CLAMPED_ELEMENTS,                \
     FixedUint8ClampedArray)
 
 
@@ -120,39 +99,17 @@
 #undef ELEMENTS_TRAITS
 
 
-ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
-
-
-static bool HasKey(Handle<FixedArray> array, Handle<Object> key_handle) {
-  DisallowHeapAllocation no_gc;
-  Object* key = *key_handle;
-  int len0 = array->length();
-  for (int i = 0; i < len0; i++) {
-    Object* element = array->get(i);
-    if (element->IsSmi() && element == key) return true;
-    if (element->IsString() &&
-        key->IsString() && String::cast(element)->Equals(String::cast(key))) {
-      return true;
-    }
-  }
-  return false;
-}
-
-
 MUST_USE_RESULT
-static MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
-  THROW_NEW_ERROR(isolate, NewRangeError("invalid_array_length",
-                                         HandleVector<Object>(NULL, 0)),
+MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
+  THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kInvalidArrayLength),
                   Object);
 }
 
 
-static void CopyObjectToObjectElements(FixedArrayBase* from_base,
-                                       ElementsKind from_kind,
-                                       uint32_t from_start,
-                                       FixedArrayBase* to_base,
-                                       ElementsKind to_kind, uint32_t to_start,
-                                       int raw_copy_size) {
+void CopyObjectToObjectElements(FixedArrayBase* from_base,
+                                ElementsKind from_kind, uint32_t from_start,
+                                FixedArrayBase* to_base, ElementsKind to_kind,
+                                uint32_t to_start, int raw_copy_size) {
   DCHECK(to_base->map() !=
       from_base->GetIsolate()->heap()->fixed_cow_array_map());
   DisallowHeapAllocation no_allocation;
@@ -179,20 +136,14 @@
   FixedArray* to = FixedArray::cast(to_base);
   DCHECK(IsFastSmiOrObjectElementsKind(from_kind));
   DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
-  Address to_address = to->address() + FixedArray::kHeaderSize;
-  Address from_address = from->address() + FixedArray::kHeaderSize;
-  CopyWords(reinterpret_cast<Object**>(to_address) + to_start,
-            reinterpret_cast<Object**>(from_address) + from_start,
-            static_cast<size_t>(copy_size));
-  if (IsFastObjectElementsKind(from_kind) &&
-      IsFastObjectElementsKind(to_kind)) {
-    Heap* heap = from->GetHeap();
-    if (!heap->InNewSpace(to)) {
-      heap->RecordWrites(to->address(),
-                         to->OffsetOfElementAt(to_start),
-                         copy_size);
-    }
-    heap->incremental_marking()->RecordWrites(to);
+
+  WriteBarrierMode write_barrier_mode =
+      (IsFastObjectElementsKind(from_kind) && IsFastObjectElementsKind(to_kind))
+          ? UPDATE_WRITE_BARRIER
+          : SKIP_WRITE_BARRIER;
+  for (int i = 0; i < copy_size; i++) {
+    Object* value = from->get(from_start + i);
+    to->set(to_start + i, value, write_barrier_mode);
   }
 }
 
@@ -203,7 +154,6 @@
   DisallowHeapAllocation no_allocation;
   SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
   int copy_size = raw_copy_size;
-  Heap* heap = from->GetHeap();
   if (raw_copy_size < 0) {
     DCHECK(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
@@ -226,24 +176,19 @@
   if (to_start + copy_size > to_length) {
     copy_size = to_length - to_start;
   }
+  WriteBarrierMode write_barrier_mode = IsFastObjectElementsKind(to_kind)
+                                            ? UPDATE_WRITE_BARRIER
+                                            : SKIP_WRITE_BARRIER;
   for (int i = 0; i < copy_size; i++) {
     int entry = from->FindEntry(i + from_start);
     if (entry != SeededNumberDictionary::kNotFound) {
       Object* value = from->ValueAt(entry);
       DCHECK(!value->IsTheHole());
-      to->set(i + to_start, value, SKIP_WRITE_BARRIER);
+      to->set(i + to_start, value, write_barrier_mode);
     } else {
       to->set_the_hole(i + to_start);
     }
   }
-  if (IsFastObjectElementsKind(to_kind)) {
-    if (!heap->InNewSpace(to)) {
-      heap->RecordWrites(to->address(),
-                         to->OffsetOfElementAt(to_start),
-                         copy_size);
-    }
-    heap->incremental_marking()->RecordWrites(to);
-  }
 }
 
 
@@ -253,9 +198,7 @@
 static void CopyDoubleToObjectElements(FixedArrayBase* from_base,
                                        uint32_t from_start,
                                        FixedArrayBase* to_base,
-                                       ElementsKind to_kind, uint32_t to_start,
-                                       int raw_copy_size) {
-  DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
+                                       uint32_t to_start, int raw_copy_size) {
   int copy_size = raw_copy_size;
   if (raw_copy_size < 0) {
     DisallowHeapAllocation no_allocation;
@@ -276,6 +219,7 @@
       }
     }
   }
+
   DCHECK((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
          (copy_size + static_cast<int>(from_start)) <= from_base->length());
   if (copy_size == 0) return;
@@ -285,12 +229,15 @@
   Isolate* isolate = from_base->GetIsolate();
   Handle<FixedDoubleArray> from(FixedDoubleArray::cast(from_base), isolate);
   Handle<FixedArray> to(FixedArray::cast(to_base), isolate);
-  for (int i = 0; i < copy_size; ++i) {
+
+  // create an outer loop to not waste too much time on creating HandleScopes
+  // on the other hand we might overflow a single handle scope depending on
+  // the copy_size
+  int offset = 0;
+  while (offset < copy_size) {
     HandleScope scope(isolate);
-    if (IsFastSmiElementsKind(to_kind)) {
-      UNIMPLEMENTED();
-    } else {
-      DCHECK(IsFastObjectElementsKind(to_kind));
+    offset += 100;
+    for (int i = offset - 100; i < offset && i < copy_size; ++i) {
       Handle<Object> value = FixedDoubleArray::get(from, i + from_start);
       to->set(i + to_start, *value, UPDATE_WRITE_BARRIER);
     }
@@ -481,8 +428,8 @@
   }
   StackFrame* raw_frame = it.frame();
   if (raw_frame->is_internal()) {
-    Code* apply_builtin = isolate->builtins()->builtin(
-        Builtins::kFunctionApply);
+    Code* apply_builtin =
+        isolate->builtins()->builtin(Builtins::kFunctionPrototypeApply);
     if (raw_frame->unchecked_code() == apply_builtin) {
       PrintF("apply from ");
       it.Advance();
@@ -493,46 +440,6 @@
 }
 
 
-void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t key,
-                     bool allow_appending) {
-  DisallowHeapAllocation no_allocation;
-  Object* raw_length = NULL;
-  const char* elements_type = "array";
-  if (obj->IsJSArray()) {
-    JSArray* array = JSArray::cast(*obj);
-    raw_length = array->length();
-  } else {
-    raw_length = Smi::FromInt(obj->elements()->length());
-    elements_type = "object";
-  }
-
-  if (raw_length->IsNumber()) {
-    double n = raw_length->Number();
-    if (FastI2D(FastD2UI(n)) == n) {
-      int32_t int32_length = DoubleToInt32(n);
-      uint32_t compare_length = static_cast<uint32_t>(int32_length);
-      if (allow_appending) compare_length++;
-      if (key >= compare_length) {
-        PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
-               elements_type, op, elements_type,
-               static_cast<int>(int32_length),
-               static_cast<int>(key));
-        TraceTopFrame(obj->GetIsolate());
-        PrintF("]\n");
-      }
-    } else {
-      PrintF("[%s elements length not integer value in ", elements_type);
-      TraceTopFrame(obj->GetIsolate());
-      PrintF("]\n");
-    }
-  } else {
-    PrintF("[%s elements length not a number in ", elements_type);
-    TraceTopFrame(obj->GetIsolate());
-    PrintF("]\n");
-  }
-}
-
-
 // Base class for element handler implementations. Contains the
 // the common logic for objects with different ElementsKinds.
 // Subclasses must specialize method for which the element
@@ -553,14 +460,14 @@
 template <typename ElementsAccessorSubclass,
           typename ElementsTraitsParam>
 class ElementsAccessorBase : public ElementsAccessor {
- protected:
+ public:
   explicit ElementsAccessorBase(const char* name)
       : ElementsAccessor(name) { }
 
   typedef ElementsTraitsParam ElementsTraits;
   typedef typename ElementsTraitsParam::BackingStore BackingStore;
 
-  ElementsKind kind() const FINAL { return ElementsTraits::Kind; }
+  static ElementsKind kind() { return ElementsTraits::Kind; }
 
   static void ValidateContents(Handle<JSObject> holder, int length) {
   }
@@ -582,119 +489,324 @@
     ElementsAccessorSubclass::ValidateContents(holder, length);
   }
 
-  void Validate(Handle<JSObject> holder) FINAL {
+  void Validate(Handle<JSObject> holder) final {
     DisallowHeapAllocation no_gc;
     ElementsAccessorSubclass::ValidateImpl(holder);
   }
 
-  static bool HasElementImpl(Handle<Object> receiver,
-                             Handle<JSObject> holder,
-                             uint32_t key,
-                             Handle<FixedArrayBase> backing_store) {
-    return ElementsAccessorSubclass::GetAttributesImpl(
-        receiver, holder, key, backing_store) != ABSENT;
+  bool IsPacked(Handle<JSObject> holder, Handle<FixedArrayBase> backing_store,
+                uint32_t start, uint32_t end) final {
+    return ElementsAccessorSubclass::IsPackedImpl(holder, backing_store, start,
+                                                  end);
   }
 
-  virtual bool HasElement(Handle<Object> receiver, Handle<JSObject> holder,
-                          uint32_t key,
-                          Handle<FixedArrayBase> backing_store) FINAL {
-    return ElementsAccessorSubclass::HasElementImpl(
-        receiver, holder, key, backing_store);
+  static bool IsPackedImpl(Handle<JSObject> holder,
+                           Handle<FixedArrayBase> backing_store, uint32_t start,
+                           uint32_t end) {
+    if (IsFastPackedElementsKind(kind())) return true;
+    for (uint32_t i = start; i < end; i++) {
+      if (!ElementsAccessorSubclass::HasElementImpl(holder, i, backing_store,
+                                                    ALL_PROPERTIES)) {
+        return false;
+      }
+    }
+    return true;
   }
 
-  MUST_USE_RESULT virtual MaybeHandle<Object> Get(
-      Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
-      Handle<FixedArrayBase> backing_store) FINAL {
-    if (!IsExternalArrayElementsKind(ElementsTraits::Kind) &&
-        FLAG_trace_js_array_abuse) {
-      CheckArrayAbuse(holder, "elements read", key);
+  static void TryTransitionResultArrayToPacked(Handle<JSArray> array) {
+    if (!IsHoleyElementsKind(kind())) return;
+    int length = Smi::cast(array->length())->value();
+    Handle<FixedArrayBase> backing_store(array->elements());
+    if (!ElementsAccessorSubclass::IsPackedImpl(array, backing_store, 0,
+                                                length)) {
+      return;
+    }
+    ElementsKind packed_kind = GetPackedElementsKind(kind());
+    Handle<Map> new_map =
+        JSObject::GetElementsTransitionMap(array, packed_kind);
+    JSObject::MigrateToMap(array, new_map);
+    if (FLAG_trace_elements_transitions) {
+      JSObject::PrintElementsTransition(stdout, array, kind(), backing_store,
+                                        packed_kind, backing_store);
+    }
+  }
+
+  bool HasElement(Handle<JSObject> holder, uint32_t index,
+                  Handle<FixedArrayBase> backing_store,
+                  PropertyFilter filter) final {
+    return ElementsAccessorSubclass::HasElementImpl(holder, index,
+                                                    backing_store, filter);
+  }
+
+  static bool HasElementImpl(Handle<JSObject> holder, uint32_t index,
+                             Handle<FixedArrayBase> backing_store,
+                             PropertyFilter filter) {
+    return ElementsAccessorSubclass::GetEntryForIndexImpl(
+               *holder, *backing_store, index, filter) != kMaxUInt32;
+  }
+
+  Handle<Object> Get(Handle<FixedArrayBase> backing_store,
+                     uint32_t entry) final {
+    return ElementsAccessorSubclass::GetImpl(backing_store, entry);
+  }
+
+  static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
+                                uint32_t entry) {
+    uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
+    return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
+  }
+
+  void Set(FixedArrayBase* backing_store, uint32_t entry, Object* value) final {
+    ElementsAccessorSubclass::SetImpl(backing_store, entry, value);
+  }
+
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value) {
+    UNREACHABLE();
+  }
+
+
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value, WriteBarrierMode mode) {
+    UNREACHABLE();
+  }
+
+  void Reconfigure(Handle<JSObject> object, Handle<FixedArrayBase> store,
+                   uint32_t entry, Handle<Object> value,
+                   PropertyAttributes attributes) final {
+    ElementsAccessorSubclass::ReconfigureImpl(object, store, entry, value,
+                                              attributes);
+  }
+
+  static void ReconfigureImpl(Handle<JSObject> object,
+                              Handle<FixedArrayBase> store, uint32_t entry,
+                              Handle<Object> value,
+                              PropertyAttributes attributes) {
+    UNREACHABLE();
+  }
+
+  void Add(Handle<JSObject> object, uint32_t index, Handle<Object> value,
+           PropertyAttributes attributes, uint32_t new_capacity) final {
+    ElementsAccessorSubclass::AddImpl(object, index, value, attributes,
+                                      new_capacity);
+  }
+
+  static void AddImpl(Handle<JSObject> object, uint32_t index,
+                      Handle<Object> value, PropertyAttributes attributes,
+                      uint32_t new_capacity) {
+    UNREACHABLE();
+  }
+
+  uint32_t Push(Handle<JSArray> receiver, Handle<FixedArrayBase> backing_store,
+                Arguments* args, uint32_t push_size) final {
+    return ElementsAccessorSubclass::PushImpl(receiver, backing_store, args,
+                                              push_size);
+  }
+
+  static uint32_t PushImpl(Handle<JSArray> receiver,
+                           Handle<FixedArrayBase> elms_obj, Arguments* args,
+                           uint32_t push_sized) {
+    UNREACHABLE();
+    return 0;
+  }
+
+  uint32_t Unshift(Handle<JSArray> receiver,
+                   Handle<FixedArrayBase> backing_store, Arguments* args,
+                   uint32_t unshift_size) final {
+    return ElementsAccessorSubclass::UnshiftImpl(receiver, backing_store, args,
+                                                 unshift_size);
+  }
+
+  static uint32_t UnshiftImpl(Handle<JSArray> receiver,
+                              Handle<FixedArrayBase> elms_obj, Arguments* args,
+                              uint32_t unshift_size) {
+    UNREACHABLE();
+    return 0;
+  }
+
+  Handle<JSArray> Slice(Handle<JSObject> receiver,
+                        Handle<FixedArrayBase> backing_store, uint32_t start,
+                        uint32_t end) final {
+    return ElementsAccessorSubclass::SliceImpl(receiver, backing_store, start,
+                                               end);
+  }
+
+  static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
+                                   Handle<FixedArrayBase> backing_store,
+                                   uint32_t start, uint32_t end) {
+    UNREACHABLE();
+    return Handle<JSArray>();
+  }
+
+  Handle<JSArray> Splice(Handle<JSArray> receiver,
+                         Handle<FixedArrayBase> backing_store, uint32_t start,
+                         uint32_t delete_count, Arguments* args,
+                         uint32_t add_count) final {
+    return ElementsAccessorSubclass::SpliceImpl(receiver, backing_store, start,
+                                                delete_count, args, add_count);
+  }
+
+  static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
+                                    Handle<FixedArrayBase> backing_store,
+                                    uint32_t start, uint32_t delete_count,
+                                    Arguments* args, uint32_t add_count) {
+    UNREACHABLE();
+    return Handle<JSArray>();
+  }
+
+  Handle<Object> Pop(Handle<JSArray> receiver,
+                     Handle<FixedArrayBase> backing_store) final {
+    return ElementsAccessorSubclass::PopImpl(receiver, backing_store);
+  }
+
+  static Handle<Object> PopImpl(Handle<JSArray> receiver,
+                                Handle<FixedArrayBase> backing_store) {
+    UNREACHABLE();
+    return Handle<Object>();
+  }
+
+  Handle<Object> Shift(Handle<JSArray> receiver,
+                       Handle<FixedArrayBase> backing_store) final {
+    return ElementsAccessorSubclass::ShiftImpl(receiver, backing_store);
+  }
+
+  static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
+                                  Handle<FixedArrayBase> backing_store) {
+    UNREACHABLE();
+    return Handle<Object>();
+  }
+
+  void SetLength(Handle<JSArray> array, uint32_t length) final {
+    ElementsAccessorSubclass::SetLengthImpl(array->GetIsolate(), array, length,
+                                            handle(array->elements()));
+  }
+
+  static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+                            uint32_t length,
+                            Handle<FixedArrayBase> backing_store) {
+    DCHECK(!array->SetLengthWouldNormalize(length));
+    DCHECK(IsFastElementsKind(array->GetElementsKind()));
+    uint32_t old_length = 0;
+    CHECK(array->length()->ToArrayIndex(&old_length));
+
+    if (old_length < length) {
+      ElementsKind kind = array->GetElementsKind();
+      if (!IsFastHoleyElementsKind(kind)) {
+        kind = GetHoleyElementsKind(kind);
+        JSObject::TransitionElementsKind(array, kind);
+      }
     }
 
-    if (IsExternalArrayElementsKind(ElementsTraits::Kind) &&
-        FLAG_trace_external_array_abuse) {
-      CheckArrayAbuse(holder, "external elements read", key);
-    }
-
-    return ElementsAccessorSubclass::GetImpl(
-        receiver, holder, key, backing_store);
-  }
-
-  MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) {
-    if (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
-      return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
+    // Check whether the backing store should be shrunk.
+    uint32_t capacity = backing_store->length();
+    old_length = Min(old_length, capacity);
+    if (length == 0) {
+      array->initialize_elements();
+    } else if (length <= capacity) {
+      if (array->HasFastSmiOrObjectElements()) {
+        backing_store = JSObject::EnsureWritableFastElements(array);
+      }
+      if (2 * length <= capacity) {
+        // If more than half the elements won't be used, trim the array.
+        isolate->heap()->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(
+            *backing_store, capacity - length);
+      } else {
+        // Otherwise, fill the unused tail with holes.
+        for (uint32_t i = length; i < old_length; i++) {
+          BackingStore::cast(*backing_store)->set_the_hole(i);
+        }
+      }
     } else {
-      return backing_store->GetIsolate()->factory()->the_hole_value();
+      // Check whether the backing store should be expanded.
+      capacity = Max(length, JSObject::NewElementsCapacity(capacity));
+      ElementsAccessorSubclass::GrowCapacityAndConvertImpl(array, capacity);
+    }
+
+    array->set_length(Smi::FromInt(length));
+    JSObject::ValidateElements(array);
+  }
+
+  static Handle<FixedArrayBase> ConvertElementsWithCapacity(
+      Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
+      ElementsKind from_kind, uint32_t capacity) {
+    return ConvertElementsWithCapacity(
+        object, old_elements, from_kind, capacity, 0, 0,
+        ElementsAccessor::kCopyToEndAndInitializeToHole);
+  }
+
+  static Handle<FixedArrayBase> ConvertElementsWithCapacity(
+      Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
+      ElementsKind from_kind, uint32_t capacity, int copy_size) {
+    return ConvertElementsWithCapacity(object, old_elements, from_kind,
+                                       capacity, 0, 0, copy_size);
+  }
+
+  static Handle<FixedArrayBase> ConvertElementsWithCapacity(
+      Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
+      ElementsKind from_kind, uint32_t capacity, uint32_t src_index,
+      uint32_t dst_index, int copy_size) {
+    Isolate* isolate = object->GetIsolate();
+    Handle<FixedArrayBase> new_elements;
+    if (IsFastDoubleElementsKind(kind())) {
+      new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
+    } else {
+      new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
+    }
+
+    int packed_size = kPackedSizeNotKnown;
+    if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
+      packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
+    }
+
+    ElementsAccessorSubclass::CopyElementsImpl(
+        *old_elements, src_index, *new_elements, from_kind, dst_index,
+        packed_size, copy_size);
+
+    return new_elements;
+  }
+
+  static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
+                                         uint32_t capacity) {
+    ElementsKind from_kind = object->GetElementsKind();
+    if (IsFastSmiOrObjectElementsKind(from_kind)) {
+      // Array optimizations rely on the prototype lookups of Array objects
+      // always returning undefined. If there is a store to the initial
+      // prototype object, make sure all of these optimizations are invalidated.
+      object->GetIsolate()->UpdateArrayProtectorOnSetLength(object);
+    }
+    Handle<FixedArrayBase> old_elements(object->elements());
+    // This method should only be called if there's a reason to update the
+    // elements.
+    DCHECK(IsFastDoubleElementsKind(from_kind) !=
+               IsFastDoubleElementsKind(kind()) ||
+           IsDictionaryElementsKind(from_kind) ||
+           static_cast<uint32_t>(old_elements->length()) < capacity);
+    Handle<FixedArrayBase> elements =
+        ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
+
+    ElementsKind to_kind = kind();
+    if (IsHoleyElementsKind(from_kind)) to_kind = GetHoleyElementsKind(to_kind);
+    Handle<Map> new_map = JSObject::GetElementsTransitionMap(object, to_kind);
+    JSObject::SetMapAndElements(object, new_map, elements);
+
+    // Transition through the allocation site as well if present.
+    JSObject::UpdateAllocationSite(object, to_kind);
+
+    if (FLAG_trace_elements_transitions) {
+      JSObject::PrintElementsTransition(stdout, object, from_kind, old_elements,
+                                        to_kind, elements);
     }
   }
 
-  MUST_USE_RESULT virtual PropertyAttributes GetAttributes(
-      Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
-      Handle<FixedArrayBase> backing_store) FINAL {
-    return ElementsAccessorSubclass::GetAttributesImpl(
-        receiver, holder, key, backing_store);
+  void GrowCapacityAndConvert(Handle<JSObject> object,
+                              uint32_t capacity) final {
+    ElementsAccessorSubclass::GrowCapacityAndConvertImpl(object, capacity);
   }
 
-  MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
-        Handle<Object> receiver,
-        Handle<JSObject> obj,
-        uint32_t key,
-        Handle<FixedArrayBase> backing_store) {
-    if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
-      return ABSENT;
-    }
-    return
-        Handle<BackingStore>::cast(backing_store)->is_the_hole(key)
-          ? ABSENT : NONE;
+  void Delete(Handle<JSObject> obj, uint32_t entry) final {
+    ElementsAccessorSubclass::DeleteImpl(obj, entry);
   }
 
-  MUST_USE_RESULT virtual MaybeHandle<AccessorPair> GetAccessorPair(
-      Handle<Object> receiver, Handle<JSObject> holder, uint32_t key,
-      Handle<FixedArrayBase> backing_store) FINAL {
-    return ElementsAccessorSubclass::GetAccessorPairImpl(
-        receiver, holder, key, backing_store);
-  }
-
-  MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) {
-    return MaybeHandle<AccessorPair>();
-  }
-
-  MUST_USE_RESULT virtual MaybeHandle<Object> SetLength(
-      Handle<JSArray> array, Handle<Object> length) FINAL {
-    return ElementsAccessorSubclass::SetLengthImpl(
-        array, length, handle(array->elements()));
-  }
-
-  MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
-      Handle<JSObject> obj,
-      Handle<Object> length,
-      Handle<FixedArrayBase> backing_store);
-
-  virtual void SetCapacityAndLength(Handle<JSArray> array, int capacity,
-                                    int length) FINAL {
-    ElementsAccessorSubclass::
-        SetFastElementsCapacityAndLength(array, capacity, length);
-  }
-
-  static void SetFastElementsCapacityAndLength(
-      Handle<JSObject> obj,
-      int capacity,
-      int length) {
-    UNIMPLEMENTED();
-  }
-
-  MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj,
-      uint32_t key,
-      JSReceiver::DeleteMode mode) OVERRIDE = 0;
-
   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
                                FixedArrayBase* to, ElementsKind from_kind,
                                uint32_t to_start, int packed_size,
@@ -702,9 +814,9 @@
     UNREACHABLE();
   }
 
-  virtual void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
-                            ElementsKind from_kind, Handle<FixedArrayBase> to,
-                            uint32_t to_start, int copy_size) FINAL {
+  void CopyElements(Handle<FixedArrayBase> from, uint32_t from_start,
+                    ElementsKind from_kind, Handle<FixedArrayBase> to,
+                    uint32_t to_start, int copy_size) final {
     DCHECK(!from.is_null());
     // NOTE: the ElementsAccessorSubclass::CopyElementsImpl() methods
     // violate the handlified function signature convention:
@@ -717,9 +829,9 @@
                                                kPackedSizeNotKnown, copy_size);
   }
 
-  virtual void CopyElements(JSObject* from_holder, uint32_t from_start,
-                            ElementsKind from_kind, Handle<FixedArrayBase> to,
-                            uint32_t to_start, int copy_size) FINAL {
+  void CopyElements(JSObject* from_holder, uint32_t from_start,
+                    ElementsKind from_kind, Handle<FixedArrayBase> to,
+                    uint32_t to_start, int copy_size) final {
     int packed_size = kPackedSizeNotKnown;
     bool is_packed = IsFastPackedElementsKind(from_kind) &&
         from_holder->IsJSArray();
@@ -744,104 +856,109 @@
         from, from_start, *to, from_kind, to_start, packed_size, copy_size);
   }
 
-  virtual MaybeHandle<FixedArray> AddElementsToFixedArray(
-      Handle<Object> receiver, Handle<JSObject> holder, Handle<FixedArray> to,
-      Handle<FixedArrayBase> from, FixedArray::KeyFilter filter) FINAL {
-    int len0 = to->length();
-#ifdef ENABLE_SLOW_DCHECKS
-    if (FLAG_enable_slow_asserts) {
-      for (int i = 0; i < len0; i++) {
-        DCHECK(!to->get(i)->IsTheHole());
-      }
+  static void CollectElementIndicesImpl(Handle<JSObject> object,
+                                        Handle<FixedArrayBase> backing_store,
+                                        KeyAccumulator* keys, uint32_t range,
+                                        PropertyFilter filter,
+                                        uint32_t offset) {
+    if (filter & ONLY_ALL_CAN_READ) {
+      // Non-dictionary elements can't have all-can-read accessors.
+      return;
     }
-#endif
-
-    // Optimize if 'other' is empty.
-    // We cannot optimize if 'this' is empty, as other may have holes.
-    uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
-    if (len1 == 0) return to;
-
-    Isolate* isolate = from->GetIsolate();
-
-    // Compute how many elements are not in other.
-    uint32_t extra = 0;
-    for (uint32_t y = 0; y < len1; y++) {
-      uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
-      if (ElementsAccessorSubclass::HasElementImpl(
-              receiver, holder, key, from)) {
-        Handle<Object> value;
-        ASSIGN_RETURN_ON_EXCEPTION(
-            isolate, value,
-            ElementsAccessorSubclass::GetImpl(receiver, holder, key, from),
-            FixedArray);
-
-        DCHECK(!value->IsTheHole());
-        if (filter == FixedArray::NON_SYMBOL_KEYS && value->IsSymbol()) {
-          continue;
-        }
-        if (!HasKey(to, value)) {
-          extra++;
-        }
-      }
+    uint32_t length = 0;
+    if (object->IsJSArray()) {
+      length = Smi::cast(JSArray::cast(*object)->length())->value();
+    } else {
+      length =
+          ElementsAccessorSubclass::GetCapacityImpl(*object, *backing_store);
     }
-
-    if (extra == 0) return to;
-
-    // Allocate the result
-    Handle<FixedArray> result = isolate->factory()->NewFixedArray(len0 + extra);
-
-    // Fill in the content
-    {
-      DisallowHeapAllocation no_gc;
-      WriteBarrierMode mode = result->GetWriteBarrierMode(no_gc);
-      for (int i = 0; i < len0; i++) {
-        Object* e = to->get(i);
-        DCHECK(e->IsString() || e->IsNumber());
-        result->set(i, e, mode);
-      }
+    if (range < length) length = range;
+    for (uint32_t i = offset; i < length; i++) {
+      if (!ElementsAccessorSubclass::HasElementImpl(object, i, backing_store,
+                                                    filter))
+        continue;
+      keys->AddKey(i);
     }
-    // Fill in the extra values.
-    uint32_t index = 0;
-    for (uint32_t y = 0; y < len1; y++) {
-      uint32_t key =
-          ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
-      if (ElementsAccessorSubclass::HasElementImpl(
-              receiver, holder, key, from)) {
-        Handle<Object> value;
-        ASSIGN_RETURN_ON_EXCEPTION(
-            isolate, value,
-            ElementsAccessorSubclass::GetImpl(receiver, holder, key, from),
-            FixedArray);
-        if (filter == FixedArray::NON_SYMBOL_KEYS && value->IsSymbol()) {
-          continue;
-        }
-        if (!value->IsTheHole() && !HasKey(to, value)) {
-          result->set(len0 + index, *value);
-          index++;
-        }
-      }
-    }
-    DCHECK(extra == index);
-    return result;
   }
 
- protected:
-  static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
+  void CollectElementIndices(Handle<JSObject> object,
+                             Handle<FixedArrayBase> backing_store,
+                             KeyAccumulator* keys, uint32_t range,
+                             PropertyFilter filter, uint32_t offset) final {
+    ElementsAccessorSubclass::CollectElementIndicesImpl(
+        object, backing_store, keys, range, filter, offset);
+  };
+
+  void AddElementsToKeyAccumulator(Handle<JSObject> receiver,
+                                   KeyAccumulator* accumulator,
+                                   AddKeyConversion convert) final {
+    Handle<FixedArrayBase> from(receiver->elements());
+    uint32_t add_length =
+        ElementsAccessorSubclass::GetCapacityImpl(*receiver, *from);
+    if (add_length == 0) return;
+
+    for (uint32_t i = 0; i < add_length; i++) {
+      if (!ElementsAccessorSubclass::HasEntryImpl(*from, i)) continue;
+      Handle<Object> value = ElementsAccessorSubclass::GetImpl(from, i);
+      DCHECK(!value->IsTheHole());
+      DCHECK(!value->IsAccessorPair());
+      DCHECK(!value->IsExecutableAccessorInfo());
+      accumulator->AddKey(value, convert);
+    }
+  }
+
+  static uint32_t GetCapacityImpl(JSObject* holder,
+                                  FixedArrayBase* backing_store) {
     return backing_store->length();
   }
 
-  uint32_t GetCapacity(Handle<FixedArrayBase> backing_store) FINAL {
-    return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
+  uint32_t GetCapacity(JSObject* holder, FixedArrayBase* backing_store) final {
+    return ElementsAccessorSubclass::GetCapacityImpl(holder, backing_store);
   }
 
-  static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> backing_store,
-                                     uint32_t index) {
-    return index;
+  static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
+    return true;
   }
 
-  virtual uint32_t GetKeyForIndex(Handle<FixedArrayBase> backing_store,
-                                  uint32_t index) FINAL {
-    return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
+  static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
+                                       uint32_t entry) {
+    return entry;
+  }
+
+  static uint32_t GetEntryForIndexImpl(JSObject* holder,
+                                       FixedArrayBase* backing_store,
+                                       uint32_t index, PropertyFilter filter) {
+    if (IsHoleyElementsKind(kind())) {
+      return index < ElementsAccessorSubclass::GetCapacityImpl(holder,
+                                                               backing_store) &&
+                     !BackingStore::cast(backing_store)->is_the_hole(index)
+                 ? index
+                 : kMaxUInt32;
+    } else {
+      uint32_t length =
+          holder->IsJSArray()
+              ? static_cast<uint32_t>(
+                    Smi::cast(JSArray::cast(holder)->length())->value())
+              : ElementsAccessorSubclass::GetCapacityImpl(holder,
+                                                          backing_store);
+      return index < length ? index : kMaxUInt32;
+    }
+  }
+
+  uint32_t GetEntryForIndex(JSObject* holder, FixedArrayBase* backing_store,
+                            uint32_t index) final {
+    return ElementsAccessorSubclass::GetEntryForIndexImpl(
+        holder, backing_store, index, ALL_PROPERTIES);
+  }
+
+  static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
+                                        uint32_t entry) {
+    return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
+  }
+
+  PropertyDetails GetDetails(FixedArrayBase* backing_store,
+                             uint32_t entry) final {
+    return ElementsAccessorSubclass::GetDetailsImpl(backing_store, entry);
   }
 
  private:
@@ -849,6 +966,202 @@
 };
 
 
+class DictionaryElementsAccessor
+    : public ElementsAccessorBase<DictionaryElementsAccessor,
+                                  ElementsKindTraits<DICTIONARY_ELEMENTS> > {
+ public:
+  explicit DictionaryElementsAccessor(const char* name)
+      : ElementsAccessorBase<DictionaryElementsAccessor,
+                             ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
+
+  static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+                            uint32_t length,
+                            Handle<FixedArrayBase> backing_store) {
+    Handle<SeededNumberDictionary> dict =
+        Handle<SeededNumberDictionary>::cast(backing_store);
+    int capacity = dict->Capacity();
+    uint32_t old_length = 0;
+    CHECK(array->length()->ToArrayLength(&old_length));
+    if (length < old_length) {
+      if (dict->requires_slow_elements()) {
+        // Find last non-deletable element in range of elements to be
+        // deleted and adjust range accordingly.
+        for (int entry = 0; entry < capacity; entry++) {
+          DisallowHeapAllocation no_gc;
+          Object* index = dict->KeyAt(entry);
+          if (index->IsNumber()) {
+            uint32_t number = static_cast<uint32_t>(index->Number());
+            if (length <= number && number < old_length) {
+              PropertyDetails details = dict->DetailsAt(entry);
+              if (!details.IsConfigurable()) length = number + 1;
+            }
+          }
+        }
+      }
+
+      if (length == 0) {
+        // Flush the backing store.
+        JSObject::ResetElements(array);
+      } else {
+        DisallowHeapAllocation no_gc;
+        // Remove elements that should be deleted.
+        int removed_entries = 0;
+        Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
+        for (int entry = 0; entry < capacity; entry++) {
+          Object* index = dict->KeyAt(entry);
+          if (index->IsNumber()) {
+            uint32_t number = static_cast<uint32_t>(index->Number());
+            if (length <= number && number < old_length) {
+              dict->SetEntry(entry, the_hole_value, the_hole_value);
+              removed_entries++;
+            }
+          }
+        }
+
+        // Update the number of elements.
+        dict->ElementsRemoved(removed_entries);
+      }
+    }
+
+    Handle<Object> length_obj = isolate->factory()->NewNumberFromUint(length);
+    array->set_length(*length_obj);
+  }
+
+  static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
+                               FixedArrayBase* to, ElementsKind from_kind,
+                               uint32_t to_start, int packed_size,
+                               int copy_size) {
+    UNREACHABLE();
+  }
+
+
+  static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+    // TODO(verwaest): Remove reliance on index in Shrink.
+    Handle<SeededNumberDictionary> dict(
+        SeededNumberDictionary::cast(obj->elements()));
+    uint32_t index = GetIndexForEntryImpl(*dict, entry);
+    Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
+    USE(result);
+    DCHECK(result->IsTrue());
+    Handle<FixedArray> new_elements =
+        SeededNumberDictionary::Shrink(dict, index);
+    obj->set_elements(*new_elements);
+  }
+
+  static Object* GetRaw(FixedArrayBase* store, uint32_t entry) {
+    SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
+    return backing_store->ValueAt(entry);
+  }
+
+  static Handle<Object> GetImpl(Handle<FixedArrayBase> store, uint32_t entry) {
+    Isolate* isolate = store->GetIsolate();
+    return handle(GetRaw(*store, entry), isolate);
+  }
+
+  static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
+                             Object* value) {
+    SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
+    dictionary->ValueAtPut(entry, value);
+  }
+
+  static void ReconfigureImpl(Handle<JSObject> object,
+                              Handle<FixedArrayBase> store, uint32_t entry,
+                              Handle<Object> value,
+                              PropertyAttributes attributes) {
+    SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(*store);
+    if (attributes != NONE) object->RequireSlowElements(dictionary);
+    dictionary->ValueAtPut(entry, *value);
+    PropertyDetails details = dictionary->DetailsAt(entry);
+    details = PropertyDetails(attributes, DATA, details.dictionary_index(),
+                              PropertyCellType::kNoCell);
+    dictionary->DetailsAtPut(entry, details);
+  }
+
+  static void AddImpl(Handle<JSObject> object, uint32_t index,
+                      Handle<Object> value, PropertyAttributes attributes,
+                      uint32_t new_capacity) {
+    PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+    Handle<SeededNumberDictionary> dictionary =
+        object->HasFastElements()
+            ? JSObject::NormalizeElements(object)
+            : handle(SeededNumberDictionary::cast(object->elements()));
+    Handle<SeededNumberDictionary> new_dictionary =
+        SeededNumberDictionary::AddNumberEntry(
+            dictionary, index, value, details,
+            object->map()->is_prototype_map());
+    if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
+    if (dictionary.is_identical_to(new_dictionary)) return;
+    object->set_elements(*new_dictionary);
+  }
+
+  static bool HasEntryImpl(FixedArrayBase* store, uint32_t entry) {
+    DisallowHeapAllocation no_gc;
+    SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
+    Object* index = dict->KeyAt(entry);
+    return !index->IsTheHole();
+  }
+
+  static uint32_t GetIndexForEntryImpl(FixedArrayBase* store, uint32_t entry) {
+    DisallowHeapAllocation no_gc;
+    SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
+    uint32_t result = 0;
+    CHECK(dict->KeyAt(entry)->ToArrayIndex(&result));
+    return result;
+  }
+
+  static uint32_t GetEntryForIndexImpl(JSObject* holder, FixedArrayBase* store,
+                                       uint32_t index, PropertyFilter filter) {
+    DisallowHeapAllocation no_gc;
+    SeededNumberDictionary* dictionary = SeededNumberDictionary::cast(store);
+    int entry = dictionary->FindEntry(index);
+    if (entry == SeededNumberDictionary::kNotFound) return kMaxUInt32;
+    if (filter != ALL_PROPERTIES) {
+      PropertyDetails details = dictionary->DetailsAt(entry);
+      PropertyAttributes attr = details.attributes();
+      if ((attr & filter) != 0) return kMaxUInt32;
+    }
+    return static_cast<uint32_t>(entry);
+  }
+
+  static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
+                                        uint32_t entry) {
+    return SeededNumberDictionary::cast(backing_store)->DetailsAt(entry);
+  }
+
+  static void CollectElementIndicesImpl(Handle<JSObject> object,
+                                        Handle<FixedArrayBase> backing_store,
+                                        KeyAccumulator* keys, uint32_t range,
+                                        PropertyFilter filter,
+                                        uint32_t offset) {
+    Handle<SeededNumberDictionary> dictionary =
+        Handle<SeededNumberDictionary>::cast(backing_store);
+    int capacity = dictionary->Capacity();
+    for (int i = 0; i < capacity; i++) {
+      Object* k = dictionary->KeyAt(i);
+      if (!dictionary->IsKey(k)) continue;
+      if (k->FilterKey(filter)) continue;
+      if (dictionary->IsDeleted(i)) continue;
+      DCHECK(k->IsNumber());
+      DCHECK_LE(k->Number(), kMaxUInt32);
+      uint32_t index = static_cast<uint32_t>(k->Number());
+      if (index < offset) continue;
+      PropertyDetails details = dictionary->DetailsAt(i);
+      if (filter & ONLY_ALL_CAN_READ) {
+        if (details.kind() != kAccessor) continue;
+        Object* accessors = dictionary->ValueAt(i);
+        if (!accessors->IsAccessorInfo()) continue;
+        if (!AccessorInfo::cast(accessors)->all_can_read()) continue;
+      }
+      PropertyAttributes attr = details.attributes();
+      if ((attr & filter) != 0) continue;
+      keys->AddKey(index);
+    }
+
+    keys->SortCurrentElementsList();
+  }
+};
+
+
 // Super class for all fast element arrays.
 template<typename FastElementsAccessorSubclass,
          typename KindTraits>
@@ -858,136 +1171,136 @@
   explicit FastElementsAccessor(const char* name)
       : ElementsAccessorBase<FastElementsAccessorSubclass,
                              KindTraits>(name) {}
- protected:
-  friend class ElementsAccessorBase<FastElementsAccessorSubclass, KindTraits>;
-  friend class SloppyArgumentsElementsAccessor;
 
   typedef typename KindTraits::BackingStore BackingStore;
 
-  // Adjusts the length of the fast backing store.
-  static Handle<Object> SetLengthWithoutNormalize(
-      Handle<FixedArrayBase> backing_store,
-      Handle<JSArray> array,
-      Handle<Object> length_object,
-      uint32_t length) {
-    Isolate* isolate = array->GetIsolate();
-    uint32_t old_capacity = backing_store->length();
-    Handle<Object> old_length(array->length(), isolate);
-    bool same_or_smaller_size = old_length->IsSmi() &&
-        static_cast<uint32_t>(Handle<Smi>::cast(old_length)->value()) >= length;
-    ElementsKind kind = array->GetElementsKind();
-
-    if (!same_or_smaller_size && IsFastElementsKind(kind) &&
-        !IsFastHoleyElementsKind(kind)) {
-      kind = GetHoleyElementsKind(kind);
-      JSObject::TransitionElementsKind(array, kind);
+  static void DeleteAtEnd(Handle<JSObject> obj,
+                          Handle<BackingStore> backing_store, uint32_t entry) {
+    uint32_t length = static_cast<uint32_t>(backing_store->length());
+    Heap* heap = obj->GetHeap();
+    for (; entry > 0; entry--) {
+      if (!backing_store->is_the_hole(entry - 1)) break;
     }
-
-    // Check whether the backing store should be shrunk.
-    if (length <= old_capacity) {
-      if (array->HasFastSmiOrObjectElements()) {
-        backing_store = JSObject::EnsureWritableFastElements(array);
-      }
-      if (2 * length <= old_capacity) {
-        // If more than half the elements won't be used, trim the array.
-        if (length == 0) {
-          array->initialize_elements();
-        } else {
-          isolate->heap()->RightTrimFixedArray<Heap::FROM_MUTATOR>(
-              *backing_store, old_capacity - length);
-        }
+    if (entry == 0) {
+      FixedArray* empty = heap->empty_fixed_array();
+      if (obj->HasFastArgumentsElements()) {
+        FixedArray::cast(obj->elements())->set(1, empty);
       } else {
-        // Otherwise, fill the unused tail with holes.
-        int old_length = FastD2IChecked(array->length()->Number());
-        for (int i = length; i < old_length; i++) {
-          Handle<BackingStore>::cast(backing_store)->set_the_hole(i);
-        }
+        obj->set_elements(empty);
       }
-      return length_object;
+      return;
     }
 
-    // Check whether the backing store should be expanded.
-    uint32_t min = JSObject::NewElementsCapacity(old_capacity);
-    uint32_t new_capacity = length > min ? length : min;
-    FastElementsAccessorSubclass::SetFastElementsCapacityAndLength(
-        array, new_capacity, length);
-    JSObject::ValidateElements(array);
-    return length_object;
+    heap->RightTrimFixedArray<Heap::CONCURRENT_TO_SWEEPER>(*backing_store,
+                                                           length - entry);
   }
 
-  static Handle<Object> DeleteCommon(Handle<JSObject> obj,
-                                     uint32_t key,
-                                     JSReceiver::DeleteMode mode) {
+  static void DeleteCommon(Handle<JSObject> obj, uint32_t entry,
+                           Handle<FixedArrayBase> store) {
     DCHECK(obj->HasFastSmiOrObjectElements() ||
            obj->HasFastDoubleElements() ||
            obj->HasFastArgumentsElements());
-    Isolate* isolate = obj->GetIsolate();
-    Heap* heap = obj->GetHeap();
-    Handle<FixedArrayBase> elements(obj->elements());
-    if (*elements == heap->empty_fixed_array()) {
-      return isolate->factory()->true_value();
+    Handle<BackingStore> backing_store = Handle<BackingStore>::cast(store);
+    if (!obj->IsJSArray() &&
+        entry == static_cast<uint32_t>(store->length()) - 1) {
+      DeleteAtEnd(obj, backing_store, entry);
+      return;
     }
-    Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
-    bool is_sloppy_arguments_elements_map =
-        backing_store->map() == heap->sloppy_arguments_elements_map();
-    if (is_sloppy_arguments_elements_map) {
-      backing_store = handle(
-          BackingStore::cast(Handle<FixedArray>::cast(backing_store)->get(1)),
-          isolate);
+
+    backing_store->set_the_hole(entry);
+
+    // TODO(verwaest): Move this out of elements.cc.
+    // If an old space backing store is larger than a certain size and
+    // has too few used values, normalize it.
+    // To avoid doing the check on every delete we require at least
+    // one adjacent hole to the value being deleted.
+    const int kMinLengthForSparsenessCheck = 64;
+    if (backing_store->length() < kMinLengthForSparsenessCheck) return;
+    if (backing_store->GetHeap()->InNewSpace(*backing_store)) return;
+    uint32_t length = 0;
+    if (obj->IsJSArray()) {
+      JSArray::cast(*obj)->length()->ToArrayLength(&length);
+    } else {
+      length = static_cast<uint32_t>(store->length());
     }
-    uint32_t length = static_cast<uint32_t>(
-        obj->IsJSArray()
-        ? Smi::cast(Handle<JSArray>::cast(obj)->length())->value()
-        : backing_store->length());
-    if (key < length) {
-      if (!is_sloppy_arguments_elements_map) {
-        ElementsKind kind = KindTraits::Kind;
-        if (IsFastPackedElementsKind(kind)) {
-          JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
+    if ((entry > 0 && backing_store->is_the_hole(entry - 1)) ||
+        (entry + 1 < length && backing_store->is_the_hole(entry + 1))) {
+      if (!obj->IsJSArray()) {
+        uint32_t i;
+        for (i = entry + 1; i < length; i++) {
+          if (!backing_store->is_the_hole(i)) break;
         }
-        if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
-          Handle<Object> writable = JSObject::EnsureWritableFastElements(obj);
-          backing_store = Handle<BackingStore>::cast(writable);
+        if (i == length) {
+          DeleteAtEnd(obj, backing_store, entry);
+          return;
         }
       }
-      backing_store->set_the_hole(key);
-      // If an old space backing store is larger than a certain size and
-      // has too few used values, normalize it.
-      // To avoid doing the check on every delete we require at least
-      // one adjacent hole to the value being deleted.
-      const int kMinLengthForSparsenessCheck = 64;
-      if (backing_store->length() >= kMinLengthForSparsenessCheck &&
-          !heap->InNewSpace(*backing_store) &&
-          ((key > 0 && backing_store->is_the_hole(key - 1)) ||
-           (key + 1 < length && backing_store->is_the_hole(key + 1)))) {
-        int num_used = 0;
-        for (int i = 0; i < backing_store->length(); ++i) {
-          if (!backing_store->is_the_hole(i)) ++num_used;
-          // Bail out early if more than 1/4 is used.
-          if (4 * num_used > backing_store->length()) break;
-        }
-        if (4 * num_used <= backing_store->length()) {
-          JSObject::NormalizeElements(obj);
+      int num_used = 0;
+      for (int i = 0; i < backing_store->length(); ++i) {
+        if (!backing_store->is_the_hole(i)) {
+          ++num_used;
+          // Bail out if a number dictionary wouldn't be able to save at least
+          // 75% space.
+          if (4 * SeededNumberDictionary::ComputeCapacity(num_used) *
+                  SeededNumberDictionary::kEntrySize >
+              backing_store->length()) {
+            return;
+          }
         }
       }
+      JSObject::NormalizeElements(obj);
     }
-    return isolate->factory()->true_value();
   }
 
-  virtual MaybeHandle<Object> Delete(Handle<JSObject> obj, uint32_t key,
-                                     JSReceiver::DeleteMode mode) FINAL {
-    return DeleteCommon(obj, key, mode);
+  static void ReconfigureImpl(Handle<JSObject> object,
+                              Handle<FixedArrayBase> store, uint32_t entry,
+                              Handle<Object> value,
+                              PropertyAttributes attributes) {
+    Handle<SeededNumberDictionary> dictionary =
+        JSObject::NormalizeElements(object);
+    entry = dictionary->FindEntry(entry);
+    DictionaryElementsAccessor::ReconfigureImpl(object, dictionary, entry,
+                                                value, attributes);
   }
 
-  static bool HasElementImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> holder,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) {
-    if (key >= static_cast<uint32_t>(backing_store->length())) {
-      return false;
+  static void AddImpl(Handle<JSObject> object, uint32_t index,
+                      Handle<Object> value, PropertyAttributes attributes,
+                      uint32_t new_capacity) {
+    DCHECK_EQ(NONE, attributes);
+    ElementsKind from_kind = object->GetElementsKind();
+    ElementsKind to_kind = FastElementsAccessorSubclass::kind();
+    if (IsDictionaryElementsKind(from_kind) ||
+        IsFastDoubleElementsKind(from_kind) !=
+            IsFastDoubleElementsKind(to_kind) ||
+        FastElementsAccessorSubclass::GetCapacityImpl(
+            *object, object->elements()) != new_capacity) {
+      FastElementsAccessorSubclass::GrowCapacityAndConvertImpl(object,
+                                                               new_capacity);
+    } else {
+      if (from_kind != to_kind) {
+        JSObject::TransitionElementsKind(object, to_kind);
+      }
+      if (IsFastSmiOrObjectElementsKind(from_kind)) {
+        DCHECK(IsFastSmiOrObjectElementsKind(to_kind));
+        JSObject::EnsureWritableFastElements(object);
+      }
     }
-    return !Handle<BackingStore>::cast(backing_store)->is_the_hole(key);
+    FastElementsAccessorSubclass::SetImpl(object->elements(), index, *value);
+  }
+
+  static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+    ElementsKind kind = KindTraits::Kind;
+    if (IsFastPackedElementsKind(kind)) {
+      JSObject::TransitionElementsKind(obj, GetHoleyElementsKind(kind));
+    }
+    if (IsFastSmiOrObjectElementsKind(KindTraits::Kind)) {
+      JSObject::EnsureWritableFastElements(obj);
+    }
+    DeleteCommon(obj, entry, handle(obj->elements()));
+  }
+
+  static bool HasEntryImpl(FixedArrayBase* backing_store, uint32_t entry) {
+    return !BackingStore::cast(backing_store)->is_the_hole(entry);
   }
 
   static void ValidateContents(Handle<JSObject> holder, int length) {
@@ -1002,45 +1315,237 @@
            (IsFastDoubleElementsKind(KindTraits::Kind) ==
             ((map == isolate->heap()->fixed_array_map() && length == 0) ||
              map == isolate->heap()->fixed_double_array_map())));
+    if (length == 0) return;  // nothing to do!
     DisallowHeapAllocation no_gc;
-    for (int i = 0; i < length; i++) {
-      HandleScope scope(isolate);
-      Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
-      DCHECK((!IsFastSmiElementsKind(KindTraits::Kind) ||
-              BackingStore::get(backing_store, i)->IsSmi()) ||
-             (IsFastHoleyElementsKind(KindTraits::Kind) ==
-              backing_store->is_the_hole(i)));
+    Handle<BackingStore> backing_store = Handle<BackingStore>::cast(elements);
+    if (IsFastSmiElementsKind(KindTraits::Kind)) {
+      for (int i = 0; i < length; i++) {
+        DCHECK(BackingStore::get(backing_store, i)->IsSmi() ||
+               (IsFastHoleyElementsKind(KindTraits::Kind) &&
+                backing_store->is_the_hole(i)));
+      }
     }
 #endif
   }
-};
 
-
-static inline ElementsKind ElementsKindForArray(FixedArrayBase* array) {
-  switch (array->map()->instance_type()) {
-    case FIXED_ARRAY_TYPE:
-      if (array->IsDictionary()) {
-        return DICTIONARY_ELEMENTS;
-      } else {
-        return FAST_HOLEY_ELEMENTS;
-      }
-    case FIXED_DOUBLE_ARRAY_TYPE:
-      return FAST_HOLEY_DOUBLE_ELEMENTS;
-
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
-    case EXTERNAL_##TYPE##_ARRAY_TYPE:                                        \
-      return EXTERNAL_##TYPE##_ELEMENTS;                                      \
-    case FIXED_##TYPE##_ARRAY_TYPE:                                           \
-      return TYPE##_ELEMENTS;
-
-    TYPED_ARRAYS(TYPED_ARRAY_CASE)
-#undef TYPED_ARRAY_CASE
-
-    default:
-      UNREACHABLE();
+  static Handle<Object> PopImpl(Handle<JSArray> receiver,
+                                Handle<FixedArrayBase> backing_store) {
+    return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
+                                                       AT_END);
   }
-  return FAST_HOLEY_ELEMENTS;
-}
+
+  static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
+                                  Handle<FixedArrayBase> backing_store) {
+    return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
+                                                       AT_START);
+  }
+
+  static uint32_t PushImpl(Handle<JSArray> receiver,
+                           Handle<FixedArrayBase> backing_store,
+                           Arguments* args, uint32_t push_size) {
+    return FastElementsAccessorSubclass::AddArguments(receiver, backing_store,
+                                                      args, push_size, AT_END);
+  }
+
+  static uint32_t UnshiftImpl(Handle<JSArray> receiver,
+                              Handle<FixedArrayBase> backing_store,
+                              Arguments* args, uint32_t unshift_size) {
+    return FastElementsAccessorSubclass::AddArguments(
+        receiver, backing_store, args, unshift_size, AT_START);
+  }
+
+  static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
+                           Handle<FixedArrayBase> backing_store, int dst_index,
+                           int src_index, int len, int hole_start,
+                           int hole_end) {
+    UNREACHABLE();
+  }
+
+  static Handle<JSArray> SliceImpl(Handle<JSObject> receiver,
+                                   Handle<FixedArrayBase> backing_store,
+                                   uint32_t start, uint32_t end) {
+    DCHECK(start < end);
+    Isolate* isolate = receiver->GetIsolate();
+    int result_len = end - start;
+    Handle<JSArray> result_array = isolate->factory()->NewJSArray(
+        KindTraits::Kind, result_len, result_len);
+    DisallowHeapAllocation no_gc;
+    FastElementsAccessorSubclass::CopyElementsImpl(
+        *backing_store, start, result_array->elements(), KindTraits::Kind, 0,
+        kPackedSizeNotKnown, result_len);
+    FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
+        result_array);
+    return result_array;
+  }
+
+  static Handle<JSArray> SpliceImpl(Handle<JSArray> receiver,
+                                    Handle<FixedArrayBase> backing_store,
+                                    uint32_t start, uint32_t delete_count,
+                                    Arguments* args, uint32_t add_count) {
+    Isolate* isolate = receiver->GetIsolate();
+    Heap* heap = isolate->heap();
+    uint32_t length = Smi::cast(receiver->length())->value();
+    uint32_t new_length = length - delete_count + add_count;
+
+    if (new_length == 0) {
+      receiver->set_elements(heap->empty_fixed_array());
+      receiver->set_length(Smi::FromInt(0));
+      return isolate->factory()->NewJSArrayWithElements(
+          backing_store, KindTraits::Kind, delete_count);
+    }
+
+    // Construct the result array which holds the deleted elements.
+    Handle<JSArray> deleted_elements = isolate->factory()->NewJSArray(
+        KindTraits::Kind, delete_count, delete_count);
+    if (delete_count > 0) {
+      DisallowHeapAllocation no_gc;
+      FastElementsAccessorSubclass::CopyElementsImpl(
+          *backing_store, start, deleted_elements->elements(), KindTraits::Kind,
+          0, kPackedSizeNotKnown, delete_count);
+    }
+
+    // Delete and move elements to make space for add_count new elements.
+    if (add_count < delete_count) {
+      FastElementsAccessorSubclass::SpliceShrinkStep(
+          isolate, receiver, backing_store, start, delete_count, add_count,
+          length, new_length);
+    } else if (add_count > delete_count) {
+      backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
+          isolate, receiver, backing_store, start, delete_count, add_count,
+          length, new_length);
+    }
+
+    // Copy over the arguments.
+    FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
+                                                3, start);
+
+    receiver->set_length(Smi::FromInt(new_length));
+    FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
+        deleted_elements);
+    return deleted_elements;
+  }
+
+ private:
+  // SpliceShrinkStep might modify the backing_store.
+  static void SpliceShrinkStep(Isolate* isolate, Handle<JSArray> receiver,
+                               Handle<FixedArrayBase> backing_store,
+                               uint32_t start, uint32_t delete_count,
+                               uint32_t add_count, uint32_t len,
+                               uint32_t new_length) {
+    const int move_left_count = len - delete_count - start;
+    const int move_left_dst_index = start + add_count;
+    FastElementsAccessorSubclass::MoveElements(
+        isolate, receiver, backing_store, move_left_dst_index,
+        start + delete_count, move_left_count, new_length, len);
+  }
+
+  // SpliceGrowStep might modify the backing_store.
+  static Handle<FixedArrayBase> SpliceGrowStep(
+      Isolate* isolate, Handle<JSArray> receiver,
+      Handle<FixedArrayBase> backing_store, uint32_t start,
+      uint32_t delete_count, uint32_t add_count, uint32_t length,
+      uint32_t new_length) {
+    // Check we do not overflow the new_length.
+    DCHECK((add_count - delete_count) <= (Smi::kMaxValue - length));
+    // Check if backing_store is big enough.
+    if (new_length <= static_cast<uint32_t>(backing_store->length())) {
+      FastElementsAccessorSubclass::MoveElements(
+          isolate, receiver, backing_store, start + add_count,
+          start + delete_count, (length - delete_count - start), 0, 0);
+      // MoveElements updates the backing_store in-place.
+      return backing_store;
+    }
+    // New backing storage is needed.
+    int capacity = JSObject::NewElementsCapacity(new_length);
+    // Partially copy all elements up to start.
+    Handle<FixedArrayBase> new_elms =
+        FastElementsAccessorSubclass::ConvertElementsWithCapacity(
+            receiver, backing_store, KindTraits::Kind, capacity, start);
+    // Copy the trailing elements after start + delete_count
+    FastElementsAccessorSubclass::CopyElementsImpl(
+        *backing_store, start + delete_count, *new_elms, KindTraits::Kind,
+        start + add_count, kPackedSizeNotKnown,
+        ElementsAccessor::kCopyToEndAndInitializeToHole);
+    receiver->set_elements(*new_elms);
+    return new_elms;
+  }
+
+  static Handle<Object> RemoveElement(Handle<JSArray> receiver,
+                                      Handle<FixedArrayBase> backing_store,
+                                      Where remove_position) {
+    Isolate* isolate = receiver->GetIsolate();
+    uint32_t length =
+        static_cast<uint32_t>(Smi::cast(receiver->length())->value());
+    DCHECK(length > 0);
+    int new_length = length - 1;
+    int remove_index = remove_position == AT_START ? 0 : new_length;
+    Handle<Object> result =
+        FastElementsAccessorSubclass::GetImpl(backing_store, remove_index);
+    if (remove_position == AT_START) {
+      FastElementsAccessorSubclass::MoveElements(
+          isolate, receiver, backing_store, 0, 1, new_length, 0, 0);
+    }
+    FastElementsAccessorSubclass::SetLengthImpl(isolate, receiver, new_length,
+                                                backing_store);
+
+    if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
+      return receiver->GetIsolate()->factory()->undefined_value();
+    }
+    return result;
+  }
+
+  static uint32_t AddArguments(Handle<JSArray> receiver,
+                               Handle<FixedArrayBase> backing_store,
+                               Arguments* args, uint32_t add_size,
+                               Where remove_position) {
+    uint32_t length = Smi::cast(receiver->length())->value();
+    DCHECK(add_size > 0);
+    uint32_t elms_len = backing_store->length();
+    // Check we do not overflow the new_length.
+    DCHECK(add_size <= static_cast<uint32_t>(Smi::kMaxValue - length));
+    uint32_t new_length = length + add_size;
+
+    if (new_length > elms_len) {
+      // New backing storage is needed.
+      uint32_t capacity = JSObject::NewElementsCapacity(new_length);
+      // If we add arguments to the start we have to shift the existing objects.
+      int copy_dst_index = remove_position == AT_START ? add_size : 0;
+      // Copy over all objects to a new backing_store.
+      backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
+          receiver, backing_store, KindTraits::Kind, capacity, 0,
+          copy_dst_index, ElementsAccessor::kCopyToEndAndInitializeToHole);
+      receiver->set_elements(*backing_store);
+    } else if (remove_position == AT_START) {
+      // If the backing store has enough capacity and we add elements to the
+      // start we have to shift the existing objects.
+      Isolate* isolate = receiver->GetIsolate();
+      FastElementsAccessorSubclass::MoveElements(
+          isolate, receiver, backing_store, add_size, 0, length, 0, 0);
+    }
+
+    int insertion_index = remove_position == AT_START ? 0 : length;
+    // Copy the arguments to the start.
+    FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_size,
+                                                1, insertion_index);
+    // Set the length.
+    receiver->set_length(Smi::FromInt(new_length));
+    return new_length;
+  }
+
+  static void CopyArguments(Arguments* args, Handle<FixedArrayBase> dst_store,
+                            uint32_t copy_size, uint32_t src_index,
+                            uint32_t dst_index) {
+    // Add the provided values.
+    DisallowHeapAllocation no_gc;
+    FixedArrayBase* raw_backing_store = *dst_store;
+    WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
+    for (uint32_t i = 0; i < copy_size; i++) {
+      Object* argument = (*args)[i + src_index];
+      FastElementsAccessorSubclass::SetImpl(raw_backing_store, i + dst_index,
+                                            argument, mode);
+    }
+  }
+};
 
 
 template<typename FastElementsAccessorSubclass,
@@ -1052,6 +1557,46 @@
       : FastElementsAccessor<FastElementsAccessorSubclass,
                              KindTraits>(name) {}
 
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value) {
+    FixedArray::cast(backing_store)->set(entry, value);
+  }
+
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value, WriteBarrierMode mode) {
+    FixedArray::cast(backing_store)->set(entry, value, mode);
+  }
+
+  static Object* GetRaw(FixedArray* backing_store, uint32_t entry) {
+    uint32_t index = FastElementsAccessorSubclass::GetIndexForEntryImpl(
+        backing_store, entry);
+    return backing_store->get(index);
+  }
+
+  static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
+                           Handle<FixedArrayBase> backing_store, int dst_index,
+                           int src_index, int len, int hole_start,
+                           int hole_end) {
+    Heap* heap = isolate->heap();
+    Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
+    if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
+      // Update all the copies of this backing_store handle.
+      *dst_elms.location() =
+          FixedArray::cast(heap->LeftTrimFixedArray(*dst_elms, src_index));
+      receiver->set_elements(*dst_elms);
+      // Adjust the hole offset as the array has been shrunk.
+      hole_end -= src_index;
+      DCHECK_LE(hole_start, backing_store->length());
+      DCHECK_LE(hole_end, backing_store->length());
+    } else if (len != 0) {
+      DisallowHeapAllocation no_gc;
+      heap->MoveElements(*dst_elms, dst_index, src_index, len);
+    }
+    if (hole_start != hole_end) {
+      dst_elms->FillWithHoles(hole_start, hole_end);
+    }
+  }
+
   // NOTE: this method violates the handlified function signature convention:
   // raw pointer parameters in the function that allocates.
   // See ElementsAccessor::CopyElements() for details.
@@ -1074,46 +1619,24 @@
       case FAST_DOUBLE_ELEMENTS:
       case FAST_HOLEY_DOUBLE_ELEMENTS: {
         AllowHeapAllocation allow_allocation;
-        CopyDoubleToObjectElements(
-            from, from_start, to, to_kind, to_start, copy_size);
+        DCHECK(IsFastObjectElementsKind(to_kind));
+        CopyDoubleToObjectElements(from, from_start, to, to_start, copy_size);
         break;
       }
       case DICTIONARY_ELEMENTS:
         CopyDictionaryToObjectElements(from, from_start, to, to_kind, to_start,
                                        copy_size);
         break;
-      case SLOPPY_ARGUMENTS_ELEMENTS: {
-        // TODO(verwaest): This is a temporary hack to support extending
-        // SLOPPY_ARGUMENTS_ELEMENTS in SetFastElementsCapacityAndLength.
-        // This case should be UNREACHABLE().
-        FixedArray* parameter_map = FixedArray::cast(from);
-        FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
-        ElementsKind from_kind = ElementsKindForArray(arguments);
-        CopyElementsImpl(arguments, from_start, to, from_kind,
-                         to_start, packed_size, copy_size);
-        break;
-      }
+      case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+      case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
+        UNREACHABLE();
 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
-      case EXTERNAL_##TYPE##_ELEMENTS:                                        \
       case TYPE##_ELEMENTS:                                                   \
         UNREACHABLE();
       TYPED_ARRAYS(TYPED_ARRAY_CASE)
 #undef TYPED_ARRAY_CASE
     }
   }
-
-
-  static void SetFastElementsCapacityAndLength(
-      Handle<JSObject> obj,
-      uint32_t capacity,
-      uint32_t length) {
-    JSObject::SetFastElementsCapacitySmiMode set_capacity_mode =
-        obj->HasFastSmiElements()
-            ? JSObject::kAllowSmiElements
-            : JSObject::kDontAllowSmiElements;
-    JSObject::SetFastElementsCapacityAndLength(
-        obj, capacity, length, set_capacity_mode);
-  }
 };
 
 
@@ -1174,13 +1697,41 @@
       : FastElementsAccessor<FastElementsAccessorSubclass,
                              KindTraits>(name) {}
 
-  static void SetFastElementsCapacityAndLength(Handle<JSObject> obj,
-                                               uint32_t capacity,
-                                               uint32_t length) {
-    JSObject::SetFastDoubleElementsCapacityAndLength(obj, capacity, length);
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value) {
+    FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
   }
 
- protected:
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value, WriteBarrierMode mode) {
+    FixedDoubleArray::cast(backing_store)->set(entry, value->Number());
+  }
+
+  static void MoveElements(Isolate* isolate, Handle<JSArray> receiver,
+                           Handle<FixedArrayBase> backing_store, int dst_index,
+                           int src_index, int len, int hole_start,
+                           int hole_end) {
+    Heap* heap = isolate->heap();
+    Handle<FixedDoubleArray> dst_elms =
+        Handle<FixedDoubleArray>::cast(backing_store);
+    if (heap->CanMoveObjectStart(*dst_elms) && dst_index == 0) {
+      // Update all the copies of this backing_store handle.
+      *dst_elms.location() = FixedDoubleArray::cast(
+          heap->LeftTrimFixedArray(*dst_elms, src_index));
+      receiver->set_elements(*dst_elms);
+      // Adjust the hole offset as the array has been shrunk.
+      hole_end -= src_index;
+      DCHECK_LE(hole_start, backing_store->length());
+      DCHECK_LE(hole_end, backing_store->length());
+    } else if (len != 0) {
+      MemMove(dst_elms->data_start() + dst_index,
+              dst_elms->data_start() + src_index, len * kDoubleSize);
+    }
+    if (hole_start != hole_end) {
+      dst_elms->FillWithHoles(hole_start, hole_end);
+    }
+  }
+
   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
                                FixedArrayBase* to, ElementsKind from_kind,
                                uint32_t to_start, int packed_size,
@@ -1206,11 +1757,11 @@
         CopyDictionaryToDoubleElements(from, from_start, to, to_start,
                                        copy_size);
         break;
-      case SLOPPY_ARGUMENTS_ELEMENTS:
+      case FAST_SLOPPY_ARGUMENTS_ELEMENTS:
+      case SLOW_SLOPPY_ARGUMENTS_ELEMENTS:
         UNREACHABLE();
 
 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                       \
-      case EXTERNAL_##TYPE##_ELEMENTS:                                        \
       case TYPE##_ELEMENTS:                                                   \
         UNREACHABLE();
       TYPED_ARRAYS(TYPED_ARRAY_CASE)
@@ -1225,8 +1776,6 @@
         FastPackedDoubleElementsAccessor,
         ElementsKindTraits<FAST_DOUBLE_ELEMENTS> > {
  public:
-  friend class ElementsAccessorBase<FastPackedDoubleElementsAccessor,
-                                    ElementsKindTraits<FAST_DOUBLE_ELEMENTS> >;
   explicit FastPackedDoubleElementsAccessor(const char* name)
       : FastDoubleElementsAccessor<
           FastPackedDoubleElementsAccessor,
@@ -1239,9 +1788,6 @@
         FastHoleyDoubleElementsAccessor,
         ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> > {
  public:
-  friend class ElementsAccessorBase<
-    FastHoleyDoubleElementsAccessor,
-    ElementsKindTraits<FAST_HOLEY_DOUBLE_ELEMENTS> >;
   explicit FastHoleyDoubleElementsAccessor(const char* name)
       : FastDoubleElementsAccessor<
           FastHoleyDoubleElementsAccessor,
@@ -1259,69 +1805,64 @@
       : ElementsAccessorBase<AccessorClass,
                              ElementsKindTraits<Kind> >(name) {}
 
- protected:
   typedef typename ElementsKindTraits<Kind>::BackingStore BackingStore;
   typedef TypedElementsAccessor<Kind> AccessorClass;
 
-  friend class ElementsAccessorBase<AccessorClass,
-                                    ElementsKindTraits<Kind> >;
-
-  MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) {
-    if (key < AccessorClass::GetCapacityImpl(backing_store)) {
-      return BackingStore::get(Handle<BackingStore>::cast(backing_store), key);
-    } else {
-      return backing_store->GetIsolate()->factory()->undefined_value();
-    }
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value) {
+    BackingStore::cast(backing_store)->SetValue(entry, value);
   }
 
-  MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) {
-    return
-        key < AccessorClass::GetCapacityImpl(backing_store)
-          ? NONE : ABSENT;
+  static inline void SetImpl(FixedArrayBase* backing_store, uint32_t entry,
+                             Object* value, WriteBarrierMode mode) {
+    BackingStore::cast(backing_store)->SetValue(entry, value);
   }
 
-  MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
-      Handle<JSObject> obj,
-      Handle<Object> length,
-      Handle<FixedArrayBase> backing_store) {
+  static Handle<Object> GetImpl(Handle<FixedArrayBase> backing_store,
+                                uint32_t entry) {
+    uint32_t index = GetIndexForEntryImpl(*backing_store, entry);
+    return BackingStore::get(Handle<BackingStore>::cast(backing_store), index);
+  }
+
+  static PropertyDetails GetDetailsImpl(FixedArrayBase* backing_store,
+                                        uint32_t entry) {
+    return PropertyDetails(DONT_DELETE, DATA, 0, PropertyCellType::kNoCell);
+  }
+
+  static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+                            uint32_t length,
+                            Handle<FixedArrayBase> backing_store) {
     // External arrays do not support changing their length.
     UNREACHABLE();
-    return obj;
   }
 
-  MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
-    // External arrays always ignore deletes.
-    return obj->GetIsolate()->factory()->true_value();
+  static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+    UNREACHABLE();
   }
 
-  static bool HasElementImpl(Handle<Object> receiver,
-                             Handle<JSObject> holder,
-                             uint32_t key,
-                             Handle<FixedArrayBase> backing_store) {
-    uint32_t capacity =
-        AccessorClass::GetCapacityImpl(backing_store);
-    return key < capacity;
+  static uint32_t GetIndexForEntryImpl(FixedArrayBase* backing_store,
+                                       uint32_t entry) {
+    return entry;
+  }
+
+  static uint32_t GetEntryForIndexImpl(JSObject* holder,
+                                       FixedArrayBase* backing_store,
+                                       uint32_t index, PropertyFilter filter) {
+    return index < AccessorClass::GetCapacityImpl(holder, backing_store)
+               ? index
+               : kMaxUInt32;
+  }
+
+  static uint32_t GetCapacityImpl(JSObject* holder,
+                                  FixedArrayBase* backing_store) {
+    JSArrayBufferView* view = JSArrayBufferView::cast(holder);
+    if (view->WasNeutered()) return 0;
+    return backing_store->length();
   }
 };
 
 
 
-#define EXTERNAL_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size)    \
-  typedef TypedElementsAccessor<EXTERNAL_##TYPE##_ELEMENTS>          \
-      External##Type##ElementsAccessor;
-
-TYPED_ARRAYS(EXTERNAL_ELEMENTS_ACCESSOR)
-#undef EXTERNAL_ELEMENTS_ACCESSOR
-
 #define FIXED_ELEMENTS_ACCESSOR(Type, type, TYPE, ctype, size)       \
   typedef TypedElementsAccessor<TYPE##_ELEMENTS >                    \
       Fixed##Type##ElementsAccessor;
@@ -1330,507 +1871,409 @@
 #undef FIXED_ELEMENTS_ACCESSOR
 
 
-
-class DictionaryElementsAccessor
-    : public ElementsAccessorBase<DictionaryElementsAccessor,
-                                  ElementsKindTraits<DICTIONARY_ELEMENTS> > {
- public:
-  explicit DictionaryElementsAccessor(const char* name)
-      : ElementsAccessorBase<DictionaryElementsAccessor,
-                             ElementsKindTraits<DICTIONARY_ELEMENTS> >(name) {}
-
-  // Adjusts the length of the dictionary backing store and returns the new
-  // length according to ES5 section 15.4.5.2 behavior.
-  static Handle<Object> SetLengthWithoutNormalize(
-      Handle<FixedArrayBase> store,
-      Handle<JSArray> array,
-      Handle<Object> length_object,
-      uint32_t length) {
-    Handle<SeededNumberDictionary> dict =
-        Handle<SeededNumberDictionary>::cast(store);
-    Isolate* isolate = array->GetIsolate();
-    int capacity = dict->Capacity();
-    uint32_t new_length = length;
-    uint32_t old_length = static_cast<uint32_t>(array->length()->Number());
-    if (new_length < old_length) {
-      // Find last non-deletable element in range of elements to be
-      // deleted and adjust range accordingly.
-      for (int i = 0; i < capacity; i++) {
-        DisallowHeapAllocation no_gc;
-        Object* key = dict->KeyAt(i);
-        if (key->IsNumber()) {
-          uint32_t number = static_cast<uint32_t>(key->Number());
-          if (new_length <= number && number < old_length) {
-            PropertyDetails details = dict->DetailsAt(i);
-            if (!details.IsConfigurable()) new_length = number + 1;
-          }
-        }
-      }
-      if (new_length != length) {
-        length_object = isolate->factory()->NewNumberFromUint(new_length);
-      }
-    }
-
-    if (new_length == 0) {
-      // Flush the backing store.
-      JSObject::ResetElements(array);
-    } else {
-      DisallowHeapAllocation no_gc;
-      // Remove elements that should be deleted.
-      int removed_entries = 0;
-      Handle<Object> the_hole_value = isolate->factory()->the_hole_value();
-      for (int i = 0; i < capacity; i++) {
-        Object* key = dict->KeyAt(i);
-        if (key->IsNumber()) {
-          uint32_t number = static_cast<uint32_t>(key->Number());
-          if (new_length <= number && number < old_length) {
-            dict->SetEntry(i, the_hole_value, the_hole_value);
-            removed_entries++;
-          }
-        }
-      }
-
-      // Update the number of elements.
-      dict->ElementsRemoved(removed_entries);
-    }
-    return length_object;
-  }
-
-  MUST_USE_RESULT static MaybeHandle<Object> DeleteCommon(
-      Handle<JSObject> obj,
-      uint32_t key,
-      JSReceiver::DeleteMode mode) {
-    Isolate* isolate = obj->GetIsolate();
-    Handle<FixedArray> backing_store(FixedArray::cast(obj->elements()),
-                                     isolate);
-    bool is_arguments =
-        (obj->GetElementsKind() == SLOPPY_ARGUMENTS_ELEMENTS);
-    if (is_arguments) {
-      backing_store = handle(FixedArray::cast(backing_store->get(1)), isolate);
-    }
-    Handle<SeededNumberDictionary> dictionary =
-        Handle<SeededNumberDictionary>::cast(backing_store);
-    int entry = dictionary->FindEntry(key);
-    if (entry != SeededNumberDictionary::kNotFound) {
-      Handle<Object> result =
-          SeededNumberDictionary::DeleteProperty(dictionary, entry, mode);
-      if (*result == *isolate->factory()->false_value()) {
-        if (mode == JSObject::STRICT_DELETION) {
-          // Deleting a non-configurable property in strict mode.
-          Handle<Object> name = isolate->factory()->NewNumberFromUint(key);
-          Handle<Object> args[2] = { name, obj };
-          THROW_NEW_ERROR(isolate, NewTypeError("strict_delete_property",
-                                                HandleVector(args, 2)),
-                          Object);
-        }
-        return isolate->factory()->false_value();
-      }
-      Handle<FixedArray> new_elements =
-          SeededNumberDictionary::Shrink(dictionary, key);
-
-      if (is_arguments) {
-        FixedArray::cast(obj->elements())->set(1, *new_elements);
-      } else {
-        obj->set_elements(*new_elements);
-      }
-    }
-    return isolate->factory()->true_value();
-  }
-
-  static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
-                               FixedArrayBase* to, ElementsKind from_kind,
-                               uint32_t to_start, int packed_size,
-                               int copy_size) {
-    UNREACHABLE();
-  }
-
-
- protected:
-  friend class ElementsAccessorBase<DictionaryElementsAccessor,
-                                    ElementsKindTraits<DICTIONARY_ELEMENTS> >;
-
-  MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
-    return DeleteCommon(obj, key, mode);
-  }
-
-  MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> store) {
-    Handle<SeededNumberDictionary> backing_store =
-        Handle<SeededNumberDictionary>::cast(store);
-    Isolate* isolate = backing_store->GetIsolate();
-    int entry = backing_store->FindEntry(key);
-    if (entry != SeededNumberDictionary::kNotFound) {
-      Handle<Object> element(backing_store->ValueAt(entry), isolate);
-      PropertyDetails details = backing_store->DetailsAt(entry);
-      if (details.type() == CALLBACKS) {
-        return JSObject::GetElementWithCallback(
-            obj, receiver, element, key, obj);
-      } else {
-        return element;
-      }
-    }
-    return isolate->factory()->the_hole_value();
-  }
-
-  MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) {
-    Handle<SeededNumberDictionary> dictionary =
-        Handle<SeededNumberDictionary>::cast(backing_store);
-    int entry = dictionary->FindEntry(key);
-    if (entry != SeededNumberDictionary::kNotFound) {
-      return dictionary->DetailsAt(entry).attributes();
-    }
-    return ABSENT;
-  }
-
-  MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> store) {
-    Handle<SeededNumberDictionary> backing_store =
-        Handle<SeededNumberDictionary>::cast(store);
-    int entry = backing_store->FindEntry(key);
-    if (entry != SeededNumberDictionary::kNotFound &&
-        backing_store->DetailsAt(entry).type() == CALLBACKS &&
-        backing_store->ValueAt(entry)->IsAccessorPair()) {
-      return handle(AccessorPair::cast(backing_store->ValueAt(entry)));
-    }
-    return MaybeHandle<AccessorPair>();
-  }
-
-  static bool HasElementImpl(Handle<Object> receiver,
-                             Handle<JSObject> holder,
-                             uint32_t key,
-                             Handle<FixedArrayBase> store) {
-    Handle<SeededNumberDictionary> backing_store =
-        Handle<SeededNumberDictionary>::cast(store);
-    return backing_store->FindEntry(key) != SeededNumberDictionary::kNotFound;
-  }
-
-  static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> store,
-                                     uint32_t index) {
-    DisallowHeapAllocation no_gc;
-    Handle<SeededNumberDictionary> dict =
-        Handle<SeededNumberDictionary>::cast(store);
-    Object* key = dict->KeyAt(index);
-    return Smi::cast(key)->value();
-  }
-};
-
-
-class SloppyArgumentsElementsAccessor : public ElementsAccessorBase<
-    SloppyArgumentsElementsAccessor,
-    ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> > {
+template <typename SloppyArgumentsElementsAccessorSubclass,
+          typename ArgumentsAccessor, typename KindTraits>
+class SloppyArgumentsElementsAccessor
+    : public ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
+                                  KindTraits> {
  public:
   explicit SloppyArgumentsElementsAccessor(const char* name)
-      : ElementsAccessorBase<
-          SloppyArgumentsElementsAccessor,
-          ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
- protected:
-  friend class ElementsAccessorBase<
-      SloppyArgumentsElementsAccessor,
-      ElementsKindTraits<SLOPPY_ARGUMENTS_ELEMENTS> >;
+      : ElementsAccessorBase<SloppyArgumentsElementsAccessorSubclass,
+                             KindTraits>(name) {
+    USE(KindTraits::Kind);
+  }
 
-  MUST_USE_RESULT static MaybeHandle<Object> GetImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> parameters) {
-    Isolate* isolate = obj->GetIsolate();
+  static Handle<Object> GetImpl(Handle<FixedArrayBase> parameters,
+                                uint32_t entry) {
+    Isolate* isolate = parameters->GetIsolate();
     Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
-    Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
-    if (!probe->IsTheHole()) {
+    uint32_t length = parameter_map->length() - 2;
+    if (entry < length) {
       DisallowHeapAllocation no_gc;
+      Object* probe = parameter_map->get(entry + 2);
       Context* context = Context::cast(parameter_map->get(0));
-      int context_index = Handle<Smi>::cast(probe)->value();
-      DCHECK(!context->get(context_index)->IsTheHole());
-      return handle(context->get(context_index), isolate);
+      int context_entry = Smi::cast(probe)->value();
+      DCHECK(!context->get(context_entry)->IsTheHole());
+      return handle(context->get(context_entry), isolate);
     } else {
       // Object is not mapped, defer to the arguments.
       Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)),
                                    isolate);
-      Handle<Object> result;
-      ASSIGN_RETURN_ON_EXCEPTION(
-          isolate, result,
-          ElementsAccessor::ForArray(arguments)->Get(
-              receiver, obj, key, arguments),
-          Object);
+      Handle<Object> result =
+          ArgumentsAccessor::GetImpl(arguments, entry - length);
       // Elements of the arguments object in slow mode might be slow aliases.
       if (result->IsAliasedArgumentsEntry()) {
         DisallowHeapAllocation no_gc;
-        AliasedArgumentsEntry* entry = AliasedArgumentsEntry::cast(*result);
+        AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(*result);
         Context* context = Context::cast(parameter_map->get(0));
-        int context_index = entry->aliased_context_slot();
-        DCHECK(!context->get(context_index)->IsTheHole());
-        return handle(context->get(context_index), isolate);
+        int context_entry = alias->aliased_context_slot();
+        DCHECK(!context->get(context_entry)->IsTheHole());
+        return handle(context->get(context_entry), isolate);
+      }
+      return result;
+    }
+  }
+
+  static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
+                                         uint32_t capacity) {
+    UNREACHABLE();
+  }
+
+  static inline void SetImpl(FixedArrayBase* store, uint32_t entry,
+                             Object* value) {
+    FixedArray* parameter_map = FixedArray::cast(store);
+    uint32_t length = parameter_map->length() - 2;
+    if (entry < length) {
+      Object* probe = parameter_map->get(entry + 2);
+      Context* context = Context::cast(parameter_map->get(0));
+      int context_entry = Smi::cast(probe)->value();
+      DCHECK(!context->get(context_entry)->IsTheHole());
+      context->set(context_entry, value);
+    } else {
+      FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+      Object* current = ArgumentsAccessor::GetRaw(arguments, entry - length);
+      if (current->IsAliasedArgumentsEntry()) {
+        AliasedArgumentsEntry* alias = AliasedArgumentsEntry::cast(current);
+        Context* context = Context::cast(parameter_map->get(0));
+        int context_entry = alias->aliased_context_slot();
+        DCHECK(!context->get(context_entry)->IsTheHole());
+        context->set(context_entry, value);
       } else {
-        return result;
+        ArgumentsAccessor::SetImpl(arguments, entry - length, value);
       }
     }
   }
 
-  MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> backing_store) {
-    Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(backing_store);
-    Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
-    if (!probe->IsTheHole()) {
-      return NONE;
-    } else {
-      // If not aliased, check the arguments.
-      Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
-      return ElementsAccessor::ForArray(arguments)->GetAttributes(
-          receiver, obj, key, arguments);
+  static void SetLengthImpl(Isolate* isolate, Handle<JSArray> array,
+                            uint32_t length,
+                            Handle<FixedArrayBase> parameter_map) {
+    // Sloppy arguments objects are not arrays.
+    UNREACHABLE();
+  }
+
+  static uint32_t GetCapacityImpl(JSObject* holder,
+                                  FixedArrayBase* backing_store) {
+    FixedArray* parameter_map = FixedArray::cast(backing_store);
+    FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
+    return parameter_map->length() - 2 +
+           ArgumentsAccessor::GetCapacityImpl(holder, arguments);
+  }
+
+  static bool HasEntryImpl(FixedArrayBase* parameters, uint32_t entry) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
+    uint32_t length = parameter_map->length() - 2;
+    if (entry < length) {
+      return !GetParameterMapArg(parameter_map, entry)->IsTheHole();
     }
+
+    FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
+    return ArgumentsAccessor::HasEntryImpl(arguments, entry - length);
   }
 
-  MUST_USE_RESULT static MaybeHandle<AccessorPair> GetAccessorPairImpl(
-      Handle<Object> receiver,
-      Handle<JSObject> obj,
-      uint32_t key,
-      Handle<FixedArrayBase> parameters) {
-    Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
-    Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
-    if (!probe->IsTheHole()) {
-      return MaybeHandle<AccessorPair>();
-    } else {
-      // If not aliased, check the arguments.
-      Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
-      return ElementsAccessor::ForArray(arguments)->GetAccessorPair(
-          receiver, obj, key, arguments);
+  static uint32_t GetIndexForEntryImpl(FixedArrayBase* parameters,
+                                       uint32_t entry) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
+    uint32_t length = parameter_map->length() - 2;
+    if (entry < length) return entry;
+
+    FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+    return ArgumentsAccessor::GetIndexForEntryImpl(arguments, entry - length);
+  }
+
+  static uint32_t GetEntryForIndexImpl(JSObject* holder,
+                                       FixedArrayBase* parameters,
+                                       uint32_t index, PropertyFilter filter) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
+    Object* probe = GetParameterMapArg(parameter_map, index);
+    if (!probe->IsTheHole()) return index;
+
+    FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+    uint32_t entry = ArgumentsAccessor::GetEntryForIndexImpl(holder, arguments,
+                                                             index, filter);
+    if (entry == kMaxUInt32) return entry;
+    return (parameter_map->length() - 2) + entry;
+  }
+
+  static PropertyDetails GetDetailsImpl(FixedArrayBase* parameters,
+                                        uint32_t entry) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
+    uint32_t length = parameter_map->length() - 2;
+    if (entry < length) {
+      return PropertyDetails(NONE, DATA, 0, PropertyCellType::kNoCell);
     }
+    FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+    return ArgumentsAccessor::GetDetailsImpl(arguments, entry - length);
   }
 
-  MUST_USE_RESULT static MaybeHandle<Object> SetLengthImpl(
-      Handle<JSObject> obj,
-      Handle<Object> length,
-      Handle<FixedArrayBase> parameter_map) {
-    // TODO(mstarzinger): This was never implemented but will be used once we
-    // correctly implement [[DefineOwnProperty]] on arrays.
-    UNIMPLEMENTED();
-    return obj;
+  static Object* GetParameterMapArg(FixedArray* parameter_map, uint32_t index) {
+    uint32_t length = parameter_map->length() - 2;
+    return index < length
+               ? parameter_map->get(index + 2)
+               : Object::cast(parameter_map->GetHeap()->the_hole_value());
   }
 
-  MUST_USE_RESULT virtual MaybeHandle<Object> Delete(
-      Handle<JSObject> obj, uint32_t key, JSReceiver::DeleteMode mode) FINAL {
-    Isolate* isolate = obj->GetIsolate();
-    Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
-    Handle<Object> probe = GetParameterMapArg(obj, parameter_map, key);
-    if (!probe->IsTheHole()) {
+  static void DeleteImpl(Handle<JSObject> obj, uint32_t entry) {
+    FixedArray* parameter_map = FixedArray::cast(obj->elements());
+    uint32_t length = static_cast<uint32_t>(parameter_map->length()) - 2;
+    if (entry < length) {
       // TODO(kmillikin): We could check if this was the last aliased
       // parameter, and revert to normal elements in that case.  That
       // would enable GC of the context.
-      parameter_map->set_the_hole(key + 2);
+      parameter_map->set_the_hole(entry + 2);
     } else {
-      Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
-      if (arguments->IsDictionary()) {
-        return DictionaryElementsAccessor::DeleteCommon(obj, key, mode);
-      } else {
-        // It's difficult to access the version of DeleteCommon that is declared
-        // in the templatized super class, call the concrete implementation in
-        // the class for the most generalized ElementsKind subclass.
-        return FastHoleyObjectElementsAccessor::DeleteCommon(obj, key, mode);
-      }
+      SloppyArgumentsElementsAccessorSubclass::DeleteFromArguments(
+          obj, entry - length);
     }
-    return isolate->factory()->true_value();
+  }
+};
+
+
+class SlowSloppyArgumentsElementsAccessor
+    : public SloppyArgumentsElementsAccessor<
+          SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+          ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> > {
+ public:
+  explicit SlowSloppyArgumentsElementsAccessor(const char* name)
+      : SloppyArgumentsElementsAccessor<
+            SlowSloppyArgumentsElementsAccessor, DictionaryElementsAccessor,
+            ElementsKindTraits<SLOW_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
+
+  static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
+    Handle<FixedArray> parameter_map(FixedArray::cast(obj->elements()));
+    Handle<SeededNumberDictionary> dict(
+        SeededNumberDictionary::cast(parameter_map->get(1)));
+    // TODO(verwaest): Remove reliance on index in Shrink.
+    uint32_t index = GetIndexForEntryImpl(*dict, entry);
+    Handle<Object> result = SeededNumberDictionary::DeleteProperty(dict, entry);
+    USE(result);
+    DCHECK(result->IsTrue());
+    Handle<FixedArray> new_elements =
+        SeededNumberDictionary::Shrink(dict, index);
+    parameter_map->set(1, *new_elements);
+  }
+
+  static void AddImpl(Handle<JSObject> object, uint32_t index,
+                      Handle<Object> value, PropertyAttributes attributes,
+                      uint32_t new_capacity) {
+    Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+    Handle<FixedArrayBase> old_elements(
+        FixedArrayBase::cast(parameter_map->get(1)));
+    Handle<SeededNumberDictionary> dictionary =
+        old_elements->IsSeededNumberDictionary()
+            ? Handle<SeededNumberDictionary>::cast(old_elements)
+            : JSObject::NormalizeElements(object);
+    PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+    Handle<SeededNumberDictionary> new_dictionary =
+        SeededNumberDictionary::AddNumberEntry(
+            dictionary, index, value, details,
+            object->map()->is_prototype_map());
+    if (attributes != NONE) object->RequireSlowElements(*new_dictionary);
+    if (*dictionary != *new_dictionary) {
+      FixedArray::cast(object->elements())->set(1, *new_dictionary);
+    }
+  }
+
+  static void ReconfigureImpl(Handle<JSObject> object,
+                              Handle<FixedArrayBase> store, uint32_t entry,
+                              Handle<Object> value,
+                              PropertyAttributes attributes) {
+    Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(store);
+    uint32_t length = parameter_map->length() - 2;
+    if (entry < length) {
+      Object* probe = parameter_map->get(entry + 2);
+      DCHECK(!probe->IsTheHole());
+      Context* context = Context::cast(parameter_map->get(0));
+      int context_entry = Smi::cast(probe)->value();
+      DCHECK(!context->get(context_entry)->IsTheHole());
+      context->set(context_entry, *value);
+
+      // Redefining attributes of an aliased element destroys fast aliasing.
+      parameter_map->set_the_hole(entry + 2);
+      // For elements that are still writable we re-establish slow aliasing.
+      if ((attributes & READ_ONLY) == 0) {
+        Isolate* isolate = store->GetIsolate();
+        value = isolate->factory()->NewAliasedArgumentsEntry(context_entry);
+      }
+
+      PropertyDetails details(attributes, DATA, 0, PropertyCellType::kNoCell);
+      Handle<SeededNumberDictionary> arguments(
+          SeededNumberDictionary::cast(parameter_map->get(1)));
+      arguments = SeededNumberDictionary::AddNumberEntry(
+          arguments, entry, value, details, object->map()->is_prototype_map());
+      // If the attributes were NONE, we would have called set rather than
+      // reconfigure.
+      DCHECK_NE(NONE, attributes);
+      object->RequireSlowElements(*arguments);
+      parameter_map->set(1, *arguments);
+    } else {
+      Handle<FixedArrayBase> arguments(
+          FixedArrayBase::cast(parameter_map->get(1)));
+      DictionaryElementsAccessor::ReconfigureImpl(
+          object, arguments, entry - length, value, attributes);
+    }
+  }
+};
+
+
+class FastSloppyArgumentsElementsAccessor
+    : public SloppyArgumentsElementsAccessor<
+          FastSloppyArgumentsElementsAccessor, FastHoleyObjectElementsAccessor,
+          ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> > {
+ public:
+  explicit FastSloppyArgumentsElementsAccessor(const char* name)
+      : SloppyArgumentsElementsAccessor<
+            FastSloppyArgumentsElementsAccessor,
+            FastHoleyObjectElementsAccessor,
+            ElementsKindTraits<FAST_SLOPPY_ARGUMENTS_ELEMENTS> >(name) {}
+
+  static void DeleteFromArguments(Handle<JSObject> obj, uint32_t entry) {
+    FixedArray* parameter_map = FixedArray::cast(obj->elements());
+    Handle<FixedArray> arguments(FixedArray::cast(parameter_map->get(1)));
+    FastHoleyObjectElementsAccessor::DeleteCommon(obj, entry, arguments);
+  }
+
+  static void AddImpl(Handle<JSObject> object, uint32_t index,
+                      Handle<Object> value, PropertyAttributes attributes,
+                      uint32_t new_capacity) {
+    DCHECK_EQ(NONE, attributes);
+    Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+    Handle<FixedArrayBase> old_elements(
+        FixedArrayBase::cast(parameter_map->get(1)));
+    if (old_elements->IsSeededNumberDictionary() ||
+        static_cast<uint32_t>(old_elements->length()) < new_capacity) {
+      GrowCapacityAndConvertImpl(object, new_capacity);
+    }
+    FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+    // For fast holey objects, the entry equals the index. The code above made
+    // sure that there's enough space to store the value. We cannot convert
+    // index to entry explicitly since the slot still contains the hole, so the
+    // current EntryForIndex would indicate that it is "absent" by returning
+    // kMaxUInt32.
+    FastHoleyObjectElementsAccessor::SetImpl(arguments, index, *value);
+  }
+
+  static void ReconfigureImpl(Handle<JSObject> object,
+                              Handle<FixedArrayBase> store, uint32_t entry,
+                              Handle<Object> value,
+                              PropertyAttributes attributes) {
+    Handle<SeededNumberDictionary> dictionary =
+        JSObject::NormalizeElements(object);
+    FixedArray::cast(*store)->set(1, *dictionary);
+    uint32_t length = static_cast<uint32_t>(store->length()) - 2;
+    if (entry >= length) {
+      entry = dictionary->FindEntry(entry - length) + length;
+    }
+    SlowSloppyArgumentsElementsAccessor::ReconfigureImpl(object, store, entry,
+                                                         value, attributes);
   }
 
   static void CopyElementsImpl(FixedArrayBase* from, uint32_t from_start,
                                FixedArrayBase* to, ElementsKind from_kind,
                                uint32_t to_start, int packed_size,
                                int copy_size) {
-    UNREACHABLE();
-  }
-
-  static uint32_t GetCapacityImpl(Handle<FixedArrayBase> backing_store) {
-    Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(backing_store);
-    Handle<FixedArrayBase> arguments(
-        FixedArrayBase::cast(parameter_map->get(1)));
-    return Max(static_cast<uint32_t>(parameter_map->length() - 2),
-               ForArray(arguments)->GetCapacity(arguments));
-  }
-
-  static uint32_t GetKeyForIndexImpl(Handle<FixedArrayBase> dict,
-                                     uint32_t index) {
-    return index;
-  }
-
-  static bool HasElementImpl(Handle<Object> receiver,
-                             Handle<JSObject> holder,
-                             uint32_t key,
-                             Handle<FixedArrayBase> parameters) {
-    Handle<FixedArray> parameter_map = Handle<FixedArray>::cast(parameters);
-    Handle<Object> probe = GetParameterMapArg(holder, parameter_map, key);
-    if (!probe->IsTheHole()) {
-      return true;
+    DCHECK(!to->IsDictionary());
+    if (from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS) {
+      CopyDictionaryToObjectElements(from, from_start, to, FAST_HOLEY_ELEMENTS,
+                                     to_start, copy_size);
     } else {
-      Isolate* isolate = holder->GetIsolate();
-      Handle<FixedArrayBase> arguments(FixedArrayBase::cast(
-          Handle<FixedArray>::cast(parameter_map)->get(1)), isolate);
-      ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
-      Handle<Object> value;
-      ASSIGN_RETURN_ON_EXCEPTION_VALUE(
-          isolate, value,
-          accessor->Get(receiver, holder, key, arguments),
-          false);
-      return !value->IsTheHole();
+      DCHECK_EQ(FAST_SLOPPY_ARGUMENTS_ELEMENTS, from_kind);
+      CopyObjectToObjectElements(from, FAST_HOLEY_ELEMENTS, from_start, to,
+                                 FAST_HOLEY_ELEMENTS, to_start, copy_size);
     }
   }
 
- private:
-  static Handle<Object> GetParameterMapArg(Handle<JSObject> holder,
-                                           Handle<FixedArray> parameter_map,
-                                           uint32_t key) {
-    Isolate* isolate = holder->GetIsolate();
-    uint32_t length = holder->IsJSArray()
-        ? Smi::cast(Handle<JSArray>::cast(holder)->length())->value()
-        : parameter_map->length();
-    return key < (length - 2)
-        ? handle(parameter_map->get(key + 2), isolate)
-        : Handle<Object>::cast(isolate->factory()->the_hole_value());
+  static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
+                                         uint32_t capacity) {
+    Handle<FixedArray> parameter_map(FixedArray::cast(object->elements()));
+    Handle<FixedArray> old_elements(FixedArray::cast(parameter_map->get(1)));
+    ElementsKind from_kind = object->GetElementsKind();
+    // This method should only be called if there's a reason to update the
+    // elements.
+    DCHECK(from_kind == SLOW_SLOPPY_ARGUMENTS_ELEMENTS ||
+           static_cast<uint32_t>(old_elements->length()) < capacity);
+    Handle<FixedArrayBase> elements =
+        ConvertElementsWithCapacity(object, old_elements, from_kind, capacity);
+    Handle<Map> new_map = JSObject::GetElementsTransitionMap(
+        object, FAST_SLOPPY_ARGUMENTS_ELEMENTS);
+    JSObject::MigrateToMap(object, new_map);
+    parameter_map->set(1, *elements);
+    JSObject::ValidateElements(object);
   }
 };
 
 
-ElementsAccessor* ElementsAccessor::ForArray(Handle<FixedArrayBase> array) {
-  return elements_accessors_[ElementsKindForArray(*array)];
-}
+}  // namespace
 
 
-void ElementsAccessor::InitializeOncePerProcess() {
-  static ElementsAccessor* accessor_array[] = {
-#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
-    ELEMENTS_LIST(ACCESSOR_ARRAY)
-#undef ACCESSOR_ARRAY
-  };
+void CheckArrayAbuse(Handle<JSObject> obj, const char* op, uint32_t index,
+                     bool allow_appending) {
+  DisallowHeapAllocation no_allocation;
+  Object* raw_length = NULL;
+  const char* elements_type = "array";
+  if (obj->IsJSArray()) {
+    JSArray* array = JSArray::cast(*obj);
+    raw_length = array->length();
+  } else {
+    raw_length = Smi::FromInt(obj->elements()->length());
+    elements_type = "object";
+  }
 
-  STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
-                kElementsKindCount);
-
-  elements_accessors_ = accessor_array;
-}
-
-
-void ElementsAccessor::TearDown() {
-  if (elements_accessors_ == NULL) return;
-#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
-  ELEMENTS_LIST(ACCESSOR_DELETE)
-#undef ACCESSOR_DELETE
-  elements_accessors_ = NULL;
-}
-
-
-template <typename ElementsAccessorSubclass, typename ElementsKindTraits>
-MUST_USE_RESULT
-MaybeHandle<Object> ElementsAccessorBase<ElementsAccessorSubclass,
-                                         ElementsKindTraits>::
-    SetLengthImpl(Handle<JSObject> obj,
-                  Handle<Object> length,
-                  Handle<FixedArrayBase> backing_store) {
-  Isolate* isolate = obj->GetIsolate();
-  Handle<JSArray> array = Handle<JSArray>::cast(obj);
-
-  // Fast case: The new length fits into a Smi.
-  Handle<Object> smi_length;
-
-  if (Object::ToSmi(isolate, length).ToHandle(&smi_length) &&
-      smi_length->IsSmi()) {
-    const int value = Handle<Smi>::cast(smi_length)->value();
-    if (value >= 0) {
-      Handle<Object> new_length = ElementsAccessorSubclass::
-          SetLengthWithoutNormalize(backing_store, array, smi_length, value);
-      DCHECK(!new_length.is_null());
-
-      // even though the proposed length was a smi, new_length could
-      // still be a heap number because SetLengthWithoutNormalize doesn't
-      // allow the array length property to drop below the index of
-      // non-deletable elements.
-      DCHECK(new_length->IsSmi() || new_length->IsHeapNumber() ||
-             new_length->IsUndefined());
-      if (new_length->IsSmi()) {
-        array->set_length(*Handle<Smi>::cast(new_length));
-        return array;
-      } else if (new_length->IsHeapNumber()) {
-        array->set_length(*new_length);
-        return array;
+  if (raw_length->IsNumber()) {
+    double n = raw_length->Number();
+    if (FastI2D(FastD2UI(n)) == n) {
+      int32_t int32_length = DoubleToInt32(n);
+      uint32_t compare_length = static_cast<uint32_t>(int32_length);
+      if (allow_appending) compare_length++;
+      if (index >= compare_length) {
+        PrintF("[OOB %s %s (%s length = %d, element accessed = %d) in ",
+               elements_type, op, elements_type, static_cast<int>(int32_length),
+               static_cast<int>(index));
+        TraceTopFrame(obj->GetIsolate());
+        PrintF("]\n");
       }
     } else {
-      return ThrowArrayLengthRangeError(isolate);
+      PrintF("[%s elements length not integer value in ", elements_type);
+      TraceTopFrame(obj->GetIsolate());
+      PrintF("]\n");
     }
+  } else {
+    PrintF("[%s elements length not a number in ", elements_type);
+    TraceTopFrame(obj->GetIsolate());
+    PrintF("]\n");
   }
-
-  // Slow case: The new length does not fit into a Smi or conversion
-  // to slow elements is needed for other reasons.
-  if (length->IsNumber()) {
-    uint32_t value;
-    if (length->ToArrayIndex(&value)) {
-      Handle<SeededNumberDictionary> dictionary =
-          JSObject::NormalizeElements(array);
-      DCHECK(!dictionary.is_null());
-
-      Handle<Object> new_length = DictionaryElementsAccessor::
-          SetLengthWithoutNormalize(dictionary, array, length, value);
-      DCHECK(!new_length.is_null());
-
-      DCHECK(new_length->IsNumber());
-      array->set_length(*new_length);
-      return array;
-    } else {
-      return ThrowArrayLengthRangeError(isolate);
-    }
-  }
-
-  // Fall-back case: The new length is not a number so make the array
-  // size one and set only element to length.
-  Handle<FixedArray> new_backing_store = isolate->factory()->NewFixedArray(1);
-  new_backing_store->set(0, *length);
-  JSArray::SetContent(array, new_backing_store);
-  return array;
 }
 
 
 MaybeHandle<Object> ArrayConstructInitializeElements(Handle<JSArray> array,
                                                      Arguments* args) {
-  // Optimize the case where there is one argument and the argument is a
-  // small smi.
-  if (args->length() == 1) {
-    Handle<Object> obj = args->at<Object>(0);
-    if (obj->IsSmi()) {
-      int len = Handle<Smi>::cast(obj)->value();
-      if (len > 0 && len < JSObject::kInitialMaxFastElementArray) {
-        ElementsKind elements_kind = array->GetElementsKind();
-        JSArray::Initialize(array, len, len);
+  if (args->length() == 0) {
+    // Optimize the case where there are no parameters passed.
+    JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
+    return array;
 
-        if (!IsFastHoleyElementsKind(elements_kind)) {
-          elements_kind = GetHoleyElementsKind(elements_kind);
-          JSObject::TransitionElementsKind(array, elements_kind);
-        }
-        return array;
-      } else if (len == 0) {
-        JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
-        return array;
-      }
+  } else if (args->length() == 1 && args->at<Object>(0)->IsNumber()) {
+    uint32_t length;
+    if (!args->at<Object>(0)->ToArrayLength(&length)) {
+      return ThrowArrayLengthRangeError(array->GetIsolate());
     }
 
-    // Take the argument as the length.
-    JSArray::Initialize(array, 0);
+    // Optimize the case where there is one argument and the argument is a small
+    // smi.
+    if (length > 0 && length < JSArray::kInitialMaxFastElementArray) {
+      ElementsKind elements_kind = array->GetElementsKind();
+      JSArray::Initialize(array, length, length);
 
-    return JSArray::SetElementsLength(array, obj);
-  }
-
-  // Optimize the case where there are no parameters passed.
-  if (args->length() == 0) {
-    JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
+      if (!IsFastHoleyElementsKind(elements_kind)) {
+        elements_kind = GetHoleyElementsKind(elements_kind);
+        JSObject::TransitionElementsKind(array, elements_kind);
+      }
+    } else if (length == 0) {
+      JSArray::Initialize(array, JSArray::kPreallocatedArrayElements);
+    } else {
+      // Take the argument as the length.
+      JSArray::Initialize(array, 0);
+      JSArray::SetLength(array, length);
+    }
     return array;
   }
 
@@ -1857,8 +2300,8 @@
     case FAST_HOLEY_SMI_ELEMENTS:
     case FAST_SMI_ELEMENTS: {
       Handle<FixedArray> smi_elms = Handle<FixedArray>::cast(elms);
-      for (int index = 0; index < number_of_elements; index++) {
-        smi_elms->set(index, (*args)[index], SKIP_WRITE_BARRIER);
+      for (int entry = 0; entry < number_of_elements; entry++) {
+        smi_elms->set(entry, (*args)[entry], SKIP_WRITE_BARRIER);
       }
       break;
     }
@@ -1867,8 +2310,8 @@
       DisallowHeapAllocation no_gc;
       WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
       Handle<FixedArray> object_elms = Handle<FixedArray>::cast(elms);
-      for (int index = 0; index < number_of_elements; index++) {
-        object_elms->set(index, (*args)[index], mode);
+      for (int entry = 0; entry < number_of_elements; entry++) {
+        object_elms->set(entry, (*args)[entry], mode);
       }
       break;
     }
@@ -1876,8 +2319,8 @@
     case FAST_DOUBLE_ELEMENTS: {
       Handle<FixedDoubleArray> double_elms =
           Handle<FixedDoubleArray>::cast(elms);
-      for (int index = 0; index < number_of_elements; index++) {
-        double_elms->set(index, (*args)[index]->Number());
+      for (int entry = 0; entry < number_of_elements; entry++) {
+        double_elms->set(entry, (*args)[entry]->Number());
       }
       break;
     }
@@ -1891,4 +2334,91 @@
   return array;
 }
 
-} }  // namespace v8::internal
+
+void ElementsAccessor::InitializeOncePerProcess() {
+  static ElementsAccessor* accessor_array[] = {
+#define ACCESSOR_ARRAY(Class, Kind, Store) new Class(#Kind),
+      ELEMENTS_LIST(ACCESSOR_ARRAY)
+#undef ACCESSOR_ARRAY
+  };
+
+  STATIC_ASSERT((sizeof(accessor_array) / sizeof(*accessor_array)) ==
+                kElementsKindCount);
+
+  elements_accessors_ = accessor_array;
+}
+
+
+void ElementsAccessor::TearDown() {
+  if (elements_accessors_ == NULL) return;
+#define ACCESSOR_DELETE(Class, Kind, Store) delete elements_accessors_[Kind];
+  ELEMENTS_LIST(ACCESSOR_DELETE)
+#undef ACCESSOR_DELETE
+  elements_accessors_ = NULL;
+}
+
+
+Handle<JSArray> ElementsAccessor::Concat(Isolate* isolate, Arguments* args,
+                                         uint32_t concat_size) {
+  int result_len = 0;
+  ElementsKind elements_kind = GetInitialFastElementsKind();
+  bool has_double = false;
+  {
+    DisallowHeapAllocation no_gc;
+    // Iterate through all the arguments performing checks
+    // and calculating total length.
+    bool is_holey = false;
+    for (uint32_t i = 0; i < concat_size; i++) {
+      Object* arg = (*args)[i];
+      int len = Smi::cast(JSArray::cast(arg)->length())->value();
+
+      // We shouldn't overflow when adding another len.
+      const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
+      STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
+      USE(kHalfOfMaxInt);
+      result_len += len;
+      DCHECK(0 <= result_len);
+      DCHECK(result_len <= FixedDoubleArray::kMaxLength);
+
+      ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
+      has_double = has_double || IsFastDoubleElementsKind(arg_kind);
+      is_holey = is_holey || IsFastHoleyElementsKind(arg_kind);
+      elements_kind = GetMoreGeneralElementsKind(elements_kind, arg_kind);
+    }
+    if (is_holey) {
+      elements_kind = GetHoleyElementsKind(elements_kind);
+    }
+  }
+
+  // If a double array is concatted into a fast elements array, the fast
+  // elements array needs to be initialized to contain proper holes, since
+  // boxing doubles may cause incremental marking.
+  ArrayStorageAllocationMode mode =
+      has_double && IsFastObjectElementsKind(elements_kind)
+          ? INITIALIZE_ARRAY_ELEMENTS_WITH_HOLE
+          : DONT_INITIALIZE_ARRAY_ELEMENTS;
+  Handle<JSArray> result_array = isolate->factory()->NewJSArray(
+      elements_kind, result_len, result_len, Strength::WEAK, mode);
+  if (result_len == 0) return result_array;
+  int j = 0;
+  Handle<FixedArrayBase> storage(result_array->elements(), isolate);
+  ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
+  for (uint32_t i = 0; i < concat_size; i++) {
+    // It is crucial to keep |array| in a raw pointer form to avoid
+    // performance degradation.
+    JSArray* array = JSArray::cast((*args)[i]);
+    int len = Smi::cast(array->length())->value();
+    if (len > 0) {
+      ElementsKind from_kind = array->GetElementsKind();
+      accessor->CopyElements(array, 0, from_kind, storage, j, len);
+      j += len;
+    }
+  }
+
+  DCHECK(j == result_len);
+  return result_array;
+}
+
+ElementsAccessor** ElementsAccessor::elements_accessors_ = NULL;
+}  // namespace internal
+}  // namespace v8