diff options
Diffstat (limited to 'js/src/jit-test/tests/wasm/exceptions/side-effects-in-try.js')
-rw-r--r-- | js/src/jit-test/tests/wasm/exceptions/side-effects-in-try.js | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/js/src/jit-test/tests/wasm/exceptions/side-effects-in-try.js b/js/src/jit-test/tests/wasm/exceptions/side-effects-in-try.js new file mode 100644 index 0000000000..d5d5567fca --- /dev/null +++ b/js/src/jit-test/tests/wasm/exceptions/side-effects-in-try.js @@ -0,0 +1,234 @@ +// ----------------------------------------------------------------------------- +// The tests in this file assert that any side effects that happened in try code +// before an exception was thrown, will be known to the landing pad. It checks +// local throws and throws from direct calls (of local and imported functions). +// Side effects checked are changes to locals, and to globals. +// ----------------------------------------------------------------------------- + +load(libdir + "eqArrayHelper.js"); + + +function testSideEffectsOnLocals() { + // Locals set before and after throwing instructions, either locally, or from + // a direct wasm function call, for locals of all Wasm numtype and a local of + // reftype (externref), and the thrown exception carrying a value from each + // Wasm numtype and one of Wasm vectype (Simd128). Testing to see if the state + // of the locals at the moment $exn is thrown, is known to the landing pad + // when $exn is caught. + + let localThrow = "(throw $exn)"; + + // The following is taken from calls.js + // Some variables to be used in all tests. + let typesJS = ["i32", "i64", "f32", "f64"]; + let types = typesJS.join(" "); + let exnTypeDef = `(type $exnType (func (param ${types})))`; + let correctLocalValues = + `;; Correct local values + (i32.const 2) + (i64.const 3) + (f32.const 4) + (f64.const 13.37)`; + let correctLocalValuesJS = [2, 3n, 4, 13.37]; + + let wrongValues = + `;; Wrong values. + (i32.const 5) + (i64.const 6) + (f32.const 0.1) + (f64.const 0.6437)`; + let wrongValuesJS = [5, 6n, 0.1, 0.6437]; + + // These variables are specific to the tests in this file. + let throwValues = + `;; Values to throw and catch. + (i32.const 7) + (i64.const 8) + (f32.const 9) + (f64.const 27.11)`; + let thrownValuesJS = [7, 8n, 9, 27.11]; + + let correctResultsJS = function(externref) { + return [].concat(thrownValuesJS, + correctLocalValuesJS, + [externref, 1]); + } + + // Testing also locals of Wasm vectype. + // The following depend on whether simd is enabled or not. We write it like + // this so we can run this test also when SIMD is not enabled. + let wrongV128 = ""; + let correctV128 = ""; + let checkV128Value = ""; + + if (wasmSimdEnabled()) { + wrongV128 = `(v128.const i32x4 11 22 33 44)`; + correctV128 = `(v128.const i32x4 55 66 77 88)`; + checkV128Value = + ` ${correctV128} + (i32x4.eq) + (i32x4.all_true)`; + v128Type = " v128"; + } else { + wrongV128 = "(i32.const 0)"; + correctV128 = "(i32.const 1)"; + v128Type = " i32"; + } + + let localTypes = types + " externref"; + let resultTypes = types + " " + localTypes; + + // The last i32 in the results is the v128 check. + let testFuncTypeInline = + `(param $argCorrectRef externref) + (param $argWrongRef externref) + (result ${resultTypes} i32) + (local $localI32 i32) + (local $localI64 i64) + (local $localF32 f32) + (local $localF64 f64) + (local $localExternref externref) + (local $localV128 ${v128Type})`; + + let localsSet = + `;; Set locals. + (local.set $localV128) + (local.set $localExternref) + (local.set $localF64) + (local.set $localF32) + (local.set $localI64) + (local.set $localI32)`; + let localsGet = + `;; Get locals. + (local.get $localI32) + (local.get $localI64) + (local.get $localF32) + (local.get $localF64) + (local.get $localExternref) + (local.get $localV128)`; + + // The test module parts. ---------------------------------------------------- + + let importsModule = + `(module + (type $exnType (func (param ${types}))) + (tag $exn (export "exn") (type $exnType)) + (func (export "throwif") (param $ifPredicate i32) + (if (local.get $ifPredicate) + (then + ${throwValues} + ${localThrow}))))`; + + let moduleHeader = ` + (module + ${exnTypeDef} + (import "m" "exn" (tag $exn (type $exnType))) + (tag $emptyExn) + (import "m" "throwif" (func $throwif (param $ifPredicate i32))) + (func $wontThrow + (throw $emptyExn)) + (func $localCallThrow + ${throwValues} + ${localThrow}) + (func (export "testFunc") ${testFuncTypeInline} + (try (result ${resultTypes} ${v128Type}) + (do + ;; Locals not set. + (i32.const 0) ;; Predicate for $throwif. + (call $throwif) ;; So this doesn't throw. + ;; Set correct locals before throw to be caught. + ${correctLocalValues} + (local.get $argCorrectRef) + ${correctV128} + ${localsSet} + ;; Next up should be $exn being thrown locally or via a call.`; + + let moduleRest = ` ;; The above throw to $exn should be caught here --------. + ;; Set wrong locals after throw to be caught. ;; | + ${wrongValues} ;; | + (local.get $argWrongRef) ;; The wrong externref param. ;; | + ${wrongV128} ;; | + ${localsSet} ;; | + (call $wontThrow) ;; | + ${wrongValues} ;; | + ${localsGet});; End of try code. ;; | + (catch $emptyExn ;; | + ${wrongValues} ;; | + ${localsGet}) ;; | + (catch $exn ;; <---------------------------------------------------' + ${localsGet}) + (catch_all + ${wrongValues} + ${localsGet})) + ;; Check if the local has the correct v128 value. + ${checkV128Value}))`; + + let localThrowValues = ` + ${throwValues} + (throw $exn)`; + let directLocalCall = ` + (call $localCallThrow)`; + let directImportCall = ` + (i32.const 1) + (call $throwif)`; + + // Run test for side effects on locals before throwing an exception locally, + // or from a direct call. + + let callInstructions = [localThrowValues, directLocalCall, directImportCall]; + + for (let callThrow of callInstructions) { + console.log("callThrow = " + callThrow); // Uncomment for debugging. + moduleText = moduleHeader + callThrow + moduleRest; + console.log("moduleText = " + moduleText); // Uncomment for debugging. + assertEqArray( + wasmEvalText(moduleText, + { m : wasmEvalText(importsModule).exports } + ).exports.testFunc("foo", "wrongFoo"), + correctResultsJS("foo")); + } +} + +// Setting globals in try code, and testing to see if the changes are known to +// the landing pad. +function testGlobals() { + let test = function (type, initialValue, resultValue, wrongValue, coercion) { + let exports = wasmEvalText( + `(module + (tag (export "exn")) + (func (export "throws") + (throw 0)))` + ).exports; + + assertEq( + wasmEvalText( + `(module + (import "m" "exn" (tag $exn)) + (tag $notThrownExn) + (import "m" "throws" (func $throws)) + (global (mut ${type}) (${type}.const ${initialValue})) + (func (export "testFunc") (result ${type}) + (try (result ${type}) + (do + (global.set 0 (${type}.const ${resultValue})) + (call $throws) + (global.set 0 (${type}.const ${wrongValue})) + (global.get 0)) + (catch $notThrownExn + (${type}.const ${wrongValue})) + (catch $exn + (global.get 0)))))`, + { m: exports } + ).exports.testFunc(), coercion(resultValue)); + }; + + test("i32", 2, 7, 27, x => x); + test("i64", 2n, 7n, 27n, x => x); + test("f32", 0.3, 0.1, 0.6, Math.fround); + test("f64", 13.37, 0.6437244242412325666666, 4, x => x); +}; + +// Run all tests. + +testSideEffectsOnLocals(); +testGlobals(); |