Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(31)

Unified Diff: src/builtins.cc

Issue 11377132: Support all fast elements kinds in the major array operations. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Addressed comments (and rebased) Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/arm/stub-cache-arm.cc ('k') | src/elements.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/builtins.cc
diff --git a/src/builtins.cc b/src/builtins.cc
index 620e4b36ce59fbef40713254c852c5220d68f086..6617fe1ad9738b80c72912c9984504a4d01ff3ce 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -325,6 +325,18 @@ BUILTIN(ArrayCodeGeneric) {
}
+static void MoveDoubleElements(FixedDoubleArray* dst,
+ int dst_index,
+ FixedDoubleArray* src,
+ int src_index,
+ int len) {
+ if (len == 0) return;
+ memmove(dst->data_start() + dst_index,
+ src->data_start() + src_index,
+ len * kDoubleSize);
+}
+
+
static void MoveElements(Heap* heap,
AssertNoAllocation* no_gc,
FixedArray* dst,
@@ -351,24 +363,39 @@ static void FillWithHoles(Heap* heap, FixedArray* dst, int from, int to) {
}
-static FixedArray* LeftTrimFixedArray(Heap* heap,
- FixedArray* elms,
- int to_trim) {
+static void FillWithHoles(FixedDoubleArray* dst, int from, int to) {
+ for (int i = from; i < to; i++) {
+ dst->set_the_hole(i);
+ }
+}
+
+
+static FixedArrayBase* LeftTrimFixedArray(Heap* heap,
+ FixedArrayBase* elms,
+ int to_trim) {
+ Map* map = elms->map();
+ int entry_size;
+ if (elms->IsFixedArray()) {
+ entry_size = kPointerSize;
+ } else {
+ entry_size = kDoubleSize;
+ }
ASSERT(elms->map() != HEAP->fixed_cow_array_map());
// For now this trick is only applied to fixed arrays in new and paged space.
// In large object space the object's start must coincide with chunk
// and thus the trick is just not applicable.
ASSERT(!HEAP->lo_space()->Contains(elms));
- STATIC_ASSERT(FixedArray::kMapOffset == 0);
- STATIC_ASSERT(FixedArray::kLengthOffset == kPointerSize);
- STATIC_ASSERT(FixedArray::kHeaderSize == 2 * kPointerSize);
+ STATIC_ASSERT(FixedArrayBase::kMapOffset == 0);
+ STATIC_ASSERT(FixedArrayBase::kLengthOffset == kPointerSize);
+ STATIC_ASSERT(FixedArrayBase::kHeaderSize == 2 * kPointerSize);
Object** former_start = HeapObject::RawField(elms, 0);
const int len = elms->length();
- if (to_trim > FixedArray::kHeaderSize / kPointerSize &&
+ if (to_trim > FixedArrayBase::kHeaderSize / entry_size &&
+ elms->IsFixedArray() &&
!heap->new_space()->Contains(elms)) {
// If we are doing a big trim in old space then we zap the space that was
// formerly part of the array so that the GC (aided by the card-based
@@ -382,14 +409,15 @@ static FixedArray* LeftTrimFixedArray(Heap* heap,
// Technically in new space this write might be omitted (except for
// debug mode which iterates through the heap), but to play safer
// we still do it.
- heap->CreateFillerObjectAt(elms->address(), to_trim * kPointerSize);
+ heap->CreateFillerObjectAt(elms->address(), to_trim * entry_size);
- former_start[to_trim] = heap->fixed_array_map();
- former_start[to_trim + 1] = Smi::FromInt(len - to_trim);
+ int new_start_index = to_trim * (entry_size / kPointerSize);
+ former_start[new_start_index] = map;
+ former_start[new_start_index + 1] = Smi::FromInt(len - to_trim);
// Maintain marking consistency for HeapObjectIterator and
// IncrementalMarking.
- int size_delta = to_trim * kPointerSize;
+ int size_delta = to_trim * entry_size;
if (heap->marking()->TransferMark(elms->address(),
elms->address() + size_delta)) {
MemoryChunk::IncrementLiveBytesFromMutator(elms->address(), -size_delta);
@@ -397,8 +425,8 @@ static FixedArray* LeftTrimFixedArray(Heap* heap,
HEAP_PROFILE(heap, ObjectMoveEvent(elms->address(),
elms->address() + size_delta));
- return FixedArray::cast(HeapObject::FromAddress(
- elms->address() + to_trim * kPointerSize));
+ return FixedArrayBase::cast(HeapObject::FromAddress(
+ elms->address() + to_trim * entry_size));
}
@@ -427,19 +455,14 @@ static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
Map* map = elms->map();
if (map == heap->fixed_array_map()) {
if (args == NULL || array->HasFastObjectElements()) return elms;
- if (array->HasFastDoubleElements()) {
- ASSERT(elms == heap->empty_fixed_array());
- MaybeObject* maybe_transition =
- array->TransitionElementsKind(FAST_ELEMENTS);
- if (maybe_transition->IsFailure()) return maybe_transition;
- return elms;
- }
} else if (map == heap->fixed_cow_array_map()) {
MaybeObject* maybe_writable_result = array->EnsureWritableFastElements();
if (args == NULL || array->HasFastObjectElements() ||
- maybe_writable_result->IsFailure()) {
+ !maybe_writable_result->To(&elms)) {
return maybe_writable_result;
}
+ } else if (map == heap->fixed_double_array_map()) {
+ if (args == NULL) return elms;
} else {
return NULL;
}
@@ -449,13 +472,28 @@ static inline MaybeObject* EnsureJSArrayWithWritableFastElements(
int args_length = args->length();
if (first_added_arg >= args_length) return array->elements();
- MaybeObject* maybe_array = array->EnsureCanContainElements(
- args,
- first_added_arg,
- args_length - first_added_arg,
- DONT_ALLOW_DOUBLE_ELEMENTS);
- if (maybe_array->IsFailure()) return maybe_array;
- return array->elements();
+ ElementsKind origin_kind = array->map()->elements_kind();
+ ASSERT(!IsFastObjectElementsKind(origin_kind));
+ ElementsKind target_kind = origin_kind;
+ int arg_count = args->length() - first_added_arg;
+ Object** arguments = args->arguments() - first_added_arg - (arg_count - 1);
+ for (int i = 0; i < arg_count; i++) {
+ Object* arg = arguments[i];
+ if (arg->IsHeapObject()) {
+ if (arg->IsHeapNumber()) {
+ target_kind = FAST_DOUBLE_ELEMENTS;
+ } else {
+ target_kind = FAST_ELEMENTS;
+ break;
+ }
+ }
+ }
+ if (target_kind != origin_kind) {
+ MaybeObject* maybe_failure = array->TransitionElementsKind(target_kind);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ return array->elements();
+ }
+ return elms;
}
@@ -499,75 +537,131 @@ MUST_USE_RESULT static MaybeObject* CallJsBuiltin(
BUILTIN(ArrayPush) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
- if (maybe_elms_obj == NULL) {
- return CallJsBuiltin(isolate, "ArrayPush", args);
- }
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms_obj =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 1);
+ if (maybe_elms_obj == NULL) {
+ return CallJsBuiltin(isolate, "ArrayPush", args);
}
- FixedArray* elms = FixedArray::cast(elms_obj);
- JSArray* array = JSArray::cast(receiver);
+ if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
- if (FLAG_harmony_observation && array->map()->is_observed()) {
+ if (FLAG_harmony_observation &&
+ JSObject::cast(receiver)->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArrayPush", args);
}
- int len = Smi::cast(array->length())->value();
- int to_add = args.length() - 1;
- if (to_add == 0) {
- return Smi::FromInt(len);
- }
- // Currently fixed arrays cannot grow too big, so
- // we should never hit this case.
- ASSERT(to_add <= (Smi::kMaxValue - len));
+ JSArray* array = JSArray::cast(receiver);
+ ElementsKind kind = array->GetElementsKind();
- int new_length = len + to_add;
+ if (IsFastSmiOrObjectElementsKind(kind)) {
+ FixedArray* elms = FixedArray::cast(elms_obj);
- if (new_length > elms->length()) {
- // New backing storage is needed.
- int capacity = new_length + (new_length >> 1) + 16;
- Object* obj;
- { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
+ int len = Smi::cast(array->length())->value();
+ int to_add = args.length() - 1;
+ if (to_add == 0) {
+ return Smi::FromInt(len);
}
- FixedArray* new_elms = FixedArray::cast(obj);
+ // Currently fixed arrays cannot grow too big, so
+ // we should never hit this case.
+ ASSERT(to_add <= (Smi::kMaxValue - len));
- ElementsKind kind = array->GetElementsKind();
- CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, 0, len);
- FillWithHoles(heap, new_elms, new_length, capacity);
+ int new_length = len + to_add;
- elms = new_elms;
- }
+ if (new_length > elms->length()) {
+ // New backing storage is needed.
+ int capacity = new_length + (new_length >> 1) + 16;
+ FixedArray* new_elms;
+ MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
+ if (!maybe_obj->To(&new_elms)) return maybe_obj;
+
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, new_elms, kind, 0, len, elms_obj);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+ FillWithHoles(heap, new_elms, new_length, capacity);
- // Add the provided values.
- AssertNoAllocation no_gc;
- WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
- for (int index = 0; index < to_add; index++) {
- elms->set(index + len, args[index + 1], mode);
- }
+ elms = new_elms;
+ }
- if (elms != array->elements()) {
- array->set_elements(elms);
- }
+ // Add the provided values.
+ AssertNoAllocation no_gc;
+ WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
+ for (int index = 0; index < to_add; index++) {
+ elms->set(index + len, args[index + 1], mode);
+ }
- // Set the length.
- array->set_length(Smi::FromInt(new_length));
- return Smi::FromInt(new_length);
+ if (elms != array->elements()) {
+ array->set_elements(elms);
+ }
+
+ // Set the length.
+ array->set_length(Smi::FromInt(new_length));
+ return Smi::FromInt(new_length);
+ } else {
+ int len = Smi::cast(array->length())->value();
+ int elms_len = elms_obj->length();
+
+ int to_add = args.length() - 1;
+ if (to_add == 0) {
+ return Smi::FromInt(len);
+ }
+ // Currently fixed arrays cannot grow too big, so
+ // we should never hit this case.
+ ASSERT(to_add <= (Smi::kMaxValue - len));
+
+ int new_length = len + to_add;
+
+ FixedDoubleArray* new_elms;
+
+ if (new_length > elms_len) {
+ // New backing storage is needed.
+ int capacity = new_length + (new_length >> 1) + 16;
+ MaybeObject* maybe_obj =
+ heap->AllocateUninitializedFixedDoubleArray(capacity);
+ if (!maybe_obj->To(&new_elms)) return maybe_obj;
+
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, new_elms, kind, 0, len, elms_obj);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+
+ FillWithHoles(new_elms, len + to_add, new_elms->length());
+ } else {
+ // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
+ // empty_fixed_array.
+ new_elms = FixedDoubleArray::cast(elms_obj);
+ }
+
+ // Add the provided values.
+ AssertNoAllocation no_gc;
+ int index;
+ for (index = 0; index < to_add; index++) {
+ Object* arg = args[index + 1];
+ new_elms->set(index + len, arg->Number());
+ }
+
+ if (new_elms != array->elements()) {
+ array->set_elements(new_elms);
+ }
+
+ // Set the length.
+ array->set_length(Smi::FromInt(new_length));
+ return Smi::FromInt(new_length);
+ }
}
BUILTIN(ArrayPop) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
- if (maybe_elms_obj == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
- }
- FixedArray* elms = FixedArray::cast(elms_obj);
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
+ if (maybe_elms == NULL) return CallJsBuiltin(isolate, "ArrayPop", args);
+ if (!maybe_elms->To(&elms_obj)) return maybe_elms;
+
JSArray* array = JSArray::cast(receiver);
if (FLAG_harmony_observation && array->map()->is_observed()) {
@@ -577,18 +671,15 @@ BUILTIN(ArrayPop) {
int len = Smi::cast(array->length())->value();
if (len == 0) return heap->undefined_value();
- // Get top element
- Object* top = elms->get(len - 1);
-
- // Set the length.
- array->set_length(Smi::FromInt(len - 1));
-
- if (!top->IsTheHole()) {
- // Delete the top element.
- elms->set_the_hole(len - 1);
- return top;
- }
-
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ int new_length = len - 1;
+ Object* result;
+ MaybeObject* maybe_result = accessor->Get(array, array, new_length);
+ if (!maybe_result->To(&result)) return maybe_result;
+ MaybeObject* maybe_failure =
+ accessor->SetLength(array, Smi::FromInt(new_length));
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ if (!result->IsTheHole()) return result;
return array->GetPrototype()->GetElement(len - 1);
}
@@ -596,19 +687,17 @@ BUILTIN(ArrayPop) {
BUILTIN(ArrayShift) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
- if (maybe_elms_obj == NULL)
- return CallJsBuiltin(isolate, "ArrayShift", args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
- }
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms_obj =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
+ if (maybe_elms_obj == NULL)
+ return CallJsBuiltin(isolate, "ArrayShift", args);
+ if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
+
if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
return CallJsBuiltin(isolate, "ArrayShift", args);
}
- FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastSmiOrObjectElements());
if (FLAG_harmony_observation && array->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArrayShift", args);
@@ -618,18 +707,25 @@ BUILTIN(ArrayShift) {
if (len == 0) return heap->undefined_value();
// Get first element
- Object* first = elms->get(0);
- if (first->IsTheHole()) {
- first = heap->undefined_value();
- }
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ Object* first;
+ MaybeObject* maybe_first = accessor->Get(receiver, array, 0, elms_obj);
+ if (!maybe_first->To(&first)) return maybe_first;
- if (!heap->lo_space()->Contains(elms)) {
- array->set_elements(LeftTrimFixedArray(heap, elms, 1));
+ if (!heap->lo_space()->Contains(elms_obj)) {
+ array->set_elements(LeftTrimFixedArray(heap, elms_obj, 1));
} else {
// Shift the elements.
- AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
- elms->set(len - 1, heap->the_hole_value());
+ if (elms_obj->IsFixedArray()) {
+ FixedArray* elms = FixedArray::cast(elms_obj);
+ AssertNoAllocation no_gc;
+ MoveElements(heap, &no_gc, elms, 0, elms, 1, len - 1);
+ elms->set(len - 1, heap->the_hole_value());
+ } else {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
+ MoveDoubleElements(elms, 0, elms, 1, len - 1);
+ elms->set_the_hole(len - 1);
+ }
}
// Set the length.
@@ -642,19 +738,21 @@ BUILTIN(ArrayShift) {
BUILTIN(ArrayUnshift) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
- if (maybe_elms_obj == NULL)
- return CallJsBuiltin(isolate, "ArrayUnshift", args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
- }
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms_obj =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, NULL, 0);
+ if (maybe_elms_obj == NULL)
+ return CallJsBuiltin(isolate, "ArrayUnshift", args);
+ if (!maybe_elms_obj->To(&elms_obj)) return maybe_elms_obj;
+
if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
return CallJsBuiltin(isolate, "ArrayUnshift", args);
}
- FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastSmiOrObjectElements());
+ if (!array->HasFastSmiOrObjectElements()) {
+ return CallJsBuiltin(isolate, "ArrayUnshift", args);
+ }
+ FixedArray* elms = FixedArray::cast(elms_obj);
if (FLAG_harmony_observation && array->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArrayUnshift", args);
@@ -675,13 +773,17 @@ BUILTIN(ArrayUnshift) {
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj;
- { MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- FixedArray* new_elms = FixedArray::cast(obj);
+ FixedArray* new_elms;
+ MaybeObject* maybe_elms = heap->AllocateUninitializedFixedArray(capacity);
+ if (!maybe_elms->To(&new_elms)) return maybe_elms;
+
ElementsKind kind = array->GetElementsKind();
- CopyObjectToObjectElements(elms, kind, 0, new_elms, kind, to_add, len);
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, new_elms, kind, to_add, len, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+
FillWithHoles(heap, new_elms, new_length, capacity);
elms = new_elms;
array->set_elements(elms);
@@ -706,16 +808,20 @@ BUILTIN(ArrayUnshift) {
BUILTIN(ArraySlice) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- FixedArray* elms;
+ FixedArrayBase* elms;
int len = -1;
if (receiver->IsJSArray()) {
JSArray* array = JSArray::cast(receiver);
- if (!array->HasFastSmiOrObjectElements() ||
- !IsJSArrayFastElementMovingAllowed(heap, array)) {
+ if (!IsJSArrayFastElementMovingAllowed(heap, array)) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+
+ if (array->HasFastElements()) {
+ elms = array->elements();
+ } else {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
- elms = FixedArray::cast(array->elements());
len = Smi::cast(array->length())->value();
} else {
// Array.slice(arguments, ...) is quite a common idiom (notably more
@@ -724,15 +830,19 @@ BUILTIN(ArraySlice) {
isolate->context()->native_context()->arguments_boilerplate()->map();
bool is_arguments_object_with_fast_elements =
- receiver->IsJSObject()
- && JSObject::cast(receiver)->map() == arguments_map
- && JSObject::cast(receiver)->HasFastSmiOrObjectElements();
+ receiver->IsJSObject() &&
+ JSObject::cast(receiver)->map() == arguments_map;
if (!is_arguments_object_with_fast_elements) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
- elms = FixedArray::cast(JSObject::cast(receiver)->elements());
- Object* len_obj = JSObject::cast(receiver)
- ->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
+ JSObject* object = JSObject::cast(receiver);
+
+ if (object->HasFastElements()) {
+ elms = object->elements();
+ } else {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+ Object* len_obj = object->InObjectPropertyAt(Heap::kArgumentsLengthIndex);
if (!len_obj->IsSmi()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -740,12 +850,27 @@ BUILTIN(ArraySlice) {
if (len > elms->length()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
+ }
+
+ JSObject* object = JSObject::cast(receiver);
+ ElementsKind kind = object->GetElementsKind();
+
+ if (IsHoleyElementsKind(kind)) {
+ bool packed = true;
+ ElementsAccessor* accessor = ElementsAccessor::ForKind(kind);
for (int i = 0; i < len; i++) {
- if (elms->get(i) == heap->the_hole_value()) {
- return CallJsBuiltin(isolate, "ArraySlice", args);
+ if (!accessor->HasElement(object, object, i, elms)) {
+ packed = false;
+ break;
}
}
+ if (packed) {
+ kind = GetPackedElementsKind(kind);
+ } else if (!receiver->IsJSArray()) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
}
+
ASSERT(len >= 0);
int n_arguments = args.length() - 1;
@@ -758,6 +883,12 @@ BUILTIN(ArraySlice) {
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) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+ relative_start = static_cast<int>(start);
} else if (!arg1->IsUndefined()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -765,6 +896,12 @@ BUILTIN(ArraySlice) {
Object* arg2 = args[2];
if (arg2->IsSmi()) {
relative_end = Smi::cast(arg2)->value();
+ } else if (arg2->IsHeapNumber()) {
+ double end = HeapNumber::cast(arg2)->value();
+ if (end < kMinInt || end > kMaxInt) {
+ return CallJsBuiltin(isolate, "ArraySlice", args);
+ }
+ relative_end = static_cast<int>(end);
} else if (!arg2->IsUndefined()) {
return CallJsBuiltin(isolate, "ArraySlice", args);
}
@@ -779,21 +916,21 @@ BUILTIN(ArraySlice) {
int final = (relative_end < 0) ? Max(len + relative_end, 0)
: Min(relative_end, len);
- ElementsKind elements_kind = JSObject::cast(receiver)->GetElementsKind();
-
// Calculate the length of result array.
int result_len = Max(final - k, 0);
- MaybeObject* maybe_array =
- heap->AllocateJSArrayAndStorage(elements_kind,
- result_len,
- result_len);
JSArray* result_array;
+ MaybeObject* maybe_array = heap->AllocateJSArrayAndStorage(kind,
+ result_len,
+ result_len);
if (!maybe_array->To(&result_array)) return maybe_array;
- CopyObjectToObjectElements(elms, elements_kind, k,
- FixedArray::cast(result_array->elements()),
- elements_kind, 0, result_len);
+ ElementsAccessor* accessor = object->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(object, k, result_array->elements(),
+ kind, 0, result_len, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
return result_array;
}
@@ -802,19 +939,18 @@ BUILTIN(ArraySlice) {
BUILTIN(ArraySplice) {
Heap* heap = isolate->heap();
Object* receiver = *args.receiver();
- Object* elms_obj;
- { MaybeObject* maybe_elms_obj =
- EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
- if (maybe_elms_obj == NULL)
- return CallJsBuiltin(isolate, "ArraySplice", args);
- if (!maybe_elms_obj->ToObject(&elms_obj)) return maybe_elms_obj;
+ FixedArrayBase* elms_obj;
+ MaybeObject* maybe_elms =
+ EnsureJSArrayWithWritableFastElements(heap, receiver, &args, 3);
+ if (maybe_elms == NULL) {
+ return CallJsBuiltin(isolate, "ArraySplice", args);
}
+ if (!maybe_elms->To(&elms_obj)) return maybe_elms;
+
if (!IsJSArrayFastElementMovingAllowed(heap, JSArray::cast(receiver))) {
return CallJsBuiltin(isolate, "ArraySplice", args);
}
- FixedArray* elms = FixedArray::cast(elms_obj);
JSArray* array = JSArray::cast(receiver);
- ASSERT(array->HasFastSmiOrObjectElements());
if (FLAG_harmony_observation && array->map()->is_observed()) {
return CallJsBuiltin(isolate, "ArraySplice", args);
@@ -829,6 +965,12 @@ BUILTIN(ArraySplice) {
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) {
+ return CallJsBuiltin(isolate, "ArraySplice", args);
+ }
+ relative_start = static_cast<int>(start);
} else if (!arg1->IsUndefined()) {
return CallJsBuiltin(isolate, "ArraySplice", args);
}
@@ -858,51 +1000,83 @@ BUILTIN(ArraySplice) {
actual_delete_count = Min(Max(value, 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 CallJsBuiltin(isolate, "ArraySplice", args);
+ }
+
+ if (new_length == 0) {
+ MaybeObject* maybe_array = heap->AllocateJSArrayWithElements(
+ elms_obj, elements_kind, actual_delete_count);
+ if (maybe_array->IsFailure()) return maybe_array;
+ array->set_elements(heap->empty_fixed_array());
+ array->set_length(Smi::FromInt(0));
+ return maybe_array;
+ }
+
JSArray* result_array = NULL;
- ElementsKind elements_kind =
- JSObject::cast(receiver)->GetElementsKind();
MaybeObject* maybe_array =
heap->AllocateJSArrayAndStorage(elements_kind,
actual_delete_count,
actual_delete_count);
if (!maybe_array->To(&result_array)) return maybe_array;
- {
- // Fill newly created array.
- CopyObjectToObjectElements(elms, elements_kind, actual_start,
- FixedArray::cast(result_array->elements()),
- elements_kind, 0, actual_delete_count);
+ if (actual_delete_count > 0) {
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, actual_start, result_array->elements(),
+ elements_kind, 0, actual_delete_count, elms_obj);
+ // Cannot fail since the origin and target array are of the same elements
+ // kind.
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
}
- int item_count = (n_arguments > 1) ? (n_arguments - 2) : 0;
- int new_length = len - actual_delete_count + item_count;
-
bool elms_changed = false;
if (item_count < actual_delete_count) {
// Shrink the array.
- const bool trim_array = !heap->lo_space()->Contains(elms) &&
+ 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()) {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
+ MoveDoubleElements(elms, delta, elms, 0, actual_start);
+ } else {
+ FixedArray* elms = FixedArray::cast(elms_obj);
AssertNoAllocation no_gc;
MoveElements(heap, &no_gc, elms, delta, elms, 0, actual_start);
}
- elms = LeftTrimFixedArray(heap, elms, delta);
+ elms_obj = LeftTrimFixedArray(heap, elms_obj, delta);
elms_changed = true;
} else {
- AssertNoAllocation no_gc;
- MoveElements(heap, &no_gc,
- elms, actual_start + item_count,
- elms, actual_start + actual_delete_count,
- (len - actual_delete_count - actual_start));
- FillWithHoles(heap, elms, new_length, len);
+ if (elms_obj->IsFixedDoubleArray()) {
+ FixedDoubleArray* elms = FixedDoubleArray::cast(elms_obj);
+ MoveDoubleElements(elms, actual_start + item_count,
+ elms, actual_start + actual_delete_count,
+ (len - actual_delete_count - actual_start));
+ FillWithHoles(elms, new_length, len);
+ } else {
+ FixedArray* elms = FixedArray::cast(elms_obj);
+ AssertNoAllocation no_gc;
+ MoveElements(heap, &no_gc,
+ elms, actual_start + item_count,
+ elms, actual_start + actual_delete_count,
+ (len - actual_delete_count - actual_start));
+ FillWithHoles(heap, elms, new_length, len);
+ }
}
} else if (item_count > actual_delete_count) {
+ FixedArray* elms = FixedArray::cast(elms_obj);
// Currently fixed arrays cannot grow too big, so
// we should never hit this case.
ASSERT((item_count - actual_delete_count) <= (Smi::kMaxValue - len));
@@ -911,28 +1085,27 @@ BUILTIN(ArraySplice) {
if (new_length > elms->length()) {
// New backing storage is needed.
int capacity = new_length + (new_length >> 1) + 16;
- Object* obj;
- { MaybeObject* maybe_obj =
- heap->AllocateUninitializedFixedArray(capacity);
- if (!maybe_obj->ToObject(&obj)) return maybe_obj;
- }
- FixedArray* new_elms = FixedArray::cast(obj);
-
- {
- // Copy the part before actual_start as is.
- ElementsKind kind = array->GetElementsKind();
- CopyObjectToObjectElements(elms, kind, 0,
- new_elms, kind, 0, actual_start);
- const int to_copy = len - actual_delete_count - actual_start;
- CopyObjectToObjectElements(elms, kind,
- actual_start + actual_delete_count,
- new_elms, kind,
- actual_start + item_count, to_copy);
- }
+ FixedArray* new_elms;
+ MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
+ if (!maybe_obj->To(&new_elms)) return maybe_obj;
+
+ // Copy the part before actual_start as is.
+ ElementsKind kind = array->GetElementsKind();
+ ElementsAccessor* accessor = array->GetElementsAccessor();
+ MaybeObject* maybe_failure = accessor->CopyElements(
+ array, 0, new_elms, kind, 0, actual_start, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
+ const int to_copy = len - actual_delete_count - actual_start;
+ maybe_failure = accessor->CopyElements(
+ array, actual_start + actual_delete_count, new_elms, kind,
+ actual_start + item_count, to_copy, elms);
+ ASSERT(!maybe_failure->IsFailure());
+ USE(maybe_failure);
FillWithHoles(heap, new_elms, new_length, capacity);
- elms = new_elms;
+ elms_obj = new_elms;
elms_changed = true;
} else {
AssertNoAllocation no_gc;
@@ -943,16 +1116,28 @@ BUILTIN(ArraySplice) {
}
}
- AssertNoAllocation 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 (IsFastDoubleElementsKind(elements_kind)) {
+ FixedDoubleArray* elms = 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 {
+ FixedArray* elms = FixedArray::cast(elms_obj);
+ AssertNoAllocation 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);
+ array->set_elements(elms_obj);
}
-
// Set the length.
array->set_length(Smi::FromInt(new_length));
@@ -977,11 +1162,10 @@ BUILTIN(ArrayConcat) {
for (int i = 0; i < n_arguments; i++) {
Object* arg = args[i];
if (!arg->IsJSArray() ||
- !JSArray::cast(arg)->HasFastSmiOrObjectElements() ||
+ !JSArray::cast(arg)->HasFastElements() ||
JSArray::cast(arg)->GetPrototype() != array_proto) {
return CallJsBuiltin(isolate, "ArrayConcat", args);
}
-
int len = Smi::cast(JSArray::cast(arg)->length())->value();
// We shouldn't overflow when adding another len.
@@ -991,27 +1175,24 @@ BUILTIN(ArrayConcat) {
result_len += len;
ASSERT(result_len >= 0);
- if (result_len > FixedArray::kMaxLength) {
+ if (result_len > FixedDoubleArray::kMaxLength) {
return CallJsBuiltin(isolate, "ArrayConcat", args);
}
- if (!JSArray::cast(arg)->HasFastSmiElements()) {
- if (IsFastSmiElementsKind(elements_kind)) {
- if (IsFastHoleyElementsKind(elements_kind)) {
- elements_kind = FAST_HOLEY_ELEMENTS;
- } else {
- elements_kind = FAST_ELEMENTS;
- }
+ ElementsKind arg_kind = JSArray::cast(arg)->map()->elements_kind();
+ ElementsKind packed_kind = GetPackedElementsKind(arg_kind);
+ if (IsMoreGeneralElementsKindTransition(
+ GetPackedElementsKind(elements_kind), packed_kind)) {
+ if (IsFastHoleyElementsKind(elements_kind)) {
+ elements_kind = GetHoleyElementsKind(arg_kind);
+ } else {
+ elements_kind = arg_kind;
}
}
-
- if (JSArray::cast(arg)->HasFastHoleyElements()) {
- elements_kind = GetHoleyElementsKind(elements_kind);
- }
}
- // Allocate result.
JSArray* result_array;
+ // Allocate result.
MaybeObject* maybe_array =
heap->AllocateJSArrayAndStorage(elements_kind,
result_len,
@@ -1019,19 +1200,19 @@ BUILTIN(ArrayConcat) {
if (!maybe_array->To(&result_array)) return maybe_array;
if (result_len == 0) return result_array;
- // Copy data.
- int start_pos = 0;
- FixedArray* result_elms(FixedArray::cast(result_array->elements()));
+ int j = 0;
+ FixedArrayBase* storage = result_array->elements();
for (int i = 0; i < n_arguments; i++) {
JSArray* array = JSArray::cast(args[i]);
+ ElementsAccessor* accessor = array->GetElementsAccessor();
int len = Smi::cast(array->length())->value();
- FixedArray* elms = FixedArray::cast(array->elements());
- CopyObjectToObjectElements(elms, elements_kind, 0,
- result_elms, elements_kind,
- start_pos, len);
- start_pos += len;
+ MaybeObject* maybe_failure =
+ accessor->CopyElements(array, 0, storage, elements_kind, j, len);
+ if (maybe_failure->IsFailure()) return maybe_failure;
+ j += len;
}
- ASSERT(start_pos == result_len);
+
+ ASSERT(j == result_len);
return result_array;
}
« no previous file with comments | « src/arm/stub-cache-arm.cc ('k') | src/elements.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698