| Index: src/elements.cc
|
| diff --git a/src/elements.cc b/src/elements.cc
|
| index 5cf248c95245ee6f09188725f372ceacbe81813c..901844bc1839d742f46376e5d0e1a13fad2bae88 100644
|
| --- a/src/elements.cc
|
| +++ b/src/elements.cc
|
| @@ -51,6 +51,8 @@ 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
|
| @@ -1338,119 +1340,28 @@ class FastElementsAccessor
|
|
|
| static Handle<Object> PopImpl(Handle<JSArray> receiver,
|
| Handle<FixedArrayBase> backing_store) {
|
| - uint32_t len =
|
| - static_cast<uint32_t>(Smi::cast(receiver->length())->value());
|
| - DCHECK(len > 0);
|
| - uint32_t new_length = len - 1;
|
| - Handle<Object> result =
|
| - FastElementsAccessorSubclass::GetImpl(backing_store, new_length);
|
| - FastElementsAccessorSubclass::SetLengthImpl(receiver, new_length,
|
| - backing_store);
|
| -
|
| - if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
|
| - return receiver->GetIsolate()->factory()->undefined_value();
|
| - }
|
| - return result;
|
| + return FastElementsAccessorSubclass::RemoveElement(receiver, backing_store,
|
| + AT_END);
|
| }
|
|
|
| static Handle<Object> ShiftImpl(Handle<JSArray> receiver,
|
| Handle<FixedArrayBase> backing_store) {
|
| - uint32_t len =
|
| - static_cast<uint32_t>(Smi::cast(receiver->length())->value());
|
| - Isolate* isolate = receiver->GetIsolate();
|
| - DCHECK(len > 0);
|
| - int new_length = len - 1;
|
| - Handle<Object> result =
|
| - FastElementsAccessorSubclass::GetImpl(backing_store, 0);
|
| - Heap* heap = isolate->heap();
|
| - if (heap->CanMoveObjectStart(*backing_store)) {
|
| - receiver->set_elements(heap->LeftTrimFixedArray(*backing_store, 1));
|
| - } else {
|
| - FastElementsAccessorSubclass::MoveElements(heap, backing_store, 0, 1,
|
| - new_length, 0, 0);
|
| - }
|
| - FastElementsAccessorSubclass::SetLengthImpl(receiver, new_length,
|
| - backing_store);
|
| -
|
| - if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
|
| - result = receiver->GetIsolate()->factory()->undefined_value();
|
| - }
|
| - return result;
|
| + 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) {
|
| - uint32_t len = Smi::cast(receiver->length())->value();
|
| - DCHECK(push_size > 0);
|
| - uint32_t elms_len = backing_store->length();
|
| - // Currently fixed arrays cannot grow too big, so
|
| - // we should never hit this case.
|
| - DCHECK(push_size <= static_cast<uint32_t>(Smi::kMaxValue - len));
|
| - uint32_t new_length = len + push_size;
|
| -
|
| - if (new_length > elms_len) {
|
| - // New backing storage is needed.
|
| - uint32_t capacity = new_length + (new_length >> 1) + 16;
|
| - backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
|
| - receiver, backing_store, KindTraits::Kind, capacity);
|
| - receiver->set_elements(*backing_store);
|
| - }
|
| -
|
| - // Add the provided values.
|
| - DisallowHeapAllocation no_gc;
|
| - FixedArrayBase* raw_backing_store = *backing_store;
|
| - WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
|
| - for (uint32_t index = 0; index < push_size; index++) {
|
| - Object* object = (*args)[index + 1];
|
| - FastElementsAccessorSubclass::SetImpl(raw_backing_store, index + len,
|
| - object, mode);
|
| - }
|
| - DCHECK(*backing_store == receiver->elements());
|
| - // Set the length.
|
| - receiver->set_length(Smi::FromInt(new_length));
|
| - return new_length;
|
| + 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) {
|
| - uint32_t len = Smi::cast(receiver->length())->value();
|
| - DCHECK(unshift_size > 0);
|
| - uint32_t elms_len = backing_store->length();
|
| - // Currently fixed arrays cannot grow too big, so
|
| - // we should never hit this case.
|
| - DCHECK(unshift_size <= static_cast<uint32_t>(Smi::kMaxValue - len));
|
| - uint32_t new_length = len + unshift_size;
|
| -
|
| - if (new_length > elms_len) {
|
| - // New backing storage is needed.
|
| - uint32_t capacity = new_length + (new_length >> 1) + 16;
|
| - backing_store = FastElementsAccessorSubclass::ConvertElementsWithCapacity(
|
| - receiver, backing_store, KindTraits::Kind, capacity, 0, unshift_size,
|
| - ElementsAccessor::kCopyToEndAndInitializeToHole);
|
| - DisallowHeapAllocation no_gc;
|
| - receiver->set_elements(*backing_store);
|
| - } else {
|
| - // unshift_size is > 0 and new_length <= elms_len, so backing_store cannot
|
| - // be the empty_fixed_array.
|
| - DisallowHeapAllocation no_gc;
|
| - Isolate* isolate = receiver->GetIsolate();
|
| - FastElementsAccessorSubclass::MoveElements(isolate->heap(), backing_store,
|
| - unshift_size, 0, len, 0, 0);
|
| - }
|
| -
|
| - // Add the provided values.
|
| - DisallowHeapAllocation no_gc;
|
| - FixedArrayBase* raw_backing_store = *backing_store;
|
| - WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
|
| - for (uint32_t index = 0; index < unshift_size; index++) {
|
| - FastElementsAccessorSubclass::SetImpl(raw_backing_store, index,
|
| - (*args)[index + 1], mode);
|
| - }
|
| - // Set the length.
|
| - receiver->set_length(Smi::FromInt(new_length));
|
| - return new_length;
|
| + return FastElementsAccessorSubclass::AddArguments(
|
| + receiver, backing_store, args, unshift_size, AT_START);
|
| }
|
|
|
| static void MoveElements(Heap* heap, Handle<FixedArrayBase> backing_store,
|
| @@ -1482,8 +1393,8 @@ class FastElementsAccessor
|
| Arguments* args, uint32_t add_count) {
|
| Isolate* isolate = receiver->GetIsolate();
|
| Heap* heap = isolate->heap();
|
| - uint32_t len = Smi::cast(receiver->length())->value();
|
| - uint32_t new_length = len - delete_count + add_count;
|
| + 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());
|
| @@ -1492,7 +1403,7 @@ class FastElementsAccessor
|
| backing_store, KindTraits::Kind, delete_count);
|
| }
|
|
|
| - // construct the result array which holds the deleted elements
|
| + // 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) {
|
| @@ -1502,30 +1413,21 @@ class FastElementsAccessor
|
| 0, kPackedSizeNotKnown, delete_count);
|
| }
|
|
|
| - // delete and move elements to make space for add_count new elements
|
| - bool elms_changed = false;
|
| + // Delete and move elements to make space for add_count new elements.
|
| if (add_count < delete_count) {
|
| - elms_changed = SpliceShrinkStep(backing_store, heap, start, delete_count,
|
| - add_count, len, new_length);
|
| + FastElementsAccessorSubclass::SpliceShrinkStep(backing_store, heap, start,
|
| + delete_count, add_count,
|
| + length, new_length);
|
| } else if (add_count > delete_count) {
|
| - elms_changed =
|
| - SpliceGrowStep(receiver, backing_store, isolate, heap, start,
|
| - delete_count, add_count, len, new_length);
|
| + backing_store = FastElementsAccessorSubclass::SpliceGrowStep(
|
| + receiver, backing_store, isolate, heap, start, delete_count,
|
| + add_count, length, new_length);
|
| }
|
|
|
| - // Copy new Elements from args
|
| - DisallowHeapAllocation no_gc;
|
| - FixedArrayBase* raw_backing_store = *backing_store;
|
| - WriteBarrierMode mode = raw_backing_store->GetWriteBarrierMode(no_gc);
|
| - for (uint32_t index = 0; index < add_count; index++) {
|
| - Object* object = (*args)[3 + index];
|
| - FastElementsAccessorSubclass::SetImpl(raw_backing_store, index + start,
|
| - object, mode);
|
| - }
|
| + // Copy over the arguments.
|
| + FastElementsAccessorSubclass::CopyArguments(args, backing_store, add_count,
|
| + 3, start);
|
|
|
| - if (elms_changed) {
|
| - receiver->set_elements(*backing_store);
|
| - }
|
| receiver->set_length(Smi::FromInt(new_length));
|
| FastElementsAccessorSubclass::TryTransitionResultArrayToPacked(
|
| deleted_elements);
|
| @@ -1533,63 +1435,121 @@ class FastElementsAccessor
|
| }
|
|
|
| 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) {
|
| + static void 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);
|
| + }
|
| +
|
| +
|
| + static Handle<FixedArrayBase> 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 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(
|
| - heap, backing_store, move_left_dst_index, start + delete_count,
|
| - move_left_count, new_length, len);
|
| + heap, backing_store, start + add_count, start + delete_count,
|
| + (length - delete_count - start), 0, 0);
|
| + 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) {
|
| + uint32_t length =
|
| + static_cast<uint32_t>(Smi::cast(receiver->length())->value());
|
| + Isolate* isolate = receiver->GetIsolate();
|
| + 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) {
|
| + Heap* heap = isolate->heap();
|
| + FastElementsAccessorSubclass::MoveElements(heap, backing_store, 0, 1,
|
| + new_length, 0, 0);
|
| + }
|
| + FastElementsAccessorSubclass::SetLengthImpl(receiver, new_length,
|
| + backing_store);
|
| +
|
| + if (IsHoleyElementsKind(KindTraits::Kind) && result->IsTheHole()) {
|
| + return receiver->GetIsolate()->factory()->undefined_value();
|
| }
|
| - return false;
|
| + 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;
|
|
|
| - 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())) {
|
| + if (new_length > elms_len) {
|
| // 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);
|
| + 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->heap(), backing_store,
|
| + add_size, 0, length, 0, 0);
|
| + }
|
|
|
| - 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);
|
| + 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);
|
| }
|
| - return false;
|
| }
|
| };
|
|
|
|
|