Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[js-api][test] Refine DefaultValue for new reference types #522

Merged
merged 4 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions document/core/appendix/embedding.rst
Original file line number Diff line number Diff line change
Expand Up @@ -630,11 +630,12 @@ Globals
\end{array}


.. index:: reference, reference type
.. index:: reference, reference type, value type, value
.. _embed-ref-type:
.. _embed-val-default:

References
~~~~~~~~~~
Values
~~~~~~

:math:`\F{ref\_type}(\store, \reff) : \reftype`
...............................................
Expand All @@ -656,6 +657,20 @@ References
In such cases, this function may return a less precise supertype.


:math:`\F{val\_default}(\valtype) : \val`
...............................................

1. If :math:`\default_{valtype}` is not defined, then return :math:`\ERROR`.

1. Else, return the :ref:`value <syntax-val>` :math:`\default_{valtype}`.

.. math::
\begin{array}{lclll}
\F{val\_default}(t) &=& v && (\iff \default_t = v) \\
\F{val\_default}(t) &=& \ERROR && (\iff \default_t = \epsilon) \\
\end{array}


.. index:: value type, external type, subtyping
.. _embed-match-valtype:
.. _embed-match-externtype:
Expand Down
12 changes: 6 additions & 6 deletions document/js-api/index.bs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df
text: global_read; url: appendix/embedding.html#embed-global-read
text: global_write; url: appendix/embedding.html#embed-global-write
text: ref_type; url: appendix/embedding.html#embed-ref-type
text: val_default; url: appendix/embedding.html#embed-val-default
text: match_valtype; url: appendix/embedding.html#embed-match-valtype
text: error; url: appendix/embedding.html#embed-error
text: store; url: exec/runtime.html#syntax-store
Expand Down Expand Up @@ -764,6 +765,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
1. If |maximum| is not empty and |maximum| &lt; |initial|, throw a {{RangeError}} exception.
1. If |value| is missing,
1. Let |ref| be [=DefaultValue=](|elementType|).
1. Assert: |ref| is not [=error=].
1. Otherwise,
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|).
1. Let |type| be the [=table type=] {[=table type|min=] |initial|, [=table type|max=] |maximum|} |elementType|.
Expand All @@ -781,6 +783,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
1. Let (<var ignore>limits</var>, |elementType|) be [=table_type=](|tableaddr|).
1. If |value| is missing,
1. Let |ref| be [=DefaultValue=](|elementType|).
1. If |ref| is [=error=], throw a {{TypeError}} exception.
1. Otherwise,
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|).
1. Let |result| be [=table_grow=](|store|, |tableaddr|, |delta|, |ref|).
Expand Down Expand Up @@ -814,6 +817,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
1. Let (<var ignore>limits</var>, |elementType|) be [=table_type=](|tableaddr|).
1. If |value| is missing,
1. Let |ref| be [=DefaultValue=](|elementType|).
1. If |ref| is [=error=], throw a {{TypeError}} exception.
1. Otherwise,
1. Let |ref| be [=?=] [=ToWebAssemblyValue=](|value|, |elementType|).
1. Let |store| be the [=surrounding agent=]'s [=associated store=].
Expand Down Expand Up @@ -890,13 +894,8 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each

<div algorithm>
The algorithm <dfn>DefaultValue</dfn>(|valuetype|) performs the following steps:
1. If |valuetype| equals [=i32=], return [=i32.const=] 0.
1. If |valuetype| equals [=i64=], return [=i64.const=] 0.
1. If |valuetype| equals [=f32=], return [=f32.const=] 0.
1. If |valuetype| equals [=f64=], return [=f64.const=] 0.
1. If |valuetype| equals [=funcref=], return [=ref.null=] [=funcref=].
1. If |valuetype| equals [=externref=], return [=ToWebAssemblyValue=](undefined, |valuetype|).
1. Assert: This step is not reached.
1. Return [=val_default=](|valuetype|).
</div>

