Skip to content

Commit 9bc302a

Browse files
authored
Reduce type complexity of InstanceAllocator async functions (#12887)
This is a follow-on to #12849 to try to simplify some of the resulting signatures a bit. Notably the `Result<..., OutOfMemory>` is now packaged up directly into the output future, so the functions still retain a sort of "async trait" feel even though they're still incompatible with `#[async_trait]` (and can't be defined with that anyway).
1 parent 1ee1020 commit 9bc302a

6 files changed

Lines changed: 70 additions & 51 deletions

File tree

crates/wasmtime/src/runtime.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@
2626
// situation should be pretty rare though.
2727
#![warn(clippy::cast_possible_truncation)]
2828

29+
use crate::prelude::*;
30+
use core::marker;
31+
use core::pin::Pin;
32+
use core::task::{Context, Poll};
33+
2934
#[cfg(feature = "component-model-async")]
3035
mod bug;
3136

@@ -127,6 +132,43 @@ pub use coredump::*;
127132
#[cfg(feature = "wave")]
128133
mod wave;
129134

135+
/// Helper method to create a future trait object from the future `F` provided.
136+
///
137+
/// This requires that the output of `F` is a result where the error can be
138+
/// created from `OutOfMemory`. This will handle OOM when allocation of `F` on
139+
/// the heap fails.
140+
fn box_future<'a, F, T, E>(future: F) -> Pin<Box<dyn Future<Output = Result<T, E>> + Send + 'a>>
141+
where
142+
F: Future<Output = Result<T, E>> + Send + 'a,
143+
T: 'a,
144+
E: From<OutOfMemory> + 'a,
145+
{
146+
if let Ok(future) = try_new::<Box<F>>(future) {
147+
return Pin::from(future);
148+
}
149+
150+
// Use a custom guaranteed-zero-size struct to implement a future that
151+
// returns an OOM error which satisfies the type signature of this function.
152+
struct OomFuture<F, T, E>(marker::PhantomData<fn() -> (T, F, E)>);
153+
154+
impl<F, T, E> Future for OomFuture<F, T, E>
155+
where
156+
E: From<OutOfMemory>,
157+
{
158+
type Output = Result<T, E>;
159+
160+
fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Self::Output> {
161+
Poll::Ready(Err(OutOfMemory::new(size_of::<F>()).into()))
162+
}
163+
}
164+
165+
// Zero-size allocations don't actually allocate memory with a `Box`, so
166+
// it's ok to use the standard `Box::pin` here and not worry about OOM.
167+
let future = OomFuture::<F, T, E>(marker::PhantomData);
168+
assert_eq!(size_of_val(&future), 0);
169+
Box::pin(future)
170+
}
171+
130172
fn _assertions_runtime() {
131173
use crate::_assert_send_and_sync;
132174

crates/wasmtime/src/runtime/store.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1958,7 +1958,7 @@ impl StoreOpaque {
19581958

19591959
let (mem_alloc_index, mem) = engine
19601960
.allocator()
1961-
.allocate_memory(&mut request, &mem_ty, None)?
1961+
.allocate_memory(&mut request, &mem_ty, None)
19621962
.await?;
19631963

19641964
// Then, allocate the actual GC heap, passing in that memory

crates/wasmtime/src/runtime/trampoline/memory.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -176,10 +176,7 @@ unsafe impl InstanceAllocator for SingleMemoryInstance<'_> {
176176
request: &'a mut InstanceAllocationRequest<'b, 'c>,
177177
ty: &'a wasmtime_environ::Memory,
178178
memory_index: Option<DefinedMemoryIndex>,
179-
) -> Result<
180-
Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>,
181-
OutOfMemory,
182-
> {
179+
) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>> {
183180
if cfg!(debug_assertions) {
184181
let module = request.runtime_info.env_module();
185182
let offsets = request.runtime_info.offsets();
@@ -188,12 +185,12 @@ unsafe impl InstanceAllocator for SingleMemoryInstance<'_> {
188185
}
189186

190187
match self.preallocation {
191-
Some(shared_memory) => Ok(Box::into_pin(try_new::<Box<_>>(async move {
188+
Some(shared_memory) => crate::runtime::box_future(async move {
192189
Ok((
193190
MemoryAllocationIndex::default(),
194191
shared_memory.clone().as_memory(),
195192
))
196-
})?)),
193+
}),
197194
None => self.ondemand.allocate_memory(request, ty, memory_index),
198195
}
199196
}
@@ -215,10 +212,7 @@ unsafe impl InstanceAllocator for SingleMemoryInstance<'_> {
215212
req: &'a mut InstanceAllocationRequest<'b, 'c>,
216213
ty: &'a wasmtime_environ::Table,
217214
table_index: DefinedTableIndex,
218-
) -> Result<
219-
Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>>,
220-
OutOfMemory,
221-
> {
215+
) -> Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>> {
222216
self.ondemand.allocate_table(req, ty, table_index)
223217
}
224218

crates/wasmtime/src/runtime/vm/instance/allocator.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -193,10 +193,7 @@ pub unsafe trait InstanceAllocator: Send + Sync {
193193
request: &'a mut InstanceAllocationRequest<'b, 'c>,
194194
ty: &'a wasmtime_environ::Memory,
195195
memory_index: Option<DefinedMemoryIndex>,
196-
) -> Result<
197-
Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>,
198-
OutOfMemory,
199-
>;
196+
) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>;
200197

201198
/// Deallocate an instance's previously allocated memory.
202199
///
@@ -221,10 +218,7 @@ pub unsafe trait InstanceAllocator: Send + Sync {
221218
req: &'a mut InstanceAllocationRequest<'b, 'c>,
222219
table: &'a wasmtime_environ::Table,
223220
table_index: DefinedTableIndex,
224-
) -> Result<
225-
Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>>,
226-
OutOfMemory,
227-
>;
221+
) -> Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>>;
228222

229223
/// Deallocate an instance's previously allocated table.
230224
///
@@ -404,9 +398,9 @@ impl dyn InstanceAllocator + '_ {
404398

405399
/// Allocate the memories for the given instance allocation request, pushing
406400
/// them into `memories`.
407-
async fn allocate_memories<'a, 'b: 'a, 'c: 'a>(
408-
&'a self,
409-
request: &'a mut InstanceAllocationRequest<'b, 'c>,
401+
async fn allocate_memories(
402+
&self,
403+
request: &mut InstanceAllocationRequest<'_, '_>,
410404
memories: &mut TryPrimaryMap<DefinedMemoryIndex, (MemoryAllocationIndex, Memory)>,
411405
) -> Result<()> {
412406
let module = request.runtime_info.env_module();
@@ -422,7 +416,7 @@ impl dyn InstanceAllocator + '_ {
422416
.expect("should be a defined memory since we skipped imported ones");
423417

424418
let memory = self
425-
.allocate_memory(request, ty, Some(memory_index))?
419+
.allocate_memory(request, ty, Some(memory_index))
426420
.await?;
427421
memories.push(memory)?;
428422
}
@@ -457,9 +451,9 @@ impl dyn InstanceAllocator + '_ {
457451

458452
/// Allocate tables for the given instance allocation request, pushing them
459453
/// into `tables`.
460-
async fn allocate_tables<'a, 'b: 'a, 'c: 'a>(
461-
&'a self,
462-
request: &'a mut InstanceAllocationRequest<'b, 'c>,
454+
async fn allocate_tables(
455+
&self,
456+
request: &mut InstanceAllocationRequest<'_, '_>,
463457
tables: &mut TryPrimaryMap<DefinedTableIndex, (TableAllocationIndex, Table)>,
464458
) -> Result<()> {
465459
let module = request.runtime_info.env_module();
@@ -474,7 +468,7 @@ impl dyn InstanceAllocator + '_ {
474468
.defined_table_index(index)
475469
.expect("should be a defined table since we skipped imported ones");
476470

477-
let table = self.allocate_table(request, table, def_index)?.await?;
471+
let table = self.allocate_table(request, table, def_index).await?;
478472
tables.push(table)?;
479473
}
480474

crates/wasmtime/src/runtime/vm/instance/allocator/on_demand.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,16 +115,13 @@ unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
115115
request: &'a mut InstanceAllocationRequest<'b, 'c>,
116116
ty: &'a wasmtime_environ::Memory,
117117
memory_index: Option<DefinedMemoryIndex>,
118-
) -> Result<
119-
Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>,
120-
OutOfMemory,
121-
> {
118+
) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>> {
122119
let creator = self
123120
.mem_creator
124121
.as_deref()
125122
.unwrap_or_else(|| &DefaultMemoryCreator);
126123

127-
Ok(Box::into_pin(try_new::<Box<_>>(async move {
124+
crate::runtime::box_future(async move {
128125
let image = if let Some(memory_index) = memory_index {
129126
request.runtime_info.memory_image(memory_index)?
130127
} else {
@@ -141,7 +138,7 @@ unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
141138
)
142139
.await?;
143140
Ok((allocation_index, memory))
144-
})?))
141+
})
145142
}
146143

147144
unsafe fn deallocate_memory(
@@ -159,11 +156,8 @@ unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
159156
request: &'a mut InstanceAllocationRequest<'b, 'c>,
160157
ty: &'a wasmtime_environ::Table,
161158
_table_index: DefinedTableIndex,
162-
) -> Result<
163-
Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>>,
164-
OutOfMemory,
165-
> {
166-
Ok(Box::into_pin(try_new::<Box<_>>(async move {
159+
) -> Pin<Box<dyn Future<Output = Result<(TableAllocationIndex, Table)>> + Send + 'a>> {
160+
crate::runtime::box_future(async move {
167161
let allocation_index = TableAllocationIndex::default();
168162
let table = Table::new_dynamic(
169163
ty,
@@ -172,7 +166,7 @@ unsafe impl InstanceAllocator for OnDemandInstanceAllocator {
172166
)
173167
.await?;
174168
Ok((allocation_index, table))
175-
})?))
169+
})
176170
}
177171

178172
unsafe fn deallocate_table(

crates/wasmtime/src/runtime/vm/instance/allocator/pooling.rs

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -684,11 +684,8 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
684684
request: &'a mut InstanceAllocationRequest<'b, 'c>,
685685
ty: &'a wasmtime_environ::Memory,
686686
memory_index: Option<DefinedMemoryIndex>,
687-
) -> Result<
688-
Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>>,
689-
OutOfMemory,
690-
> {
691-
Ok(Box::into_pin(try_new::<Box<_>>(async move {
687+
) -> Pin<Box<dyn Future<Output = Result<(MemoryAllocationIndex, Memory)>> + Send + 'a>> {
688+
crate::runtime::box_future(async move {
692689
async {
693690
// FIXME(rust-lang/rust#145127) this should ideally use a version of
694691
// `with_flush_and_retry` but adapted for async closures instead of only
@@ -712,7 +709,7 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
712709
.inspect(|_| {
713710
self.live_memories.fetch_add(1, Ordering::Relaxed);
714711
})
715-
})?))
712+
})
716713
}
717714

718715
unsafe fn deallocate_memory(
@@ -758,11 +755,9 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
758755
request: &'a mut InstanceAllocationRequest<'b, 'c>,
759756
ty: &'a wasmtime_environ::Table,
760757
_table_index: DefinedTableIndex,
761-
) -> Result<
762-
Pin<Box<dyn Future<Output = Result<(super::TableAllocationIndex, Table)>> + Send + 'a>>,
763-
OutOfMemory,
764-
> {
765-
Ok(Box::into_pin(try_new::<Box<_>>(async move {
758+
) -> Pin<Box<dyn Future<Output = Result<(super::TableAllocationIndex, Table)>> + Send + 'a>>
759+
{
760+
crate::runtime::box_future(async move {
766761
async {
767762
// FIXME: see `allocate_memory` above for comments about duplication
768763
// with `with_flush_and_retry`.
@@ -784,7 +779,7 @@ unsafe impl InstanceAllocator for PoolingInstanceAllocator {
784779
.inspect(|_| {
785780
self.live_tables.fetch_add(1, Ordering::Relaxed);
786781
})
787-
})?))
782+
})
788783
}
789784

790785
unsafe fn deallocate_table(

0 commit comments

Comments
 (0)