BUILTIN_LIST_C(DEF_ARG_TYPE)
#undef DEF_ARG_TYPE
-} // namespace
// ----------------------------------------------------------------------------
// Support macro for defining builtins in C++.
// ----------------------------------------------------------------------------
-BUILTIN(Illegal) {
- UNREACHABLE();
- return isolate->heap()->undefined_value(); // Make compiler happy.
-}
-
-BUILTIN(EmptyFunction) {
- return isolate->heap()->undefined_value();
+bool ClampedToInteger(Object* object, int* out) {
+ // This is an extended version of ECMA-262 7.1.11 handling signed values
+ // Try to convert object to a number and clamp 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 = object->IsTrue();
+ return true;
+ }
+ return false;
}
}
+} // namespace
+
+
+BUILTIN(Illegal) {
+ UNREACHABLE();
+ return isolate->heap()->undefined_value(); // Make compiler happy.
+}
+
+
+BUILTIN(EmptyFunction) { return isolate->heap()->undefined_value(); }
+
+
BUILTIN(ArrayPush) {
HandleScope scope(isolate);
Handle<Object> receiver = args.receiver();
BUILTIN(ArraySplice) {
HandleScope scope(isolate);
- Heap* heap = isolate->heap();
Handle<Object> receiver = args.receiver();
MaybeHandle<FixedArrayBase> maybe_elms_obj =
EnsureJSArrayWithWritableFastElements(isolate, receiver, &args, 3);
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 CallJsIntrinsic(isolate, isolate->array_splice(), 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 CallJsIntrinsic(isolate, isolate->array_splice(), 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 CallJsIntrinsic(isolate, isolate->array_splice(), 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 CallJsIntrinsic(isolate, isolate->array_splice(), 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 CallJsIntrinsic(isolate, isolate->array_splice(), 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;
}
MUST_USE_RESULT
-static MaybeHandle<Object> ThrowArrayLengthRangeError(Isolate* isolate) {
+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;
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()));
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,
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;
}
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
+ DisallowHeapAllocation no_gc;
+ for (uint32_t index = start; index < start + add_count; index++) {
+ Object* arg = args[3 + index - start];
+ FastElementsAccessorSubclass::SetImpl(*backing_store, index, arg);
+ }
+
+ 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;
+ }
};
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) {
+ Handle<FixedArray> dst_elms = Handle<FixedArray>::cast(backing_store);
+ 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.
: 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) {
+ Handle<FixedDoubleArray> dst_elms =
+ Handle<FixedDoubleArray>::cast(backing_store);
+ 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,
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;
assertTrue(%HasFastSmiElements(a3));
assertEquals([1], a3r);
assertEquals([2, 2, 3], a3);
-
a3 = [1.1,2,3];
a3r = a3.splice(0, 0);
assertTrue(%HasFastDoubleElements(a3r));
assertTrue(%HasFastDoubleElements(a3));
assertEquals([], a3r);
assertEquals([1.1, 2, 3], a3);
- a3 = [1.1,2,3];
+ a3 = [1.1, 2, 3];
a3r = a3.splice(0, 1);
assertTrue(%HasFastDoubleElements(a3r));
assertTrue(%HasFastDoubleElements(a3));
assertEquals([1.1], a3r);
assertEquals([2, 3], a3);
- a3 = [1.1,2,3];
+ 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];
+ a3 = [1.1, 2, 3];
+ assertTrue(%HasFastDoubleElements(a3));
a3r = a3.splice(0, 1, 2);
assertTrue(%HasFastDoubleElements(a3r));
assertTrue(%HasFastDoubleElements(a3));
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);
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);
assertTrue(%HasFastDoubleElements(a3));
assertEquals([1], a3r);
assertEquals([2.2, 2, 3], a3);
-
a3 = [{},2,3];
a3r = a3.splice(0, 0);
assertTrue(%HasFastObjectElements(a3r));
assertTrue(%HasFastObjectElements(a3));
assertEquals([1], a3r);
assertEquals([{}, 2, 3], a3);
-
a3 = [1.1,2,3];
a3r = a3.splice(0, 0, {});
assertTrue(%HasFastObjectElements(a3r));
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];
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);
array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(-3.999999);
+ assertEquals([1, 2, 3, 4], array);
+ assertEquals([5, 6, 7], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(-3.000001);
+ assertEquals([1, 2, 3, 4], array);
+ assertEquals([5, 6, 7], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
spliced = array.splice(4);
assertEquals([1, 2, 3, 4], array);
assertEquals([5, 6, 7], spliced);
array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(4.999999);
+ assertEquals([1, 2, 3, 4], array);
+ assertEquals([5, 6, 7], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(4.000001);
+ assertEquals([1, 2, 3, 4], array);
+ assertEquals([5, 6, 7], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
spliced = array.splice(6);
assertEquals([1, 2, 3, 4, 5, 6], array);
assertEquals([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);
array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(0, -3.999999);
+ assertEquals([1, 2, 3, 4, 5, 6, 7], array);
+ assertEquals([], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(0, -3.000001);
+ assertEquals([1, 2, 3, 4, 5, 6, 7], array);
+ assertEquals([], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
spliced = array.splice(0, 4);
assertEquals([5, 6, 7], array);
assertEquals([1, 2, 3, 4], spliced);
array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(0, 4.999999);
+ assertEquals([5, 6, 7], array);
+ assertEquals([1, 2, 3, 4], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
+ spliced = array.splice(0, 4.000001);
+ assertEquals([5, 6, 7], array);
+ assertEquals([1, 2, 3, 4], spliced);
+
+ array = [1, 2, 3, 4, 5, 6, 7];
spliced = array.splice(0, 6);
assertEquals([7], array);
assertEquals([1, 2, 3, 4, 5, 6], 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'; } };