Make table/memory creation async functions #11470
Make table/memory creation async functions #11470alexcrichton merged 4 commits intobytecodealliance:mainfrom
Conversation
|
I'll note that I've split this into two commits, the first of which is #11456 resurrected here. That commit cannot be split out to a second PR due to all the various constraints in play unfortunately, so this is a bit larger than I would have otherwise anticipated. |
|
Oh, I should also note, this is a 5% performance penalty overhead to instance instantiation. Benchmarking makes me think it's primarily related to the |
This commit is a step in preparation for bytecodealliance#11430, notably core instance allocation, or `StoreOpaque::allocate_instance` is now an `async fn`. This function does not actually use the `async`-ness just yet so it's a noop from that point of view, but this propagates outwards to enough locations that I wanted to split this off to make future changes more digestable. Notably some creation functions here such as making an `Instance`, `Table`, or `Memory` are refactored internally to use this new `async` function. Annotations of `assert_ready` or `one_poll` are used as appropriate as well. For reference this commit was benchmarked with our `instantiation.rs` benchmark in the pooling allocator and shows no changes relative to the original baseline from before-`async`-PRs.
This commit is a large-ish refactor which is made possible by the many previous refactorings to internals w.r.t. async-in-Wasmtime. The end goal of this change is that table and memory allocation are both `async` functions. Achieving this, however, required some refactoring to enable it to work: * To work with `Send` neither function can close over `dyn VMStore`. This required changing their `Option<&mut dyn VMStore>` arugment to `Option<&mut StoreResourceLimiter<'_>>` * Somehow a `StoreResourceLimiter` needed to be acquired from an `InstanceAllocationRequest`. Previously the store was stored here as an unsafe raw pointer, but I've refactored this now so `InstanceAllocationRequest` directly stores `&StoreOpaque` and `Option<&mut StoreResourceLimiter>` meaning it's trivial to acquire them. This additionally means no more `unsafe` access of the store during instance allocation (yay!). * Now-redundant fields of `InstanceAllocationRequest` were removed since they can be safely inferred from `&StoreOpaque`. For example passing around `&Tunables` is now all gone. * Methods upwards from table/memory allocation to the `InstanceAllocator` trait needed to be made `async`. This includes new `#[async_trait]` methods for example. * `StoreOpaque::ensure_gc_store` is now an `async` function. This internally carries a new `unsafe` block carried over from before with the raw point passed around in `InstanceAllocationRequest`. A future PR will delete this `unsafe` block, it's just temporary. I attempted a few times to split this PR up into separate commits but everything is relatively intertwined here so this is the smallest "atomic" unit I could manage to land these changes and refactorings.
02b763f to
cfc2cea
Compare
| vm::one_poll(Table::_new(store.as_context_mut().0, ty, init)) | ||
| .expect("must use `new_async` when async resource limiters are in use") |
There was a problem hiding this comment.
Should we not assert that this is a non-async config before the .expect(..) to catch mismatches a little earlier?
There was a problem hiding this comment.
Oh this is actually replicating the documented behavior where this works with async_support so long as an async resource limiter isn't used. In that sense to avoid breaking the semantics here one_poll is what's required as opposed to an assert!(!async_support) plus vm::assert_ready.
| ); | ||
| store.on_fiber(|store| self.instantiate_impl(store)).await? | ||
| pub async fn instantiate_async(&self, store: impl AsContextMut<Data = T>) -> Result<Instance> { | ||
| self._instantiate(store).await |
There was a problem hiding this comment.
And similarly assert that the config is async here?
There was a problem hiding this comment.
As I've been making these changes I've actually been undoing a lot of assert!(async_support)-style assertions. Previously that was required because on_fiber was immediately used which required async_support to be turned on, but now it's just normal Rust async functions so there's no reason to prevent usage when async_support is disabled. In that sense it's intentional that the assert here is lost, but how's that sound to you?
| // FIXME(rust-lang/rust#145127) this should ideally use a version of | ||
| // `with_flush_and_retry` but adapted for async closures instead of only | ||
| // sync closures. Right now that won't compile though so this is the | ||
| // manually expanded version of the method. |
There was a problem hiding this comment.
Add a note for this to our items to discuss with the lang team, if we don't have one already?
There was a problem hiding this comment.
Oh this one's technically already fixed and just waiting on stabilization, and browsing rust-lang/rust#110338 shows this is pretty well-known, so not a major issue.
| /// The store that this instance is being allocated into. | ||
| pub store: &'a StoreOpaque, |
|
I'm going to go ahead and land this, but @fitzgen if you have follow up comments I'm happy to address them. |
Nope, looks good |
* Make core instance allocation an `async` function This commit is a step in preparation for bytecodealliance#11430, notably core instance allocation, or `StoreOpaque::allocate_instance` is now an `async fn`. This function does not actually use the `async`-ness just yet so it's a noop from that point of view, but this propagates outwards to enough locations that I wanted to split this off to make future changes more digestable. Notably some creation functions here such as making an `Instance`, `Table`, or `Memory` are refactored internally to use this new `async` function. Annotations of `assert_ready` or `one_poll` are used as appropriate as well. For reference this commit was benchmarked with our `instantiation.rs` benchmark in the pooling allocator and shows no changes relative to the original baseline from before-`async`-PRs. * Make table/memory creation `async` functions This commit is a large-ish refactor which is made possible by the many previous refactorings to internals w.r.t. async-in-Wasmtime. The end goal of this change is that table and memory allocation are both `async` functions. Achieving this, however, required some refactoring to enable it to work: * To work with `Send` neither function can close over `dyn VMStore`. This required changing their `Option<&mut dyn VMStore>` arugment to `Option<&mut StoreResourceLimiter<'_>>` * Somehow a `StoreResourceLimiter` needed to be acquired from an `InstanceAllocationRequest`. Previously the store was stored here as an unsafe raw pointer, but I've refactored this now so `InstanceAllocationRequest` directly stores `&StoreOpaque` and `Option<&mut StoreResourceLimiter>` meaning it's trivial to acquire them. This additionally means no more `unsafe` access of the store during instance allocation (yay!). * Now-redundant fields of `InstanceAllocationRequest` were removed since they can be safely inferred from `&StoreOpaque`. For example passing around `&Tunables` is now all gone. * Methods upwards from table/memory allocation to the `InstanceAllocator` trait needed to be made `async`. This includes new `#[async_trait]` methods for example. * `StoreOpaque::ensure_gc_store` is now an `async` function. This internally carries a new `unsafe` block carried over from before with the raw point passed around in `InstanceAllocationRequest`. A future PR will delete this `unsafe` block, it's just temporary. I attempted a few times to split this PR up into separate commits but everything is relatively intertwined here so this is the smallest "atomic" unit I could manage to land these changes and refactorings. * Shuffle `async-trait` dep * Fix configured build
This commit is a large-ish refactor which is made possible by the many
previous refactorings to internals w.r.t. async-in-Wasmtime. The end
goal of this change is that table and memory allocation are both
asyncfunctions. Achieving this, however, required some refactoring to enable
it to work:
Sendneither function can close overdyn VMStore.This required changing their
Option<&mut dyn VMStore>arugment toOption<&mut StoreResourceLimiter<'_>>StoreResourceLimiterneeded to be acquired from anInstanceAllocationRequest. Previously the store was stored here asan unsafe raw pointer, but I've refactored this now so
InstanceAllocationRequestdirectly stores&StoreOpaqueandOption<&mut StoreResourceLimiter>meaning it's trivial to acquirethem. This additionally means no more
unsafeaccess of the storeduring instance allocation (yay!).
InstanceAllocationRequestwere removed sincethey can be safely inferred from
&StoreOpaque. For example passingaround
&Tunablesis now all gone.InstanceAllocatortrait needed to be madeasync. This includes new#[async_trait]methods for example.StoreOpaque::ensure_gc_storeis now anasyncfunction. Thisinternally carries a new
unsafeblock carried over from before withthe raw point passed around in
InstanceAllocationRequest. A futurePR will delete this
unsafeblock, it's just temporary.I attempted a few times to split this PR up into separate commits but
everything is relatively intertwined here so this is the smallest
"atomic" unit I could manage to land these changes and refactorings.
cc #11430