<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[279265] trunk</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/279265">279265</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2021-06-24 19:23:28 -0700 (Thu, 24 Jun 2021)</dd>
</dl>
<h3>Log Message</h3>
<pre>[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 <asumu@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/JavaScriptCore:
Patch by Asumu Takikawa <asumu@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:</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkJSTestsChangeLog">trunk/JSTests/ChangeLog</a></li>
<li><a href="#trunkJSTestswasmwasmjson">trunk/JSTests/wasm/wasm.json</a></li>
<li><a href="#trunkSourceJavaScriptCoreChangeLog">trunk/Source/JavaScriptCore/ChangeLog</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmAirIRGeneratorcpp">trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmCallingConventionh">trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmFormath">trunk/Source/JavaScriptCore/wasm/WasmFormat.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmFunctionParserh">trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmGlobalcpp">trunk/Source/JavaScriptCore/wasm/WasmGlobal.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmLLIntGeneratorcpp">trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmParserh">trunk/Source/JavaScriptCore/wasm/WasmParser.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmSectionParsercpp">trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmWasmSignaturecpp">trunk/Source/JavaScriptCore/wasm/WasmSignature.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmgenerateWasmOpsHeaderpy">trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWasmToJScpp">trunk/Source/JavaScriptCore/wasm/js/WasmToJS.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyFunctioncpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyFunctionBaseh">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunctionBase.h</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp">trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp</a></li>
<li><a href="#trunkSourceJavaScriptCorewasmwasmjson">trunk/Source/JavaScriptCore/wasm/wasm.json</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#trunkJSTestswasmfunctionreferencesref_typesjs">trunk/JSTests/wasm/function-references/ref_types.js</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkJSTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/ChangeLog (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/JSTests/ChangeLog 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/JSTests/ChangeLog 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2021-06-24 Asumu Takikawa <asumu@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:
+
</ins><span class="cx"> 2021-06-24 Guillaume Emont <guijemont@igalia.com>
</span><span class="cx">
</span><span class="cx"> Improve our checking of NaN values in DataView tests
</span></span></pre></div>
<a id="trunkJSTestswasmfunctionreferencesref_typesjs"></a>
<div class="addfile"><h4>Added: trunk/JSTests/wasm/function-references/ref_types.js (0 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -0,0 +1,316 @@
</span><ins>+//@ 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());
</ins></span></pre></div>
<a id="trunkJSTestswasmwasmjson"></a>
<div class="modfile"><h4>Modified: trunk/JSTests/wasm/wasm.json (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -13,6 +13,8 @@
</span><span class="cx"> "f64": { "type": "varint7", "value": -4, "b3type": "B3::Double" },
</span><span class="cx"> "funcref": { "type": "varint7", "value": -16, "b3type": "B3::Int64" },
</span><span class="cx"> "externref": { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
</span><ins>+ "ref_null": { "type": "varint7", "value": -20, "b3type": "B3::Int64" },
+ "ref": { "type": "varint7", "value": -21, "b3type": "B3::Int64" },
</ins><span class="cx"> "func": { "type": "varint7", "value": -32, "b3type": "B3::Void" },
</span><span class="cx"> "void": { "type": "varint7", "value": -64, "b3type": "B3::Void" },
</span><span class="cx"> "type_idx": { "type": "varint7", "value": -128, "b3type": "B3::Int64" }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/ChangeLog (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/ChangeLog 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/ChangeLog 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -1,3 +1,76 @@
</span><ins>+2021-06-24 Asumu Takikawa <asumu@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:
+
</ins><span class="cx"> 2021-06-24 Mark Lam <mark.lam@apple.com>
</span><span class="cx">
</span><span class="cx"> Use ldp and stp more for saving / restoring registers on ARM64.
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmAirIRGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -413,6 +413,7 @@
</span><span class="cx"> TypedTmp g64() { return { newTmp(B3::GP), Types::I64 }; }
</span><span class="cx"> TypedTmp gExternref() { return { newTmp(B3::GP), Types::Externref }; }
</span><span class="cx"> TypedTmp gFuncref() { return { newTmp(B3::GP), Types::Funcref }; }
</span><ins>+ TypedTmp gTypeIdx(Type type) { return { newTmp(B3::GP), type }; }
</ins><span class="cx"> TypedTmp f32() { return { newTmp(B3::FP), Types::F32 }; }
</span><span class="cx"> TypedTmp f64() { return { newTmp(B3::FP), Types::F64 }; }
</span><span class="cx">
</span><span class="lines">@@ -425,6 +426,8 @@
</span><span class="cx"> return g64();
</span><span class="cx"> case TypeKind::Funcref:
</span><span class="cx"> return gFuncref();
</span><ins>+ case TypeKind::TypeIdx:
+ return gTypeIdx(type);
</ins><span class="cx"> case TypeKind::Externref:
</span><span class="cx"> return gExternref();
</span><span class="cx"> case TypeKind::F32:
</span><span class="lines">@@ -601,6 +604,7 @@
</span><span class="cx"> case TypeKind::I64:
</span><span class="cx"> case TypeKind::Externref:
</span><span class="cx"> case TypeKind::Funcref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> resultType = B3::Int64;
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::F32:
</span><span class="lines">@@ -650,6 +654,7 @@
</span><span class="cx"> case TypeKind::I64:
</span><span class="cx"> case TypeKind::Externref:
</span><span class="cx"> case TypeKind::Funcref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> return Move;
</span><span class="cx"> case TypeKind::F32:
</span><span class="cx"> return MoveFloat;
</span><span class="lines">@@ -907,6 +912,7 @@
</span><span class="cx"> case TypeKind::I64:
</span><span class="cx"> case TypeKind::Externref:
</span><span class="cx"> case TypeKind::Funcref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> append(Move, arg, m_locals[i]);
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::F32:
</span><span class="lines">@@ -1009,6 +1015,7 @@
</span><span class="cx"> switch (type.kind) {
</span><span class="cx"> case TypeKind::Externref:
</span><span class="cx"> case TypeKind::Funcref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> append(Move, Arg::imm(JSValue::encode(jsNull())), local);
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::I32:
</span><span class="lines">@@ -1044,6 +1051,7 @@
</span><span class="cx"> case TypeKind::I64:
</span><span class="cx"> case TypeKind::Externref:
</span><span class="cx"> case TypeKind::Funcref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> append(block, Move, Arg::bigImm(value), result);
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::F32:
</span><span class="lines">@@ -1088,7 +1096,11 @@
</span><span class="cx"> auto AirIRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> PartialResult
</span><span class="cx"> {
</span><span class="cx"> // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
</span><del>- result = tmpForType(Types::Funcref);
</del><ins>+ if (Options::useWebAssemblyTypedFunctionReferences()) {
+ SignatureIndex signatureIndex = m_info.signatureIndexFromFunctionIndexSpace(index);
+ result = tmpForType(Type { TypeKind::TypeIdx, Nullable::No, signatureIndex });
+ } else
+ result = tmpForType(Types::Funcref);
</ins><span class="cx"> emitCCall(&operationWasmRefFunc, result, instanceValue(), addConstant(Types::I32, index));
</span><span class="cx">
</span><span class="cx"> return { };
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmCallingConventionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmCallingConvention.h 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -107,6 +107,7 @@
</span><span class="cx"> case TypeKind::I64:
</span><span class="cx"> case TypeKind::Funcref:
</span><span class="cx"> case TypeKind::Externref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> return marshallLocationImpl(role, gprArgs, gpArgumentCount, stackOffset);
</span><span class="cx"> case TypeKind::F32:
</span><span class="cx"> case TypeKind::F64:
</span><span class="lines">@@ -195,6 +196,7 @@
</span><span class="cx"> case TypeKind::I64:
</span><span class="cx"> case TypeKind::Funcref:
</span><span class="cx"> case TypeKind::Externref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> return marshallLocationImpl(role, gprArgs, gpArgumentCount, stackOffset);
</span><span class="cx"> case TypeKind::F32:
</span><span class="cx"> case TypeKind::F64:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmFormath"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmFormat.h (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmFormat.h 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmFormat.h 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -79,6 +79,9 @@
</span><span class="cx">
</span><span class="cx"> inline bool isSubtype(Type sub, Type parent)
</span><span class="cx"> {
</span><ins>+ if (sub.isNullable() && !parent.isNullable())
+ return false;
+
</ins><span class="cx"> if (sub.isTypeIdx() && parent.isFuncref())
</span><span class="cx"> return true;
</span><span class="cx">
</span><span class="lines">@@ -90,6 +93,23 @@
</span><span class="cx"> return type.isFuncref() || type.isExternref() || type.isTypeIdx();
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+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();
+}
+
</ins><span class="cx"> enum class ExternalKind : uint8_t {
</span><span class="cx"> // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
</span><span class="cx"> Function = 0,
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmFunctionParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmFunctionParser.h 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -243,7 +243,8 @@
</span><span class="cx"> WASM_PARSER_FAIL_IF(!parseVarUInt32(numberOfLocals), "can't get Function's number of locals in group ", i);
</span><span class="cx"> totalNumberOfLocals += numberOfLocals;
</span><span class="cx"> WASM_PARSER_FAIL_IF(totalNumberOfLocals > maxFunctionLocals, "Function's number of locals is too big ", totalNumberOfLocals, " maximum ", maxFunctionLocals);
</span><del>- WASM_PARSER_FAIL_IF(!parseValueType(typeOfLocal), "can't get Function local's type in group ", i);
</del><ins>+ 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");
</ins><span class="cx">
</span><span class="cx"> WASM_PARSER_FAIL_IF(!m_locals.tryReserveCapacity(totalNumberOfLocals), "can't allocate enough memory for function's ", totalNumberOfLocals, " locals");
</span><span class="cx"> for (uint32_t i = 0; i < numberOfLocals; ++i)
</span><span class="lines">@@ -644,7 +645,7 @@
</span><span class="cx"> WASM_PARSER_FAIL_IF(sizeOfAnnotationVector != 1, "select invalid result arity for");
</span><span class="cx">
</span><span class="cx"> Type targetType;
</span><del>- WASM_PARSER_FAIL_IF(!parseValueType(targetType), "select can't parse annotations");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseValueType(m_info, targetType), "select can't parse annotations");
</ins><span class="cx">
</span><span class="cx"> result.sizeOfAnnotationVector = sizeOfAnnotationVector;
</span><span class="cx"> result.targetType = targetType;
</span><span class="lines">@@ -699,7 +700,7 @@
</span><span class="cx">
</span><span class="cx"> unsigned offset = m_expressionStack.size() - target.branchTargetArity();
</span><span class="cx"> for (unsigned i = 0; i < target.branchTargetArity(); ++i)
</span><del>- 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);
</del><ins>+ 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);
</ins><span class="cx">
</span><span class="cx"> return { };
</span><span class="cx"> }
</span><span class="lines">@@ -1079,7 +1080,7 @@
</span><span class="cx"> case RefNull: {
</span><span class="cx"> WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
</span><span class="cx"> Type typeOfNull;
</span><del>- WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a reference type");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseRefType(m_info, typeOfNull), "ref.null type must be a reference type");
</ins><span class="cx"> m_expressionStack.constructAndAppend(typeOfNull, m_context.addConstant(typeOfNull, JSValue::encode(jsNull())));
</span><span class="cx"> return { };
</span><span class="cx"> }
</span><span class="lines">@@ -1109,7 +1110,7 @@
</span><span class="cx">
</span><span class="cx"> if (Options::useWebAssemblyTypedFunctionReferences()) {
</span><span class="cx"> SignatureIndex signatureIndex = m_info.signatureIndexFromFunctionIndexSpace(index);
</span><del>- m_expressionStack.constructAndAppend(Type {TypeKind::TypeIdx, signatureIndex}, result);
</del><ins>+ m_expressionStack.constructAndAppend(Type {TypeKind::TypeIdx, Nullable::No, signatureIndex}, result);
</ins><span class="cx"> return { };
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmGlobalcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmGlobal.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmGlobal.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmGlobal.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -48,6 +48,7 @@
</span><span class="cx"> return jsNumber(purifyNaN(bitwise_cast<double>(m_value.m_primitive)));
</span><span class="cx"> case TypeKind::Externref:
</span><span class="cx"> case TypeKind::Funcref:
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> return m_value.m_externref.get();
</span><span class="cx"> default:
</span><span class="cx"> return jsUndefined();
</span><span class="lines">@@ -86,15 +87,35 @@
</span><span class="cx"> }
</span><span class="cx"> case TypeKind::Externref: {
</span><span class="cx"> RELEASE_ASSERT(m_owner);
</span><ins>+ if (!m_type.isNullable() && argument.isNull()) {
+ throwException(globalObject, throwScope, createJSWebAssemblyRuntimeError(globalObject, vm, "Non-null Externref cannot be null"));
+ return;
+ }
</ins><span class="cx"> m_value.m_externref.set(m_owner->vm(), m_owner, argument);
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+ case TypeKind::TypeIdx:
</ins><span class="cx"> case TypeKind::Funcref: {
</span><span class="cx"> RELEASE_ASSERT(m_owner);
</span><del>- if (!isWebAssemblyHostFunction(vm, argument) && !argument.isNull()) {
</del><ins>+ bool isNullable = m_type.isNullable();
+ WebAssemblyFunction* wasmFunction = nullptr;
+ WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
+ if (!isWebAssemblyHostFunction(vm, argument, wasmFunction, wasmWrapperFunction) && (!isNullable || !argument.isNull())) {
</ins><span class="cx"> throwException(globalObject, throwScope, createJSWebAssemblyRuntimeError(globalObject, vm, "Funcref must be an exported wasm function"));
</span><span class="cx"> return;
</span><span class="cx"> }
</span><ins>+ 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;
+ }
+ }
</ins><span class="cx"> m_value.m_externref.set(m_owner->vm(), m_owner, argument);
</span><span class="cx"> break;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmLLIntGeneratorcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -562,6 +562,8 @@
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> };
</span><span class="lines">@@ -618,6 +620,8 @@
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -646,6 +650,8 @@
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -702,6 +708,8 @@
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> }
</span><span class="lines">@@ -751,6 +759,8 @@
</span><span class="cx"> break;
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmParserh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmParser.h (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmParser.h 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmParser.h 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -84,8 +84,8 @@
</span><span class="cx"> bool WARN_UNUSED_RETURN parseVarInt64(int64_t&);
</span><span class="cx">
</span><span class="cx"> PartialResult WARN_UNUSED_RETURN parseBlockSignature(const ModuleInformation&, BlockSignature&);
</span><del>- bool WARN_UNUSED_RETURN parseValueType(Type&);
- bool WARN_UNUSED_RETURN parseRefType(Type&);
</del><ins>+ bool WARN_UNUSED_RETURN parseValueType(const ModuleInformation&, Type&);
+ bool WARN_UNUSED_RETURN parseRefType(const ModuleInformation&, Type&);
</ins><span class="cx"> bool WARN_UNUSED_RETURN parseExternalKind(ExternalKind&);
</span><span class="cx">
</span><span class="cx"> size_t m_offset = 0;
</span><span class="lines">@@ -277,7 +277,7 @@
</span><span class="cx"> {
</span><span class="cx"> int8_t typeKind;
</span><span class="cx"> if (peekInt7(typeKind) && isValidTypeKind(typeKind)) {
</span><del>- Type type = {static_cast<TypeKind>(typeKind), 0};
</del><ins>+ Type type = {static_cast<TypeKind>(typeKind), Nullable::Yes, 0};
</ins><span class="cx"> WASM_PARSER_FAIL_IF(!(isValueType(type) || type.isVoid()), "result type of block: ", makeString(type.kind), " is not a value type or Void");
</span><span class="cx"> result = m_signatureInformation.thunkFor(type);
</span><span class="cx"> m_offset++;
</span><span class="lines">@@ -296,22 +296,50 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename SuccessType>
</span><del>-ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(Type& result)
</del><ins>+ALWAYS_INLINE bool Parser<SuccessType>::parseValueType(const ModuleInformation& info, Type& result)
</ins><span class="cx"> {
</span><span class="cx"> int8_t kind;
</span><span class="cx"> if (!parseInt7(kind))
</span><span class="cx"> return false;
</span><del>- Type type = {static_cast<TypeKind>(kind), 0};
- if (!isValidTypeKind(kind) || !isValueType(type))
</del><ins>+ if (!isValidTypeKind(kind))
</ins><span class="cx"> return false;
</span><ins>+
+ 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;
</ins><span class="cx"> result = type;
</span><span class="cx"> return true;
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> template<typename SuccessType>
</span><del>-ALWAYS_INLINE bool Parser<SuccessType>::parseRefType(Type& result)
</del><ins>+ALWAYS_INLINE bool Parser<SuccessType>::parseRefType(const ModuleInformation& info, Type& result)
</ins><span class="cx"> {
</span><del>- const bool parsed = parseValueType(result);
</del><ins>+ const bool parsed = parseValueType(info, result);
</ins><span class="cx"> return parsed && isRefType(result);
</span><span class="cx"> }
</span><span class="cx">
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmSectionParsercpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmSectionParser.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx">
</span><span class="cx"> for (unsigned i = 0; i < argumentCount; ++i) {
</span><span class="cx"> Type argumentType;
</span><del>- WASM_PARSER_FAIL_IF(!parseValueType(argumentType), "can't get ", i, "th argument Type");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseValueType(m_info, argumentType), "can't get ", i, "th argument Type");
</ins><span class="cx"> arguments.append(argumentType);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -72,7 +72,7 @@
</span><span class="cx"> WASM_PARSER_FAIL_IF(!returnTypes.tryReserveCapacity(argumentCount), "can't allocate enough memory for Type section's ", i, "th signature");
</span><span class="cx"> for (unsigned i = 0; i < returnCount; ++i) {
</span><span class="cx"> Type value;
</span><del>- WASM_PARSER_FAIL_IF(!parseValueType(value), "can't get ", i, "th Type's return value");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseValueType(m_info, value), "can't get ", i, "th Type's return value");
</ins><span class="cx"> returnTypes.append(value);
</span><span class="cx"> }
</span><span class="cx">
</span><span class="lines">@@ -483,7 +483,7 @@
</span><span class="cx"> case 0x05: {
</span><span class="cx"> WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
</span><span class="cx"> Type refType;
</span><del>- WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseRefType(m_info, refType), "can't parse reftype in elem section");
</ins><span class="cx"> WASM_PARSER_FAIL_IF(!refType.isFuncref(), "reftype in element section should be funcref");
</span><span class="cx">
</span><span class="cx"> uint32_t indexCount;
</span><span class="lines">@@ -507,7 +507,7 @@
</span><span class="cx"> WASM_FAIL_IF_HELPER_FAILS(parseI32InitExprForElementSection(initExpr));
</span><span class="cx">
</span><span class="cx"> Type refType;
</span><del>- WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseRefType(m_info, refType), "can't parse reftype in elem section");
</ins><span class="cx"> WASM_PARSER_FAIL_IF(!refType.isFuncref(), "reftype in element section should be funcref");
</span><span class="cx">
</span><span class="cx"> uint32_t indexCount;
</span><span class="lines">@@ -525,7 +525,7 @@
</span><span class="cx"> WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
</span><span class="cx">
</span><span class="cx"> Type refType;
</span><del>- WASM_PARSER_FAIL_IF(!parseRefType(refType), "can't parse reftype in elem section");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseRefType(m_info, refType), "can't parse reftype in elem section");
</ins><span class="cx"> WASM_PARSER_FAIL_IF(!refType.isFuncref(), "reftype in element section should be funcref");
</span><span class="cx">
</span><span class="cx"> uint32_t indexCount;
</span><span class="lines">@@ -605,7 +605,7 @@
</span><span class="cx">
</span><span class="cx"> case RefNull: {
</span><span class="cx"> Type typeOfNull;
</span><del>- WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a reference type");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseRefType(m_info, typeOfNull), "ref.null type must be a reference type");
</ins><span class="cx"> resultType = typeOfNull;
</span><span class="cx"> bitsOrImportNumber = JSValue::encode(jsNull());
</span><span class="cx"> break;
</span><span class="lines">@@ -616,7 +616,12 @@
</span><span class="cx"> WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ref.func index");
</span><span class="cx"> WASM_PARSER_FAIL_IF(index >= m_info->functions.size(), "ref.func index", index, " exceeds the number of functions ", m_info->functions.size());
</span><span class="cx">
</span><del>- resultType = Types::Funcref;
</del><ins>+ if (Options::useWebAssemblyTypedFunctionReferences()) {
+ SignatureIndex signatureIndex = m_info->signatureIndexFromFunctionIndexSpace(index);
+ resultType = { TypeKind::TypeIdx, Nullable::No, signatureIndex };
+ } else
+ resultType = Types::Funcref;
+
</ins><span class="cx"> bitsOrImportNumber = index;
</span><span class="cx"> break;
</span><span class="cx"> }
</span><span class="lines">@@ -691,7 +696,7 @@
</span><span class="cx"> m_info->addDeclaredFunction(functionIndex);
</span><span class="cx"> } else {
</span><span class="cx"> Type typeOfNull;
</span><del>- WASM_PARSER_FAIL_IF(!parseRefType(typeOfNull), "ref.null type must be a func type in elem section");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseRefType(m_info, typeOfNull), "ref.null type must be a func type in elem section");
</ins><span class="cx"> WASM_PARSER_FAIL_IF(!typeOfNull.isFuncref(), "ref.null extern is forbidden in element section's, ", elementNum, "th element's ", index, "th index");
</span><span class="cx"> functionIndex = Element::nullFuncIndex;
</span><span class="cx"> }
</span><span class="lines">@@ -727,7 +732,7 @@
</span><span class="cx"> auto SectionParser::parseGlobalType(GlobalInformation& global) -> PartialResult
</span><span class="cx"> {
</span><span class="cx"> uint8_t mutability;
</span><del>- WASM_PARSER_FAIL_IF(!parseValueType(global.type), "can't get Global's value type");
</del><ins>+ WASM_PARSER_FAIL_IF(!parseValueType(m_info, global.type), "can't get Global's value type");
</ins><span class="cx"> WASM_PARSER_FAIL_IF(!parseUInt8(mutability), "can't get Global type's mutability");
</span><span class="cx"> WASM_PARSER_FAIL_IF(mutability != 0x0 && mutability != 0x1, "invalid Global's mutability: 0x", hex(mutability, 2, Lowercase));
</span><span class="cx"> global.mutability = static_cast<GlobalInformation::Mutability>(mutability);
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmWasmSignaturecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/WasmSignature.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/WasmSignature.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/WasmSignature.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -70,10 +70,12 @@
</span><span class="cx"> unsigned accumulator = 0xa1bcedd8u;
</span><span class="cx"> for (uint32_t i = 0; i < argumentCount; ++i) {
</span><span class="cx"> accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(argumentTypes[i].kind)));
</span><ins>+ accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(argumentTypes[i].nullable)));
</ins><span class="cx"> accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<unsigned>::hash(argumentTypes[i].index));
</span><span class="cx"> }
</span><span class="cx"> for (uint32_t i = 0; i < returnCount; ++i) {
</span><span class="cx"> accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(returnTypes[i].kind)));
</span><ins>+ accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<uint8_t>::hash(static_cast<uint8_t>(returnTypes[i].nullable)));
</ins><span class="cx"> accumulator = WTF::pairIntHash(accumulator, WTF::IntHash<unsigned>::hash(returnTypes[i].index));
</span><span class="cx"> }
</span><span class="cx"> return accumulator;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmgenerateWasmOpsHeaderpy"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -212,15 +212,21 @@
</span><span class="cx"> };
</span><span class="cx"> #undef CREATE_ENUM_VALUE
</span><span class="cx">
</span><ins>+enum class Nullable : bool {
+ No = false,
+ Yes = true,
+};
+
</ins><span class="cx"> using SignatureIndex = uintptr_t;
</span><span class="cx">
</span><span class="cx"> struct Type {
</span><span class="cx"> TypeKind kind;
</span><ins>+ Nullable nullable;
</ins><span class="cx"> SignatureIndex index;
</span><span class="cx">
</span><span class="cx"> bool operator==(const Type& other) const
</span><span class="cx"> {
</span><del>- return other.kind == kind && other.index == index;
</del><ins>+ return other.kind == kind && other.nullable == nullable && other.index == index;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> bool operator!=(const Type& other) const
</span><span class="lines">@@ -228,6 +234,11 @@
</span><span class="cx"> return !(other == *this);
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+ bool isNullable() const
+ {
+ return static_cast<bool>(nullable);
+ }
+
</ins><span class="cx"> #define CREATE_PREDICATE(name, ...) bool is ## name() const { return kind == TypeKind::name; }
</span><span class="cx"> FOR_EACH_WASM_TYPE(CREATE_PREDICATE)
</span><span class="cx"> #undef CREATE_PREDICATE
</span><span class="lines">@@ -235,7 +246,7 @@
</span><span class="cx">
</span><span class="cx"> namespace Types
</span><span class="cx"> {
</span><del>-#define CREATE_CONSTANT(name, id, ...) constexpr Type name = Type{TypeKind::name, 0u};
</del><ins>+#define CREATE_CONSTANT(name, id, ...) constexpr Type name = Type{TypeKind::name, Nullable::Yes, 0u};
</ins><span class="cx"> FOR_EACH_WASM_TYPE(CREATE_CONSTANT)
</span><span class="cx"> #undef CREATE_CONSTANT
</span><span class="cx"> } // namespace Types
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWasmToJScpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WasmToJS.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WasmToJS.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/js/WasmToJS.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -104,6 +104,8 @@
</span><span class="cx"> switch (argType.kind) {
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED(); // Handled above.
</span><span class="cx"> case TypeKind::TypeIdx:
</span><span class="cx"> case TypeKind::Externref:
</span><span class="lines">@@ -177,6 +179,8 @@
</span><span class="cx"> switch (argType.kind) {
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED(); // Handled above.
</span><span class="cx"> case TypeKind::TypeIdx:
</span><span class="cx"> case TypeKind::Externref:
</span><span class="lines">@@ -278,6 +282,8 @@
</span><span class="cx"> switch (signature.returnType(0).kind) {
</span><span class="cx"> case TypeKind::Void:
</span><span class="cx"> case TypeKind::Func:
</span><ins>+ case TypeKind::RefNull:
+ case TypeKind::Ref:
</ins><span class="cx"> // For the JavaScript embedding, imports with these types in their signature return are a WebAssembly.Module validation error.
</span><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> break;
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyFunctioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -85,11 +85,26 @@
</span><span class="cx"> break;
</span><span class="cx"> case Wasm::TypeKind::TypeIdx:
</span><span class="cx"> case Wasm::TypeKind::Funcref: {
</span><del>- if (!isWebAssemblyHostFunction(vm, arg) && !arg.isNull())
</del><ins>+ bool isNullable = signature.argument(argIndex).isNullable();
+ WebAssemblyFunction* wasmFunction = nullptr;
+ WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
+ if (!isWebAssemblyHostFunction(vm, arg, wasmFunction, wasmWrapperFunction) && (!isNullable || !arg.isNull()))
</ins><span class="cx"> return JSValue::encode(throwException(globalObject, scope, createJSWebAssemblyRuntimeError(globalObject, vm, "Funcref must be an exported wasm function")));
</span><ins>+ 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")));
+ }
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::TypeKind::Externref:
</span><ins>+ if (!signature.argument(argIndex).isNullable() && arg.isNull())
+ return JSValue::encode(throwException(globalObject, scope, createJSWebAssemblyRuntimeError(globalObject, vm, "Non-null Externref cannot be null")));
</ins><span class="cx"> break;
</span><span class="cx"> case Wasm::TypeKind::I64:
</span><span class="cx"> arg = JSValue::decode(bitwise_cast<uint64_t>(arg.toBigInt64(globalObject)));
</span><span class="lines">@@ -102,6 +117,8 @@
</span><span class="cx"> break;
</span><span class="cx"> case Wasm::TypeKind::Void:
</span><span class="cx"> case Wasm::TypeKind::Func:
</span><ins>+ case Wasm::TypeKind::RefNull:
+ case Wasm::TypeKind::Ref:
</ins><span class="cx"> RELEASE_ASSERT_NOT_REACHED();
</span><span class="cx"> }
</span><span class="cx"> RETURN_IF_EXCEPTION(scope, encodedJSValue());
</span><span class="lines">@@ -277,10 +294,13 @@
</span><span class="cx"> jit.zeroExtend32ToWord(scratchGPR, wasmCallInfo.params[i].gpr());
</span><span class="cx"> break;
</span><span class="cx"> }
</span><ins>+ case Wasm::TypeKind::TypeIdx:
</ins><span class="cx"> case Wasm::TypeKind::Funcref: {
</span><span class="cx"> // Ensure we have a WASM exported function.
</span><span class="cx"> jit.load64(jsParam, scratchGPR);
</span><span class="cx"> auto isNull = jit.branchIfNull(scratchGPR);
</span><ins>+ if (!type.isNullable())
+ slowPath.append(isNull);
</ins><span class="cx"> slowPath.append(jit.branchIfNotCell(scratchGPR));
</span><span class="cx">
</span><span class="cx"> stackLimitGPRIsClobbered = true;
</span><span class="lines">@@ -294,15 +314,28 @@
</span><span class="cx"> slowPath.append(jit.branchPtr(CCallHelpers::NotEqual, scratchGPR, CCallHelpers::TrustedImmPtr(WebAssemblyWrapperFunction::info())));
</span><span class="cx">
</span><span class="cx"> isWasmFunction.link(&jit);
</span><del>- isNull.link(&jit);
</del><ins>+ 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);
</ins><span class="cx"> FALLTHROUGH;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::TypeKind::Externref: {
</span><span class="cx"> if (isStack) {
</span><span class="cx"> jit.load64(jsParam, scratchGPR);
</span><ins>+ if (!type.isNullable())
+ slowPath.append(jit.branchIfNull(scratchGPR));
</ins><span class="cx"> jit.store64(scratchGPR, calleeFrame.withOffset(wasmCallInfo.params[i].offsetFromSP()));
</span><del>- } else
- jit.load64(jsParam, wasmCallInfo.params[i].gpr());
</del><ins>+ } else {
+ auto externGPR = wasmCallInfo.params[i].gpr();
+ jit.load64(jsParam, externGPR);
+ if (!type.isNullable())
+ slowPath.append(jit.branchIfNull(externGPR));
+ }
</ins><span class="cx"> break;
</span><span class="cx"> }
</span><span class="cx"> case Wasm::TypeKind::F32:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyFunctionBaseh"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunctionBase.h (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunctionBase.h 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyFunctionBase.h 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -52,6 +52,8 @@
</span><span class="cx">
</span><span class="cx"> static ptrdiff_t offsetOfInstance() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_instance); }
</span><span class="cx">
</span><ins>+ static ptrdiff_t offsetOfSignatureIndex() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_importableFunction) + WasmToWasmImportableFunction::offsetOfSignatureIndex(); }
+
</ins><span class="cx"> static ptrdiff_t offsetOfEntrypointLoadLocation() { return OBJECT_OFFSETOF(WebAssemblyFunctionBase, m_importableFunction) + WasmToWasmImportableFunction::offsetOfEntrypointLoadLocation(); }
</span><span class="cx">
</span><span class="cx"> protected:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmjsWebAssemblyModuleRecordcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/js/WebAssemblyModuleRecord.cpp 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -247,16 +247,35 @@
</span><span class="cx"> if (globalValue->global()->mutability() != Wasm::GlobalInformation::Immutable)
</span><span class="cx"> return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "must be a same mutability")));
</span><span class="cx"> switch (moduleInformation.globals[import.kindIndex].type.kind) {
</span><del>- case Wasm::TypeKind::Funcref:
</del><ins>+ case Wasm::TypeKind::TypeIdx:
+ case Wasm::TypeKind::Funcref: {
+ bool isNullable = global.type.isNullable();
+ WebAssemblyFunction* wasmFunction = nullptr;
+ WebAssemblyWrapperFunction* wasmWrapperFunction = nullptr;
</ins><span class="cx"> value = globalValue->global()->get(globalObject);
</span><span class="cx"> RETURN_IF_EXCEPTION(scope, void());
</span><del>- if (!isWebAssemblyHostFunction(vm, value) && !value.isNull())
- return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "must be a wasm exported function or null")));
</del><ins>+ 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")));
+ }
</ins><span class="cx"> m_instance->instance().setGlobal(import.kindIndex, value);
</span><span class="cx"> break;
</span><ins>+ }
</ins><span class="cx"> case Wasm::TypeKind::Externref:
</span><span class="cx"> value = globalValue->global()->get(globalObject);
</span><span class="cx"> RETURN_IF_EXCEPTION(scope, void());
</span><ins>+ if (!global.type.isNullable() && value.isNull())
+ return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "non-null externref cannot be null")));
</ins><span class="cx"> m_instance->instance().setGlobal(import.kindIndex, value);
</span><span class="cx"> break;
</span><span class="cx"> case Wasm::TypeKind::I32:
</span><span class="lines">@@ -283,12 +302,31 @@
</span><span class="cx">
</span><span class="cx"> // iii. Append ToWebAssemblyValue(v) to imports.
</span><span class="cx"> switch (globalType.kind) {
</span><del>- 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")));
</del><ins>+ 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")));
+ }
</ins><span class="cx"> m_instance->instance().setGlobal(import.kindIndex, value);
</span><span class="cx"> break;
</span><ins>+ }
</ins><span class="cx"> case Wasm::TypeKind::Externref:
</span><ins>+ if (!globalType.isNullable() && value.isNull())
+ return exception(createJSWebAssemblyLinkError(globalObject, vm, importFailMessage(import, "imported global", "must be a non-null value")));
</ins><span class="cx"> m_instance->instance().setGlobal(import.kindIndex, value);
</span><span class="cx"> break;
</span><span class="cx"> case Wasm::TypeKind::I32:
</span><span class="lines">@@ -490,6 +528,7 @@
</span><span class="cx"> switch (global.type.kind) {
</span><span class="cx"> case Wasm::TypeKind::Externref:
</span><span class="cx"> case Wasm::TypeKind::Funcref:
</span><ins>+ case Wasm::TypeKind::TypeIdx:
</ins><span class="cx"> case Wasm::TypeKind::I32:
</span><span class="cx"> case Wasm::TypeKind::I64:
</span><span class="cx"> case Wasm::TypeKind::F32:
</span></span></pre></div>
<a id="trunkSourceJavaScriptCorewasmwasmjson"></a>
<div class="modfile"><h4>Modified: trunk/Source/JavaScriptCore/wasm/wasm.json (279264 => 279265)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/JavaScriptCore/wasm/wasm.json 2021-06-25 01:27:32 UTC (rev 279264)
+++ trunk/Source/JavaScriptCore/wasm/wasm.json 2021-06-25 02:23:28 UTC (rev 279265)
</span><span class="lines">@@ -13,6 +13,8 @@
</span><span class="cx"> "f64": { "type": "varint7", "value": -4, "b3type": "B3::Double" },
</span><span class="cx"> "funcref": { "type": "varint7", "value": -16, "b3type": "B3::Int64" },
</span><span class="cx"> "externref": { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
</span><ins>+ "ref_null": { "type": "varint7", "value": -20, "b3type": "B3::Int64" },
+ "ref": { "type": "varint7", "value": -21, "b3type": "B3::Int64" },
</ins><span class="cx"> "func": { "type": "varint7", "value": -32, "b3type": "B3::Void" },
</span><span class="cx"> "void": { "type": "varint7", "value": -64, "b3type": "B3::Void" },
</span><span class="cx"> "type_idx": { "type": "varint7", "value": -128, "b3type": "B3::Int64" }
</span></span></pre>
</div>
</div>
</body>
</html>