smarcd opened issue #14965:
#14386 narrowed epoch-deadline and call-hook callbacks to
StoreHookState, which implementsAsContextand gives&mut T. We agree with the rationale: mutating wasm-visible state between instructions is wrong.That change leaves one read-only use case with no API: reading the current value of a mutable numeric global from inside the callback.
Global::gettakesimpl AsContextMut. As far as I can tell that is because theRefarms clone GC refs (clone_gc_ref,ExternRef::from_cloned_gc_ref) and needAutoAssertNoGc. Fori32/i64/f32/f64(andv128) it is a plain load from theVMGlobalDefinitionand mutates nothing. So there is no way to read a numeric global with only anAsContext.Our use case: an embedder that snapshots a suspended guest thread reads the guest's mutable globals (such as the shadow stack pointer) at the moment an epoch tick parks the thread, while the wasm frames are still live on the stack. The thread is paused at a safe point; nothing is mutated, and we do not call back into wasm.
Proposal: a getter that takes
impl AsContextand returnsOption<Val>/Result<Val>for non-reference global types (returningNone/ErrforReftypes), e.g.Global::get_numeric. It would be safe to expose fromStoreHookStatefor the same reasonMemory::data(&store)already is.If you would rather not add API surface, is there an intended way for an embedder to observe global values from an epoch callback now? The
DebugHandlerroute (DebugEvent::EpochYield) seems to requireguest_debugand async, which is heavier than we want for this.Happy to send a PR if this direction is acceptable.
alexcrichton commented on issue #14965:
Thanks for the report! This was a known possible downside of #14386 and there's no current replacement for the functionality.
One of the downsides of an accessor like this is that it's so specialized to just numeric globals and doesn't handle the GC proposal of wasm. Originally
Global::getused to takeAsContextbut with GC that's where it changed toAsContextMutbecause rooting/frobbing needs to happen in that situation. I realize though that's exactly the intention here, but the second downside is that this is duplicating API/implementation surface area for this.That being said I don't really see a way around this, and I think it's a reasonable ask to be able to read globals with just
AsContext. We'll eventually need to extend that to tables too most likely, but that can probably wait until it's needed.Bikeshedding-wise I don't have any great idea other than
get_numeric, so that seems reasonable to me. If you'd like to send a PR we can review.
alexcrichton added the enhancement label to Issue #14965.
alexcrichton added the wasmtime:api label to Issue #14965.
pchickey closed issue #14965:
#14386 narrowed epoch-deadline and call-hook callbacks to
StoreHookState, which implementsAsContextand gives&mut T. We agree with the rationale: mutating wasm-visible state between instructions is wrong.That change leaves one read-only use case with no API: reading the current value of a mutable numeric global from inside the callback.
Global::gettakesimpl AsContextMut. As far as I can tell that is because theRefarms clone GC refs (clone_gc_ref,ExternRef::from_cloned_gc_ref) and needAutoAssertNoGc. Fori32/i64/f32/f64(andv128) it is a plain load from theVMGlobalDefinitionand mutates nothing. So there is no way to read a numeric global with only anAsContext.Our use case: an embedder that snapshots a suspended guest thread reads the guest's mutable globals (such as the shadow stack pointer) at the moment an epoch tick parks the thread, while the wasm frames are still live on the stack. The thread is paused at a safe point; nothing is mutated, and we do not call back into wasm.
Proposal: a getter that takes
impl AsContextand returnsOption<Val>/Result<Val>for non-reference global types (returningNone/ErrforReftypes), e.g.Global::get_numeric. It would be safe to expose fromStoreHookStatefor the same reasonMemory::data(&store)already is.If you would rather not add API surface, is there an intended way for an embedder to observe global values from an epoch callback now? The
DebugHandlerroute (DebugEvent::EpochYield) seems to requireguest_debugand async, which is heavier than we want for this.Happy to send a PR if this direction is acceptable.
Last updated: Oct 31 2026 at 23:03 UTC