Revision: 4151 Author: [email protected] Date: Wed Mar 17 01:30:07 2010 Log: More generic version of Array.concat builtin.
Review URL: http://codereview.chromium.org/1036002 http://code.google.com/p/v8/source/detail?r=4151 Modified: /branches/bleeding_edge/src/builtins.cc /branches/bleeding_edge/src/v8-counters.h ======================================= --- /branches/bleeding_edge/src/builtins.cc Mon Mar 15 03:52:38 2010 +++ /branches/bleeding_edge/src/builtins.cc Wed Mar 17 01:30:07 2010 @@ -728,36 +728,34 @@ BUILTIN(ArrayConcat) { - Counters::array_concat_builtin_total.Increment(); - if (args.length() != 2) { - // Fast case only for concating two arrays. + if (!ArrayPrototypeHasNoElements()) { return CallJsBuiltin("ArrayConcat", args); } - Counters::array_concat_builtin_two_args.Increment(); - - Object* receiver_obj = *args.receiver(); - FixedArray* receiver_elms = NULL; - Object* arg_obj = args[1]; - FixedArray* arg_elms = NULL; - if (!IsJSArrayWithFastElements(receiver_obj, &receiver_elms) - || !IsJSArrayWithFastElements(arg_obj, &arg_elms) - || !ArrayPrototypeHasNoElements()) { - return CallJsBuiltin("ArrayConcat", args); - } - - JSArray* receiver_array = JSArray::cast(receiver_obj); - ASSERT(receiver_array->HasFastElements()); - JSArray* arg_array = JSArray::cast(arg_obj); - ASSERT(arg_array->HasFastElements()); - - int receiver_len = Smi::cast(receiver_array->length())->value(); - int arg_len = Smi::cast(arg_array->length())->value(); - ASSERT(receiver_len <= (Smi::kMaxValue - arg_len)); - - int result_len = receiver_len + arg_len; - if (result_len > FixedArray::kMaxSize) { - 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(); } @@ -773,8 +771,15 @@ // Copy data. AssertNoAllocation no_gc; - CopyElements(&no_gc, result_elms, 0, receiver_elms, 0, receiver_len); - CopyElements(&no_gc, result_elms, receiver_len, arg_elms, 0, arg_len); + 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)); ======================================= --- /branches/bleeding_edge/src/v8-counters.h Mon Mar 15 03:52:38 2010 +++ /branches/bleeding_edge/src/v8-counters.h Wed Mar 17 01:30:07 2010 @@ -151,8 +151,6 @@ SC(constructed_objects_stub, V8.ConstructedObjectsStub) \ SC(array_function_runtime, V8.ArrayFunctionRuntime) \ SC(array_function_native, V8.ArrayFunctionNative) \ - SC(array_concat_builtin_total, V8.ArrayConcatTotal) \ - SC(array_concat_builtin_two_args, V8.ArrayConcatTwoArgs) \ SC(for_in, V8.ForIn) \ SC(enum_cache_hits, V8.EnumCacheHits) \ SC(enum_cache_misses, V8.EnumCacheMisses) \ -- v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev
