- remove the Backing-Store specific code from builtins.cc and put it in elements.cc.
authorcbruni <cbruni@chromium.org>
Mon, 24 Aug 2015 10:55:08 +0000 (03:55 -0700)
committerCommit bot <commit-bot@chromium.org>
Mon, 24 Aug 2015 10:55:13 +0000 (10:55 +0000)
- adding tests to improve coverage of the splice method

BUG=

Committed: https://crrev.com/8533d4b5433d3a9e9fb1015f206997bd6d869fe3
Cr-Commit-Position: refs/heads/master@{#30269}

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

Cr-Commit-Position: refs/heads/master@{#30326}

src/builtins.cc
src/elements.cc
src/elements.h
test/mjsunit/array-natives-elements.js
test/mjsunit/array-splice.js

index 4bc61b8..6fe2d24 100644 (file)
@@ -176,6 +176,27 @@ BUILTIN(EmptyFunction) {
 }
 
 
+// TODO(cbruni): check if this is a suitable method on Object
+bool ClampedToInteger(Object* object, int* out) {
+  // This is an extended version of ECMA-262 9.4, but additionally
+  // clamps values to [kMinInt, kMaxInt]
+  if (object->IsSmi()) {
+    *out = Smi::cast(object)->value();
+    return true;
+  } else if (object->IsHeapNumber()) {
+    *out = FastD2IChecked(HeapNumber::cast(object)->value());
+    return true;
+  } else if (object->IsUndefined()) {
+    *out = 0;
+    return true;
+  } else if (object->IsBoolean()) {
+    *out = (Oddball::cast(object)->kind() == Oddball::kTrue) ? 1 : 0;
+    return true;
+  }
+  return false;
+}
+
+
 static void MoveDoubleElements(FixedDoubleArray* dst, int dst_index,
                                FixedDoubleArray* src, int src_index, int len) {
   if (len == 0) return;
@@ -621,7 +642,6 @@ BUILTIN(ArraySlice) {
 
 BUILTIN(ArraySplice) {
   HandleScope scope(isolate);
-  Heap* heap = isolate->heap();
   Handle<Object> receiver = args.receiver();
   MaybeHandle<FixedArrayBase> maybe_elms_obj =
       EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
@@ -632,209 +652,51 @@ BUILTIN(ArraySplice) {
   Handle<JSArray> array = Handle<JSArray>::cast(receiver);
   DCHECK(!array->map()->is_observed());
 
-  int len = Smi::cast(array->length())->value();
-
-  int n_arguments = args.length() - 1;
-
+  int argument_count = args.length() - 1;
   int relative_start = 0;
-  if (n_arguments > 0) {
+  if (argument_count > 0) {
     DisallowHeapAllocation no_gc;
-    Object* arg1 = args[1];
-    if (arg1->IsSmi()) {
-      relative_start = Smi::cast(arg1)->value();
-    } else if (arg1->IsHeapNumber()) {
-      double start = HeapNumber::cast(arg1)->value();
-      if (start < kMinInt || start > kMaxInt) {
-        AllowHeapAllocation allow_allocation;
-        return CallJsBuiltin(isolate, "$arraySplice", args);
-      }
-      relative_start = std::isnan(start) ? 0 : static_cast<int>(start);
-    } else if (!arg1->IsUndefined()) {
+    if (!ClampedToInteger(args[1], &relative_start)) {
       AllowHeapAllocation allow_allocation;
       return CallJsBuiltin(isolate, "$arraySplice", args);
     }
   }
+  int len = Smi::cast(array->length())->value();
+  // clip relative start to [0, len]
   int actual_start = (relative_start < 0) ? Max(len + relative_start, 0)
                                           : Min(relative_start, len);
 
-  // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
-  // given as a request to delete all the elements from the start.
-  // And it differs from the case of undefined delete count.
-  // This does not follow ECMA-262, but we do the same for
-  // compatibility.
   int actual_delete_count;
-  if (n_arguments == 1) {
+  if (argument_count == 1) {
+    // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
+    // given as a request to delete all the elements from the start.
+    // And it differs from the case of undefined delete count.
+    // This does not follow ECMA-262, but we do the same for compatibility.
     DCHECK(len - actual_start >= 0);
     actual_delete_count = len - actual_start;
   } else {
-    int value = 0;  // ToInteger(undefined) == 0
-    if (n_arguments > 1) {
-      DisallowHeapAllocation no_gc;
-      Object* arg2 = args[2];
-      if (arg2->IsSmi()) {
-        value = Smi::cast(arg2)->value();
-      } else {
+    int delete_count = 0;
+    DisallowHeapAllocation no_gc;
+    if (argument_count > 1) {
+      if (!ClampedToInteger(args[2], &delete_count)) {
         AllowHeapAllocation allow_allocation;
         return CallJsBuiltin(isolate, "$arraySplice", args);
       }
     }
-    actual_delete_count = Min(Max(value, 0), len - actual_start);
+    actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
   }
 
-  ElementsKind elements_kind = array->GetElementsKind();
-
-  int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
-  int new_length = len - actual_delete_count + item_count;
-
-  // For double mode we do not support changing the length.
-  if (new_length > len && IsFastDoubleElementsKind(elements_kind)) {
-    return CallJsBuiltin(isolate, "$arraySplice", args);
-  }
+  int add_count = (argument_count > 1) ? (argument_count - 2) : 0;
+  int new_length = len - actual_delete_count + add_count;
 
   if (new_length != len && JSArray::HasReadOnlyLength(array)) {
     AllowHeapAllocation allow_allocation;
     return CallJsBuiltin(isolate, "$arraySplice", args);
   }
-
-  if (new_length == 0) {
-    Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(
-        elms_obj, elements_kind, actual_delete_count);
-    array->set_elements(heap->empty_fixed_array());
-    array->set_length(Smi::FromInt(0));
-    return *result;
-  }
-
-  Handle<JSArray> result_array =
-      isolate->factory()->NewJSArray(elements_kind,
-                                     actual_delete_count,
-                                     actual_delete_count);
-
-  if (actual_delete_count > 0) {
-    DisallowHeapAllocation no_gc;
-    ElementsAccessor* accessor = array->GetElementsAccessor();
-    accessor->CopyElements(
-        elms_obj, actual_start, elements_kind,
-        handle(result_array->elements(), isolate), 0, actual_delete_count);
-  }
-
-  bool elms_changed = false;
-  if (item_count < actual_delete_count) {
-    // Shrink the array.
-    const bool trim_array = !heap->lo_space()->Contains(*elms_obj) &&
-      ((actual_start + item_count) <
-          (len - actual_delete_count - actual_start));
-    if (trim_array) {
-      const int delta = actual_delete_count - item_count;
-
-      if (elms_obj->IsFixedDoubleArray()) {
-        Handle<FixedDoubleArray> elms =
-            Handle<FixedDoubleArray>::cast(elms_obj);
-        MoveDoubleElements(*elms, delta, *elms, 0, actual_start);
-      } else {
-        Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-        DisallowHeapAllocation no_gc;
-        heap->MoveElements(*elms, delta, 0, actual_start);
-      }
-
-      if (heap->CanMoveObjectStart(*elms_obj)) {
-        // On the fast path we move the start of the object in memory.
-        elms_obj = handle(heap->LeftTrimFixedArray(*elms_obj, delta));
-      } else {
-        // This is the slow path. We are going to move the elements to the left
-        // by copying them. For trimmed values we store the hole.
-        if (elms_obj->IsFixedDoubleArray()) {
-          Handle<FixedDoubleArray> elms =
-              Handle<FixedDoubleArray>::cast(elms_obj);
-          MoveDoubleElements(*elms, 0, *elms, delta, len - delta);
-          elms->FillWithHoles(len - delta, len);
-        } else {
-          Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-          DisallowHeapAllocation no_gc;
-          heap->MoveElements(*elms, 0, delta, len - delta);
-          elms->FillWithHoles(len - delta, len);
-        }
-      }
-      elms_changed = true;
-    } else {
-      if (elms_obj->IsFixedDoubleArray()) {
-        Handle<FixedDoubleArray> elms =
-            Handle<FixedDoubleArray>::cast(elms_obj);
-        MoveDoubleElements(*elms, actual_start + item_count,
-                           *elms, actual_start + actual_delete_count,
-                           (len - actual_delete_count - actual_start));
-        elms->FillWithHoles(new_length, len);
-      } else {
-        Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-        DisallowHeapAllocation no_gc;
-        heap->MoveElements(*elms, actual_start + item_count,
-                           actual_start + actual_delete_count,
-                           (len - actual_delete_count - actual_start));
-        elms->FillWithHoles(new_length, len);
-      }
-    }
-  } else if (item_count > actual_delete_count) {
-    Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-    // Currently fixed arrays cannot grow too big, so
-    // we should never hit this case.
-    DCHECK((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
-
-    // Check if array need to grow.
-    if (new_length > elms->length()) {
-      // New backing storage is needed.
-      int capacity = new_length + (new_length >> 1) + 16;
-      Handle<FixedArray> new_elms =
-          isolate->factory()->NewUninitializedFixedArray(capacity);
-
-      DisallowHeapAllocation no_gc;
-
-      ElementsKind kind = array->GetElementsKind();
-      ElementsAccessor* accessor = array->GetElementsAccessor();
-      if (actual_start > 0) {
-        // Copy the part before actual_start as is.
-        accessor->CopyElements(
-            elms, 0, kind, new_elms, 0, actual_start);
-      }
-      accessor->CopyElements(
-          elms, actual_start + actual_delete_count, kind,
-          new_elms, actual_start + item_count,
-          ElementsAccessor::kCopyToEndAndInitializeToHole);
-
-      elms_obj = new_elms;
-      elms_changed = true;
-    } else {
-      DisallowHeapAllocation no_gc;
-      heap->MoveElements(*elms, actual_start + item_count,
-                         actual_start + actual_delete_count,
-                         (len - actual_delete_count - actual_start));
-    }
-  }
-
-  if (IsFastDoubleElementsKind(elements_kind)) {
-    Handle<FixedDoubleArray> elms = Handle<FixedDoubleArray>::cast(elms_obj);
-    for (int k = actual_start; k < actual_start + item_count; k++) {
-      Object* arg = args[3 + k - actual_start];
-      if (arg->IsSmi()) {
-        elms->set(k, Smi::cast(arg)->value());
-      } else {
-        elms->set(k, HeapNumber::cast(arg)->value());
-      }
-    }
-  } else {
-    Handle<FixedArray> elms = Handle<FixedArray>::cast(elms_obj);
-    DisallowHeapAllocation no_gc;
-    WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
-    for (int k = actual_start; k < actual_start + item_count; k++) {
-      elms->set(k, args[3 + k - actual_start], mode);
-    }
-  }
-
-  if (elms_changed) {
-    array->set_elements(*elms_obj);
-  }
-  // Set the length.
-  array->set_length(Smi::FromInt(new_length));
-
-  return *result_array;
+  ElementsAccessor* accessor = array->GetElementsAccessor();
+  Handle<JSArray> result = accessor->Splice(
+      array, elms_obj, actual_start, actual_delete_count, args, add_count);
+  return *result;
 }
 
 
index e0fb6fb..e133f8f 100644 (file)
@@ -115,7 +115,6 @@ static MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
                   Object);
 }
 
-
 static void CopyObjectToObjectElements(FixedArrayBase* from_base,
                                        ElementsKind from_kind,
                                        uint32_t from_start,
@@ -586,6 +585,23 @@ class ElementsAccessorBase : public ElementsAccessor {
     return 0;
   }
 
+  virtual Handle<JSArray> Splice(Handle<JSArray> receiver,
+                                 Handle<FixedArrayBase> backing_store,
+                                 uint32_t start, uint32_t delete_count,
+                                 Arguments args, uint32_t add_count) {
+    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>();
+  }
+
+
   virtual void SetLength(Handle<JSArray> array, uint32_t length) final {
     ElementsAccessorSubclass::SetLengthImpl(array, length,
                                             handle(array->elements()));
@@ -597,23 +613,31 @@ class ElementsAccessorBase : public ElementsAccessor {
   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,
+        ElementsAccessor::kCopyToEndAndInitializeToHole);
+  }
+
+  static Handle<FixedArrayBase> ConvertElementsWithCapacity(
+      Handle<JSObject> object, Handle<FixedArrayBase> old_elements,
+      ElementsKind from_kind, uint32_t capacity, int copy_size) {
     Isolate* isolate = object->GetIsolate();
-    Handle<FixedArrayBase> elements;
+    Handle<FixedArrayBase> new_elements;
     if (IsFastDoubleElementsKind(kind())) {
-      elements = isolate->factory()->NewFixedDoubleArray(capacity);
+      new_elements = isolate->factory()->NewFixedDoubleArray(capacity);
     } else {
-      elements = isolate->factory()->NewUninitializedFixedArray(capacity);
+      new_elements = isolate->factory()->NewUninitializedFixedArray(capacity);
     }
 
-    int packed = kPackedSizeNotKnown;
+    int packed_size = kPackedSizeNotKnown;
     if (IsFastPackedElementsKind(from_kind) && object->IsJSArray()) {
-      packed = Smi::cast(JSArray::cast(*object)->length())->value();
+      packed_size = Smi::cast(JSArray::cast(*object)->length())->value();
     }
 
     ElementsAccessorSubclass::CopyElementsImpl(
-        *old_elements, 0, *elements, from_kind, 0, packed,
-        ElementsAccessor::kCopyToEndAndInitializeToHole);
-    return elements;
+        *old_elements, 0, *new_elements, from_kind, 0, packed_size, copy_size);
+
+    return new_elements;
   }
 
   static void GrowCapacityAndConvertImpl(Handle<JSObject> object,
@@ -1179,8 +1203,7 @@ class FastElementsAccessor
           receiver, backing_store, KindTraits::Kind, capacity);
     } else {
       // push_size is > 0 and new_length <= elms_len, so backing_store cannot be
-      // the
-      // empty_fixed_array.
+      // the empty_fixed_array.
       new_elms = backing_store;
     }
 
@@ -1203,6 +1226,132 @@ class FastElementsAccessor
     receiver->set_length(Smi::FromInt(new_length));
     return new_length;
   }
+
+  static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store,
+                           int dst_index, int src_index, int len,
+                           int hole_start, int hole_end) {
+    UNREACHABLE();
+  }
+
+  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();
+    const uint32_t len = Smi::cast(receiver->length())->value();
+    const uint32_t new_length = len - 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
+    bool elms_changed = false;
+    if (add_count < delete_count) {
+      elms_changed = SpliceShrinkStep(backing_store, heap, start, delete_count,
+                                      add_count, len, new_length);
+    } else if (add_count > delete_count) {
+      elms_changed =
+          SpliceGrowStep(receiver, backing_store, isolate, heap, start,
+                         delete_count, add_count, len, new_length);
+    }
+
+    // Copy new Elements from args
+    if (IsFastDoubleElementsKind(KindTraits::Kind)) {
+      for (uint32_t index = start; index < start + add_count; index++) {
+        Object* arg = args[3 + index - start];
+        FastElementsAccessorSubclass::SetImpl(*backing_store, index, arg);
+      }
+    } else {
+      // FastSmiOrObjectElementsKind
+      Handle<FixedArray> elms = Handle<FixedArray>::cast(backing_store);
+      DisallowHeapAllocation no_gc;
+      WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+      for (uint32_t index = start; index < start + add_count; index++) {
+        elms->set(index, args[3 + index - start], mode);
+      }
+    }
+
+    if (elms_changed) {
+      receiver->set_elements(*backing_store);
+    }
+    receiver->set_length(Smi::FromInt(new_length));
+    return deleted_elements;
+  }
+
+ private:
+  static bool SpliceShrinkStep(Handle<FixedArrayBase>& backing_store,
+                               Heap* heap, 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;
+    const bool left_trim_array = heap->CanMoveObjectStart(*backing_store) &&
+                                 (move_left_dst_index < move_left_count);
+    if (left_trim_array) {
+      const int delta = delete_count - add_count;
+      // shift from before the insertion point to the right
+      FastElementsAccessorSubclass::MoveElements(heap, backing_store, delta, 0,
+                                                 start, 0, 0);
+      backing_store = handle(heap->LeftTrimFixedArray(*backing_store, delta));
+      return true;
+    } else {
+      // No left-trim needed or possible (in this case we left-move and store
+      // the hole)
+      FastElementsAccessorSubclass::MoveElements(
+          heap, backing_store, move_left_dst_index, start + delete_count,
+          move_left_count, new_length, len);
+    }
+    return false;
+  }
+
+
+  static bool SpliceGrowStep(Handle<JSArray> receiver,
+                             Handle<FixedArrayBase>& backing_store,
+                             Isolate* isolate, Heap* heap, uint32_t start,
+                             uint32_t delete_count, uint32_t add_count,
+                             uint32_t len, uint32_t new_length) {
+    // Currently fixed arrays cannot grow too big, so
+    // we should never hit this case.
+    DCHECK((add_count - delete_count) <= (Smi::kMaxValue - len));
+    // Check if backing_store needs to grow.
+    if (new_length > static_cast<uint32_t>(backing_store->length())) {
+      // New backing storage is needed.
+      int capacity = new_length + (new_length >> 1) + 16;
+      // 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);
+
+      backing_store = new_elms;
+      return true;
+    } else {
+      DisallowHeapAllocation no_gc;
+      FastElementsAccessorSubclass::MoveElements(
+          heap, backing_store, start + add_count, start + delete_count,
+          (len - delete_count - start), 0, 0);
+    }
+    return false;
+  }
 };
 
 
@@ -1221,6 +1370,18 @@ class FastSmiOrObjectElementsAccessor
     return backing_store->get(index);
   }
 
+  static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store,
+                           int dst_index, int src_index, int len,
+                           int hole_start, int hole_end) {
+    if (len == 0) return;
+    Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
+    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.
@@ -1321,6 +1482,19 @@ class FastDoubleElementsAccessor
       : FastElementsAccessor<FastElementsAccessorSubclass,
                              KindTraits>(name) {}
 
+  static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store,
+                           int dst_index, int src_index, int len,
+                           int hole_start, int hole_end) {
+    if (len == 0) return;
+    Handle<FixedDoubleArray> dst_elms =
+        Handle<FixedDoubleArray>::cast(backing_store);
+    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,
index 0131f0b..16be8ec 100644 (file)
@@ -131,6 +131,11 @@ class ElementsAccessor {
                         Handle<FixedArrayBase> backing_store, Object** objects,
                         uint32_t start, int direction) = 0;
 
+  virtual Handle<JSArray> Splice(Handle<JSArray> receiver,
+                                 Handle<FixedArrayBase> backing_store,
+                                 uint32_t start, uint32_t delete_count,
+                                 Arguments args, uint32_t add_count) = 0;
+
  protected:
   friend class LookupIterator;
 
index a19a931..7ed108e 100644 (file)
@@ -30,7 +30,7 @@
 // IC and Crankshaft support for smi-only elements in dynamic array literals.
 function get(foo) { return foo; }  // Used to generate dynamic values.
 
-function array_natives_test() {
+function array_natives_test(optimized) {
 
   // Ensure small array literals start in specific element kind mode.
   assertTrue(%HasFastSmiElements([]));
@@ -151,7 +151,6 @@ function array_natives_test() {
   assertTrue(%HasFastSmiElements(a3));
   assertEquals([1], a3r);
   assertEquals([2, 2, 3], a3);
-
   a3 = [1.1,2,3];
   a3r = a3.splice(0, 0);
   assertTrue(%HasFastDoubleElements(a3r));
@@ -166,13 +165,12 @@ function array_natives_test() {
   assertEquals([2, 3], a3);
   a3 = [1.1,2,3];
   a3r = a3.splice(0, 0, 2);
-  // Commented out since handled in js, which takes the best fit.
-  // assertTrue(%HasFastDoubleElements(a3r));
-  assertTrue(%HasFastSmiElements(a3r));
+  assertTrue(%HasFastDoubleElements(a3r));
   assertTrue(%HasFastDoubleElements(a3));
   assertEquals([], a3r);
   assertEquals([2, 1.1, 2, 3], a3);
   a3 = [1.1,2,3];
+  assertTrue(%HasFastDoubleElements(a3));
   a3r = a3.splice(0, 1, 2);
   assertTrue(%HasFastDoubleElements(a3r));
   assertTrue(%HasFastDoubleElements(a3));
@@ -180,9 +178,7 @@ function array_natives_test() {
   assertEquals([2, 2, 3], a3);
   a3 = [1.1,2,3];
   a3r = a3.splice(0, 0, 2.1);
-  // Commented out since handled in js, which takes the best fit.
-  // assertTrue(%HasFastDoubleElements(a3r));
-  assertTrue(%HasFastSmiElements(a3r));
+  assertTrue(%HasFastDoubleElements(a3r));
   assertTrue(%HasFastDoubleElements(a3));
   assertEquals([], a3r);
   assertEquals([2.1, 1.1, 2, 3], a3);
@@ -194,9 +190,7 @@ function array_natives_test() {
   assertEquals([2.2, 2, 3], a3);
   a3 = [1,2,3];
   a3r = a3.splice(0, 0, 2.1);
-  // Commented out since handled in js, which takes the best fit.
-  // assertTrue(%HasFastDoubleElements(a3r));
-  assertTrue(%HasFastSmiElements(a3r));
+  assertTrue(%HasFastDoubleElements(a3r));
   assertTrue(%HasFastDoubleElements(a3));
   assertEquals([], a3r);
   assertEquals([2.1, 1, 2, 3], a3);
@@ -206,7 +200,6 @@ function array_natives_test() {
   assertTrue(%HasFastDoubleElements(a3));
   assertEquals([1], a3r);
   assertEquals([2.2, 2, 3], a3);
-
   a3 = [{},2,3];
   a3r = a3.splice(0, 0);
   assertTrue(%HasFastObjectElements(a3r));
@@ -231,7 +224,6 @@ function array_natives_test() {
   assertTrue(%HasFastObjectElements(a3));
   assertEquals([1], a3r);
   assertEquals([{}, 2, 3], a3);
-
   a3 = [1.1,2,3];
   a3r = a3.splice(0, 0, {});
   assertTrue(%HasFastObjectElements(a3r));
@@ -244,6 +236,19 @@ function array_natives_test() {
   assertTrue(%HasFastObjectElements(a3));
   assertEquals([1.1], a3r);
   assertEquals([{}, 2, 3], a3);
+  a3 = [1.1, 2.2, 3.3];
+  a3r = a3.splice(2, 1);
+  assertTrue(%HasFastDoubleElements(a3r));
+  assertTrue(%HasFastDoubleElements(a3));
+  assertEquals([3.3], a3r);
+  //assertTrue(%HasFastDoubleElements(a3r));
+  assertEquals([1.1, 2.2], a3);
+  //assertTrue(%HasFastDoubleElements(a3r));
+  a3r = a3.splice(1, 1, 4.4, 5.5);
+  //assertTrue(%HasFastDoubleElements(a3r));
+  //assertTrue(%HasFastDoubleElements(a3));
+  assertEquals([2.2], a3r);
+  assertEquals([1.1, 4.4, 5.5], a3);
 
   // Pop
   var a4 = [1,2,3];
@@ -291,7 +296,7 @@ function array_natives_test() {
 }
 
 for (var i = 0; i < 3; i++) {
-  array_natives_test();
+  array_natives_test(false);
 }
 %OptimizeFunctionOnNextCall(array_natives_test);
-array_natives_test();
+array_natives_test(true);
index be2b106..f683350 100644 (file)
     assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
 
     array = [1, 2, 3, 4, 5, 6, 7];
+    spliced = array.splice(-1e100);
+    assertEquals([], array);
+    assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
+
+    array = [1, 2, 3, 4, 5, 6, 7];
     spliced = array.splice(-3);
     assertEquals([1, 2, 3, 4], array);
     assertEquals([5, 6, 7], spliced);
     assertEquals([], spliced);
 
     array = [1, 2, 3, 4, 5, 6, 7];
+    spliced = array.splice(1e100);
+    assertEquals([1, 2, 3, 4, 5, 6, 7], array);
+    assertEquals([], spliced);
+
+    array = [1, 2, 3, 4, 5, 6, 7];
     spliced = array.splice(0, -100);
     assertEquals([1, 2, 3, 4, 5, 6, 7], array);
     assertEquals([], spliced);
 
     array = [1, 2, 3, 4, 5, 6, 7];
+    spliced = array.splice(0, -1e100);
+    assertEquals([1, 2, 3, 4, 5, 6, 7], array);
+    assertEquals([], spliced);
+
+    array = [1, 2, 3, 4, 5, 6, 7];
     spliced = array.splice(0, -3);
     assertEquals([1, 2, 3, 4, 5, 6, 7], array);
     assertEquals([], spliced);
     assertEquals([], array);
     assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
 
+    array = [1, 2, 3, 4, 5, 6, 7];
+    spliced = array.splice(0, 1e100);
+    assertEquals([], array);
+    assertEquals([1, 2, 3, 4, 5, 6, 7], spliced);
+
     // Some exotic cases.
     obj = { toString: function() { throw 'Exception'; } };