Skip to content

Commit 1f9637b

Browse files
committed
[spec] Normative: Add i64<->BigInt conversion in JS API
With this patch, BigInts have support for bidirectionally converting to 64-bit integer WebAssembly values, which appears as - Parameters and return values to exported WebAssembly functions - Parameters and return values to host functions - Imported and exported globals BigInts can be read or written from WebAssembly memory using the BigInt proposal's BigInt64Array or BigUint64Array; no additional support is needed. This patch includes basic conformance tests in jsapi.js, which tests that the conversion is done properly in the six cases listed above. I don't know of any Wasm implementation that attempts to implement this specification, so I converted most of the test to be against i32 and saw that converted version pass on V8 (this process helped work out a few silly test bugs). Closes WebAssembly/design#1172
1 parent 8a0c449 commit 1f9637b

File tree

2 files changed

+72
-12
lines changed

2 files changed

+72
-12
lines changed

document/js-api/index.bs

+19-12
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ Prepare For TR: true
2020
"title": "WebAssembly Specification",
2121
"publisher": "W3C WebAssembly Community Group",
2222
"status": "Draft"
23+
},
24+
"BIGINT": {
25+
"href": "https://tc39.github.io/proposal-bigint/",
26+
"title": "BigInt Specification",
27+
"publisher": "TC39",
28+
"status": "Stage 3 proposal"
2329
}
2430
}
2531
</pre>
@@ -154,6 +160,10 @@ urlPrefix: https://webassembly.github.io/spec/core/multipage/; spec: WebAssembly
154160
text: 𝗀𝗅𝗈𝖻𝖺𝗅
155161
text: global type; url: syntax/types.html#syntax-globaltype
156162
text: address; url: exec/runtime.html#addresses
163+
text: signed_64; url: exec/numerics.html#aux-signed
164+
urlPrefix: https://tc39.github.io/proposal-bigint/; spec: BIGINT; type: dfn
165+
text: ToBigInt64; url: #sec-to-big-int64
166+
text: BigInt; url: #sec-ecmascript-language-types-bigint-type
157167
</pre>
158168

