From cbc8527a4d9c4fc050738d072bfc00fb8573c8ab Mon Sep 17 00:00:00 2001 From: Andreas Haas Date: Fri, 29 Oct 2021 12:08:43 +0200 Subject: [PATCH 1/8] Make anyfunc an alias of funcref --- document/js-api/index.bs | 9 +++++---- interpreter/script/js.ml | 2 +- proposals/js-types/Overview.md | 4 ++-- test/js-api/table/constructor.any.js | 6 ++++++ 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 5fe37d01..0062f098 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -794,7 +794,7 @@ The type() method steps are:
 enum TableKind {
   "externref",
-  "anyfunc",
+  "funcref",
   // Note: More values may be added in future iterations,
   // e.g., typed function references, typed GC references
 };
@@ -848,7 +848,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
 
 The algorithm ToTableKind(|t|) performs the following steps:
 
-1. If |t| equals [=funcref=], return "{{TableKind/anyfunc}}".
+1. If |t| equals [=funcref=], return "{{TableKind/funcref}}".
 1. If |t| equals [=externref=], return "{{TableKind/externref}}".
 1. Assert: This step is not reached.
 
@@ -950,7 +950,7 @@ enum ValueType {
   "f32",
   "f64",
   "externref",
-  "anyfunc",
+  "funcref",
 };
 
