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, |