diff --git a/deps/v8/src/builtins.cc b/deps/v8/src/builtins.cc index 4d399b2ca0cd39..e8bd830a1b16fa 100644 --- a/deps/v8/src/builtins.cc +++ b/deps/v8/src/builtins.cc @@ -795,14 +795,18 @@ namespace { */ class ArrayConcatVisitor { public: - ArrayConcatVisitor(Isolate* isolate, Handle storage, + ArrayConcatVisitor(Isolate* isolate, Handle storage, bool fast_elements) : isolate_(isolate), storage_(isolate->global_handles()->Create(*storage)), index_offset_(0u), - bit_field_(FastElementsField::encode(fast_elements) | - ExceedsLimitField::encode(false) | - IsFixedArrayField::encode(storage->IsFixedArray())) { + bit_field_( + FastElementsField::encode(fast_elements) | + ExceedsLimitField::encode(false) | + IsFixedArrayField::encode(storage->IsFixedArray()) | + HasSimpleElementsField::encode(storage->IsFixedArray() || + storage->map()->instance_type() > + LAST_CUSTOM_ELEMENTS_RECEIVER)) { DCHECK(!(this->fast_elements() && !is_fixed_array())); } @@ -891,12 +895,16 @@ class ArrayConcatVisitor { // (otherwise) Handle storage_fixed_array() { DCHECK(is_fixed_array()); + DCHECK(has_simple_elements()); return Handle::cast(storage_); } Handle storage_jsreceiver() { DCHECK(!is_fixed_array()); return Handle::cast(storage_); } + bool has_simple_elements() const { + return HasSimpleElementsField::decode(bit_field_); + } private: // Convert storage to dictionary mode. @@ -929,12 +937,14 @@ class ArrayConcatVisitor { inline void set_storage(FixedArray* storage) { DCHECK(is_fixed_array()); + DCHECK(has_simple_elements()); storage_ = isolate_->global_handles()->Create(storage); } class FastElementsField : public BitField {}; class ExceedsLimitField : public BitField {}; class IsFixedArrayField : public BitField {}; + class HasSimpleElementsField : public BitField {}; bool fast_elements() const { return FastElementsField::decode(bit_field_); } void set_fast_elements(bool fast) { @@ -1166,8 +1176,6 @@ bool IterateElementsSlow(Isolate* isolate, Handle receiver, visitor->increase_index_offset(length); return true; } - - /** * A helper function that visits "array" elements of a JSReceiver in numerical * order. @@ -1201,7 +1209,8 @@ bool IterateElements(Isolate* isolate, Handle receiver, return IterateElementsSlow(isolate, receiver, length, visitor); } - if (!HasOnlySimpleElements(isolate, *receiver)) { + if (!HasOnlySimpleElements(isolate, *receiver) || + !visitor->has_simple_elements()) { return IterateElementsSlow(isolate, receiver, length, visitor); } Handle array = Handle::cast(receiver); @@ -1476,7 +1485,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle species, // In case of failure, fall through. } - Handle storage; + Handle storage; if (fast_case) { // The backing storage array must have non-existing elements to preserve // holes across concat operations. @@ -1494,7 +1503,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle species, ASSIGN_RETURN_FAILURE_ON_EXCEPTION( isolate, storage_object, Execution::New(isolate, species, species, 1, &length)); - storage = storage_object; + storage = Handle::cast(storage_object); } ArrayConcatVisitor visitor(isolate, storage, fast_case); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-682194.js b/deps/v8/test/mjsunit/regress/regress-crbug-682194.js new file mode 100644 index 00000000000000..62a4347eefee73 --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-682194.js @@ -0,0 +1,35 @@ +// Copyright 2017 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: --expose-gc + +var proxy = new Proxy([], { + defineProperty() { + w.length = 1; // shorten the array so the backstore pointer is relocated + gc(); // force gc to move the array's elements backstore + return Object.defineProperty.apply(this, arguments); + } +}); + +class MyArray extends Array { + // custom constructor which returns a proxy object + static get[Symbol.species](){ + return function() { + return proxy; + } + }; +} + +var w = new MyArray(100); +w[1] = 0.1; +w[2] = 0.1; + +var result = Array.prototype.concat.call(w); + +assertEquals(undefined, result[0]); +assertEquals(0.1, result[1]); + +for (var i = 2; i < 200; i++) { + assertEquals(undefined, result[i]); +}