@@ -1002,6 +1002,7 @@ which can be simultaneously referenced by multiple {{Instance}} objects. Each 1. If |s| equals "i64", return [=i64=]. 1. If |s| equals "f32", return [=f32=]. 1. If |s| equals "f64", return [=f64=]. + 1. If |s| equals "funcref", return [=funcref=]. 1. If |s| equals "anyfunc", return [=funcref=]. 1. If |s| equals "externref", return [=externref=]. 1. Assert: This step is not reached. @@ -1015,7 +1016,7 @@ The algorithm FromValueType(|s|) performs the following s 1. If |s| equals [=i64=], return "{{ValueType/i64}}". 1. If |s| equals [=f32=], return "{{ValueType/f32}}". 1. If |s| equals [=f64=], return "{{ValueType/f64}}". -1. If |s| equals [=funcref=], return "{{ValueType/anyfunc}}". +1. If |s| equals [=funcref=], return "{{ValueType/funcref}}". 1. If |s| equals [=externref=], return "{{ValueType/externref}}". 1. Assert: This step is not reached. diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml index 827c97a6..96d3707e 100644 --- a/interpreter/script/js.ml +++ b/interpreter/script/js.ml @@ -45,7 +45,7 @@ let spectest = { global_i64: 666n, global_f32: 666, global_f64: 666, - table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'anyfunc'}), + table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'funcref'}), memory: new WebAssembly.Memory({initial: 1, maximum: 2}) }; diff --git a/proposals/js-types/Overview.md b/proposals/js-types/Overview.md index 28a040be..1c863b2c 100644 --- a/proposals/js-types/Overview.md +++ b/proposals/js-types/Overview.md @@ -32,7 +32,7 @@ All Wasm types can be defined by a simple grammar. This grammar could be mapped ```TypeScript type ValueType = "i32" | "i64" | "f32" | "f64" -type ElemType = "anyfunc" +type ElemType = "funcref" type GlobalType = {value: ValueType, mutable: boolean} type MemoryType = {limits: Limits} type TableType = {limits: Limits, element: ElemType} @@ -200,7 +200,7 @@ function print(...args) { for (let x of args) console.log(x + "\n") } -let table = new Table({element: "anyfunc", minimum: 10}); +let table = new Table({element: "funcref", minimum: 10}); let print_i32 = new WebAssembly.Function({parameters: ["i32"], results: []}, print); table.set(0, print_i32); diff --git a/test/js-api/table/constructor.any.js b/test/js-api/table/constructor.any.js index e9e77a13..cfc73b2b 100644 --- a/test/js-api/table/constructor.any.js +++ b/test/js-api/table/constructor.any.js @@ -96,6 +96,12 @@ test(() => { assert_Table(table, { "length": 5 }); }, "Basic (non-zero)"); +test(() => { + const argument = { "element": "funcref", "initial": 5 }; + const table = new WebAssembly.Table(argument); + assert_Table(table, { "length": 5 }); +}, "Basic with 'funcref'"); + test(() => { const argument = { "element": "anyfunc", "initial": 0 }; const table = new WebAssembly.Table(argument, {}); From 5d432ee8731c7403a0f4f833b868844970c74e51 Mon Sep 17 00:00:00 2001 From: Andreas Haas Date: Fri, 29 Oct 2021 13:00:25 +0200 Subject: [PATCH 2/8] rename most anyfunc to funcref --- test/core/binary.wast | 6 +++--- test/harness/async_index.js | 2 +- test/harness/sync_index.js | 2 +- test/js-api/bad-imports.js | 2 +- test/js-api/instanceTestFactory.js | 2 +- test/js-api/limits.any.js | 4 ++-- test/js-api/prototypes.any.js | 2 +- test/js-api/table/constructor.any.js | 20 ++++++++++---------- test/js-api/table/get-set.any.js | 24 ++++++++++++------------ test/js-api/table/grow.any.js | 12 ++++++------ test/js-api/table/length.any.js | 6 +++--- test/js-api/table/toString.any.js | 2 +- test/meta/generate_memory_init.js | 2 +- 13 files changed, 43 insertions(+), 43 deletions(-) diff --git a/test/core/binary.wast b/test/core/binary.wast index c6f97557..c9ae9e19 100644 --- a/test/core/binary.wast +++ b/test/core/binary.wast @@ -1407,7 +1407,7 @@ (module binary "\00asm" "\01\00\00\00" "\05\03\01" ;; table section with one entry - "\70" ;; anyfunc + "\70" ;; funcref "\02" ;; malformed table limits flag ) "integer too large" @@ -1416,7 +1416,7 @@ (module binary "\00asm" "\01\00\00\00" "\05\04\01" ;; table section with one entry - "\70" ;; anyfunc + "\70" ;; funcref "\02" ;; malformed table limits flag "\00" ;; dummy byte ) @@ -1426,7 +1426,7 @@ (module binary "\00asm" "\01\00\00\00" "\05\06\01" ;; table section with one entry - "\70" ;; anyfunc + "\70" ;; funcref "\81\00" ;; malformed table limits flag as LEB128 "\00\00" ;; dummy bytes ) diff --git a/test/harness/async_index.js b/test/harness/async_index.js index c200019a..576886a6 100644 --- a/test/harness/async_index.js +++ b/test/harness/async_index.js @@ -103,7 +103,7 @@ function reinitializeRegistry() { table: new WebAssembly.Table({ initial: 10, maximum: 20, - element: "anyfunc" + element: "funcref" }), memory: new WebAssembly.Memory({ initial: 1, maximum: 2 }) }; diff --git a/test/harness/sync_index.js b/test/harness/sync_index.js index 7ed9f291..d76a42df 100644 --- a/test/harness/sync_index.js +++ b/test/harness/sync_index.js @@ -110,7 +110,7 @@ function reinitializeRegistry() { global_i32: 666, global_f32: 666, global_f64: 666, - table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'anyfunc'}), + table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'funcref'}), memory: new WebAssembly.Memory({initial: 1, maximum: 2}) }; let handler = { diff --git a/test/js-api/bad-imports.js b/test/js-api/bad-imports.js index 786fc650..7f005eb1 100644 --- a/test/js-api/bad-imports.js +++ b/test/js-api/bad-imports.js @@ -167,7 +167,7 @@ function test_bad_imports(t) { [WebAssembly.Table, "WebAssembly.Table"], [WebAssembly.Table.prototype, "WebAssembly.Table.prototype"], [Object.create(WebAssembly.Table.prototype), "Object.create(WebAssembly.Table.prototype)"], - [new WebAssembly.Table({"element": "anyfunc", "initial": 256}), "WebAssembly.Table object (too large)"], + [new WebAssembly.Table({"element": "funcref", "initial": 256}), "WebAssembly.Table object (too large)"], ]; for (const [value, name = format_value(value)] of nonTables) { diff --git a/test/js-api/instanceTestFactory.js b/test/js-api/instanceTestFactory.js index 86f593f4..6bd91c66 100644 --- a/test/js-api/instanceTestFactory.js +++ b/test/js-api/instanceTestFactory.js @@ -110,7 +110,7 @@ const instanceTestFactory = [ "fn": function() {}, "global": 0, "memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }), - "table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }), + "table": new WebAssembly.Table({ "element": "funcref", "initial": 64, maximum: 128 }), }, get "module2"() { assert_unreached("Should not get modules that are not imported"); diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js index 7e690cad..4fdbbf64 100644 --- a/test/js-api/limits.any.js +++ b/test/js-api/limits.any.js @@ -236,10 +236,10 @@ test(() => { assert_throws( new RangeError(), () => new WebAssembly.Table( - {element : "anyfunc", initial : kJSEmbeddingMaxTableSize + 1})); + {element : "funcref", initial : kJSEmbeddingMaxTableSize + 1})); let memory = new WebAssembly.Table( - {initial : 1, maximum : kJSEmbeddingMaxTableSize + 1, element: "anyfunc"}); + {initial : 1, maximum : kJSEmbeddingMaxTableSize + 1, element: "funcref"}); assert_throws(new RangeError(), () => memory.grow(kJSEmbeddingMaxTableSize)); }, `Grow WebAssembly.Table object beyond the embedder-defined limit`); diff --git a/test/js-api/prototypes.any.js b/test/js-api/prototypes.any.js index 714f4f84..6d20d735 100644 --- a/test/js-api/prototypes.any.js +++ b/test/js-api/prototypes.any.js @@ -30,7 +30,7 @@ test(() => { test(() => { class _Table extends WebAssembly.Table {} - let table = new _Table({initial: 0, element: "anyfunc"}); + let table = new _Table({initial: 0, element: "funcref"}); assert_true(table instanceof _Table, "_Table instanceof _Table"); assert_true(table instanceof WebAssembly.Table, "_Table instanceof WebAssembly.Table"); }, "_Table"); diff --git a/test/js-api/table/constructor.any.js b/test/js-api/table/constructor.any.js index cfc73b2b..ceeeccfb 100644 --- a/test/js-api/table/constructor.any.js +++ b/test/js-api/table/constructor.any.js @@ -25,7 +25,7 @@ test(() => { }, "No arguments"); test(() => { - const argument = { "element": "anyfunc", "initial": 0 }; + const argument = { "element": "funcref", "initial": 0 }; assert_throws_js(TypeError, () => WebAssembly.Table(argument)); }, "Calling"); @@ -54,7 +54,7 @@ test(() => { }, "Invalid descriptor argument"); test(() => { - assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": undefined })); + assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "funcref", "initial": undefined })); }, "Undefined initial value in descriptor"); test(() => { @@ -72,20 +72,20 @@ const outOfRangeValues = [ for (const value of outOfRangeValues) { test(() => { - assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": value })); + assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "funcref", "initial": value })); }, `Out-of-range initial value in descriptor: ${format_value(value)}`); test(() => { - assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value })); + assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "funcref", "initial": 0, "maximum": value })); }, `Out-of-range maximum value in descriptor: ${format_value(value)}`); } test(() => { - assert_throws_js(RangeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": 10, "maximum": 9 })); + assert_throws_js(RangeError, () => new WebAssembly.Table({ "element": "funcref", "initial": 10, "maximum": 9 })); }, "Initial value exceeds maximum"); test(() => { - const argument = { "element": "anyfunc", "initial": 0 }; + const argument = { "element": "funcref", "initial": 0 }; const table = new WebAssembly.Table(argument); assert_Table(table, { "length": 0 }); }, "Basic (zero)"); @@ -103,7 +103,7 @@ test(() => { }, "Basic with 'funcref'"); test(() => { - const argument = { "element": "anyfunc", "initial": 0 }; + const argument = { "element": "funcref", "initial": 0 }; const table = new WebAssembly.Table(argument, {}); assert_Table(table, { "length": 0 }); }, "Stray argument"); @@ -116,7 +116,7 @@ test(() => { get(o, x) { switch (x) { case "element": - return "anyfunc"; + return "funcref"; case "initial": case "maximum": return 0; @@ -132,7 +132,7 @@ test(() => { test(() => { const table = new WebAssembly.Table({ "element": { - toString() { return "anyfunc"; }, + toString() { return "funcref"; }, }, "initial": 1, }); @@ -168,7 +168,7 @@ test(() => { return { toString() { order.push("element toString"); - return "anyfunc"; + return "funcref"; }, }; }, diff --git a/test/js-api/table/get-set.any.js b/test/js-api/table/get-set.any.js index 2e16346c..e21e09f5 100644 --- a/test/js-api/table/get-set.any.js +++ b/test/js-api/table/get-set.any.js @@ -22,7 +22,7 @@ setup(() => { }); test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_throws_js(TypeError, () => table.get()); }, "Missing arguments: get"); @@ -53,7 +53,7 @@ test(t => { }, "Branding: get"); test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_throws_js(TypeError, () => table.set()); assert_throws_js(TypeError, () => table.set(0)); @@ -85,7 +85,7 @@ test(t => { }, "Branding: set"); test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, [null, null, null, null, null]); @@ -102,7 +102,7 @@ test(() => { }, "Basic"); test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, [null, null, null, null, null]); @@ -120,7 +120,7 @@ test(() => { }, "Growing"); test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, [null, null, null, null, null]); @@ -134,7 +134,7 @@ test(() => { }, "Setting out-of-bounds"); test(() => { - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, [null]); @@ -156,7 +156,7 @@ test(() => { }, "Setting non-function"); test(() => { - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, [null]); @@ -166,7 +166,7 @@ test(() => { }, "Setting non-wasm function"); test(() => { - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, [null]); @@ -189,20 +189,20 @@ const outOfRangeValues = [ for (const value of outOfRangeValues) { test(() => { - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); assert_throws_js(TypeError, () => table.get(value)); }, `Getting out-of-range argument: ${format_value(value)}`); test(() => { - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); assert_throws_js(TypeError, () => table.set(value, null)); }, `Setting out-of-range argument: ${format_value(value)}`); } test(() => { - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); let called = 0; const value = { @@ -217,7 +217,7 @@ test(() => { test(() => { const {fn} = functions; - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); assert_equals(table.get(0, {}), null); diff --git a/test/js-api/table/grow.any.js b/test/js-api/table/grow.any.js index 3b2ee5fa..43c83d0e 100644 --- a/test/js-api/table/grow.any.js +++ b/test/js-api/table/grow.any.js @@ -6,7 +6,7 @@ function nulls(n) { } test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_throws_js(TypeError, () => table.grow()); }, "Missing arguments"); @@ -37,7 +37,7 @@ test(t => { }, "Branding"); test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, nulls(5), "before"); @@ -47,7 +47,7 @@ test(() => { }, "Basic"); test(() => { - const argument = { "element": "anyfunc", "initial": 3, "maximum": 5 }; + const argument = { "element": "funcref", "initial": 3, "maximum": 5 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, nulls(3), "before"); @@ -57,7 +57,7 @@ test(() => { }, "Reached maximum"); test(() => { - const argument = { "element": "anyfunc", "initial": 2, "maximum": 5 }; + const argument = { "element": "funcref", "initial": 2, "maximum": 5 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, nulls(2), "before"); @@ -79,14 +79,14 @@ const outOfRangeValues = [ for (const value of outOfRangeValues) { test(() => { - const argument = { "element": "anyfunc", "initial": 1 }; + const argument = { "element": "funcref", "initial": 1 }; const table = new WebAssembly.Table(argument); assert_throws_js(TypeError, () => table.grow(value)); }, `Out-of-range argument: ${format_value(value)}`); } test(() => { - const argument = { "element": "anyfunc", "initial": 5 }; + const argument = { "element": "funcref", "initial": 5 }; const table = new WebAssembly.Table(argument); assert_equal_to_array(table, nulls(5), "before"); diff --git a/test/js-api/table/length.any.js b/test/js-api/table/length.any.js index a9ef095d..c2120242 100644 --- a/test/js-api/table/length.any.js +++ b/test/js-api/table/length.any.js @@ -27,7 +27,7 @@ test(() => { }, "Branding"); test(() => { - const argument = { "element": "anyfunc", "initial": 2 }; + const argument = { "element": "funcref", "initial": 2 }; const table = new WebAssembly.Table(argument); assert_equals(table.length, 2, "Initial length"); @@ -41,7 +41,7 @@ test(() => { }, "Stray argument"); test(() => { - const argument = { "element": "anyfunc", "initial": 2 }; + const argument = { "element": "funcref", "initial": 2 }; const table = new WebAssembly.Table(argument); assert_equals(table.length, 2, "Initial length"); table.length = 4; @@ -49,7 +49,7 @@ test(() => { }, "Setting (sloppy mode)"); test(() => { - const argument = { "element": "anyfunc", "initial": 2 }; + const argument = { "element": "funcref", "initial": 2 }; const table = new WebAssembly.Table(argument); assert_equals(table.length, 2, "Initial length"); assert_throws_js(TypeError, () => { diff --git a/test/js-api/table/toString.any.js b/test/js-api/table/toString.any.js index 8a09f283..49c58ff4 100644 --- a/test/js-api/table/toString.any.js +++ b/test/js-api/table/toString.any.js @@ -1,7 +1,7 @@ // META: global=window,dedicatedworker,jsshell test(() => { - const argument = { "element": "anyfunc", "initial": 0 }; + const argument = { "element": "funcref", "initial": 0 }; const table = new WebAssembly.Table(argument); assert_class_string(table, "WebAssembly.Table"); }, "Object.prototype.toString on an Table"); diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js index 64fb07f9..de5ced37 100644 --- a/test/meta/generate_memory_init.js +++ b/test/meta/generate_memory_init.js @@ -219,7 +219,7 @@ print( (assert_trap (invoke "test") "out of bounds") `); -// invalid argument types. TODO: can add anyfunc etc here. +// invalid argument types. TODO: can add funcref etc here. { const tys = ['i32', 'f32', 'i64', 'f64']; From e411acbde74ce1887a47d056140547b18f25ff84 Mon Sep 17 00:00:00 2001 From: Andreas Haas Date: Fri, 29 Oct 2021 14:19:45 +0200 Subject: [PATCH 3/8] address comments --- document/js-api/index.bs | 4 ++-- interpreter/script/js.ml | 2 +- test/core/binary.wast | 6 +++--- test/harness/async_index.js | 2 +- test/harness/sync_index.js | 2 +- test/js-api/bad-imports.js | 2 +- test/js-api/instanceTestFactory.js | 2 +- test/js-api/limits.any.js | 4 ++-- test/js-api/prototypes.any.js | 2 +- test/js-api/table/constructor.any.js | 20 ++++++++++---------- test/js-api/table/get-set.any.js | 24 ++++++++++++------------ test/js-api/table/grow.any.js | 12 ++++++------ test/js-api/table/length.any.js | 6 +++--- test/js-api/table/toString.any.js | 2 +- test/meta/generate_memory_init.js | 2 +- 15 files changed, 46 insertions(+), 46 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 0062f098..93e82436 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -794,7 +794,7 @@ The type() method steps are:
 enum TableKind {
   "externref",
-  "funcref",
+  "anyfunc",
   // Note: More values may be added in future iterations,
   // e.g., typed function references, typed GC references
 };
