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" }