Source code

Revision control

Copy as Markdown

Other Tools

// |jit-test| --setpref=wasm_gc=true; 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/);