fitzgen opened PR #9565 from fitzgen:instance-and-store-split to bytecodealliance:main:
At various times, for example in libcalls, we need to go from a raw
vmctxpointer that Wasm gave us to both an&mut Instanceand an&mut Store{Opaque,Context}. This is a pretty fundamental unsafe aspect of implementing a language runtimne in Rust, but we can tighten things up a bit and make them a little safer than they currently are. This commit is such an attempt and is notably tackling the issue of creating multiple store borrows after we have an instance borrow.This commit makes the following changes:
Instancedoesn't expose a method to get the raw*mut dyn VMStorepointer or otherwise create a store borrow.You cannot construct an
Instancedirectly from avmctxpointer.There is now an
InstanceAndStoretype that represents unique access to both anInstanceand aStore.You can (with
unsafe) create anInstanceAndStorefrom a rawvmctxpointer. This generally only happens inside a couple "bottlenecks", not all throughout the codebase, like the shared plumbing code for libcalls.The
InstanceAndStorecan be unpacked into a mutable borrow of anInstanceand a mutable borrow of aStore. This unpacking takes holds a mutable borrow of the originalInstanceAndStore, so double borrows of the store are no longer a concern, so long as you don't useunsafeto create newInstanceAndStores for the samevmctx.All
Instancemethods and functions that previously would unsafely turn theInstance's internal store pointer into a store borrow to perform some action now take a store argument, and this store is threaded around as necessary.Altogether, I feel that we've ended up with an architecture that is a safety improvement over where we were previously, and will help us properly avoid Rust UB.
For what its worth, I do not think this is the end state. I foresee at least two additional follow ups that I unfortunately do not currently have time for:
Create
ComponentInstanceAndStore, which is the same thing that this commit did but for components. I started on this but ran out of fuel while trying to update macros for all the component shims and transcoders.Stop dealing with
&mut vm::Tables and&mut vm::Globals and all that in the runtime. Instead just deal with indices, similar to how things are structured in the host API level. This refactoring was not previously possible due to (1) thewasmtimeversuswasmtime-runtimecrate split and (2) the lack ofStoreOpaques threaded through the VM internals. The first blocker was addressed a few months ago, this commit removes the second blocker. This will still be a pretty large refactoring though, but I think ultimately will be worth it.<!--
Please make sure you include the following information:
If this work has been discussed elsewhere, please include a link to that
conversation. If it was discussed in an issue, just mention "issue #...".Explain why this change is needed. If the details are in an issue already,
this can be brief.Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.htmlPlease ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->
fitzgen requested wasmtime-core-reviewers for a review on PR #9565.
fitzgen requested alexcrichton for a review on PR #9565.
fitzgen updated PR #9565.
fitzgen updated PR #9565.
alexcrichton submitted PR review:
Looks great :+1:
One comment about the
'staticthough on thedyn VMStoretype though.
alexcrichton created PR review comment:
Can the
'statichere be removed? In theory that's a "lie" because we don't constrainT: 'staticin theStore<T>.
fitzgen submitted PR review.
fitzgen created PR review comment:
Unfortunately, I don't think it can be or else the borrow is invariant and the
InstanceAndStoreis unusable after calling unpack once, which isn't acceptable forCaller::with, which needs to access the pair multiple times. It miiight have been an issue in certain libcalls too, I can't quite remember.Morally, I see this as a "smaller lie" than our current status quo where we just whip up a borrow from a raw pointer whenever we feel like it...
I can try poking at it again, but if I can't figure out a way to remove the
'static, do you think this is a blocker to landing this?
alexcrichton submitted PR review.
alexcrichton created PR review comment:
Hm this is surprising. I'm worried about labeling this
'staticwhen it wasn't since that to me isn't a failure condition we worried about before (I think at least?). Mind trying to remove it and see what happens?I'm also surprised if
InstanceAndStoreis unusable after one call, as that probably means we have this whole tying typed incorrectly anyway...
fitzgen submitted PR review.
fitzgen created PR review comment:
I guess we could maybe get rid of
InstanceAndStoreand just haveimpl Instance { pub(crate) unsafe fn from_vmctx<R>(vmctx: *mut VMContext, f: impl FnOnce(&mut StoreOpaque, &mut Instance) -> R) -> R { // ... } }(And another version for
StoreInner<T>)
fitzgen submitted PR review.
fitzgen created PR review comment:
This would require moving all the
VMStoretrait methods toStoreOpaque
fitzgen updated PR #9565.
alexcrichton submitted PR review.
fitzgen merged PR #9565.
Last updated: Dec 06 2025 at 06:05 UTC