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:
Gus Caplan 2020-09-25 11:23:01 -05:00 committed by Commit Bot
parent 74794fb937
commit 83f778aff1
3 changed files with 37 additions and 3 deletions

View File

@ -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);

View File

@ -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],
]
---

View 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);