6904a8120b
.. mostly mentions in mjsunit `Flags:` lines and in comments. Bug: v8:10386 Change-Id: If79dfdc448d0a3f19883ef1f816e77e750cb4061 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3865964 Commit-Queue: Jakob Linke <jgruber@chromium.org> Reviewed-by: Michael Achenbach <machenbach@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/main@{#82852}
96 lines
2.8 KiB
JavaScript
96 lines
2.8 KiB
JavaScript
// Copyright 2021 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 --expose-gc --turbofan --no-concurrent-recompilation
|
|
// Flags: --no-always-turbofan --no-assert-types
|
|
|
|
// This weak ref is for checking whether the closure-allocated object o got
|
|
// collected as it should.
|
|
var weak;
|
|
|
|
// Return a function which refers to a variable from its enclosing function.
|
|
function makeFn() {
|
|
var o = {};
|
|
weak = new WeakRef(o);
|
|
o.num = 0;
|
|
return () => { return ++o.num; };
|
|
}
|
|
|
|
// Simple wrapper function which will cause inlining.
|
|
function g(f) {
|
|
f();
|
|
}
|
|
|
|
// Optimize g so that it inlines a specific function instance created by makeFn,
|
|
// and then drop all user-visible references to that function instance.
|
|
(function () {
|
|
var fn = makeFn();
|
|
%PrepareFunctionForOptimization(g);
|
|
%PrepareFunctionForOptimization(fn);
|
|
g(fn);
|
|
%OptimizeFunctionOnNextCall(g);
|
|
g(fn);
|
|
})();
|
|
|
|
// WeakRefs created during the current microtask are strong, so defer the rest.
|
|
setTimeout(() => {
|
|
// Since the function inlined by g no longer exists, it should deopt and
|
|
// release the inner function.
|
|
gc();
|
|
|
|
// Check that the memory leak described in v8:4578 no longer happens.
|
|
assertEquals(undefined, weak.deref());
|
|
|
|
// Next, let's check the opposite case: if an optimized function's Code is
|
|
// currently running at the time of gc, then it must keep its deoptimization
|
|
// data alive.
|
|
|
|
// Another simple wrapper function, but this one causes a GC internally.
|
|
function h(f) {
|
|
gcAndCheckState(); // Non-inlined call
|
|
f(); // Inlined call
|
|
}
|
|
|
|
var doCheck = false;
|
|
function gcAndCheckState() {
|
|
if (!doCheck) return;
|
|
|
|
// It's possible that h has already deoptimized by this point if
|
|
// --stress-incremental-marking caused additional gc cycles.
|
|
var optimized = isOptimized(h);
|
|
|
|
gc();
|
|
|
|
// If the optimized code for h is still on the stack, then it must not clear
|
|
// out its own deoptimization data. Eventually h will deopt due to the wrong
|
|
// function being passed, but only after this function has returned.
|
|
if (optimized) {
|
|
assertNotEquals(undefined, weak.deref());
|
|
} else {
|
|
assertEquals(undefined, weak.deref());
|
|
}
|
|
}
|
|
|
|
// Don't inline gcAndCheckState, to avoid the possibility that its content
|
|
// could cause h to deoptimize.
|
|
%NeverOptimizeFunction(gcAndCheckState);
|
|
|
|
// Optimize h to inline a specific function instance, and then drop all
|
|
// user-visible references to that inlined function.
|
|
(function () {
|
|
var fn = makeFn();
|
|
%PrepareFunctionForOptimization(h);
|
|
%PrepareFunctionForOptimization(fn);
|
|
h(fn);
|
|
%OptimizeFunctionOnNextCall(h);
|
|
h(fn);
|
|
})();
|
|
|
|
// Defer again so the WeakRef can expire.
|
|
setTimeout(() => {
|
|
doCheck = true;
|
|
h(() => {});
|
|
}, 0);
|
|
}, 0);
|