<div algorithm>
Expand All @@ -907,6 +906,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
1. Throw a {{TypeError}} exception.
1. If |v| is missing,
1. Let |value| be [=DefaultValue=](|valuetype|).
1. Assert: |value| is not [=error=].
1. Otherwise,
1. Let |value| be [=ToWebAssemblyValue=](|v|, |valuetype|).
1. If |mutable| is true, let |globaltype| be [=var=] |valuetype|; otherwise, let |globaltype| be [=const=] |valuetype|.
Expand Down
43 changes: 43 additions & 0 deletions test/js-api/gc/default-value.tentative.any.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// META: global=window,dedicatedworker,jsshell
// META: script=/wasm/jsapi/wasm-module-builder.js

let exports = {};
setup(() => {
const builder = new WasmModuleBuilder();

builder.addTable(wasmRefType(kWasmAnyRef), 10, 20, [...wasmI32Const(42), ...GCInstr(kExprRefI31)])
.exportAs("tableAnyNonNullable");
builder.addTable(wasmRefNullType(kWasmAnyRef), 10, 20)
.exportAs("tableAnyNullable");

const buffer = builder.toBuffer();
const module = new WebAssembly.Module(buffer);
const instance = new WebAssembly.Instance(module, {});
exports = instance.exports;
});

test(() => {
exports.tableAnyNullable.grow(5);
for (let i = 0; i < 5; i++)
assert_equals(exports.tableAnyNullable.get(10 + i), null);
}, "grow (nullable anyref)");

test(() => {
assert_throws_js(TypeError, () => { exports.tableAnyNonNullable.grow(5); });
exports.tableAnyNonNullable.grow(5, "foo");
for (let i = 0; i < 5; i++)
assert_equals(exports.tableAnyNonNullable.get(10 + i), "foo");
}, "grow (non-nullable anyref)");

test(() => {
for (let i = 0; i < exports.tableAnyNullable.length; i++) {
exports.tableAnyNullable.set(i);
assert_equals(exports.tableAnyNullable.get(i), null);
}
}, "set (nullable anyref)");

test(() => {
for (let i = 0; i < exports.tableAnyNonNullable.length; i++) {
assert_throws_js(TypeError, () => { exports.tableAnyNonNullable.set(i); });
}
}, "set (non-nullable anyref)");
4 changes: 2 additions & 2 deletions test/js-api/gc/i31.tentative.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ setup(() => {
builder
.addFunction("makeI31", makeSig_r_x(i31Ref, kWasmI32))
.addBody([kExprLocalGet, 0,
...GCInstr(kExprI31New)])
...GCInstr(kExprRefI31)])
.exportFunc();

builder
Expand All @@ -33,7 +33,7 @@ setup(() => {
.exportFunc();

builder
.addGlobal(i31NullableRef, true, [...wasmI32Const(0), ...GCInstr(kExprI31New)])
.addGlobal(i31NullableRef, true, [...wasmI32Const(0), ...GCInstr(kExprRefI31)])
builder
.addExportOfKind("i31Global", kExternalGlobal, 0);

Expand Down
6 changes: 5 additions & 1 deletion test/js-api/wasm-module-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ let kExprBrOnCast = 0x18;
let kExprBrOnCastFail = 0x19;
let kExprExternInternalize = 0x1a;
let kExprExternExternalize = 0x1b;
let kExprI31New = 0x1c;
let kExprRefI31 = 0x1c;
let kExprI31GetS = 0x1d;
let kExprI31GetU = 0x1e;

Expand Down Expand Up @@ -1199,6 +1199,10 @@ class WasmModuleBuilder {
binary.emit_section(kTableSectionCode, section => {
section.emit_u32v(wasm.tables.length);
for (let table of wasm.tables) {
if (table.has_init) {
section.emit_u8(0x40); // "has initializer"
section.emit_u8(0x00); // Reserved byte.
}
section.emit_type(table.type);
section.emit_u8(table.has_max);
section.emit_u32v(table.initial_size);
Expand Down
Loading