@@ -848,7 +848,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address
 
 The algorithm ToTableKind(|t|) performs the following steps:
 
-1. If |t| equals [=funcref=], return "{{TableKind/funcref}}".
+1. If |t| equals [=funcref=], return "{{TableKind/anyfunc}}".
 1. If |t| equals [=externref=], return "{{TableKind/externref}}".
 1. Assert: This step is not reached.
 
diff --git a/interpreter/script/js.ml b/interpreter/script/js.ml
index 96d3707e..827c97a6 100644
--- a/interpreter/script/js.ml
+++ b/interpreter/script/js.ml
@@ -45,7 +45,7 @@ let spectest = {
   global_i64: 666n,
   global_f32: 666,
   global_f64: 666,
-  table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'funcref'}),
+  table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'anyfunc'}),
   memory: new WebAssembly.Memory({initial: 1, maximum: 2})
 };
 
diff --git a/test/core/binary.wast b/test/core/binary.wast
index c9ae9e19..c6f97557 100644
--- a/test/core/binary.wast
+++ b/test/core/binary.wast
@@ -1407,7 +1407,7 @@
   (module binary
       "\00asm" "\01\00\00\00"
       "\05\03\01"                           ;; table section with one entry
-      "\70"                                 ;; funcref
+      "\70"                                 ;; anyfunc
       "\02"                                 ;; malformed table limits flag
   )
   "integer too large"
@@ -1416,7 +1416,7 @@
   (module binary
       "\00asm" "\01\00\00\00"
       "\05\04\01"                           ;; table section with one entry
-      "\70"                                 ;; funcref
+      "\70"                                 ;; anyfunc
       "\02"                                 ;; malformed table limits flag
       "\00"                                 ;; dummy byte
   )
@@ -1426,7 +1426,7 @@
   (module binary
       "\00asm" "\01\00\00\00"
       "\05\06\01"                           ;; table section with one entry
-      "\70"                                 ;; funcref
+      "\70"                                 ;; anyfunc
       "\81\00"                              ;; malformed table limits flag as LEB128
       "\00\00"                              ;; dummy bytes
   )
diff --git a/test/harness/async_index.js b/test/harness/async_index.js
index 576886a6..c200019a 100644
--- a/test/harness/async_index.js
+++ b/test/harness/async_index.js
@@ -103,7 +103,7 @@ function reinitializeRegistry() {
       table: new WebAssembly.Table({
         initial: 10,
         maximum: 20,
-        element: "funcref"
+        element: "anyfunc"
       }),
       memory: new WebAssembly.Memory({ initial: 1, maximum: 2 })
     };
diff --git a/test/harness/sync_index.js b/test/harness/sync_index.js
index d76a42df..7ed9f291 100644
--- a/test/harness/sync_index.js
+++ b/test/harness/sync_index.js
@@ -110,7 +110,7 @@ function reinitializeRegistry() {
         global_i32: 666,
         global_f32: 666,
         global_f64: 666,
-        table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'funcref'}),
+        table: new WebAssembly.Table({initial: 10, maximum: 20, element: 'anyfunc'}),
         memory: new WebAssembly.Memory({initial: 1, maximum: 2})
     };
     let handler = {
diff --git a/test/js-api/bad-imports.js b/test/js-api/bad-imports.js
index 7f005eb1..786fc650 100644
--- a/test/js-api/bad-imports.js
+++ b/test/js-api/bad-imports.js
@@ -167,7 +167,7 @@ function test_bad_imports(t) {
     [WebAssembly.Table, "WebAssembly.Table"],
     [WebAssembly.Table.prototype, "WebAssembly.Table.prototype"],
     [Object.create(WebAssembly.Table.prototype), "Object.create(WebAssembly.Table.prototype)"],
-    [new WebAssembly.Table({"element": "funcref", "initial": 256}), "WebAssembly.Table object (too large)"],
+    [new WebAssembly.Table({"element": "anyfunc", "initial": 256}), "WebAssembly.Table object (too large)"],
   ];
 
   for (const [value, name = format_value(value)] of nonTables) {
diff --git a/test/js-api/instanceTestFactory.js b/test/js-api/instanceTestFactory.js
index 6bd91c66..86f593f4 100644
--- a/test/js-api/instanceTestFactory.js
+++ b/test/js-api/instanceTestFactory.js
@@ -110,7 +110,7 @@ const instanceTestFactory = [
           "fn": function() {},
           "global": 0,
           "memory": new WebAssembly.Memory({ "initial": 64, maximum: 128 }),
-          "table": new WebAssembly.Table({ "element": "funcref", "initial": 64, maximum: 128 }),
+          "table": new WebAssembly.Table({ "element": "anyfunc", "initial": 64, maximum: 128 }),
         },
         get "module2"() {
           assert_unreached("Should not get modules that are not imported");
diff --git a/test/js-api/limits.any.js b/test/js-api/limits.any.js
index 4fdbbf64..7e690cad 100644
--- a/test/js-api/limits.any.js
+++ b/test/js-api/limits.any.js
@@ -236,10 +236,10 @@ test(() => {
   assert_throws(
       new RangeError(),
       () => new WebAssembly.Table(
-          {element : "funcref", initial : kJSEmbeddingMaxTableSize + 1}));
+          {element : "anyfunc", initial : kJSEmbeddingMaxTableSize + 1}));
 
   let memory = new WebAssembly.Table(
-      {initial : 1, maximum : kJSEmbeddingMaxTableSize + 1, element: "funcref"});
+      {initial : 1, maximum : kJSEmbeddingMaxTableSize + 1, element: "anyfunc"});
   assert_throws(new RangeError(),
                 () => memory.grow(kJSEmbeddingMaxTableSize));
 }, `Grow WebAssembly.Table object beyond the embedder-defined limit`);
diff --git a/test/js-api/prototypes.any.js b/test/js-api/prototypes.any.js
index 6d20d735..714f4f84 100644
--- a/test/js-api/prototypes.any.js
+++ b/test/js-api/prototypes.any.js
@@ -30,7 +30,7 @@ test(() => {
 
 test(() => {
   class _Table extends WebAssembly.Table {}
-  let table = new _Table({initial: 0, element: "funcref"});
+  let table = new _Table({initial: 0, element: "anyfunc"});
   assert_true(table instanceof _Table, "_Table instanceof _Table");
   assert_true(table instanceof WebAssembly.Table, "_Table instanceof WebAssembly.Table");
 }, "_Table");
diff --git a/test/js-api/table/constructor.any.js b/test/js-api/table/constructor.any.js
index ceeeccfb..cfc73b2b 100644
--- a/test/js-api/table/constructor.any.js
+++ b/test/js-api/table/constructor.any.js
@@ -25,7 +25,7 @@ test(() => {
 }, "No arguments");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 0 };
+  const argument = { "element": "anyfunc", "initial": 0 };
   assert_throws_js(TypeError, () => WebAssembly.Table(argument));
 }, "Calling");
 
@@ -54,7 +54,7 @@ test(() => {
 }, "Invalid descriptor argument");
 
 test(() => {
-  assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "funcref", "initial": undefined }));
+  assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": undefined }));
 }, "Undefined initial value in descriptor");
 
 test(() => {
@@ -72,20 +72,20 @@ const outOfRangeValues = [
 
 for (const value of outOfRangeValues) {
   test(() => {
-    assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "funcref", "initial": value }));
+    assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": value }));
   }, `Out-of-range initial value in descriptor: ${format_value(value)}`);
 
   test(() => {
-    assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "funcref", "initial": 0, "maximum": value }));
+    assert_throws_js(TypeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": 0, "maximum": value }));
   }, `Out-of-range maximum value in descriptor: ${format_value(value)}`);
 }
 
 test(() => {
-  assert_throws_js(RangeError, () => new WebAssembly.Table({ "element": "funcref", "initial": 10, "maximum": 9 }));
+  assert_throws_js(RangeError, () => new WebAssembly.Table({ "element": "anyfunc", "initial": 10, "maximum": 9 }));
 }, "Initial value exceeds maximum");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 0 };
+  const argument = { "element": "anyfunc", "initial": 0 };
   const table = new WebAssembly.Table(argument);
   assert_Table(table, { "length": 0 });
 }, "Basic (zero)");
@@ -103,7 +103,7 @@ test(() => {
 }, "Basic with 'funcref'");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 0 };
+  const argument = { "element": "anyfunc", "initial": 0 };
   const table = new WebAssembly.Table(argument, {});
   assert_Table(table, { "length": 0 });
 }, "Stray argument");
@@ -116,7 +116,7 @@ test(() => {
     get(o, x) {
       switch (x) {
       case "element":
-        return "funcref";
+        return "anyfunc";
       case "initial":
       case "maximum":
         return 0;
@@ -132,7 +132,7 @@ test(() => {
 test(() => {
   const table = new WebAssembly.Table({
     "element": {
-      toString() { return "funcref"; },
+      toString() { return "anyfunc"; },
     },
     "initial": 1,
   });
@@ -168,7 +168,7 @@ test(() => {
       return {
         toString() {
           order.push("element toString");
-          return "funcref";
+          return "anyfunc";
         },
       };
     },
diff --git a/test/js-api/table/get-set.any.js b/test/js-api/table/get-set.any.js
index e21e09f5..2e16346c 100644
--- a/test/js-api/table/get-set.any.js
+++ b/test/js-api/table/get-set.any.js
@@ -22,7 +22,7 @@ setup(() => {
 });
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_throws_js(TypeError, () => table.get());
 }, "Missing arguments: get");
@@ -53,7 +53,7 @@ test(t => {
 }, "Branding: get");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_throws_js(TypeError, () => table.set());
   assert_throws_js(TypeError, () => table.set(0));
@@ -85,7 +85,7 @@ test(t => {
 }, "Branding: set");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null, null, null, null, null]);
 
@@ -102,7 +102,7 @@ test(() => {
 }, "Basic");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null, null, null, null, null]);
 
@@ -120,7 +120,7 @@ test(() => {
 }, "Growing");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null, null, null, null, null]);
 
@@ -134,7 +134,7 @@ test(() => {
 }, "Setting out-of-bounds");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 1 };
+  const argument = { "element": "anyfunc", "initial": 1 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null]);
 
@@ -156,7 +156,7 @@ test(() => {
 }, "Setting non-function");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 1 };
+  const argument = { "element": "anyfunc", "initial": 1 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null]);
 
@@ -166,7 +166,7 @@ test(() => {
 }, "Setting non-wasm function");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 1 };
+  const argument = { "element": "anyfunc", "initial": 1 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, [null]);
 
