From c8e795e3af3133c2133befe3cc5166a69e61e65c Mon Sep 17 00:00:00 2001 From: "antonm@chromium.org" Date: Wed, 17 Mar 2010 08:30:07 +0000 Subject: [PATCH] More generic version of Array.concat builtin. Review URL: http://codereview.chromium.org/1036002 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4151 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/builtins.cc | 57 ++++++++++++++++++++++++++++++------------------------- src/v8-counters.h | 2 -- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/builtins.cc b/src/builtins.cc index 4166b71..d545c34 100644 --- a/src/builtins.cc +++ b/src/builtins.cc @@ -728,36 +728,34 @@ BUILTIN(ArraySplice) { BUILTIN(ArrayConcat) { - Counters::array_concat_builtin_total.Increment(); - if (args.length() != 2) { - // Fast case only for concating two arrays. - 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()) { + if (!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()); + // 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 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 len = Smi::cast(JSArray::cast(arg)->length())->value(); - int result_len = receiver_len + arg_len; - if (result_len > FixedArray::kMaxSize) { - return CallJsBuiltin("ArrayConcat", args); + // 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 @@ BUILTIN(ArrayConcat) { // 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)); diff --git a/src/v8-counters.h b/src/v8-counters.h index c1400ae..b595cd4 100644 --- a/src/v8-counters.h +++ b/src/v8-counters.h @@ -151,8 +151,6 @@ namespace internal { 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) \ -- 2.7.4