Skip to content

Commit 16ee859

Browse files
committed
add component-model-async/task-builtins.wast test
This is another piece of bytecodealliance#9582 which I'm splitting out to make review easier. This test includes components which use the `task.backpressure`, `task.return`, `task.wait`, `task.poll`, `task.yield`, and `subtask.drop` builtins. The rest of the changes fill in some TODOs to make the test pass. Signed-off-by: Joel Dice <[email protected]>
1 parent 91a3a8b commit 16ee859

File tree

5 files changed

+352
-56
lines changed

5 files changed

+352
-56
lines changed

crates/cranelift/src/compiler/component.rs

Lines changed: 120 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -95,34 +95,25 @@ impl<'a> TrampolineCompiler<'a> {
9595
self.translate_always_trap();
9696
}
9797
Trampoline::TaskBackpressure { instance } => {
98-
_ = instance;
99-
todo!()
98+
self.translate_task_backpressure_call(*instance)
10099
}
101100
Trampoline::TaskReturn { results } => self.translate_task_return_call(*results),
102101
Trampoline::TaskWait {
103102
instance,
104103
async_,
105104
memory,
106105
} => {
107-
_ = (instance, async_, memory);
108-
todo!()
106+
self.translate_task_wait_or_poll_call(*instance, *async_, *memory, host::task_wait)
109107
}
110108
Trampoline::TaskPoll {
111109
instance,
112110
async_,
113111
memory,
114112
} => {
115-
_ = (instance, async_, memory);
116-
todo!()
117-
}
118-
Trampoline::TaskYield { async_ } => {
119-
_ = async_;
120-
todo!()
121-
}
122-
Trampoline::SubtaskDrop { instance } => {
123-
_ = instance;
124-
todo!()
113+
self.translate_task_wait_or_poll_call(*instance, *async_, *memory, host::task_poll)
125114
}
115+
Trampoline::TaskYield { async_ } => self.translate_task_yield_call(*async_),
116+
Trampoline::SubtaskDrop { instance } => self.translate_subtask_drop_call(*instance),
126117
Trampoline::StreamNew { ty } => {
127118
_ = ty;
128119
todo!()
@@ -261,7 +252,16 @@ impl<'a> TrampolineCompiler<'a> {
261252
}
262253
}
263254

