| // Copyright 2018 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Flags: --expose-wasm --experimental-wasm-eh |
| |
| load("test/mjsunit/wasm/wasm-module-builder.js"); |
| |
| // Helper function to return a new exported exception with the {kSig_v_v} type |
| // signature from an anonymous module. The underlying module is thrown away. |
| function NewExportedException() { |
| let builder = new WasmModuleBuilder(); |
| let except = builder.addException(kSig_v_v); |
| builder.addExportOfKind("ex", kExternalException, except); |
| let instance = builder.instantiate(); |
| return instance.exports.ex; |
| } |
| |
| // Check that an instance matches an exception thrown by itself, even when the |
| // exception is re-thrown by a regular JavaScript function. |
| (function TestSingleInstance() { |
| print(arguments.callee.name); |
| let builder = new WasmModuleBuilder(); |
| let sig_index = builder.addType(kSig_v_v); |
| let fun = builder.addImport("m", "f", sig_index); |
| let except = builder.addException(kSig_v_v); |
| builder.addFunction("throw", kSig_v_v) |
| .addBody([ |
| kExprThrow, except |
| ]).exportFunc(); |
| builder.addFunction("catch", kSig_v_v) |
| .addBody([ |
| kExprTry, kWasmStmt, |
| kExprCallFunction, fun, |
| kExprCatch, |
| kExprBrOnExn, 0, except, |
| kExprRethrow, |
| kExprEnd, |
| ]).exportFunc(); |
| let ex_obj = new Error("my exception"); |
| let instance = builder.instantiate({ m: { f: function() { throw ex_obj }}}); |
| |
| assertThrows(() => instance.exports.throw(), WebAssembly.RuntimeError); |
| assertThrowsEquals(() => instance.exports.catch(), ex_obj); |
| try { |
| instance.exports.throw(); |
| } catch (e) { |
| ex_obj = e; |
| } |
| assertDoesNotThrow(() => instance.exports.catch()); |
| })(); |
| |
| // Check that two instances distinguish their individual exceptions if they are |
| // not shared, even when declared by the same underlying module. |
| (function TestMultiInstanceNonShared() { |
| print(arguments.callee.name); |
| let builder = new WasmModuleBuilder(); |
| let sig_index = builder.addType(kSig_v_v); |
| let fun = builder.addImport("m", "f", sig_index); |
| let except = builder.addException(kSig_v_v); |
| builder.addFunction("throw", kSig_v_v) |
| .addBody([ |
| kExprThrow, except |
| ]).exportFunc(); |
| builder.addFunction("catch", kSig_v_v) |
| .addBody([ |
| kExprTry, kWasmStmt, |
| kExprCallFunction, fun, |
| kExprCatch, |
| kExprBrOnExn, 0, except, |
| kExprRethrow, |
| kExprEnd, |
| ]).exportFunc(); |
| let ex_obj = new Error("my exception"); |
| let instance1 = builder.instantiate({ m: { f: assertUnreachable }}); |
| let instance2 = builder.instantiate({ m: { f: function() { throw ex_obj }}}); |
| |
| assertThrows(() => instance1.exports.throw(), WebAssembly.RuntimeError); |
| assertThrowsEquals(() => instance2.exports.catch(), ex_obj); |
| try { |
| instance1.exports.throw(); |
| } catch (e) { |
| ex_obj = e; |
| } |
| assertThrowsEquals(() => instance2.exports.catch(), ex_obj); |
| })(); |
| |
| // Check that two instances match their exceptions if they are shared properly, |
| // even if the local exception index of export and import is different. |
| (function TestMultiInstanceShared() { |
| print(arguments.callee.name); |
| let builder = new WasmModuleBuilder(); |
| let sig_index = builder.addType(kSig_v_v); |
| let fun = builder.addImport("m", "f", sig_index); |
| let except1 = builder.addImportedException("m", "ex1", kSig_v_v); |
| let except2 = builder.addException(kSig_v_v); |
| builder.addExportOfKind("ex2", kExternalException, except2); |
| builder.addFunction("throw", kSig_v_v) |
| .addBody([ |
| kExprThrow, except2 |
| ]).exportFunc(); |
| builder.addFunction("catch", kSig_v_v) |
| .addBody([ |
| kExprTry, kWasmStmt, |
| kExprCallFunction, fun, |
| kExprCatch, |
| kExprBrOnExn, 0, except1, |
| kExprRethrow, |
| kExprEnd, |
| ]).exportFunc(); |
| let ex_obj = new Error("my exception"); |
| let instance1 = builder.instantiate({ m: { f: assertUnreachable, |
| ex1: NewExportedException() }}); |
| let instance2 = builder.instantiate({ m: { f: function() { throw ex_obj }, |
| ex1: instance1.exports.ex2 }}); |
| |
| assertThrows(() => instance1.exports.throw(), WebAssembly.RuntimeError); |
| assertThrowsEquals(() => instance2.exports.catch(), ex_obj); |
| try { |
| instance1.exports.throw(); |
| } catch (e) { |
| ex_obj = e; |
| } |
| assertDoesNotThrow(() => instance2.exports.catch()); |
| })(); |
| |
| // Check that two instances based on different modules match their exceptions if |
| // they are shared properly, even if the local exception index is different. |
| (function TestMultiModuleShared() { |
| print(arguments.callee.name); |
| let builder1 = new WasmModuleBuilder(); |
| let except1 = builder1.addException(kSig_v_v); |
| let except2 = builder1.addException(kSig_v_v); |
| builder1.addExportOfKind("ex", kExternalException, except2); |
| builder1.addFunction("throw", kSig_v_v) |
| .addBody([ |
| kExprThrow, except2 |
| ]).exportFunc(); |
| let builder2 = new WasmModuleBuilder(); |
| let sig_index = builder2.addType(kSig_v_v); |
| let fun = builder2.addImport("m", "f", sig_index); |
| let except = builder2.addImportedException("m", "ex", kSig_v_v); |
| builder2.addFunction("catch", kSig_v_v) |
| .addBody([ |
| kExprTry, kWasmStmt, |
| kExprCallFunction, fun, |
| kExprCatch, |
| kExprBrOnExn, 0, except, |
| kExprRethrow, |
| kExprEnd, |
| ]).exportFunc(); |
| let ex_obj = new Error("my exception"); |
| let instance1 = builder1.instantiate(); |
| let instance2 = builder2.instantiate({ m: { f: function() { throw ex_obj }, |
| ex: instance1.exports.ex }}); |
| |
| assertThrows(() => instance1.exports.throw(), WebAssembly.RuntimeError); |
| assertThrowsEquals(() => instance2.exports.catch(), ex_obj); |
| try { |
| instance1.exports.throw(); |
| } catch (e) { |
| ex_obj = e; |
| } |
| assertDoesNotThrow(() => instance2.exports.catch()); |
| })(); |