side-effects-in-try.js (8462B)
1 // ----------------------------------------------------------------------------- 2 // The tests in this file assert that any side effects that happened in try code 3 // before an exception was thrown, will be known to the landing pad. It checks 4 // local throws and throws from direct calls (of local and imported functions). 5 // Side effects checked are changes to locals, and to globals. 6 // ----------------------------------------------------------------------------- 7 8 load(libdir + "eqArrayHelper.js"); 9 10 11 function testSideEffectsOnLocals() { 12 // Locals set before and after throwing instructions, either locally, or from 13 // a direct wasm function call, for locals of all Wasm numtype and a local of 14 // reftype (externref), and the thrown exception carrying a value from each 15 // Wasm numtype and one of Wasm vectype (Simd128). Testing to see if the state 16 // of the locals at the moment $exn is thrown, is known to the landing pad 17 // when $exn is caught. 18 19 let localThrow = "(throw $exn)"; 20 21 // The following is taken from calls.js 22 // Some variables to be used in all tests. 23 let typesJS = ["i32", "i64", "f32", "f64"]; 24 let types = typesJS.join(" "); 25 let exnTypeDef = `(type $exnType (func (param ${types})))`; 26 let correctLocalValues = 27 `;; Correct local values 28 (i32.const 2) 29 (i64.const 3) 30 (f32.const 4) 31 (f64.const 13.37)`; 32 let correctLocalValuesJS = [2, 3n, 4, 13.37]; 33 34 let wrongValues = 35 `;; Wrong values. 36 (i32.const 5) 37 (i64.const 6) 38 (f32.const 0.1) 39 (f64.const 0.6437)`; 40 let wrongValuesJS = [5, 6n, 0.1, 0.6437]; 41 42 // These variables are specific to the tests in this file. 43 let throwValues = 44 `;; Values to throw and catch. 45 (i32.const 7) 46 (i64.const 8) 47 (f32.const 9) 48 (f64.const 27.11)`; 49 let thrownValuesJS = [7, 8n, 9, 27.11]; 50 51 let correctResultsJS = function(externref) { 52 return [].concat(thrownValuesJS, 53 correctLocalValuesJS, 54 [externref, 1]); 55 } 56 57 // Testing also locals of Wasm vectype. 58 // The following depend on whether simd is enabled or not. We write it like 59 // this so we can run this test also when SIMD is not enabled. 60 let wrongV128 = ""; 61 let correctV128 = ""; 62 let checkV128Value = ""; 63 64 if (wasmSimdEnabled()) { 65 wrongV128 = `(v128.const i32x4 11 22 33 44)`; 66 correctV128 = `(v128.const i32x4 55 66 77 88)`; 67 checkV128Value = 68 ` ${correctV128} 69 (i32x4.eq) 70 (i32x4.all_true)`; 71 v128Type = " v128"; 72 } else { 73 wrongV128 = "(i32.const 0)"; 74 correctV128 = "(i32.const 1)"; 75 v128Type = " i32"; 76 } 77 78 let localTypes = types + " externref"; 79 let resultTypes = types + " " + localTypes; 80 81 // The last i32 in the results is the v128 check. 82 let testFuncTypeInline = 83 `(param $argCorrectRef externref) 84 (param $argWrongRef externref) 85 (result ${resultTypes} i32) 86 (local $localI32 i32) 87 (local $localI64 i64) 88 (local $localF32 f32) 89 (local $localF64 f64) 90 (local $localExternref externref) 91 (local $localV128 ${v128Type})`; 92 93 let localsSet = 94 `;; Set locals. 95 (local.set $localV128) 96 (local.set $localExternref) 97 (local.set $localF64) 98 (local.set $localF32) 99 (local.set $localI64) 100 (local.set $localI32)`; 101 let localsGet = 102 `;; Get locals. 103 (local.get $localI32) 104 (local.get $localI64) 105 (local.get $localF32) 106 (local.get $localF64) 107 (local.get $localExternref) 108 (local.get $localV128)`; 109 110 // The test module parts. ---------------------------------------------------- 111 112 let importsModule = 113 `(module 114 (type $exnType (func (param ${types}))) 115 (tag $exn (export "exn") (type $exnType)) 116 (func (export "throwif") (param $ifPredicate i32) 117 (if (local.get $ifPredicate) 118 (then 119 ${throwValues} 120 ${localThrow}))))`; 121 122 let moduleHeader = ` 123 (module 124 ${exnTypeDef} 125 (import "m" "exn" (tag $exn (type $exnType))) 126 (tag $emptyExn) 127 (import "m" "throwif" (func $throwif (param $ifPredicate i32))) 128 (func $wontThrow 129 (throw $emptyExn)) 130 (func $localCallThrow 131 ${throwValues} 132 ${localThrow}) 133 (func (export "testFunc") ${testFuncTypeInline} 134 try (result ${resultTypes} ${v128Type}) 135 ;; Locals not set. 136 (i32.const 0) ;; Predicate for $throwif. 137 (call $throwif) ;; So this doesn't throw. 138 ;; Set correct locals before throw to be caught. 139 ${correctLocalValues} 140 (local.get $argCorrectRef) 141 ${correctV128} 142 ${localsSet} 143 ;; Next up should be $exn being thrown locally or via a call.`; 144 145 let moduleRest = ` ;; The above throw to $exn should be caught here --------. 146 ;; Set wrong locals after throw to be caught. ;; | 147 ${wrongValues} ;; | 148 (local.get $argWrongRef) ;; The wrong externref param. ;; | 149 ${wrongV128} ;; | 150 ${localsSet} ;; | 151 (call $wontThrow) ;; | 152 ${wrongValues} ;; | 153 ${localsGet} ;; End of try code. ;; | 154 catch $emptyExn ;; | 155 ${wrongValues} ;; | 156 ${localsGet} ;; | 157 catch $exn ;; <---------------------------------------------------' 158 ${localsGet} 159 catch_all 160 ${wrongValues} 161 ${localsGet} 162 end 163 ;; Check if the local has the correct v128 value. 164 ${checkV128Value}))`; 165 166 let localThrowValues = ` 167 ${throwValues} 168 (throw $exn)`; 169 let directLocalCall = ` 170 (call $localCallThrow)`; 171 let directImportCall = ` 172 (i32.const 1) 173 (call $throwif)`; 174 175 // Run test for side effects on locals before throwing an exception locally, 176 // or from a direct call. 177 178 let callInstructions = [localThrowValues, directLocalCall, directImportCall]; 179 180 for (let callThrow of callInstructions) { 181 console.log("callThrow = " + callThrow); // Uncomment for debugging. 182 moduleText = moduleHeader + callThrow + moduleRest; 183 console.log("moduleText = " + moduleText); // Uncomment for debugging. 184 assertEqArray( 185 wasmEvalText(moduleText, 186 { m : wasmEvalText(importsModule).exports } 187 ).exports.testFunc("foo", "wrongFoo"), 188 correctResultsJS("foo")); 189 } 190 } 191 192 // Setting globals in try code, and testing to see if the changes are known to 193 // the landing pad. 194 function testGlobals() { 195 let test = function (type, initialValue, resultValue, wrongValue, coercion) { 196 let exports = wasmEvalText( 197 `(module 198 (tag (export "exn")) 199 (func (export "throws") 200 (throw 0)))` 201 ).exports; 202 203 assertEq( 204 wasmEvalText( 205 `(module 206 (import "m" "exn" (tag $exn)) 207 (tag $notThrownExn) 208 (import "m" "throws" (func $throws)) 209 (global (mut ${type}) (${type}.const ${initialValue})) 210 (func (export "testFunc") (result ${type}) 211 try (result ${type}) 212 (global.set 0 (${type}.const ${resultValue})) 213 (call $throws) 214 (global.set 0 (${type}.const ${wrongValue})) 215 (global.get 0) 216 catch $notThrownExn 217 (${type}.const ${wrongValue}) 218 catch $exn 219 (global.get 0) 220 end))`, 221 { m: exports } 222 ).exports.testFunc(), coercion(resultValue)); 223 }; 224 225 test("i32", 2, 7, 27, x => x); 226 test("i64", 2n, 7n, 27n, x => x); 227 test("f32", 0.3, 0.1, 0.6, Math.fround); 228 test("f64", 13.37, 0.6437244242412325666666, 4, x => x); 229 }; 230 231 // Run all tests. 232 233 testSideEffectsOnLocals(); 234 testGlobals();