| // 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: --experimental-wasm-eh --experimental-wasm-reftypes --allow-natives-syntax | 
 |  | 
 | load("test/mjsunit/wasm/wasm-module-builder.js"); | 
 | load("test/mjsunit/wasm/exceptions-utils.js"); | 
 |  | 
 | // Test the encoding of a thrown exception with a null-ref value. | 
 | (function TestThrowRefNull() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_r); | 
 |   builder.addFunction("throw_null", kSig_v_v) | 
 |       .addBody([ | 
 |         kExprRefNull, kWasmExternRef, | 
 |         kExprThrow, except, | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |  | 
 |   assertWasmThrows(instance, except, [null], () => instance.exports.throw_null()); | 
 | })(); | 
 |  | 
 | // Test throwing/catching the null-ref value. | 
 | (function TestThrowCatchRefNull() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_r); | 
 |   builder.addFunction("throw_catch_null", kSig_i_i) | 
 |       .addBody([ | 
 |         kExprTry, kWasmExternRef, | 
 |           kExprLocalGet, 0, | 
 |           kExprI32Eqz, | 
 |           kExprIf, kWasmExternRef, | 
 |             kExprRefNull, kWasmExternRef, | 
 |             kExprThrow, except, | 
 |           kExprElse, | 
 |             kExprI32Const, 42, | 
 |             kExprReturn, | 
 |           kExprEnd, | 
 |         kExprCatch, | 
 |           kExprBrOnExn, 0, except, | 
 |           kExprRethrow, | 
 |         kExprEnd, | 
 |         kExprRefIsNull, | 
 |         kExprIf, kWasmI32, | 
 |           kExprI32Const, 23, | 
 |         kExprElse, | 
 |           kExprUnreachable, | 
 |         kExprEnd, | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |  | 
 |   assertEquals(23, instance.exports.throw_catch_null(0)); | 
 |   assertEquals(42, instance.exports.throw_catch_null(1)); | 
 | })(); | 
 |  | 
 | // Test the encoding of a thrown exception with a reference type value. | 
 | (function TestThrowRefParam() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_r); | 
 |   builder.addFunction("throw_param", kSig_v_r) | 
 |       .addBody([ | 
 |         kExprLocalGet, 0, | 
 |         kExprThrow, except, | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |   let o = new Object(); | 
 |  | 
 |   assertWasmThrows(instance, except, [o], () => instance.exports.throw_param(o)); | 
 |   assertWasmThrows(instance, except, [1], () => instance.exports.throw_param(1)); | 
 |   assertWasmThrows(instance, except, [2.3], () => instance.exports.throw_param(2.3)); | 
 |   assertWasmThrows(instance, except, ["str"], () => instance.exports.throw_param("str")); | 
 | })(); | 
 |  | 
 | // Test throwing/catching the reference type value. | 
 | (function TestThrowCatchRefParam() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_r); | 
 |   builder.addFunction("throw_catch_param", kSig_r_r) | 
 |       .addBody([ | 
 |         kExprTry, kWasmExternRef, | 
 |           kExprLocalGet, 0, | 
 |           kExprThrow, except, | 
 |         kExprCatch, | 
 |           kExprBrOnExn, 0, except, | 
 |           kExprRethrow, | 
 |         kExprEnd, | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |   let o = new Object(); | 
 |  | 
 |   assertEquals(o, instance.exports.throw_catch_param(o)); | 
 |   assertEquals(1, instance.exports.throw_catch_param(1)); | 
 |   assertEquals(2.3, instance.exports.throw_catch_param(2.3)); | 
 |   assertEquals("str", instance.exports.throw_catch_param("str")); | 
 | })(); | 
 |  | 
 | // Test throwing/catching a function reference type value. | 
 | (function TestThrowCatchAnyFunc() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_a); | 
 |   builder.addFunction("throw_catch_local", kSig_a_v) | 
 |       .addLocals(kWasmAnyFunc, 1) | 
 |       .addBody([ | 
 |         kExprTry, kWasmAnyFunc, | 
 |           kExprLocalGet, 0, | 
 |           kExprThrow, except, | 
 |         kExprCatch, | 
 |           kExprBrOnExn, 0, except, | 
 |           kExprRethrow, | 
 |         kExprEnd, | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |  | 
 |   assertEquals(null, instance.exports.throw_catch_local()); | 
 | })(); | 
 |  | 
 | // Test throwing/catching an encapsulated exception type value. | 
 | (function TestThrowCatchExnRef() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_e); | 
 |   builder.addFunction("throw_catch_param", kSig_e_e) | 
 |       .addBody([ | 
 |         kExprTry, kWasmExnRef, | 
 |           kExprLocalGet, 0, | 
 |           kExprThrow, except, | 
 |         kExprCatch, | 
 |           kExprBrOnExn, 0, except, | 
 |           kExprRethrow, | 
 |         kExprEnd, | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |   let e = new Error("my encapsulated error"); | 
 |  | 
 |   assertEquals(e, instance.exports.throw_catch_param(e)); | 
 |   assertEquals(1, instance.exports.throw_catch_param(1)); | 
 |   assertEquals(2.3, instance.exports.throw_catch_param(2.3)); | 
 |   assertEquals("str", instance.exports.throw_catch_param("str")); | 
 | })(); | 
 |  | 
 | // Test storing and loading to/from an exception type table. | 
 | (function TestTableExnRef() { | 
 |   print(arguments.callee.name); | 
 |   let kSig_e_i = makeSig([kWasmI32], [kWasmExnRef]); | 
 |   let kSig_v_ie = makeSig([kWasmI32, kWasmExnRef], []); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let table = builder.addTable(kWasmExnRef, 2).exportAs("table"); | 
 |   builder.addFunction("table_load", kSig_e_i) | 
 |       .addBody([ | 
 |         kExprLocalGet, 0, | 
 |         kExprTableGet, table.index | 
 |       ]).exportFunc(); | 
 |   builder.addFunction("table_store", kSig_v_ie) | 
 |       .addBody([ | 
 |         kExprLocalGet, 0, | 
 |         kExprLocalGet, 1, | 
 |         kExprTableSet, table.index | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |   let e0 = new Error("my encapsulated error"); | 
 |   let e1 = new Error("my other encapsulated error"); | 
 |  | 
 |   assertNull(instance.exports.table_load(0)); | 
 |   assertNull(instance.exports.table_load(1)); | 
 |   assertNull(instance.exports.table.get(0)); | 
 |   assertNull(instance.exports.table.get(1)); | 
 |  | 
 |   instance.exports.table_store(0, e0); | 
 |   assertSame(e0, instance.exports.table_load(0)); | 
 |   assertNull(instance.exports.table_load(1)); | 
 |   assertSame(e0, instance.exports.table.get(0)); | 
 |   assertNull(instance.exports.table.get(1)); | 
 |  | 
 |   instance.exports.table.set(1, e1); | 
 |   assertSame(e0, instance.exports.table_load(0)); | 
 |   assertSame(e1, instance.exports.table_load(1)); | 
 |   assertSame(e0, instance.exports.table.get(0)); | 
 |   assertSame(e1, instance.exports.table.get(1)); | 
 | })(); | 
 |  | 
 | // 'br_on_exn' on a null-ref value should trap. | 
 | (function TestBrOnExnNullSimple() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_r); | 
 |   builder.addFunction('br_on_exn_null', kSig_v_v) | 
 |       .addBody([ | 
 |         kExprRefNull, kWasmExnRef, | 
 |         kExprBrOnExn, 0, except, | 
 |         kExprDrop | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |  | 
 |   assertTraps(kTrapBrOnExnNull, () => instance.exports.br_on_exn_null()); | 
 | })(); | 
 |  | 
 | (function TestBrOnExnNullFromJS() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_i); | 
 |   let imp = builder.addImport('imp', 'ort', kSig_i_i); | 
 |   let kConstant0 = 11; | 
 |   let kNoMatch = 13; | 
 |   builder.addFunction('call_import', kSig_i_i) | 
 |       .addBody([ | 
 |         kExprTry, kWasmI32, | 
 |           kExprLocalGet, 0, | 
 |           kExprCallFunction, imp, | 
 |         kExprCatch, | 
 |           kExprBrOnExn, 0, except, | 
 |           kExprDrop, | 
 |           kExprI32Const, kNoMatch, | 
 |         kExprEnd | 
 |       ]).exportFunc(); | 
 |   let instance; | 
 |   function js_import(i) { | 
 |     if (i == 0) return kConstant0;     // Will return kConstant0. | 
 |     if (i == 1) throw new Error('1');  // Will not match. | 
 |     if (i == 2) throw null;            // Will trap. | 
 |     throw undefined;                   // Will not match. | 
 |   } | 
 |   instance = builder.instantiate({imp: {ort: js_import}}); | 
 |  | 
 |   assertEquals(kConstant0, instance.exports.call_import(0)); | 
 |   assertEquals(kNoMatch, instance.exports.call_import(1)); | 
 |   assertTraps(kTrapBrOnExnNull, () => instance.exports.call_import(2)); | 
 |   assertEquals(kNoMatch, instance.exports.call_import(3)); | 
 | })(); | 
 |  | 
 | // 'rethrow' on a null-ref value should trap. | 
 | (function TestRethrowNullSimple() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_r); | 
 |   builder.addFunction('rethrow_null', kSig_v_v) | 
 |       .addBody([ | 
 |         kExprRefNull, kWasmExnRef, | 
 |         kExprRethrow | 
 |       ]).exportFunc(); | 
 |   let instance = builder.instantiate(); | 
 |  | 
 |   assertTraps(kTrapRethrowNull, () => instance.exports.rethrow_null()); | 
 | })(); | 
 |  | 
 | (function TestRethrowNullFromJS() { | 
 |   print(arguments.callee.name); | 
 |   let builder = new WasmModuleBuilder(); | 
 |   let except = builder.addException(kSig_v_i); | 
 |   let imp = builder.addImport('imp', 'ort', kSig_i_i); | 
 |   let kSuccess = 11; | 
 |   builder.addFunction('call_import', kSig_i_i) | 
 |       .addBody([ | 
 |         kExprTry, kWasmI32, | 
 |           kExprLocalGet, 0, | 
 |           kExprCallFunction, imp, | 
 |         kExprCatch, | 
 |           kExprRethrow, | 
 |         kExprEnd | 
 |       ]).exportFunc(); | 
 |   let instance; | 
 |   function js_import(i) { | 
 |     if (i == 0) return kSuccess;       // Will return kSuccess. | 
 |     if (i == 1) throw new Error('1');  // Will rethrow. | 
 |     if (i == 2) throw null;            // Will trap. | 
 |     throw undefined;                   // Will rethrow. | 
 |   } | 
 |   instance = builder.instantiate({imp: {ort: js_import}}); | 
 |  | 
 |   assertEquals(kSuccess, instance.exports.call_import(0)); | 
 |   assertThrows(() => instance.exports.call_import(1), Error, '1'); | 
 |   assertTraps(kTrapRethrowNull, () => instance.exports.call_import(2)); | 
 |   assertThrowsEquals(() => instance.exports.call_import(3), undefined); | 
 | })(); |