Skip to content

Commit

Permalink
Merge pull request #522 from takikawa/default_value
Browse files Browse the repository at this point in the history
[js-api][test] Refine DefaultValue for new reference types
  • Loading branch information
rossberg committed Feb 16, 2024
2 parents 2361fee + d5a49d2 commit 322e948
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 12 deletions.
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

0 comments on commit 322e948

Please sign in to comment.