elements.cc cleanup

Reuse code for copying arguments and pushing/shifting elements.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#30825}
This commit is contained in:
cbruni 2015-09-18 04:15:34 -07:00 committed by Commit bot
parent b89eec39a1
commit 061e2a9b2b

View File

@ -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
@ -1274,119 +1276,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,
@ -1418,8 +1329,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());
@ -1428,7 +1339,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) {
@ -1438,30 +1349,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);
@ -1469,45 +1371,34 @@ 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);
}
return false;
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, start + add_count, start + delete_count,
(length - delete_count - start), 0, 0);
return backing_store;
}
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
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);
@ -1516,16 +1407,85 @@ class FastElementsAccessor
*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);
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 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;
if (new_length > elms_len) {
// New backing storage is needed.
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);
}
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;
}
};