Skip to content

Commit 812dd1e

Browse files
authored
add component-model-async/{fused|futures|streams}.wast tests (#10106)
* add component-model-async/{fused|futures|streams}.wast tests This is another piece of #9582 which I'm splitting out to make review easier. The fused.wast test exercises fused adapter generation for various flavors of intercomponent async->async, async->sync, and sync->async calls. The futures.wast and streams.wast tests exercise the various intrinsics (e.g. `stream.read`, `future.close_writable`, etc.) involving `future`s and `stream`s. The remaining changes fill in some TODOs to make the tests pass, plus plumbing for a few intrinsics which aren't needed for these tests but which set the foundation for future tests. Signed-off-by: Joel Dice <[email protected]> * address review feedback Signed-off-by: Joel Dice <[email protected]> --------- Signed-off-by: Joel Dice <[email protected]>
1 parent 6d028ab commit 812dd1e

File tree

23 files changed

+3800
-343
lines changed

23 files changed

+3800
-343
lines changed

crates/cranelift/src/compiler/component.rs

+699-145
Large diffs are not rendered by default.

crates/environ/src/component.rs

+61
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,69 @@ 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;
88+
#[cfg(feature = "component-model-async")]
89+
task_return(vmctx: vmctx, ty: u32, storage: ptr_u8, storage_len: size) -> bool;
90+
#[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")]
99+
sync_enter(vmctx: vmctx, start: ptr_u8, return_: ptr_u8, caller_instance: u32, task_return_type: u32, result_count: u32, storage: ptr_u8, storage_len: size) -> bool;
100+
#[cfg(feature = "component-model-async")]
101+
sync_exit(vmctx: vmctx, callback: ptr_u8, caller_instance: u32, callee: ptr_u8, callee_instance: u32, param_count: u32, storage: ptr_u8, storage_len: size) -> bool;
102+
#[cfg(feature = "component-model-async")]
103+
async_enter(vmctx: vmctx, start: ptr_u8, return_: ptr_u8, caller_instance: u32, task_return_type: u32, params: u32, results: u32) -> bool;
104+
#[cfg(feature = "component-model-async")]
105+
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;
106+
#[cfg(feature = "component-model-async")]
107+
future_new(vmctx: vmctx, ty: u32) -> u64;
108+
#[cfg(feature = "component-model-async")]
109+
future_write(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, future: u32, address: u32) -> u64;
110+
#[cfg(feature = "component-model-async")]
111+
future_read(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, err_ctx_ty: u32, future: u32, address: u32) -> u64;
112+
#[cfg(feature = "component-model-async")]
113+
future_cancel_write(vmctx: vmctx, ty: u32, async_: u8, writer: u32) -> u64;
114+
#[cfg(feature = "component-model-async")]
115+
future_cancel_read(vmctx: vmctx, ty: u32, async_: u8, reader: u32) -> u64;
116+
#[cfg(feature = "component-model-async")]
117+
future_close_writable(vmctx: vmctx, ty: u32, err_ctx_ty: u32, writer: u32, error: u32) -> bool;
118+
#[cfg(feature = "component-model-async")]
119+
future_close_readable(vmctx: vmctx, ty: u32, reader: u32) -> bool;
120+
#[cfg(feature = "component-model-async")]
121+
stream_new(vmctx: vmctx, ty: u32) -> u64;
122+
#[cfg(feature = "component-model-async")]
123+
stream_write(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, stream: u32, address: u32, count: u32) -> u64;
124+
#[cfg(feature = "component-model-async")]
125+
stream_read(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, err_ctx_ty: u32, stream: u32, address: u32, count: u32) -> u64;
126+
#[cfg(feature = "component-model-async")]
127+
stream_cancel_write(vmctx: vmctx, ty: u32, async_: u8, writer: u32) -> u64;
128+
#[cfg(feature = "component-model-async")]
129+
stream_cancel_read(vmctx: vmctx, ty: u32, async_: u8, reader: u32) -> u64;
130+
#[cfg(feature = "component-model-async")]
131+
stream_close_writable(vmctx: vmctx, ty: u32, err_ctx_ty: u32, writer: u32, error: u32) -> bool;
132+
#[cfg(feature = "component-model-async")]
133+
stream_close_readable(vmctx: vmctx, ty: u32, reader: u32) -> bool;
134+
#[cfg(feature = "component-model-async")]
135+
flat_stream_write(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, ty: u32, payload_size: u32, payload_align: u32, stream: u32, address: u32, count: u32) -> u64;
136+
#[cfg(feature = "component-model-async")]
137+
flat_stream_read(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, ty: u32, err_ctx_ty: u32, payload_size: u32, payload_align: u32, stream: u32, address: u32, count: u32) -> u64;
138+
#[cfg(feature = "component-model-async")]
139+
error_context_new(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, debug_msg_address: u32, debug_msg_len: u32) -> u64;
140+
#[cfg(feature = "component-model-async")]
141+
error_context_debug_message(vmctx: vmctx, memory: ptr_u8, realloc: ptr_u8, string_encoding: u8, ty: u32, err_ctx_handle: u32, debug_msg_address: u32) -> bool;
142+
#[cfg(feature = "component-model-async")]
143+
error_context_drop(vmctx: vmctx, ty: u32, err_ctx_handle: u32) -> bool;
144+
#[cfg(feature = "component-model-async")]
86145
future_transfer(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64;
146+
#[cfg(feature = "component-model-async")]
87147
stream_transfer(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64;
148+
#[cfg(feature = "component-model-async")]
88149
error_context_transfer(vmctx: vmctx, src_idx: u32, src_table: u32, dst_table: u32) -> u64;
89150

90151
trap(vmctx: vmctx, code: u8);

crates/environ/src/component/dfg.rs

+40-8
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,9 @@ pub enum Trampoline {
286286
TaskBackpressure {
287287
instance: RuntimeComponentInstanceIndex,
288288
},
289-
TaskReturn,
289+
TaskReturn {
290+
results: TypeTupleIndex,
291+
},
290292
TaskWait {
291293
instance: RuntimeComponentInstanceIndex,
292294
async_: bool,
@@ -308,6 +310,7 @@ pub enum Trampoline {
308310
},
309311
StreamRead {
310312
ty: TypeStreamTableIndex,
313+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
311314
options: CanonicalOptions,
312315
},
313316
StreamWrite {
@@ -327,12 +330,14 @@ pub enum Trampoline {
327330
},
328331
StreamCloseWritable {
329332
ty: TypeStreamTableIndex,
333+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
330334
},
331335
FutureNew {
332336
ty: TypeFutureTableIndex,
333337
},
334338
FutureRead {
335339
ty: TypeFutureTableIndex,
340+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
336341
options: CanonicalOptions,
337342
},
338343
FutureWrite {
@@ -352,6 +357,7 @@ pub enum Trampoline {
352357
},
353358
FutureCloseWritable {
354359
ty: TypeFutureTableIndex,
360+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
355361
},
356362
ErrorContextNew {
357363
ty: TypeComponentLocalErrorContextTableIndex,
@@ -368,6 +374,10 @@ pub enum Trampoline {
368374
ResourceTransferBorrow,
369375
ResourceEnterCall,
370376
ResourceExitCall,
377+
SyncEnterCall,
378+
SyncExitCall {
379+
callback: Option<CallbackId>,
380+
},
371381
AsyncEnterCall,
372382
AsyncExitCall {
373383
callback: Option<CallbackId>,
@@ -765,7 +775,9 @@ impl LinearizeDfg<'_> {
765775
Trampoline::TaskBackpressure { instance } => info::Trampoline::TaskBackpressure {
766776
instance: *instance,
767777
},
768-
Trampoline::TaskReturn => info::Trampoline::TaskReturn,
778+
Trampoline::TaskReturn { results } => {
779+
info::Trampoline::TaskReturn { results: *results }
780+
}
769781
Trampoline::TaskWait {
770782
instance,
771783
async_,
@@ -789,8 +801,13 @@ impl LinearizeDfg<'_> {
789801
instance: *instance,
790802
},
791803
Trampoline::StreamNew { ty } => info::Trampoline::StreamNew { ty: *ty },
792-
Trampoline::StreamRead { ty, options } => info::Trampoline::StreamRead {
804+
Trampoline::StreamRead {
805+
ty,
806+
err_ctx_ty,
807+
options,
808+
} => info::Trampoline::StreamRead {
793809
ty: *ty,
810+
err_ctx_ty: *err_ctx_ty,
794811
options: self.options(options),
795812
},
796813
Trampoline::StreamWrite { ty, options } => info::Trampoline::StreamWrite {
@@ -808,12 +825,20 @@ impl LinearizeDfg<'_> {
808825
Trampoline::StreamCloseReadable { ty } => {
809826
info::Trampoline::StreamCloseReadable { ty: *ty }
810827
}
811-
Trampoline::StreamCloseWritable { ty } => {
812-
info::Trampoline::StreamCloseWritable { ty: *ty }
828+
Trampoline::StreamCloseWritable { ty, err_ctx_ty } => {
829+
info::Trampoline::StreamCloseWritable {
830+
ty: *ty,
831+
err_ctx_ty: *err_ctx_ty,
832+
}
813833
}
814834
Trampoline::FutureNew { ty } => info::Trampoline::FutureNew { ty: *ty },
815-
Trampoline::FutureRead { ty, options } => info::Trampoline::FutureRead {
835+
Trampoline::FutureRead {
836+
ty,
837+
err_ctx_ty,
838+
options,
839+
} => info::Trampoline::FutureRead {
816840
ty: *ty,
841+
err_ctx_ty: *err_ctx_ty,
817842
options: self.options(options),
818843
},
819844
Trampoline::FutureWrite { ty, options } => info::Trampoline::FutureWrite {
@@ -831,8 +856,11 @@ impl LinearizeDfg<'_> {
831856
Trampoline::FutureCloseReadable { ty } => {
832857
info::Trampoline::FutureCloseReadable { ty: *ty }
833858
}
834-
Trampoline::FutureCloseWritable { ty } => {
835-
info::Trampoline::FutureCloseWritable { ty: *ty }
859+
Trampoline::FutureCloseWritable { ty, err_ctx_ty } => {
860+
info::Trampoline::FutureCloseWritable {
861+
ty: *ty,
862+
err_ctx_ty: *err_ctx_ty,
863+
}
836864
}
837865
Trampoline::ErrorContextNew { ty, options } => info::Trampoline::ErrorContextNew {
838866
ty: *ty,
@@ -849,6 +877,10 @@ impl LinearizeDfg<'_> {
849877
Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
850878
Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
851879
Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
880+
Trampoline::SyncEnterCall => info::Trampoline::SyncEnterCall,
881+
Trampoline::SyncExitCall { callback } => info::Trampoline::SyncExitCall {
882+
callback: callback.map(|v| self.runtime_callback(v)),
883+
},
852884
Trampoline::AsyncEnterCall => info::Trampoline::AsyncEnterCall,
853885
Trampoline::AsyncExitCall {
854886
callback,

crates/environ/src/component/info.rs

+35-5
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,10 @@ pub enum Trampoline {
689689
/// A `task.return` intrinsic, which returns a result to the caller of a
690690
/// lifted export function. This allows the callee to continue executing
691691
/// after returning a result.
692-
TaskReturn,
692+
TaskReturn {
693+
/// Tuple representing the result types this intrinsic accepts.
694+
results: TypeTupleIndex,
695+
},
693696

694697
/// A `task.wait` intrinsic, which waits for at least one outstanding async
695698
/// task/stream/future to make progress, returning the first such event.
@@ -738,6 +741,10 @@ pub enum Trampoline {
738741
StreamRead {
739742
/// The table index for the specific `stream` type and caller instance.
740743
ty: TypeStreamTableIndex,
744+
745+
/// The table index for the `error-context` type in the caller instance.
746+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
747+
741748
/// Any options (e.g. string encoding) to use when storing values to
742749
/// memory.
743750
options: CanonicalOptions,
@@ -784,6 +791,9 @@ pub enum Trampoline {
784791
StreamCloseWritable {
785792
/// The table index for the specific `stream` type and caller instance.
786793
ty: TypeStreamTableIndex,
794+
795+
/// The table index for the `error-context` type in the caller instance.
796+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
787797
},
788798

789799
/// A `future.new` intrinsic to create a new `future` handle of the
@@ -797,6 +807,10 @@ pub enum Trampoline {
797807
FutureRead {
798808
/// The table index for the specific `future` type and caller instance.
799809
ty: TypeFutureTableIndex,
810+
811+
/// The table index for the `error-context` type in the caller instance.
812+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
813+
800814
/// Any options (e.g. string encoding) to use when storing values to
801815
/// memory.
802816
options: CanonicalOptions,
@@ -843,6 +857,9 @@ pub enum Trampoline {
843857
FutureCloseWritable {
844858
/// The table index for the specific `future` type and caller instance.
845859
ty: TypeFutureTableIndex,
860+
861+
/// The table index for the `error-context` type in the caller instance.
862+
err_ctx_ty: TypeComponentLocalErrorContextTableIndex,
846863
},
847864

848865
/// A `error-context.new` intrinsic to create a new `error-context` with a
@@ -890,12 +907,23 @@ pub enum Trampoline {
890907
/// Same as `ResourceEnterCall` except for when exiting a call.
891908
ResourceExitCall,
892909

893-
/// An intrinsic used by FACT-generated modules to begin a call to an
910+
/// An intrinsic used by FACT-generated modules to begin a call involving a
911+
/// sync-lowered import and async-lifted export.
912+
SyncEnterCall,
913+
914+
/// An intrinsic used by FACT-generated modules to complete a call involving
915+
/// a sync-lowered import and async-lifted export.
916+
SyncExitCall {
917+
/// The callee's callback function, if any.
918+
callback: Option<RuntimeCallbackIndex>,
919+
},
920+
921+
/// An intrinsic used by FACT-generated modules to begin a call involving an
894922
/// async-lowered import function.
895923
AsyncEnterCall,
896924

897-
/// An intrinsic used by FACT-generated modules to complete a call to an
898-
/// async-lowered import function.
925+
/// An intrinsic used by FACT-generated modules to complete a call involving
926+
/// an async-lowered import function.
899927
///
900928
/// Note that `AsyncEnterCall` and `AsyncExitCall` could theoretically be
901929
/// combined into a single `AsyncCall` intrinsic, but we separate them to
@@ -956,7 +984,7 @@ impl Trampoline {
956984
ResourceRep(i) => format!("component-resource-rep[{}]", i.as_u32()),
957985
ResourceDrop(i) => format!("component-resource-drop[{}]", i.as_u32()),
958986
TaskBackpressure { .. } => format!("task-backpressure"),
959-
TaskReturn => format!("task-return"),
987+
TaskReturn { .. } => format!("task-return"),
960988
TaskWait { .. } => format!("task-wait"),
961989
TaskPoll { .. } => format!("task-poll"),
962990
TaskYield { .. } => format!("task-yield"),
@@ -982,6 +1010,8 @@ impl Trampoline {
9821010
ResourceTransferBorrow => format!("component-resource-transfer-borrow"),
9831011
ResourceEnterCall => format!("component-resource-enter-call"),
9841012
ResourceExitCall => format!("component-resource-exit-call"),
1013+
SyncEnterCall => format!("component-sync-enter-call"),
1014+
SyncExitCall { .. } => format!("component-sync-exit-call"),
9851015
AsyncEnterCall => format!("component-async-enter-call"),
9861016
AsyncExitCall { .. } => format!("component-async-exit-call"),
9871017
FutureTransfer => format!("future-transfer"),

crates/environ/src/component/translate.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use std::collections::HashMap;
1313
use std::mem;
1414
use wasmparser::component_types::{
1515
AliasableResourceId, ComponentCoreModuleTypeId, ComponentDefinedTypeId, ComponentEntityType,
16-
ComponentFuncTypeId, ComponentInstanceTypeId,
16+
ComponentFuncTypeId, ComponentInstanceTypeId, ComponentValType,
1717
};
1818
use wasmparser::types::Types;
1919
use wasmparser::{Chunk, ComponentImportName, Encoding, Parser, Payload, Validator};
@@ -193,6 +193,7 @@ enum LocalInitializer<'data> {
193193
},
194194
TaskReturn {
195195
func: ModuleInternedTypeIndex,
196+
result: Option<ComponentValType>,
196197
},
197198
TaskWait {
198199
func: ModuleInternedTypeIndex,
@@ -632,10 +633,18 @@ impl<'a, 'data> Translator<'a, 'data> {
632633
core_func_index += 1;
633634
LocalInitializer::TaskBackpressure { func: core_type }
634635
}
635-
wasmparser::CanonicalFunction::TaskReturn { .. } => {
636-
let core_type = self.core_func_signature(core_func_index)?;
636+
wasmparser::CanonicalFunction::TaskReturn { result } => {
637+
let result = result.map(|ty| match ty {
638+
wasmparser::ComponentValType::Primitive(ty) => {
639+
ComponentValType::Primitive(ty)
640+
}
641+
wasmparser::ComponentValType::Type(ty) => {
642+
ComponentValType::Type(types.component_defined_type_at(ty))
643+
}
644+
});
645+
let func = self.core_func_signature(core_func_index)?;
637646
core_func_index += 1;
638-
LocalInitializer::TaskReturn { func: core_type }
647+
LocalInitializer::TaskReturn { func, result }
639648
}
640649
wasmparser::CanonicalFunction::TaskWait { async_, memory } => {
641650
let func = self.core_func_signature(core_func_index)?;

crates/environ/src/component/translate/adapt.rs

+6
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,12 @@ fn fact_import_to_core_def(
304304
}
305305
fact::Import::ResourceEnterCall => simple_intrinsic(dfg::Trampoline::ResourceEnterCall),
306306
fact::Import::ResourceExitCall => simple_intrinsic(dfg::Trampoline::ResourceExitCall),
307+
fact::Import::SyncEnterCall => simple_intrinsic(dfg::Trampoline::SyncEnterCall),
308+
fact::Import::SyncExitCall { callback } => {
309+
simple_intrinsic(dfg::Trampoline::SyncExitCall {
310+
callback: callback.clone().map(|v| dfg.callbacks.push(v)),
311+
})
312+
}
307313
fact::Import::AsyncEnterCall => simple_intrinsic(dfg::Trampoline::AsyncEnterCall),
308314
fact::Import::AsyncExitCall {
309315
callback,

0 commit comments

Comments
 (0)