PR-URL: https://github.com/nodejs/node/pull/55014 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com>
69 lines
2.6 KiB
JavaScript
69 lines
2.6 KiB
JavaScript
// Copyright 2023 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
|
|
|
|
// This is a fairly complex tests that tries to combine the following things:
|
|
//
|
|
// - compile a function in a garbage-initialized zone (ie, a zone that isn't
|
|
// initialized with 0s).
|
|
//
|
|
// - have a loop phi whose input count get reduced (because the graph builder
|
|
// realizes that one of its predecessor is dead)
|
|
//
|
|
// - have this loop phi have a Phi as backedge.
|
|
//
|
|
// A bit of context: in an optimization for Phi untagging, I was iterating Phi
|
|
// inputs on RecordUseHint, but I didn't want to visit the backedge if it wasn't
|
|
// bound. To know if it was bound or not, I would set it to nullptr when
|
|
// creating the loop phi, and I could thus check if the last input was nullptr
|
|
// or not. However, this doesn't work when phi inputs get shrunk, as the last
|
|
// input (the backedge) could then contain garbage before it's bound (but this
|
|
// garbage wouldn't be nullptr, so it would look like a regular valid
|
|
// pointer). This didn't show any bug in mjsunit; but this test reproduces the
|
|
// error.
|
|
|
|
function f(a) {
|
|
let x = 2;
|
|
let i = 0;
|
|
if (a) {
|
|
x += 14;
|
|
} else {
|
|
%DeoptimizeNow();
|
|
if (a === 0) {
|
|
// The following addition has no feedback, which will cause Maglev to
|
|
// replace it with an unconditional deopt, thus removing one of the
|
|
// predecessors of the while-loop header.
|
|
x += 25;
|
|
}
|
|
}
|
|
// The following loop has a Phi for `x`, which initially is seen by the graph
|
|
// builder as having 3 predecessors. And its backedge is a Phi (that's
|
|
// important). One of its predecessor is removed during graph building because
|
|
// the `x += 25` is replaced by a Deopt.
|
|
while (i < 5) {
|
|
// We now have an Int32 use of `x`. It should be recorded as such, and
|
|
// should be propagated upwards in the Phi inputs of `x`. However, the
|
|
// backedge hasn't been bound yet, so we should skip it. Note that the
|
|
// backedge is at offset 1 rather than 2 because we've reduced the number
|
|
// of predecessors of `x`.
|
|
x ^ 2;
|
|
x = a ? i - 2 : 8;
|
|
i++;
|
|
}
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(f);
|
|
f(1);
|
|
%OptimizeMaglevOnNextCall(f);
|
|
f(1);
|
|
// We now cause `f` to deopt so that it can be re-optimized, ideally using the
|
|
// same zone as before (which is thus not 0-initialized anymore but rather
|
|
// filled with old garbage in release mode, and filled with non-zero invalid
|
|
// pointers in debug mode (something like 0xcdcdcdcdcdcdcdcd).
|
|
f();
|
|
|
|
%OptimizeMaglevOnNextCall(f);
|
|
f(1);
|