Skip to content

Commit 1bf8e0f

Browse files
authored
Update JS API to handle index types (WebAssembly#75)
This introduces an IndexValue typedef, which is a union of Number and BigInt, and two algorithms, IndexValueToU64 and U64ToIndexValue, which can be used to convert between IndexValue and WebAssembly's u64 type (used in the embedding spec). It also makes several drive-by fixes and improvements.
1 parent 5a8c4db commit 1bf8e0f

File tree

1 file changed

+86
-46
lines changed

1 file changed

+86
-46
lines changed

Diff for: document/js-api/index.bs

+86-46
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
4747
text: SetFunctionLength; url: sec-setfunctionlength
4848
text: the Number value; url: sec-ecmascript-language-types-number-type
4949
text: is a Number; url: sec-ecmascript-language-types-number-type
50+
text: is a BigInt; url: sec-ecmascript-language-types-bigint-type
5051
text: NumberToRawBytes; url: sec-numbertorawbytes
5152
text: Built-in Function Objects; url: sec-built-in-function-objects
5253
text: NativeError Object Structure; url: sec-nativeerror-object-structure
@@ -61,6 +62,7 @@ urlPrefix: https://tc39.github.io/ecma262/; spec: ECMASCRIPT
6162
text: NativeError Object Structure; url: sec-nativeerror-object-structure
6263
text: 𝔽; url: #𝔽
6364
text: ℤ; url: #ℤ
65+
text: mathematical value; url: #mathematical-value
6466
text: SameValue; url: sec-samevalue
6567
urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: dfn
6668
url: valid/modules.html#valid-module
@@ -121,6 +123,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
121123
text: match_valtype; url: appendix/embedding.html#embed-match-valtype
122124
text: error; url: appendix/embedding.html#embed-error
123125
text: store; url: exec/runtime.html#syntax-store
126+
text: index type; url: syntax/types.html#syntax-idxtype
124127
text: table type; url: syntax/types.html#syntax-tabletype
125128
text: table address; url: exec/runtime.html#syntax-tableaddr
126129
text: function address; url: exec/runtime.html#syntax-funcaddr
@@ -139,6 +142,9 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
139142
text: exn_alloc; url: appendix/embedding.html#embed-exn-alloc
140143
text: exn_tag; url: appendix/embedding.html#embed-exn-tag
141144
text: exn_read; url: appendix/embedding.html#embed-exn-read
145+
url: syntax/values.html#syntax-int
146+
text: u32
147+
text: u64
142148
url: syntax/types.html#syntax-numtype
143149
text: i32
144150
text: i64
@@ -200,6 +206,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
200206
urlPrefix: https://heycam.github.io/webidl/; spec: WebIDL
201207
type: dfn
202208
text: create a namespace object; url: create-a-namespace-object
209+
text: [EnforceRange]; url: #EnforceRange
203210
urlPrefix: https://webassembly.github.io/js-types/js-api/; spec: WebAssembly JS API (JS Type Reflection)
204211
type: abstract-op; text: FromValueType; url: abstract-opdef-fromvaluetype
205212
urlPrefix: https://tc39.es/proposal-resizablearraybuffer/; spec: ResizableArrayBuffer proposal
@@ -561,6 +568,8 @@ enum IndexType {
561568
"i64",
562569
};
563570

571+
typedef ([EnforceRange] unsigned long long or bigint) IndexValue;
572+
564573
dictionary ModuleExportDescriptor {
565574
required USVString name;
566575
required ImportExportKind kind;
@@ -665,15 +674,15 @@ Note: The use of this synchronous API is discouraged, as some implementations so
665674

666675
<pre class="idl">
667676
dictionary MemoryDescriptor {
668-
required [EnforceRange] unsigned long long initial;
669-
[EnforceRange] unsigned long long maximum;
677+
required IndexValue initial;
678+
IndexValue maximum;
670679
IndexType index;
671680
};
672681

673682
[LegacyNamespace=WebAssembly, Exposed=*]
674683
interface Memory {
675684
constructor(MemoryDescriptor descriptor);
676-
unsigned long grow([EnforceRange] unsigned long long delta);
685+
unsigned long grow(IndexValue delta);
677686
ArrayBuffer toFixedLengthBuffer();
678687
ArrayBuffer toResizableBuffer();
679688
readonly attribute ArrayBuffer buffer;
@@ -736,11 +745,11 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
736745

737746
<div algorithm>
738747
The <dfn constructor for="Memory">Memory(|descriptor|)</dfn> constructor, when invoked, performs the following steps:
739-
1. Let |initial| be |descriptor|["initial"].
740-
1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty.
748+
1. If |descriptor|["index"] [=map/exists=], let |indextype| be |descriptor|["index"]; otherwise, let |indextype| be "i32".
749+
1. Let |initial| be [=?=] [=IndexValueToU64=](|descriptor|["initial"], |indextype|).
750+
1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be [=?=] [=IndexValueToU64=](|descriptor|["maximum"], |indextype|); otherwise, let |maximum| be empty.
741751
1. If |maximum| is not empty and |maximum| &lt; |initial|, throw a {{RangeError}} exception.
742-
1. If |descriptior|["index"] [=map/exists=], let |index| be |descriptor|["index"]; otherwise, let |index| be "i32".
743-
1. Let |memtype| be { min |initial|, max |maximum|, index |index| }.
752+
1. Let |memtype| be |indextype| { **min** |initial|, **max** |maximum| }.
744753
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
745754
1. Let (|store|, |memaddr|) be [=mem_alloc=](|store|, |memtype|). If allocation fails, throw a {{RangeError}} exception.
746755
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
@@ -779,7 +788,10 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
779788
<div algorithm=dom-Memory-grow>
780789
The <dfn method for="Memory">grow(|delta|)</dfn> method, when invoked, performs the following steps:
781790
1. Let |memaddr| be **this**.\[[Memory]].
782-
1. Return the result of [=grow the memory buffer|growing the memory buffer=] associated with |memaddr| by |delta|.
791+
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
792+
1. Let |indextype| be the [=index type=] in [=mem_type=](|store|, |memaddr|).
793+
1. Let |delta64| be [=?=] [=IndexValueToU64=](|delta|, |indextype|).
794+
1. Return the result of [=grow the memory buffer|growing the memory buffer=] associated with |memaddr| by |delta64|.
783795
</div>
784796

785797
Immediately after a WebAssembly [=memory.grow=] instruction executes, perform the following steps:
@@ -857,18 +869,18 @@ enum TableKind {
857869

858870
dictionary TableDescriptor {
859871
required TableKind element;
860-
required [EnforceRange] unsigned long long initial;
861-
[EnforceRange] unsigned long long maximum;
872+
required IndexValue initial;
873+
IndexValue maximum;
862874
IndexType index;
863875
};
864876

865877
[LegacyNamespace=WebAssembly, Exposed=*]
866878
interface Table {
867879
constructor(TableDescriptor descriptor, optional any value);
868-
unsigned long long grow([EnforceRange] unsigned long long delta, optional any value);
869-
any get([EnforceRange] unsigned long long index);
870-
undefined set([EnforceRange] unsigned long long index, optional any value);
871-
readonly attribute unsigned long length;
880+
IndexValue grow(IndexValue delta, optional any value);
881+
any get(IndexValue index);
882+
undefined set(IndexValue index, optional any value);
883+
readonly attribute IndexValue length;
872884
};
873885
</pre>
874886

@@ -896,19 +908,19 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
896908

897909
<div algorithm>
898910
The <dfn constructor for="Table">Table(|descriptor|, |value|)</dfn> constructor, when invoked, performs the following steps:
899-
1. Let |elementType| be [=ToValueType=](|descriptor|["element"]).
900-
1. If |elementType| is not a [=reftype=],
901-
1. Throw a {{TypeError}} exception.
902-
1. Let |initial| be |descriptor|["initial"].
903-
1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be |descriptor|["maximum"]; otherwise, let |maximum| be empty.
911+
1. Let |elementtype| be [=ToValueType=](|descriptor|["element"]).
912+
1. If |elementtype| is not a [=reftype=],
913+
1. [=Throw=] a {{TypeError}} exception.
914+
1. If |descriptor|["index"] [=map/exists=], let |indextype| be |descriptor|["index"]; otherwise, let |indextype| be "i32".
915+
1. Let |initial| be [=?=] [=IndexValueToU64=](|descriptor|["initial"], |indextype|).
916+
1. If |descriptor|["maximum"] [=map/exists=], let |maximum| be [=?=] [=IndexValueToU64=](|descriptor|["maximum"], |indextype|); otherwise, let |maximum| be empty.
904917
1. If |maximum| is not empty and |maximum| &lt; |initial|, throw a {{RangeError}} exception.
905918
1. If |value| is missing,
906-
1. Let |ref| be [=DefaultValue=](|elementType|).
919+
1. Let |ref| be [=DefaultValue=](|elementtype|).
907920
1. Assert: |ref| is not [=error=].
908921
1. Otherwise,
909-
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|).
910-
1. If |descriptior|["index"] [=map/exists=], let |index| be |descriptor|["index"]; otherwise, let |index| be "i32".
911-
1. Let |type| be the [=table type=] [=table type|index=] |index| {[=table type|min=] |initial|, [=table type|max=] |maximum|} [=table type|refType=] |elementType|.
922+
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementtype|).
923+
1. Let |type| be the [=table type=] (|indextype|, { **min** |initial|, **max** |maximum| }, |elementtype|).
912924
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
913925
1. Let (|store|, |tableaddr|) be [=table_alloc=](|store|, |type|, |ref|). <!-- TODO(littledan): Report allocation failure https://github.com/WebAssembly/spec/issues/584 -->
914926
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
@@ -920,13 +932,14 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
920932
1. Let |tableaddr| be **this**.\[[Table]].
921933
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
922934
1. Let |initialSize| be [=table_size=](|store|, |tableaddr|).
923-
1. Let (<var ignore>limits</var>, |elementType|) be [=table_type=](|tableaddr|).
935+
1. Let (|indextype|, <var ignore>limits</var>, |elementtype|) be [=table_type=](|store|, |tableaddr|).
936+
1. Let |delta64| be [=?=] [=IndexValueToU64=](|delta|, |indextype|).
924937
1. If |value| is missing,
925-
1. Let |ref| be [=DefaultValue=](|elementType|).
938+
1. Let |ref| be [=DefaultValue=](|elementtype|).
926939
1. If |ref| is [=error=], throw a {{TypeError}} exception.
927940
1. Otherwise,
928-
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|).
929-
1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta|, |ref|).
941+
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementtype|).
942+
1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta64|, |ref|).
930943
1. If |result| is [=error=], throw a {{RangeError}} exception.
931944