@@ -189,20 +189,20 @@ const outOfRangeValues = [
 
 for (const value of outOfRangeValues) {
   test(() => {
-    const argument = { "element": "funcref", "initial": 1 };
+    const argument = { "element": "anyfunc", "initial": 1 };
     const table = new WebAssembly.Table(argument);
     assert_throws_js(TypeError, () => table.get(value));
   }, `Getting out-of-range argument: ${format_value(value)}`);
 
   test(() => {
-    const argument = { "element": "funcref", "initial": 1 };
+    const argument = { "element": "anyfunc", "initial": 1 };
     const table = new WebAssembly.Table(argument);
     assert_throws_js(TypeError, () => table.set(value, null));
   }, `Setting out-of-range argument: ${format_value(value)}`);
 }
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 1 };
+  const argument = { "element": "anyfunc", "initial": 1 };
   const table = new WebAssembly.Table(argument);
   let called = 0;
   const value = {
@@ -217,7 +217,7 @@ test(() => {
 
 test(() => {
   const {fn} = functions;
-  const argument = { "element": "funcref", "initial": 1 };
+  const argument = { "element": "anyfunc", "initial": 1 };
   const table = new WebAssembly.Table(argument);
 
   assert_equals(table.get(0, {}), null);
diff --git a/test/js-api/table/grow.any.js b/test/js-api/table/grow.any.js
index 43c83d0e..3b2ee5fa 100644
--- a/test/js-api/table/grow.any.js
+++ b/test/js-api/table/grow.any.js
@@ -6,7 +6,7 @@ function nulls(n) {
 }
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_throws_js(TypeError, () => table.grow());
 }, "Missing arguments");
@@ -37,7 +37,7 @@ test(t => {
 }, "Branding");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, nulls(5), "before");
 
@@ -47,7 +47,7 @@ test(() => {
 }, "Basic");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 3, "maximum": 5 };
+  const argument = { "element": "anyfunc", "initial": 3, "maximum": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, nulls(3), "before");
 
@@ -57,7 +57,7 @@ test(() => {
 }, "Reached maximum");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 2, "maximum": 5 };
+  const argument = { "element": "anyfunc", "initial": 2, "maximum": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, nulls(2), "before");
 
@@ -79,14 +79,14 @@ const outOfRangeValues = [
 
 for (const value of outOfRangeValues) {
   test(() => {
-    const argument = { "element": "funcref", "initial": 1 };
+    const argument = { "element": "anyfunc", "initial": 1 };
     const table = new WebAssembly.Table(argument);
     assert_throws_js(TypeError, () => table.grow(value));
   }, `Out-of-range argument: ${format_value(value)}`);
 }
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 5 };
+  const argument = { "element": "anyfunc", "initial": 5 };
   const table = new WebAssembly.Table(argument);
   assert_equal_to_array(table, nulls(5), "before");
 
diff --git a/test/js-api/table/length.any.js b/test/js-api/table/length.any.js
index c2120242..a9ef095d 100644
--- a/test/js-api/table/length.any.js
+++ b/test/js-api/table/length.any.js
@@ -27,7 +27,7 @@ test(() => {
 }, "Branding");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 2 };
+  const argument = { "element": "anyfunc", "initial": 2 };
   const table = new WebAssembly.Table(argument);
   assert_equals(table.length, 2, "Initial length");
 
@@ -41,7 +41,7 @@ test(() => {
 }, "Stray argument");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 2 };
+  const argument = { "element": "anyfunc", "initial": 2 };
   const table = new WebAssembly.Table(argument);
   assert_equals(table.length, 2, "Initial length");
   table.length = 4;
