diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index bb12a12621..9800ae5fa1 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -89,6 +89,8 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
text: CreateArrayFromList; url: sec-createarrayfromlist
text: GetMethod; url: sec-getmethod
text: IterableToList; url: sec-iterabletolist
+ text: ToBigInt64; url: #sec-tobigint64
+ text: BigInt; url: #sec-ecmascript-language-types-bigint-type
type: abstract-op
text: CreateMethodProperty; url: sec-createmethodproperty
urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn
@@ -172,6 +174,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
text: current frame; url: exec/conventions.html#exec-notation-textual
text: module; for: frame; url: exec/runtime.html#syntax-frame
text: memaddrs; for: moduleinst; url: exec/runtime.html#syntax-moduleinst
+ text: signed_64; url: exec/numerics.html#aux-signed
text: sequence; url: syntax/conventions.html#grammar-notation
urlPrefix: https://heycam.github.io/webidl/; spec: WebIDL
type: dfn
@@ -348,8 +351,11 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
1. Let |externfunc| be the [=external value=] [=external value|func=] |funcaddr|.
1. [=list/Append=] |externfunc| to |imports|.
1. If |externtype| is of the form [=global=] mut |valtype|,
- 1. If [=Type=](|v|) is Number,
- 1. If |valtype| is [=i64=], throw a {{LinkError}} exception.
+ 1. If [=Type=](|v|) is Number or BigInt,
+ 1. If |valtype| is [=i64=] and [=Type=](|v|) is Number,
+ 1. Throw a {{LinkError}} exception.
+ 1. If |valtype| is not [=i64=] and [=Type=](|v|) is BigInt,
+ 1. Throw a {{LinkError}} exception.
1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|).
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|).
@@ -871,7 +877,6 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
1. If |v| is undefined,
1. Let |value| be [=DefaultValue=](|valuetype|).
1. Otherwise,
- 1. If |valuetype| is [=i64=], throw a {{TypeError}} exception.
1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|).
1. If |mutable| is true, let |globaltype| be [=var=] |valuetype|; otherwise, let |globaltype| be [=const=] |valuetype|.
1. Let |store| be the current agent's [=associated store=].
@@ -884,8 +889,6 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
The algorithm GetGlobalValue({{Global}} |global|) performs the following steps:
1. Let |store| be the current agent's [=associated store=].
1. Let |globaladdr| be |global|.\[[Global]].
- 1. Let |globaltype| be [=global_type=](|store|, |globaladdr|).
- 1. If |globaltype| is of the form mut [=i64=], throw a {{TypeError}}.
1. Let |value| be [=global_read=](|store|, |globaladdr|).
1. Return [=ToJSValue=](|value|).
@@ -899,7 +902,6 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
1. Let |globaladdr| be **this**.\[[Global]].
1. Let |mut| |valuetype| be [=global_type=](|store|, |globaladdr|).
1. If |mut| is [=const=], throw a {{TypeError}}.
- 1. If |valuetype| is [=i64=], throw a {{TypeError}}.
1. Let |value| be [=ToWebAssemblyValue=](**the given value**, |valuetype|).
1. Let |store| be [=global_write=](|store|, |globaladdr|, |value|).
1. If |store| is [=error=], throw a {{RangeError}} exception.
@@ -958,11 +960,7 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
1. Let |functype| be [=func_type=](|store|, |funcaddr|).
- 1. Let [|parameters|] → [|results|] be |functype|.
- 1. If |parameters| or |results| contains an [=i64=], throw a {{TypeError}}.
-
- Note: the above error is thrown each time the \[[Call]] method is invoked.
-
+ 1. Let [|parameters|] → [results] be |functype|.
1. Let |args| be an empty [=list=] of WebAssembly values.
1. Let |i| be 0.
1. [=list/iterate|For each=] |t| of |parameters|,
@@ -990,8 +988,7 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
To
run a host function from the JavaScript object |func|, type |functype|, and [=list=] of [=WebAssembly values=] |arguments|, perform the following steps:
- 1. Let [|parameters|] → [|results|] be |functype|.
- 1. If either |parameters| or |results| contains [=i64=], throw a {{TypeError}}.
+ 1. Let [
parameters] → [|results|] be |functype|.
1. Let |jsArguments| be an empty [=list=].
1. [=list/iterate|For each=] |arg| of |arguments|,
1. [=list/Append=] ! [=ToJSValue=](|arg|) to |jsArguments|.
@@ -1028,7 +1025,9 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
The algorithm ToJSValue(|w|) coerces a [=WebAssembly value=] to a JavaScript value by performing the following steps:
-1. Assert: |w| is not of the form [=i64.const=] i64.
+1. If |w| is of the form [=i64.const=] |i64|,
+ 1. Let |v| be [=signed_64=](|i64|).
+ 1. Return a [=BigInt=] representing the mathematical value |v|.
1. If |w| is of the form [=i32.const=] |i32|, return [=the Number value=] for [=signed_32=](|i32|).
1. If |w| is of the form [=f32.const=] |f32|, return [=the Number value=] for |f32|.
1. If |w| is of the form [=f64.const=] |f64|, return [=the Number value=] for |f64|.
@@ -1042,7 +1041,9 @@ Note: Number values which are equal to NaN may have various observable NaN paylo
The algorithm ToWebAssemblyValue(|v|, |type|) coerce a JavaScript value to a [=WebAssembly value=] performs the following steps:
-1. Assert: |type| is not [=i64=].
+1. If |type| is [=i64=],
+ 1. Let |i64| be ? [=ToBigInt64=](|v|).
+ 1. Return [=i64.const=] |i64|.
1. If |type| is [=i32=],
1. Let |i32| be ? [=ToInt32=](|v|).
1. Return [=i32.const=] |i32|.
diff --git a/test/js-api/bad-imports.js b/test/js-api/bad-imports.js
index afd41936d3..786fc650e3 100644
--- a/test/js-api/bad-imports.js
+++ b/test/js-api/bad-imports.js
@@ -11,6 +11,16 @@
* (if any) yields the correct error.
*/
function test_bad_imports(t) {
+ function value_type(type) {
+ switch (type) {
+ case "i32": return kWasmI32;
+ case "i64": return kWasmI64;
+ case "f32": return kWasmF32;
+ case "f64": return kWasmF64;
+ default: throw new TypeError(`Unexpected type ${type}`);
+ }
+ }
+
for (const value of [null, true, "", Symbol(), 1, 0.1, NaN]) {
t(`Non-object imports argument: ${format_value(value)}`,
TypeError,
@@ -45,17 +55,6 @@ function test_bad_imports(t) {
value);
}
- t(`Importing an i64 global`,
- WebAssembly.LinkError,
- builder => {
- builder.addImportedGlobal("module", "global", kWasmI64);
- },
- {
- "module": {
- "global": 0,
- },
- });
-
for (const value of [undefined, null, true, "", Symbol(), 1, 0.1, NaN, {}]) {
t(`Importing a function with an incorrectly-typed value: ${format_value(value)}`,
WebAssembly.LinkError,
@@ -79,20 +78,51 @@ function test_bad_imports(t) {
[WebAssembly.Global, "WebAssembly.Global"],
[WebAssembly.Global.prototype, "WebAssembly.Global.prototype"],
[Object.create(WebAssembly.Global.prototype), "Object.create(WebAssembly.Global.prototype)"],
- [new WebAssembly.Global({value: "f32"}), "WebAssembly.Global object (wrong value type)"],
];
- for (const [value, name = format_value(value)] of nonGlobals) {
- t(`Importing a global with an incorrectly-typed value: ${name}`,
+ for (const type of ["i32", "i64", "f32", "f64"]) {
+ const extendedNonGlobals = nonGlobals.concat([
+ type === "i64" ? [0, "Number"] : [0n, "BigInt"],
+ [new WebAssembly.Global({value: type === "f32" ? "f64" : "f32"}), "WebAssembly.Global object (wrong value type)"],
+ ]);
+ for (const [value, name = format_value(value)] of extendedNonGlobals) {
+ t(`Importing an ${type} global with an incorrectly-typed value: ${name}`,
+ WebAssembly.LinkError,
+ builder => {
+ builder.addImportedGlobal("module", "global", value_type(type));
+ },
+ {
+ "module": {
+ "global": value,
+ },
+ });
+ }
+ }
+
+ for (const type of ["i32", "i64", "f32", "f64"]) {
+ const value = type === "i64" ? 0n : 0;
+ t(`Importing an ${type} mutable global with a primitive value`,
WebAssembly.LinkError,
builder => {
- builder.addImportedGlobal("module", "global", kWasmI32);
+ builder.addImportedGlobal("module", "global", value_type(type), true);
},
{
"module": {
"global": value,
},
});
+
+ const global = new WebAssembly.Global({ "value": type }, value);
+ t(`Importing an ${type} mutable global with an immutable Global object`,
+ WebAssembly.LinkError,
+ builder => {
+ builder.addImportedGlobal("module", "global", value_type(type), true);
+ },
+ {
+ "module": {
+ "global": global,
+ },
+ });
}
const nonMemories = [
diff --git a/test/js-api/global/constructor.any.js b/test/js-api/global/constructor.any.js
index b008ef3016..f536f5d7b5 100644
--- a/test/js-api/global/constructor.any.js
+++ b/test/js-api/global/constructor.any.js
@@ -90,8 +90,7 @@ test(() => {
test(() => {
const argument = { "value": "i64" };
const global = new WebAssembly.Global(argument);
- assert_throws_js(TypeError, () => global.value);
- assert_throws_js(TypeError, () => global.valueOf());
+ assert_Global(global, 0n);
}, "i64 with default");
for (const type of ["i32", "f32", "f64"]) {
@@ -108,8 +107,10 @@ for (const type of ["i32", "f32", "f64"]) {
[false, 0],
[2, 2],
["3", 3],
- [{ toString() { return "5" } }, 5, "object with toString"],
- [{ valueOf() { return "8" } }, 8, "object with valueOf"],
+ [{ toString() { return "5" } }, 5, "object with toString returning string"],
+ [{ valueOf() { return "8" } }, 8, "object with valueOf returning string"],
+ [{ toString() { return 6 } }, 6, "object with toString returning number"],
+ [{ valueOf() { return 9 } }, 9, "object with valueOf returning number"],
];
for (const [value, expected, name = format_value(value)] of valueArguments) {
test(() => {
@@ -118,6 +119,44 @@ for (const type of ["i32", "f32", "f64"]) {
assert_Global(global, expected);
}, `Explicit value ${name} for type ${type}`);
}
+
+ test(() => {
+ const argument = { "value": type };
+ assert_throws_js(TypeError, () => new WebAssembly.Global(argument, 0n));
+ }, `BigInt value for type ${type}`);
+}
+
+const valueArguments = [
+ [undefined, 0n],
+ [true, 1n],
+ [false, 0n],
+ ["3", 3n],
+ [123n, 123n],
+ [{ toString() { return "5" } }, 5n, "object with toString returning string"],
+ [{ valueOf() { return "8" } }, 8n, "object with valueOf returning string"],
+ [{ toString() { return 6n } }, 6n, "object with toString returning bigint"],
+ [{ valueOf() { return 9n } }, 9n, "object with valueOf returning bigint"],
+];
+for (const [value, expected, name = format_value(value)] of valueArguments) {
+ test(() => {
+ const argument = { "value": "i64" };
+ const global = new WebAssembly.Global(argument, value);
+ assert_Global(global, expected);
+ }, `Explicit value ${name} for type i64`);
+}
+
+const invalidBigints = [
+ null,
+ 666,
+ { toString() { return 5 } },
+ { valueOf() { return 8 } },
+ Symbol(),
+];
+for (const invalidBigint of invalidBigints) {
+ test(() => {
+ var argument = { "value": "i64" };
+ assert_throws_js(TypeError, () => new WebAssembly.Global(argument, invalidBigint));
+ }, `Pass non-bigint as i64 Global value: ${format_value(invalidBigint)}`);
}
test(() => {
diff --git a/test/js-api/global/value-get-set.any.js b/test/js-api/global/value-get-set.any.js
index 43d8474a25..f95b7ca9e3 100644
--- a/test/js-api/global/value-get-set.any.js
+++ b/test/js-api/global/value-get-set.any.js
@@ -28,7 +28,8 @@ test(() => {
}
}, "Branding");
-for (const type of ["i32", "f32", "f64"]) {
+for (const type of ["i32", "i64", "f32", "f64"]) {
+ const [initial, value, invalid] = type === "i64" ? [0n, 1n, 2] : [0, 1, 2n];
const immutableOptions = [
[{}, "missing"],
[{ "mutable": undefined }, "undefined"],
@@ -41,20 +42,20 @@ for (const type of ["i32", "f32", "f64"]) {
test(() => {
opts.value = type;
const global = new WebAssembly.Global(opts);
- assert_equals(global.value, 0, "initial value");
- assert_equals(global.valueOf(), 0, "initial valueOf");
+ assert_equals(global.value, initial, "initial value");
+ assert_equals(global.valueOf(), initial, "initial valueOf");
- assert_throws_js(TypeError, () => global.value = 1);
+ assert_throws_js(TypeError, () => global.value = value);
- assert_equals(global.value, 0, "post-set value");
- assert_equals(global.valueOf(), 0, "post-set valueOf");
+ assert_equals(global.value, initial, "post-set value");
+ assert_equals(global.valueOf(), initial, "post-set valueOf");
}, `Immutable ${type} (${name})`);
test(t => {
opts.value = type;
const global = new WebAssembly.Global(opts);
- assert_equals(global.value, 0, "initial value");
- assert_equals(global.valueOf(), 0, "initial valueOf");
+ assert_equals(global.value, initial, "initial value");
+ assert_equals(global.valueOf(), initial, "initial valueOf");
const value = {
valueOf: t.unreached_func("should not call valueOf"),
@@ -62,8 +63,8 @@ for (const type of ["i32", "f32", "f64"]) {
};
assert_throws_js(TypeError, () => global.value = value);
- assert_equals(global.value, 0, "post-set value");
- assert_equals(global.valueOf(), 0, "post-set valueOf");
+ assert_equals(global.value, initial, "post-set value");
+ assert_equals(global.valueOf(), initial, "post-set valueOf");
}, `Immutable ${type} with ToNumber side-effects (${name})`);
}
@@ -77,13 +78,15 @@ for (const type of ["i32", "f32", "f64"]) {
test(() => {
opts.value = type;
const global = new WebAssembly.Global(opts);
- assert_equals(global.value, 0, "initial value");
- assert_equals(global.valueOf(), 0, "initial valueOf");
+ assert_equals(global.value, initial, "initial value");
+ assert_equals(global.valueOf(), initial, "initial valueOf");
+
+ global.value = value;
- global.value = 1;
+ assert_throws_js(TypeError, () => global.value = invalid);
- assert_equals(global.value, 1, "post-set value");
- assert_equals(global.valueOf(), 1, "post-set valueOf");
+ assert_equals(global.value, value, "post-set value");
+ assert_equals(global.valueOf(), value, "post-set valueOf");
}, `Mutable ${type} (${name})`);
}
}
@@ -91,20 +94,33 @@ for (const type of ["i32", "f32", "f64"]) {
test(() => {
const argument = { "value": "i64", "mutable": true };
const global = new WebAssembly.Global(argument);
- assert_throws_js(TypeError, () => global.value);
- assert_throws_js(TypeError, () => global.value = 0);
- assert_throws_js(TypeError, () => global.valueOf());
-}, "i64 with default");
-test(t => {
- const argument = { "value": "i64", "mutable": true };
- const global = new WebAssembly.Global(argument);
- const value = {
- valueOf: t.unreached_func("should not call valueOf"),
- toString: t.unreached_func("should not call toString"),
- };
- assert_throws_js(TypeError, () => global.value = value);
-}, "i64 with ToNumber side-effects");
+ assert_equals(global.value, 0n, "initial value using ToJSValue");
+
+ const valid = [
+ [123n, 123n],
+ [2n ** 63n, - (2n ** 63n)],
+ [true, 1n],
+ [false, 0n],
+ ["456", 456n],
+ ];
+ for (const [input, output] of valid) {
+ global.value = input;
+ assert_equals(global.valueOf(), output, "post-set valueOf");
+ }
+
+ const invalid = [
+ undefined,
+ null,
+ 0,
+ 1,
+ 4.2,
+ Symbol(),
+ ];
+ for (const input of invalid) {
+ assert_throws_js(TypeError, () => global.value = input);
+ }
+}, "i64 mutability");
test(() => {
const argument = { "value": "i32", "mutable": true };
diff --git a/test/js-api/instanceTestFactory.js b/test/js-api/instanceTestFactory.js
index c81672f208..86f593f46f 100644
--- a/test/js-api/instanceTestFactory.js
+++ b/test/js-api/instanceTestFactory.js
@@ -210,6 +210,415 @@ const instanceTestFactory = [
}
],
+ [
+ "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() {