264-
fn translate_task_return_call(&mut self, results: TypeTupleIndex) {
255+
fn translate_intrinsic_libcall(
256+
&mut self,
257+
vmctx: ir::Value,
258+
get_libcall: fn(
259+
&dyn TargetIsa,
260+
&mut ir::Function,
261+
) -> (ir::SigRef, ComponentBuiltinFunctionIndex),
262+
args: &[ir::Value],
263+
result: ir::types::Type,
264+
) {
265265
match self.abi {
266266
Abi::Wasm => {}
267267

@@ -274,29 +274,39 @@ impl<'a> TrampolineCompiler<'a> {
274274
}
275275
}
276276

277+
let call = self.call_libcall(vmctx, get_libcall, args);
278+
279+
if result == ir::types::I64 {
280+
let result = self.builder.func.dfg.inst_results(call)[0];
281+
let result = self.raise_if_negative_one(result);
282+
self.abi_store_results(&[result]);
283+
} else {
284+
if result != ir::types::I8 {
285+
todo!("support additional intrinsic return types")
286+
}
287+
let succeeded = self.builder.func.dfg.inst_results(call)[0];
288+
self.raise_if_host_trapped(succeeded);
289+
self.builder.ins().return_(&[]);
290+
}
291+
}
292+
293+
fn translate_task_return_call(&mut self, results: TypeTupleIndex) {
277294
let args = self.builder.func.dfg.block_params(self.block0).to_vec();
278295
let vmctx = args[0];
279296

280297
let (values_vec_ptr, values_vec_len) = self.store_wasm_arguments(&args[2..]);
281298

282-
let (host_sig, index) = host::task_return(self.isa, &mut self.builder.func);
283-
let host_fn = self.load_libcall(vmctx, index);
284-
285299
let ty = self
286300
.builder
287301
.ins()
288302
.iconst(ir::types::I32, i64::from(results.as_u32()));
289303

290-
let call = self.compiler.call_indirect_host(
291-
&mut self.builder,
292-
index,
293-
host_sig,
294-
host_fn,
304+
self.translate_intrinsic_libcall(
305+
vmctx,
306+
host::task_return,
295307
&[vmctx, ty, values_vec_ptr, values_vec_len],
308+
ir::types::I8,
296309
);
297-
let succeeded = self.builder.func.dfg.inst_results(call)[0];
298-
self.raise_if_host_trapped(succeeded);
299-
self.builder.ins().return_(&[]);
300310
}
301311

302312
fn translate_async_enter_or_exit(
@@ -311,23 +321,9 @@ impl<'a> TrampolineCompiler<'a> {
311321
)>,
312322
result: ir::types::Type,
313323
) {
314-
match self.abi {
315-
Abi::Wasm => {}
316-
317-
// These trampolines can only actually be called by Wasm, so
318-
// let's assert that here.
319-
Abi::Array => {
320-
self.builder.ins().trap(TRAP_INTERNAL_ASSERT);
321-
return;
322-
}
323-
}
324-
325324
let args = self.builder.func.dfg.block_params(self.block0).to_vec();
326325
let vmctx = args[0];
327326

328-
let (host_sig, index) = get_libcall(self.isa, &mut self.builder.func);
329-
let host_fn = self.load_libcall(vmctx, index);
330-
331327
let mut callee_args = vec![vmctx];
332328

333329
if let Some((callback, post_return)) = callback_and_post_return {
@@ -361,24 +357,93 @@ impl<'a> TrampolineCompiler<'a> {
361357
// remaining parameters
362358
callee_args.extend(args[2..].iter().copied());
363359

364-
let call = self.compiler.call_indirect_host(
365-
&mut self.builder,
366-
index,
367-
host_sig,
368-
host_fn,
360+
self.translate_intrinsic_libcall(vmctx, get_libcall, &callee_args, result);
361+
}
362+
363+
fn translate_task_backpressure_call(&mut self, caller_instance: RuntimeComponentInstanceIndex) {
364+
let args = self.builder.func.dfg.block_params(self.block0).to_vec();
365+
let vmctx = args[0];
366+
367+
let mut callee_args = vec![
368+
vmctx,
369+
self.builder
370+
.ins()
371+
.iconst(ir::types::I32, i64::from(caller_instance.as_u32())),
372+
];
373+
374+
callee_args.extend(args[2..].iter().copied());
375+
376+
self.translate_intrinsic_libcall(
377+
vmctx,
378+
host::task_backpressure,
369379
&callee_args,
380+
ir::types::I8,
370381
);
382+
}
371383

372-
if result == ir::types::I64 {
373-
let result = self.builder.func.dfg.inst_results(call)[0];
374-
let result = self.raise_if_negative_one(result);
375-
self.abi_store_results(&[result]);
376-
} else {
377-
assert!(result == ir::types::I8);
378-
let succeeded = self.builder.func.dfg.inst_results(call)[0];
379-
self.raise_if_host_trapped(succeeded);
380-
self.builder.ins().return_(&[]);
381-
}
384+
fn translate_task_wait_or_poll_call(
385+
&mut self,
386+
caller_instance: RuntimeComponentInstanceIndex,
387+
async_: bool,
388+
memory: RuntimeMemoryIndex,
389+
get_libcall: fn(
390+
&dyn TargetIsa,
391+
&mut ir::Function,
392+
) -> (ir::SigRef, ComponentBuiltinFunctionIndex),
393+
) {
394+
let pointer_type = self.isa.pointer_type();
395+
let args = self.builder.func.dfg.block_params(self.block0).to_vec();
396+
let vmctx = args[0];
397+
398+
let mut callee_args = vec![
399+
vmctx,
400+
self.builder
401+
.ins()
402+
.iconst(ir::types::I32, i64::from(caller_instance.as_u32())),
403+
self.builder
404+
.ins()
405+
.iconst(ir::types::I8, if async_ { 1 } else { 0 }),
406+
self.builder.ins().load(
407+
pointer_type,
408+
MemFlags::trusted(),
409+
vmctx,
410+
i32::try_from(self.offsets.runtime_memory(memory)).unwrap(),
411+
),
412+
];
413+
414+
callee_args.extend(args[2..].iter().copied());
415+
416+
self.translate_intrinsic_libcall(vmctx, get_libcall, &callee_args, ir::types::I64);
417+
}
418+
419+
fn translate_task_yield_call(&mut self, async_: bool) {
420+
let args = self.builder.func.dfg.block_params(self.block0).to_vec();
421+
let vmctx = args[0];
422+
423+
let callee_args = [
424+
vmctx,
425+
self.builder
426+
.ins()
427+
.iconst(ir::types::I8, if async_ { 1 } else { 0 }),
428+
];
429+
430+
self.translate_intrinsic_libcall(vmctx, host::task_yield, &callee_args, ir::types::I8);
431+
}
432+
433+
fn translate_subtask_drop_call(&mut self, caller_instance: RuntimeComponentInstanceIndex) {
434+
let args = self.builder.func.dfg.block_params(self.block0).to_vec();
435+
let vmctx = args[0];
436+
437+
let mut callee_args = vec![
438+
vmctx,
439+
self.builder
440+
.ins()
441+
.iconst(ir::types::I32, i64::from(caller_instance.as_u32())),
442+
];
443+
444+
callee_args.extend(args[2..].iter().copied());
445+
446+
self.translate_intrinsic_libcall(vmctx, host::subtask_drop, &callee_args, ir::types::I8);
382447
}
383448

384449
fn translate_lower_import(

crates/environ/src/component.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,19 @@ macro_rules! foreach_builtin_component_function {
8383
resource_enter_call(vmctx: vmctx);
8484
resource_exit_call(vmctx: vmctx) -> bool;
8585

86+
#[cfg(feature = "component-model-async")]
87+
task_backpressure(vmctx: vmctx, caller_instance: u32, enabled: u32) -> bool;
8688
#[cfg(feature = "component-model-async")]
8789
task_return(vmctx: vmctx, ty: u32, storage: ptr_u8, storage_len: size) -> bool;
8890
#[cfg(feature = "component-model-async")]
91+
task_wait(vmctx: vmctx, caller_instance: u32, async_: u8, memory: ptr_u8, payload: u32) -> u64;
92+
#[cfg(feature = "component-model-async")]
93+
task_poll(vmctx: vmctx, caller_instance: u32, async_: u8, memory: ptr_u8, payload: u32) -> u64;
94+
#[cfg(feature = "component-model-async")]
95+
task_yield(vmctx: vmctx, async_: u8) -> bool;
96+
#[cfg(feature = "component-model-async")]
97+
subtask_drop(vmctx: vmctx, caller_instance: u32, task_id: u32) -> bool;
98+
#[cfg(feature = "component-model-async")]
8999
async_enter(vmctx: vmctx, start: ptr_u8, return_: ptr_u8, caller_instance: u32, task_return_type: u32, params: u32, results: u32) -> bool;
90100
#[cfg(feature = "component-model-async")]
91101
async_exit(vmctx: vmctx, callback: ptr_u8, post_return: ptr_u8, caller_instance: u32, callee: ptr_u8, callee_instance: u32, param_count: u32, result_count: u32, flags: u32) -> u64;

crates/wasmtime/src/runtime/component/concurrent.rs

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
use {
2-
crate::{store::StoreInner, vm::VMFuncRef, AsContextMut, ValRaw},
2+
crate::{
3+
store::StoreInner,
4+
vm::{VMFuncRef, VMMemoryDefinition},
5+
AsContextMut, ValRaw,
6+
},
37
anyhow::Result,
48
futures::{stream::FuturesUnordered, FutureExt},
59
std::{boxed::Box, future::Future, pin::Pin},
@@ -77,6 +81,13 @@ impl<T: 'static> PromisesUnordered<T> {
7781
/// Trait representing component model ABI async intrinsics and fused adapter
7882
/// helper functions.
7983
pub unsafe trait VMComponentAsyncStore {
84+
/// The `task.backpressure` intrinsic.
85+
fn task_backpressure(
86+
&mut self,
87+
caller_instance: RuntimeComponentInstanceIndex,
88+
enabled: u32,
89+
) -> Result<()>;
90+
8091
/// The `task.return` intrinsic.
8192
fn task_return(
8293
&mut self,
@@ -85,6 +96,34 @@ pub unsafe trait VMComponentAsyncStore {
8596
storage_len: usize,
8697
) -> Result<()>;
8798

99+
/// The `task.wait` intrinsic.
100+
fn task_wait(
101+
&mut self,
102+
caller_instance: RuntimeComponentInstanceIndex,
103+
async_: bool,
104+
memory: *mut VMMemoryDefinition,
105+
payload: u32,
106+
) -> Result<u32>;
107+
108+
/// The `task.poll` intrinsic.
109+
fn task_poll(
110+
&mut self,
111+
caller_instance: RuntimeComponentInstanceIndex,
112+
async_: bool,
113+
memory: *mut VMMemoryDefinition,
114+
payload: u32,
115+
) -> Result<u32>;
116+
117+
/// The `task.yield` intrinsic.
118+
fn task_yield(&mut self, async_: bool) -> Result<()>;
119+
120+
/// The `subtask.drop` intrinsic.
121+
fn subtask_drop(
122+
&mut self,
123+
caller_instance: RuntimeComponentInstanceIndex,
124+
task_id: u32,
125+
) -> Result<()>;
126+
88127
/// A helper function for fused adapter modules involving calls where one or
89128
/// both of the functions involved are async functions.
90129
fn async_enter(
@@ -113,6 +152,15 @@ pub unsafe trait VMComponentAsyncStore {
113152
}
114153

115154
unsafe impl<T> VMComponentAsyncStore for StoreInner<T> {
155+
fn task_backpressure(
156+
&mut self,
157+
caller_instance: RuntimeComponentInstanceIndex,
158+
enabled: u32,
159+
) -> Result<()> {
160+
_ = (caller_instance, enabled);
161+
todo!()
162+
}
163+
116164
fn task_return(
117165
&mut self,
118166
ty: TypeTupleIndex,
@@ -123,6 +171,42 @@ unsafe impl<T> VMComponentAsyncStore for StoreInner<T> {
123171
todo!()
124172
}
125173

174+
fn task_wait(
175+
&mut self,
176+
caller_instance: RuntimeComponentInstanceIndex,
177+
async_: bool,
178+
memory: *mut VMMemoryDefinition,
179+
payload: u32,
180+
) -> Result<u32> {
181+
_ = (caller_instance, async_, memory, payload);
182+
todo!()
183+
}
184+
185+
fn task_poll(
186+
&mut self,
187+
caller_instance: RuntimeComponentInstanceIndex,
188+
async_: bool,
189+
memory: *mut VMMemoryDefinition,
190+
payload: u32,
191+
) -> Result<u32> {
192+
_ = (caller_instance, async_, memory, payload);
193+
todo!()
194+
}
195+
196+
fn task_yield(&mut self, async_: bool) -> Result<()> {
197+
_ = async_;
198+
todo!()
199+
}
200+
201+
fn subtask_drop(
202+
&mut self,
203+
caller_instance: RuntimeComponentInstanceIndex,
204+
task_id: u32,
205+
) -> Result<()> {
206+
_ = (caller_instance, task_id);
207+
todo!()
208+
}
209+
126210
fn async_enter(
127211
&mut self,
128212
start: *mut VMFuncRef,

0 commit comments

Comments
 (0)