Drop the FixedArray allocation in ArrayDestructure, and write registers
directly when performing the ArrayDestructure.
This is needed not (just) for performance, but for correctness. The
two-phase approach of reading the iterator into a FixedArray and then
setting registers meant that throwing an exception in `next()` would
cause either all or none of the target registers to be set, rather
than setting them one-by-one as they are returned by the iterator.
This is done differently depending on the tier:
* In Ignition and Sparkplug, the ArrayDestructure builtin now writes
directly to the register frame, receiving its address as an
argument.
* In Maglev, the ArrayDestructure builtin is effectively eagerly
inlined, desugared into the appropriate iteration protocol
execution, where the abstract interpreter register values are
updated one-by one to be exception safe, and lazy continuations
handle finishing the writes to the remaining register in case
there's a deopt
* In Turbofan, I ain't doin' all that, so it's UNREACHABLE. Please
write your local Turbolev representative to get the Maglev
implementation working in the 4th tier.
TAG=agy
Conversation-Id: 7fc7c031-68c6-4ddc-bdff-6ce4e63adc59
Change-Id: Ie1d21dc20f845e8d04aea8a177cd632b155dbd32
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8035120
Reviewed-by: Marja Hölttä <marja@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#108498}
75 lines
1.8 KiB
JavaScript
75 lines
1.8 KiB
JavaScript
// Copyright 2026 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: --allow-natives-syntax --maglev --turbolev --array-destructure-bytecode
|
|
|
|
(function TestDestructuringAsValueExpression() {
|
|
let a, b;
|
|
let arr = [10, 20];
|
|
let res = ([a, b] = arr);
|
|
assertEquals(arr, res);
|
|
assertEquals(10, a);
|
|
assertEquals(20, b);
|
|
})();
|
|
|
|
(function TestDestructuringInReturnStatement() {
|
|
function f(arr) {
|
|
let x, y;
|
|
return ([x, y] = arr);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(f);
|
|
let arr = [30, 40];
|
|
assertEquals(arr, f(arr));
|
|
assertEquals(arr, f(arr));
|
|
%OptimizeFunctionOnNextCall(f);
|
|
assertEquals(arr, f(arr));
|
|
assertOptimized(f);
|
|
})();
|
|
|
|
(function TestChainedDestructuringAssignments() {
|
|
function f(arr) {
|
|
let a, b, c, d;
|
|
let res = ([a, b] = ([c, d] = arr));
|
|
assertEquals(arr, res);
|
|
return a + b + c + d;
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(f);
|
|
assertEquals(220, f([50, 60]));
|
|
assertEquals(220, f([50, 60]));
|
|
%OptimizeFunctionOnNextCall(f);
|
|
assertEquals(220, f([50, 60]));
|
|
assertOptimized(f);
|
|
})();
|
|
|
|
(function TestDestructuringWithDefaultValuesInExpression() {
|
|
function f(arr) {
|
|
let x, y;
|
|
return ([x = 100, y = 200] = arr);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(f);
|
|
let arr1 = [5, undefined];
|
|
assertEquals(arr1, f(arr1));
|
|
%OptimizeFunctionOnNextCall(f);
|
|
assertEquals(arr1, f(arr1));
|
|
assertOptimized(f);
|
|
})();
|
|
|
|
(function TestDestructuringWithHoles() {
|
|
function f(arr) {
|
|
let x, z;
|
|
return ([x, , z] = arr);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(f);
|
|
let arr = [10, 20, 30];
|
|
assertEquals(arr, f(arr));
|
|
assertEquals(arr, f(arr));
|
|
%OptimizeFunctionOnNextCall(f);
|
|
assertEquals(arr, f(arr));
|
|
assertOptimized(f);
|
|
})();
|