From 11f7584d0aa19473162bf55d1e6801d975690d33 Mon Sep 17 00:00:00 2001 From: "jkummerow@chromium.org" Date: Thu, 11 Sep 2014 10:04:13 +0000 Subject: [PATCH] Fix ElementsKind handling of prototypes in Array.concat 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 | 50 +++++++++++++++++----------- test/mjsunit/regress/regress-crbug-412203.js | 31 +++++++++++++++++ 2 files changed, 62 insertions(+), 19 deletions(-) create mode 100644 test/mjsunit/regress/regress-crbug-412203.js diff --git a/src/runtime.cc b/src/runtime.cc index 77c7bb9..45d5ed0 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -10280,8 +10280,19 @@ static void CollectElementIndices(Handle 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 elements( + FixedDoubleArray::cast(object->elements())); + uint32_t length = static_cast(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 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(dense_elements_length); + { + uint32_t length = static_cast( + 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 object, if (length == range) return; // All indices accounted for already. break; } + case SLOPPY_ARGUMENTS_ELEMENTS: { + uint32_t length = static_cast( + Handle::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 index 0000000..6a78130 --- /dev/null +++ b/test/mjsunit/regress/regress-crbug-412203.js @@ -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); -- 2.7.4