-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Make table growth a true async fn
#11442
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
Merged
alexcrichton
merged 2 commits into
bytecodealliance:main
from
alexcrichton:really-start-the-async-journey
Aug 18, 2025
Merged
Make table growth a true async fn
#11442
alexcrichton
merged 2 commits into
bytecodealliance:main
from
alexcrichton:really-start-the-async-journey
Aug 18, 2025
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Upon further refactoring and thinking about bytecodealliance#11430 I've realized that we might be able to sidestep `T: Send` on the store entirely which would be quite the boon if it can be pulled off. The realization I had is that the main reason for this was `&mut dyn VMStore` on the stack, but that itself is actually a bug in Wasmtime (bytecodealliance#11178) and shouldn't be done. The functions which have this on the stack should actually ONLY have the resource limiter, if configured. This means that while the `ResourceLimiter{,Async}` traits need a `Send` supertrait that's relatively easy to add without much impact. My hunch is that plumbing this through to the end will enable all the benefits of bytecodealliance#11430 without requiring adding `T: Send` to the store. This commit starts out on this journey by making table growth a true `async fn`. A new internal type is added to represent a store's limiter which is plumbed to growth functions. This represents a hierarchy of borrows that look like: * `StoreInner<T>` * `StoreResourceLimiter<'_>` * `StoreOpaque` * `Pin<&mut Instance>` * `&mut vm::Table` This notably, safely, allows operating on `vm::Table` with a `StoreResourceLimiter` at the same time. This is exactly what's needed and prevents needing to have `&mut dyn VMStore`, the previous argument, on the stack. This refactoring cleans up `unsafe` blocks in table growth right now which manually uses raw pointers to work around the borrow checker. No more now! I'll note as well that this is just an incremental step. What I plan on doing next is handling other locations like memory growth, memory allocation, and table allocation. Each of those will require further refactorings to ensure that things like GC are correctly accounted for so they're going to be split into separate PRs. Functionally though this PR should have no impact other than a fiber is no longer required for `Table::grow_async`.
pchickey
approved these changes
Aug 18, 2025
alexcrichton
added a commit
to alexcrichton/wasmtime
that referenced
this pull request
Aug 19, 2025
This is an analog of bytecodealliance#11442 but for memories. This had a little more impact due to memories being hooked into GC operations. Further refactoring of GC operations to make them safer/more-async is deferred to a future PR and for now it's "no worse than before". This is another step towards bytecodealliance#11430 and enables removing a longstanding `unsafe` block in `runtime/memory.rs` which previously could not be removed. One semantic change from this is that growth of a shared memory no longer uses an async limiter. This is done to keep growth of a shared memory consistent with creation of a shared memory where no limits are applied. This is due to the cross-store nature of shared memories which means that we can't tie growth to any one particular store. This additionally fixes an issue where an rwlock write guard was otherwise held across a `.await` point which creates a non-`Send` future, closing a possible soundness hole in Wasmtime.
alexcrichton
added a commit
to alexcrichton/wasmtime
that referenced
this pull request
Aug 19, 2025
This is an analog of bytecodealliance#11442 but for memories. This had a little more impact due to memories being hooked into GC operations. Further refactoring of GC operations to make them safer/more-async is deferred to a future PR and for now it's "no worse than before". This is another step towards bytecodealliance#11430 and enables removing a longstanding `unsafe` block in `runtime/memory.rs` which previously could not be removed. One semantic change from this is that growth of a shared memory no longer uses an async limiter. This is done to keep growth of a shared memory consistent with creation of a shared memory where no limits are applied. This is due to the cross-store nature of shared memories which means that we can't tie growth to any one particular store. This additionally fixes an issue where an rwlock write guard was otherwise held across a `.await` point which creates a non-`Send` future, closing a possible soundness hole in Wasmtime.
alexcrichton
added a commit
to alexcrichton/wasmtime
that referenced
this pull request
Aug 19, 2025
This commit is similar to bytecodealliance#11442 and bytecodealliance#11460 except it's applied to the garbage collection phase of Wasmtime's GC. Specifically the functions that actually perform a GC are no longer duplicated across sync, async, and maybe async versions. There's only one "always async" version and the root-level crate entrypoints for sync versions assert that async support is disabled and then use the async version. Worth noting here is that GC suffers from a preexisting issue described in bytecodealliance#11409 where it's not sound how a `StoreOpaque` is widened to acquire a resource limiter. This commit seemingly makes the issue worse by adding a few more `unsafe` blocks, but they're all fundamentally doing the same thing as before. Fully solving this issue will require making memory/table creation an `async` function that takes the limiter as an argument. Doing this will require further refactoring/code movement so my goal is to effectively maintain the status quo, but in a slightly different location, and enable knocking out the `unsafe` in the future. In the meantime the previous `unsafe` block is "lifted higher up" so it's not quite so deep and should be easier to remove in the future.
alexcrichton
added a commit
to alexcrichton/wasmtime
that referenced
this pull request
Aug 19, 2025
This is an analog of bytecodealliance#11442 but for memories. This had a little more impact due to memories being hooked into GC operations. Further refactoring of GC operations to make them safer/more-async is deferred to a future PR and for now it's "no worse than before". This is another step towards bytecodealliance#11430 and enables removing a longstanding `unsafe` block in `runtime/memory.rs` which previously could not be removed. One semantic change from this is that growth of a shared memory no longer uses an async limiter. This is done to keep growth of a shared memory consistent with creation of a shared memory where no limits are applied. This is due to the cross-store nature of shared memories which means that we can't tie growth to any one particular store. This additionally fixes an issue where an rwlock write guard was otherwise held across a `.await` point which creates a non-`Send` future, closing a possible soundness hole in Wasmtime.
github-merge-queue bot
pushed a commit
that referenced
this pull request
Aug 19, 2025
* Make memory growth an `async` function This is an analog of #11442 but for memories. This had a little more impact due to memories being hooked into GC operations. Further refactoring of GC operations to make them safer/more-async is deferred to a future PR and for now it's "no worse than before". This is another step towards #11430 and enables removing a longstanding `unsafe` block in `runtime/memory.rs` which previously could not be removed. One semantic change from this is that growth of a shared memory no longer uses an async limiter. This is done to keep growth of a shared memory consistent with creation of a shared memory where no limits are applied. This is due to the cross-store nature of shared memories which means that we can't tie growth to any one particular store. This additionally fixes an issue where an rwlock write guard was otherwise held across a `.await` point which creates a non-`Send` future, closing a possible soundness hole in Wasmtime. * Fix threads-disabled build * Review comments
alexcrichton
added a commit
to alexcrichton/wasmtime
that referenced
this pull request
Aug 19, 2025
This commit is similar to bytecodealliance#11442 and bytecodealliance#11460 except it's applied to the garbage collection phase of Wasmtime's GC. Specifically the functions that actually perform a GC are no longer duplicated across sync, async, and maybe async versions. There's only one "always async" version and the root-level crate entrypoints for sync versions assert that async support is disabled and then use the async version. Worth noting here is that GC suffers from a preexisting issue described in bytecodealliance#11409 where it's not sound how a `StoreOpaque` is widened to acquire a resource limiter. This commit seemingly makes the issue worse by adding a few more `unsafe` blocks, but they're all fundamentally doing the same thing as before. Fully solving this issue will require making memory/table creation an `async` function that takes the limiter as an argument. Doing this will require further refactoring/code movement so my goal is to effectively maintain the status quo, but in a slightly different location, and enable knocking out the `unsafe` in the future. In the meantime the previous `unsafe` block is "lifted higher up" so it's not quite so deep and should be easier to remove in the future.
github-merge-queue bot
pushed a commit
that referenced
this pull request
Aug 19, 2025
* Make garbage collection an `async` function This commit is similar to #11442 and #11460 except it's applied to the garbage collection phase of Wasmtime's GC. Specifically the functions that actually perform a GC are no longer duplicated across sync, async, and maybe async versions. There's only one "always async" version and the root-level crate entrypoints for sync versions assert that async support is disabled and then use the async version. Worth noting here is that GC suffers from a preexisting issue described in #11409 where it's not sound how a `StoreOpaque` is widened to acquire a resource limiter. This commit seemingly makes the issue worse by adding a few more `unsafe` blocks, but they're all fundamentally doing the same thing as before. Fully solving this issue will require making memory/table creation an `async` function that takes the limiter as an argument. Doing this will require further refactoring/code movement so my goal is to effectively maintain the status quo, but in a slightly different location, and enable knocking out the `unsafe` in the future. In the meantime the previous `unsafe` block is "lifted higher up" so it's not quite so deep and should be easier to remove in the future. * Review comments * Fix configured build * More configured build fixes
bongjunj
pushed a commit
to prosyslab/wasmtime
that referenced
this pull request
Oct 20, 2025
* Make table growth a true `async fn` Upon further refactoring and thinking about bytecodealliance#11430 I've realized that we might be able to sidestep `T: Send` on the store entirely which would be quite the boon if it can be pulled off. The realization I had is that the main reason for this was `&mut dyn VMStore` on the stack, but that itself is actually a bug in Wasmtime (bytecodealliance#11178) and shouldn't be done. The functions which have this on the stack should actually ONLY have the resource limiter, if configured. This means that while the `ResourceLimiter{,Async}` traits need a `Send` supertrait that's relatively easy to add without much impact. My hunch is that plumbing this through to the end will enable all the benefits of bytecodealliance#11430 without requiring adding `T: Send` to the store. This commit starts out on this journey by making table growth a true `async fn`. A new internal type is added to represent a store's limiter which is plumbed to growth functions. This represents a hierarchy of borrows that look like: * `StoreInner<T>` * `StoreResourceLimiter<'_>` * `StoreOpaque` * `Pin<&mut Instance>` * `&mut vm::Table` This notably, safely, allows operating on `vm::Table` with a `StoreResourceLimiter` at the same time. This is exactly what's needed and prevents needing to have `&mut dyn VMStore`, the previous argument, on the stack. This refactoring cleans up `unsafe` blocks in table growth right now which manually uses raw pointers to work around the borrow checker. No more now! I'll note as well that this is just an incremental step. What I plan on doing next is handling other locations like memory growth, memory allocation, and table allocation. Each of those will require further refactorings to ensure that things like GC are correctly accounted for so they're going to be split into separate PRs. Functionally though this PR should have no impact other than a fiber is no longer required for `Table::grow_async`. * Remove #[cfg] gate
bongjunj
pushed a commit
to prosyslab/wasmtime
that referenced
this pull request
Oct 20, 2025
* Make memory growth an `async` function This is an analog of bytecodealliance#11442 but for memories. This had a little more impact due to memories being hooked into GC operations. Further refactoring of GC operations to make them safer/more-async is deferred to a future PR and for now it's "no worse than before". This is another step towards bytecodealliance#11430 and enables removing a longstanding `unsafe` block in `runtime/memory.rs` which previously could not be removed. One semantic change from this is that growth of a shared memory no longer uses an async limiter. This is done to keep growth of a shared memory consistent with creation of a shared memory where no limits are applied. This is due to the cross-store nature of shared memories which means that we can't tie growth to any one particular store. This additionally fixes an issue where an rwlock write guard was otherwise held across a `.await` point which creates a non-`Send` future, closing a possible soundness hole in Wasmtime. * Fix threads-disabled build * Review comments
bongjunj
pushed a commit
to prosyslab/wasmtime
that referenced
this pull request
Oct 20, 2025
* Make garbage collection an `async` function This commit is similar to bytecodealliance#11442 and bytecodealliance#11460 except it's applied to the garbage collection phase of Wasmtime's GC. Specifically the functions that actually perform a GC are no longer duplicated across sync, async, and maybe async versions. There's only one "always async" version and the root-level crate entrypoints for sync versions assert that async support is disabled and then use the async version. Worth noting here is that GC suffers from a preexisting issue described in bytecodealliance#11409 where it's not sound how a `StoreOpaque` is widened to acquire a resource limiter. This commit seemingly makes the issue worse by adding a few more `unsafe` blocks, but they're all fundamentally doing the same thing as before. Fully solving this issue will require making memory/table creation an `async` function that takes the limiter as an argument. Doing this will require further refactoring/code movement so my goal is to effectively maintain the status quo, but in a slightly different location, and enable knocking out the `unsafe` in the future. In the meantime the previous `unsafe` block is "lifted higher up" so it's not quite so deep and should be easier to remove in the future. * Review comments * Fix configured build * More configured build fixes
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Upon further refactoring and thinking about #11430 I've realized that we might be able to sidestep
T: Sendon the store entirely which would be quite the boon if it can be pulled off. The realization I had is that the main reason for this was&mut dyn VMStoreon the stack, but that itself is actually a bug in Wasmtime (#11178) and shouldn't be done. The functions which have this on the stack should actually ONLY have the resource limiter, if configured. This means that while theResourceLimiter{,Async}traits need aSendsupertrait that's relatively easy to add without much impact. My hunch is that plumbing this through to the end will enable all the benefits of #11430 without requiring addingT: Sendto the store.This commit starts out on this journey by making table growth a true
async fn. A new internal type is added to represent a store's limiter which is plumbed to growth functions. This represents a hierarchy of borrows that look like:StoreInner<T>StoreResourceLimiter<'_>StoreOpaquePin<&mut Instance>&mut vm::TableThis notably, safely, allows operating on
vm::Tablewith aStoreResourceLimiterat the same time. This is exactly what's needed and prevents needing to have&mut dyn VMStore, the previous argument, on the stack.This refactoring cleans up
unsafeblocks in table growth right now which manually uses raw pointers to work around the borrow checker. No more now!I'll note as well that this is just an incremental step. What I plan on doing next is handling other locations like memory growth, memory allocation, and table allocation. Each of those will require further refactorings to ensure that things like GC are correctly accounted for so they're going to be split into separate PRs. Functionally though this PR should have no impact other than a fiber is no longer required for
Table::grow_async.