Title: [279265] trunk
Revision
279265
Author
commit-qu...@webkit.org
Date
2021-06-24 19:23:28 -0700 (Thu, 24 Jun 2021)

Log Message

[WASM-Function-References] Add support for (ref null? $t) type constructor
https://bugs.webkit.org/show_bug.cgi?id=226296

JSTests:

Adds additional tests for uses of `(ref $t)` and `(ref null $t)`
types, including with non-null extern/funcrefs.

Patch by Asumu Takikawa <as...@igalia.com> on 2021-06-24
Reviewed by Yusuke Suzuki.

* wasm/function-references/ref_types.js: Added.
(module):
(async testRefTypeLocal):
(async testNonNullRefTypeLocal):
(async testRefTypeInSignature):
(async testRefTypeParamCheck):
(async testRefGlobalCheck):
(async testExternFuncrefNonNullCheck):
(async testExternrefCompatibility):
(async testNonNullExternrefIncompatible):
(async testFuncrefCompatibility):
(async testNonNullFuncrefIncompatible):
* wasm/wasm.json:

Source/_javascript_Core:

Patch by Asumu Takikawa <as...@igalia.com> on 2021-06-24
Reviewed by Yusuke Suzuki.

Adds the `ref` type constructor from the typed function references proposal:

  https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md

It's also required for the type imports and GC proposals as well. Ref types represent
references to any heap type (including existing funcref and externref) with a specified
nullability.

This requires a new isNullable flag in the type representation. This flag also enables
non-null externref and funcrefs, and hence this commit also adds the necessary checks
at Wasm/JS boundaries.

Non-null reference types also generally cannot be used as function locals.

* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::gTypeIdx):
(JSC::Wasm::AirIRGenerator::tmpForType):
(JSC::Wasm::AirIRGenerator::emitCCall):
(JSC::Wasm::AirIRGenerator::moveOpForValueType):
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::addLocal):
(JSC::Wasm::AirIRGenerator::addConstant):
(JSC::Wasm::AirIRGenerator::addRefFunc):
* wasm/WasmCallingConvention.h:
(JSC::Wasm::WasmCallingConvention::marshallLocation const):
(JSC::Wasm::JSCallingConvention::marshallLocation const):
* wasm/WasmFormat.h:
(JSC::Wasm::isSubtype):
(JSC::Wasm::isValidHeapTypeKind):
(JSC::Wasm::isDefaultableType):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parse):
(JSC::Wasm::FunctionParser<Context>::parseAnnotatedSelectImmediates):
(JSC::Wasm::FunctionParser<Context>::checkBranchTarget):
(JSC::Wasm::FunctionParser<Context>::parseExpression):
* wasm/WasmGlobal.cpp:
(JSC::Wasm::Global::get const):
(JSC::Wasm::Global::set):
* wasm/WasmLLIntGenerator.cpp:
(JSC::Wasm::LLIntGenerator::callInformationForCaller):
(JSC::Wasm::LLIntGenerator::callInformationForCallee):
(JSC::Wasm::LLIntGenerator::addArguments):
* wasm/WasmParser.h:
(JSC::Wasm::Parser<SuccessType>::parseBlockSignature):
(JSC::Wasm::Parser<SuccessType>::parseValueType):
(JSC::Wasm::Parser<SuccessType>::parseRefType):
* wasm/WasmSectionParser.cpp:
(JSC::Wasm::SectionParser::parseType):
(JSC::Wasm::SectionParser::parseElement):
(JSC::Wasm::SectionParser::parseInitExpr):
(JSC::Wasm::SectionParser::parseElementSegmentVectorOfExpressions):
(JSC::Wasm::SectionParser::parseGlobalType):
* wasm/WasmSignature.cpp:
(JSC::Wasm::computeHash):
* wasm/generateWasmOpsHeader.py:
* wasm/js/WasmToJS.cpp:
(JSC::Wasm::wasmToJS):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
(JSC::WebAssemblyFunction::jsCallEntrypointSlow):
* wasm/js/WebAssemblyFunctionBase.h:
(JSC::WebAssemblyFunctionBase::offsetOfSignatureIndex):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::linkImpl):
* wasm/wasm.json:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (279264 => 279265)


--- trunk/JSTests/ChangeLog	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/JSTests/ChangeLog	2021-06-25 02:23:28 UTC (rev 279265)
@@ -1,3 +1,27 @@
+2021-06-24  Asumu Takikawa  <as...@igalia.com>
+
+        [WASM-Function-References] Add support for (ref null? $t) type constructor
+        https://bugs.webkit.org/show_bug.cgi?id=226296
+
+        Adds additional tests for uses of `(ref $t)` and `(ref null $t)`
+        types, including with non-null extern/funcrefs.
+
+        Reviewed by Yusuke Suzuki.
+
+        * wasm/function-references/ref_types.js: Added.
+        (module):
+        (async testRefTypeLocal):
+        (async testNonNullRefTypeLocal):
+        (async testRefTypeInSignature):
+        (async testRefTypeParamCheck):
+        (async testRefGlobalCheck):
+        (async testExternFuncrefNonNullCheck):
+        (async testExternrefCompatibility):
+        (async testNonNullExternrefIncompatible):
+        (async testFuncrefCompatibility):
+        (async testNonNullFuncrefIncompatible):
+        * wasm/wasm.json:
+
 2021-06-24  Guillaume Emont  <guijem...@igalia.com>
 
         Improve our checking of NaN values in DataView tests

Added: trunk/JSTests/wasm/function-references/ref_types.js (0 => 279265)


--- trunk/JSTests/wasm/function-references/ref_types.js	                        (rev 0)
+++ trunk/JSTests/wasm/function-references/ref_types.js	2021-06-25 02:23:28 UTC (rev 279265)
@@ -0,0 +1,316 @@
+//@ runWebAssemblySuite("--useWebAssemblyTypedFunctionReferences=true")
+import * as assert from "../assert.js";
+import { instantiate } from "../wabt-wrapper.js";
+
+function module(bytes, valid = true) {
+  let buffer = new ArrayBuffer(bytes.length);
+  let view = new Uint8Array(buffer);
+  for (let i = 0; i < bytes.length; ++i) {
+    view[i] = bytes.charCodeAt(i);
+  }
+  return new WebAssembly.Module(buffer);
+}
+
+async function testRefTypeLocal() {
+  /*
+   * (module
+   *   (type (func (param i32) (result i32)))
+   *   (func (result (ref null 0)) (local (ref null 0))
+   *     (local.get 0)))
+   */
+  new WebAssembly.Instance(
+    module(
+      "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0b\x02\x60\x01\x7f\x01\x7f\x60\x00\x01\x6c\x00\x03\x02\x01\x01\x0a\x09\x01\x07\x01\x01\x6c\x00\x20\x00\x0b"
+    )
+  );
+}
+
+async function testNonNullRefTypeLocal() {
+  /*
+   * (module
+   *   (type (func (param i32) (result i32)))
+   *   (func (local (ref 0))))
+   */
+  assert.throws(
+    () =>
+      module(
+        "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x09\x02\x60\x01\x7f\x01\x7f\x60\x00\x00\x03\x02\x01\x01\x0a\x07\x01\x05\x01\x01\x6b\x00\x0b"
+      ),
+    WebAssembly.CompileError,
+    "Function locals must have a defaultable type"
+  );
+}
+
+async function testRefTypeInSignature() {
+  /*
+   * (module
+   *   (elem declare funcref (ref.func $f))
+   *   (type $t1 (func (param i32) (result i32)))
+   *   (type $t2 (func (param) (result (ref $t1))))
+   *   (func $f (type $t1) (i32.const 1))
+   *   (func $g (type $t2) (ref.func $f)))
+   */
+  new WebAssembly.Instance(
+    module(
+      "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0b\x02\x60\x01\x7f\x01\x7f\x60\x00\x01\x6b\x00\x03\x03\x02\x00\x01\x09\x05\x01\x03\x00\x01\x00\x0a\x0b\x02\x04\x00\x41\x01\x0b\x04\x00\xd2\x00\x0b\x00\x0e\x04\x6e\x61\x6d\x65\x01\x07\x02\x00\x01\x66\x01\x01\x67"
+    )
+  );
+}
+
+async function testRefTypeParamCheck() {
+  const wat1 = `
+    (module
+      (func (export "f") (param f64) (result f64)
+        (local.get 0)))
+    `;
+
+  const instance1 = await instantiate(wat1);
+
+  /*
+   * (module
+   *   (type $t1 (func (param i32) (result i32)))
+   *   (type $t2 (func (param (ref $t1)) (result)))
+   *   (func (export "f") (type $t2)))
+   */
+  const m2 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0b\x02\x60\x01\x7f\x01\x7f\x60\x01\x6b\x00\x00\x03\x02\x01\x01\x07\x05\x01\x01\x66\x00\x00\x0a\x04\x01\x02\x00\x0b"
+  );
+  const instance2 = new WebAssembly.Instance(m2);
+
+  /*
+   * (module
+   *   (type $t1 (func (param i32) (result i32)))
+   *   (type $t2 (func (param (ref null $t1)) (result)))
+   *   (func (export "f") (type $t2)))
+   */
+  const m3 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x0b\x02\x60\x01\x7f\x01\x7f\x60\x01\x6c\x00\x00\x03\x02\x01\x01\x07\x05\x01\x01\x66\x00\x00\x0a\x04\x01\x02\x00\x0b"
+  );
+  const instance3 = new WebAssembly.Instance(m3);
+
+  for (let i=0; i<1000; ++i) {
+    // Trigger the ic path
+    assert.throws(
+      () => instance2.exports.f(null),
+      WebAssembly.RuntimeError,
+      "Funcref must be an exported wasm function"
+    );
+    assert.throws(
+      () => instance2.exports.f(instance1.exports.f),
+      WebAssembly.RuntimeError,
+      "Argument function did not match the reference type"
+    );
+    instance3.exports.f(null);
+  }
+}
+
+async function testRefGlobalCheck() {
+  const wat = `
+    (module
+      (global (export "g") funcref (ref.null func))
+      (func (export "f") (param f64) (result f64)
+        (local.get 0)))
+    `;
+
+  const providerInstance = await instantiate(
+    wat,
+    {},
+    { reference_types: true }
+  );
+
+  /*
+   * (module
+   *   (global (export "g") (mut (ref func)) (ref.func $f))
+   *   (func $f))
+   */
+  const m1 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x06\x07\x01\x6b\x70\x01\xd2\x00\x0b\x07\x05\x01\x01\x67\x03\x00\x0a\x04\x01\x02\x00\x0b\x00\x0b\x04\x6e\x61\x6d\x65\x01\x04\x01\x00\x01\x66"
+  );
+  const instance1 = new WebAssembly.Instance(m1);
+  assert.throws(
+    () => (instance1.exports.g.value = null),
+    WebAssembly.RuntimeError,
+    "Funcref must be an exported wasm function"
+  );
+
+  /*
+   * (module
+   *   (type (func))
+   *   (global (export "g") (mut (ref 0)) (ref.func $f))
+   *   (func $f (type 0)))
+   */
+  const m2 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x03\x02\x01\x00\x06\x07\x01\x6b\x00\x01\xd2\x00\x0b\x07\x05\x01\x01\x67\x03\x00\x0a\x04\x01\x02\x00\x0b\x00\x0b\x04\x6e\x61\x6d\x65\x01\x04\x01\x00\x01\x66"
+  );
+  const instance2 = new WebAssembly.Instance(m2);
+  assert.throws(
+    () => (instance2.exports.g.value = null),
+    WebAssembly.RuntimeError,
+    "Funcref must be an exported wasm function"
+  );
+  assert.throws(
+    () => (instance2.exports.g.value = providerInstance.exports.f),
+    WebAssembly.RuntimeError,
+    "Argument function did not match the reference type"
+  );
+
+  /*
+   * (module
+   *   (import "m" "g" (global (ref func))))
+   */
+  const m3 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x09\x01\x01\x6d\x01\x67\x03\x6b\x70\x00"
+  );
+  assert.throws(
+    () =>
+      new WebAssembly.Instance(m3, { m: { g: providerInstance.exports.g } }),
+    WebAssembly.LinkError,
+    "imported global m:g must be a same type"
+  );
+
+  /*
+   * (module
+   *   (type (func))
+   *   (import "m" "g" (global (ref 0))))
+   */
+  const m4 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x02\x09\x01\x01\x6d\x01\x67\x03\x6b\x00\x00"
+  );
+  assert.throws(
+    () =>
+      new WebAssembly.Instance(m4, { m: { g: providerInstance.exports.g } }),
+    WebAssembly.LinkError,
+    "imported global m:g must be a same type"
+  );
+
+  /*
+   * (module
+   *   (import "m" "g" (global (ref extern))))
+   */
+  const m5 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x09\x01\x01\x6d\x01\x67\x03\x6b\x6f\x00"
+  );
+  assert.throws(
+    () => new WebAssembly.Instance(m5, { m: { g: null } }),
+    WebAssembly.LinkError,
+    "imported global m:g must be a non-null value"
+  );
+
+  /*
+   * (module
+   *   (global $g (import "m" "g") (mut (ref extern)))
+   *   (func (global.set $g (ref.null extern))))
+   */
+  assert.throws(
+    () => {
+      module(
+        "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x04\x01\x60\x00\x00\x02\x09\x01\x01\x6d\x01\x67\x03\x6b\x6f\x01\x03\x02\x01\x00\x0a\x08\x01\x06\x00\xd0\x6f\x24\x00\x0b"
+      )
+    },
+    WebAssembly.CompileError,
+    "WebAssembly.Module doesn't validate: set_global 0 with type Externref"
+  );
+}
+
+async function testExternFuncrefNonNullCheck() {
+  /*
+   * (module
+   *   (type $t (func (param (ref extern)) (result)))
+   *   (func (export "f") (type $t)))
+   */
+  const m1 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x06\x01\x60\x01\x6b\x6f\x00\x03\x02\x01\x00\x07\x05\x01\x01\x66\x00\x00\x0a\x04\x01\x02\x00\x0b"
+  );
+  const instance1 = new WebAssembly.Instance(m1);
+
+  /*
+   * (module
+   *   (type $t (func (param (ref func)) (result)))
+   *   (func (export "f") (type $t)))
+   */
+  const m2 = module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x06\x01\x60\x01\x6b\x70\x00\x03\x02\x01\x00\x07\x05\x01\x01\x66\x00\x00\x0a\x04\x01\x02\x00\x0b"
+  );
+  const instance2 = new WebAssembly.Instance(m2);
+
+  for (let i=0; i<1000; ++i) {
+    // Trigger the ic path
+    assert.throws(
+      () => instance1.exports.f(null),
+      WebAssembly.RuntimeError,
+      "Non-null Externref cannot be null"
+    );
+    assert.throws(
+      () => instance2.exports.f(null),
+      WebAssembly.RuntimeError,
+      "Funcref must be an exported wasm function"
+    );
+  }
+}
+
+// Ensure two ways of writing externref are equivalent.
+async function testExternrefCompatibility() {
+  /*
+   * (module
+   *   (type $t (func (param externref) (result (ref null extern))))
+   *   (func $f (type $t) (local.get 0)))
+   */
+  module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x07\x01\x60\x01\x6f\x01\x6c\x6f\x03\x02\x01\x00\x0a\x06\x01\x04\x00\x20\x00\x0b\x00\x0b\x04\x6e\x61\x6d\x65\x01\x04\x01\x00\x01\x66"
+  );
+}
+
+async function testNonNullExternrefIncompatible() {
+  /*
+   * (module
+   *   (type $t (func (param externref) (result (ref extern))))
+   *   (func $f (type $t) (local.get 0)))
+   */
+  assert.throws(
+    () =>
+      module(
+        "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x07\x01\x60\x01\x6f\x01\x6b\x6f\x03\x02\x01\x00\x0a\x06\x01\x04\x00\x20\x00\x0b\x00\x0b\x04\x6e\x61\x6d\x65\x01\x04\x01\x00\x01\x66"
+      ),
+    WebAssembly.CompileError,
+    "control flow returns with unexpected type. Externref"
+  );
+}
+
+// Ensure two ways of writing funcref are equivalent.
+async function testFuncrefCompatibility() {
+  /*
+   * (module
+   *   (type $t (func (param funcref) (result (ref null func))))
+   *   (func $f (type $t) (local.get 0)))
+   */
+  module(
+    "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x07\x01\x60\x01\x70\x01\x6c\x70\x03\x02\x01\x00\x0a\x06\x01\x04\x00\x20\x00\x0b\x00\x0b\x04\x6e\x61\x6d\x65\x01\x04\x01\x00\x01\x66"
+  );
+}
+
+async function testNonNullFuncrefIncompatible() {
+  /*
+   * (module
+   *   (type $t (func (param funcref) (result (ref func))))
+   *   (func $f (type $t) (local.get 0)))
+   */
+  assert.throws(
+    () =>
+      module(
+        "\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x07\x01\x60\x01\x70\x01\x6b\x70\x03\x02\x01\x00\x0a\x06\x01\x04\x00\x20\x00\x0b\x00\x0b\x04\x6e\x61\x6d\x65\x01\x04\x01\x00\x01\x66"
+      ),
+    WebAssembly.CompileError,
+    "control flow returns with unexpected type. Funcref"
+  );
+}
+
+assert.asyncTest(testRefTypeLocal());
+assert.asyncTest(testNonNullRefTypeLocal());
+assert.asyncTest(testRefTypeInSignature());
+assert.asyncTest(testRefTypeParamCheck());
+assert.asyncTest(testRefGlobalCheck());
+assert.asyncTest(testExternFuncrefNonNullCheck());
+assert.asyncTest(testExternrefCompatibility());
+assert.asyncTest(testNonNullExternrefIncompatible());
+assert.asyncTest(testFuncrefCompatibility());
+assert.asyncTest(testNonNullFuncrefIncompatible());

Modified: trunk/JSTests/wasm/wasm.json (279264 => 279265)


--- trunk/JSTests/wasm/wasm.json	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/JSTests/wasm/wasm.json	2021-06-25 02:23:28 UTC (rev 279265)
@@ -13,6 +13,8 @@
         "f64":       { "type": "varint7", "value":   -4, "b3type": "B3::Double" },
         "funcref":   { "type": "varint7", "value":  -16, "b3type": "B3::Int64" },
         "externref": { "type": "varint7", "value":  -17, "b3type": "B3::Int64" },
+        "ref_null":  { "type": "varint7", "value":  -20, "b3type": "B3::Int64" },
+        "ref":       { "type": "varint7", "value":  -21, "b3type": "B3::Int64" },
         "func":      { "type": "varint7", "value":  -32, "b3type": "B3::Void" },
         "void":      { "type": "varint7", "value":  -64, "b3type": "B3::Void" },
         "type_idx":  { "type": "varint7", "value": -128, "b3type": "B3::Int64" }

Modified: trunk/Source/_javascript_Core/ChangeLog (279264 => 279265)


--- trunk/Source/_javascript_Core/ChangeLog	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/ChangeLog	2021-06-25 02:23:28 UTC (rev 279265)
@@ -1,3 +1,76 @@
+2021-06-24  Asumu Takikawa  <as...@igalia.com>
+
+        [WASM-Function-References] Add support for (ref null? $t) type constructor
+        https://bugs.webkit.org/show_bug.cgi?id=226296
+
+        Reviewed by Yusuke Suzuki.
+
+        Adds the `ref` type constructor from the typed function references proposal:
+
+          https://github.com/WebAssembly/function-references/blob/master/proposals/function-references/Overview.md
+
+        It's also required for the type imports and GC proposals as well. Ref types represent
+        references to any heap type (including existing funcref and externref) with a specified
+        nullability.
+
+        This requires a new isNullable flag in the type representation. This flag also enables
+        non-null externref and funcrefs, and hence this commit also adds the necessary checks
+        at Wasm/JS boundaries.
+
+        Non-null reference types also generally cannot be used as function locals.
+
+        * wasm/WasmAirIRGenerator.cpp:
+        (JSC::Wasm::AirIRGenerator::gTypeIdx):
+        (JSC::Wasm::AirIRGenerator::tmpForType):
+        (JSC::Wasm::AirIRGenerator::emitCCall):
+        (JSC::Wasm::AirIRGenerator::moveOpForValueType):
+        (JSC::Wasm::AirIRGenerator::AirIRGenerator):
+        (JSC::Wasm::AirIRGenerator::addLocal):
+        (JSC::Wasm::AirIRGenerator::addConstant):
+        (JSC::Wasm::AirIRGenerator::addRefFunc):
+        * wasm/WasmCallingConvention.h:
+        (JSC::Wasm::WasmCallingConvention::marshallLocation const):
+        (JSC::Wasm::JSCallingConvention::marshallLocation const):
+        * wasm/WasmFormat.h:
+        (JSC::Wasm::isSubtype):
+        (JSC::Wasm::isValidHeapTypeKind):
+        (JSC::Wasm::isDefaultableType):
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::FunctionParser<Context>::parse):
+        (JSC::Wasm::FunctionParser<Context>::parseAnnotatedSelectImmediates):
+        (JSC::Wasm::FunctionParser<Context>::checkBranchTarget):
+        (JSC::Wasm::FunctionParser<Context>::parseExpression):
+        * wasm/WasmGlobal.cpp:
+        (JSC::Wasm::Global::get const):
+        (JSC::Wasm::Global::set):
+        * wasm/WasmLLIntGenerator.cpp:
+        (JSC::Wasm::LLIntGenerator::callInformationForCaller):
+        (JSC::Wasm::LLIntGenerator::callInformationForCallee):
+        (JSC::Wasm::LLIntGenerator::addArguments):
+        * wasm/WasmParser.h:
+        (JSC::Wasm::Parser<SuccessType>::parseBlockSignature):
+        (JSC::Wasm::Parser<SuccessType>::parseValueType):
+        (JSC::Wasm::Parser<SuccessType>::parseRefType):
+        * wasm/WasmSectionParser.cpp:
+        (JSC::Wasm::SectionParser::parseType):
+        (JSC::Wasm::SectionParser::parseElement):
+        (JSC::Wasm::SectionParser::parseInitExpr):
+        (JSC::Wasm::SectionParser::parseElementSegmentVectorOfExpressions):
+        (JSC::Wasm::SectionParser::parseGlobalType):
+        * wasm/WasmSignature.cpp:
+        (JSC::Wasm::computeHash):
+        * wasm/generateWasmOpsHeader.py:
+        * wasm/js/WasmToJS.cpp:
+        (JSC::Wasm::wasmToJS):
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::JSC_DEFINE_HOST_FUNCTION):
+        (JSC::WebAssemblyFunction::jsCallEntrypointSlow):
+        * wasm/js/WebAssemblyFunctionBase.h:
+        (JSC::WebAssemblyFunctionBase::offsetOfSignatureIndex):
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::linkImpl):
+        * wasm/wasm.json:
+
 2021-06-24  Mark Lam  <mark....@apple.com>
 
         Use ldp and stp more for saving / restoring registers on ARM64.

Modified: trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -413,6 +413,7 @@
     TypedTmp g64() { return { newTmp(B3::GP), Types::I64 }; }
     TypedTmp gExternref() { return { newTmp(B3::GP), Types::Externref }; }
     TypedTmp gFuncref() { return { newTmp(B3::GP), Types::Funcref }; }
+    TypedTmp gTypeIdx(Type type) { return { newTmp(B3::GP), type }; }
     TypedTmp f32() { return { newTmp(B3::FP), Types::F32 }; }
     TypedTmp f64() { return { newTmp(B3::FP), Types::F64 }; }
 
@@ -425,6 +426,8 @@
             return g64();
         case TypeKind::Funcref:
             return gFuncref();
+        case TypeKind::TypeIdx:
+            return gTypeIdx(type);
         case TypeKind::Externref:
             return gExternref();
         case TypeKind::F32:
@@ -601,6 +604,7 @@
             case TypeKind::I64:
             case TypeKind::Externref:
             case TypeKind::Funcref:
+            case TypeKind::TypeIdx:
                 resultType = B3::Int64;
                 break;
             case TypeKind::F32:
@@ -650,6 +654,7 @@
         case TypeKind::I64:
         case TypeKind::Externref:
         case TypeKind::Funcref:
+        case TypeKind::TypeIdx:
             return Move;
         case TypeKind::F32:
             return MoveFloat;
@@ -907,6 +912,7 @@
         case TypeKind::I64:
         case TypeKind::Externref:
         case TypeKind::Funcref:
+        case TypeKind::TypeIdx:
             append(Move, arg, m_locals[i]);
             break;
         case TypeKind::F32:
@@ -1009,6 +1015,7 @@
         switch (type.kind) {
         case TypeKind::Externref:
         case TypeKind::Funcref:
+        case TypeKind::TypeIdx:
             append(Move, Arg::imm(JSValue::encode(jsNull())), local);
             break;
         case TypeKind::I32:
@@ -1044,6 +1051,7 @@
     case TypeKind::I64:
     case TypeKind::Externref:
     case TypeKind::Funcref:
+    case TypeKind::TypeIdx:
         append(block, Move, Arg::bigImm(value), result);
         break;
     case TypeKind::F32:
@@ -1088,7 +1096,11 @@
 auto AirIRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
-    result = tmpForType(Types::Funcref);
+    if (Options::useWebAssemblyTypedFunctionReferences()) {
+        SignatureIndex signatureIndex = m_info.signatureIndexFromFunctionIndexSpace(index);
+        result = tmpForType(Type { TypeKind::TypeIdx, Nullable::No, signatureIndex });
+    } else
+        result = tmpForType(Types::Funcref);
     emitCCall(&operationWasmRefFunc, result, instanceValue(), addConstant(Types::I32, index));
 
     return { };

Modified: trunk/Source/_javascript_Core/wasm/WasmCallingConvention.h (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmCallingConvention.h	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmCallingConvention.h	2021-06-25 02:23:28 UTC (rev 279265)
@@ -107,6 +107,7 @@
         case TypeKind::I64:
         case TypeKind::Funcref:
         case TypeKind::Externref:
+        case TypeKind::TypeIdx:
             return marshallLocationImpl(role, gprArgs, gpArgumentCount, stackOffset);
         case TypeKind::F32:
         case TypeKind::F64:
@@ -195,6 +196,7 @@
         case TypeKind::I64:
         case TypeKind::Funcref:
         case TypeKind::Externref:
+        case TypeKind::TypeIdx:
             return marshallLocationImpl(role, gprArgs, gpArgumentCount, stackOffset);
         case TypeKind::F32:
         case TypeKind::F64:

Modified: trunk/Source/_javascript_Core/wasm/WasmFormat.h (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmFormat.h	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmFormat.h	2021-06-25 02:23:28 UTC (rev 279265)
@@ -79,6 +79,9 @@
 
 inline bool isSubtype(Type sub, Type parent)
 {
+    if (sub.isNullable() && !parent.isNullable())
+        return false;
+
     if (sub.isTypeIdx() && parent.isFuncref())
         return true;
 
@@ -90,6 +93,23 @@
     return type.isFuncref() || type.isExternref() || type.isTypeIdx();
 }
 
+inline bool isValidHeapTypeKind(TypeKind kind)
+{
+    switch (kind) {
+    case TypeKind::Funcref:
+    case TypeKind::Externref:
+        return true;
+    default:
+        break;
+    }
+    return false;
+}
+
+inline bool isDefaultableType(Type type)
+{
+    return !isRefType(type) || type.isNullable();
+}
+
 enum class ExternalKind : uint8_t {
     // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
     Function = 0,

Modified: trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2021-06-25 02:23:28 UTC (rev 279265)
@@ -243,7 +243,8 @@
         WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfLocals), "can't get Function's number of locals in group ", i);
         totalNumberOfLocals += numberOfLocals;
         WASM_PARSER_FAIL_IF(totalNumberOfLocals > maxFunctionLocals, "Function's number of locals is too big ", totalNumberOfLocals, " maximum ", maxFunctionLocals);
-        WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i);
+        WASM_PARSER_FAIL_IF(!parseValueType(m_info, typeOfLocal), "can't get Function local's type in group ", i);
+        WASM_PARSER_FAIL_IF(!isDefaultableType(typeOfLocal), "Function locals must have a defaultable type");
 
         WASM_PARSER_FAIL_IF(!m_locals.tryReserveCapacity(totalNumberOfLocals), "can't allocate enough memory for function's ", totalNumberOfLocals, " locals");
         for (uint32_t i = 0; i < numberOfLocals; ++i)
@@ -644,7 +645,7 @@
     WASM_PARSER_FAIL_IF(sizeOfAnnotationVector != 1, "select invalid result arity for");
 
     Type targetType;
-    WASM_PARSER_FAIL_IF(!parseValueType(targetType), "select can't parse annotations");
+    WASM_PARSER_FAIL_IF(!parseValueType(m_info, targetType), "select can't parse annotations");
 
     result.sizeOfAnnotationVector = sizeOfAnnotationVector;
     result.targetType = targetType;
@@ -699,7 +700,7 @@
 
     unsigned offset = m_expressionStack.size() - target.branchTargetArity();
     for (unsigned i = 0; i < target.branchTargetArity(); ++i)
-        WASM_VALIDATOR_FAIL_IF(!isSubtype(target.branchTargetType(i), m_expressionStack[offset + i].type()), "branch's stack type is not a block's type branch target type. Stack value has type", m_expressionStack[offset + i].type().kind, " but branch target expects a value of ", target.branchTargetType(i).kind, " at index ", i);
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(m_expressionStack[offset + i].type(), target.branchTargetType(i)), "branch's stack type is not a block's type branch target type. Stack value has type ", m_expressionStack[offset + i].type().kind, " but branch target expects a value of ", target.branchTargetType(i).kind, " at index ", i);
 
     return { };
 }
@@ -1079,7 +1080,7 @@
     case RefNull: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
         Type typeOfNull;
-        WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a reference type");
+        WASM_PARSER_FAIL_IF(!parseRefType(m_info, typeOfNull), "ref.null type must be a reference type");
         m_expressionStack.constructAndAppend(typeOfNull, m_context.addConstant(typeOfNull, JSValue::encode(jsNull())));
         return { };
     }
@@ -1109,7 +1110,7 @@
 
         if (Options::useWebAssemblyTypedFunctionReferences()) {
             SignatureIndex signatureIndex = m_info.signatureIndexFromFunctionIndexSpace(index);
-            m_expressionStack.constructAndAppend(Type {TypeKind::TypeIdx, signatureIndex}, result);
+            m_expressionStack.constructAndAppend(Type {TypeKind::TypeIdx, Nullable::No, signatureIndex}, result);
             return { };
         }
 

Modified: trunk/Source/_javascript_Core/wasm/WasmGlobal.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmGlobal.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmGlobal.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -48,6 +48,7 @@
         return jsNumber(purifyNaN(bitwise_cast<double>(m_value.m_primitive)));
     case TypeKind::Externref:
     case TypeKind::Funcref:
+    case TypeKind::TypeIdx:
         return m_value.m_externref.get();
     default:
         return jsUndefined();
@@ -86,15 +87,35 @@
     }
     case TypeKind::Externref: {
         RELEASE_ASSERT(m_owner);
+        if (!m_type.isNullable() && argument.isNull()) {
+            throwException(globalObject, throwScope, createJSWebAssemblyRuntimeError(globalObject, vm, "Non-null Externref cannot be null"));
+            return;
+        }
         m_value.m_externref.set(m_owner->vm(), m_owner, argument);
         break;
     }
+    case TypeKind::TypeIdx:
     case TypeKind::Funcref: {
         RELEASE_ASSERT(m_owner);
-        if (!isWebAssemblyHostFunction(vm, argument) && !argument.isNull()) {
+        bool isNullable = m_type.isNullable();
+        WebAssemblyFunction* wasmFunction = nullptr;
+        WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
+        if (!isWebAssemblyHostFunction(vm, argument, wasmFunction, wasmWrapperFunction) && (!isNullable || !argument.isNull())) {
             throwException(globalObject, throwScope, createJSWebAssemblyRuntimeError(globalObject, vm, "Funcref must be an exported wasm function"));
             return;
         }
+        if (m_type.kind == TypeKind::TypeIdx && (wasmFunction || wasmWrapperFunction)) {
+            Wasm::SignatureIndex paramIndex = m_type.index;
+            Wasm::SignatureIndex argIndex;
+            if (wasmFunction)
+                argIndex = wasmFunction->signatureIndex();
+            else
+                argIndex = wasmWrapperFunction->signatureIndex();
+            if (paramIndex != argIndex) {
+                throwException(globalObject, throwScope, createJSWebAssemblyRuntimeError(globalObject, vm, "Argument function did not match the reference type"));
+                return;
+            }
+        }
         m_value.m_externref.set(m_owner->vm(), m_owner, argument);
         break;
     }

Modified: trunk/Source/_javascript_Core/wasm/WasmLLIntGenerator.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmLLIntGenerator.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmLLIntGenerator.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -562,6 +562,8 @@
             break;
         case TypeKind::Void:
         case TypeKind::Func:
+        case TypeKind::RefNull:
+        case TypeKind::Ref:
             RELEASE_ASSERT_NOT_REACHED();
         }
     };
@@ -618,6 +620,8 @@
             break;
         case TypeKind::Void:
         case TypeKind::Func:
+        case TypeKind::RefNull:
+        case TypeKind::Ref:
             RELEASE_ASSERT_NOT_REACHED();
         }
     }
@@ -646,6 +650,8 @@
             break;
         case TypeKind::Void:
         case TypeKind::Func:
+        case TypeKind::RefNull:
+        case TypeKind::Ref:
             RELEASE_ASSERT_NOT_REACHED();
         }
     }
@@ -702,6 +708,8 @@
             break;
         case TypeKind::Void:
         case TypeKind::Func:
+        case TypeKind::RefNull:
+        case TypeKind::Ref:
             RELEASE_ASSERT_NOT_REACHED();
         }
     }
@@ -751,6 +759,8 @@
             break;
         case TypeKind::Void:
         case TypeKind::Func:
+        case TypeKind::RefNull:
+        case TypeKind::Ref:
             RELEASE_ASSERT_NOT_REACHED();
         }
     }

Modified: trunk/Source/_javascript_Core/wasm/WasmParser.h (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmParser.h	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmParser.h	2021-06-25 02:23:28 UTC (rev 279265)
@@ -84,8 +84,8 @@
     bool WARN_UNUSED_RETURN parseVarInt64(int64_t&);
 
     PartialResult WARN_UNUSED_RETURN parseBlockSignature(const ModuleInformation&, BlockSignature&);
-    bool WARN_UNUSED_RETURN parseValueType(Type&);
-    bool WARN_UNUSED_RETURN parseRefType(Type&);
+    bool WARN_UNUSED_RETURN parseValueType(const ModuleInformation&, Type&);
+    bool WARN_UNUSED_RETURN parseRefType(const ModuleInformation&, Type&);
     bool WARN_UNUSED_RETURN parseExternalKind(ExternalKind&);
 
     size_t m_offset = 0;
@@ -277,7 +277,7 @@
 {
     int8_t typeKind;
     if (peekInt7(typeKind) && isValidTypeKind(typeKind)) {
-        Type type = {static_cast<TypeKind>(typeKind), 0};
+        Type type = {static_cast<TypeKind>(typeKind), Nullable::Yes, 0};
         WASM_PARSER_FAIL_IF(!(isValueType(type) || type.isVoid()), "result type of block: ", makeString(type.kind), " is not a value type or Void");
         result = m_signatureInformation.thunkFor(type);
         m_offset++;
@@ -296,22 +296,50 @@
 }
 
 template<typename SuccessType>
-ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(Type& result)
+ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(const ModuleInformation& info, Type& result)
 {
     int8_t kind;
     if (!parseInt7(kind))
         return false;
-    Type type = {static_cast<TypeKind>(kind), 0};
-    if (!isValidTypeKind(kind) || !isValueType(type))
+    if (!isValidTypeKind(kind))
         return false;
+
+    TypeKind typeKind = static_cast<TypeKind>(kind);
+    bool isNullable = true;
+    SignatureIndex sigIndex = 0;
+    if (typeKind == TypeKind::Ref || typeKind == TypeKind::RefNull) {
+        if (!Options::useWebAssemblyTypedFunctionReferences())
+            return false;
+
+        int32_t heapType;
+        isNullable = typeKind == TypeKind::RefNull;
+
+        if (!parseVarInt32(heapType))
+            return false;
+        if (heapType < 0) {
+            TypeKind heapKind = static_cast<TypeKind>(heapType);
+            if (!isValidHeapTypeKind(heapKind))
+                return false;
+            typeKind = heapKind;
+        } else {
+            typeKind = TypeKind::TypeIdx;
+            if (static_cast<size_t>(heapType) >= info.usedSignatures.size())
+                return false;
+            sigIndex = SignatureInformation::get(info.usedSignatures[heapType].get());
+        }
+    }
+
+    Type type = { typeKind, static_cast<Nullable>(isNullable), sigIndex };
+    if (!isValueType(type))
+        return false;
     result = type;
     return true;
 }
 
 template<typename SuccessType>
-ALWAYS_INLINE bool Parser<SuccessType>::parseRefType(Type& result)
+ALWAYS_INLINE bool Parser<SuccessType>::parseRefType(const ModuleInformation& info, Type& result)
 {
-    const bool parsed = parseValueType(result);
+    const bool parsed = parseValueType(info, result);
     return parsed && isRefType(result);
 }
 

Modified: trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -60,7 +60,7 @@
 
         for (unsigned i = 0; i < argumentCount; ++i) {
             Type argumentType;
-            WASM_PARSER_FAIL_IF(!parseValueType(argumentType), "can't get ", i, "th argument Type");
+            WASM_PARSER_FAIL_IF(!parseValueType(m_info, argumentType), "can't get ", i, "th argument Type");
             arguments.append(argumentType);
         }
 
@@ -72,7 +72,7 @@
         WASM_PARSER_FAIL_IF(!returnTypes.tryReserveCapacity(argumentCount), "can't allocate enough memory for Type section's ", i, "th signature");
         for (unsigned i = 0; i < returnCount; ++i) {
             Type value;
-            WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value");
+            WASM_PARSER_FAIL_IF(!parseValueType(m_info, value), "can't get ", i, "th Type's return value");
             returnTypes.append(value);
         }
 
@@ -483,7 +483,7 @@
         case 0x05: {
             WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
             Type refType;
-            WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
+            WASM_PARSER_FAIL_IF(!parseRefType(m_info, refType), "can't parse reftype in elem section");
             WASM_PARSER_FAIL_IF(!refType.isFuncref(), "reftype in element section should be funcref");
 
             uint32_t indexCount;
@@ -507,7 +507,7 @@
             WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr));
 
             Type refType;
-            WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
+            WASM_PARSER_FAIL_IF(!parseRefType(m_info, refType), "can't parse reftype in elem section");
             WASM_PARSER_FAIL_IF(!refType.isFuncref(), "reftype in element section should be funcref");
 
             uint32_t indexCount;
@@ -525,7 +525,7 @@
             WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
 
             Type refType;
-            WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
+            WASM_PARSER_FAIL_IF(!parseRefType(m_info, refType), "can't parse reftype in elem section");
             WASM_PARSER_FAIL_IF(!refType.isFuncref(), "reftype in element section should be funcref");
 
             uint32_t indexCount;
@@ -605,7 +605,7 @@
 
     case RefNull: {
         Type typeOfNull;
-        WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a reference type");
+        WASM_PARSER_FAIL_IF(!parseRefType(m_info, typeOfNull), "ref.null type must be a reference type");
         resultType = typeOfNull;
         bitsOrImportNumber = JSValue::encode(jsNull());
         break;
@@ -616,7 +616,12 @@
         WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ref.func index");
         WASM_PARSER_FAIL_IF(index >= m_info->functions.size(), "ref.func index", index, " exceeds the number of functions ", m_info->functions.size());
 
-        resultType = Types::Funcref;
+        if (Options::useWebAssemblyTypedFunctionReferences()) {
+            SignatureIndex signatureIndex = m_info->signatureIndexFromFunctionIndexSpace(index);
+            resultType = { TypeKind::TypeIdx, Nullable::No, signatureIndex };
+        } else
+            resultType = Types::Funcref;
+
         bitsOrImportNumber = index;
         break;
     }
@@ -691,7 +696,7 @@
             m_info->addDeclaredFunction(functionIndex);
         } else {
             Type typeOfNull;
-            WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a func type in elem section");
+            WASM_PARSER_FAIL_IF(!parseRefType(m_info, typeOfNull), "ref.null type must be a func type in elem section");
             WASM_PARSER_FAIL_IF(!typeOfNull.isFuncref(), "ref.null extern is forbidden in element section's, ", elementNum, "th element's ", index, "th index");
             functionIndex = Element::nullFuncIndex;
         }
@@ -727,7 +732,7 @@
 auto SectionParser::parseGlobalType(GlobalInformation& global) -> PartialResult
 {
     uint8_t mutability;
-    WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type");
+    WASM_PARSER_FAIL_IF(!parseValueType(m_info, global.type), "can't get Global's value type");
     WASM_PARSER_FAIL_IF(!parseUInt8(mutability), "can't get Global type's mutability");
     WASM_PARSER_FAIL_IF(mutability != 0x0 && mutability != 0x1, "invalid Global's mutability: 0x", hex(mutability, 2, Lowercase));
     global.mutability = static_cast<GlobalInformation::Mutability>(mutability);

Modified: trunk/Source/_javascript_Core/wasm/WasmSignature.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/WasmSignature.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/WasmSignature.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -70,10 +70,12 @@
     unsigned accumulator = 0xa1bcedd8u;
     for (uint32_t i = 0; i < argumentCount; ++i) {
         accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(argumentTypes[i].kind)));
+        accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(argumentTypes[i].nullable)));
         accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<unsigned>::hash(argumentTypes[i].index));
     }
     for (uint32_t i = 0; i < returnCount; ++i) {
         accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(returnTypes[i].kind)));
+        accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(returnTypes[i].nullable)));
         accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<unsigned>::hash(returnTypes[i].index));
     }
     return accumulator;

Modified: trunk/Source/_javascript_Core/wasm/generateWasmOpsHeader.py (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/generateWasmOpsHeader.py	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/generateWasmOpsHeader.py	2021-06-25 02:23:28 UTC (rev 279265)
@@ -212,15 +212,21 @@
 };
 #undef CREATE_ENUM_VALUE
 
+enum class Nullable : bool {
+  No = false,
+  Yes = true,
+};
+
 using SignatureIndex = uintptr_t;
 
 struct Type {
     TypeKind kind;
+    Nullable nullable;
     SignatureIndex index;
 
     bool operator==(const Type& other) const
     {
-        return other.kind == kind && other.index == index;
+        return other.kind == kind && other.nullable == nullable && other.index == index;
     }
 
     bool operator!=(const Type& other) const
@@ -228,6 +234,11 @@
         return !(other == *this);
     }
 
+    bool isNullable() const
+    {
+        return static_cast<bool>(nullable);
+    }
+
     #define CREATE_PREDICATE(name, ...) bool is ## name() const { return kind == TypeKind::name; }
     FOR_EACH_WASM_TYPE(CREATE_PREDICATE)
     #undef CREATE_PREDICATE
@@ -235,7 +246,7 @@
 
 namespace Types
 {
-#define CREATE_CONSTANT(name, id, ...) constexpr Type name = Type{TypeKind::name, 0u};
+#define CREATE_CONSTANT(name, id, ...) constexpr Type name = Type{TypeKind::name, Nullable::Yes, 0u};
 FOR_EACH_WASM_TYPE(CREATE_CONSTANT)
 #undef CREATE_CONSTANT
 } // namespace Types

Modified: trunk/Source/_javascript_Core/wasm/js/WasmToJS.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/js/WasmToJS.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/js/WasmToJS.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -104,6 +104,8 @@
             switch (argType.kind) {
             case TypeKind::Void:
             case TypeKind::Func:
+            case TypeKind::RefNull:
+            case TypeKind::Ref:
                 RELEASE_ASSERT_NOT_REACHED(); // Handled above.
             case TypeKind::TypeIdx:
             case TypeKind::Externref:
@@ -177,6 +179,8 @@
             switch (argType.kind) {
             case TypeKind::Void:
             case TypeKind::Func:
+            case TypeKind::RefNull:
+            case TypeKind::Ref:
                 RELEASE_ASSERT_NOT_REACHED(); // Handled above.
             case TypeKind::TypeIdx:
             case TypeKind::Externref:
@@ -278,6 +282,8 @@
         switch (signature.returnType(0).kind) {
         case TypeKind::Void:
         case TypeKind::Func:
+        case TypeKind::RefNull:
+        case TypeKind::Ref:
             // For the _javascript_ embedding, imports with these types in their signature return are a WebAssembly.Module validation error.
             RELEASE_ASSERT_NOT_REACHED();
             break;

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -85,11 +85,26 @@
             break;
         case Wasm::TypeKind::TypeIdx:
         case Wasm::TypeKind::Funcref: {
-            if (!isWebAssemblyHostFunction(vm, arg) && !arg.isNull())
+            bool isNullable = signature.argument(argIndex).isNullable();
+            WebAssemblyFunction* wasmFunction = nullptr;
+            WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
+            if (!isWebAssemblyHostFunction(vm, arg, wasmFunction, wasmWrapperFunction) && (!isNullable || !arg.isNull()))
                 return JSValue::encode(throwException(globalObject, scope, createJSWebAssemblyRuntimeError(globalObject, vm, "Funcref must be an exported wasm function")));
+            if (signature.argument(argIndex).kind == Wasm::TypeKind::TypeIdx && (wasmFunction || wasmWrapperFunction)) {
+                Wasm::SignatureIndex paramIndex = signature.argument(argIndex).index;
+                Wasm::SignatureIndex argIndex;
+                if (wasmFunction)
+                    argIndex = wasmFunction->signatureIndex();
+                else
+                    argIndex = wasmWrapperFunction->signatureIndex();
+                if (paramIndex != argIndex)
+                    return JSValue::encode(throwException(globalObject, scope, createJSWebAssemblyRuntimeError(globalObject, vm, "Argument function did not match the reference type")));
+            }
             break;
         }
         case Wasm::TypeKind::Externref:
+            if (!signature.argument(argIndex).isNullable() && arg.isNull())
+                return JSValue::encode(throwException(globalObject, scope, createJSWebAssemblyRuntimeError(globalObject, vm, "Non-null Externref cannot be null")));
             break;
         case Wasm::TypeKind::I64:
             arg = JSValue::decode(bitwise_cast<uint64_t>(arg.toBigInt64(globalObject)));
@@ -102,6 +117,8 @@
             break;
         case Wasm::TypeKind::Void:
         case Wasm::TypeKind::Func:
+        case Wasm::TypeKind::RefNull:
+        case Wasm::TypeKind::Ref:
             RELEASE_ASSERT_NOT_REACHED();
         }
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
@@ -277,10 +294,13 @@
                 jit.zeroExtend32ToWord(scratchGPR, wasmCallInfo.params[i].gpr());
             break;
         }
+        case Wasm::TypeKind::TypeIdx:
         case Wasm::TypeKind::Funcref: {
             // Ensure we have a WASM exported function.
             jit.load64(jsParam, scratchGPR);
             auto isNull = jit.branchIfNull(scratchGPR);
+            if (!type.isNullable())
+                slowPath.append(isNull);
             slowPath.append(jit.branchIfNotCell(scratchGPR));
 
             stackLimitGPRIsClobbered = true;
@@ -294,15 +314,28 @@
             slowPath.append(jit.branchPtr(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImmPtr(WebAssemblyWrapperFunction::info())));
 
             isWasmFunction.link(&jit);
-            isNull.link(&jit);
+            if (type.kind == Wasm::TypeKind::TypeIdx) {
+                jit.load64(jsParam, scratchGPR);
+                jit.loadPtr(CCallHelpers::Address(scratchGPR, WebAssemblyFunctionBase::offsetOfSignatureIndex()), scratchGPR);
+                slowPath.append(jit.branchPtr(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImmPtr(type.index)));
+            }
+
+            if (type.isNullable())
+                isNull.link(&jit);
             FALLTHROUGH;
         }
         case Wasm::TypeKind::Externref: {
             if (isStack) {
                 jit.load64(jsParam, scratchGPR);
+                if (!type.isNullable())
+                    slowPath.append(jit.branchIfNull(scratchGPR));
                 jit.store64(scratchGPR, calleeFrame.withOffset(wasmCallInfo.params[i].offsetFromSP()));
-            } else
-                jit.load64(jsParam, wasmCallInfo.params[i].gpr());
+            } else {
+                auto externGPR = wasmCallInfo.params[i].gpr();
+                jit.load64(jsParam, externGPR);
+                if (!type.isNullable())
+                    slowPath.append(jit.branchIfNull(externGPR));
+            }
             break;
         }
         case Wasm::TypeKind::F32:

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.h (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.h	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunctionBase.h	2021-06-25 02:23:28 UTC (rev 279265)
@@ -52,6 +52,8 @@
 
     static ptrdiff_t offsetOfInstance() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_instance); }
 
