| const instanceTestFactory = [ | |
| [ | |
| "Empty module without imports argument", | |
| function() { | |
| return { | |
| buffer: emptyModuleBinary, | |
| args: [], | |
| exports: {}, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "Empty module with undefined imports argument", | |
| function() { | |
| return { | |
| buffer: emptyModuleBinary, | |
| args: [undefined], | |
| exports: {}, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "Empty module with empty imports argument", | |
| function() { | |
| return { | |
| buffer: emptyModuleBinary, | |
| args: [{}], | |
| exports: {}, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "getter order for imports object", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder.addImportedGlobal("module", "global1", kWasmI32); | |
| builder.addImportedGlobal("module2", "global3", kWasmI32); | |
| builder.addImportedMemory("module", "memory", 0, 128); | |
| builder.addImportedGlobal("module", "global2", kWasmI32); | |
| const buffer = builder.toBuffer(); | |
| const order = []; | |
| const imports = { | |
| get module() { | |
| order.push("module getter"); | |
| return { | |
| get global1() { | |
| order.push("global1 getter"); | |
| return 0; | |
| }, | |
| get global2() { | |
| order.push("global2 getter"); | |
| return 0; | |
| }, | |
| get memory() { | |
| order.push("memory getter"); | |
| return new WebAssembly.Memory({ "initial": 64, maximum: 128 }); | |
| }, | |
| } | |
| }, | |
| get module2() { | |
| order.push("module2 getter"); | |
| return { | |
| get global3() { | |
| order.push("global3 getter"); | |
| return 0; | |
| }, | |
| } | |
| }, | |
| }; | |
| const expected = [ | |
| "module getter", | |
| "global1 getter", | |
| "module2 getter", | |
| "global3 getter", | |
| "module getter", | |
| "memory getter", | |
| "module getter", | |
| "global2 getter", | |
| ]; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: {}, | |
| verify: () => assert_array_equals(order, expected), | |
| }; | |
| } | |
| ], | |
| [ | |
| "imports", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder.addImport("module", "fn", kSig_v_v); | |
| builder.addImportedGlobal("module", "global", kWasmI32); | |
| builder.addImportedMemory("module", "memory", 0, 128); | |
| builder.addImportedTable("module", "table", 0, 128); | |
| const buffer = builder.toBuffer(); | |
| const imports = { | |
| "module": { | |
| "fn": function() {}, | |
| "global": 0, | |
| "memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }), | |
| "table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }), | |
| }, | |
| get "module2"() { | |
| assert_unreached("Should not get modules that are not imported"); | |
| }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: {}, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "imports with empty module names", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder.addImport("", "fn", kSig_v_v); | |
| builder.addImportedGlobal("", "global", kWasmI32); | |
| builder.addImportedMemory("", "memory", 0, 128); | |
| builder.addImportedTable("", "table", 0, 128); | |
| const buffer = builder.toBuffer(); | |
| const imports = { | |
| "": { | |
| "fn": function() {}, | |
| "global": 0, | |
| "memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }), | |
| "table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }), | |
| }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: {}, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "imports with empty names", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder.addImport("a", "", kSig_v_v); | |
| builder.addImportedGlobal("b", "", kWasmI32); | |
| builder.addImportedMemory("c", "", 0, 128); | |
| builder.addImportedTable("d", "", 0, 128); | |
| const buffer = builder.toBuffer(); | |
| const imports = { | |
| "a": { "": function() {} }, | |
| "b": { "": 0 }, | |
| "c": { "": new WebAssembly.Memory({ "initial": 64, maximum: 128 }) }, | |
| "d": { "": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }) }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: {}, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "exports with empty name: function", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder | |
| .addFunction("", kSig_v_d) | |
| .addBody([]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| const exports = { | |
| "": { "kind": "function", "name": "0", "length": 1 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [], | |
| exports, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "exports with empty name: table", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder.setTableBounds(1); | |
| builder.addExportOfKind("", kExternalTable, 0); | |
| const buffer = builder.toBuffer(); | |
| const exports = { | |
| "": { "kind": "table", "length": 1 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [], | |
| exports, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "exports with empty name: global", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder.addGlobal(kWasmI32, true) | |
| .exportAs("") | |
| .init = wasmI32Const(7); | |
| const buffer = builder.toBuffer(); | |
| const exports = { | |
| "": { "kind": "global", "value": 7 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [], | |
| exports, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "No imports", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| builder | |
| .addFunction("fn", kSig_v_d) | |
| .addBody([]) | |
| .exportFunc(); | |
| builder | |
| .addFunction("fn2", kSig_v_v) | |
| .addBody([]) | |
| .exportFunc(); | |
| builder.setTableBounds(1); | |
| builder.addExportOfKind("table", kExternalTable, 0); | |
| builder.addGlobal(kWasmI32, true) | |
| .exportAs("global") | |
| .init = wasmI32Const(7); | |
| builder.addGlobal(kWasmF64, true) | |
| .exportAs("global2") | |
| .init = wasmF64Const(1.2); | |
| builder.addMemory(4, 8, true); | |
| const buffer = builder.toBuffer(); | |
| const exports = { | |
| "fn": { "kind": "function", "name": "0", "length": 1 }, | |
| "fn2": { "kind": "function", "name": "1", "length": 0 }, | |
| "table": { "kind": "table", "length": 1 }, | |
| "global": { "kind": "global", "value": 7 }, | |
| "global2": { "kind": "global", "value": 1.2 }, | |
| "memory": { "kind": "memory", "size": 4 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [], | |
| exports, | |
| verify: () => {}, | |
| }; | |
| } | |
| ], | |
| [ | |
| "exports and imports", | |
| function() { | |
| const value = 102; | |
| const builder = new WasmModuleBuilder(); | |
| const index = builder.addImportedGlobal("module", "global", kWasmI32); | |
| builder | |
| .addFunction("fn", kSig_i_v) | |
| .addBody([ | |
| kExprGlobalGet, | |
| index, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| const imports = { | |
| "module": { | |
| "global": value, | |
| }, | |
| }; | |
| const exports = { | |
| "fn": { "kind": "function", "name": "0", "length": 0 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports, | |
| verify: instance => assert_equals(instance.exports.fn(), value) | |
| }; | |
| } | |
| ], | |
| [ | |
| "i64 exports and imports", | |
| function() { | |
| const value = 102n; | |
| const builder = new WasmModuleBuilder(); | |
| const index = builder.addImportedGlobal("module", "global", kWasmI64); | |
| builder | |
| .addFunction("fn", kSig_l_v) | |
| .addBody([ | |
| kExprGlobalGet, | |
| index, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const index2 = builder.addImportedGlobal("module", "global2", kWasmI64); | |
| builder.addExportOfKind("global", kExternalGlobal, index2); | |
| const buffer = builder.toBuffer(); | |
| const imports = { | |
| "module": { | |
| "global": value, | |
| "global2": 2n ** 63n, | |
| }, | |
| }; | |
| const exports = { | |
| "fn": { "kind": "function", "name": "0", "length": 0 }, | |
| "global": { "kind": "global", "value": -(2n ** 63n) }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports, | |
| verify: instance => assert_equals(instance.exports.fn(), value) | |
| }; | |
| } | |
| ], | |
| [ | |
| "import with i32-returning function", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fnIndex = builder.addImport("module", "fn", kSig_i_v); | |
| const fn2 = builder | |
| .addFunction("fn2", kSig_v_v) | |
| .addBody([ | |
| kExprCallFunction, | |
| fnIndex, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| let called = false; | |
| const imports = { | |
| "module": { | |
| "fn": function() { | |
| called = true; | |
| return 6n; | |
| }, | |
| }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: { | |
| "fn2": { "kind": "function", "name": String(fn2.index), "length": 0 }, | |
| }, | |
| verify: instance => { | |
| assert_throws_js(TypeError, () => instance.exports.fn2()); | |
| assert_true(called, "Should have called into JS"); | |
| } | |
| }; | |
| } | |
| ], | |
| [ | |
| "import with function that takes and returns i32", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fnIndex = builder.addImport("module", "fn", kSig_i_i); | |
| const fn2 = builder | |
| .addFunction("fn2", kSig_i_v) | |
| .addBody([ | |
| kExprI32Const, 0x66, | |
| kExprCallFunction, | |
| fnIndex, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| let called = false; | |
| const imports = { | |
| "module": { | |
| "fn": function(n) { | |
| called = true; | |
| assert_equals(n, -26); | |
| return { valueOf() { return 6; } }; | |
| }, | |
| }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: { | |
| "fn2": { "kind": "function", "name": String(fn2.index), "length": 0 }, | |
| }, | |
| verify: instance => { | |
| assert_equals(instance.exports.fn2(), 6); | |
| assert_true(called, "Should have called into JS"); | |
| } | |
| }; | |
| } | |
| ], | |
| [ | |
| "import with i64-returning function", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fnIndex = builder.addImport("module", "fn", kSig_l_v); | |
| const fn2 = builder | |
| .addFunction("fn2", kSig_v_v) | |
| .addBody([ | |
| kExprCallFunction, | |
| fnIndex, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| let called = false; | |
| const imports = { | |
| "module": { | |
| "fn": function() { | |
| called = true; | |
| return 6; | |
| }, | |
| }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: { | |
| "fn2": { "kind": "function", "name": String(fn2.index), "length": 0 }, | |
| }, | |
| verify: instance => { | |
| assert_throws_js(TypeError, () => instance.exports.fn2()); | |
| assert_true(called, "Should have called into JS"); | |
| } | |
| }; | |
| } | |
| ], | |
| [ | |
| "import with function that takes and returns i64", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fnIndex = builder.addImport("module", "fn", kSig_l_l); | |
| const fn2 = builder | |
| .addFunction("fn2", kSig_l_v) | |
| .addBody([ | |
| kExprI64Const, 0x66, | |
| kExprCallFunction, | |
| fnIndex, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| let called = false; | |
| const imports = { | |
| "module": { | |
| "fn": function(n) { | |
| called = true; | |
| assert_equals(n, -26n); | |
| return { valueOf() { return 6n; } }; | |
| }, | |
| }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports: { | |
| "fn2": { "kind": "function", "name": String(fn2.index), "length": 0 }, | |
| }, | |
| verify: instance => { | |
| assert_equals(instance.exports.fn2(), 6n); | |
| assert_true(called, "Should have called into JS"); | |
| } | |
| }; | |
| } | |
| ], | |
| [ | |
| "import with i32-taking function", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fn = builder | |
| .addFunction("fn", kSig_v_i) | |
| .addBody([ | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| return { | |
| buffer, | |
| args: [], | |
| exports: { | |
| "fn": { "kind": "function", "name": String(fn.index), "length": 1 }, | |
| }, | |
| verify: instance => assert_throws_js(TypeError, () => instance.exports.fn(6n)) | |
| }; | |
| } | |
| ], | |
| [ | |
| "import with i64-taking function", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fn = builder | |
| .addFunction("fn", kSig_v_l) | |
| .addBody([ | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| return { | |
| buffer, | |
| args: [], | |
| exports: { | |
| "fn": { "kind": "function", "name": String(fn.index), "length": 1 }, | |
| }, | |
| verify: instance => assert_throws_js(TypeError, () => instance.exports.fn(6)) | |
| }; | |
| } | |
| ], | |
| [ | |
| "export i64-returning function", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fn = builder | |
| .addFunction("fn", kSig_l_v) | |
| .addBody([ | |
| kExprI64Const, 0x66, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| return { | |
| buffer, | |
| args: [], | |
| exports: { | |
| "fn": { "kind": "function", "name": String(fn.index), "length": 0 }, | |
| }, | |
| verify: instance => assert_equals(instance.exports.fn(), -26n) | |
| }; | |
| } | |
| ], | |
| [ | |
| "i32 mutable WebAssembly.Global import", | |
| function() { | |
| const initial = 102; | |
| const value = new WebAssembly.Global({ "value": "i32", "mutable": true }, initial); | |
| const builder = new WasmModuleBuilder(); | |
| const index = builder.addImportedGlobal("module", "global", kWasmI32, true); | |
| const fn = builder | |
| .addFunction("fn", kSig_i_v) | |
| .addBody([ | |
| kExprGlobalGet, | |
| index, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| const imports = { | |
| "module": { | |
| "global": value, | |
| }, | |
| }; | |
| const exports = { | |
| "fn": { "kind": "function", "name": String(fn.index), "length": 0 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports, | |
| verify: instance => { | |
| assert_equals(instance.exports.fn(), initial); | |
| const after = 201; | |
| value.value = after; | |
| assert_equals(instance.exports.fn(), after); | |
| } | |
| }; | |
| } | |
| ], | |
| [ | |
| "i64 mutable WebAssembly.Global import", | |
| function() { | |
| const initial = 102n; | |
| const value = new WebAssembly.Global({ "value": "i64", "mutable": true }, initial); | |
| const builder = new WasmModuleBuilder(); | |
| const index = builder.addImportedGlobal("module", "global", kWasmI64, true); | |
| const fn = builder | |
| .addFunction("fn", kSig_l_v) | |
| .addBody([ | |
| kExprGlobalGet, | |
| index, | |
| kExprReturn, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| const imports = { | |
| "module": { | |
| "global": value, | |
| }, | |
| }; | |
| const exports = { | |
| "fn": { "kind": "function", "name": String(fn.index), "length": 0 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [imports], | |
| exports, | |
| verify: instance => { | |
| assert_equals(instance.exports.fn(), initial); | |
| const after = 201n; | |
| value.value = after; | |
| assert_equals(instance.exports.fn(), after); | |
| } | |
| }; | |
| } | |
| ], | |
| [ | |
| "Multiple i64 arguments", | |
| function() { | |
| const builder = new WasmModuleBuilder(); | |
| const fn = builder | |
| .addFunction("fn", kSig_l_ll) | |
| .addBody([ | |
| kExprLocalGet, 1, | |
| ]) | |
| .exportFunc(); | |
| const buffer = builder.toBuffer(); | |
| const exports = { | |
| "fn": { "kind": "function", "name": String(fn.index), "length": 2 }, | |
| }; | |
| return { | |
| buffer, | |
| args: [], | |
| exports, | |
| verify: instance => { | |
| const fn = instance.exports.fn; | |
| assert_equals(fn(1n, 0n), 0n); | |
| assert_equals(fn(1n, 123n), 123n); | |
| assert_equals(fn(1n, -123n), -123n); | |
| assert_equals(fn(1n, "5"), 5n); | |
| assert_throws_js(TypeError, () => fn(1n, 5)); | |
| } | |
| }; | |
| } | |
| ], | |
| [ | |
| "stray argument", | |
| function() { | |
| return { | |
| buffer: emptyModuleBinary, | |
| args: [{}, {}], | |
| exports: {}, | |
| verify: () => {} | |
| }; | |
| } | |
| ], | |
| ]; |