932945
Note: The above exception can happen due to either insufficient memory or an invalid size parameter.
@@ -939,17 +952,20 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
939952
The getter of the <dfn attribute for="Table">length</dfn> attribute of {{Table}}, when invoked, performs the following steps:
940953
1. Let |tableaddr| be **this**.\[[Table]].
941954
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
942-
1. Return [=table_size=](|store|, |tableaddr|).
955+
1. Let |indextype| be the [=index type=] in [=table_type=](|store|, |tableaddr|).
956+
1. Let |length64| be [=table_size=](|store|, |tableaddr|).
957+
1. Return [=U64ToIndexValue=](|length64|, |indextype|).
943958
</div>
944959

945960
<div algorithm>
946961
The <dfn method for="Table">get(|index|)</dfn> method, when invoked, performs the following steps:
947962
1. Let |tableaddr| be **this**.\[[Table]].
948963
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
949-
1. Let (<var ignore>limits</var>, |elementType|) be [=table_type=](|store|, |tableaddr|).
950-
1. If |elementType| is [=exnref=],
964+
1. Let (|indextype|, <var ignore>limits</var>, |elementtype|) be [=table_type=](|store|, |tableaddr|).
965+
1. If |elementtype| is [=exnref=],
951966
1. Throw a {{TypeError}} exception.
952-
1. Let |result| be [=table_read=](|store|, |tableaddr|, |index|).
967+
1. Let |index64| be [=?=] [=IndexValueToU64=](|index|, |indextype|).
968+
1. Let |result| be [=table_read=](|store|, |tableaddr|, |index64|).
953969
1. If |result| is [=error=], throw a {{RangeError}} exception.
954970
1. Return [=ToJSValue=](|result|).
955971
</div>
@@ -958,16 +974,16 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
958974
The <dfn method for="Table">set(|index|, |value|)</dfn> method, when invoked, performs the following steps:
959975
1. Let |tableaddr| be **this**.\[[Table]].
960976
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
961-
1. Let (<var ignore>limits</var>, |elementType|) be [=table_type=](|store|, |tableaddr|).
962-
1. If |elementType| is [=exnref=],
977+
1. Let (|indextype|, <var ignore>limits</var>, |elementtype|) be [=table_type=](|store|, |tableaddr|).
978+
1. If |elementtype| is [=exnref=],
963979
1. Throw a {{TypeError}} exception.
980+
1. Let |index64| be [=?=] [=IndexValueToU64=](|index|, |indextype|).
964981
1. If |value| is missing,
965-
1. Let |ref| be [=DefaultValue=](|elementType|).
982+
1. Let |ref| be [=DefaultValue=](|elementtype|).
966983
1. If |ref| is [=error=], throw a {{TypeError}} exception.
967984
1. Otherwise,
968-
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|).
969-
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
970-
1. Let |store| be [=table_write=](|store|, |tableaddr|, |index|, |ref|).
985+
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementtype|).
986+
1. Let |store| be [=table_write=](|store|, |tableaddr|, |index64|, |ref|).
971987
1. If |store| is [=error=], throw a {{RangeError}} exception.
972988
1. Set the [=surrounding agent=]'s [=associated store=] to |store|.
973989
</div>
@@ -1236,18 +1252,18 @@ The algorithm <dfn>ToJSValue</dfn>(|w|) coerces a [=WebAssembly value=] to a Jav
12361252
1. Assert: |w| is not of the form [=ref.exn=] <var ignore>exnaddr</var>.
12371253
1. If |w| is of the form [=i64.const=] |u64|,
12381254
1. Let |i64| be [=signed_64=](|u64|).
1239-
1. Return [=ℤ=](|i64| interpreted as a mathematical value).
1240-
1. If |w| is of the form [=i32.const=] |i32|,
1241-
1. Let |i32| be [=signed_32=](|i32|).
1242-
2. Return [=𝔽=](|i32| interpreted as a mathematical value).
1255+
1. Return [=ℤ=](|i64| interpreted as a [=mathematical value=]).
1256+
1. If |w| is of the form [=i32.const=] |u32|,
1257+
1. Let |i32| be [=signed_32=](|u32|).
1258+
2. Return [=𝔽=](|i32| interpreted as a [=mathematical value=]).
12431259
1. If |w| is of the form [=f32.const=] |f32|,
12441260
1. If |f32| is [=+∞=] or [=−∞=], return **+∞**<sub>𝔽</sub> or **-∞**<sub>𝔽</sub>, respectively.
12451261
1. If |f32| is [=nan=], return **NaN**.
1246-
1. Return [=𝔽=](|f32| interpreted as a mathematical value).
1262+
1. Return [=𝔽=](|f32| interpreted as a [=mathematical value=]).
12471263
1. If |w| is of the form [=f64.const=] |f64|,
12481264
1. If |f64| is [=+∞=] or [=−∞=], return **+∞**<sub>𝔽</sub> or **-∞**<sub>𝔽</sub>, respectively.
12491265
1. If |f64| is [=nan=], return **NaN**.
1250-
1. Return [=𝔽=](|f64| interpreted as a mathematical value).
1266+
1. Return [=𝔽=](|f64| interpreted as a [=mathematical value=]).
12511267
1. If |w| is of the form [=ref.null=] <var ignore>t</var>, return null.
12521268
1. If |w| is of the form [=ref.i31=] |u31|,
12531269
1. Let |i31| be [=signed_31=](|u31|).
@@ -1288,15 +1304,15 @@ The algorithm <dfn>ToWebAssemblyValue</dfn>(|v|, |type|) coerces a JavaScript va
12881304
1. If |type| is [=f32=],
12891305
1. Let |number| be [=?=] [$ToNumber$](|v|).
12901306
1. If |number| is **NaN**,
1291-
1. Let |n| be an implementation-defined integer such that [=canon=]<sub>32</sub> |n| < 2<sup>[=signif=](32)</sup>.
1307+
1. Let |n| be an implementation-defined integer such that [=canon=]<sub>32</sub> &leq; |n| &lt; 2<sup>[=signif=](32)</sup>.
12921308
1. Let |f32| be [=nan=](n).
12931309
1. Otherwise,
12941310
1. Let |f32| be |number| rounded to the nearest representable value using IEEE 754-2008 round to nearest, ties to even mode. [[IEEE-754]]
12951311
1. Return [=f32.const=] |f32|.
12961312
1. If |type| is [=f64=],
12971313
1. Let |number| be [=?=] [$ToNumber$](|v|).
12981314
1. If |number| is **NaN**,
1299-
1. Let |n| be an implementation-defined integer such that [=canon=]<sub>64</sub> |n| < 2<sup>[=signif=](64)</sup>.
1315+
1. Let |n| be an implementation-defined integer such that [=canon=]<sub>64</sub> &leq; |n| &lt; 2<sup>[=signif=](64)</sup>.
13001316
1. Let |f64| be [=nan=](n).
13011317
1. Otherwise,
13021318
1. Let |f64| be |number|.
@@ -1337,6 +1353,31 @@ The algorithm <dfn>ToWebAssemblyValue</dfn>(|v|, |type|) coerces a JavaScript va
13371353

13381354
</div>
13391355

1356+
<div algorithm>
1357+
The algorithm <dfn>IndexValueToU64</dfn>(|v|, |indextype|) asserts that a JavaScript value is the appropriate variant of {{IndexValue}} for an {{IndexType}}, and ensures that its value is in [=u64=] range for WebAssembly embedding operations, by performing the following steps:
1358+
1359+
1. If |indextype| is "i32",
1360+
1. If |v| [=is a Number=],
1361+
1. Assert: Due to WebIDL types and [=[EnforceRange]=], 0 ≤ [=ℝ=](|v|) < 2<sup>64</sup>.
1362+
1. Return [=ℝ=](|v|) as a WebAssembly [=u64=].
1363+
1. Otherwise, [=throw=] a {{TypeError}}.
1364+
1. Else if |indextype| is "i64",
1365+
1. If |v| [=is a BigInt=],
1366+
1. If |v| is not equal to [=!=] [$ToBigUint64$](|v|), [=throw=] a {{RangeError}}.
1367+
1. Return [=ℝ=](|v|) as a WebAssembly [=u64=].
1368+
1. Otherwise, [=throw=] a {{TypeError}}.
1369+
1. Assert: This step is not reached.
1370+
1371+
</div>
1372+
1373+
<div algorithm>
1374+
The algorithm <dfn>U64ToIndexValue</dfn>(|v|, |indextype|) converts a [=u64=] value from a WebAssembly embedding operation to the correct variant of {{IndexValue}} for an {{IndexType}}, by performing the following steps:
1375+
1376+
1. If |indextype| is "i32", return [=𝔽=](|v| interpreted as a [=mathematical value=]).
1377+
1. Else if |indextype| is "i64", return [=ℤ=](|v| interpreted as a [=mathematical value=]).
1378+
1. Assert: This step is not reached.
1379+
1380+
</div>
13401381

13411382
<h3 id="tags">Tags</h3>
13421383

@@ -1369,7 +1410,6 @@ To <dfn>initialize a Tag object</dfn> |tag| from a [=tag address=] |tagAddress|,
13691410
</div>
13701411

13711412
<div algorithm>
1372-
13731413
To <dfn>create a Tag object</dfn> from a [=tag address=] |tagAddress|, perform the following steps:
13741414

13751415
1. Let |map| be the [=surrounding agent=]'s associated [=Tag object cache=].

0 commit comments

Comments
 (0)