@@ -49,7 +49,7 @@ test(() => {
 }, "Setting (sloppy mode)");
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 2 };
+  const argument = { "element": "anyfunc", "initial": 2 };
   const table = new WebAssembly.Table(argument);
   assert_equals(table.length, 2, "Initial length");
   assert_throws_js(TypeError, () => {
diff --git a/test/js-api/table/toString.any.js b/test/js-api/table/toString.any.js
index 49c58ff4..8a09f283 100644
--- a/test/js-api/table/toString.any.js
+++ b/test/js-api/table/toString.any.js
@@ -1,7 +1,7 @@
 // META: global=window,dedicatedworker,jsshell
 
 test(() => {
-  const argument = { "element": "funcref", "initial": 0 };
+  const argument = { "element": "anyfunc", "initial": 0 };
   const table = new WebAssembly.Table(argument);
   assert_class_string(table, "WebAssembly.Table");
 }, "Object.prototype.toString on an Table");
diff --git a/test/meta/generate_memory_init.js b/test/meta/generate_memory_init.js
index de5ced37..64fb07f9 100644
--- a/test/meta/generate_memory_init.js
+++ b/test/meta/generate_memory_init.js
@@ -219,7 +219,7 @@ print(
 (assert_trap (invoke "test") "out of bounds")
 `);
 
-// invalid argument types.  TODO: can add funcref etc here.
+// invalid argument types.  TODO: can add anyfunc etc here.
 {
     const tys  = ['i32', 'f32', 'i64', 'f64'];
 

From 6402a3025be6694b77ac1a93235125f4f4cd12d6 Mon Sep 17 00:00:00 2001
From: Andreas Haas 
Date: Mon, 15 Nov 2021 14:58:47 +0100
Subject: [PATCH 4/8] Add more tests

---
 document/js-api/index.bs              |  1 +
 test/js-api/global/constructor.any.js | 12 ++++
 test/js-api/global/type.any.js        | 83 +++++++++++++++++++++++++++
 test/js-api/module/exports.any.js     | 53 ++++++++++++++---
 test/js-api/module/imports.any.js     | 40 +++++++++++--
 test/js-api/table/type.any.js         | 42 ++++++++++++++
 6 files changed, 220 insertions(+), 11 deletions(-)
 create mode 100644 test/js-api/global/type.any.js
 create mode 100644 test/js-api/table/type.any.js

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 93e82436..488f1b52 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -795,6 +795,7 @@ The type() method steps are:
 enum TableKind {
   "externref",
   "anyfunc",
+  "funcref",
   // Note: More values may be added in future iterations,
   // e.g., typed function references, typed GC references
 };
diff --git a/test/js-api/global/constructor.any.js b/test/js-api/global/constructor.any.js
index f536f5d7..4e123164 100644
--- a/test/js-api/global/constructor.any.js
+++ b/test/js-api/global/constructor.any.js
@@ -164,3 +164,15 @@ test(() => {
   const global = new WebAssembly.Global(argument, 0, {});
   assert_Global(global, 0);
 }, "Stray argument");
+
+test(() => {
+  const argument = { "value": "anyfunc" };
+  const global = new WebAssembly.Global(argument);
+  assert_Global(global, null);
+}, "funcref with default");
+
+test(() => {
+  const argument = { "value": "funcref" };
+  const global = new WebAssembly.Global(argument);
+  assert_Global(global, null);
+}, "funcref with default");
diff --git a/test/js-api/global/type.any.js b/test/js-api/global/type.any.js
new file mode 100644
index 00000000..68a51fba
--- /dev/null
+++ b/test/js-api/global/type.any.js
@@ -0,0 +1,83 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/assertions.js
+
+function assert_type(argument) {
+    const myglobal = new WebAssembly.Global(argument);
+    const globaltype = myglobal.type();
+
+    assert_equals(globaltype.value, argument.value);
+    assert_equals(globaltype.mutable, argument.mutable);
+}
+
+test(() => {
+    assert_type({ "value": "i32", "mutable": true});
+}, "i32, mutable");
+
+test(() => {
+    assert_type({ "value": "i32", "mutable": false});
+}, "i32, immutable");
+
+test(() => {
+    assert_type({ "value": "i64", "mutable": true});
+}, "i64, mutable");
+
+test(() => {
+    assert_type({ "value": "i64", "mutable": false});
+}, "i64, immutable");
+
+test(() => {
+    assert_type({ "value": "f32", "mutable": true});
+}, "f32, mutable");
+
+test(() => {
+    assert_type({ "value": "f32", "mutable": false});
+}, "f32, immutable");
+
+test(() => {
+    assert_type({ "value": "f64", "mutable": true});
+}, "f64, mutable");
+
+test(() => {
+    assert_type({ "value": "f64", "mutable": false});
+}, "f64, immutable");
+
+test(() => {
+    assert_type({"value": "externref", "mutable": true})
+}, "externref, mutable")
+
+test(() => {
+    assert_type({"value": "externref", "mutable": false})
+}, "externref, immutable")
+
+test(() => {
+    const argument = {"value": "anyfunc", "mutable": true};
+    const myglobal = new WebAssembly.Global(argument);
+    const globaltype = myglobal.type();
+
+    assert_equals(globaltype.value, "funcref");
+    assert_equals(globaltype.mutable, argument.mutable);
+}, "anyfunc, mutable")
+
+test(() => {
+    const argument = {"value": "anyfunc", "mutable": false};
+    const myglobal = new WebAssembly.Global(argument);
+    const globaltype = myglobal.type();
+
+    assert_equals(globaltype.value, "funcref");
+    assert_equals(globaltype.mutable, argument.mutable);
+}, "anyfunc, immutable")
+
+test(() => {
+    assert_type({"value": "funcref", "mutable": true})
+}, "funcref, mutable")
+
+test(() => {
+    assert_type({"value": "funcref", "mutable": false})
+}, "funcref, immutable")
+
+test(() => {
+    const myglobal = new WebAssembly.Global({"value": "i32", "mutable": true});
+    const propertyNames = Object.getOwnPropertyNames(myglobal.type());
+    assert_equals(propertyNames[0], "mutable");
+    assert_equals(propertyNames[1], "value");
+}, "key ordering");
diff --git a/test/js-api/module/exports.any.js b/test/js-api/module/exports.any.js
index 60b2c04f..4a6aaad8 100644
--- a/test/js-api/module/exports.any.js
+++ b/test/js-api/module/exports.any.js
@@ -21,6 +21,15 @@ function assert_ModuleExportDescriptor(export_, expected) {
   assert_true(kind.enumerable, "kind: enumerable");
   assert_true(kind.configurable, "kind: configurable");
   assert_equals(kind.value, expected.kind);
+
+  if (expected.type) {
+    const type = Object.getOwnPropertyDescriptor(export_, 'type');
+    assert_true(type.writable, 'type: writable');
+    assert_true(type.enumerable, 'type: enumerable');
+    assert_true(type.configurable, 'type: configurable');
+    assert_array_equals(type.value.parameters, expected.type.parameters);
+    assert_array_equals(type.value.results, expected.type.results);
+  }
 }
 
 function assert_exports(exports, expected) {
@@ -83,7 +92,8 @@ test(() => {
 
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
-  assert_not_equals(WebAssembly.Module.exports(module), WebAssembly.Module.exports(module));
+  assert_not_equals(
+      WebAssembly.Module.exports(module), WebAssembly.Module.exports(module));
 }, "Empty module: array caching");
 
 test(() => {
@@ -114,12 +124,20 @@ test(() => {
   const module = new WebAssembly.Module(buffer);
   const exports = WebAssembly.Module.exports(module);
   const expected = [
-    { "kind": "function", "name": "fn" },
-    { "kind": "function", "name": "fn2" },
-    { "kind": "table", "name": "table" },
-    { "kind": "global", "name": "global" },
-    { "kind": "global", "name": "global2" },
-    { "kind": "memory", "name": "memory" },
+    {
+      'kind': 'function',
+      'name': 'fn',
+      'type': {'parameters': [], 'results': []}
+    },
+    {
+      'kind': 'function',
+      'name': 'fn2',
+      'type': {'parameters': [], 'results': []}
+    },
+    {'kind': 'table', 'name': 'table'},
+    {'kind': 'global', 'name': 'global'},
+    {'kind': 'global', 'name': 'global2'},
+    {'kind': 'memory', 'name': 'memory'},
   ];
   assert_exports(exports, expected);
 }, "exports");
@@ -129,3 +147,24 @@ test(() => {
   const exports = WebAssembly.Module.exports(module, {});
   assert_exports(exports, []);
 }, "Stray argument");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder
+    .addFunction("fn", kSig_a_a)
+    .addBody([kExprLocalGet, 0])
+    .exportFunc();
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const exports = WebAssembly.Module.exports(module);
+  const expected = [
+    {
+      'kind': 'function',
+      'name': 'fn',
+      'type': {'parameters': ['funcref'], 'results': ['funcref']}
+    },
+  ];
+  assert_exports(exports, expected);
+}, "export function with funcref parameter and result");
diff --git a/test/js-api/module/imports.any.js b/test/js-api/module/imports.any.js
index d6754c9e..6f4b5366 100644
--- a/test/js-api/module/imports.any.js
+++ b/test/js-api/module/imports.any.js
@@ -22,6 +22,15 @@ function assert_ModuleImportDescriptor(import_, expected) {
   assert_true(kind.enumerable, "kind: enumerable");
   assert_true(kind.configurable, "kind: configurable");
   assert_equals(kind.value, expected.kind);
+
+  if (expected.type) {
+    const type = Object.getOwnPropertyDescriptor(import_, 'type');
+    assert_true(type.writable, 'type: writable');
+    assert_true(type.enumerable, 'type: enumerable');
+    assert_true(type.configurable, 'type: configurable');
+    assert_array_equals(type.value.parameters, expected.type.parameters);
+    assert_array_equals(type.value.results, expected.type.results);
+  }
 }
 
 function assert_imports(imports, expected) {
@@ -110,10 +119,15 @@ test(() => {
   const module = new WebAssembly.Module(buffer);
   const imports = WebAssembly.Module.imports(module);
   const expected = [
-    { "module": "module", "kind": "function", "name": "fn" },
-    { "module": "module", "kind": "global", "name": "global" },
-    { "module": "module", "kind": "memory", "name": "memory" },
-    { "module": "module", "kind": "table", "name": "table" },
+    {
+      'module': 'module',
+      'kind': 'function',
+      'name': 'fn',
+      'type': {'parameters': [], 'results': []}
+    },
+    {'module': 'module', 'kind': 'global', 'name': 'global'},
+    {'module': 'module', 'kind': 'memory', 'name': 'memory'},
+    {'module': 'module', 'kind': 'table', 'name': 'table'},
   ];
   assert_imports(imports, expected);
 }, "imports");
@@ -123,3 +137,21 @@ test(() => {
   const imports = WebAssembly.Module.imports(module, {});
   assert_imports(imports, []);
 }, "Stray argument");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+  builder.addImport("module", "fn", kSig_a_a);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const imports = WebAssembly.Module.imports(module);
+  const expected = [
+    {
+      'kind': 'function',
+      'module': 'module',
+      'name': 'fn',
+      'type': {'parameters': ['funcref'], 'results': ['funcref']}
+    },
+  ];
+  assert_imports(imports, expected);
+}, "import function with funcref parameter and result");
diff --git a/test/js-api/table/type.any.js b/test/js-api/table/type.any.js
new file mode 100644
index 00000000..eedb80b5
--- /dev/null
+++ b/test/js-api/table/type.any.js
@@ -0,0 +1,42 @@
+// META: global=window,dedicatedworker,jsshell
+// META: script=/wasm/jsapi/assertions.js
+
+function assert_type(argument, element) {
+    const mytable = new WebAssembly.Table(argument);
+    const tabletype = mytable.type()
+    assert_equals(tabletype.minimum, argument.minimum);
+    assert_equals(tabletype.maximum, argument.maximum);
+    assert_equals(tabletype.element, element);
+}
+
+test(() => {
+    assert_type({ "minimum": 0, "element": "anyfunc"}, "funcref");
+}, "anyfunc, Zero initial, no maximum");
+
+test(() => {
+    assert_type({ "minimum": 5, "element": "anyfunc" }, "funcref");
+}, "anyfunc, Non-zero initial, no maximum");
+
+test(() => {
+    assert_type({ "minimum": 0, "maximum": 0, "element": "anyfunc" }, "funcref");
+}, "anyfunc, Zero maximum");
+
+test(() => {
+    assert_type({ "minimum": 0, "maximum": 5, "element": "anyfunc" }, "funcref");
+}, "anyfunc, Non-zero maximum");
+
+test(() => {
+    assert_type({ "minimum": 0, "element": "funcref"}, "funcref");
+}, "funcref, Zero initial, no maximum");
+
+test(() => {
+    assert_type({ "minimum": 5, "element": "funcref" }, "funcref");
+}, "funcref, Non-zero initial, no maximum");
+
+test(() => {
+    assert_type({ "minimum": 0, "maximum": 0, "element": "funcref" }, "funcref");
+}, "funcref, Zero maximum");
+
+test(() => {
+    assert_type({ "minimum": 0, "maximum": 5, "element": "funcref" }, "funcref");
+}, "funcref, Non-zero maximum");

From 9aa66d51126654c4d4e1bfca961cbadadc9ded09 Mon Sep 17 00:00:00 2001
From: Andreas Haas 
Date: Mon, 15 Nov 2021 16:15:47 +0100
Subject: [PATCH 5/8] Add more tests

---
 test/js-api/module/exports.any.js |  99 +++++++++++++++++++++++--
 test/js-api/module/imports.any.js | 116 ++++++++++++++++++++++++++++--
 2 files changed, 207 insertions(+), 8 deletions(-)

diff --git a/test/js-api/module/exports.any.js b/test/js-api/module/exports.any.js
index 4a6aaad8..63cc5ab3 100644
--- a/test/js-api/module/exports.any.js
+++ b/test/js-api/module/exports.any.js
@@ -27,8 +27,28 @@ function assert_ModuleExportDescriptor(export_, expected) {
     assert_true(type.writable, 'type: writable');
     assert_true(type.enumerable, 'type: enumerable');
     assert_true(type.configurable, 'type: configurable');
-    assert_array_equals(type.value.parameters, expected.type.parameters);
-    assert_array_equals(type.value.results, expected.type.results);
+
+    if (expected.type.parameters) {
+      assert_array_equals(type.value.parameters, expected.type.parameters);
+    }
+    if (expected.type.results) {
+      assert_array_equals(type.value.results, expected.type.results);
+    }
+    if (expected.type.value) {
+      assert_equals(type.value.value, expected.type.value);
+    }
+    if (expected.type.mutable !== undefined) {
+      assert_equals(type.value.mutable, expected.type.mutable);
+    }
+    if (expected.type.mimimum) {
+      assert_equals(type.value.mimimum, expected.type.mimimum);
+    }
+    if (expected.type.maximum) {
+      assert_equals(type.value.maximum, expected.type.maximum);
+    }
+    if (expected.type.element) {
+      assert_equals(type.value.element, expected.type.element);
+    }
   }
 }
 
@@ -84,6 +104,12 @@ test(() => {
   }
 }, "Branding");
 
+test(() => {
+  const module = new WebAssembly.Module(emptyModuleBinary);
+  const exports = WebAssembly.Module.exports(module);
+  assert_true(Array.isArray(exports));
+}, "Return type");
+
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   const exports = WebAssembly.Module.exports(module);
@@ -142,6 +168,54 @@ test(() => {
   assert_exports(exports, expected);
 }, "exports");
 
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder
+    .addFunction("", kSig_v_v)
+    .addBody([])
+    .exportFunc();
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const exports = WebAssembly.Module.exports(module);
+  const expected = [
+    {'kind': 'function', 'name': '', 'type': {'parameters': [], 'results': []}},
+  ];
+  assert_exports(exports, expected);
+}, "exports with empty name: function");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder.setTableBounds(1);
+  builder.addExportOfKind("", kExternalTable, 0);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const exports = WebAssembly.Module.exports(module);
+  const expected = [
+    { "kind": "table", "name": "" },
+  ];
+  assert_exports(exports, expected);
+}, "exports with empty name: table");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder.addGlobal(kWasmI32, true)
+    .exportAs("")
+    .init = 7;
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const exports = WebAssembly.Module.exports(module);
+  const expected = [
+    { "kind": "global", "name": "" },
+  ];
+  assert_exports(exports, expected);
+}, "exports with empty name: global");
+
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   const exports = WebAssembly.Module.exports(module, {});
@@ -156,7 +230,13 @@ test(() => {
     .addBody([kExprLocalGet, 0])
     .exportFunc();
 
-  const buffer = builder.toBuffer()
+  builder.addTable(kWasmAnyFunc, 10, 100);
+  builder.addExportOfKind("table", kExternalTable, 0);
+
+  builder.addGlobal(kWasmAnyFunc, true)
+    .exportAs("global").function_index = 0;
+
+  const buffer = builder.toBuffer();
   const module = new WebAssembly.Module(buffer);
   const exports = WebAssembly.Module.exports(module);
   const expected = [
@@ -165,6 +245,17 @@ test(() => {
       'name': 'fn',
       'type': {'parameters': ['funcref'], 'results': ['funcref']}
     },
+    {
+      'kind': 'table',
+      'name': 'table',
+      'type': {'minimum': 10, 'maximum': 100, 'element': 'funcref'}
+    },
+    {
+      'kind': 'global',
+      'name': 'global',
+      'type': {'value': 'funcref', 'mutable': true}
+    },
   ];
   assert_exports(exports, expected);
-}, "export function with funcref parameter and result");
+}, "exports with type funcref");
+
diff --git a/test/js-api/module/imports.any.js b/test/js-api/module/imports.any.js
index 6f4b5366..80488ccd 100644
--- a/test/js-api/module/imports.any.js
+++ b/test/js-api/module/imports.any.js
@@ -28,8 +28,27 @@ function assert_ModuleImportDescriptor(import_, expected) {
     assert_true(type.writable, 'type: writable');
     assert_true(type.enumerable, 'type: enumerable');
     assert_true(type.configurable, 'type: configurable');
-    assert_array_equals(type.value.parameters, expected.type.parameters);
-    assert_array_equals(type.value.results, expected.type.results);
+    if (expected.type.parameters) {
+      assert_array_equals(type.value.parameters, expected.type.parameters);
+    }
+    if (expected.type.results) {
+      assert_array_equals(type.value.results, expected.type.results);
+    }
+    if (expected.type.value) {
+      assert_equals(type.value.value, expected.type.value);
+    }
+    if (expected.type.mutable !== undefined) {
+      assert_equals(type.value.mutable, expected.type.mutable);
+    }
+    if (expected.type.mimimum) {
+      assert_equals(type.value.mimimum, expected.type.mimimum);
+    }
+    if (expected.type.maximum) {
+      assert_equals(type.value.maximum, expected.type.maximum);
+    }
+    if (expected.type.element) {
+      assert_equals(type.value.element, expected.type.element);
+    }
   }
 }
 
@@ -125,13 +144,88 @@ test(() => {
       'name': 'fn',
       'type': {'parameters': [], 'results': []}
     },
-    {'module': 'module', 'kind': 'global', 'name': 'global'},
+    {'module': 'module', 'kind': 'global', 'name': 'global', 'value': 'i32'},
     {'module': 'module', 'kind': 'memory', 'name': 'memory'},
     {'module': 'module', 'kind': 'table', 'name': 'table'},
   ];
   assert_imports(imports, expected);
 }, "imports");
 
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder.addImport("", "fn", kSig_v_v);
+  builder.addImportedGlobal("", "global", kWasmI32);
+  builder.addImportedMemory("", "memory", 0, 128);
+  builder.addImportedTable("", "table", 0, 128);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const imports = WebAssembly.Module.imports(module);
+  const expected = [
+    {
+      'module': '',
+      'kind': 'function',
+      'name': 'fn',
+      'type': {'parameters': [], 'results': []}
+    },
+    {'module': '', 'kind': 'global', 'name': 'global', 'value': 'i32'},
+    {'module': '', 'kind': 'memory', 'name': 'memory'},
+    {'module': '', 'kind': 'table', 'name': 'table'},
+  ];
+  assert_imports(imports, expected);
+}, "imports with empty module name");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder.addImport("a", "", kSig_v_v);
+  builder.addImportedGlobal("b", "", kWasmI32);
+  builder.addImportedMemory("c", "", 0, 128);
+  builder.addImportedTable("d", "", 0, 128);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const imports = WebAssembly.Module.imports(module);
+  const expected = [
+    {
+      'module': 'a',
+      'kind': 'function',
+      'name': '',
+      'type': {'parameters': [], 'results': []}
+    },
+    {'module': 'b', 'kind': 'global', 'name': '', 'value': 'i32'},
+    {'module': 'c', 'kind': 'memory', 'name': ''},
+    {'module': 'd', 'kind': 'table', 'name': ''},
+  ];
+  assert_imports(imports, expected);
+}, "imports with empty names");
+
+test(() => {
+  const builder = new WasmModuleBuilder();
+
+  builder.addImport("", "", kSig_v_v);
+  builder.addImportedGlobal("", "", kWasmI32);
+  builder.addImportedMemory("", "", 0, 128);
+  builder.addImportedTable("", "", 0, 128);
+
+  const buffer = builder.toBuffer()
+  const module = new WebAssembly.Module(buffer);
+  const imports = WebAssembly.Module.imports(module);
+  const expected = [
+    {
+      'module': '',
+      'kind': 'function',
+      'name': '',
+      'type': {'parameters': [], 'results': []}
+    },
+    {'module': '', 'kind': 'global', 'name': '', 'value': 'i32'},
+    {'module': '', 'kind': 'memory', 'name': ''},
+    {'module': '', 'kind': 'table', 'name': ''},
+  ];
+  assert_imports(imports, expected);
+}, "imports with empty module names and names");
+
 test(() => {
   const module = new WebAssembly.Module(emptyModuleBinary);
   const imports = WebAssembly.Module.imports(module, {});
@@ -141,6 +235,8 @@ test(() => {
 test(() => {
   const builder = new WasmModuleBuilder();
   builder.addImport("module", "fn", kSig_a_a);
+  builder.addImportedGlobal("module", "g", kWasmAnyFunc);
+  builder.addImportedTable("module", "t", 0, 128);
 
   const buffer = builder.toBuffer()
   const module = new WebAssembly.Module(buffer);
@@ -152,6 +248,18 @@ test(() => {
       'name': 'fn',
       'type': {'parameters': ['funcref'], 'results': ['funcref']}
     },
+    {
+      'module': 'module',
+      'kind': 'global',
+      'name': 'g',
+      'type': {'value': 'funcref', 'mutable': false}
+    },
+    {
+      'module': 'module',
+      'kind': 'table',
+      'name': 't',
+      'type': {'minimum': 0, 'maximum': 128, 'element': 'funcref'}
+    },
   ];
   assert_imports(imports, expected);
-}, "import function with funcref parameter and result");
+}, "imports with type funcref");

From fa0897bbaccc6dcaab357e22a53c70a104d84b79 Mon Sep 17 00:00:00 2001
From: Andreas Haas 
Date: Mon, 15 Nov 2021 17:06:11 +0100
Subject: [PATCH 6/8] Add 'anyfunc' back to ValueType

---
 document/js-api/index.bs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/document/js-api/index.bs b/document/js-api/index.bs
index 488f1b52..6b35f239 100644
--- a/document/js-api/index.bs
+++ b/document/js-api/index.bs
@@ -952,6 +952,7 @@ enum ValueType {
   "f64",
   "externref",
   "funcref",
+  "anyfunc",
 };
 
From 9a9a14371a17e9bb6a66a648df58a647b3556416 Mon Sep 17 00:00:00 2001 From: Andreas Haas Date: Wed, 17 Nov 2021 17:42:52 +0100 Subject: [PATCH 7/8] Handle ToTableKind as well --- document/js-api/index.bs | 2 +- test/js-api/module/exports.any.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/document/js-api/index.bs b/document/js-api/index.bs index 6b35f239..b0184d0e 100644 --- a/document/js-api/index.bs +++ b/document/js-api/index.bs @@ -849,7 +849,7 @@ Each {{Table}} object has a \[[Table]] internal slot, which is a [=table address The algorithm ToTableKind(|t|) performs the following steps: -1. If |t| equals [=funcref=], return "{{TableKind/anyfunc}}". +1. If |t| equals [=funcref=], return "{{TableKind/funcref}}". 1. If |t| equals [=externref=], return "{{TableKind/externref}}". 1. Assert: This step is not reached. diff --git a/test/js-api/module/exports.any.js b/test/js-api/module/exports.any.js index 63cc5ab3..0a179319 100644 --- a/test/js-api/module/exports.any.js +++ b/test/js-api/module/exports.any.js @@ -28,25 +28,25 @@ function assert_ModuleExportDescriptor(export_, expected) { assert_true(type.enumerable, 'type: enumerable'); assert_true(type.configurable, 'type: configurable'); - if (expected.type.parameters) { + if (expected.type.parameters !== undefined) { assert_array_equals(type.value.parameters, expected.type.parameters); } - if (expected.type.results) { + if (expected.type.results !== undefined) { assert_array_equals(type.value.results, expected.type.results); } - if (expected.type.value) { + if (expected.type.value !== undefined) { assert_equals(type.value.value, expected.type.value); } if (expected.type.mutable !== undefined) { assert_equals(type.value.mutable, expected.type.mutable); } - if (expected.type.mimimum) { + if (expected.type.mimimum !== undefined) { assert_equals(type.value.mimimum, expected.type.mimimum); } - if (expected.type.maximum) { + if (expected.type.maximum !== undefined) { assert_equals(type.value.maximum, expected.type.maximum); } - if (expected.type.element) { + if (expected.type.element !== undefined) { assert_equals(type.value.element, expected.type.element); } } From eb4262279c61e84d3fc9a1a86e788ccc119d2858 Mon Sep 17 00:00:00 2001 From: Andreas Haas Date: Thu, 18 Nov 2021 12:20:48 +0100 Subject: [PATCH 8/8] Also change import tests --- test/js-api/module/imports.any.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/js-api/module/imports.any.js b/test/js-api/module/imports.any.js index 80488ccd..0f0b2017 100644 --- a/test/js-api/module/imports.any.js +++ b/test/js-api/module/imports.any.js @@ -31,22 +31,22 @@ function assert_ModuleImportDescriptor(import_, expected) { if (expected.type.parameters) { assert_array_equals(type.value.parameters, expected.type.parameters); } - if (expected.type.results) { + if (expected.type.results !== undefined) { assert_array_equals(type.value.results, expected.type.results); } - if (expected.type.value) { + if (expected.type.value !== undefined) { assert_equals(type.value.value, expected.type.value); } if (expected.type.mutable !== undefined) { assert_equals(type.value.mutable, expected.type.mutable); } - if (expected.type.mimimum) { + if (expected.type.mimimum !== undefined) { assert_equals(type.value.mimimum, expected.type.mimimum); } - if (expected.type.maximum) { + if (expected.type.maximum !== undefined) { assert_equals(type.value.maximum, expected.type.maximum); } - if (expected.type.element) { + if (expected.type.element !== undefined) { assert_equals(type.value.element, expected.type.element); } }