159169
<pre class='link-defaults'>
@@ -333,7 +343,6 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
333343
1. Let |externfunc| be the [=external value=] [=external value|𝖿𝗎𝗇𝖼=] |funcaddr|.
334344
1. [=Append=] |externfunc| to |imports|.
335345
1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] |globaltype|,
336-
1. If |globaltype| is [=𝗂𝟨𝟦=] or [=Type=](|v|) is not [=Number=], throw a {{LinkError}} exception.
337346
1. Let |value| be [=ToWebAssemblyValue=](|v|, |globaltype|.<em>[=global type|valtype=]</em>)
338347
1. Assert: |globaltype|.<em>[=global type|mut=]</em> is [=global type|𝖼𝗈𝗇𝗌𝗍=], as verified by WebAssembly validation.
339348
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
@@ -371,7 +380,6 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje
371380
1. Let |func| be the result of creating [=a new Exported Function=] from |funcaddr|.
372381
1. Let |value| be |func|.
373382
1. If |externtype| is of the form [=𝗀𝗅𝗈𝖻𝖺𝗅=] |globaltype|,
374-
1. If |globaltype|.<em>[=global type|valtype=]</em>) is [=𝗂𝟨𝟦=], throw a {{LinkError}} exception.
375383
1. Assert: |globaltype|.<em>[=global type|mut=]</em> is [=global type|𝖼𝗈𝗇𝗌𝗍=], as verified by WebAssembly validation.
376384
1. Assert: |externval| is of the form [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr|.
377385
1. Let [=external value|𝗀𝗅𝗈𝖻𝖺𝗅=] |globaladdr| be |externval|.
@@ -741,10 +749,6 @@ This slot holds a [=function address=] relative to the [=surrounding agent=]'s [
741749
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
742750
1. Let |functype| be [=type_func=](|store|, |funcaddr|).
743751
1. Let [|parameters|][|results|] be |functype|.
744-
1. If |parameters| or |results| contains an [=𝗂𝟨𝟦=], throw a {{TypeError}}.
745-
746-
Note: the above error is thrown each time the \[[Call]] method is invoked.
747-
748752
5. Let |args| be an empty list of WebAssembly values.
749753
1. Let |i| be 0.
750754
1. For each type |t| of |parameters|,
@@ -767,7 +771,6 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
767771
To <dfn>create a host function</dfn> from the JavaScript object |func|, perform the following steps:
768772

769773
1. Let |hostfunc| be a [=host function=] which performs the following steps when called:
770-
1. If the signature contains an [=𝗂𝟨𝟦=] (as argument or result), the host function throws a {{TypeError}} when called.
771774
1. Let |arguments| be a [=list=] of the arguments of the invocation of this function.
772775
1. Let |jsArguments| be an empty [=list=].
773776
1. For each |arg| in |arguments|,
@@ -785,10 +788,12 @@ Note: Exported Functions do not have a \[[Construct]] method and thus it is not
785788
<div algorithm>
786789
The algorithm <dfn>ToJSValue</dfn>(|w|) coerces a [=WebAssembly value=] to a JavaScript value performs the following steps:
787790

788-
Assert: |w| is not of the form [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |i64|.
789-
1. If |w| is of the form [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|, return [=the Number value=] for |i32|.
790-
1. If |w| is of the form [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |f32|, return [=the Number value=] for |f32|.
791-
1. If |w| is of the form [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|, return [=the Number value=] for |f64|.
791+
1. If |w| is of the form [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |i64|,
792+
1. Let |v| be [=signed_64=](|i64|).
793+
1. Return a [=BigInt=] representing the mathematical value |v|.
794+
1. If |w| is of the form [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|, return [=the Number value=] of |i32|.
795+
1. If |w| is of the form [=𝖿𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |f32|, return [=the Number value=] of |f32|.
796+
1. If |w| is of the form [=𝖿𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |f64|, return [=the Number value=] of |f64|.
792797

793798
<!-- If the WebAssembly value is optional, then given `None`, return JavaScript value `undefined`. -->
794799

@@ -799,7 +804,9 @@ Note: Implementations may optionally replace the NaN payload with any other NaN
799804
The algorithm <dfn>ToWebAssemblyValue</dfn>(|v|, |type|) coerce a JavaScript value to a [=WebAssembly value=] performs the following steps:
800805

801806

802-
Assert: |type| is not [=𝗂𝟨𝟦=].
807+
1. If |type| is [=𝗂𝟨𝟦=],
808+
1. Let |i64| be [=ToBigInt64=](|v|).
809+
1. Return [=𝗂𝟨𝟦.𝖼𝗈𝗇𝗌𝗍=] |i64|.
803810
1. If |type| is [=𝗂𝟥𝟤=],
804811
1. Let |i32| be ? [=ToInt32=](|v|).
805812
1. Return [=𝗂𝟥𝟤.𝖼𝗈𝗇𝗌𝗍=] |i32|.

test/js-api/jsapi.js

+53
Original file line numberDiff line numberDiff line change
@@ -881,4 +881,57 @@ test(() => {
881881
assert_equals(table.get(2)(), 46);
882882
}, "Tables export cached");
883883

884+
const exportingModuleLongIdentityFn = (() => {
885+
let builder = new WasmModuleBuilder();
886+
887+
builder
888+
.addFunction('id', kSig_l_l)
889+
.addBody([ kExprGetLocal, 0 ])
890+
.exportFunc();
891+
892+
return builder.toBuffer();
893+
})();
894+
895+
test(() => {
896+
let module = new WebAssembly.Module(exportingModuleLongIdentityFn);
897+
let instance = new WebAssembly.Instance(module);
898+
899+
let value = 2n ** 63n;
900+
let output = instance.exports.id(value);
901+
assert_equals(output, - (2n ** 63n));
902+
assertThrows(() => instance.exports.id(5), TypeError);
903+
assert_equals(instance.exports.id("5"), 5n);
904+
}, "WebAssembly longs are converted to JavaScript as if by ToBigInt64 in exported functions");
905+
906+
const exportingModuleImportingLongFn = (() => {
907+
let builder = new WasmModuleBuilder();
908+
909+
let fnIndex = builder.addImport('mod', 'fn', kSig_l_l);
910+
let globalIndex = builder.addImportedGlobal('mod', 'gl', kWasmI64);
911+
912+
builder.addExport('fn', fnIndex)
913+
builder.addExportOfKind('gl', kExternalGlobal, globalIndex)
914+
915+
return builder.toBuffer();
916+
})();
917+
918+
test(() => {
919+
let module = new WebAssembly.Module(exportingModuleImportingLongFn);
920+
let input;
921+
let instance = new WebAssembly.Instance(module, {
922+
mod: {
923+
fn(arg) {
924+
input = arg;
925+
return 2n ** 63n;
926+
},
927+
gl: 2n ** 63n,
928+
}
929+
});
930+
931+
let output = instance.exports.fn(2n ** 63n);
932+
assert_equals(input, - (2n ** 63n));
933+
assert_equals(output, - (2n ** 63n));
934+
assert_equals(instance.exports.gl, - (2n ** 63n));
935+
}, "WebAssembly longs are converted to JavaScript as if by ToBigInt64 in host functions");
936+
884937
})();

0 commit comments

Comments
 (0)