diff --git a/src/elements.cc b/src/elements.cc index 742942b844..2ec224c23e 100644 --- a/src/elements.cc +++ b/src/elements.cc @@ -866,10 +866,10 @@ class ElementsAccessorBase : public ElementsAccessor { static Handle DirectCollectElementIndicesImpl( Isolate* isolate, Handle object, Handle backing_store, GetKeysConversion convert, - PropertyFilter filter, Handle list, uint32_t* nof_indices) { + PropertyFilter filter, Handle list, uint32_t* nof_indices, + uint32_t insertion_index = 0) { uint32_t length = ElementsAccessorSubclass::GetIterationLength(*object, *backing_store); - uint32_t insertion_index = 0; for (uint32_t i = 0; i < length; i++) { if (ElementsAccessorSubclass::HasElementImpl(object, i, backing_store, filter)) { @@ -914,7 +914,7 @@ class ElementsAccessorBase : public ElementsAccessor { &nof_indices); // Sort the indices list if necessary. - if (IsDictionaryElementsKind(kind())) { + if (IsDictionaryElementsKind(kind()) || IsSloppyArgumentsElements(kind())) { struct { bool operator()(Object* a, Object* b) { if (!a->IsUndefined()) { @@ -1227,11 +1227,11 @@ class DictionaryElementsAccessor static Handle DirectCollectElementIndicesImpl( Isolate* isolate, Handle object, Handle backing_store, GetKeysConversion convert, - PropertyFilter filter, Handle list, uint32_t* nof_indices) { + PropertyFilter filter, Handle list, uint32_t* nof_indices, + uint32_t insertion_index = 0) { Handle dictionary = Handle::cast(backing_store); uint32_t capacity = dictionary->Capacity(); - uint32_t insertion_index = 0; for (uint32_t i = 0; i < capacity; i++) { uint32_t key = GetKeyForEntryImpl(dictionary, i, filter); if (key == kMaxUInt32) continue; @@ -2223,6 +2223,55 @@ class SloppyArgumentsElementsAccessor obj, entry - length); } } + + static void CollectElementIndicesImpl(Handle object, + Handle backing_store, + KeyAccumulator* keys, uint32_t range, + PropertyFilter filter, + uint32_t offset) { + FixedArray* parameter_map = FixedArray::cast(*backing_store); + uint32_t length = parameter_map->length() - 2; + if (range < length) length = range; + + for (uint32_t i = offset; i < length; ++i) { + if (!parameter_map->get(i + 2)->IsTheHole()) { + keys->AddKey(i); + } + } + + Handle store(FixedArrayBase::cast(parameter_map->get(1))); + ArgumentsAccessor::CollectElementIndicesImpl(object, store, keys, range, + filter, offset); + if (SloppyArgumentsElementsAccessorSubclass::kind() == + FAST_SLOPPY_ARGUMENTS_ELEMENTS) { + keys->SortCurrentElementsList(); + } + } + + static Handle DirectCollectElementIndicesImpl( + Isolate* isolate, Handle object, + Handle backing_store, GetKeysConversion convert, + PropertyFilter filter, Handle list, uint32_t* nof_indices, + uint32_t insertion_index = 0) { + FixedArray* parameter_map = FixedArray::cast(*backing_store); + uint32_t length = parameter_map->length() - 2; + + for (uint32_t i = 0; i < length; ++i) { + if (parameter_map->get(i + 2)->IsTheHole()) continue; + if (convert == CONVERT_TO_STRING) { + Handle index_string = isolate->factory()->Uint32ToString(i); + list->set(insertion_index, *index_string); + } else { + list->set(insertion_index, Smi::FromInt(i), SKIP_WRITE_BARRIER); + } + insertion_index++; + } + + Handle store(FixedArrayBase::cast(parameter_map->get(1))); + return ArgumentsAccessor::DirectCollectElementIndicesImpl( + isolate, object, store, convert, filter, list, nof_indices, + insertion_index); + } }; diff --git a/test/mjsunit/regress/regress-4825.js b/test/mjsunit/regress/regress-4825.js new file mode 100644 index 0000000000..5ad096f3ed --- /dev/null +++ b/test/mjsunit/regress/regress-4825.js @@ -0,0 +1,95 @@ +// Copyright 2016 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. + +function enumerate(o) { + var keys = []; + for (var key in o) keys.push(key); + return keys; +} + +(function testSlowSloppyArgumentsElements() { + function slowSloppyArguments(a, b, c) { + arguments[10000] = "last"; + arguments[4000] = "first"; + arguments[6000] = "second"; + arguments[5999] = "x"; + arguments[3999] = "y"; + return arguments; + } + assertEquals(["0", "1", "2", "3999", "4000", "5999", "6000", "10000"], + Object.keys(slowSloppyArguments(1, 2, 3))); + + assertEquals(["0", "1", "2", "3999", "4000", "5999", "6000", "10000"], + enumerate(slowSloppyArguments(1,2,3))); +})(); + +(function testSlowSloppyArgumentsElementsNotEnumerable() { + function slowSloppyArguments(a, b, c) { + Object.defineProperty(arguments, 10000, { + enumerable: false, configurable: false, value: "NOPE" + }); + arguments[4000] = "first"; + arguments[6000] = "second"; + arguments[5999] = "x"; + arguments[3999] = "y"; + return arguments; + } + + assertEquals(["0", "1", "2", "3999", "4000", "5999", "6000"], + Object.keys(slowSloppyArguments(1, 2, 3))); + + assertEquals(["0", "1", "2", "3999", "4000", "5999", "6000"], + enumerate(slowSloppyArguments(1,2,3))); +})(); + +(function testFastSloppyArgumentsElements() { + function fastSloppyArguments(a, b, c) { + arguments[5] = 1; + arguments[7] = 0; + arguments[3] = 2; + return arguments; + } + assertEquals(["0", "1", "2", "3", "5", "7"], + Object.keys(fastSloppyArguments(1, 2, 3))); + + assertEquals( + ["0", "1", "2", "3", "5", "7"], enumerate(fastSloppyArguments(1, 2, 3))); + + function fastSloppyArguments2(a, b, c) { + delete arguments[0]; + arguments[0] = "test"; + return arguments; + } + + assertEquals(["0", "1", "2"], Object.keys(fastSloppyArguments2(1, 2, 3))); + assertEquals(["0", "1", "2"], enumerate(fastSloppyArguments2(1, 2, 3))); +})(); + +(function testFastSloppyArgumentsElementsNotEnumerable() { + function fastSloppyArguments(a, b, c) { + Object.defineProperty(arguments, 5, { + enumerable: false, configurable: false, value: "NOPE" + }); + arguments[7] = 0; + arguments[3] = 2; + return arguments; + } + assertEquals( + ["0", "1", "2", "3", "7"], Object.keys(fastSloppyArguments(1, 2, 3))); + + assertEquals( + ["0", "1", "2", "3", "7"], enumerate(fastSloppyArguments(1,2,3))); + + function fastSloppyArguments2(a, b, c) { + delete arguments[0]; + Object.defineProperty(arguments, 1, { + enumerable: false, configurable: false, value: "NOPE" + }); + arguments[0] = "test"; + return arguments; + } + + assertEquals(["0", "2"], Object.keys(fastSloppyArguments2(1, 2, 3))); + assertEquals(["0", "2"], enumerate(fastSloppyArguments2(1, 2, 3))); +})();