| Index: src/elements.cc
|
| diff --git a/src/elements.cc b/src/elements.cc
|
| index e0fb6fba0931cd580ed4feb00b6baa30031f1bea..775ec39c4eb5f42157f5b93d92c85cb8280c1272 100644
|
| --- a/src/elements.cc
|
| +++ b/src/elements.cc
|
| @@ -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,123 @@ 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
|
| + 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;
|
| + }
|
| };
|
|
|
|
|
| @@ -1221,6 +1361,19 @@ 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) {
|
| + 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.
|
| @@ -1321,6 +1474,20 @@ 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) {
|
| + 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,
|
|
|