| Index: src/builtins.cc
|
| diff --git a/src/builtins.cc b/src/builtins.cc
|
| index 8e88c28695599a1e71f54d633ca53febb545d76a..27a32fa01d272981a18c71d7a8e895672b461352 100644
|
| --- a/src/builtins.cc
|
| +++ b/src/builtins.cc
|
| @@ -362,7 +362,56 @@ BUILTIN(ArrayShift) {
|
| }
|
|
|
|
|
| +static Object* CallJsBuiltin(const char* name,
|
| + BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
|
| + HandleScope handleScope;
|
| +
|
| + Handle<Object> js_builtin =
|
| + GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
|
| + name);
|
| + ASSERT(js_builtin->IsJSFunction());
|
| + Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
|
| + Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
|
| + int n_args = args.length() - 1;
|
| + for (int i = 0; i < n_args; i++) {
|
| + argv[i] = &args[i + 1];
|
| + }
|
| + bool pending_exception = false;
|
| + Handle<Object> result = Execution::Call(function,
|
| + args.receiver(),
|
| + n_args,
|
| + argv.start(),
|
| + &pending_exception);
|
| + if (pending_exception) return Failure::Exception();
|
| + return *result;
|
| +}
|
| +
|
| +
|
| +static bool ArrayPrototypeHasNoElements() {
|
| + // This method depends on non writability of Object and Array prototype
|
| + // fields.
|
| + Context* global_context = Top::context()->global_context();
|
| + // Array.prototype
|
| + JSObject* proto =
|
| + JSObject::cast(global_context->array_function()->prototype());
|
| + if (proto->elements() != Heap::empty_fixed_array()) return false;
|
| + // Hidden prototype
|
| + proto = JSObject::cast(proto->GetPrototype());
|
| + ASSERT(proto->elements() == Heap::empty_fixed_array());
|
| + // Object.prototype
|
| + proto = JSObject::cast(proto->GetPrototype());
|
| + if (proto != global_context->initial_object_prototype()) return false;
|
| + if (proto->elements() != Heap::empty_fixed_array()) return false;
|
| + ASSERT(proto->GetPrototype()->IsNull());
|
| + return true;
|
| +}
|
| +
|
| +
|
| BUILTIN(ArrayUnshift) {
|
| + if (!ArrayPrototypeHasNoElements()) {
|
| + return CallJsBuiltin("ArrayUnshift", args);
|
| + }
|
| +
|
| JSArray* array = JSArray::cast(*args.receiver());
|
| ASSERT(array->HasFastElements());
|
|
|
| @@ -379,45 +428,44 @@ BUILTIN(ArrayUnshift) {
|
|
|
| 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);
|
| + Object* obj = Heap::AllocateRawFixedArray(capacity);
|
| if (obj->IsFailure()) return obj;
|
|
|
| - AssertNoAllocation no_gc;
|
| + reinterpret_cast<Array*>(obj)->set_map(Heap::fixed_array_map());
|
| 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);
|
| + new_elms->set_length(capacity);
|
| +
|
| + Object** new_elms_data = new_elms->data_start();
|
| + memcpy(new_elms_data + to_add, elms->data_start(), len * kPointerSize);
|
| +
|
| + // Let's hope that compiler can easily optimize this filling code.
|
| + Object* hole = Heap::the_hole_value();
|
| + for (int i = new_length; i < capacity; i++) {
|
| + new_elms_data[i] = hole;
|
| + }
|
|
|
| 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);
|
| - }
|
| + memmove(elms->data_start() + to_add,
|
| + elms->data_start(),
|
| + len * kPointerSize);
|
| }
|
|
|
| // 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);
|
| + elms->set(i, args[i + 1], SKIP_WRITE_BARRIER);
|
| + }
|
| + WriteBarrierMode mode = elms->GetWriteBarrierMode(no_gc);
|
| + if (mode == UPDATE_WRITE_BARRIER) {
|
| + Address address = elms->address();
|
| + for (int i = 0; i < new_length; i++) {
|
| + Heap::RecordWrite(address, FixedArray::kHeaderSize + i * kPointerSize);
|
| + }
|
| }
|
|
|
| // Set the length.
|
| @@ -426,31 +474,6 @@ BUILTIN(ArrayUnshift) {
|
| }
|
|
|
|
|
| -static Object* CallJsBuiltin(const char* name,
|
| - BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
|
| - HandleScope handleScope;
|
| -
|
| - Handle<Object> js_builtin =
|
| - GetProperty(Handle<JSObject>(Top::global_context()->builtins()),
|
| - name);
|
| - ASSERT(js_builtin->IsJSFunction());
|
| - Handle<JSFunction> function(Handle<JSFunction>::cast(js_builtin));
|
| - Vector<Object**> argv(Vector<Object**>::New(args.length() - 1));
|
| - int n_args = args.length() - 1;
|
| - for (int i = 0; i < n_args; i++) {
|
| - argv[i] = &args[i + 1];
|
| - }
|
| - bool pending_exception = false;
|
| - Handle<Object> result = Execution::Call(function,
|
| - args.receiver(),
|
| - n_args,
|
| - argv.start(),
|
| - &pending_exception);
|
| - if (pending_exception) return Failure::Exception();
|
| - return *result;
|
| -}
|
| -
|
| -
|
| BUILTIN(ArraySlice) {
|
| JSArray* array = JSArray::cast(*args.receiver());
|
| ASSERT(array->HasFastElements());
|
|
|