From 36d22d82aa202bb199967e9512281e9a53db42c9 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 21:33:14 +0200 Subject: Adding upstream version 115.7.0esr. Signed-off-by: Daniel Baumann --- js/src/jit-test/tests/wasm/ref-types/stackmaps3.js | 201 +++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 js/src/jit-test/tests/wasm/ref-types/stackmaps3.js (limited to 'js/src/jit-test/tests/wasm/ref-types/stackmaps3.js') diff --git a/js/src/jit-test/tests/wasm/ref-types/stackmaps3.js b/js/src/jit-test/tests/wasm/ref-types/stackmaps3.js new file mode 100644 index 0000000000..1b4c15abd2 --- /dev/null +++ b/js/src/jit-test/tests/wasm/ref-types/stackmaps3.js @@ -0,0 +1,201 @@ +// Generates a bunch of numbers-on-the-heap, and tries to ensure that they are +// held live -- at least for a short while -- only by references from the wasm +// evaluation stack. Then assembles them in a list and checks that the list +// is as expected (and we don't segfault). While all this is running we also +// have an regular interrupt whose handler does a bunch of allocation, so as +// to cause as much disruption as possible. + +// Note this makes an assumption about how the wasm compiler works. There's +// no particular reason that the wasm compiler needs to keep the results of +// the $mkBoxedInt calls on the machine stack. It could equally cache them in +// registers or even reorder the call sequences so as to interleave +// construction of the list elements with construction of the list itself. It +// just happens that our baseline compiler will behave as described. That +// said, however, it's hard to imagine how an implementation could complete +// the list construction without having at least one root in a register or on +// the stack, so the test still has value regardless of how the underlying +// implementation works. + +const {Module,Instance} = WebAssembly; + +const DEBUG = false; + +let t = + `(module + (import "" "mkCons" (func $mkCons (param externref) (param externref) (result externref))) + (import "" "mkBoxedInt" (func $mkBoxedInt (result externref))) + + (func $mkNil (result externref) + ref.null extern + ) + + (func $mkConsIgnoringScalar + (param $hd externref) (param i32) (param $tl externref) + (result externref) + (local.get $hd) + (local.get $tl) + call $mkCons + ) + + (func $mkList (export "mkList") (result externref) + call $mkList20 + ) + + (func $mkList20 (result externref) + ;; create 20 pointers to boxed ints on the stack, plus a few + ;; scalars for added confusion + (local $scalar99 i32) + (local $scalar97 i32) + (local.set $scalar99 (i32.const 99)) + (local.set $scalar97 (i32.const 97)) + + call $mkBoxedInt + local.get $scalar99 + call $mkBoxedInt + call $mkBoxedInt + local.get $scalar97 + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkBoxedInt + call $mkNil + ;; Now we have (pointers to) 20 boxed ints and a NIL on the stack, and + ;; nothing else holding them live. Build a list from the elements. + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkCons + call $mkConsIgnoringScalar + call $mkCons + call $mkConsIgnoringScalar + ) + )`; + +let boxedIntCounter = 0; + +function BoxedInt() { + this.theInt = boxedIntCounter; + boxedIntCounter++; +} + +function mkBoxedInt() { + return new BoxedInt(); +} + +function printBoxedInt(bi) { + print(bi.theInt); +} + +function Cons(hd, tl) { + this.hd = hd; + this.tl = tl; +} + +function mkCons(hd, tl) { + return new Cons(hd, tl); +} + +function showList(list) { + print("["); + while (list) { + printBoxedInt(list.hd); + print(","); + list = list.tl; + } + print("]"); +} + +function checkList(list, expectedHdValue, expectedLength) { + while (list) { + if (expectedLength <= 0) + return false; + if (list.hd.theInt !== expectedHdValue) { + return false; + } + list = list.tl; + expectedHdValue++; + expectedLength--; + } + if (expectedLength == 0) { + return true; + } else { + return false; + } +} + +let i = wasmEvalText(t, {"":{mkCons: mkCons, mkBoxedInt: mkBoxedInt}}); + + +function Croissant(chocolate) { + this.chocolate = chocolate; +} + +function allocates() { + return new Croissant(true); +} + +function handler() { + if (DEBUG) { + print('XXXXXXXX icallback: START'); + } + let q = allocates(); + let sum = 0; + for (let i = 0; i < 15000; 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++; } + } + // Artificial use of |sum|. See comment above. + if (sum == 133713371337) { print("unlikely!"); } + timeout(1, handler); + if (DEBUG) { + print('XXXXXXXX icallback: END'); + } + return true; +} + +timeout(1, handler); + +for (let n = 0; n < 10000; n++) { + let listLowest = boxedIntCounter; + + // Create the list in wasm land, possibly inducing GC on the way + let aList = i.exports.mkList(); + + // Check it is as we expect + let ok = checkList(aList, listLowest, 20/*expected length*/); + if (!ok) { + print("Failed on list: "); + showList(aList); + } + assertEq(ok, true); +} + +// If we get here, the test finished successfully. -- cgit v1.2.3