When a host export function calls a guest import, the guest import can then call the same or a different host export.
The host export function has access to the Caller<T>
, which contains a normal &mut T
inside. When the guest function is called, causing the host code to subsequently enter a host export a new Caller<T>
will be available.
These two callers will exist simultaneously in the call stack, and alias &mut T
.
What I wonder is how it is possible, and how the MIR stacked borrows tags are upheld. I know that mutable reborrowing can solve some of these problems, but I suspect that this is not the case here and there is unsafe code going on to reconstruct a valid enough mutable reference without provenance before the call from the guest side, while a reference to the store and user data already exists higher up the call stack with a JIT block inbetween.
Here is a link to an example of this reentrant call and access to Caller
: https://github.com/ten3roberts/wasmtime-example/blob/daef67392558456415ddd880f76f231378c8618a/src/main.rs#L18-L37
The guest code isn't rust so yes there is certainly some unsafe
code at the guest/host boundaries (as with any FFI).
The way I think about this is that it's the same as passing &mut T
as an argument a to functions in Rust. You can have multiple frames on the stack which all refer to the same &mut T
, but the key is that each frame knows that the frame beneath it also has access.
For example calling wasm requires giving the entire Store<T>
(e.g. the entire T
) via mutable borrow back to Wasmtime. When Wasmtime calls the host Rust code it can give back the Store<T>
borrow through Caller<T>
while it hasn't been proven out the intention is that Wasmtime's API could theoretically be implemented entirely with safe code
Last updated: Dec 23 2024 at 13:07 UTC