Fix ElementsKind handling of prototypes in Array.concat
authorjkummerow@chromium.org <jkummerow@chromium.org>
Thu, 11 Sep 2014 10:04:13 +0000 (10:04 +0000)
committerjkummerow@chromium.org <jkummerow@chromium.org>
Thu, 11 Sep 2014 10:04:13 +0000 (10:04 +0000)
Double elements, typed elements, and sloppy arguments elements were all erroneously marked UNREACHABLE.

BUG=chromium:412203
LOG=n
R=ulan@chromium.org

Review URL: https://codereview.chromium.org/560463002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23863 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/runtime.cc
test/mjsunit/regress/regress-crbug-412203.js [new file with mode: 0644]

index 77c7bb9..45d5ed0 100644 (file)
@@ -10280,8 +10280,19 @@ static void CollectElementIndices(Handle<JSObject> object,
     }
     case FAST_HOLEY_DOUBLE_ELEMENTS:
     case FAST_DOUBLE_ELEMENTS: {
-      // TODO(1810): Decide if it's worthwhile to implement this.
-      UNREACHABLE();
+      if (object->elements()->IsFixedArray()) {
+        DCHECK(object->elements()->length() == 0);
+        break;
+      }
+      Handle<FixedDoubleArray> elements(
+          FixedDoubleArray::cast(object->elements()));
+      uint32_t length = static_cast<uint32_t>(elements->length());
+      if (range < length) length = range;
+      for (uint32_t i = 0; i < length; i++) {
+        if (!elements->is_the_hole(i)) {
+          indices->Add(i);
+        }
+      }
       break;
     }
     case DICTIONARY_ELEMENTS: {
@@ -10301,25 +10312,15 @@ static void CollectElementIndices(Handle<JSObject> object,
       }
       break;
     }
-    default: {
-      int dense_elements_length;
-      switch (kind) {
-#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size)                        \
-        case EXTERNAL_##TYPE##_ELEMENTS: {                                     \
-          dense_elements_length =                                              \
-              External##Type##Array::cast(object->elements())->length();       \
-          break;                                                               \
-        }
+#define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \
+    case TYPE##_ELEMENTS:                               \
+    case EXTERNAL_##TYPE##_ELEMENTS:
 
-        TYPED_ARRAYS(TYPED_ARRAY_CASE)
+      TYPED_ARRAYS(TYPED_ARRAY_CASE)
 #undef TYPED_ARRAY_CASE
-
-        default:
-          UNREACHABLE();
-          dense_elements_length = 0;
-          break;
-      }
-      uint32_t length = static_cast<uint32_t>(dense_elements_length);
+    {
+      uint32_t length = static_cast<uint32_t>(
+          FixedArrayBase::cast(object->elements())->length());
       if (range <= length) {
         length = range;
         // We will add all indices, so we might as well clear it first
@@ -10332,6 +10333,17 @@ static void CollectElementIndices(Handle<JSObject> object,
       if (length == range) return;  // All indices accounted for already.
       break;
     }
+    case SLOPPY_ARGUMENTS_ELEMENTS: {
+      uint32_t length = static_cast<uint32_t>(
+          Handle<JSArray>::cast(object)->length()->Number());
+      ElementsAccessor* accessor = object->GetElementsAccessor();
+      for (uint32_t i = 0; i < length; i++) {
+        if (accessor->HasElement(object, object, i)) {
+          indices->Add(i);
+        }
+      }
+      break;
+    }
   }
 
   PrototypeIterator iter(isolate, object);
diff --git a/test/mjsunit/regress/regress-crbug-412203.js b/test/mjsunit/regress/regress-crbug-412203.js
new file mode 100644 (file)
index 0000000..6a78130
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --allow-natives-syntax
+
+var b = [];
+b[10000] = 1;
+// Required to reproduce the bug.
+assertTrue(%HasDictionaryElements(b));
+
+var a1 = [1.5];
+b.__proto__ = a1;
+assertEquals(1.5, ([].concat(b))[0]);
+
+var a2 = new Int32Array(2);
+a2[0] = 3;
+b.__proto__ = a2
+assertEquals(3, ([].concat(b))[0]);
+
+function foo(x, y) {
+  var a = [];
+  a[10000] = 1;
+  assertTrue(%HasDictionaryElements(a));
+
+  a.__proto__ = arguments;
+  var c = [].concat(a);
+  assertEquals(2, c[0]);
+  assertEquals(undefined, c[1]);
+}
+foo(2);