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

Exit through Cranelift-generated trampolines for builtins #8152

Conversation

alexcrichton
Copy link
Member

This commit changes how builtin functions in Wasmtime (think memory.grow) are implemented. These functions are required to exit through some manner of trampoline to handle runtime requirements for backtracing right now. Currently this is done via inline assembly for each architecture (or external assembly for s390x). This is a bit unfortunate as it's a lot of hand-coding and making sure everything is right, and it's not easy to update as it's multiple platforms to update.

The change in this commit is to instead use Cranelift-generated trampolines for this purpose instead. The path for invoking a builtin function now looks like:

  • Wasm code calls a statically known symbol for each builtin.
  • The statically known symbol will perform exit trampoline duties (e.g. pc/fp/etc) and then load a function pointer to the host implementation.
  • The host implementation is invoked and then proceeds as usual.

The main new piece for this PR is that all wasm modules and functions are compiled in parallel but an output of this compilation phase is what builtin functions are required. All builtin functions are then unioned together into one set and then anything required is generated just afterwards. That means that only one builtin-trampoline per-module is generated per-builtin.

This work is inspired by #8135 and my own personal desire to have as much about our ABI details flowing through Cranelift as we can. This in theory makes it more flexible to deal with future improvements to our ABI.

@alexcrichton alexcrichton requested a review from a team as a code owner March 15, 2024 20:34
@alexcrichton alexcrichton requested review from fitzgen and removed request for a team March 15, 2024 20:34
@alexcrichton alexcrichton marked this pull request as draft March 15, 2024 20:34
@alexcrichton
Copy link
Member Author

I'll note that I'm opening this up as a draft because Winch doesn't work yet. I'll need to update invocation of those libcalls in addition to updating how trampolines are required. I plan on waiting until #8109 lands to fully implement that though to avoid implementing this new trampoline in Winch.

@github-actions github-actions bot added wasmtime:api Related to the API of the `wasmtime` crate itself winch Winch issues or pull requests labels Mar 15, 2024
Copy link

Subscribe to Label Action

cc @peterhuene, @saulecabrera

This issue or pull request has been labeled: "wasmtime:api", "winch"

Thus the following users have been cc'd because of the following labels:

  • peterhuene: wasmtime:api
  • saulecabrera: winch

To subscribe or unsubscribe from this label, edit the .github/subscribe-to-label.json configuration file.

Learn more.

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

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

Looks great! Excited to remove the last vestiges of hand-written asm.

crates/cranelift/src/func_environ.rs Outdated Show resolved Hide resolved
crates/runtime/src/libcalls.rs Outdated Show resolved Hide resolved
crates/wasmtime/src/compile.rs Outdated Show resolved Hide resolved
@alexcrichton alexcrichton force-pushed the builtin-trampolines-through-cranelift branch 3 times, most recently from 9735d55 to 2dd385c Compare March 21, 2024 18:03
@alexcrichton alexcrichton marked this pull request as ready for review March 21, 2024 18:04
@alexcrichton alexcrichton requested a review from a team as a code owner March 21, 2024 18:04
@alexcrichton alexcrichton requested review from abrown and removed request for a team March 21, 2024 18:04
@alexcrichton alexcrichton force-pushed the builtin-trampolines-through-cranelift branch from 2dd385c to fa18c36 Compare March 21, 2024 19:40
@alexcrichton alexcrichton requested a review from a team as a code owner March 22, 2024 15:00
@alexcrichton alexcrichton force-pushed the builtin-trampolines-through-cranelift branch from 3810ab5 to f08e292 Compare March 22, 2024 15:06
@alexcrichton
Copy link
Member Author

Ok various prerequisites are now landed on main and I've additionally implemented this for Winch too. The Winch changes are pretty nontrivial, so I'm going to request review from @saulecabrera and @elliottt, so if one of y'all could look at those and make sure I didn't do anything too weird it'd be much appreciated!

@alexcrichton alexcrichton requested review from saulecabrera, elliottt and fitzgen and removed request for abrown and a team March 22, 2024 15:08
Copy link
Member

@saulecabrera saulecabrera left a comment

Choose a reason for hiding this comment

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

Winch pieces look great to me, thanks!

winch/codegen/src/codegen/builtin.rs Show resolved Hide resolved
Comment on lines +92 to +96
Local(FuncIndex),
/// Imported function.
Import(&'a CalleeInfo),
Import(FuncIndex),
/// Function reference.
FuncRef(&'a ABISig),
FuncRef(TypeIndex),
Copy link
Member

Choose a reason for hiding this comment

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

Nice!

Copy link
Member

@elliottt elliottt left a comment

Choose a reason for hiding this comment

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

Awesome!

This commit changes how builtin functions in Wasmtime (think
`memory.grow`) are implemented. These functions are required to exit
through some manner of trampoline to handle runtime requirements for
backtracing right now. Currently this is done via inline assembly for
each architecture (or external assembly for s390x). This is a bit
unfortunate as it's a lot of hand-coding and making sure everything is
right, and it's not easy to update as it's multiple platforms to update.

The change in this commit is to instead use Cranelift-generated
trampolines for this purpose instead. The path for invoking a builtin
function now looks like:

* Wasm code calls a statically known symbol for each builtin.
* The statically known symbol will perform exit trampoline duties (e.g.
  pc/fp/etc) and then load a function pointer to the host
  implementation.
* The host implementation is invoked and then proceeds as usual.

The main new piece for this PR is that all wasm modules and functions
are compiled in parallel but an output of this compilation phase is what
builtin functions are required. All builtin functions are then unioned
together into one set and then anything required is generated just
afterwards. That means that only one builtin-trampoline per-module is
generated per-builtin.

This work is inspired by bytecodealliance#8135 and my own personal desire to have as
much about our ABI details flowing through Cranelift as we can. This in
theory makes it more flexible to deal with future improvements to our
ABI.

prtest:full
This commit refactors the Winch compiler to use the new trampolines for
all Wasmtime builtins created in the previous commits. This required a
fair bit of refactoring to handle plumbing through a new kind of
relocation and function call.

Winch's `FuncEnv` now contains a `PrimaryMap` from `UserExternalNameRef`
to `UserExternalName`. This is because there's now more than one kind of
name than just wasm function relocations, so the raw index space of
`UserExternalNameRef` is no longer applicable. This required threading
`FuncEnv` to more locations along with some refactorings to ensure that
lifetimes work out ok.

The `CompiledFunction` no longer stores a trait object of how to map
name refs to names and now directly has a `Primarymap`. This also means
that Winch's return value from its `TargetIsa` is a `CompiledFunction`
as opposed to the previous just-a-`MachBuffer` so it can also package up
all the relocation information. This ends up having `winch-codegen`
depend on `wasmtime-cranelift-shared` as a new dependency.
@alexcrichton alexcrichton force-pushed the builtin-trampolines-through-cranelift branch from f08e292 to ed948fa Compare March 22, 2024 20:09
@alexcrichton alexcrichton added this pull request to the merge queue Mar 22, 2024
Merged via the queue into bytecodealliance:main with commit 355990b Mar 22, 2024
43 checks passed
@alexcrichton alexcrichton deleted the builtin-trampolines-through-cranelift branch March 22, 2024 21:00
dhil pushed a commit to dhil/wasmtime that referenced this pull request Mar 26, 2024
…liance#8152)

* Exit through Cranelift-generated trampolines for builtins

This commit changes how builtin functions in Wasmtime (think
`memory.grow`) are implemented. These functions are required to exit
through some manner of trampoline to handle runtime requirements for
backtracing right now. Currently this is done via inline assembly for
each architecture (or external assembly for s390x). This is a bit
unfortunate as it's a lot of hand-coding and making sure everything is
right, and it's not easy to update as it's multiple platforms to update.

The change in this commit is to instead use Cranelift-generated
trampolines for this purpose instead. The path for invoking a builtin
function now looks like:

* Wasm code calls a statically known symbol for each builtin.
* The statically known symbol will perform exit trampoline duties (e.g.
  pc/fp/etc) and then load a function pointer to the host
  implementation.
* The host implementation is invoked and then proceeds as usual.

The main new piece for this PR is that all wasm modules and functions
are compiled in parallel but an output of this compilation phase is what
builtin functions are required. All builtin functions are then unioned
together into one set and then anything required is generated just
afterwards. That means that only one builtin-trampoline per-module is
generated per-builtin.

This work is inspired by bytecodealliance#8135 and my own personal desire to have as
much about our ABI details flowing through Cranelift as we can. This in
theory makes it more flexible to deal with future improvements to our
ABI.

prtest:full

* Fix some build issues

* Update winch test expectations

* Update Winch to use new builtin shims.

This commit refactors the Winch compiler to use the new trampolines for
all Wasmtime builtins created in the previous commits. This required a
fair bit of refactoring to handle plumbing through a new kind of
relocation and function call.

Winch's `FuncEnv` now contains a `PrimaryMap` from `UserExternalNameRef`
to `UserExternalName`. This is because there's now more than one kind of
name than just wasm function relocations, so the raw index space of
`UserExternalNameRef` is no longer applicable. This required threading
`FuncEnv` to more locations along with some refactorings to ensure that
lifetimes work out ok.

The `CompiledFunction` no longer stores a trait object of how to map
name refs to names and now directly has a `Primarymap`. This also means
that Winch's return value from its `TargetIsa` is a `CompiledFunction`
as opposed to the previous just-a-`MachBuffer` so it can also package up
all the relocation information. This ends up having `winch-codegen`
depend on `wasmtime-cranelift-shared` as a new dependency.

* Review feedback
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasmtime:api Related to the API of the `wasmtime` crate itself winch Winch issues or pull requests
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants