Skip to content

Commit

Permalink
[Wasm-GC] Add support for new constant expressions
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=254696

Reviewed by Justin Michaud.

Enables new constant expressions used in the GC proposal: array.new (normal,
default, and fixed), struct.new (normal, default),
extern.internalize/externalize, and i31.new. Both GC and extended constant expr
flags need to be turned on to use these.

The representation of ExpressionType used in the constant expression generator
is changed to potentially hold a Strong<JSObject> reference in order to keep
allocated objects live.

This enables most GC array spec tests to run, so this patch also adds
those tests to the suite. The remaining test failure is blocked on
parsing element vector items.

Running these spec tests also required updating part of the GC spec test
harness to match the upstream JS test helpers.

This patch also fixes a minor bug in parsing `array.new_data` that's exposed by
these tests.

* JSTests/wasm/gc-spec-harness.js:
* JSTests/wasm/gc-spec-harness/async_index.js:
(hostref):
(eq_ref):
(reinitializeRegistry.get promise_test):
(reinitializeRegistry):
(externref): Deleted.
(is_externref): Deleted.
(is_funcref): Deleted.
(eq_externref): Deleted.
(eq_funcref): Deleted.
* JSTests/wasm/gc-spec-harness/sync_index.js:
(hostref):
(eq_ref):
(externref): Deleted.
(is_externref): Deleted.
(is_funcref): Deleted.
(eq_externref): Deleted.
(eq_funcref): Deleted.
* JSTests/wasm/gc-spec-harness/wasm-constants.js: Added.
(bytes):
(bytesWithHeader):
(makeSig):
(makeSig_v_x):
(makeSig_v_xx):
(makeSig_r_v):
(makeSig_r_x):
(makeSig_r_xx):
(assertTraps):
(assertWasmThrows):
* JSTests/wasm/gc-spec-tests/array.wast.js: Added.
* JSTests/wasm/gc-spec-tests/i31.wast.js: Added.
* JSTests/wasm/gc/const-exprs-flag-off.js: Added.
(async testInvalidGCConstExprs):
* JSTests/wasm/gc/const-exprs.js: Added.
(async testGCConstExprs):
(async testInvalidConstExprs):
* Source/JavaScriptCore/wasm/WasmConstExprGenerator.cpp:
(JSC::Wasm::ConstExprGenerator::ConstExprValue::ConstExprValue):
(JSC::Wasm::ConstExprGenerator::ConstExprValue::getValue):
(JSC::Wasm::ConstExprGenerator::ConstExprValue::type):
(JSC::Wasm::ConstExprGenerator::ConstExprValue::operator+):
(JSC::Wasm::ConstExprGenerator::ConstExprValue::operator-):
(JSC::Wasm::ConstExprGenerator::ConstExprValue::operator*):
(JSC::Wasm::ConstExprGenerator::result const):
(JSC::Wasm::ConstExprGenerator::addConstant):
(JSC::Wasm::ConstExprGenerator::getGlobal):
(JSC::Wasm::ConstExprGenerator::addRefI31):
(JSC::Wasm::ConstExprGenerator::createNewArray):
(JSC::Wasm::ConstExprGenerator::addArrayNew):
(JSC::Wasm::ConstExprGenerator::addArrayNewDefault):
(JSC::Wasm::ConstExprGenerator::addArrayNewFixed):
(JSC::Wasm::ConstExprGenerator::createNewStruct):
(JSC::Wasm::ConstExprGenerator::addStructNewDefault):
(JSC::Wasm::ConstExprGenerator::addStructNew):
(JSC::Wasm::ConstExprGenerator::addAnyConvertExtern):
(JSC::Wasm::ConstExprGenerator::addExternConvertAny):
(JSC::Wasm::ConstExprGenerator::addRefFunc):
(JSC::Wasm::evaluateExtendedConstExpr):
* Source/JavaScriptCore/wasm/WasmConstExprGenerator.h:
* Source/JavaScriptCore/wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
* Source/JavaScriptCore/wasm/WasmSectionParser.cpp:
(JSC::Wasm::SectionParser::parseInitExpr):
* Tools/Scripts/run-jsc-stress-tests:

Canonical link: https://commits.webkit.org/269484@main
  • Loading branch information
takikawa committed Oct 18, 2023
1 parent 5273909 commit 2b9318e
Show file tree
Hide file tree
Showing 13 changed files with 1,058 additions and 65 deletions.
2 changes: 1 addition & 1 deletion JSTests/wasm/gc-spec-harness.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,4 @@ let console = {
};

load("./gc-spec-harness/sync_index.js", "caller relative");
load("./spec-harness/wasm-constants.js", "caller relative");
load("./gc-spec-harness/wasm-constants.js", "caller relative");
43 changes: 23 additions & 20 deletions JSTests/wasm/gc-spec-harness/async_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,22 +52,13 @@ const EXPECT_INVALID = false;

/* DATA **********************************************************************/

