| Index: src/builtins.cc
|
| ===================================================================
|
| --- src/builtins.cc (revision 4205)
|
| +++ src/builtins.cc (working copy)
|
| @@ -319,6 +319,24 @@
|
| }
|
|
|
|
|
| +static bool IsJSArrayWithFastElements(Object* receiver,
|
| + FixedArray** elements) {
|
| + if (!receiver->IsJSArray()) {
|
| + return false;
|
| + }
|
| +
|
| + JSArray* array = JSArray::cast(receiver);
|
| +
|
| + HeapObject* elms = HeapObject::cast(array->elements());
|
| + if (elms->map() != Heap::fixed_array_map()) {
|
| + return false;
|
| + }
|
| +
|
| + *elements = FixedArray::cast(elms);
|
| + return true;
|
| +}
|
| +
|
| +
|
| static Object* CallJsBuiltin(const char* name,
|
| BuiltinArguments<NO_EXTRA_ARGUMENTS> args) {
|
| HandleScope handleScope;
|
| @@ -331,7 +349,7 @@
|
| 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];
|
| + argv[i] = args.at<Object>(i + 1).location();
|
| }
|
| bool pending_exception = false;
|
| Handle<Object> result = Execution::Call(function,
|
| @@ -346,8 +364,12 @@
|
|
|
|
|
| BUILTIN(ArrayPush) {
|
| - JSArray* array = JSArray::cast(*args.receiver());
|
| - ASSERT(array->HasFastElements());
|
| + Object* receiver = *args.receiver();
|
| + FixedArray* elms = NULL;
|
| + if (!IsJSArrayWithFastElements(receiver, &elms)) {
|
| + return CallJsBuiltin("ArrayPush", args);
|
| + }
|
| + JSArray* array = JSArray::cast(receiver);
|
|
|
| int len = Smi::cast(array->length())->value();
|
| int to_add = args.length() - 1;
|
| @@ -359,7 +381,6 @@
|
| ASSERT(to_add <= (Smi::kMaxValue - len));
|
|
|
| int new_length = len + to_add;
|
| - FixedArray* elms = FixedArray::cast(array->elements());
|
|
|
| if (new_length > elms->length()) {
|
| // New backing storage is needed.
|
| @@ -390,14 +411,17 @@
|
|
|
|
|
| BUILTIN(ArrayPop) {
|
| - JSArray* array = JSArray::cast(*args.receiver());
|
| - ASSERT(array->HasFastElements());
|
| + Object* receiver = *args.receiver();
|
| + FixedArray* elms = NULL;
|
| + if (!IsJSArrayWithFastElements(receiver, &elms)) {
|
| + return CallJsBuiltin("ArrayPop", args);
|
| + }
|
| + JSArray* array = JSArray::cast(receiver);
|
|
|
| int len = Smi::cast(array->length())->value();
|
| if (len == 0) return Heap::undefined_value();
|
|
|
| // Get top element
|
| - FixedArray* elms = FixedArray::cast(array->elements());
|
| Object* top = elms->get(len - 1);
|
|
|
| // Set the length.
|
| @@ -420,18 +444,18 @@
|
|
|
|
|
| BUILTIN(ArrayShift) {
|
| - if (!ArrayPrototypeHasNoElements()) {
|
| + Object* receiver = *args.receiver();
|
| + FixedArray* elms = NULL;
|
| + if (!IsJSArrayWithFastElements(receiver, &elms)
|
| + || !ArrayPrototypeHasNoElements()) {
|
| return CallJsBuiltin("ArrayShift", args);
|
| }
|
| -
|
| - JSArray* array = JSArray::cast(*args.receiver());
|
| + JSArray* array = JSArray::cast(receiver);
|
| ASSERT(array->HasFastElements());
|
|
|
| int len = Smi::cast(array->length())->value();
|
| if (len == 0) return Heap::undefined_value();
|
|
|
| - FixedArray* elms = FixedArray::cast(array->elements());
|
| -
|
| // Get first element
|
| Object* first = elms->get(0);
|
| if (first->IsTheHole()) {
|
| @@ -451,26 +475,22 @@
|
|
|
|
|
| BUILTIN(ArrayUnshift) {
|
| - if (!ArrayPrototypeHasNoElements()) {
|
| + Object* receiver = *args.receiver();
|
| + FixedArray* elms = NULL;
|
| + if (!IsJSArrayWithFastElements(receiver, &elms)
|
| + || !ArrayPrototypeHasNoElements()) {
|
| return CallJsBuiltin("ArrayUnshift", args);
|
| }
|
| -
|
| - JSArray* array = JSArray::cast(*args.receiver());
|
| + JSArray* array = JSArray::cast(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;
|
| // Currently fixed arrays cannot grow too big, so
|
| // we should never hit this case.
|
| ASSERT(to_add <= (Smi::kMaxValue - len));
|
|
|
| - FixedArray* elms = FixedArray::cast(array->elements());
|
| -
|
| if (new_length > elms->length()) {
|
| // New backing storage is needed.
|
| int capacity = new_length + (new_length >> 1) + 16;
|
| @@ -503,11 +523,13 @@
|
|
|
|
|
| BUILTIN(ArraySlice) {
|
| - if (!ArrayPrototypeHasNoElements()) {
|
| + Object* receiver = *args.receiver();
|
| + FixedArray* elms = NULL;
|
| + if (!IsJSArrayWithFastElements(receiver, &elms)
|
| + || !ArrayPrototypeHasNoElements()) {
|
| return CallJsBuiltin("ArraySlice", args);
|
| }
|
| -
|
| - JSArray* array = JSArray::cast(*args.receiver());
|
| + JSArray* array = JSArray::cast(receiver);
|
| ASSERT(array->HasFastElements());
|
|
|
| int len = Smi::cast(array->length())->value();
|
| @@ -558,8 +580,6 @@
|
| if (result->IsFailure()) return result;
|
| FixedArray* result_elms = FixedArray::cast(result);
|
|
|
| - FixedArray* elms = FixedArray::cast(array->elements());
|
| -
|
| AssertNoAllocation no_gc;
|
| CopyElements(&no_gc, result_elms, 0, elms, k, result_len);
|
|
|
| @@ -573,11 +593,13 @@
|
|
|
|
|
| BUILTIN(ArraySplice) {
|
| - if (!ArrayPrototypeHasNoElements()) {
|
| + Object* receiver = *args.receiver();
|
| + FixedArray* elms = NULL;
|
| + if (!IsJSArrayWithFastElements(receiver, &elms)
|
| + || !ArrayPrototypeHasNoElements()) {
|
| return CallJsBuiltin("ArraySplice", args);
|
| }
|
| -
|
| - JSArray* array = JSArray::cast(*args.receiver());
|
| + JSArray* array = JSArray::cast(receiver);
|
| ASSERT(array->HasFastElements());
|
|
|
| int len = Smi::cast(array->length())->value();
|
| @@ -618,8 +640,6 @@
|
| }
|
| int actual_delete_count = Min(Max(delete_count, 0), len - actual_start);
|
|
|
| - FixedArray* elms = FixedArray::cast(array->elements());
|
| -
|
| JSArray* result_array = NULL;
|
| if (actual_delete_count == 0) {
|
| Object* result = AllocateEmptyJSArray();
|
| @@ -707,6 +727,68 @@
|
| }
|
|
|
|
|
| +BUILTIN(ArrayConcat) {
|
| + if (!ArrayPrototypeHasNoElements()) {
|
| + return CallJsBuiltin("ArrayConcat", args);
|
| + }
|
| +
|
| + // Iterate through all the arguments performing checks
|
| + // and calculating total length.
|
| + int n_arguments = args.length();
|
| + int result_len = 0;
|
| + for (int i = 0; i < n_arguments; i++) {
|
| + Object* arg = args[i];
|
| + if (!arg->IsJSArray() || !JSArray::cast(arg)->HasFastElements()) {
|
| + return CallJsBuiltin("ArrayConcat", args);
|
| + }
|
| +
|
| + int len = Smi::cast(JSArray::cast(arg)->length())->value();
|
| +
|
| + // We shouldn't overflow when adding another len.
|
| + const int kHalfOfMaxInt = 1 << (kBitsPerInt - 2);
|
| + STATIC_ASSERT(FixedArray::kMaxLength < kHalfOfMaxInt);
|
| + USE(kHalfOfMaxInt);
|
| + result_len += len;
|
| + ASSERT(result_len >= 0);
|
| +
|
| + if (result_len > FixedArray::kMaxLength) {
|
| + return CallJsBuiltin("ArrayConcat", args);
|
| + }
|
| + }
|
| +
|
| + if (result_len == 0) {
|
| + return AllocateEmptyJSArray();
|
| + }
|
| +
|
| + // Allocate result.
|
| + Object* result = AllocateJSArray();
|
| + if (result->IsFailure()) return result;
|
| + JSArray* result_array = JSArray::cast(result);
|
| +
|
| + result = Heap::AllocateUninitializedFixedArray(result_len);
|
| + if (result->IsFailure()) return result;
|
| + FixedArray* result_elms = FixedArray::cast(result);
|
| +
|
| + // Copy data.
|
| + AssertNoAllocation no_gc;
|
| + int start_pos = 0;
|
| + for (int i = 0; i < n_arguments; i++) {
|
| + JSArray* array = JSArray::cast(args[i]);
|
| + FixedArray* elms = FixedArray::cast(array->elements());
|
| + int len = Smi::cast(array->length())->value();
|
| + CopyElements(&no_gc, result_elms, start_pos, elms, 0, len);
|
| + start_pos += len;
|
| + }
|
| + ASSERT(start_pos == result_len);
|
| +
|
| + // Set the length and elements.
|
| + result_array->set_length(Smi::FromInt(result_len));
|
| + result_array->set_elements(result_elms);
|
| +
|
| + return result_array;
|
| +}
|
| +
|
| +
|
| // -----------------------------------------------------------------------------
|
| //
|
|
|
| @@ -766,20 +848,19 @@
|
|
|
| HandleScope scope;
|
| Handle<JSFunction> function = args.called_function();
|
| + ASSERT(function->shared()->IsApiFunction());
|
|
|
| + FunctionTemplateInfo* fun_data = function->shared()->get_api_func_data();
|
| if (is_construct) {
|
| - Handle<FunctionTemplateInfo> desc =
|
| - Handle<FunctionTemplateInfo>(
|
| - FunctionTemplateInfo::cast(function->shared()->function_data()));
|
| + Handle<FunctionTemplateInfo> desc(fun_data);
|
| bool pending_exception = false;
|
| Factory::ConfigureInstance(desc, Handle<JSObject>::cast(args.receiver()),
|
| &pending_exception);
|
| ASSERT(Top::has_pending_exception() == pending_exception);
|
| if (pending_exception) return Failure::Exception();
|
| + fun_data = *desc;
|
| }
|
|
|
| - FunctionTemplateInfo* fun_data =
|
| - FunctionTemplateInfo::cast(function->shared()->function_data());
|
| Object* raw_holder = TypeCheck(args.length(), &args[0], fun_data);
|
|
|
| if (raw_holder->IsNull()) {
|
| @@ -850,8 +931,8 @@
|
|
|
| static void VerifyTypeCheck(Handle<JSObject> object,
|
| Handle<JSFunction> function) {
|
| - FunctionTemplateInfo* info =
|
| - FunctionTemplateInfo::cast(function->shared()->function_data());
|
| + ASSERT(function->shared()->IsApiFunction());
|
| + FunctionTemplateInfo* info = function->shared()->get_api_func_data();
|
| if (info->signature()->IsUndefined()) return;
|
| SignatureInfo* signature = SignatureInfo::cast(info->signature());
|
| Object* receiver_type = signature->receiver();
|
| @@ -935,9 +1016,9 @@
|
| // used to create the called object.
|
| ASSERT(obj->map()->has_instance_call_handler());
|
| JSFunction* constructor = JSFunction::cast(obj->map()->constructor());
|
| - Object* template_info = constructor->shared()->function_data();
|
| + ASSERT(constructor->shared()->IsApiFunction());
|
| Object* handler =
|
| - FunctionTemplateInfo::cast(template_info)->instance_call_handler();
|
| + constructor->shared()->get_api_func_data()->instance_call_handler();
|
| ASSERT(!handler->IsUndefined());
|
| CallHandlerInfo* call_data = CallHandlerInfo::cast(handler);
|
| Object* callback_obj = call_data->callback();
|
|
|