+    static ptrdiff_t offsetOfSignatureIndex() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_importableFunction) + WasmToWasmImportableFunction::offsetOfSignatureIndex(); }
+
     static ptrdiff_t offsetOfEntrypointLoadLocation() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_importableFunction) + WasmToWasmImportableFunction::offsetOfEntrypointLoadLocation(); }
 
 protected:

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2021-06-25 02:23:28 UTC (rev 279265)
@@ -247,16 +247,35 @@
                     if (globalValue->global()->mutability() != Wasm::GlobalInformation::Immutable)
                         return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "must be a same mutability")));
                     switch (moduleInformation.globals[import.kindIndex].type.kind) {
-                    case Wasm::TypeKind::Funcref:
+                    case Wasm::TypeKind::TypeIdx:
+                    case Wasm::TypeKind::Funcref: {
+                        bool isNullable = global.type.isNullable();
+                        WebAssemblyFunction* wasmFunction = nullptr;
+                        WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
                         value = globalValue->global()->get(globalObject);
                         RETURN_IF_EXCEPTION(scope, void());
-                        if (!isWebAssemblyHostFunction(vm, value) && !value.isNull())
-                            return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "must be a wasm exported function or null")));
+                        if (!isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction) && (!isNullable || !value.isNull())) {
+                            const char* msg = isNullable ? "must be a wasm exported function or null" : "must be a wasm exported function";
+                            return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", msg)));
+                        }
+                        if (global.type.kind == Wasm::TypeKind::TypeIdx && (wasmFunction || wasmWrapperFunction)) {
+                            Wasm::SignatureIndex paramIndex = global.type.index;
+                            Wasm::SignatureIndex argIndex;
+                            if (wasmFunction)
+                                argIndex = wasmFunction->signatureIndex();
+                            else
+                                argIndex = wasmWrapperFunction->signatureIndex();
+                            if (paramIndex != argIndex)
+                                return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "Argument function did not match the reference type")));
+                        }
                         m_instance->instance().setGlobal(import.kindIndex, value);
                         break;
+                    }
                     case Wasm::TypeKind::Externref:
                         value = globalValue->global()->get(globalObject);
                         RETURN_IF_EXCEPTION(scope, void());
+                        if (!global.type.isNullable() && value.isNull())
+                            return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "non-null externref cannot be null")));
                         m_instance->instance().setGlobal(import.kindIndex, value);
                         break;
                     case Wasm::TypeKind::I32:
@@ -283,12 +302,31 @@
 
                     // iii. Append ToWebAssemblyValue(v) to imports.
                     switch (globalType.kind) {
-                    case Wasm::TypeKind::Funcref:
-                        if (!isWebAssemblyHostFunction(vm, value) && !value.isNull())
-                            return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "must be a wasm exported function or null")));
+                    case Wasm::TypeKind::TypeIdx:
+                    case Wasm::TypeKind::Funcref: {
+                        bool isNullable = globalType.isNullable();
+                        WebAssemblyFunction* wasmFunction = nullptr;
+                        WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
+                        if (!isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction) && (!isNullable || !value.isNull())) {
+                            const char* msg = isNullable ? "must be a wasm exported function or null" : "must be a wasm exported function";
+                            return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", msg)));
+                        }
+                        if (globalType.kind == Wasm::TypeKind::TypeIdx && (wasmFunction || wasmWrapperFunction)) {
+                            Wasm::SignatureIndex paramIndex = global.type.index;
+                            Wasm::SignatureIndex argIndex;
+                            if (wasmFunction)
+                                argIndex = wasmFunction->signatureIndex();
+                            else
+                                argIndex = wasmWrapperFunction->signatureIndex();
+                            if (paramIndex != argIndex)
+                                return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "Argument function did not match the reference type")));
+                        }
                         m_instance->instance().setGlobal(import.kindIndex, value);
                         break;
+                    }
                     case Wasm::TypeKind::Externref:
+                        if (!globalType.isNullable() && value.isNull())
+                            return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "must be a non-null value")));
                         m_instance->instance().setGlobal(import.kindIndex, value);
                         break;
                     case Wasm::TypeKind::I32:
@@ -490,6 +528,7 @@
             switch (global.type.kind) {
             case Wasm::TypeKind::Externref:
             case Wasm::TypeKind::Funcref:
+            case Wasm::TypeKind::TypeIdx:
             case Wasm::TypeKind::I32:
             case Wasm::TypeKind::I64:
             case Wasm::TypeKind::F32:

Modified: trunk/Source/_javascript_Core/wasm/wasm.json (279264 => 279265)


--- trunk/Source/_javascript_Core/wasm/wasm.json	2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/_javascript_Core/wasm/wasm.json	2021-06-25 02:23:28 UTC (rev 279265)
@@ -13,6 +13,8 @@
         "f64":       { "type": "varint7", "value":   -4, "b3type": "B3::Double" },
         "funcref":   { "type": "varint7", "value":  -16, "b3type": "B3::Int64" },
         "externref": { "type": "varint7", "value":  -17, "b3type": "B3::Int64" },
+        "ref_null":  { "type": "varint7", "value":  -20, "b3type": "B3::Int64" },
+        "ref":       { "type": "varint7", "value":  -21, "b3type": "B3::Int64" },
         "func":      { "type": "varint7", "value":  -32, "b3type": "B3::Void" },
         "void":      { "type": "varint7", "value":  -64, "b3type": "B3::Void" },
         "type_idx":  { "type": "varint7", "value": -128, "b3type": "B3::Int64" }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to