diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/tail-calls/gc.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/tail-calls/gc.js | 220 |
1 files changed, 220 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/tail-calls/gc.js b/js/src/jit-test/tests/wasm/tail-calls/gc.js new file mode 100644 index 0000000000..10e5971e6d --- /dev/null +++ b/js/src/jit-test/tests/wasm/tail-calls/gc.js @@ -0,0 +1,220 @@ +// |jit-test| --wasm-function-references; --wasm-gc; skip-if: !wasmGcEnabled() || getBuildConfiguration("simulator") + +// Tests GC references passed as arguments during return calls. +// Similar to js/src/jit-test/tests/wasm/gc/trailers-gc-stress.js + +let base = wasmEvalText(`(module + ;; A simple pseudo-random number generator. + ;; Produces numbers in the range 0 .. 2^16-1. + (global $rngState (export "rngState") + (mut i32) (i32.const 1) + ) + (func $rand (export "rand") (result i32) + (local $t i32) + ;; update $rngState + (local.set $t (global.get $rngState)) + (local.set $t (i32.mul (local.get $t) (i32.const 1103515245))) + (local.set $t (i32.add (local.get $t) (i32.const 12345))) + (global.set $rngState (local.get $t)) + ;; pull 16 random bits out of it + (local.set $t (i32.shr_u (local.get $t) (i32.const 15))) + (local.set $t (i32.and (local.get $t) (i32.const 0xFFFF))) + (local.get $t) + ) + + ;; Array types + (type $tArrayI32 (array (mut i32))) ;; "secondary array" above + (type $tArrayArrayI32 (array (mut (ref null $tArrayI32)))) ;; "primary array" + + (func $createSecondaryArrayLoop (export "createSecondaryArrayLoop") + (param $i i32) (param $arr (ref $tArrayI32)) + (result (ref $tArrayI32)) + (block $cont + (br_if $cont (i32.ge_u (local.get $i) (array.len (local.get $arr)))) + (array.set $tArrayI32 (local.get $arr) (local.get $i) (call $rand)) + (return_call $createSecondaryArrayLoop + (i32.add (local.get $i) (i32.const 1)) + (local.get $arr)) + ) + (local.get $arr) + ) + ;; Create an array ("secondary array") containing random numbers, with a + ;; size between 1 and 50, also randomly chosen. + (func $createSecondaryArray (export "createSecondaryArray") + (result (ref $tArrayI32)) + (return_call $createSecondaryArrayLoop + (i32.const 0) + (array.new $tArrayI32 + (i32.const 0) + (i32.add (i32.rem_u (call $rand) (i32.const 50)) (i32.const 1))) + ) + ) + + (func $createPrimaryArrayLoop (export "createPrimaryArrayLoop") + (param $i i32) (param $arrarr (ref $tArrayArrayI32)) + (result (ref $tArrayArrayI32)) + (block $cont + (br_if $cont (i32.ge_u (local.get $i) (array.len (local.get $arrarr)))) + (array.set $tArrayArrayI32 (local.get $arrarr) + (local.get $i) (call $createSecondaryArray)) + (return_call $createPrimaryArrayLoop + (i32.add (local.get $i) (i32.const 1)) + (local.get $arrarr)) + ) + (local.get $arrarr) + ) +)`); +let t = +`(module + ;; Array types (the same as in the base) + (type $tArrayI32 (array (mut i32))) ;; "secondary array" above + (type $tArrayArrayI32 (array (mut (ref null $tArrayI32)))) ;; "primary array" + + (import "" "rngState" (global $rngState (mut i32))) + (import "" "rand" (func $rand (result i32))) + (import "" "createSecondaryArrayLoop" + (func $createSecondaryArrayLoop + (param $i i32) (param $arr (ref $tArrayI32)) + (result (ref $tArrayI32)))) + (import "" "createPrimaryArrayLoop" + (func $createPrimaryArrayLoop + (param $i i32) (param $arrarr (ref $tArrayArrayI32)) + (result (ref $tArrayArrayI32)))) + + ;; Create an array ("secondary array") containing random numbers, with a + ;; size between 1 and 50, also randomly chosen. + ;; (Copy of the base one to create trampoline) + (func $createSecondaryArray (export "createSecondaryArray") + (result (ref $tArrayI32)) + (return_call $createSecondaryArrayLoop + (i32.const 0) + (array.new $tArrayI32 + (i32.const 0) + (i32.add (i32.rem_u (call $rand) (i32.const 50)) (i32.const 1))) + ) + ) + + ;; Create an array (the "primary array") of 1500 elements of + ;; type ref-of-tArrayI32. + (func $createPrimaryArray (export "createPrimaryArray") + (result (ref $tArrayArrayI32)) + (return_call $createPrimaryArrayLoop + (i32.const 0) + (array.new $tArrayArrayI32 (ref.null $tArrayI32) (i32.const 1500))) + ) + + ;; Use $createPrimaryArray to create an initial array. Then randomly replace + ;; elements for a while. + (func $churn (export "churn") (param $thresh i32) (result i32) + (local $i i32) + (local $j i32) + (local $finalSum i32) + (local $arrarr (ref $tArrayArrayI32)) + (local $arr (ref null $tArrayI32)) + (local $arrLen i32) + (local.set $arrarr (call $createPrimaryArray)) + ;; This loop iterates 500,000 times. Each iteration, it chooses + ;; a randomly element in $arrarr and replaces it with a new + ;; random array of 32-bit ints. + (loop $cont + ;; make $j be a random number in 0 .. $thresh-1. + ;; Then replace that index in $arrarr with a new random arrayI32. + (local.set $j (i32.rem_u (call $rand) (local.get $thresh))) + (array.set $tArrayArrayI32 (local.get $arrarr) + (local.get $j) (call $createSecondaryArray)) + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br_if $cont (i32.lt_u (local.get $i) (i32.const 500000))) + ) + + ;; Finally, compute a checksum by summing all the numbers + ;; in all secondary arrays. This simply assumes that all of the refs to + ;; secondary arrays are non-null, which isn't per-se guaranteed by the + ;; previous loop, but it works in this case because the RNG + ;; produces each index value to overwrite at least once. + (local.set $finalSum (i32.const 0)) + (local.set $i (i32.const 0)) ;; loop var for the outer loop + (loop $outer + ;; body of outer loop + ;; $arr = $arrarr[i] + (local.set $arr (array.get $tArrayArrayI32 (local.get $arrarr) + (local.get $i))) + ;; iterate over $arr + (local.set $arrLen (array.len (local.get $arr))) + (local.set $j (i32.const 0)) ;; loop var for the inner loop + (loop $inner + ;; body of inner loop + (local.set $finalSum + (i32.rotl (local.get $finalSum) (i32.const 1))) + (local.set $finalSum + (i32.xor (local.get $finalSum) + (array.get $tArrayI32 (local.get $arr) + (local.get $j)))) + ;; loop control for the inner loop + (local.set $j (i32.add (local.get $j) (i32.const 1))) + (br_if $inner (i32.lt_u (local.get $j) (local.get $arrLen))) + ) + ;; loop control for the outer loop + (local.set $i (i32.add (local.get $i) (i32.const 1))) + (br_if $outer (i32.lt_u (local.get $i) (i32.const 1500))) + ) + + ;; finally, roll in the final value of the RNG state + (i32.xor (local.get $finalSum) (global.get $rngState)) + ) +)`; + +let i = wasmEvalText(t, {"": base.exports,}); +let fns = i.exports; + +assertEq(fns.churn(800), -575895114); +assertEq(fns.churn(1200), -1164697516); + +wasmValidateText(`(module + (rec + (type $s1 (sub (struct (field i32)))) + (type $s2 (sub $s1 (struct (field i32 f32)))) + ) + (func (result (ref $s2)) + struct.new_default $s2 + ) + (func (export "f") (result (ref $s1)) + return_call 0 + ) +)`); + +wasmFailValidateText(`(module + (rec + (type $s1 (sub (struct (field i32)))) + (type $s2 (sub $s1 (struct (field i32 f32)))) + ) + (func (result (ref $s1)) + struct.new_default $s1 + ) + (func (export "f") (result (ref $s2)) + return_call 0 + ) +)`, /type mismatch/); + +wasmValidateText(`(module + (rec + (type $s1 (sub (struct (field i32)))) + (type $s2 (sub $s1 (struct (field i32 f32)))) + ) + (type $t (func (result (ref $s2)))) + (func (export "f") (param (ref $t)) (result (ref $s1)) + local.get 0 + return_call_ref $t + ) +)`); + +wasmFailValidateText(`(module + (rec + (type $s1 (sub (struct (field i32)))) + (type $s2 (sub $s1 (struct (field i32 f32)))) + ) + (type $t (func (result (ref $s1)))) + (func (export "f") (param (ref $t)) (result (ref $s2)) + local.get 0 + return_call_ref $t + ) +)`, /type mismatch/); |