Add iterator done check in spread destructuring
This fixes the logic in the desugaring of destructuring assignments. In particular, a spread element would not check if previous `next` results had already been done, and would always call `next()` again. Change-Id: I1bd384678722e6cf51c5777fc3b0dd965360291a Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2430488 Commit-Queue: Gus Caplan <snek@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#70144}
This commit is contained in:
parent
74794fb937
commit
83f778aff1
@ -3793,6 +3793,7 @@ void BytecodeGenerator::BuildDestructuringArrayAssignment(
|
||||
|
||||
if (spread) {
|
||||
RegisterAllocationScope scope(this);
|
||||
BytecodeLabel is_done;
|
||||
|
||||
// A spread is turned into a loop over the remainer of the iterator.
|
||||
Expression* target = spread->expression();
|
||||
@ -3809,6 +3810,10 @@ void BytecodeGenerator::BuildDestructuringArrayAssignment(
|
||||
feedback_index(feedback_spec()->AddLiteralSlot()));
|
||||
builder()->StoreAccumulatorInRegister(array);
|
||||
|
||||
// If done, jump to assigning empty array
|
||||
builder()->LoadAccumulatorWithRegister(done);
|
||||
builder()->JumpIfTrue(ToBooleanMode::kConvertToBoolean, &is_done);
|
||||
|
||||
// var index = 0;
|
||||
Register index = register_allocator()->NewRegister();
|
||||
builder()->LoadLiteral(Smi::zero());
|
||||
@ -3826,6 +3831,7 @@ void BytecodeGenerator::BuildDestructuringArrayAssignment(
|
||||
next_value_load_slot, next_done_load_slot,
|
||||
index_slot, element_slot);
|
||||
|
||||
builder()->Bind(&is_done);
|
||||
// Assign the array to the LHS.
|
||||
builder()->LoadAccumulatorWithRegister(array);
|
||||
BuildAssignment(lhs_data, op, lookup_hoisting_mode);
|
||||
|
@ -100,7 +100,7 @@ snippet: "
|
||||
"
|
||||
frame size: 14
|
||||
parameter count: 1
|
||||
bytecode array length: 232
|
||||
bytecode array length: 236
|
||||
bytecodes: [
|
||||
/* 48 S> */ B(CreateArrayLiteral), U8(0), U8(0), U8(37),
|
||||
B(Star), R(2),
|
||||
@ -149,6 +149,8 @@ bytecodes: [
|
||||
B(Star), R(0),
|
||||
/* 63 S> */ B(CreateEmptyArrayLiteral), U8(15),
|
||||
B(Star), R(11),
|
||||
B(Ldar), R(6),
|
||||
B(JumpIfToBooleanTrue), U8(44),
|
||||
B(LdaZero),
|
||||
B(Star), R(12),
|
||||
B(LdaTrue),
|
||||
@ -211,8 +213,8 @@ constant pool: [
|
||||
ONE_BYTE_INTERNALIZED_STRING_TYPE ["return"],
|
||||
]
|
||||
handlers: [
|
||||
[34, 162, 170],
|
||||
[186, 207, 209],
|
||||
[34, 166, 174],
|
||||
[190, 211, 213],
|
||||
]
|
||||
|
||||
---
|
||||
|
26
test/mjsunit/destruct-array-spread-done.js
Normal file
26
test/mjsunit/destruct-array-spread-done.js
Normal file
@ -0,0 +1,26 @@
|
||||
// Copyright 2020 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.
|
||||
|
||||
'use strict';
|
||||
|
||||
let called = 0
|
||||
const it = {
|
||||
[Symbol.iterator]() {
|
||||
return this;
|
||||
},
|
||||
next() {
|
||||
called += 1;
|
||||
return {
|
||||
value: 42,
|
||||
done: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
const [a, b, ...c] = it;
|
||||
|
||||
assertEquals(called, 1);
|
||||
assertEquals(a, undefined);
|
||||
assertEquals(b, undefined);
|
||||
assertEquals(c.length, 0);
|
Loading…
Reference in New Issue
Block a user