| 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 = 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 = 7; |
| builder.addGlobal(kWasmF64, true) |
| .exportAs("global2") |
| .init = 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: () => {} |
| }; |
| } |
| ], |
| ]; |