Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Wasm-GC] Introduce i31ref types #2202

Conversation

takikawa
Copy link
Contributor

@takikawa takikawa commented Jul 7, 2022

2215792

[Wasm-GC] Introduce i31ref types
https://bugs.webkit.org/show_bug.cgi?id=242261

Reviewed by Justin Michaud.

Adds support for i31ref types and i31 operations (i31.new, i31.get_s,
i32.get_u) when experimental GC support is turned on.

As Wasm reference types are represented as encoded JS pointer values,
i31refs are represented with encoded JS integer values with the standard
NumberTag for 32-bit integers.

* JSTests/wasm/gc/i31.js: Added.
(module):
(testI31Type):
(testI31New):
(testI31Get):
(testI31JS):
* JSTests/wasm/wasm.json:
* Source/JavaScriptCore/bytecode/BytecodeList.rb:
* Source/JavaScriptCore/llint/WebAssembly32_64.asm:
* Source/JavaScriptCore/llint/WebAssembly64.asm:
* Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::addI31New):
(JSC::Wasm::AirIRGenerator::addI31GetS):
(JSC::Wasm::AirIRGenerator::addI31GetU):
* Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::addI31New):
(JSC::Wasm::B3IRGenerator::addI31GetS):
(JSC::Wasm::B3IRGenerator::addI31GetU):
* Source/JavaScriptCore/wasm/WasmExceptionType.h:
* Source/JavaScriptCore/wasm/WasmFormat.h:
(JSC::Wasm::isI31ref):
(JSC::Wasm::isRefWithTypeIndex):
(JSC::Wasm::isValidHeapTypeKind):
* Source/JavaScriptCore/wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
* Source/JavaScriptCore/wasm/WasmGlobal.cpp:
(JSC::Wasm::Global::set):
* Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp:
(JSC::Wasm::LLIntGenerator::callInformationForCaller):
(JSC::Wasm::LLIntGenerator::callInformationForCallee):
(JSC::Wasm::LLIntGenerator::addArguments):
(JSC::Wasm::LLIntGenerator::addI31New):
(JSC::Wasm::LLIntGenerator::addI31GetS):
(JSC::Wasm::LLIntGenerator::addI31GetU):
* Source/JavaScriptCore/wasm/WasmParser.h:
(JSC::Wasm::Parser<SuccessType>::parseValueType):
* Source/JavaScriptCore/wasm/js/JSToWasm.cpp:
(JSC::Wasm::marshallJSResult):
* Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h:
(JSC::fromJSValue):
* Source/JavaScriptCore/wasm/js/WasmToJS.cpp:
(JSC::Wasm::wasmToJS):
* Source/JavaScriptCore/wasm/js/WebAssemblyGlobalConstructor.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/wasm/wasm.json:

Canonical link: https://commits.webkit.org/252688@main

@takikawa takikawa requested a review from a team as a code owner July 7, 2022 23:08
@webkit-early-warning-system webkit-early-warning-system added the merging-blocked Applied to prevent a change from being merged label Jul 7, 2022
@takikawa
Copy link
Contributor Author

takikawa commented Jul 8, 2022

I was originally thinking of leaving the 32-bit support out in this initial patch, but it looks like EWS won't be happy that way so I will add that into the patch and revise this PR.

bqeq t0, ValueNull, .throw
returni(ctx, t0)

.throw:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spec says to trap if null, but I am wondering: if i31 refs aren't nullable, then shouldn't downcasts and imports trap before getting here? The only way to get here is by passing in null directly? This seems somewhat unfortunate unless I am missing something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i31 refs aren't nullable, then shouldn't downcasts and imports trap before getting here?

In general it should be possible for a non-null i31ref to get passed in here, they share a null with other reference types. For example the type i31ref is shorthand for (ref null i31) and includes null.

I think it might be possible in the B3/Air tiers to elide the null check though by inspecting the argument type and seeing if it allows null.