let externrefs = {};
let externsym = Symbol("externref");
function externref(s) {
if (! (s in externrefs)) externrefs[s] = {[externsym]: s};
return externrefs[s];
let hostrefs = {};
let hostsym = Symbol("hostref");
function hostref(s) {
if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s};
return hostrefs[s];
}
function is_externref(x) {
return (x !== null && externsym in x) ? 1 : 0;
}
function is_funcref(x) {
return typeof x === "function" ? 1 : 0;
}
function eq_externref(x, y) {
return x === y ? 1 : 0;
}
function eq_funcref(x, y) {
function eq_ref(x, y) {
return x === y ? 1 : 0;
}

Expand All @@ -86,11 +77,8 @@ function reinitializeRegistry() {

chain = chain.then(_ => {
let spectest = {
externref: externref,
is_externref: is_externref,
is_funcref: is_funcref,
eq_externref: eq_externref,
eq_funcref: eq_funcref,
hostref: hostref,
eq_ref: eq_ref,
print: console.log.bind(console),
print_i32: console.log.bind(console),
print_i32_f32: console.log.bind(console),
Expand Down Expand Up @@ -284,12 +272,27 @@ function assert_return(action, ...expected) {
// so there's no good way to test that it's a canonical NaN.
assert_true(Number.isNaN(actual[i]), `expected NaN, observed ${actual[i]}.`);
return;
case "ref.i31":
assert_true(typeof actual[i] === "number" && (actual[i] & 0x7fffffff) === actual[i],
`expected Wasm i31, got ${actual[i]}`);
return;
case "ref.any":
case "ref.eq":
case "ref.struct":
case "ref.array":
// For now, JS can't distinguish exported Wasm GC values,
// so we only test for object.
assert_true(typeof actua[i] === "object", `expected Wasm object, got ${actual[i]}`);
return;
case "ref.func":
assert_true(typeof actual[i] === "function", `expected Wasm function, got ${actual[i]}`);
return;
case "ref.extern":
assert_true(actual[i] !== null, `expected Wasm reference, got ${actual[i]}`);
return;
case "ref.null":
assert_true(actual[i] === null, `expected Wasm null reference, got ${actual[i]}`);
return;
default:
assert_equals(actual[i], expected[i], loc);
}
Expand Down
47 changes: 26 additions & 21 deletions JSTests/wasm/gc-spec-harness/sync_index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,13 @@ const EXPECT_INVALID = false;

/* DATA **********************************************************************/

let externrefs = {};
let externsym = Symbol("externref");
function externref(s) {
if (! (s in externrefs)) externrefs[s] = {[externsym]: s};
return externrefs[s];
let hostrefs = {};
let hostsym = Symbol("hostref");
function hostref(s) {
if (! (s in hostrefs)) hostrefs[s] = {[hostsym]: s};
return hostrefs[s];
}
function is_externref(x) {
return (x !== null && externsym in x) ? 1 : 0;
}
function is_funcref(x) {
return typeof x === "function" ? 1 : 0;
}
function eq_externref(x, y) {
return x === y ? 1 : 0;
}
function eq_funcref(x, y) {
function eq_ref(x, y) {
return x === y ? 1 : 0;
}

Expand All @@ -96,11 +87,8 @@ function reinitializeRegistry() {
return;

let spectest = {
externref: externref,
is_externref: is_externref,
is_funcref: is_funcref,
eq_externref: eq_externref,
eq_funcref: eq_funcref,
hostref: hostref,
eq_ref: eq_ref,
print: console.log.bind(console),
print_i32: console.log.bind(console),
print_i32_f32: console.log.bind(console),
Expand Down Expand Up @@ -336,7 +324,9 @@ function assert_return(action, ...expected) {
_assert(result instanceof Result);

uniqueTest(() => {
assert_true(!result.isError(), `expected success result, got: ${result.value}.`);
// FIXME: the currently JS API behavior results in string coerion failing for GC objects,
// so we cannot construct an error message here currently.
assert_true(!result.isError());
let actual = result.value;
if (actual === undefined) {
actual = [];
Expand All @@ -360,12 +350,27 @@ function assert_return(action, ...expected) {
// so there's no good way to test that it's a canonical NaN.
assert_true(Number.isNaN(actual[i]), `expected NaN, observed ${actual[i]}.`);
return;
case "ref.i31":
assert_true(typeof actual[i] === "number" && (actual[i] & 0x7fffffff) === actual[i],
`expected Wasm i31, got ${actual[i]}`);
return;
case "ref.any":
case "ref.eq":
case "ref.struct":
case "ref.array":
// For now, JS can't distinguish exported Wasm GC values,
// so we only test for object.
//assert_true(typeof actua[i] === "object", `expected Wasm object, got ${actual[i]}`);
return;
case "ref.func":
assert_true(typeof actual[i] === "function", `expected Wasm function, got ${actual[i]}`);
return;
case "ref.extern":
assert_true(actual[i] !== null, `expected Wasm reference, got ${actual[i]}`);
return;
case "ref.null":
assert_true(actual[i] === null, `expected Wasm null reference, got ${actual[i]}`);
return;
default:
assert_equals(actual[i], expected[i]);
}
Expand Down
Loading

0 comments on commit 2b9318e

Please sign in to comment.