Skip to content

Commit

Permalink
deps: V8: backport e560815 from upstream
Browse files Browse the repository at this point in the history
Original commit message:
  [runtime] Fix Array.prototype.concat with complex @@species
  Array.prototype.concat does not properly handle JSProxy species that will
  modify the currently visited array.

  BUG=682194

  Review-Url: https://codereview.chromium.org/2655623004
  Cr-Commit-Position: refs/heads/master@{#42640}

Refs: #12779

PR-URL: #16133
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
Reviewed-By: Franziska Hinkelmann <franziska.hinkelmann@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
  • Loading branch information
ofrobots authored and MylesBorins committed Oct 13, 2017
1 parent 31e4f2b commit f35071b
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 9 deletions.
27 changes: 18 additions & 9 deletions deps/v8/src/builtins.cc
Original file line number Diff line number Diff line change
Expand Up @@ -795,14 +795,18 @@ namespace {
*/
class ArrayConcatVisitor {
public:
ArrayConcatVisitor(Isolate* isolate, Handle<Object> storage,
ArrayConcatVisitor(Isolate* isolate, Handle<HeapObject> 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()));
}

Expand Down Expand Up @@ -891,12 +895,16 @@ class ArrayConcatVisitor {
// (otherwise)
Handle<FixedArray> storage_fixed_array() {
DCHECK(is_fixed_array());
DCHECK(has_simple_elements());
return Handle<FixedArray>::cast(storage_);
}
Handle<JSReceiver> storage_jsreceiver() {
DCHECK(!is_fixed_array());
return Handle<JSReceiver>::cast(storage_);
}
bool has_simple_elements() const {
return HasSimpleElementsField::decode(bit_field_);
}

private:
// Convert storage to dictionary mode.
Expand Down Expand Up @@ -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<bool, 0, 1> {};
class ExceedsLimitField : public BitField<bool, 1, 1> {};
class IsFixedArrayField : public BitField<bool, 2, 1> {};
class HasSimpleElementsField : public BitField<bool, 3, 1> {};

bool fast_elements() const { return FastElementsField::decode(bit_field_); }
void set_fast_elements(bool fast) {
Expand Down Expand Up @@ -1166,8 +1176,6 @@ bool IterateElementsSlow(Isolate* isolate, Handle<JSReceiver> receiver,
visitor->increase_index_offset(length);
return true;
}


/**
* A helper function that visits "array" elements of a JSReceiver in numerical
* order.
Expand Down Expand Up @@ -1201,7 +1209,8 @@ bool IterateElements(Isolate* isolate, Handle<JSReceiver> 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<JSObject> array = Handle<JSObject>::cast(receiver);
Expand Down Expand Up @@ -1476,7 +1485,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
// In case of failure, fall through.
}

Handle<Object> storage;
Handle<HeapObject> storage;
if (fast_case) {
// The backing storage array must have non-existing elements to preserve
// holes across concat operations.
Expand All @@ -1494,7 +1503,7 @@ Object* Slow_ArrayConcat(Arguments* args, Handle<Object> species,
ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
isolate, storage_object,
Execution::New(isolate, species, species, 1, &length));
storage = storage_object;
storage = Handle<HeapObject>::cast(storage_object);
}

ArrayConcatVisitor visitor(isolate, storage, fast_case);
Expand Down
35 changes: 35 additions & 0 deletions deps/v8/test/mjsunit/regress/regress-crbug-682194.js
Original file line number Diff line number Diff line change
@@ -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]);
}

0 comments on commit f35071b

Please sign in to comment.