More generic version of Array.concat builtin.
authorantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Mar 2010 08:30:07 +0000 (08:30 +0000)
committerantonm@chromium.org <antonm@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Wed, 17 Mar 2010 08:30:07 +0000 (08:30 +0000)
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
src/v8-counters.h

index 4166b71..d545c34 100644 (file)
@@ -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));
index c1400ae..b595cd4 100644 (file)
@@ -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)                           \