* (type (func (param i31ref) (result (ref i31))))
* )
*/
new WebAssembly.Instance(module("\x00\x61\x73\x6d\x01\x00\x00\x00\x01\x87\x80\x80\x80\x00\x01\x60\x01\x6a\x01\x6b\x6a"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should make a script or IDE plugin to compile/decompile these automatically

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about using the Wasm GC spec's reference interpreter (bundling the compiled to JS code) to write these tests? Then the tests can all be written in text format, except those that test malformed binary format code.

Currently the spec interpreter's compile-to-JS mode appears to be broken, but I'm looking into a possible fix.

Source/JavaScriptCore/wasm/WasmExceptionType.h Outdated Show resolved Hide resolved
@takikawa takikawa force-pushed the eng/Wasm-GC-Introduce-i31ref-types branch 2 times, most recently from 28417a3 to 2c37b45 Compare July 9, 2022 01:42
Copy link
Contributor

@justinmichaud justinmichaud left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM as long as we gate everything by the Wasm GC option, not just typed function references. r=me

Source/JavaScriptCore/wasm/WasmFormat.h Outdated Show resolved Hide resolved
@@ -66,7 +66,7 @@ void marshallJSResult(CCallHelpers& jit, const TypeDefinition& typeDefinition, c
break;
}
default: {
if (isFuncref(type) || isExternref(type))
if (isFuncref(type) || isExternref(type) || isI31ref(type))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So is this supposed to be a number, or an instance of the JS type Webassembly.i31ref? I'm not sure what the current status of the spec is, it seems like the JS api document is out of date?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JS API isn't fully decided yet, but I think it's likely that the semantics will be that I31refs that flow to JS will be interpreted as JS Numbers. For the other direction, JS numbers that are in the i31ref range would be normalized/converted to an i31ref (based on discussion in WebAssembly/gc#76).

For now this PR should let Wasm i31refs get treated as JS values, but the other direction currently should fail and error as the conversion logic hasn't been implemented yet.

@@ -15,6 +15,7 @@
"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" },
"i31ref": { "type": "varint7", "value": -22, "b3type": "B3::Void" },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the B3 type be an Int64?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had left this as Void here to be consistent with, e.g., structs. In particular TypeKind::I31ref shouldn't show up as a type on its own (same with structs), because the parser should always convert an i31ref type to TypeKind::Ref (or RefNull) with an I31 heap type.

@takikawa takikawa force-pushed the eng/Wasm-GC-Introduce-i31ref-types branch from 2c37b45 to 99ef4f8 Compare July 18, 2022 21:01
@takikawa
Copy link
Contributor Author

takikawa commented Jul 18, 2022

I think I've addressed essentially all the comments now (gated by GC flag, uses single exception for i31.get errors) and additionally added a few new tests and improved error messages to clarify what the JS API interaction should be. Specifically, i31ref imports get an explicit error case instead of failing with a funcref-related message.

The relevant diffs are:

Re: tests, I'd be happy to follow up with a separate PR to convert all of the GC proposal tests we have so far to a nicer text format embedding a JS-compiled version of the Wasm reference interpreter, so that the comment text and binary cannot go out-of-sync.

@justinmichaud
Copy link
Contributor

This looks good to me, I don't know if you want to get feedback from others on JSC or from 32-bit folks. It seems unlikely to break anything though, so LGTM.

@takikawa takikawa force-pushed the eng/Wasm-GC-Introduce-i31ref-types branch from 99ef4f8 to 3db6bed Compare July 19, 2022 05:23
@takikawa
Copy link
Contributor Author

Thanks for the review! I think I'm happy with the PR now, I tested the 32-bit support as well on an arm7 machine and it looks like the CI is green now. I don't have the committer flag so will need someone else to apply the merge-queue label though.

@justinmichaud justinmichaud added merge-queue Applied to send a pull request to merge-queue and removed merging-blocked Applied to prevent a change from being merged labels Jul 19, 2022
@webkit-early-warning-system webkit-early-warning-system force-pushed the eng/Wasm-GC-Introduce-i31ref-types branch from 3db6bed to debcb9f Compare July 19, 2022 21:40
@JonWBedard JonWBedard added merge-queue Applied to send a pull request to merge-queue and removed merge-queue Applied to send a pull request to merge-queue labels Jul 20, 2022
@webkit-early-warning-system webkit-early-warning-system force-pushed the eng/Wasm-GC-Introduce-i31ref-types branch from debcb9f to f550016 Compare July 20, 2022 21:18
@JonWBedard JonWBedard added unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing and removed merge-queue Applied to send a pull request to merge-queue labels Jul 21, 2022
https://bugs.webkit.org/show_bug.cgi?id=242261

Reviewed by Justin Michaud.

Adds support for i31ref types and i31 operations (i31.new, i31.get_s,
i32.get_u) when experimental GC support is turned on.

As Wasm reference types are represented as encoded JS pointer values,
i31refs are represented with encoded JS integer values with the standard
NumberTag for 32-bit integers.

* JSTests/wasm/gc/i31.js: Added.
(module):
(testI31Type):
(testI31New):
(testI31Get):
(testI31JS):
* JSTests/wasm/wasm.json:
* Source/JavaScriptCore/bytecode/BytecodeList.rb:
* Source/JavaScriptCore/llint/WebAssembly32_64.asm:
* Source/JavaScriptCore/llint/WebAssembly64.asm:
* Source/JavaScriptCore/wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::addI31New):
(JSC::Wasm::AirIRGenerator::addI31GetS):
(JSC::Wasm::AirIRGenerator::addI31GetU):
* Source/JavaScriptCore/wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::addI31New):
(JSC::Wasm::B3IRGenerator::addI31GetS):
(JSC::Wasm::B3IRGenerator::addI31GetU):
* Source/JavaScriptCore/wasm/WasmExceptionType.h:
* Source/JavaScriptCore/wasm/WasmFormat.h:
(JSC::Wasm::isI31ref):
(JSC::Wasm::isRefWithTypeIndex):
(JSC::Wasm::isValidHeapTypeKind):
* Source/JavaScriptCore/wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
* Source/JavaScriptCore/wasm/WasmGlobal.cpp:
(JSC::Wasm::Global::set):
* Source/JavaScriptCore/wasm/WasmLLIntGenerator.cpp:
(JSC::Wasm::LLIntGenerator::callInformationForCaller):
(JSC::Wasm::LLIntGenerator::callInformationForCallee):
(JSC::Wasm::LLIntGenerator::addArguments):
(JSC::Wasm::LLIntGenerator::addI31New):
(JSC::Wasm::LLIntGenerator::addI31GetS):
(JSC::Wasm::LLIntGenerator::addI31GetU):
* Source/JavaScriptCore/wasm/WasmParser.h:
(JSC::Wasm::Parser<SuccessType>::parseValueType):
* Source/JavaScriptCore/wasm/js/JSToWasm.cpp:
(JSC::Wasm::marshallJSResult):
* Source/JavaScriptCore/wasm/js/JSWebAssemblyHelpers.h:
(JSC::fromJSValue):
* Source/JavaScriptCore/wasm/js/WasmToJS.cpp:
(JSC::Wasm::wasmToJS):
* Source/JavaScriptCore/wasm/js/WebAssemblyGlobalConstructor.cpp:
(JSC::JSC_DEFINE_HOST_FUNCTION):
* Source/JavaScriptCore/wasm/wasm.json:

Canonical link: https://commits.webkit.org/252688@main
@webkit-early-warning-system webkit-early-warning-system force-pushed the eng/Wasm-GC-Introduce-i31ref-types branch from f550016 to 2215792 Compare July 21, 2022 15:20
@webkit-commit-queue
Copy link
Collaborator

Committed 252688@main (2215792): https://commits.webkit.org/252688@main

Reviewed commits have been landed. Closing PR #2202 and removing active labels.

@webkit-early-warning-system webkit-early-warning-system merged commit 2215792 into WebKit:main Jul 21, 2022
@webkit-commit-queue webkit-commit-queue removed the unsafe-merge-queue Applied to send a pull request to merge-queue, but skip building and testing label Jul 21, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants