From 663c8d532329e280916da789a28583bf93b2c71f Mon Sep 17 00:00:00 2001 From: Asumu Takikawa Date: Wed, 14 Feb 2024 11:59:12 -0800 Subject: [PATCH 01/29] [js-api][test] Refine DefaultValue for new reference types DefaultValue will return undefined for externref as before, but for other nullable reference types will return null. For non-nullable reference types, operations like grow and set should error if the value to set is missing. Also adds WPT tests for the error cases. This requires some updates to wasm-module-builder.js as well. Fixes issue #501 --- document/core/appendix/embedding.rst | 20 +++++++++ document/js-api/index.bs | 12 +++--- test/js-api/gc/default-value.tentative.any.js | 43 +++++++++++++++++++ test/js-api/gc/i31.tentative.any.js | 4 +- test/js-api/wasm-module-builder.js | 6 ++- 5 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 test/js-api/gc/default-value.tentative.any.js diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index c0a19791de..e7d60a1a44 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -693,3 +693,23 @@ Matching \F{match\_externtype}(\X{et}_1, \X{et}_2) &=& \TRUE && (\iff \vdashexterntypematch \X{et}_1 \matchesexterntype \X{et}_2) \\ \F{match\_externtype}(\X{et}_1, \X{et}_2) &=& \FALSE && (\otherwise) \\ \end{array} + + +.. index:: value type +.. _embed-default-value: + +Value types +~~~~~~~~~~~ + +:math:`\F{default\_value}(\type) : \val` +............................................... + +1. If :math:`\default_{type}` is not defined, then return :math:`\ERROR`. + +1. Else, return the :ref:`value ` :math:`\default_{type}`. + +.. math:: + \begin{array}{lclll} + \F{default\_value}(t) &=& v && (\iff \default_t = v) \\ + \F{default\_value}(t) &=& \ERROR && (\iff \default_t = \epsilon) \\ + \end{array} diff --git a/document/js-api/index.bs b/document/js-api/index.bs index d7657d9fe0..9df91d001c 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -116,6 +116,7 @@ urlPrefix: https://webassembly.github.io/spec/core/; spec: WebAssembly; type: df text: global_write; url: appendix/embedding.html#embed-global-write text: ref_type; url: appendix/embedding.html#embed-ref-type text: match_valtype; url: appendix/embedding.html#embed-match-valtype + text: default_value; url: appendix/embedding.html#embed-default-value text: error; url: appendix/embedding.html#embed-error text: store; url: exec/runtime.html#syntax-store text: table type; url: syntax/types.html#syntax-tabletype @@ -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| < |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|. @@ -781,6 +783,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address 1. Let (limits, |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|). @@ -814,6 +817,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address 1. Let (limits, |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=]. @@ -890,13 +894,8 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
The algorithm DefaultValue(|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 [=default_value=](|valuetype|).
@@ -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|. diff --git a/test/js-api/gc/default-value.tentative.any.js b/test/js-api/gc/default-value.tentative.any.js new file mode 100644 index 0000000000..d828b4d87f --- /dev/null +++ b/test/js-api/gc/default-value.tentative.any.js @@ -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)"); diff --git a/test/js-api/gc/i31.tentative.any.js b/test/js-api/gc/i31.tentative.any.js index 17fd82440c..d8cfe424e8 100644 --- a/test/js-api/gc/i31.tentative.any.js +++ b/test/js-api/gc/i31.tentative.any.js @@ -11,7 +11,7 @@ setup(() => { builder .addFunction("makeI31", makeSig_r_x(i31Ref, kWasmI32)) .addBody([kExprLocalGet, 0, - ...GCInstr(kExprI31New)]) + ...GCInstr(kExprRefI31)]) .exportFunc(); builder @@ -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); diff --git a/test/js-api/wasm-module-builder.js b/test/js-api/wasm-module-builder.js index 8c6519239b..104c730c7c 100644 --- a/test/js-api/wasm-module-builder.js +++ b/test/js-api/wasm-module-builder.js @@ -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; @@ -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); From d9302a8892886857f9f012656522bfacf4f8ec1c Mon Sep 17 00:00:00 2001 From: Asumu Takikawa Date: Wed, 14 Feb 2024 17:45:49 -0800 Subject: [PATCH 02/29] [spec] Throw consistent exns in "read the imports" Instead of allowing ToWebAssemblyValue to throw a TypeError, explicitly catch any exceptions and throw a WebAssembly.LinkError. --- document/js-api/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index d7657d9fe0..41df72d75d 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -370,7 +370,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 1. Throw a {{LinkError}} exception. 1. If |valtype| is [=v128=], 1. Throw a {{LinkError}} exception. - 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). If this operation throws an exception, catch it, and throw a {{LinkError}} exception. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. From e1b39d5b9c077dbf97539c98d8b0882141184add Mon Sep 17 00:00:00 2001 From: Asumu Takikawa Date: Wed, 14 Feb 2024 17:45:49 -0800 Subject: [PATCH 03/29] [js-api] Throw consistent exns in "read the imports" Instead of allowing ToWebAssemblyValue to throw a TypeError, explicitly catch any exceptions and throw a WebAssembly.LinkError. --- document/js-api/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index d7657d9fe0..41df72d75d 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -370,7 +370,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 1. Throw a {{LinkError}} exception. 1. If |valtype| is [=v128=], 1. Throw a {{LinkError}} exception. - 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). If this operation throws an exception, catch it, and throw a {{LinkError}} exception. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. From f8410fbaab2c9792f93fe6e43a0d0fa8cd799117 Mon Sep 17 00:00:00 2001 From: Asumu Takikawa Date: Thu, 15 Feb 2024 10:49:17 -0800 Subject: [PATCH 04/29] Update document/core/appendix/embedding.rst Co-authored-by: Andreas Rossberg --- document/core/appendix/embedding.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index e7d60a1a44..859c8c027f 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -695,7 +695,7 @@ Matching \end{array} -.. index:: value type +.. index:: value type, value .. _embed-default-value: Value types From dc2426213a8918a5f83162a6f8be5727930a3cff Mon Sep 17 00:00:00 2001 From: Asumu Takikawa Date: Thu, 15 Feb 2024 10:58:55 -0800 Subject: [PATCH 05/29] Address feedback, rename to val_default --- document/core/appendix/embedding.rst | 41 ++++++++++++---------------- document/js-api/index.bs | 4 +-- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 859c8c027f..46d1582c4b 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -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` ............................................... @@ -656,6 +657,20 @@ References In such cases, this function may return a less precise supertype. +:math:`\F{val\_default}(\type) : \val` +............................................... + +1. If :math:`\default_{type}` is not defined, then return :math:`\ERROR`. + +1. Else, return the :ref:`value ` :math:`\default_{type}`. + +.. 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: @@ -693,23 +708,3 @@ Matching \F{match\_externtype}(\X{et}_1, \X{et}_2) &=& \TRUE && (\iff \vdashexterntypematch \X{et}_1 \matchesexterntype \X{et}_2) \\ \F{match\_externtype}(\X{et}_1, \X{et}_2) &=& \FALSE && (\otherwise) \\ \end{array} - - -.. index:: value type, value -.. _embed-default-value: - -Value types -~~~~~~~~~~~ - -:math:`\F{default\_value}(\type) : \val` -............................................... - -1. If :math:`\default_{type}` is not defined, then return :math:`\ERROR`. - -1. Else, return the :ref:`value ` :math:`\default_{type}`. - -.. math:: - \begin{array}{lclll} - \F{default\_value}(t) &=& v && (\iff \default_t = v) \\ - \F{default\_value}(t) &=& \ERROR && (\iff \default_t = \epsilon) \\ - \end{array} diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 9df91d001c..6f978a86e5 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -115,8 +115,8 @@ 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: default_value; url: appendix/embedding.html#embed-default-value text: error; url: appendix/embedding.html#embed-error text: store; url: exec/runtime.html#syntax-store text: table type; url: syntax/types.html#syntax-tabletype @@ -895,7 +895,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each
The algorithm DefaultValue(|valuetype|) performs the following steps: 1. If |valuetype| equals [=externref=], return [=ToWebAssemblyValue=](undefined, |valuetype|). - 1. Return [=default_value=](|valuetype|). + 1. Return [=val_default=](|valuetype|).
From cae2341e8fdbfc11016dfc860fcc95bbb8012d60 Mon Sep 17 00:00:00 2001 From: Asumu Takikawa Date: Thu, 15 Feb 2024 11:05:09 -0800 Subject: [PATCH 06/29] Catch only TypeError in case TWAV throws other exns in the future --- document/js-api/index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 41df72d75d..36d688c136 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -370,7 +370,7 @@ A {{Module}} object represents a single WebAssembly module. Each {{Module}} obje 1. Throw a {{LinkError}} exception. 1. If |valtype| is [=v128=], 1. Throw a {{LinkError}} exception. - 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). If this operation throws an exception, catch it, and throw a {{LinkError}} exception. + 1. Let |value| be [=ToWebAssemblyValue=](|v|, |valtype|). If this operation throws a {{TypeError}}, catch it, and throw a {{LinkError}} exception. 1. Let |store| be the [=surrounding agent=]'s [=associated store=]. 1. Let (|store|, |globaladdr|) be [=global_alloc=](|store|, [=const=] |valtype|, |value|). 1. Set the [=surrounding agent=]'s [=associated store=] to |store|. From d5a49d2b4ba484edb2f5845281d4156c374de532 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Fri, 16 Feb 2024 07:38:49 +0100 Subject: [PATCH 07/29] Update document/core/appendix/embedding.rst --- document/core/appendix/embedding.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/document/core/appendix/embedding.rst b/document/core/appendix/embedding.rst index 46d1582c4b..3dc750bfa0 100644 --- a/document/core/appendix/embedding.rst +++ b/document/core/appendix/embedding.rst @@ -657,12 +657,12 @@ Values In such cases, this function may return a less precise supertype. -:math:`\F{val\_default}(\type) : \val` +:math:`\F{val\_default}(\valtype) : \val` ............................................... -1. If :math:`\default_{type}` is not defined, then return :math:`\ERROR`. +1. If :math:`\default_{valtype}` is not defined, then return :math:`\ERROR`. -1. Else, return the :ref:`value ` :math:`\default_{type}`. +1. Else, return the :ref:`value ` :math:`\default_{valtype}`. .. math:: \begin{array}{lclll} From f09b033ac23518f747b4dade61eebe39e41c0e9d Mon Sep 17 00:00:00 2001 From: zapashcanon Date: Sun, 18 Feb 2024 13:41:57 +0100 Subject: [PATCH 08/29] typo --- document/core/exec/values.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/exec/values.rst b/document/core/exec/values.rst index 6b19fcef38..145645c308 100644 --- a/document/core/exec/values.rst +++ b/document/core/exec/values.rst @@ -48,7 +48,7 @@ The following auxiliary typing rules specify this typing relation relative to a * The :ref:`heap type ` must be :ref:`valid ` under the empty :ref:`context `. -* Then value is valid with :ref:`reference type ` :math:`(\REF~\NULL~t')`, where the :ref:`heap type ` :math:`t'` that is the least type that :ref:`matches ` :math:`t`. +* Then the value is valid with :ref:`reference type ` :math:`(\REF~\NULL~t')`, where the :ref:`heap type ` :math:`t'` is the least type that :ref:`matches ` :math:`t`. .. math:: \frac{ From 16041aab00e4d9bf9fc8328faf77f151cd6d05b7 Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Thu, 22 Feb 2024 11:54:36 -0800 Subject: [PATCH 09/29] [test] Test `call_indirect` subtyping more thoroughly Test that validation allows `call_indirect` to have a type immediate that is a supertype of or unrelated to the table element type and that the runtime behavior is correct in these cases. --- test/core/gc/type-subtyping.wast | 35 ++++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/test/core/gc/type-subtyping.wast b/test/core/gc/type-subtyping.wast index a9022fc334..f2b33d7c49 100644 --- a/test/core/gc/type-subtyping.wast +++ b/test/core/gc/type-subtyping.wast @@ -316,6 +316,34 @@ (assert_trap (invoke "fail3") "cast") (assert_trap (invoke "fail4") "cast") +(module + (type $t1 (sub (func))) + (type $t2 (sub $t1 (func))) + (type $t3 (sub $t2 (func))) + (type $t4 (sub final (func))) + + (func $f2 (type $t2)) + (func $f3 (type $t3)) + (table (ref null $t2) (elem $f2 $f3)) + + (func (export "run") + (call_indirect (type $t1) (i32.const 0)) + (call_indirect (type $t1) (i32.const 1)) + (call_indirect (type $t2) (i32.const 0)) + (call_indirect (type $t2) (i32.const 1)) + (call_indirect (type $t3) (i32.const 1)) + ) + + (func (export "fail1") + (call_indirect (type $t3) (i32.const 0)) + ) + (func (export "fail2") + (call_indirect (type $t4) (i32.const 0)) + ) +) +(assert_return (invoke "run")) +(assert_trap (invoke "fail1") "indirect call") +(assert_trap (invoke "fail2") "indirect call") (module (rec (type $f1 (sub (func))) (type (struct (field (ref $f1))))) @@ -740,7 +768,7 @@ "sub type" ) -(assert_invalid +(assert_invalid (module (type $f0 (sub (func (param i32) (result i32)))) (type $s0 (sub $f0 (struct))) @@ -764,7 +792,7 @@ "sub type" ) -(assert_invalid +(assert_invalid (module (type $s0 (sub (struct))) (type $f0 (sub $s0 (func (param i32) (result i32)))) @@ -772,7 +800,7 @@ "sub type" ) -(assert_invalid +(assert_invalid (module (type $a0 (sub (array i32))) (type $f0 (sub $a0 (func (param i32) (result i32)))) @@ -803,4 +831,3 @@ ) "sub type" ) - From c2e70ce650c04d127d3002fa1e686e747e29bbcb Mon Sep 17 00:00:00 2001 From: Rikito Taniguchi Date: Sun, 25 Feb 2024 13:47:47 +0900 Subject: [PATCH 10/29] Fix an example code for ref.cast in MVP.md The first operand for `ref.cast` should be a reference type. However, the code example in `MVP.md` seems to have a heaptype which is invalid. (Assuming the `$C` is defined as follows based on the context) ``` (module (type $A (sub (struct))) (type $B (sub $A (struct (field i32)))) (type $C (sub $B (struct (field i32 i32)))) (func $castBtoC (param $x (ref $B)) (result (ref $C)) (ref.cast $C (local.get $x)) ) ) ``` ``` $ wasm -d test.wat test.wat:6.15-6.17: syntax error: unexpected token ``` (Where `wasm` is a reference interpreter built from https://github.com/WebAssembly/gc/commit/0ba84fb5f993348fc3eb052968bd869aa7bc3875) --- proposals/gc/MVP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/gc/MVP.md b/proposals/gc/MVP.md index 081dfc539e..cec9ee12b7 100644 --- a/proposals/gc/MVP.md +++ b/proposals/gc/MVP.md @@ -466,7 +466,7 @@ Then, `$rttA` would carry supertype vector `[$rttA]`, `$rttB` has `[$rttA, $rttB Now consider a function that casts a `$B` to a `$C`: ``` (func $castBtoC (param $x (ref $B)) (result (ref $C)) - (ref.cast $C (local.get $x)) + (ref.cast (ref $C) (local.get $x)) ) ``` This can compile to machine code that (1) reads the RTT from `$x`, (2) checks that the length of its supertype table is >= 3, and (3) pointer-compares table[2] against `$rttC`. From b03e35188f7bb768792089b375ffff55188c07c6 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 5 Mar 2024 14:15:08 +0100 Subject: [PATCH 11/29] Typos --- document/core/valid/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index f88fe1bf39..ea71a991ce 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -508,7 +508,7 @@ Aggregate Reference Instructions \qquad C \vdashreftypematch C.\CELEMS[y] \matchesreftype \X{rt} }{ - C \vdashinstr \ARRAYNEWELEM~x~n : [\I32~\I32] \to [(\REF~x)] + C \vdashinstr \ARRAYNEWELEM~x~y : [\I32~\I32] \to [(\REF~x)] } @@ -539,7 +539,7 @@ Aggregate Reference Instructions \qquad C.\CDATAS[y] = {\ok} }{ - C \vdashinstr \ARRAYNEWDATA~x~n : [\I32~\I32] \to [(\REF~x)] + C \vdashinstr \ARRAYNEWDATA~x~y : [\I32~\I32] \to [(\REF~x)] } From 7c26de335f84152a192e91a0837215011b739f7d Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 5 Mar 2024 14:21:53 +0100 Subject: [PATCH 12/29] More typos --- document/core/valid/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/valid/instructions.rst b/document/core/valid/instructions.rst index ea71a991ce..5ab841a606 100644 --- a/document/core/valid/instructions.rst +++ b/document/core/valid/instructions.rst @@ -379,7 +379,7 @@ Aggregate Reference Instructions \qquad \X{ft}^\ast[y] = \mut~\X{st} \qquad - \sx = \epsilon \Leftrightarrow \X{st} = \unpacktype(\X{st}) + \sx^? = \epsilon \Leftrightarrow \X{st} = \unpacktype(\X{st}) }{ C \vdashinstr \STRUCTGET\K{\_}\sx^?~x~y : [(\REF~\NULL~x)] \to [\unpacktype(\X{st})] } @@ -566,7 +566,7 @@ Aggregate Reference Instructions \frac{ \expanddt(C.\CTYPES[x]) = \TARRAY~(\mut~\X{st}) \qquad - \sx = \epsilon \Leftrightarrow \X{st} = \unpacktype(\X{st}) + \sx^? = \epsilon \Leftrightarrow \X{st} = \unpacktype(\X{st}) }{ C \vdashinstr \ARRAYGET\K{\_}\sx^?~x : [(\REF~\NULL~x)~\I32] \to [\unpacktype(\X{st})] } From 1705935f146e7fdb3b182ed9b8897145ee93109b Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Wed, 6 Mar 2024 06:58:22 -0800 Subject: [PATCH 13/29] Fix typing of `ref.i31` in the appendix It produces a non-null `(ref i31)` not an `i31ref` aka `(ref null i31)`. --- document/core/appendix/index-instructions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/appendix/index-instructions.py b/document/core/appendix/index-instructions.py index 0b10aaba27..a824f26ed2 100755 --- a/document/core/appendix/index-instructions.py +++ b/document/core/appendix/index-instructions.py @@ -347,7 +347,7 @@ def Instruction(name, opcode, type=None, validation=None, execution=None, operat Instruction(r'\BRONCASTFAIL~t_1~t_2', r'\hex{FB}~\hex{19}', r'[t_1] \to [t_2]', r'valid-br_on_cast_fail', r'exec-br_on_cast_fail'), Instruction(r'\ANYCONVERTEXTERN', r'\hex{FB}~\hex{1A}', r'[(\REF~\NULL~\EXTERN)] \to [(\REF~\NULL~\ANY)]', r'valid-any.convert_extern', r'exec-any.convert_extern'), Instruction(r'\EXTERNCONVERTANY', r'\hex{FB}~\hex{1B}', r'[(\REF~\NULL~\ANY)] \to [(\REF~\NULL~\EXTERN)]', r'valid-extern.convert_any', r'exec-extern.convert_any'), - Instruction(r'\REFI31', r'\hex{FB}~\hex{1C}', r'[\I32] \to [\I31REF]', r'valid-ref.i31', r'exec-ref.i31'), + Instruction(r'\REFI31', r'\hex{FB}~\hex{1C}', r'[\I32] \to [(\REF~\I31)]', r'valid-ref.i31', r'exec-ref.i31'), Instruction(r'\I31GETS', r'\hex{FB}~\hex{1D}', r'[\I31REF] \to [\I32]', r'valid-i31.get_sx', r'exec-i31.get_sx'), Instruction(r'\I31GETU', r'\hex{FB}~\hex{1E}', r'[\I31REF] \to [\I32]', r'valid-i31.get_sx', r'exec-i31.get_sx'), Instruction(None, r'\hex{FB}~\hex{1E} \dots'), From 606931a1ffa8defe712748cb52e8858427dd3f2b Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 17 Mar 2024 07:55:12 +0100 Subject: [PATCH 14/29] Backport value subsumption --- document/core/exec/values.rst | 20 ++++++++++++++++++++ document/core/valid/matching.rst | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/document/core/exec/values.rst b/document/core/exec/values.rst index e0fd90e245..17c68e1091 100644 --- a/document/core/exec/values.rst +++ b/document/core/exec/values.rst @@ -83,6 +83,26 @@ The following auxiliary typing rules specify this typing relation relative to a S \vdashval \REFEXTERNADDR~a : (\REF~\EXTERN) } +Subsumption +........... + +* The value must be valid with some value type :math:`t`. + +* The value type :math:`t` :ref:`matches ` another :ref:`valid ` type :math:`t'`. + +* Then the value is valid with type :math:`t'`. + +.. math:: + \frac{ + S \vdashval \val : t + \qquad + \vdashvaltype t' \ok + \qquad + \vdashvaltypematch t \matchesvaltype t' + }{ + S \vdashval \val : t' + } + .. index:: external value, external type, validation, import, store diff --git a/document/core/valid/matching.rst b/document/core/valid/matching.rst index e6fededdbd..ff1072462d 100644 --- a/document/core/valid/matching.rst +++ b/document/core/valid/matching.rst @@ -54,7 +54,7 @@ A :ref:`heap type ` :math:`\heaptype_1` matches a :ref:`heap ty * Either both :math:`\heaptype_1` and :math:`\heaptype_2` are the same. -* Or :math:`\heaptype_1` is a :ref:`function type ` and :math:`\heaptype_2` is :math:`FUNC`. +* Or :math:`\heaptype_1` is a :ref:`function type ` and :math:`\heaptype_2` is :math:`\FUNC`. * Or :math:`\heaptype_1` is a :ref:`function type ` :math:`\functype_1` and :math:`\heaptype_2` is a :ref:`function type ` :math:`\functype_2`, and :math:`\functype_1` :ref:`matches ` :math:`\functype_2`. From b172ec0ac284334a69aa815f0edee52a0de4fc39 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 19 Mar 2024 13:39:35 +0100 Subject: [PATCH 15/29] Fix typo --- document/core/exec/instructions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index a96aaaadbb..4c58321101 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -819,14 +819,14 @@ Reference Instructions S; F; (\I32.\CONST~s)~(\I32.\CONST~n)~(\ARRAYNEWDATA~x~y) &\stepto& \TRAP \\&& \begin{array}[t]{@{}r@{~}l@{}} - (\iff & \expanddt(F.\AMODULE.\MITYPES[x]) = \TARRAY~\X{ft}^n \\ + (\iff & \expanddt(F.\AMODULE.\MITYPES[x]) = \TARRAY~\X{ft} \\ \land & s + n\cdot|\X{ft}|/8 > |S.\SDATAS[F.\AMODULE.\MIDATAS[y]].\DIDATA|) \end{array} \\ \\[1ex] S; F; (\I32.\CONST~s)~(\I32.\CONST~n)~(\ARRAYNEWDATA~x~y) &\stepto& (t.\CONST~c)^n~(\ARRAYNEWFIXED~x~n) \\&& \begin{array}[t]{@{}r@{~}l@{}} - (\iff & \expanddt(F.\AMODULE.\MITYPES[x]) = \TARRAY~\X{ft}^n \\ + (\iff & \expanddt(F.\AMODULE.\MITYPES[x]) = \TARRAY~\X{ft} \\ \land & t = \unpacktype(\X{ft}) \\ \land & \concat((\bytes_{\X{ft}}(c))^n) = S.\SDATAS[F.\AMODULE.\MIDATAS[y]].\DIDATA[s \slice n\cdot|\X{ft}|/8] \\ \end{array} \\ From 33f15e692b492cccba702e49ac9ff67e1302987a Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Thu, 4 Apr 2024 10:42:34 -0700 Subject: [PATCH 16/29] Add additional i31ref spec tests I noticed that Wasmtime was passing the spec tests despite having bits that were known to be unimplemented. This should help the tests exercise those corners of the spec. Notably: * Setting `i31ref` globals. * Initializing tables and globals with `(ref.i31 (global.get $g))`. * Table operations on `i31ref` tables. * Accessing `anyref` globals and tables that are actually `i31ref`s. This is interesting to exercise outside of general subtyping because we have different paths in our inline GC barriers for `anyref`s that are actually `i31ref`s. --- test/core/gc/i31.wast | 215 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 215 insertions(+) diff --git a/test/core/gc/i31.wast b/test/core/gc/i31.wast index 3b6c32fbad..0a8b21e476 100644 --- a/test/core/gc/i31.wast +++ b/test/core/gc/i31.wast @@ -19,10 +19,17 @@ (global $i (ref i31) (ref.i31 (i32.const 2))) (global $m (mut (ref i31)) (ref.i31 (i32.const 3))) + (func (export "get_globals") (result i32 i32) (i31.get_u (global.get $i)) (i31.get_u (global.get $m)) ) + + (func (export "set_global") (param i32) + local.get 0 + ref.i31 + global.set $m + ) ) (assert_return (invoke "new" (i32.const 1)) (ref.i31)) @@ -49,3 +56,211 @@ (assert_trap (invoke "get_s-null") "null i31 reference") (assert_return (invoke "get_globals") (i32.const 2) (i32.const 3)) + +(invoke "set_global" (i32.const 1234)) +(assert_return (invoke "get_globals") (i32.const 2) (i32.const 1234)) + +(module $tables_of_i31ref + (table $table 3 10 i31ref) + (elem (table $table) (i32.const 0) i31ref (item (ref.i31 (i32.const 999))) + (item (ref.i31 (i32.const 888))) + (item (ref.i31 (i32.const 777)))) + + (func (export "size") (result i32) + table.size $table + ) + + (func (export "get") (param i32) (result i32) + local.get 0 + table.get $table + i31.get_u + ) + + (func (export "grow") (param i32 i32) (result i32) + (ref.i31 (local.get 1)) + local.get 0 + table.grow $table + ) + + (func (export "fill") (param i32 i32 i32) + local.get 0 + (ref.i31 (local.get 1)) + local.get 2 + table.fill $table + ) + + (func (export "copy") (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + table.copy $table $table + ) + + (elem $elem i31ref (item (ref.i31 (i32.const 123))) + (item (ref.i31 (i32.const 456))) + (item (ref.i31 (i32.const 789)))) + (func (export "init") (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + table.init $table $elem + ) +) + +;; Initial state. +(assert_return (invoke "size") (i32.const 3)) +(assert_return (invoke "get" (i32.const 0)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 1)) (i32.const 888)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 777)) + +;; Grow from size 3 to size 5. +(assert_return (invoke "grow" (i32.const 2) (i32.const 333)) (i32.const 3)) +(assert_return (invoke "size") (i32.const 5)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 333)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 333)) + +;; Fill table[2..4] = 111. +(invoke "fill" (i32.const 2) (i32.const 111) (i32.const 2)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 111)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 111)) + +;; Copy from table[0..2] to table[3..5]. +(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 2)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 888)) + +;; Initialize the passive element at table[1..4]. +(invoke "init" (i32.const 1) (i32.const 0) (i32.const 3)) +(assert_return (invoke "get" (i32.const 1)) (i32.const 123)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 456)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 789)) + +(module $env + (global (export "g") i32 (i32.const 42)) +) +(register "env") + +(module $i31ref_of_global_table_initializer + (global $g (import "env" "g") i32) + (table $t 3 3 (ref i31) (ref.i31 (global.get $g))) + (func (export "get") (param i32) (result i32) + local.get 0 + table.get $t + i31.get_u + ) +) + +(assert_return (invoke "get" (i32.const 0)) (i32.const 42)) +(assert_return (invoke "get" (i32.const 0)) (i32.const 42)) +(assert_return (invoke "get" (i32.const 0)) (i32.const 42)) + +(module $i31ref_of_global_global_initializer + (global $g0 (import "env" "g") i32) + (global $g1 i31ref (ref.i31 (global.get $g0))) + (func (export "get") (result i32) + global.get $g1 + i31.get_u + ) +) + +(assert_return (invoke "get") (i32.const 42)) + +(module $anyref_global_of_i31ref + (global $c anyref (ref.i31 (i32.const 1234))) + (global $m (mut anyref) (ref.i31 (i32.const 5678))) + + (func (export "get_globals") (result i32 i32) + global.get $c + ref.cast i31ref + i31.get_u + global.get $m + ref.cast i31ref + i31.get_u + ) + + (func (export "set_global") (param i32) + local.get 0 + ref.i31 + global.set $m + ) +) + +(assert_return (invoke "get_globals") (i32.const 1234) (i32.const 5678)) +(invoke "set_global" (i32.const 0)) +(assert_return (invoke "get_globals") (i32.const 1234) (i32.const 0)) + +(module $anyref_table_of_i31ref + (table $table 3 10 anyref) + (elem (table $table) (i32.const 0) i31ref (item (ref.i31 (i32.const 999))) + (item (ref.i31 (i32.const 888))) + (item (ref.i31 (i32.const 777)))) + + (func (export "size") (result i32) + table.size $table + ) + + (func (export "get") (param i32) (result i32) + local.get 0 + table.get $table + ref.cast i31ref + i31.get_u + ) + + (func (export "grow") (param i32 i32) (result i32) + (ref.i31 (local.get 1)) + local.get 0 + table.grow $table + ) + + (func (export "fill") (param i32 i32 i32) + local.get 0 + (ref.i31 (local.get 1)) + local.get 2 + table.fill $table + ) + + (func (export "copy") (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + table.copy $table $table + ) + + (elem $elem i31ref (item (ref.i31 (i32.const 123))) + (item (ref.i31 (i32.const 456))) + (item (ref.i31 (i32.const 789)))) + (func (export "init") (param i32 i32 i32) + local.get 0 + local.get 1 + local.get 2 + table.init $table $elem + ) +) + +;; Initial state. +(assert_return (invoke "size") (i32.const 3)) +(assert_return (invoke "get" (i32.const 0)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 1)) (i32.const 888)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 777)) + +;; Grow from size 3 to size 5. +(assert_return (invoke "grow" (i32.const 2) (i32.const 333)) (i32.const 3)) +(assert_return (invoke "size") (i32.const 5)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 333)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 333)) + +;; Fill table[2..4] = 111. +(invoke "fill" (i32.const 2) (i32.const 111) (i32.const 2)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 111)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 111)) + +;; Copy from table[0..2] to table[3..5]. +(invoke "copy" (i32.const 3) (i32.const 0) (i32.const 2)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 999)) +(assert_return (invoke "get" (i32.const 4)) (i32.const 888)) + +;; Initialize the passive element at table[1..4]. +(invoke "init" (i32.const 1) (i32.const 0) (i32.const 3)) +(assert_return (invoke "get" (i32.const 1)) (i32.const 123)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 456)) +(assert_return (invoke "get" (i32.const 3)) (i32.const 789)) From 18ab40c8ea900f551f96ab705d9e4ea56ce08000 Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Mon, 8 Apr 2024 13:41:33 -0700 Subject: [PATCH 17/29] Switch to nested operators --- test/core/gc/i31.wast | 70 ++++++++++--------------------------------- 1 file changed, 16 insertions(+), 54 deletions(-) diff --git a/test/core/gc/i31.wast b/test/core/gc/i31.wast index 0a8b21e476..1d98abb655 100644 --- a/test/core/gc/i31.wast +++ b/test/core/gc/i31.wast @@ -26,9 +26,7 @@ ) (func (export "set_global") (param i32) - local.get 0 - ref.i31 - global.set $m + (global.set $m (ref.i31 (local.get 0))) ) ) @@ -71,39 +69,26 @@ ) (func (export "get") (param i32) (result i32) - local.get 0 - table.get $table - i31.get_u + (i31.get_u (table.get $table (local.get 0))) ) (func (export "grow") (param i32 i32) (result i32) - (ref.i31 (local.get 1)) - local.get 0 - table.grow $table + (table.grow $table (ref.i31 (local.get 1)) (local.get 0)) ) (func (export "fill") (param i32 i32 i32) - local.get 0 - (ref.i31 (local.get 1)) - local.get 2 - table.fill $table + (table.fill $table (local.get 0) (ref.i31 (local.get 1)) (local.get 2)) ) (func (export "copy") (param i32 i32 i32) - local.get 0 - local.get 1 - local.get 2 - table.copy $table $table + (table.copy $table $table (local.get 0) (local.get 1) (local.get 2)) ) (elem $elem i31ref (item (ref.i31 (i32.const 123))) (item (ref.i31 (i32.const 456))) (item (ref.i31 (i32.const 789)))) (func (export "init") (param i32 i32 i32) - local.get 0 - local.get 1 - local.get 2 - table.init $table $elem + (table.init $table $elem (local.get 0) (local.get 1) (local.get 2)) ) ) @@ -144,9 +129,7 @@ (global $g (import "env" "g") i32) (table $t 3 3 (ref i31) (ref.i31 (global.get $g))) (func (export "get") (param i32) (result i32) - local.get 0 - table.get $t - i31.get_u + (i31.get_u (local.get 0) (table.get $t)) ) ) @@ -158,8 +141,7 @@ (global $g0 (import "env" "g") i32) (global $g1 i31ref (ref.i31 (global.get $g0))) (func (export "get") (result i32) - global.get $g1 - i31.get_u + (i31.get_u (global.get $g1)) ) ) @@ -170,18 +152,12 @@ (global $m (mut anyref) (ref.i31 (i32.const 5678))) (func (export "get_globals") (result i32 i32) - global.get $c - ref.cast i31ref - i31.get_u - global.get $m - ref.cast i31ref - i31.get_u + (i31.get_u (ref.cast i31ref (global.get $c))) + (i31.get_u (ref.cast i31ref (global.get $m))) ) (func (export "set_global") (param i32) - local.get 0 - ref.i31 - global.set $m + (global.set $m (ref.i31 (local.get 0))) ) ) @@ -200,40 +176,26 @@ ) (func (export "get") (param i32) (result i32) - local.get 0 - table.get $table - ref.cast i31ref - i31.get_u + (i31.get_u (ref.cast i31ref (table.get $table (local.get 0)))) ) (func (export "grow") (param i32 i32) (result i32) - (ref.i31 (local.get 1)) - local.get 0 - table.grow $table + (table.grow $table (ref.i31 (local.get 1)) (local.get 0)) ) (func (export "fill") (param i32 i32 i32) - local.get 0 - (ref.i31 (local.get 1)) - local.get 2 - table.fill $table + (table.fill $table (local.get 0) (ref.i31 (local.get 1)) (local.get 2)) ) (func (export "copy") (param i32 i32 i32) - local.get 0 - local.get 1 - local.get 2 - table.copy $table $table + (table.copy $table $table (local.get 0) (local.get 1) (local.get 2)) ) (elem $elem i31ref (item (ref.i31 (i32.const 123))) (item (ref.i31 (i32.const 456))) (item (ref.i31 (i32.const 789)))) (func (export "init") (param i32 i32 i32) - local.get 0 - local.get 1 - local.get 2 - table.init $table $elem + (table.init $table $elem (local.get 0) (local.get 1) (local.get 2)) ) ) From c84a3c63b19fe11e79d3afec0ac1eb6ab7ac80aa Mon Sep 17 00:00:00 2001 From: Thomas Lively Date: Sun, 14 Apr 2024 16:59:21 -0700 Subject: [PATCH 18/29] [Spec] Fix bounds check prose for array.fill and array.copy The prose incorrectly used "larger than or equal to" when it should have used just "larger than." The formalism was already correct. Fixes #536. --- document/core/exec/instructions.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index 4c58321101..c9db8bc3d6 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -1065,7 +1065,7 @@ Reference Instructions 12. Assert: due to :ref:`validation `, the :ref:`array instance ` :math:`S.\SARRAYS[a]` exists. -13. If :math:`d + n` is larger than or equal to the length of :math:`S.\SARRAYS[a].\AIFIELDS`, then: +13. If :math:`d + n` is larger than the length of :math:`S.\SARRAYS[a].\AIFIELDS`, then: a. Trap. @@ -1175,11 +1175,11 @@ Reference Instructions 23. Assert: due to :ref:`validation `, the :ref:`array instance ` :math:`S.\SARRAYS[a_2]` exists. -24. If :math:`d + n` is larger than or equal to the length of :math:`S.\SARRAYS[a_1].\AIFIELDS`, then: +24. If :math:`d + n` is larger than the length of :math:`S.\SARRAYS[a_1].\AIFIELDS`, then: a. Trap. -25. If :math:`s + n` is larger than or equal to the length of :math:`S.\SARRAYS[a_2].\AIFIELDS`, then: +25. If :math:`s + n` is larger than the length of :math:`S.\SARRAYS[a_2].\AIFIELDS`, then: a. Trap. From be51b19e571d60f7be24b1ef1798f991cbc1f8ca Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 21 Apr 2024 10:01:03 +0200 Subject: [PATCH 19/29] Fix wrong type expansion --- document/core/binary/modules.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 59c7c2540a..3d77894d6a 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -338,7 +338,7 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element segment} & \Belem &::=& 0{:}\Bu32~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \\&&&\quad - \{ \ETYPE~(\REF~\NULL~\FUNC), \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \{ \ETYPE~(\REF~\FUNC), \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& 1{:}\Bu32~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \\&&&\quad \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EPASSIVE \} \\ &&|& @@ -350,7 +350,7 @@ It decodes into a vector of :ref:`element segments ` that represent \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EDECLARATIVE \} \\ &&|& 4{:}\Bu32~~e{:}\Bexpr~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \\&&&\quad - \{ \ETYPE~(\REF~\NULL~\FUNC), \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \{ \ETYPE~(\REF~\FUNC), \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& 5{:}\Bu32~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \\&&&\quad \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EPASSIVE \} \\ &&|& From 7514d9a1724edc4f9f00c2a92681d5bc8a93f79f Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 21 Apr 2024 10:14:13 +0200 Subject: [PATCH 20/29] Tweak type-setting / typos in some rules --- document/core/exec/instructions.rst | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index c9db8bc3d6..be03d738e8 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -1102,13 +1102,13 @@ Reference Instructions (\iff d + n > |S.\SARRAYS[a].\AIFIELDS|) \\[1ex] S; (\REFARRAYADDR~a)~(\I32.\CONST~d)~\val~(\I32.\CONST~0)~(\ARRAYFILL~x) - \quad\stepto\quad S; \epsilon + \quad\stepto\quad \epsilon \\ \qquad (\otherwise) \\[1ex] S; (\REFARRAYADDR~a)~(\I32.\CONST~d)~\val~(\I32.\CONST~n+1)~(\ARRAYFILL~x) \quad\stepto - \\ \quad S; + \\ \quad \begin{array}[t]{@{}l@{}} (\REFARRAYADDR~a)~(\I32.\CONST~d)~\val~(\ARRAYSET~x) \\ (\REFARRAYADDR~a)~(\I32.\CONST~d+1)~\val~(\I32.\CONST~n)~(\ARRAYFILL~x) \\ @@ -1252,7 +1252,7 @@ Reference Instructions (\iff d + n > |S.\SARRAYS[a_1].\AIFIELDS| \vee s + n > |S.\SARRAYS[a_2].\AIFIELDS|) \\[1ex] S; F; (\REFARRAYADDR~a_1)~(\I32.\CONST~d)~(\REFARRAYADDR~a_2)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\ARRAYCOPY~x~y) - \quad\stepto\quad S; \epsilon + \quad\stepto\quad \epsilon \\ \qquad (\otherwise) \\[1ex] @@ -1391,13 +1391,13 @@ Where: \end{array} \\[1ex] S; F; (\REFARRAYADDR~a)~(\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\ARRAYINITDATA~x~y) - \quad\stepto\quad S; F; \epsilon + \quad\stepto\quad \epsilon \\ \qquad (\otherwise) \\[1ex] S; F; (\REFARRAYADDR~a)~(\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\ARRAYINITDATA~x~y) \quad\stepto - \\ \quad S; F; + \\ \quad \begin{array}[t]{@{}l@{}} (\REFARRAYADDR~a)~(\I32.\CONST~d)~(t.\CONST~c)~(\ARRAYSET~x) \\ (\REFARRAYADDR~a)~(\I32.\CONST~d+1)~(\I32.\CONST~s+|\X{ft}|/8)~(\I32.\CONST~n)~(\ARRAYINITDATA~x~y) \\ @@ -1497,13 +1497,13 @@ Where: \end{array} \\[1ex] S; F; (\REFARRAYADDR~a)~(\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~0)~(\ARRAYINITELEM~x~y) - \quad\stepto\quad S; F; \epsilon + \quad\stepto\quad \epsilon \\ \qquad (\otherwise) \\[1ex] S; F; (\REFARRAYADDR~a)~(\I32.\CONST~d)~(\I32.\CONST~s)~(\I32.\CONST~n+1)~(\ARRAYINITELEM~x~y) \quad\stepto - \\ \quad S; F; + \\ \quad \begin{array}[t]{@{}l@{}} (\REFARRAYADDR~a)~(\I32.\CONST~d)~\REF~(\ARRAYSET~x) \\ (\REFARRAYADDR~a)~(\I32.\CONST~d+1)~(\I32.\CONST~s+1)~(\I32.\CONST~n)~(\ARRAYINITELEM~x~y) \\ @@ -1538,7 +1538,7 @@ Where: .. math:: \begin{array}{lcl@{\qquad}l} - (\REFNULL \X{ht})~\ANYCONVERTEXTERN &\stepto& (\REFNULL~\ANY) \\ + (\REFNULL~\X{ht})~\ANYCONVERTEXTERN &\stepto& (\REFNULL~\ANY) \\ (\REFEXTERN~\reff)~\ANYCONVERTEXTERN &\stepto& \reff \\ \end{array} @@ -1564,8 +1564,8 @@ Where: .. math:: \begin{array}{lcl@{\qquad}l} - (\REFNULL \X{ht})~\EXTERNCONVERTANY &\stepto& (\REFNULL~\EXTERN) \\ - \reff~\EXTERNCONVERTANY &\stepto& (\REFEXTERN~\reff) & (\iff \reff \neq (\REFNULL \X{ht})) \\ + (\REFNULL~\X{ht})~\EXTERNCONVERTANY &\stepto& (\REFNULL~\EXTERN) \\ + \reff~\EXTERNCONVERTANY &\stepto& (\REFEXTERN~\reff) & (\iff \reff \neq (\REFNULL~\X{ht})) \\ \end{array} @@ -4187,8 +4187,8 @@ Control Instructions .. math:: \begin{array}{lcl@{\qquad}l} S; F; \reff~(\BRONCAST~l~\X{rt}_1~\X{rt}_2) &\stepto& \reff~(\BR~l) - & (\iff S \vdashval \reff : \X{rt} - \land \vdashreftypematch \X{rt} \matchesreftype \insttype_{F.\AMODULE}(\X{rt}_2)) \\ + & (\iff S \vdashval \reff : \X{rt}} + \land {} \vdashreftypematch \X{rt} \matchesreftype \insttype_{F.\AMODULE}(\X{rt}_2)) \\ S; F; \reff~(\BRONCAST~l~\X{rt}_1~\X{rt}_2) &\stepto& \reff & (\otherwise) \\ \end{array} @@ -4223,7 +4223,7 @@ Control Instructions \begin{array}{lcl@{\qquad}l} S; F; \reff~(\BRONCASTFAIL~l~\X{rt}_1~\X{rt}_2) &\stepto& \reff & (\iff S \vdashval \reff : \X{rt} - \land \vdashreftypematch \X{rt} \matchesreftype \insttype_{F.\AMODULE}(\X{rt}_2)) \\ + \land {} \vdashreftypematch \X{rt} \matchesreftype \insttype_{F.\AMODULE}(\X{rt}_2)) \\ S; F; \reff~(\BRONCASTFAIL~l~\X{rt}_1~\X{rt}_2) &\stepto& \reff~(\BR~l) & (\otherwise) \\ \end{array} From 9ce923e2a5a428510c0ab3a37b84dc369a81f17a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 21 Apr 2024 10:01:03 +0200 Subject: [PATCH 21/29] Fix wrong type expansion --- document/core/binary/modules.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index d0c602ba52..1dbb083aaa 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -341,7 +341,7 @@ It decodes into a vector of :ref:`element segments ` that represent \production{element segment} & \Belem &::=& 0{:}\Bu32~~e{:}\Bexpr~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \\&&&\quad - \{ \ETYPE~(\REF~\NULL~\FUNC), \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \{ \ETYPE~(\REF~\FUNC), \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& 1{:}\Bu32~~\X{et}:\Belemkind~~y^\ast{:}\Bvec(\Bfuncidx) &\Rightarrow& \\&&&\quad \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EPASSIVE \} \\ &&|& @@ -353,7 +353,7 @@ It decodes into a vector of :ref:`element segments ` that represent \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EDECLARATIVE \} \\ &&|& 4{:}\Bu32~~e{:}\Bexpr~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \\&&&\quad - \{ \ETYPE~(\REF~\NULL~\FUNC), \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \{ \ETYPE~(\REF~\FUNC), \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& 5{:}\Bu32~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \\&&&\quad \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EPASSIVE \} \\ &&|& From cd543fa9b7e8eb852d37e560361c5520a3fe6156 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 21 Apr 2024 10:44:37 +0200 Subject: [PATCH 22/29] Fix typo --- document/core/exec/instructions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/document/core/exec/instructions.rst b/document/core/exec/instructions.rst index be03d738e8..428064eca9 100644 --- a/document/core/exec/instructions.rst +++ b/document/core/exec/instructions.rst @@ -4187,7 +4187,7 @@ Control Instructions .. math:: \begin{array}{lcl@{\qquad}l} S; F; \reff~(\BRONCAST~l~\X{rt}_1~\X{rt}_2) &\stepto& \reff~(\BR~l) - & (\iff S \vdashval \reff : \X{rt}} + & (\iff S \vdashval \reff : \X{rt} \land {} \vdashreftypematch \X{rt} \matchesreftype \insttype_{F.\AMODULE}(\X{rt}_2)) \\ S; F; \reff~(\BRONCAST~l~\X{rt}_1~\X{rt}_2) &\stepto& \reff & (\otherwise) \\ From 6871e547daf09e1b4fa415a8815e16d7539fc634 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 23 Apr 2024 04:10:09 +0200 Subject: [PATCH 23/29] More fixes and tests around element segments --- document/core/binary/modules.rst | 4 +- interpreter/binary/decode.ml | 2 +- interpreter/binary/encode.ml | 4 +- test/core/elem.wast | 346 +++++++++++++++++++++++++++++++ 4 files changed, 351 insertions(+), 5 deletions(-) diff --git a/document/core/binary/modules.rst b/document/core/binary/modules.rst index 3d77894d6a..1cd115dba2 100644 --- a/document/core/binary/modules.rst +++ b/document/core/binary/modules.rst @@ -350,7 +350,7 @@ It decodes into a vector of :ref:`element segments ` that represent \{ \ETYPE~\X{et}, \EINIT~((\REFFUNC~y)~\END)^\ast, \EMODE~\EDECLARATIVE \} \\ &&|& 4{:}\Bu32~~e{:}\Bexpr~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \\&&&\quad - \{ \ETYPE~(\REF~\FUNC), \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& + \{ \ETYPE~(\REF~\NULL~\FUNC), \EINIT~\X{el}^\ast, \EMODE~\EACTIVE~\{ \ETABLE~0, \EOFFSET~e \} \} \\ &&|& 5{:}\Bu32~~\X{et}:\Breftype~~\X{el}^\ast{:}\Bvec(\Bexpr) &\Rightarrow& \\&&&\quad \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EPASSIVE \} \\ &&|& @@ -361,7 +361,7 @@ It decodes into a vector of :ref:`element segments ` that represent &\Rightarrow& \\&&&\quad \{ \ETYPE~et, \EINIT~\X{el}^\ast, \EMODE~\EDECLARATIVE \} \\ \production{element kind} & \Belemkind &::=& - \hex{00} &\Rightarrow& \FUNCREF \\ + \hex{00} &\Rightarrow& (\REF~\FUNC) \\ \end{array} .. note:: diff --git a/interpreter/binary/decode.ml b/interpreter/binary/decode.ml index 887da409b6..7312232331 100644 --- a/interpreter/binary/decode.ml +++ b/interpreter/binary/decode.ml @@ -1043,7 +1043,7 @@ let elem s = | 0x04l -> let emode = at active_zero s in let einit = vec const s in - {etype = (NoNull, FuncHT); einit; emode} + {etype = (Null, FuncHT); einit; emode} | 0x05l -> let emode = at passive s in let etype = ref_type s in diff --git a/interpreter/binary/encode.ml b/interpreter/binary/encode.ml index 7f9bb347fc..98a5363534 100644 --- a/interpreter/binary/encode.ml +++ b/interpreter/binary/encode.ml @@ -898,7 +898,7 @@ struct match emode.it with | Passive -> u32 0x01l; elem_kind etype; vec elem_index einit - | Active {index; offset} when index.it = 0l && is_elem_kind etype -> + | Active {index; offset} when index.it = 0l -> u32 0x00l; const offset; vec elem_index einit | Active {index; offset} -> u32 0x02l; @@ -909,7 +909,7 @@ struct match emode.it with | Passive -> u32 0x05l; ref_type etype; vec const einit - | Active {index; offset} when index.it = 0l && is_elem_kind etype -> + | Active {index; offset} when index.it = 0l && etype = (Null, FuncHT) -> u32 0x04l; const offset; vec const einit | Active {index; offset} -> u32 0x06l; var index; const offset; ref_type etype; vec const einit diff --git a/test/core/elem.wast b/test/core/elem.wast index 0e6ea202aa..2bb25b09f8 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -233,6 +233,352 @@ ) +;; Binary format variations + +(module + (func) + (table 1 funcref) + (elem (i32.const 0) func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\07\01" ;; Elem section: 1 element segment + "\00\41\00\0b\01\00" ;; Segment 0: (i32.const 0) func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 funcref) + (elem func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\05\01" ;; Elem section: 1 element segment + "\01\00\01\00" ;; Segment 0: func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 funcref) + (elem (table 0) (i32.const 0) func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\09\01" ;; Elem section: 1 element segment + "\02\00\41\00\0b\00\01\00" ;; Segment 0: (table 0) (i32.const 0) func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 funcref) + (elem declare func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\05\01" ;; Elem section: 1 element segment + "\03\00\01\00" ;; Segment 0: declare func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 funcref) + (elem (i32.const 0) (;;)(ref func) (ref.func 0)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\09\01" ;; Elem section: 1 element segment + "\04\41\00\0b\01\d2\00\0b" ;; Segment 0: (i32.const 0) (ref.func 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) +(module + (func) + (table 1 funcref) + (elem (i32.const 0) funcref (ref.null func)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\09\01" ;; Elem section: 1 element segment + "\04\41\00\0b\01\d0\70\0b" ;; Segment 0: (i32.const 0) (ref.null func) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 funcref) + (elem (i32.const 0) funcref (ref.func 0)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\07\01" ;; Elem section: 1 element segment + "\05\70\01\d2\00\0b" ;; Segment 0: funcref (ref.func 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) +(module + (func) + (table 1 funcref) + (elem (i32.const 0) funcref (ref.null func)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\07\01" ;; Elem section: 1 element segment + "\05\70\01\d0\70\0b" ;; Segment 0: funcref (ref.null func) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 funcref) + (elem (table 0) (i32.const 0) funcref (ref.func 0)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\0b\01" ;; Elem section: 1 element segment + "\06\00\41\00\0b\70\01\d2\00\0b" ;; Segment 0: (table 0) (i32.const 0) funcref (ref.null 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) +(module + (func) + (table 1 funcref) + (elem (table 0) (i32.const 0) funcref (ref.null func)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\0b\01" ;; Elem section: 1 element segment + "\06\00\41\00\0b\70\01\d0\70\0b" ;; Segment 0: (table 0) (i32.const 0) funcref (ref.null func) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 funcref) + (elem declare funcref (ref.func 0)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\07\01" ;; Elem section: 1 element segment + "\07\70\01\d2\00\0b" ;; Segment 0: declare funcref (ref.func 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) +(module + (func) + (table 1 funcref) + (elem declare funcref (ref.null func)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\04\01" ;; Table section: 1 table + "\70\00\01" ;; Table 0: [1..] funcref + "\09\07\01" ;; Elem section: 1 element segment + "\07\70\01\d0\70\0b" ;; Segment 0: declare funcref (ref.null func) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + + +(module + (func) + (table 1 (ref func) (ref.func 0)) + (elem (i32.const 0) func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\07\01" ;; Elem section: 1 element segment + "\00\41\00\0b\01\00" ;; Segment 0: (i32.const 0) func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 (ref func) (ref.func 0)) + (elem func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\05\01" ;; Elem section: 1 element segment + "\01\00\01\00" ;; Segment 0: func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 (ref func) (ref.func 0)) + (elem (table 0) (i32.const 0) func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\09\01" ;; Elem section: 1 element segment + "\02\00\41\00\0b\00\01\00" ;; Segment 0: (table 0) (i32.const 0) func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 (ref func) (ref.func 0)) + (elem declare func 0) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\05\01" ;; Elem section: 1 element segment + "\03\00\01\00" ;; Segment 0: declare func 0 + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(assert_invalid + (module + (func) + (table 1 (ref func) (ref.func 0)) + (elem (i32.const 0) funcref (ref.func 0)) + ) + "type mismatch" +) +(assert_invalid + (module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\09\01" ;; Elem section: 1 element segment + "\04\41\00\0b\01\d2\00\0b" ;; Segment 0: (i32.const 0) (ref.func 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty + ) + "type mismatch" +) + +(module + (func) + (table 1 (ref func) (ref.func 0)) + (elem (ref func) (ref.func 0)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\08\01" ;; Elem section: 1 element segment + "\05\64\70\01\d2\00\0b" ;; Segment 0: (ref func) (ref.func 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 (ref func) (ref.func 0)) + (elem (table 0) (i32.const 0) (ref func) (ref.func 0)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\0c\01" ;; Elem section: 1 element segment + "\06\00\41\00\0b\64\70\01\d2\00\0b" ;; Segment 0: (table 0) (i32.const 0) (ref func) (ref.func 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + +(module + (func) + (table 1 (ref func) (ref.func 0)) + (elem declare (ref func) (ref.func 0)) +) +(module binary + "\00asm" "\01\00\00\00" ;; Magic + "\01\04\01\60\00\00" ;; Type section: 1 type + "\03\02\01\00" ;; Function section: 1 function + "\04\0a\01" ;; Table section: 1 table + "\40\00\64\70\00\01\d2\00\0b" ;; Table 0: [1..] (ref func) (ref.func 0) + "\09\08\01" ;; Elem section: 1 element segment + "\07\64\70\01\d2\00\0b" ;; Segment 0: declare (ref func) (ref.func 0) + "\0a\04\01" ;; Code section: 1 function + "\02\00\0b" ;; Function 0: empty +) + + ;; Invalid bounds for elements (assert_trap From 70ddb4b4fe973bf916643682321ba424a1917d76 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 23 Apr 2024 10:29:18 +0200 Subject: [PATCH 24/29] Update test/core/elem.wast Co-authored-by: Manos Koukoutos --- test/core/elem.wast | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/core/elem.wast b/test/core/elem.wast index 2bb25b09f8..70c1a9ad53 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -381,7 +381,7 @@ "\04\04\01" ;; Table section: 1 table "\70\00\01" ;; Table 0: [1..] funcref "\09\0b\01" ;; Elem section: 1 element segment - "\06\00\41\00\0b\70\01\d2\00\0b" ;; Segment 0: (table 0) (i32.const 0) funcref (ref.null 0) + "\06\00\41\00\0b\70\01\d2\00\0b" ;; Segment 0: (table 0) (i32.const 0) funcref (ref.func 0) "\0a\04\01" ;; Code section: 1 function "\02\00\0b" ;; Function 0: empty ) From 354c2cbbb371257e8122c71549516e55589b674a Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 23 Apr 2024 11:53:47 +0200 Subject: [PATCH 25/29] Fix JS type test wrappers --- interpreter/runtime/value.ml | 14 ++++------- interpreter/script/js.ml | 45 ++++++++++++++++++++++++++++-------- interpreter/script/run.ml | 1 + interpreter/text/parser.mly | 2 +- 4 files changed, 42 insertions(+), 20 deletions(-) diff --git a/interpreter/runtime/value.ml b/interpreter/runtime/value.ml index a3762725e5..dec2597229 100644 --- a/interpreter/runtime/value.ml +++ b/interpreter/runtime/value.ml @@ -95,23 +95,17 @@ let is_null_ref = function (* Typing *) let type_of_op = function - | I32 _ -> Types.I32T - | I64 _ -> Types.I64T - | F32 _ -> Types.F32T - | F64 _ -> Types.F64T - -let type_of_vecop = function - | V128 _ -> Types.V128T - -let type_of_num = function | I32 _ -> I32T | I64 _ -> I64T | F32 _ -> F32T | F64 _ -> F64T -let type_of_vec = function +let type_of_vecop = function | V128 _ -> V128T +let type_of_num = type_of_op +let type_of_vec = type_of_vecop + let type_of_ref' = ref (function _ -> assert false) let type_of_ref = function | NullRef t -> (Null, Match.bot_of_heap_type [] t) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index bd6a19e863..d3433456fa 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -294,8 +294,29 @@ let nan_bitmask_of = function | CanonicalNan -> abs_mask_of (* differ from canonical NaN in sign bit *) | ArithmeticNan -> canonical_nan_of (* 1 everywhere canonical NaN is *) +let type_of_num_pat = function + | NumPat num -> Value.type_of_num num.it + | NanPat op -> Value.type_of_op op.it + +let type_of_vec_pat = function + | VecPat vec -> Value.type_of_vec vec + +let type_of_ref_pat = function + | RefPat ref -> type_of_ref ref.it + | RefTypePat ht -> (NoNull, ht) + | NullPat -> (Null, BotHT) + +let type_of_result res = + match res.it with + | NumResult pat -> NumT (type_of_num_pat pat) + | VecResult pat -> VecT (type_of_vec_pat pat) + | RefResult pat -> RefT (type_of_ref_pat pat) + let assert_return ress ts at = let test (res, t) = + if not (Match.match_val_type [] t (type_of_result res)) then + [ Br (0l @@ at) @@ at ] + else match res.it with | NumResult (NumPat {it = num; at = at'}) -> let t', reinterpret = reinterpret_of (Value.type_of_op num) in @@ -362,7 +383,7 @@ let assert_return ress ts at = VecTest (V128 (V128.I8x16 V128Op.AllTrue)) @@ at; Test (I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] - | RefResult (RefPat {it = NullRef t; _}) -> + | RefResult (RefPat {it = NullRef _; _}) -> [ RefIsNull @@ at; Test (Value.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] @@ -374,17 +395,16 @@ let assert_return ress ts at = BrIf (0l @@ at) @@ at ] | RefResult (RefPat _) -> assert false + | RefResult (RefTypePat (ExnHT | ExternHT)) -> + [ BrOnNull (0l @@ at) @@ at ] | RefResult (RefTypePat t) -> [ RefTest (NoNull, t) @@ at; Test (I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] | RefResult NullPat -> - (match t with - | RefT _ -> - [ BrOnNull (0l @@ at) @@ at ] - | _ -> - [ Br (0l @@ at) @@ at ] - ) + [ RefIsNull @@ at; + Test (I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] in [], List.flatten (List.rev_map test (List.combine ress ts)) let i32 = NumT I32T @@ -431,10 +451,17 @@ let is_js_num_type = function | I32T -> true | I64T | F32T | F64T -> false +let is_js_vec_type = function + | _ -> false + +let is_js_ref_type = function + | (_, ExnHT) -> false + | _ -> true + let is_js_val_type = function | NumT t -> is_js_num_type t - | VecT _ -> false - | RefT _ -> true + | VecT t -> is_js_vec_type t + | RefT t -> is_js_ref_type t | BotT -> assert false let is_js_global_type = function diff --git a/interpreter/script/run.ml b/interpreter/script/run.ml index fe4bcec156..86fa5ee5ef 100644 --- a/interpreter/script/run.ml +++ b/interpreter/script/run.ml @@ -394,6 +394,7 @@ let assert_ref_pat r p = | RefTypePat Types.StructHT, Aggr.StructRef _ | RefTypePat Types.ArrayHT, Aggr.ArrayRef _ -> true | RefTypePat Types.FuncHT, Instance.FuncRef _ + | RefTypePat Types.ExnHT, Value.ExnRef _ | RefTypePat Types.ExternHT, _ -> true | NullPat, Value.NullRef _ -> true | _ -> false diff --git a/interpreter/text/parser.mly b/interpreter/text/parser.mly index 966eaedf5e..b45fbd138e 100644 --- a/interpreter/text/parser.mly +++ b/interpreter/text/parser.mly @@ -1449,7 +1449,7 @@ result : | LPAR REF_STRUCT RPAR { RefResult (RefTypePat StructHT) @@ $sloc } | LPAR REF_ARRAY RPAR { RefResult (RefTypePat ArrayHT) @@ $sloc } | LPAR REF_FUNC RPAR { RefResult (RefTypePat FuncHT) @@ $sloc } -/*| LPAR REF_EXN RPAR { RefResult (RefTypePat ExnRefType) @@ $sloc }*/ + | LPAR REF_EXN RPAR { RefResult (RefTypePat ExnHT) @@ $sloc } | LPAR REF_EXTERN RPAR { RefResult (RefTypePat ExternHT) @@ $sloc } | LPAR REF_NULL RPAR { RefResult NullPat @@ $sloc } | LPAR VEC_CONST VEC_SHAPE list(numpat) RPAR From f8190d1ca37cfaa1358ee49aecbcd08a8c4585c3 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Tue, 23 Apr 2024 11:56:47 +0200 Subject: [PATCH 26/29] Fix JS type test wrappers --- interpreter/runtime/value.ml | 14 ++++-------- interpreter/script/js.ml | 44 ++++++++++++++++++++++++++++-------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/interpreter/runtime/value.ml b/interpreter/runtime/value.ml index 84fb20535a..a9f162b220 100644 --- a/interpreter/runtime/value.ml +++ b/interpreter/runtime/value.ml @@ -93,23 +93,17 @@ let is_null_ref = function (* Typing *) let type_of_op = function - | I32 _ -> Types.I32T - | I64 _ -> Types.I64T - | F32 _ -> Types.F32T - | F64 _ -> Types.F64T - -let type_of_vecop = function - | V128 _ -> Types.V128T - -let type_of_num = function | I32 _ -> I32T | I64 _ -> I64T | F32 _ -> F32T | F64 _ -> F64T -let type_of_vec = function +let type_of_vecop = function | V128 _ -> V128T +let type_of_num = type_of_op +let type_of_vec = type_of_vecop + let type_of_ref' = ref (function _ -> assert false) let type_of_ref = function | NullRef t -> (Null, Match.bot_of_heap_type [] t) diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 6b57258c51..d5aa3a6010 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -289,8 +289,29 @@ let nan_bitmask_of = function | CanonicalNan -> abs_mask_of (* differ from canonical NaN in sign bit *) | ArithmeticNan -> canonical_nan_of (* 1 everywhere canonical NaN is *) +let type_of_num_pat = function + | NumPat num -> Value.type_of_num num.it + | NanPat op -> Value.type_of_op op.it + +let type_of_vec_pat = function + | VecPat vec -> Value.type_of_vec vec + +let type_of_ref_pat = function + | RefPat ref -> type_of_ref ref.it + | RefTypePat ht -> (NoNull, ht) + | NullPat -> (Null, BotHT) + +let type_of_result res = + match res.it with + | NumResult pat -> NumT (type_of_num_pat pat) + | VecResult pat -> VecT (type_of_vec_pat pat) + | RefResult pat -> RefT (type_of_ref_pat pat) + let assert_return ress ts at = let test (res, t) = + if not (Match.match_val_type [] t (type_of_result res)) then + [ Br (0l @@ at) @@ at ] + else match res.it with | NumResult (NumPat {it = num; at = at'}) -> let t', reinterpret = reinterpret_of (Value.type_of_op num) in @@ -357,7 +378,7 @@ let assert_return ress ts at = VecTest (V128 (V128.I8x16 V128Op.AllTrue)) @@ at; Test (I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] - | RefResult (RefPat {it = NullRef t; _}) -> + | RefResult (RefPat {it = NullRef _; _}) -> [ RefIsNull @@ at; Test (Value.I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] @@ -369,17 +390,16 @@ let assert_return ress ts at = BrIf (0l @@ at) @@ at ] | RefResult (RefPat _) -> assert false + | RefResult (RefTypePat ExternHT) -> + [ BrOnNull (0l @@ at) @@ at ] | RefResult (RefTypePat t) -> [ RefTest (NoNull, t) @@ at; Test (I32 I32Op.Eqz) @@ at; BrIf (0l @@ at) @@ at ] | RefResult NullPat -> - (match t with - | RefT _ -> - [ BrOnNull (0l @@ at) @@ at ] - | _ -> - [ Br (0l @@ at) @@ at ] - ) + [ RefIsNull @@ at; + Test (I32 I32Op.Eqz) @@ at; + BrIf (0l @@ at) @@ at ] in [], List.flatten (List.rev_map test (List.combine ress ts)) let i32 = NumT I32T @@ -426,10 +446,16 @@ let is_js_num_type = function | I32T -> true | I64T | F32T | F64T -> false +let is_js_vec_type = function + | _ -> false + +let is_js_ref_type = function + | _ -> true + let is_js_val_type = function | NumT t -> is_js_num_type t - | VecT _ -> false - | RefT _ -> true + | VecT t -> is_js_vec_type t + | RefT t -> is_js_ref_type t | BotT -> assert false let is_js_global_type = function From cd8b5c503a13e35e6eba5f514e89b6054ec83a0a Mon Sep 17 00:00:00 2001 From: Nick Fitzgerald Date: Tue, 23 Apr 2024 15:58:01 -0700 Subject: [PATCH 27/29] Fix i31.wast default table element assertions (#541) Copy-paste bug. Don't repeatedly assert the first element's value, but each element in the table. --- test/core/gc/i31.wast | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core/gc/i31.wast b/test/core/gc/i31.wast index 1d98abb655..7485650454 100644 --- a/test/core/gc/i31.wast +++ b/test/core/gc/i31.wast @@ -134,8 +134,8 @@ ) (assert_return (invoke "get" (i32.const 0)) (i32.const 42)) -(assert_return (invoke "get" (i32.const 0)) (i32.const 42)) -(assert_return (invoke "get" (i32.const 0)) (i32.const 42)) +(assert_return (invoke "get" (i32.const 1)) (i32.const 42)) +(assert_return (invoke "get" (i32.const 2)) (i32.const 42)) (module $i31ref_of_global_global_initializer (global $g0 (import "env" "g") i32) From beb8fb572c9d3ebf5c090a7c0e9a21c7b11893a0 Mon Sep 17 00:00:00 2001 From: Sam Clegg Date: Wed, 24 Apr 2024 15:03:24 -0700 Subject: [PATCH 28/29] [test] Remove stray tabs from test files (#1745) --- test/core/elem.wast | 10 +++++----- test/core/memory.wast | 40 ++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/test/core/elem.wast b/test/core/elem.wast index 33b3f67bc6..68a244b992 100644 --- a/test/core/elem.wast +++ b/test/core/elem.wast @@ -644,11 +644,11 @@ ;; Initializing a table with an externref-type element segment (module $m - (table $t (export "table") 2 externref) - (func (export "get") (param $i i32) (result externref) - (table.get $t (local.get $i))) - (func (export "set") (param $i i32) (param $x externref) - (table.set $t (local.get $i) (local.get $x)))) + (table $t (export "table") 2 externref) + (func (export "get") (param $i i32) (result externref) + (table.get $t (local.get $i))) + (func (export "set") (param $i i32) (param $x externref) + (table.set $t (local.get $i) (local.get $x)))) (register "exporter" $m) diff --git a/test/core/memory.wast b/test/core/memory.wast index 497b69fc94..6cd2560c6b 100644 --- a/test/core/memory.wast +++ b/test/core/memory.wast @@ -136,44 +136,44 @@ ;; Sign and zero extending memory loads (func (export "i32_load8_s") (param $i i32) (result i32) - (i32.store8 (i32.const 8) (local.get $i)) - (i32.load8_s (i32.const 8)) + (i32.store8 (i32.const 8) (local.get $i)) + (i32.load8_s (i32.const 8)) ) (func (export "i32_load8_u") (param $i i32) (result i32) - (i32.store8 (i32.const 8) (local.get $i)) - (i32.load8_u (i32.const 8)) + (i32.store8 (i32.const 8) (local.get $i)) + (i32.load8_u (i32.const 8)) ) (func (export "i32_load16_s") (param $i i32) (result i32) - (i32.store16 (i32.const 8) (local.get $i)) - (i32.load16_s (i32.const 8)) + (i32.store16 (i32.const 8) (local.get $i)) + (i32.load16_s (i32.const 8)) ) (func (export "i32_load16_u") (param $i i32) (result i32) - (i32.store16 (i32.const 8) (local.get $i)) - (i32.load16_u (i32.const 8)) + (i32.store16 (i32.const 8) (local.get $i)) + (i32.load16_u (i32.const 8)) ) (func (export "i64_load8_s") (param $i i64) (result i64) - (i64.store8 (i32.const 8) (local.get $i)) - (i64.load8_s (i32.const 8)) + (i64.store8 (i32.const 8) (local.get $i)) + (i64.load8_s (i32.const 8)) ) (func (export "i64_load8_u") (param $i i64) (result i64) - (i64.store8 (i32.const 8) (local.get $i)) - (i64.load8_u (i32.const 8)) + (i64.store8 (i32.const 8) (local.get $i)) + (i64.load8_u (i32.const 8)) ) (func (export "i64_load16_s") (param $i i64) (result i64) - (i64.store16 (i32.const 8) (local.get $i)) - (i64.load16_s (i32.const 8)) + (i64.store16 (i32.const 8) (local.get $i)) + (i64.load16_s (i32.const 8)) ) (func (export "i64_load16_u") (param $i i64) (result i64) - (i64.store16 (i32.const 8) (local.get $i)) - (i64.load16_u (i32.const 8)) + (i64.store16 (i32.const 8) (local.get $i)) + (i64.load16_u (i32.const 8)) ) (func (export "i64_load32_s") (param $i i64) (result i64) - (i64.store32 (i32.const 8) (local.get $i)) - (i64.load32_s (i32.const 8)) + (i64.store32 (i32.const 8) (local.get $i)) + (i64.load32_s (i32.const 8)) ) (func (export "i64_load32_u") (param $i i64) (result i64) - (i64.store32 (i32.const 8) (local.get $i)) - (i64.load32_u (i32.const 8)) + (i64.store32 (i32.const 8) (local.get $i)) + (i64.load32_u (i32.const 8)) ) ) From 242847319caa342faac3903c9107a851f11ac141 Mon Sep 17 00:00:00 2001 From: Andreas Rossberg Date: Sun, 28 Apr 2024 09:09:30 +0200 Subject: [PATCH 29/29] [spec] Check and fix cross-references (#1746) --- document/core/Makefile | 6 ++++- document/core/text/lexical.rst | 3 ++- document/core/text/modules.rst | 2 +- document/core/util/check_macros.sh | 32 ++++++++++++++++++++++++ document/core/util/macros.def | 40 ++++++++++-------------------- 5 files changed, 53 insertions(+), 30 deletions(-) create mode 100644 document/core/util/check_macros.sh diff --git a/document/core/Makefile b/document/core/Makefile index 74c9daeea6..3ac2f1c814 100644 --- a/document/core/Makefile +++ b/document/core/Makefile @@ -80,7 +80,7 @@ publish-main: clean main bikeshed-keep deploy all: pdf html bikeshed .PHONY: main -main: pdf html +main: macrosok pdf html # Dirty hack to avoid rebuilding the Bikeshed version for every push. .PHONY: bikeshed-keep @@ -97,6 +97,10 @@ GENERATED = appendix/index-instructions.rst %.rst: %.py (cd `dirname $@`; ./`basename $^`) +.PHONY: macrosok +macrosok: $(GENERATED) + sh util/check_macros.sh + .PHONY: pdf pdf: $(GENERATED) latexpdf mkdir -p $(BUILDDIR)/html/$(DOWNLOADDIR) diff --git a/document/core/text/lexical.rst b/document/core/text/lexical.rst index 4584b0c424..684688d49a 100644 --- a/document/core/text/lexical.rst +++ b/document/core/text/lexical.rst @@ -71,8 +71,9 @@ Any token that does not fall into any of the other categories is considered *res .. index:: ! white space, character, ASCII single: text format; white space -.. _text-format: .. _text-space: +.. _text-format: +.. _text-newline: White Space ~~~~~~~~~~~ diff --git a/document/core/text/modules.rst b/document/core/text/modules.rst index 5aab9b32cd..5be5ce8441 100644 --- a/document/core/text/modules.rst +++ b/document/core/text/modules.rst @@ -569,7 +569,7 @@ As another abbreviation, element segments may also be specified inline with :ref single: data; segment .. _text-datastring: .. _text-data: -.. _test-memuse: +.. _text-memuse: Data Segments ~~~~~~~~~~~~~ diff --git a/document/core/util/check_macros.sh b/document/core/util/check_macros.sh new file mode 100644 index 0000000000..46d9d76803 --- /dev/null +++ b/document/core/util/check_macros.sh @@ -0,0 +1,32 @@ +#!/bin/sh + +cd `dirname $0`/.. + +FILES=`ls */*.rst` +ERRORS=0 + +for XREF in `grep xref util/macros.def`; do + if echo $XREF | grep -q "[|]"; then + MACRO=`echo $XREF | sed 's/^[^|]*[|]//g' | sed 's/[|].*$//g'` + elif echo $XREF | grep -q xref; then + FILE=`echo $XREF | sed 's/^.*xref{//g' | sed 's/}.*$//g'`.rst + LABEL=`echo $XREF | sed 's/^[^}]*}{//g' | sed 's/}.*$//g'` + TARGET=".. _$LABEL:" + if ! [ -f $FILE ] || ! grep -q "$TARGET" $FILE; then + ERRORS=1 + echo Undefined cross-reference $FILE:$LABEL in macro "|$MACRO|" + if ! [ -f $FILE ]; then + echo ...non-existent file $FILE + fi + if grep -q "$TARGET" $FILES; then + echo ...defined in `grep -l "$TARGET" $FILES` + fi + fi + fi +done + +if [ $ERRORS -eq 0 ]; then + echo All cross-references okay. +else + exit 1; +fi diff --git a/document/core/util/macros.def b/document/core/util/macros.def index 1dcec42d2d..06b60fd6f4 100644 --- a/document/core/util/macros.def +++ b/document/core/util/macros.def @@ -177,8 +177,6 @@ .. |to| mathdef:: \xref{syntax/types}{syntax-functype}{\rightarrow} -.. |I8| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i8}} -.. |I16| mathdef:: \xref{exec/runtime}{syntax-storagetype}{\K{i16}} .. |I32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i32}} .. |I64| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{i64}} .. |F32| mathdef:: \xref{syntax/types}{syntax-valtype}{\K{f32}} @@ -227,8 +225,8 @@ .. |externtype| mathdef:: \xref{syntax/types}{syntax-externtype}{\X{externtype}} -.. |stacktype| mathdef:: \xref{syntax/types}{syntax-stacktype}{\X{stacktype}} -.. |opdtype| mathdef:: \xref{syntax/types}{syntax-opdtype}{\X{opdtype}} +.. |stacktype| mathdef:: \xref{valid/instructions}{syntax-stacktype}{\X{stacktype}} +.. |opdtype| mathdef:: \xref{valid/instructions}{syntax-opdtype}{\X{opdtype}} .. Types, meta functions @@ -523,9 +521,7 @@ .. |vunop| mathdef:: \xref{syntax/instructions}{syntax-vunop}{\X{vunop}} .. |vbinop| mathdef:: \xref{syntax/instructions}{syntax-vbinop}{\X{vbinop}} .. |vrelop| mathdef:: \xref{syntax/instructions}{syntax-vrelop}{\X{vrelop}} -.. |vternop| mathdef:: \xref{syntax/instructions}{syntax-vternop}{\X{vternop}} .. |vcvtop| mathdef:: \xref{syntax/instructions}{syntax-vcvtop}{\X{vcvtop}} -.. |vextmul| mathdef:: \xref{syntax/instructions}{syntax-vextmul}{\X{vextmul}} .. |laneidx| mathdef:: \xref{syntax/instructions}{syntax-laneidx}{\X{laneidx}} .. |vvunop| mathdef:: \xref{syntax/instructions}{syntax-vvunop}{\X{vvunop}} @@ -797,19 +793,10 @@ .. |Tlocalidx| mathdef:: \xref{text/modules}{text-localidx}{\T{localidx}} .. |Tlabelidx| mathdef:: \xref{text/modules}{text-labelidx}{\T{labelidx}} -.. |Ttypebind| mathdef:: \xref{text/modules}{text-typebind}{\T{typebind}} -.. |Tfuncbind| mathdef:: \xref{text/modules}{text-funcbind}{\T{funcbind}} -.. |Ttablebind| mathdef:: \xref{text/modules}{text-tablebind}{\T{tablebind}} -.. |Tmembind| mathdef:: \xref{text/modules}{text-membind}{\T{membind}} -.. |Tglobalbind| mathdef:: \xref{text/modules}{text-globalbind}{\T{globalbind}} -.. |Tlocalbind| mathdef:: \xref{text/modules}{text-localbind}{\T{localbind}} -.. |Tlabelbind| mathdef:: \xref{text/modules}{text-labelbind}{\T{labelbind}} - .. Modules, non-terminals .. |Tmodule| mathdef:: \xref{text/modules}{text-module}{\T{module}} -.. |Tmodulebody| mathdef:: \xref{text/modules}{text-modulebody}{\T{modulebody}} .. |Tmodulefield| mathdef:: \xref{text/modules}{text-modulefield}{\T{modulefield}} .. |Ttype| mathdef:: \xref{text/modules}{text-typedef}{\T{type}} .. |Ttypeuse| mathdef:: \xref{text/modules}{text-typeuse}{\T{typeuse}} @@ -825,7 +812,6 @@ .. |Telemlist| mathdef:: \xref{text/modules}{text-elemlist}{\T{elemlist}} .. |Telemexpr| mathdef:: \xref{text/modules}{text-elemexpr}{\T{elemexpr}} .. |Ttableuse| mathdef:: \xref{text/modules}{text-tableuse}{\T{tableuse}} -.. |Tcode| mathdef:: \xref{text/modules}{text-code}{\T{code}} .. |Tlocal| mathdef:: \xref{text/modules}{text-local}{\T{local}} .. |Tlocals| mathdef:: \xref{text/modules}{text-local}{\T{locals}} .. |Tdata| mathdef:: \xref{text/modules}{text-data}{\T{data}} @@ -940,10 +926,10 @@ .. Notation -.. |stepto| mathdef:: \xref{exec/conventions}{formal-notation}{\hookrightarrow} +.. |stepto| mathdef:: \xref{exec/conventions}{exec-notation}{\hookrightarrow} .. |extendsto| mathdef:: \xref{appendix/properties}{extend}{\preceq} -.. |matchesexterntype| mathdef:: \xref{exec/modules}{match-externtype}{\leq} -.. |matcheslimits| mathdef:: \xref{exec/modules}{match-limits}{\leq} +.. |matchesexterntype| mathdef:: \xref{valid/types}{match-externtype}{\leq} +.. |matcheslimits| mathdef:: \xref{valid/types}{match-limits}{\leq} .. Allocation @@ -1081,7 +1067,7 @@ .. Values & Results, non-terminals .. |num| mathdef:: \xref{exec/runtime}{syntax-num}{\X{num}} -.. |vecc| mathdef:: \xref{exec/runtime}{syntax-vec}{\X{vec}} +.. |vecc| mathdef:: \xref{exec/runtime}{syntax-vecc}{\X{vec}} .. |reff| mathdef:: \xref{exec/runtime}{syntax-ref}{\X{ref}} .. |val| mathdef:: \xref{exec/runtime}{syntax-val}{\X{val}} .. |result| mathdef:: \xref{exec/runtime}{syntax-result}{\X{result}} @@ -1144,10 +1130,10 @@ .. |imins| mathdef:: \xref{exec/numerics}{op-imin_s}{\F{imin\_s}} .. |imaxu| mathdef:: \xref{exec/numerics}{op-imax_u}{\F{imax\_u}} .. |imaxs| mathdef:: \xref{exec/numerics}{op-imax_s}{\F{imax\_s}} -.. |iaddsatu| mathdef:: \xref{exec/numerics}{op-iaddsat_u}{\F{iaddsat\_u}} -.. |iaddsats| mathdef:: \xref{exec/numerics}{op-iaddsat_s}{\F{iaddsat\_s}} -.. |isubsatu| mathdef:: \xref{exec/numerics}{op-isubsat_u}{\F{isubsat\_u}} -.. |isubsats| mathdef:: \xref{exec/numerics}{op-isubsat_s}{\F{isubsat\_s}} +.. |iaddsatu| mathdef:: \xref{exec/numerics}{op-iadd_sat_u}{\F{iadd\_sat\_u}} +.. |iaddsats| mathdef:: \xref{exec/numerics}{op-iadd_sat_s}{\F{iadd\_sat\_s}} +.. |isubsatu| mathdef:: \xref{exec/numerics}{op-isub_sat_u}{\F{isub\_sat\_u}} +.. |isubsats| mathdef:: \xref{exec/numerics}{op-isub_sat_s}{\F{isub\_sat\_s}} .. |iavgru| mathdef:: \xref{exec/numerics}{op-iavgr_u}{\F{iavgr\_u}} .. |iq15mulrsats| mathdef:: \xref{exec/numerics}{op-iq15mulrsat_s}{\F{iq15mulrsat\_s}} @@ -1223,8 +1209,8 @@ .. |vdashexternval| mathdef:: \xref{exec/modules}{valid-externval}{\vdash} -.. |vdashlimitsmatch| mathdef:: \xref{exec/modules}{match-limits}{\vdash} -.. |vdashexterntypematch| mathdef:: \xref{exec/modules}{match-externtype}{\vdash} +.. |vdashlimitsmatch| mathdef:: \xref{valid/types}{match-limits}{\vdash} +.. |vdashexterntypematch| mathdef:: \xref{valid/types}{match-externtype}{\vdash} .. Soundness @@ -1234,7 +1220,7 @@ .. |vdashadmininstr| mathdef:: \xref{appendix/properties}{valid-instr-admin}{\vdash} -.. |vdashval| mathdef:: \xref{appendix/properties}{valid-val}{\vdash} +.. |vdashval| mathdef:: \xref{exec/modules}{valid-val}{\vdash} .. |vdashresult| mathdef:: \xref{appendix/properties}{valid-result}{\vdash} .. |vdashfuncinst| mathdef:: \xref{appendix/properties}{valid-funcinst}{\vdash}