[WASM-References] Add support for Anyref in parameters and return types, Ref.null and Ref.is_null for Anyref values.
https://bugs.webkit.org/show_bug.cgi?id=197969
JSTests:
Reviewed by Keith Miller.
Support the anyref type in Builder.js, plus add some extra error logging.
Add new folder for wasm references tests.
* wasm.yaml:
* wasm/Builder.js:
(const._isValidValue):
* wasm/references/anyref_modules.js: Added.
(Call.3.RefIsNull.End.End.WebAssembly.js.ident):
(Call.3.RefIsNull.End.End.WebAssembly.js.make_null):
(Call.3.RefIsNull.End.End.WebAssembly):
(undefined):
* wasm/references/is_null.js: Added.
* wasm/references/is_null_error.js: Added.
* wasm/spec-harness/index.js:
* wasm/wasm.json:
Source/JavaScriptCore:
Reviewed by Keith Miller.
Add a new runtime option for wasm references.
Add support for Anyref as a value type.
Add support for Anyref in parameters and return types of Wasm functions. JSValues are marshalled into/out of wasm Anyrefs
as a black box, except null which becomes a Nullref value. Nullref is not expressible in the bytecode or in the js API.
Add Ref.null and Ref.is_null for Anyref values. Support for these functions with funcrefs is out of scope.
* runtime/Options.h:
* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::tmpForType):
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::addConstant):
(JSC::Wasm::AirIRGenerator::addRefIsNull):
(JSC::Wasm::AirIRGenerator::addReturn):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::addRefIsNull):
* wasm/WasmCallingConvention.h:
(JSC::Wasm::CallingConventionAir::marshallArgument const):
(JSC::Wasm::CallingConventionAir::setupCall const):
* wasm/WasmFormat.h:
(JSC::Wasm::isValueType):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::FunctionParser):
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
* wasm/WasmValidate.cpp:
(JSC::Wasm::Validate::addRefIsNull):
* wasm/generateWasmOpsHeader.py:
(bitSet):
* wasm/js/JSToWasm.cpp:
(JSC::Wasm::createJSToWasmWrapper):
* wasm/js/WasmToJS.cpp:
(JSC::Wasm::wasmToJS):
* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::jsCallEntrypointSlow):
* wasm/wasm.json:
Tools:
Run wasm tests additionally with wasmBBQUsesAir=0.
Reviewed by Keith Miller.
* Scripts/run-jsc-stress-tests:
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@245496 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/JSTests/ChangeLog b/JSTests/ChangeLog
index e68c826..0daf3b1 100644
--- a/JSTests/ChangeLog
+++ b/JSTests/ChangeLog
@@ -1,3 +1,26 @@
+2019-05-17 Justin Michaud <justin_michaud@apple.com>
+
+ [WASM-References] Add support for Anyref in parameters and return types, Ref.null and Ref.is_null for Anyref values.
+ https://bugs.webkit.org/show_bug.cgi?id=197969
+
+ Reviewed by Keith Miller.
+
+ Support the anyref type in Builder.js, plus add some extra error logging.
+ Add new folder for wasm references tests.
+
+ * wasm.yaml:
+ * wasm/Builder.js:
+ (const._isValidValue):
+ * wasm/references/anyref_modules.js: Added.
+ (Call.3.RefIsNull.End.End.WebAssembly.js.ident):
+ (Call.3.RefIsNull.End.End.WebAssembly.js.make_null):
+ (Call.3.RefIsNull.End.End.WebAssembly):
+ (undefined):
+ * wasm/references/is_null.js: Added.
+ * wasm/references/is_null_error.js: Added.
+ * wasm/spec-harness/index.js:
+ * wasm/wasm.json:
+
2019-05-16 Ross Kirsling <ross.kirsling@sony.com>
[JSC] Invalid AssignmentTargetType should be an early error.
diff --git a/JSTests/wasm.yaml b/JSTests/wasm.yaml
index 3c1a5fc..45dbd1a 100644
--- a/JSTests/wasm.yaml
+++ b/JSTests/wasm.yaml
@@ -29,6 +29,8 @@
cmd: runNoJIT unless parseRunCommands
- path: wasm/function-tests
cmd: runWebAssemblySuite unless parseRunCommands
+- path: wasm/references
+ cmd: runWebAssemblySuite unless parseRunCommands
- path: wasm/fuzz
cmd: runWebAssemblySuite unless parseRunCommands
- path: wasm/stress
diff --git a/JSTests/wasm/Builder.js b/JSTests/wasm/Builder.js
index e94f0a3..f22de1b 100644
--- a/JSTests/wasm/Builder.js
+++ b/JSTests/wasm/Builder.js
@@ -33,6 +33,7 @@
switch (type) {
// We allow both signed and unsigned numbers.
case "i32": return Math.round(value) === value && LLB.varint32Min <= value && value <= LLB.varuint32Max;
+ case "anyref": return true;
case "i64": return true; // FIXME https://bugs.webkit.org/show_bug.cgi?id=163420 64-bit values
case "f32": return typeof(value) === "number" && isFinite(value);
case "f64": return typeof(value) === "number" && isFinite(value);
diff --git a/JSTests/wasm/references/anyref_modules.js b/JSTests/wasm/references/anyref_modules.js
new file mode 100644
index 0000000..ed10096
--- /dev/null
+++ b/JSTests/wasm/references/anyref_modules.js
@@ -0,0 +1,132 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Export()
+ .Function("h")
+ .Function("i")
+ .Function("j")
+ .Function("k")
+ .End()
+ .Code()
+ .Function("h", { params: ["anyref"], ret: "anyref" })
+ .GetLocal(0)
+ .End()
+
+ .Function("i", { params: [], ret: "anyref" })
+ .RefNull()
+ .Call(0)
+ .End()
+
+ .Function("j", { params: ["anyref"], ret: "i32" })
+ .GetLocal(0)
+ .RefIsNull()
+ .End()
+
+ .Function("k", { params: [], ret: "i32" })
+ .RefNull()
+ .RefIsNull()
+ .End()
+ .End().WebAssembly().get()));
+
+const $2 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Import()
+ .Function("m1", "h", { params: ["anyref"], ret: "anyref" })
+ .Function("m1", "j", { params: ["anyref"], ret: "i32" })
+ .Function("js", "ident", { params: ["anyref"], ret: "anyref" })
+ .Function("js", "make_null", { params: [], ret: "anyref" })
+ .End()
+ .Function().End()
+ .Export()
+ .Function("call_h")
+ .Function("call_j")
+ .Function("call_h_null")
+ .Function("call_j_null")
+ .Function("call_ident")
+ .Function("call_ident_null")
+ .Function("is_makenull_null")
+ .End()
+ .Code()
+ .Function("call_h", { params: ["anyref"], ret: "anyref" })
+ .GetLocal(0)
+ .Call(0)
+ .End()
+
+ .Function("call_j", { params: ["anyref"], ret: "i32" })
+ .GetLocal(0)
+ .Call(1)
+ .End()
+
+ .Function("call_h_null", { params: [], ret: "anyref" })
+ .RefNull()
+ .Call(0)
+ .End()
+
+ .Function("call_j_null", { params: [], ret: "i32" })
+ .RefNull()
+ .Call(1)
+ .End()
+
+ .Function("call_ident", { params: ["anyref"], ret: "anyref" })
+ .I32Const(1)
+ .If("anyref")
+ .Block("anyref", (b) =>
+ b.GetLocal(0)
+ )
+ .Else()
+ .Block("anyref", (b) =>
+ b.GetLocal(0)
+ )
+ .End()
+ .Call(2)
+ .End()
+
+ .Function("call_ident_null", { params: [], ret: "anyref" })
+ .RefNull()
+ .Call(2)
+ .End()
+
+ .Function("is_makenull_null", { params: [], ret: "i32" })
+ .Call(3)
+ .RefIsNull()
+ .End()
+ .End().WebAssembly().get()), { m1: $1.exports, js: {
+ ident: function(x) { return x; },
+ make_null: function() { return null; },
+ } });
+
+assert.eq($2.exports.call_h(null), null)
+
+const obj = { test: "hi" }
+assert.eq($2.exports.call_h(obj), obj)
+assert.eq($2.exports.call_h(5), 5)
+assert.eq($2.exports.call_h("hi"), "hi")
+assert.eq($2.exports.call_h(undefined), undefined)
+
+assert.eq($2.exports.call_j(obj), 0)
+assert.eq($2.exports.call_j(5), 0)
+assert.eq($2.exports.call_j("hi"), 0)
+assert.eq($2.exports.call_j(null), 1)
+assert.eq($2.exports.call_j(undefined), 0)
+
+assert.eq($2.exports.call_h_null(), null)
+assert.eq($2.exports.call_j_null(), 1)
+
+assert.eq($2.exports.call_ident(null), null)
+assert.eq($2.exports.call_ident(obj), obj)
+assert.eq($2.exports.call_ident(5), 5)
+assert.eq($2.exports.call_ident("hi"), "hi")
+assert.eq($2.exports.call_ident(undefined), undefined)
+
+for (let i=0; i<1000; ++i) {
+ // Trigger the ic path
+ assert.eq($2.exports.call_ident(null), null)
+ assert.eq($2.exports.call_ident(7), 7)
+ assert.eq($2.exports.call_ident("bye"), "bye")
+}
+
+assert.eq($2.exports.call_ident_null(), null)
+assert.eq($2.exports.is_makenull_null(), 1)
diff --git a/JSTests/wasm/references/is_null.js b/JSTests/wasm/references/is_null.js
new file mode 100644
index 0000000..52bcbf3
--- /dev/null
+++ b/JSTests/wasm/references/is_null.js
@@ -0,0 +1,60 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+const builder = (new Builder())
+ .Type().End()
+ .Function().End()
+ .Export()
+ .Function("h")
+ .Function("i")
+ .Function("j")
+ .Function("k")
+ .End()
+ .Code()
+ .Function("h", { params: ["anyref"], ret: "anyref" })
+ .GetLocal(0)
+ .End()
+
+ .Function("i", { params: [], ret: "anyref" })
+ .RefNull()
+ .Call(0)
+ .End()
+
+ .Function("j", { params: ["anyref"], ret: "i32" })
+ .GetLocal(0)
+ .RefIsNull()
+ .End()
+
+ .Function("k", { params: [], ret: "i32" })
+ .RefNull()
+ .RefIsNull()
+ .End()
+ .End();
+
+const bin = builder.WebAssembly().get();
+const module = new WebAssembly.Module(bin);
+const instance = new WebAssembly.Instance(module);
+assert.eq(instance.exports.h(null), null)
+
+const obj = { test: "hi" }
+assert.eq(instance.exports.h(obj), obj)
+assert.eq(instance.exports.h(5), 5)
+assert.eq(instance.exports.h("hi"), "hi")
+assert.eq(instance.exports.h(undefined), undefined)
+
+assert.eq(instance.exports.i(), null)
+
+assert.eq(instance.exports.j(obj), 0)
+assert.eq(instance.exports.j(5), 0)
+assert.eq(instance.exports.j("hi"), 0)
+assert.eq(instance.exports.j(null), 1)
+assert.eq(instance.exports.j(undefined), 0)
+
+assert.eq(instance.exports.k(), 1)
+
+assert.eq(obj.test, "hi")
+const obj2 = instance.exports.h(obj)
+obj2.test = "bye"
+assert.eq(obj.test, "bye")
+
+for (let i=0; i<1000; ++i) assert.eq(instance.exports.h(null), null)
diff --git a/JSTests/wasm/references/is_null_error.js b/JSTests/wasm/references/is_null_error.js
new file mode 100644
index 0000000..915b36a
--- /dev/null
+++ b/JSTests/wasm/references/is_null_error.js
@@ -0,0 +1,22 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+{
+ const builder = (new Builder())
+ .Type().End()
+ .Function().End()
+ .Export()
+ .Function("j")
+ .End()
+ .Code()
+ .Function("j", { params: [], ret: "i32" })
+ .I32Const(0)
+ .RefIsNull()
+ .End()
+ .End();
+
+ const bin = builder.WebAssembly();
+ bin.trim();
+
+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: ref.is_null to type I32 expected Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
+}
diff --git a/JSTests/wasm/spec-harness/index.js b/JSTests/wasm/spec-harness/index.js
index bc298d2..eb00c6d 100644
--- a/JSTests/wasm/spec-harness/index.js
+++ b/JSTests/wasm/spec-harness/index.js
@@ -190,6 +190,7 @@
if (valid) {
uniqueTest(() => {
let instantiated = err === null;
+ if (!instantiated) print(err);
assert_true(instantiated, err);
}, "module successfully instantiated");
}
diff --git a/JSTests/wasm/wasm.json b/JSTests/wasm/wasm.json
index 31d103f..e61aa74 100644
--- a/JSTests/wasm/wasm.json
+++ b/JSTests/wasm/wasm.json
@@ -12,11 +12,12 @@
"f32": { "type": "varint7", "value": -3, "b3type": "B3::Float" },
"f64": { "type": "varint7", "value": -4, "b3type": "B3::Double" },
"anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Void" },
+ "anyref": { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
"func": { "type": "varint7", "value": -32, "b3type": "B3::Void" },
"void": { "type": "varint7", "value": -64, "b3type": "B3::Void" }
},
- "value_type": ["i32", "i64", "f32", "f64"],
- "block_type": ["i32", "i64", "f32", "f64", "void"],
+ "value_type": ["i32", "i64", "f32", "f64", "anyref"],
+ "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
"elem_type": ["anyfunc"],
"external_kind": {
"Function": { "type": "uint8", "value": 0 },
@@ -58,6 +59,8 @@
"i64.const": { "category": "special", "value": 66, "return": ["i64"], "parameter": [], "immediate": [{"name": "value", "type": "varint64"}], "description": "a constant value interpreted as i64" },
"f64.const": { "category": "special", "value": 68, "return": ["f64"], "parameter": [], "immediate": [{"name": "value", "type": "double"}], "description": "a constant value interpreted as f64" },
"f32.const": { "category": "special", "value": 67, "return": ["f32"], "parameter": [], "immediate": [{"name": "value", "type": "float"}], "description": "a constant value interpreted as f32" },
+ "ref.null": { "category": "special", "value": 208, "return": ["anyref"], "parameter": [], "immediate": [], "description": "a constant null reference" },
+ "ref.is_null": { "category": "special", "value": 209, "return": ["i32"], "parameter": ["anyref"], "immediate": [], "description": "determine if a reference is null" },
"get_local": { "category": "special", "value": 32, "return": ["any"], "parameter": [], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "read a local variable or parameter" },
"set_local": { "category": "special", "value": 33, "return": [], "parameter": ["any"], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "write a local variable or parameter" },
"tee_local": { "category": "special", "value": 34, "return": ["any"], "parameter": ["any"], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "write a local variable or parameter and return the same value" },
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 5511733..1851c98 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,47 @@
+2019-05-17 Justin Michaud <justin_michaud@apple.com>
+
+ [WASM-References] Add support for Anyref in parameters and return types, Ref.null and Ref.is_null for Anyref values.
+ https://bugs.webkit.org/show_bug.cgi?id=197969
+
+ Reviewed by Keith Miller.
+
+ Add a new runtime option for wasm references.
+ Add support for Anyref as a value type.
+ Add support for Anyref in parameters and return types of Wasm functions. JSValues are marshalled into/out of wasm Anyrefs
+ as a black box, except null which becomes a Nullref value. Nullref is not expressible in the bytecode or in the js API.
+ Add Ref.null and Ref.is_null for Anyref values. Support for these functions with funcrefs is out of scope.
+
+ * runtime/Options.h:
+ * wasm/WasmAirIRGenerator.cpp:
+ (JSC::Wasm::AirIRGenerator::tmpForType):
+ (JSC::Wasm::AirIRGenerator::AirIRGenerator):
+ (JSC::Wasm::AirIRGenerator::addConstant):
+ (JSC::Wasm::AirIRGenerator::addRefIsNull):
+ (JSC::Wasm::AirIRGenerator::addReturn):
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::addRefIsNull):
+ * wasm/WasmCallingConvention.h:
+ (JSC::Wasm::CallingConventionAir::marshallArgument const):
+ (JSC::Wasm::CallingConventionAir::setupCall const):
+ * wasm/WasmFormat.h:
+ (JSC::Wasm::isValueType):
+ * wasm/WasmFunctionParser.h:
+ (JSC::Wasm::FunctionParser<Context>::FunctionParser):
+ (JSC::Wasm::FunctionParser<Context>::parseExpression):
+ (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
+ * wasm/WasmValidate.cpp:
+ (JSC::Wasm::Validate::addRefIsNull):
+ * wasm/generateWasmOpsHeader.py:
+ (bitSet):
+ * wasm/js/JSToWasm.cpp:
+ (JSC::Wasm::createJSToWasmWrapper):
+ * wasm/js/WasmToJS.cpp:
+ (JSC::Wasm::wasmToJS):
+ * wasm/js/WebAssemblyFunction.cpp:
+ (JSC::callWebAssemblyFunction):
+ (JSC::WebAssemblyFunction::jsCallEntrypointSlow):
+ * wasm/wasm.json:
+
2019-05-17 Don Olmstead <don.olmstead@sony.com>
[CMake] Use builtin FindICU
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index 6bc1500..f32fa6e 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -502,6 +502,7 @@
v(bool, useWebAssemblyStreamingApi, enableWebAssemblyStreamingApi, Normal, "Allow to run WebAssembly's Streaming API") \
v(bool, useCallICsForWebAssemblyToJSCalls, true, Normal, "If true, we will use CallLinkInfo to inline cache Wasm to JS calls.") \
v(bool, useEagerWebAssemblyModuleHashing, false, Normal, "Unnamed WebAssembly modules are identified in backtraces through their hash, if available.") \
+ v(bool, useWebAssemblyReferences, true, Normal, "Allow types from the wasm references spec.") \
v(bool, useBigInt, false, Normal, "If true, we will enable BigInt support.") \
v(bool, useIntlNumberFormatToParts, enableIntlNumberFormatToParts, Normal, "If true, we will enable Intl.NumberFormat.prototype.formatToParts") \
v(bool, useIntlPluralRules, enableIntlPluralRules, Normal, "If true, we will enable Intl.PluralRules.") \
diff --git a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
index 475e926..f796073 100644
--- a/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
+++ b/Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp
@@ -41,6 +41,7 @@
#include "B3ProcedureInlines.h"
#include "BinarySwitch.h"
#include "DisallowMacroScratchRegisterUsage.h"
+#include "JSCInlines.h"
#include "ScratchRegisterAllocator.h"
#include "VirtualRegister.h"
#include "WasmCallingConvention.h"
@@ -230,6 +231,8 @@
ExpressionType addConstant(Type, uint64_t);
ExpressionType addConstant(BasicBlock*, Type, uint64_t);
+ PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+
// Locals
PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -360,6 +363,7 @@
case Type::I32:
return g32();
case Type::I64:
+ case Type::Anyref:
return g64();
case Type::F32:
return f32();
@@ -786,6 +790,7 @@
append(Move32, arg, m_locals[i]);
break;
case Type::I64:
+ case Type::Anyref:
append(Move, arg, m_locals[i]);
break;
case Type::F32:
@@ -902,6 +907,7 @@
switch (type) {
case Type::I32:
case Type::I64:
+ case Type::Anyref:
append(block, Move, Arg::bigImm(value), result);
break;
case Type::F32:
@@ -925,6 +931,18 @@
return { };
}
+auto AirIRGenerator::addRefIsNull(ExpressionType& value, ExpressionType& result) -> PartialResult
+{
+ ASSERT(value.tmp());
+ result = tmpForType(Type::I32);
+ auto tmp = g64();
+
+ append(Move, Arg::bigImm(JSValue::encode(jsNull())), tmp);
+ append(Compare64, Arg::relCond(MacroAssembler::Equal), value, tmp, result);
+
+ return { };
+}
+
auto AirIRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
{
ASSERT(m_locals[index].tmp());
@@ -1509,6 +1527,7 @@
append(Ret32, returnValueGPR);
break;
case Type::I64:
+ case Type::Anyref:
append(Move, returnValues[0], returnValueGPR);
append(Ret64, returnValueGPR);
break;
diff --git a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
index 15f464f..bb2471f 100644
--- a/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
+++ b/Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp
@@ -184,6 +184,8 @@
PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
ExpressionType addConstant(Type, uint64_t);
+ PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+
// Locals
PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -550,6 +552,12 @@
return { };
}
+auto B3IRGenerator::addRefIsNull(ExpressionType& value, ExpressionType& result) -> PartialResult
+{
+ result = m_currentBlock->appendNew<Value>(m_proc, B3::Equal, origin(), value, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), JSValue::encode(jsNull())));
+ return { };
+}
+
auto B3IRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
{
ASSERT(m_locals[index]);
diff --git a/Source/JavaScriptCore/wasm/WasmCallingConvention.h b/Source/JavaScriptCore/wasm/WasmCallingConvention.h
index 31866c2..10eb8cd 100644
--- a/Source/JavaScriptCore/wasm/WasmCallingConvention.h
+++ b/Source/JavaScriptCore/wasm/WasmCallingConvention.h
@@ -235,6 +235,7 @@
switch (type) {
case Type::I32:
case Type::I64:
+ case Type::Anyref:
marshallArgumentImpl(m_gprArgs, gpArgumentCount, stackOffset, regFunc, stackFunc);
break;
case Type::F32:
@@ -299,6 +300,7 @@
break;
case Type::I32:
case Type::I64:
+ case Type::Anyref:
patchpoint->resultConstraint = B3::ValueRep::reg(GPRInfo::returnValueGPR);
break;
default:
diff --git a/Source/JavaScriptCore/wasm/WasmFormat.h b/Source/JavaScriptCore/wasm/WasmFormat.h
index fc69ee5..b762264 100644
--- a/Source/JavaScriptCore/wasm/WasmFormat.h
+++ b/Source/JavaScriptCore/wasm/WasmFormat.h
@@ -62,6 +62,8 @@
case F32:
case F64:
return true;
+ case Anyref:
+ return Options::useWebAssemblyReferences();
default:
break;
}
diff --git a/Source/JavaScriptCore/wasm/WasmFunctionParser.h b/Source/JavaScriptCore/wasm/WasmFunctionParser.h
index 2e028e3..175056b 100644
--- a/Source/JavaScriptCore/wasm/WasmFunctionParser.h
+++ b/Source/JavaScriptCore/wasm/WasmFunctionParser.h
@@ -105,7 +105,7 @@
, m_info(info)
{
if (verbose)
- dataLogLn("Parsing function starting at: ", (uintptr_t)functionStart, " of length: ", functionLength);
+ dataLogLn("Parsing function starting at: ", (uintptr_t)functionStart, " of length: ", functionLength, " with signature: ", signature);
m_context.setParser(this);
}
@@ -281,6 +281,21 @@
return { };
}
+ case RefNull: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ m_expressionStack.append(m_context.addConstant(Anyref, JSValue::encode(jsNull())));
+ return { };
+ }
+
+ case RefIsNull: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ ExpressionType result, value;
+ WASM_TRY_POP_EXPRESSION_STACK_INTO(value, "ref.is_null");
+ WASM_TRY_ADD_TO_CONTEXT(addRefIsNull(value, result));
+ m_expressionStack.append(result);
+ return { };
+ }
+
case GetLocal: {
uint32_t index;
ExpressionType result;
@@ -639,6 +654,16 @@
return { };
}
+ case RefNull: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ return { };
+ }
+
+ case RefIsNull: {
+ WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ return { };
+ }
+
case GrowMemory:
case CurrentMemory: {
uint8_t reserved;
diff --git a/Source/JavaScriptCore/wasm/WasmValidate.cpp b/Source/JavaScriptCore/wasm/WasmValidate.cpp
index bcd477b..fd54162 100644
--- a/Source/JavaScriptCore/wasm/WasmValidate.cpp
+++ b/Source/JavaScriptCore/wasm/WasmValidate.cpp
@@ -100,6 +100,8 @@
Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
ExpressionType addConstant(Type type, uint64_t) { return type; }
+ Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+
// Locals
Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -169,6 +171,14 @@
return { };
}
+auto Validate::addRefIsNull(ExpressionType& value, ExpressionType& result) -> Result
+{
+ result = Type::I32;
+ WASM_VALIDATOR_FAIL_IF(Type::Anyref != value, "ref.is_null to type ", value, " expected ", Type::Anyref);
+
+ return { };
+}
+
auto Validate::addLocal(Type type, uint32_t count) -> Result
{
size_t size = m_locals.size() + count;
diff --git a/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py b/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py
index 0b8d7b0..4e9a665 100755
--- a/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py
+++ b/Source/JavaScriptCore/wasm/generateWasmOpsHeader.py
@@ -95,7 +95,7 @@
def bitSet():
v = ""
- for i in range(ceilDiv(maxOpValue, 8)):
+ for i in range(ceilDiv(maxOpValue + 1, 8)):
entry = 0
for j in range(8):
if i * 8 + j in opValueSet:
diff --git a/Source/JavaScriptCore/wasm/js/JSToWasm.cpp b/Source/JavaScriptCore/wasm/js/JSToWasm.cpp
index 774bce0..657da57 100644
--- a/Source/JavaScriptCore/wasm/js/JSToWasm.cpp
+++ b/Source/JavaScriptCore/wasm/js/JSToWasm.cpp
@@ -82,6 +82,7 @@
argumentsIncludeI64 = true;
FALLTHROUGH;
case Wasm::I32:
+ case Wasm::Anyref:
if (numGPRs >= wasmCallingConvention().m_gprArgs.size())
totalFrameSize += sizeof(void*);
++numGPRs;
@@ -164,6 +165,7 @@
switch (signature.argument(i)) {
case Wasm::I32:
case Wasm::I64:
+ case Wasm::Anyref:
if (numGPRs >= wasmCallingConvention().m_gprArgs.size()) {
if (signature.argument(i) == Wasm::I32) {
jit.load32(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchReg);
@@ -247,6 +249,9 @@
case Wasm::Void:
jit.moveTrustedValue(jsUndefined(), JSValueRegs { GPRInfo::returnValueGPR });
break;
+ case Wasm::Anyref:
+ // FIXME: We need to box wasm Funcrefs once they are supported here.
+ break;
case Wasm::I32:
jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR);
jit.boxInt32(GPRInfo::returnValueGPR, JSValueRegs { GPRInfo::returnValueGPR }, DoNotHaveTagRegisters);
diff --git a/Source/JavaScriptCore/wasm/js/WasmToJS.cpp b/Source/JavaScriptCore/wasm/js/WasmToJS.cpp
index 572b030..5bff9cc 100644
--- a/Source/JavaScriptCore/wasm/js/WasmToJS.cpp
+++ b/Source/JavaScriptCore/wasm/js/WasmToJS.cpp
@@ -165,6 +165,7 @@
case Anyfunc:
case I64:
RELEASE_ASSERT_NOT_REACHED();
+ case Anyref:
case I32: {
GPRReg gprReg;
if (marshalledGPRs < wasmCC.m_gprArgs.size())
@@ -175,7 +176,8 @@
jit.load64(JIT::Address(GPRInfo::callFrameRegister, frOffset), gprReg);
frOffset += sizeof(Register);
}
- jit.zeroExtend32ToPtr(gprReg, gprReg);
+ if (argType == I32)
+ jit.zeroExtend32ToPtr(gprReg, gprReg);
jit.store64(gprReg, buffer + bufferOffset);
++marshalledGPRs;
break;
@@ -241,6 +243,10 @@
case I32:
arg = jsNumber(static_cast<int32_t>(buffer[argNum]));
break;
+ case Anyref:
+ // FIXME: We need to box wasm Funcrefs once they are supported here.
+ arg = JSValue::decode(buffer[argNum]);
+ break;
case F32:
case F64:
arg = jsNumber(purifyNaN(bitwise_cast<double>(buffer[argNum])));
@@ -272,6 +278,10 @@
realResult = static_cast<uint64_t>(static_cast<uint32_t>(result.toInt32(exec)));
break;
}
+ case Anyref: {
+ realResult = JSValue::encode(result);
+ break;
+ }
case F64:
case F32: {
realResult = bitwise_cast<uint64_t>(result.toNumber(exec));
@@ -364,6 +374,7 @@
case Anyfunc:
case I64:
RELEASE_ASSERT_NOT_REACHED(); // Handled above.
+ case Anyref:
case I32: {
GPRReg gprReg;
if (marshalledGPRs < wasmCC.m_gprArgs.size())
@@ -375,8 +386,11 @@
frOffset += sizeof(Register);
}
++marshalledGPRs;
- jit.zeroExtend32ToPtr(gprReg, gprReg); // Clear non-int32 and non-tag bits.
- jit.boxInt32(gprReg, JSValueRegs(gprReg), DoNotHaveTagRegisters);
+ if (argType == I32) {
+ jit.zeroExtend32ToPtr(gprReg, gprReg); // Clear non-int32 and non-tag bits.
+ jit.boxInt32(gprReg, JSValueRegs(gprReg), DoNotHaveTagRegisters);
+ }
+ // FIXME: We need to box wasm Funcrefs once they are supported here.
jit.store64(gprReg, calleeFrame.withOffset(calleeFrameOffset));
calleeFrameOffset += sizeof(Register);
break;
@@ -430,6 +444,7 @@
case Anyfunc:
case I64:
RELEASE_ASSERT_NOT_REACHED(); // Handled above.
+ case Anyref:
case I32:
// Skipped: handled above.
if (marshalledGPRs >= wasmCC.m_gprArgs.size())
@@ -538,6 +553,8 @@
done.link(&jit);
break;
}
+ case Anyref:
+ break;
case F32: {
CCallHelpers::JumpList done;
diff --git a/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp b/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
index 6dcec80..2ff0e78 100644
--- a/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
+++ b/Source/JavaScriptCore/wasm/js/WebAssemblyFunction.cpp
@@ -84,6 +84,8 @@
case Wasm::I32:
arg = JSValue::decode(arg.toInt32(exec));
break;
+ case Wasm::Anyref:
+ break;
case Wasm::I64:
arg = JSValue();
break;
@@ -225,6 +227,7 @@
case Wasm::I64:
argumentsIncludeI64 = true;
break;
+ case Wasm::Anyref:
case Wasm::I32:
if (numGPRs >= Wasm::wasmCallingConvention().m_gprArgs.size())
totalFrameSize += sizeof(CPURegister);
@@ -300,6 +303,18 @@
++numGPRs;
}
break;
+ case Wasm::Anyref: {
+ jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchGPR);
+
+ if (numGPRs >= Wasm::wasmCallingConvention().m_gprArgs.size()) {
+ jit.store64(scratchGPR, calleeFrame.withOffset(wasmOffset));
+ wasmOffset += sizeof(CPURegister);
+ } else {
+ jit.move(scratchGPR, Wasm::wasmCallingConvention().m_gprArgs[numGPRs].gpr());
+ ++numGPRs;
+ }
+ break;
+ }
case Wasm::F32:
case Wasm::F64:
if (numFPRs >= Wasm::wasmCallingConvention().m_fprArgs.size()) {
@@ -451,6 +466,10 @@
isNaN.link(&jit);
break;
}
+ case Wasm::Anyref: {
+ // FIXME: We need to box wasm Funcrefs once they are supported here.
+ break;
+ }
case Wasm::I64:
case Wasm::Func:
case Wasm::Anyfunc:
diff --git a/Source/JavaScriptCore/wasm/wasm.json b/Source/JavaScriptCore/wasm/wasm.json
index 31d103f..e61aa74 100644
--- a/Source/JavaScriptCore/wasm/wasm.json
+++ b/Source/JavaScriptCore/wasm/wasm.json
@@ -12,11 +12,12 @@
"f32": { "type": "varint7", "value": -3, "b3type": "B3::Float" },
"f64": { "type": "varint7", "value": -4, "b3type": "B3::Double" },
"anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Void" },
+ "anyref": { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
"func": { "type": "varint7", "value": -32, "b3type": "B3::Void" },
"void": { "type": "varint7", "value": -64, "b3type": "B3::Void" }
},
- "value_type": ["i32", "i64", "f32", "f64"],
- "block_type": ["i32", "i64", "f32", "f64", "void"],
+ "value_type": ["i32", "i64", "f32", "f64", "anyref"],
+ "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
"elem_type": ["anyfunc"],
"external_kind": {
"Function": { "type": "uint8", "value": 0 },
@@ -58,6 +59,8 @@
"i64.const": { "category": "special", "value": 66, "return": ["i64"], "parameter": [], "immediate": [{"name": "value", "type": "varint64"}], "description": "a constant value interpreted as i64" },
"f64.const": { "category": "special", "value": 68, "return": ["f64"], "parameter": [], "immediate": [{"name": "value", "type": "double"}], "description": "a constant value interpreted as f64" },
"f32.const": { "category": "special", "value": 67, "return": ["f32"], "parameter": [], "immediate": [{"name": "value", "type": "float"}], "description": "a constant value interpreted as f32" },
+ "ref.null": { "category": "special", "value": 208, "return": ["anyref"], "parameter": [], "immediate": [], "description": "a constant null reference" },
+ "ref.is_null": { "category": "special", "value": 209, "return": ["i32"], "parameter": ["anyref"], "immediate": [], "description": "determine if a reference is null" },
"get_local": { "category": "special", "value": 32, "return": ["any"], "parameter": [], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "read a local variable or parameter" },
"set_local": { "category": "special", "value": 33, "return": [], "parameter": ["any"], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "write a local variable or parameter" },
"tee_local": { "category": "special", "value": 34, "return": ["any"], "parameter": ["any"], "immediate": [{"name": "local_index", "type": "varuint32"}], "description": "write a local variable or parameter and return the same value" },
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
index 7a9ef1c..20f2f23 100644
--- a/Tools/ChangeLog
+++ b/Tools/ChangeLog
@@ -1,3 +1,14 @@
+2019-05-17 Justin Michaud <justin_michaud@apple.com>
+
+ [WASM-References] Add support for Anyref in parameters and return types, Ref.null and Ref.is_null for Anyref values.
+ https://bugs.webkit.org/show_bug.cgi?id=197969
+
+ Run wasm tests additionally with wasmBBQUsesAir=0.
+
+ Reviewed by Keith Miller.
+
+ * Scripts/run-jsc-stress-tests:
+
2019-05-17 Don Olmstead <don.olmstead@sony.com>
[CMake] Use builtin FindICU
diff --git a/Tools/Scripts/run-jsc-stress-tests b/Tools/Scripts/run-jsc-stress-tests
index a7be368..2703c40 100755
--- a/Tools/Scripts/run-jsc-stress-tests
+++ b/Tools/Scripts/run-jsc-stress-tests
@@ -1080,6 +1080,7 @@
run("wasm-no-call-ic", "-m", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
run("wasm-no-tls-context", "-m", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
run("wasm-slow-memory", "-m", "--useWebAssemblyFastMemory=false", *FTL_OPTIONS)
+ run("wasm-no-air", "-m", "--wasmBBQUsesAir=false", *FTL_OPTIONS)
end
end
@@ -1096,6 +1097,7 @@
run("wasm-no-call-ic", "-m", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
run("wasm-no-tls-context", "-m", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
run("wasm-slow-memory", "-m", "--useWebAssemblyFastMemory=false", *FTL_OPTIONS)
+ run("wasm-no-air", "-m", "--wasmBBQUsesAir=false", *FTL_OPTIONS)
end
end
@@ -1114,6 +1116,7 @@
run("wasm-eager-jettison", "--forceCodeBlockToJettisonDueToOldAge=true", *FTL_OPTIONS)
run("wasm-no-call-ic", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
run("wasm-no-tls-context", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
+ run("wasm-no-air", "--wasmBBQUsesAir=false", *FTL_OPTIONS)
end
end
@@ -1138,6 +1141,7 @@
runWithOutputHandler("wasm-eager-jettison", noisyOutputHandler, "../spec-harness.js", "--forceCodeBlockToJettisonDueToOldAge=true", *FTL_OPTIONS)
runWithOutputHandler("wasm-no-call-ic", noisyOutputHandler, "../spec-harness.js", "--useCallICsForWebAssemblyToJSCalls=false", *FTL_OPTIONS)
runWithOutputHandler("wasm-no-tls-context", noisyOutputHandler, "../spec-harness.js", "--useFastTLSForWasmContext=false", *FTL_OPTIONS)
+ runWithOutputHandler("wasm-no-air", noisyOutputHandler, "../spec-harness.js", "--wasmBBQUsesAir=false", *FTL_OPTIONS)
end
end