blob: 7886495bcd9a3c4fab38f751101d2d0a1a32a01e [file] [edit]
//@ requireOptions("--alwaysUseShadowChicken=true", "--slowPathAllocsBetweenGCs=1", "--forceGCSlowPaths=true")
import { compile } from "../wabt-wrapper.js"
import * as assert from "../assert.js"
// ref.func materializes the funcref's JS wrapper via ensureFunctionWrapper, which
// allocates and so can GC. Wasm tiers update topCallFrame only just-in-time, so
// after a JS import returns it points at dead native state, and a GC there makes
// ShadowChicken read that as a JS CallFrame.
//
// Each ref.func targets a distinct function, preceded by an import call to leave
// topCallFrame stale. Fresh instances have empty wrapper caches, so later
// iterations rerun the path in whichever tier the function reached.
const numFuncs = 8;
const numInstances = 8;
let funcs = "";
let declares = "";
let body = "";
for (let i = 0; i < numFuncs; ++i) {
funcs += ` (func $f${i})\n`;
declares += ` $f${i}`;
body += ` (call $import)\n (drop (ref.func $f${i}))\n`;
}
let wat = `
(module
(import "m" "f" (func $import))
(elem declare func${declares})
${funcs} (func (export "test")
${body} )
)
`;
let calls = 0;
const imports = { m: { f: () => { ++calls; } } };
const module = await compile(wat);
for (let i = 0; i < numInstances; ++i)
new WebAssembly.Instance(module, imports).exports.test();
assert.eq(calls, numFuncs * numInstances);