gc.js (8170B)
1 // |jit-test| skip-if: getBuildConfiguration("simulator") 2 3 // Tests GC references passed as arguments during return calls. 4 // Similar to js/src/jit-test/tests/wasm/gc/trailers-gc-stress.js 5 6 let base = wasmEvalText(`(module 7 ;; A simple pseudo-random number generator. 8 ;; Produces numbers in the range 0 .. 2^16-1. 9 (global $rngState (export "rngState") 10 (mut i32) (i32.const 1) 11 ) 12 (func $rand (export "rand") (result i32) 13 (local $t i32) 14 ;; update $rngState 15 (local.set $t (global.get $rngState)) 16 (local.set $t (i32.mul (local.get $t) (i32.const 1103515245))) 17 (local.set $t (i32.add (local.get $t) (i32.const 12345))) 18 (global.set $rngState (local.get $t)) 19 ;; pull 16 random bits out of it 20 (local.set $t (i32.shr_u (local.get $t) (i32.const 15))) 21 (local.set $t (i32.and (local.get $t) (i32.const 0xFFFF))) 22 (local.get $t) 23 ) 24 25 ;; Array types 26 (type $tArrayI32 (array (mut i32))) ;; "secondary array" above 27 (type $tArrayArrayI32 (array (mut (ref null $tArrayI32)))) ;; "primary array" 28 29 (func $createSecondaryArrayLoop (export "createSecondaryArrayLoop") 30 (param $i i32) (param $arr (ref $tArrayI32)) 31 (result (ref $tArrayI32)) 32 (block $cont 33 (br_if $cont (i32.ge_u (local.get $i) (array.len (local.get $arr)))) 34 (array.set $tArrayI32 (local.get $arr) (local.get $i) (call $rand)) 35 (return_call $createSecondaryArrayLoop 36 (i32.add (local.get $i) (i32.const 1)) 37 (local.get $arr)) 38 ) 39 (local.get $arr) 40 ) 41 ;; Create an array ("secondary array") containing random numbers, with a 42 ;; size between 1 and 50, also randomly chosen. 43 (func $createSecondaryArray (export "createSecondaryArray") 44 (result (ref $tArrayI32)) 45 (return_call $createSecondaryArrayLoop 46 (i32.const 0) 47 (array.new $tArrayI32 48 (i32.const 0) 49 (i32.add (i32.rem_u (call $rand) (i32.const 50)) (i32.const 1))) 50 ) 51 ) 52 53 (func $createPrimaryArrayLoop (export "createPrimaryArrayLoop") 54 (param $i i32) (param $arrarr (ref $tArrayArrayI32)) 55 (result (ref $tArrayArrayI32)) 56 (block $cont 57 (br_if $cont (i32.ge_u (local.get $i) (array.len (local.get $arrarr)))) 58 (array.set $tArrayArrayI32 (local.get $arrarr) 59 (local.get $i) (call $createSecondaryArray)) 60 (return_call $createPrimaryArrayLoop 61 (i32.add (local.get $i) (i32.const 1)) 62 (local.get $arrarr)) 63 ) 64 (local.get $arrarr) 65 ) 66 )`); 67 let t = 68 `(module 69 ;; Array types (the same as in the base) 70 (type $tArrayI32 (array (mut i32))) ;; "secondary array" above 71 (type $tArrayArrayI32 (array (mut (ref null $tArrayI32)))) ;; "primary array" 72 73 (import "" "rngState" (global $rngState (mut i32))) 74 (import "" "rand" (func $rand (result i32))) 75 (import "" "createSecondaryArrayLoop" 76 (func $createSecondaryArrayLoop 77 (param $i i32) (param $arr (ref $tArrayI32)) 78 (result (ref $tArrayI32)))) 79 (import "" "createPrimaryArrayLoop" 80 (func $createPrimaryArrayLoop 81 (param $i i32) (param $arrarr (ref $tArrayArrayI32)) 82 (result (ref $tArrayArrayI32)))) 83 84 ;; Create an array ("secondary array") containing random numbers, with a 85 ;; size between 1 and 50, also randomly chosen. 86 ;; (Copy of the base one to create trampoline) 87 (func $createSecondaryArray (export "createSecondaryArray") 88 (result (ref $tArrayI32)) 89 (return_call $createSecondaryArrayLoop 90 (i32.const 0) 91 (array.new $tArrayI32 92 (i32.const 0) 93 (i32.add (i32.rem_u (call $rand) (i32.const 50)) (i32.const 1))) 94 ) 95 ) 96 97 ;; Create an array (the "primary array") of 1500 elements of 98 ;; type ref-of-tArrayI32. 99 (func $createPrimaryArray (export "createPrimaryArray") 100 (result (ref $tArrayArrayI32)) 101 (return_call $createPrimaryArrayLoop 102 (i32.const 0) 103 (array.new $tArrayArrayI32 (ref.null $tArrayI32) (i32.const 1500))) 104 ) 105 106 ;; Use $createPrimaryArray to create an initial array. Then randomly replace 107 ;; elements for a while. 108 (func $churn (export "churn") (param $thresh i32) (result i32) 109 (local $i i32) 110 (local $j i32) 111 (local $finalSum i32) 112 (local $arrarr (ref $tArrayArrayI32)) 113 (local $arr (ref null $tArrayI32)) 114 (local $arrLen i32) 115 (local.set $arrarr (call $createPrimaryArray)) 116 ;; This loop iterates 500,000 times. Each iteration, it chooses 117 ;; a randomly element in $arrarr and replaces it with a new 118 ;; random array of 32-bit ints. 119 (loop $cont 120 ;; make $j be a random number in 0 .. $thresh-1. 121 ;; Then replace that index in $arrarr with a new random arrayI32. 122 (local.set $j (i32.rem_u (call $rand) (local.get $thresh))) 123 (array.set $tArrayArrayI32 (local.get $arrarr) 124 (local.get $j) (call $createSecondaryArray)) 125 (local.set $i (i32.add (local.get $i) (i32.const 1))) 126 (br_if $cont (i32.lt_u (local.get $i) (i32.const 500000))) 127 ) 128 129 ;; Finally, compute a checksum by summing all the numbers 130 ;; in all secondary arrays. This simply assumes that all of the refs to 131 ;; secondary arrays are non-null, which isn't per-se guaranteed by the 132 ;; previous loop, but it works in this case because the RNG 133 ;; produces each index value to overwrite at least once. 134 (local.set $finalSum (i32.const 0)) 135 (local.set $i (i32.const 0)) ;; loop var for the outer loop 136 (loop $outer 137 ;; body of outer loop 138 ;; $arr = $arrarr[i] 139 (local.set $arr (array.get $tArrayArrayI32 (local.get $arrarr) 140 (local.get $i))) 141 ;; iterate over $arr 142 (local.set $arrLen (array.len (local.get $arr))) 143 (local.set $j (i32.const 0)) ;; loop var for the inner loop 144 (loop $inner 145 ;; body of inner loop 146 (local.set $finalSum 147 (i32.rotl (local.get $finalSum) (i32.const 1))) 148 (local.set $finalSum 149 (i32.xor (local.get $finalSum) 150 (array.get $tArrayI32 (local.get $arr) 151 (local.get $j)))) 152 ;; loop control for the inner loop 153 (local.set $j (i32.add (local.get $j) (i32.const 1))) 154 (br_if $inner (i32.lt_u (local.get $j) (local.get $arrLen))) 155 ) 156 ;; loop control for the outer loop 157 (local.set $i (i32.add (local.get $i) (i32.const 1))) 158 (br_if $outer (i32.lt_u (local.get $i) (i32.const 1500))) 159 ) 160 161 ;; finally, roll in the final value of the RNG state 162 (i32.xor (local.get $finalSum) (global.get $rngState)) 163 ) 164 )`; 165 166 let i = wasmEvalText(t, {"": base.exports,}); 167 let fns = i.exports; 168 169 assertEq(fns.churn(800), -575895114); 170 assertEq(fns.churn(1200), -1164697516); 171 172 wasmValidateText(`(module 173 (rec 174 (type $s1 (sub (struct (field i32)))) 175 (type $s2 (sub $s1 (struct (field i32 f32)))) 176 ) 177 (func (result (ref $s2)) 178 struct.new_default $s2 179 ) 180 (func (export "f") (result (ref $s1)) 181 return_call 0 182 ) 183 )`); 184 185 wasmFailValidateText(`(module 186 (rec 187 (type $s1 (sub (struct (field i32)))) 188 (type $s2 (sub $s1 (struct (field i32 f32)))) 189 ) 190 (func (result (ref $s1)) 191 struct.new_default $s1 192 ) 193 (func (export "f") (result (ref $s2)) 194 return_call 0 195 ) 196 )`, /type mismatch/); 197 198 wasmValidateText(`(module 199 (rec 200 (type $s1 (sub (struct (field i32)))) 201 (type $s2 (sub $s1 (struct (field i32 f32)))) 202 ) 203 (type $t (func (result (ref $s2)))) 204 (func (export "f") (param (ref $t)) (result (ref $s1)) 205 local.get 0 206 return_call_ref $t 207 ) 208 )`); 209 210 wasmFailValidateText(`(module 211 (rec 212 (type $s1 (sub (struct (field i32)))) 213 (type $s2 (sub $s1 (struct (field i32 f32)))) 214 ) 215 (type $t (func (result (ref $s1)))) 216 (func (export "f") (param (ref $t)) (result (ref $s2)) 217 local.get 0 218 return_call_ref $t 219 ) 220 )`, /type mismatch/);