summaryrefslogtreecommitdiffstats
path: root/js/src/jit-test/tests/wasm/ref-types/stackmaps2.js
diff options
context:
space:
mode:
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.js132
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) ));