diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /js/src/jit-test/tests/wasm/ref-types/stackmaps2.js | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'js/src/jit-test/tests/wasm/ref-types/stackmaps2.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/ref-types/stackmaps2.js | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/ref-types/stackmaps2.js b/js/src/jit-test/tests/wasm/ref-types/stackmaps2.js new file mode 100644 index 0000000000..986d378a75 --- /dev/null +++ b/js/src/jit-test/tests/wasm/ref-types/stackmaps2.js @@ -0,0 +1,132 @@ +// Tests wasm frame tracing in the presence of interrupt handlers that perform +// allocation. The structure is +// +// test top level: call fn2 +// fn2: call fn1 +// fn1: repeat { call-direct fn0; call-indirect fn0; } +// fn0: a 100-iteration loop that does nothing except waste time +// +// At the same time we are asynchronously runnning handler(), which does a lot +// of allocation. At some point that will trigger a GC. Assuming that +// handler() runs whilst fn0 is running (the most likely scenario, since fn0 +// consumes the majority of the wasm running time), then the runtime will walk +// the stack from the wasm exit frame, through fn0, fn1 and finally fn2. As +// with stackmaps1.js, there are some ref-typed args in use so as provide +// traceable stack slots to follow. +// +// The test runs until the loop in fn1 determines that handler() has allocated +// sufficient memory as to have caused at least three collections. This helps +// keep the test effective in the face of wide variations in the rate of +// progress of the handler()'s loop (eg x86+native is fast, arm64+simulator is +// slow). + +const {Module,Instance} = WebAssembly; + +const DEBUG = false; + +let t = + `(module + (type $typeOfFn0 + (func (param i32) (param externref) (param i32) + (param externref) (param externref) (param i32) (result i32))) + + (import "" "alloc" (func $alloc (result externref))) + (import "" "quitp" (func $quitp (result i32))) + (import "" "check3" (func $check3 (param externref) (param externref) (param externref))) + + (table 1 1 funcref) + (elem (i32.const 0) $fn0) + + ;; -- fn 0 + (func $fn0 (export "fn0") + (param $arg1 i32) (param $arg2 externref) (param $arg3 i32) + (param $arg4 externref) (param $arg5 externref) (param $arg6 i32) (result i32) + (local $i i32) + + ;; spinloop to waste time + (loop + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br_if 0 (i32.lt_s (local.get $i) (i32.const 100))) + ) + + (i32.add (i32.add (local.get $arg1) (local.get $arg3)) (local.get $arg6)) + + ;; Poke the ref-typed arguments, to be sure that they got kept alive + ;; properly across any GC that might have happened. + (call $check3 (local.get $arg2) (local.get $arg4) (local.get $arg5)) + ) + + ;; -- fn 1 + (func $fn1 (export "fn1") (param $arg1 externref) (result i32) + (loop (result i32) + ;; call direct to $fn0 + (call $fn0 (i32.const 10) (local.get $arg1) (i32.const 12) + (local.get $arg1) (local.get $arg1) (i32.const 15)) + + ;; call indirect to table index 0, which is $fn0 + (call_indirect (type $typeOfFn0) + (i32.const 10) (local.get $arg1) (i32.const 12) + (local.get $arg1) (local.get $arg1) (i32.const 15) + (i32.const 0)) ;; table index + + i32.add + + ;; Continue iterating until handler() has allocated enough + (br_if 0 (i32.eq (call $quitp) (i32.const 0))) + ) + ) + + ;; -- fn 2 + (func $fn2 (export "fn2") (param $arg1 externref) (result i32) + (call $fn1 (local.get $arg1)) + ) + )`; + +function Croissant(chocolate, number) { + this.chocolate = chocolate; + this.number = number; +} + +function allocates() { + return new Croissant(true, 271828); +} + +let totAllocs = 0; + +function handler() { + if (DEBUG) { + print('XXXXXXXX icallback: START'); + } + let q = allocates(); + let sum = 0; + let iters = 15000; + for (let i = 0; i < iters; i++) { + let x = allocates(); + // Without this hoop jumping to create an apparent use of |x|, Ion + // will remove the allocation call and make the test pointless. + if (x == q) { sum++; } + } + totAllocs += iters; + // Artificial use of |sum|. See comment above. + if (sum == 133713371337) { print("unlikely!"); } + timeout(0.5, handler); + if (DEBUG) { + print('XXXXXXXX icallback: END'); + } + return true; +} + +function quitp() { + return totAllocs > 200000 ? 1 : 0; +} + +function check3(a1, a2, a3) { + assertEq(a1.number, 31415927); + assertEq(a2.number, 31415927); + assertEq(a3.number, 31415927); +} + +let i = wasmEvalText(t, {"":{alloc: allocates, quitp: quitp, check3: check3}}); + +timeout(0.5, handler); +print(i.exports.fn2( new Croissant(false, 31415927) )); |