| Index: src/builtins.cc
|
| diff --git a/src/builtins.cc b/src/builtins.cc
|
| index 1159a213dce7b3961b8f58117371b34f42a28243..c68de9ac794adc7b37fa23530fc822ca5bf70d8e 100644
|
| --- a/src/builtins.cc
|
| +++ b/src/builtins.cc
|
| @@ -246,19 +246,16 @@ BUILTIN(ArrayPush) {
|
| JSArray* array = JSArray::cast(*args.receiver());
|
| ASSERT(array->HasFastElements());
|
|
|
| - // Make sure we have space for the elements.
|
| int len = Smi::cast(array->length())->value();
|
| + int to_add = args.length() - 1;
|
| + if (to_add == 0) {
|
| + return Smi::FromInt(len);
|
| + }
|
|
|
| - // Set new length.
|
| - int new_length = len + args.length() - 1;
|
| + int new_length = len + to_add;
|
| FixedArray* elms = FixedArray::cast(array->elements());
|
|
|
| - if (new_length <= elms->length()) {
|
| - // Backing storage has extra space for the provided values.
|
| - for (int index = 0; index < args.length() - 1; index++) {
|
| - elms->set(index + len, args[index+1]);
|
| - }
|
| - } else {
|
| + if (new_length > elms->length()) {
|
| // New backing storage is needed.
|
| int capacity = new_length + (new_length >> 1) + 16;
|
| Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
|
| @@ -269,16 +266,21 @@ BUILTIN(ArrayPush) {
|
| WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
|
| // Fill out the new array with old elements.
|
| for (int i = 0; i < len; i++) new_elms->set(i, elms->get(i), mode);
|
| - // Add the provided values.
|
| - for (int index = 0; index < args.length() - 1; index++) {
|
| - new_elms->set(index + len, args[index+1], mode);
|
| - }
|
| - // Set the new backing storage.
|
| - array->set_elements(new_elms);
|
| + elms = new_elms;
|
| + array->set_elements(elms);
|
| + }
|
| +
|
| + AssertNoAllocation no_gc;
|
| + WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
|
| +
|
| + // Add the provided values.
|
| + 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 array->length();
|
| + return Smi::FromInt(new_length);
|
| }
|
|
|
|
|
| @@ -313,6 +315,17 @@ BUILTIN(ArrayPop) {
|
| }
|
|
|
|
|
| +static Object* GetElementToMove(uint32_t index,
|
| + FixedArray* elms,
|
| + JSObject* prototype) {
|
| + Object* e = elms->get(index);
|
| + if (e->IsTheHole() && prototype->HasElement(index)) {
|
| + e = prototype->GetElement(index);
|
| + }
|
| + return e;
|
| +}
|
| +
|
| +
|
| BUILTIN(ArrayShift) {
|
| JSArray* array = JSArray::cast(*args.receiver());
|
| ASSERT(array->HasFastElements());
|
| @@ -325,21 +338,17 @@ BUILTIN(ArrayShift) {
|
| Top::context()->global_context()->array_function();
|
| JSObject* prototype = JSObject::cast(array_function->prototype());
|
|
|
| - // Get first element
|
| FixedArray* elms = FixedArray::cast(array->elements());
|
| - Object* first = elms->get(0);
|
|
|
| + // Get first element
|
| + Object* first = elms->get(0);
|
| if (first->IsTheHole()) {
|
| first = prototype->GetElement(0);
|
| }
|
|
|
| // Shift the elements.
|
| for (int i = 0; i < len - 1; i++) {
|
| - Object* e = elms->get(i + 1);
|
| - if (e->IsTheHole() && prototype->HasElement(i + 1)) {
|
| - e = prototype->GetElement(i + 1);
|
| - }
|
| - elms->set(i, e);
|
| + elms->set(i, GetElementToMove(i + 1, elms, prototype));
|
| }
|
| elms->set(len - 1, Heap::the_hole_value());
|
|
|
| @@ -350,6 +359,66 @@ BUILTIN(ArrayShift) {
|
| }
|
|
|
|
|
| +BUILTIN(ArrayUnshift) {
|
| + JSArray* array = JSArray::cast(*args.receiver());
|
| + ASSERT(array->HasFastElements());
|
| +
|
| + int len = Smi::cast(array->length())->value();
|
| + int to_add = args.length() - 1;
|
| + // Note that we cannot quit early if to_add == 0 as
|
| + // values should be lifted from prototype into
|
| + // the array.
|
| +
|
| + int new_length = len + to_add;
|
| + FixedArray* elms = FixedArray::cast(array->elements());
|
| +
|
| + // Fetch the prototype.
|
| + JSFunction* array_function =
|
| + Top::context()->global_context()->array_function();
|
| + JSObject* prototype = JSObject::cast(array_function->prototype());
|
| +
|
| + if (new_length > elms->length()) {
|
| + // New backing storage is needed.
|
| + int capacity = new_length + (new_length >> 1) + 16;
|
| + Object* obj = Heap::AllocateFixedArrayWithHoles(capacity);
|
| + if (obj->IsFailure()) return obj;
|
| +
|
| + AssertNoAllocation no_gc;
|
| + FixedArray* new_elms = FixedArray::cast(obj);
|
| + WriteBarrierMode mode = new_elms->GetWriteBarrierMode(no_gc);
|
| + // Fill out the new array with old elements.
|
| + for (int i = 0; i < len; i++)
|
| + new_elms->set(to_add + i,
|
| + GetElementToMove(i, elms, prototype),
|
| + mode);
|
| +
|
| + elms = new_elms;
|
| + array->set_elements(elms);
|
| + } else {
|
| + AssertNoAllocation no_gc;
|
| + WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
|
| +
|
| + // Move elements to the right
|
| + for (int i = 0; i < len; i++) {
|
| + elms->set(new_length - i - 1,
|
| + GetElementToMove(len - i - 1, elms, prototype),
|
| + mode);
|
| + }
|
| + }
|
| +
|
| + // Add the provided values.
|
| + AssertNoAllocation no_gc;
|
| + WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
|
| + for (int i = 0; i < to_add; i++) {
|
| + elms->set(i, args[i + 1], mode);
|
| + }
|
| +
|
| + // Set the length.
|
| + array->set_length(Smi::FromInt(new_length));
|
| + return Smi::FromInt(new_length);
|
| +}
|
| +
|
| +
|
| // -----------------------------------------------------------------------------
|
| //
|
|
|
|
|