Skip to content

Commit 66f0bbf

Browse files
committed
support callback-less (AKA stackful) async lifts
Signed-off-by: Joel Dice <[email protected]>
1 parent 81c83e5 commit 66f0bbf

File tree

5 files changed

+106
-43
lines changed

5 files changed

+106
-43
lines changed

crates/wasmparser/src/validator/component.rs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::{
44
check_max,
55
component_types::{
6-
AliasableResourceId, ComponentAnyTypeId, ComponentCoreInstanceTypeId,
6+
Abi, AliasableResourceId, ComponentAnyTypeId, ComponentCoreInstanceTypeId,
77
ComponentCoreModuleTypeId, ComponentCoreTypeId, ComponentDefinedType,
88
ComponentDefinedTypeId, ComponentEntityType, ComponentFuncType, ComponentFuncTypeId,
99
ComponentInstanceType, ComponentInstanceTypeId, ComponentType, ComponentTypeId,
@@ -963,7 +963,21 @@ impl ComponentState {
963963

964964
// Lifting a function is for an export, so match the expected canonical ABI
965965
// export signature
966-
let info = ty.lower(types, false, options.contains(&CanonicalOption::Async));
966+
let info = ty.lower(
967+
types,
968+
if options.contains(&CanonicalOption::Async) {
969+
if options
970+
.iter()
971+
.any(|v| matches!(v, CanonicalOption::Callback(_)))
972+
{
973+
Abi::LiftAsync
974+
} else {
975+
Abi::LiftAsyncStackful
976+
}
977+
} else {
978+
Abi::LiftSync
979+
},
980+
);
967981
self.check_options(
968982
Some(core_ty),
969983
&info,
@@ -1012,7 +1026,14 @@ impl ComponentState {
10121026

10131027
// Lowering a function is for an import, so use a function type that matches
10141028
// the expected canonical ABI import signature.
1015-
let info = ty.lower(types, true, options.contains(&CanonicalOption::Async));
1029+
let info = ty.lower(
1030+
types,
1031+
if options.contains(&CanonicalOption::Async) {
1032+
Abi::LowerAsync
1033+
} else {
1034+
Abi::LowerSync
1035+
},
1036+
);
10161037

10171038
self.check_options(None, &info, &options, types, offset, features, true)?;
10181039

crates/wasmparser/src/validator/component_types.rs

Lines changed: 49 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -891,21 +891,34 @@ impl TypeData for ComponentFuncType {
891891
}
892892
}
893893

894+
#[derive(Copy, Clone, Debug)]
895+
pub(crate) enum Abi {
896+
LowerSync,
897+
LowerAsync,
898+
LiftSync,
899+
LiftAsync,
900+
LiftAsyncStackful,
901+
}
902+
894903
impl ComponentFuncType {
895904
/// Lowers the component function type to core parameter and result types for the
896905
/// canonical ABI.
897-
pub(crate) fn lower(&self, types: &TypeList, is_lower: bool, async_: bool) -> LoweringInfo {
906+
pub(crate) fn lower(&self, types: &TypeList, abi: Abi) -> LoweringInfo {
898907
let mut info = LoweringInfo::default();
899908

900-
if async_ && is_lower {
901-
for _ in 0..2 {
902-
info.params.push(ValType::I32);
909+
let is_lower = match abi {
910+
Abi::LowerAsync => {
911+
for _ in 0..2 {
912+
info.params.push(ValType::I32);
913+
}
914+
info.results.push(ValType::I32);
915+
info.requires_memory = true;
916+
info.requires_realloc = self.results.iter().any(|(_, ty)| ty.contains_ptr(types));
917+
return info;
903918
}
904-
info.results.push(ValType::I32);
905-
info.requires_memory = true;
906-
info.requires_realloc = self.results.iter().any(|(_, ty)| ty.contains_ptr(types));
907-
return info;
908-
}
919+
Abi::LowerSync => true,
920+
Abi::LiftSync | Abi::LiftAsync | Abi::LiftAsyncStackful => false,
921+
};
909922

910923
for (_, ty) in self.params.iter() {
911924
// Check to see if `ty` has a pointer somewhere in it, needed for
@@ -940,32 +953,37 @@ impl ComponentFuncType {
940953
}
941954
}
942955

943-
if async_ {
944-
info.results.push(ValType::I32);
945-
} else {
946-
for (_, ty) in self.results.iter() {
947-
// Results of lowered functions that contains pointers must be
948-
// allocated by the callee meaning that realloc is required.
949-
// Results of lifted function are allocated by the guest which
950-
// means that no realloc option is necessary.
951-
if is_lower && !info.requires_realloc {
952-
info.requires_realloc = ty.contains_ptr(types);
953-
}
956+
match abi {
957+
Abi::LowerAsync => unreachable!(),
958+
Abi::LowerSync | Abi::LiftSync => {
959+
for (_, ty) in self.results.iter() {
960+
// Results of lowered functions that contains pointers must be
961+
// allocated by the callee meaning that realloc is required.
962+
// Results of lifted function are allocated by the guest which
963+
// means that no realloc option is necessary.
964+
if is_lower && !info.requires_realloc {
965+
info.requires_realloc = ty.contains_ptr(types);
966+
}
954967

955-
if !ty.push_wasm_types(types, &mut info.results) {
956-
// Too many results to return directly, either a retptr parameter will be used (import)
957-
// or a single pointer will be returned (export)
958-
info.results.clear();
959-
if is_lower {
960-
info.params.max = MAX_LOWERED_TYPES;
961-
assert!(info.params.push(ValType::I32));
962-
} else {
963-
assert!(info.results.push(ValType::I32));
968+
if !ty.push_wasm_types(types, &mut info.results) {
969+
// Too many results to return directly, either a retptr parameter will be used (import)
970+
// or a single pointer will be returned (export)
971+
info.results.clear();
972+
if is_lower {
973+
info.params.max = MAX_LOWERED_TYPES;
974+
assert!(info.params.push(ValType::I32));
975+
} else {
976+
assert!(info.results.push(ValType::I32));
977+
}
978+
info.requires_memory = true;
979+
break;
964980
}
965-
info.requires_memory = true;
966-
break;
967981
}
968982
}
983+
Abi::LiftAsync => {
984+
info.results.push(ValType::I32);
985+
}
986+
Abi::LiftAsyncStackful => {}
969987
}
970988

971989
// Memory is always required when realloc is required

crates/wit-component/src/encoding.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ impl RequiredOptions {
169169
ret |= RequiredOptions::REALLOC;
170170
}
171171
}
172-
if abi == AbiVariant::GuestExportAsync {
172+
if let AbiVariant::GuestExportAsync | AbiVariant::GuestExportAsyncStackful = abi {
173173
ret |= RequiredOptions::ASYNC;
174174
}
175175
ret

crates/wit-component/src/validation.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,8 @@ impl ExportMap {
816816
let full_name = name;
817817
let (abi, name) = if let Some(name) = names.async_name(name) {
818818
(AbiVariant::GuestExportAsync, name)
819+
} else if let Some(name) = names.async_stackful_name(name) {
820+
(AbiVariant::GuestExportAsyncStackful, name)
819821
} else {
820822
(AbiVariant::GuestExport, name)
821823
};
@@ -1081,6 +1083,7 @@ trait NameMangling {
10811083
fn subtask_drop(&self) -> Option<&str>;
10821084
fn callback_name<'a>(&self, s: &'a str) -> Option<&'a str>;
10831085
fn async_name<'a>(&self, s: &'a str) -> Option<&'a str>;
1086+
fn async_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str>;
10841087
fn error_context_new(&self, s: &str) -> Option<StringEncoding>;
10851088
fn error_context_debug_message<'a>(&self, s: &'a str) -> Option<(StringEncoding, &'a str)>;
10861089
fn error_context_drop(&self) -> Option<&str>;
@@ -1176,6 +1179,10 @@ impl NameMangling for Standard {
11761179
_ = s;
11771180
None
11781181
}
1182+
fn async_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1183+
_ = s;
1184+
None
1185+
}
11791186
fn error_context_new(&self, s: &str) -> Option<StringEncoding> {
11801187
_ = s;
11811188
None
@@ -1357,6 +1364,9 @@ impl NameMangling for Legacy {
13571364
fn async_name<'a>(&self, s: &'a str) -> Option<&'a str> {
13581365
s.strip_prefix("[async]")
13591366
}
1367+
fn async_stackful_name<'a>(&self, s: &'a str) -> Option<&'a str> {
1368+
s.strip_prefix("[async-stackful]")
1369+
}
13601370
fn error_context_new(&self, s: &str) -> Option<StringEncoding> {
13611371
parse_encoding(
13621372
s.strip_prefix("[error-context-new;encoding=")?

crates/wit-parser/src/abi.rs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ pub enum AbiVariant {
129129
GuestExport,
130130
GuestImportAsync,
131131
GuestExportAsync,
132+
GuestExportAsyncStackful,
132133
}
133134

134135
impl Resolve {
@@ -164,7 +165,9 @@ impl Resolve {
164165
(&func.kind, variant),
165166
(
166167
crate::FunctionKind::Method(_),
167-
AbiVariant::GuestExport | AbiVariant::GuestExportAsync
168+
AbiVariant::GuestExport
169+
| AbiVariant::GuestExportAsync
170+
| AbiVariant::GuestExportAsyncStackful
168171
)
169172
) {
170173
// Guest exported methods always receive resource rep as first argument
@@ -178,13 +181,24 @@ impl Resolve {
178181
}
179182
}
180183

181-
if let AbiVariant::GuestExportAsync = variant {
182-
return WasmSignature {
183-
params,
184-
indirect_params,
185-
results: vec![WasmType::Pointer],
186-
retptr: false,
187-
};
184+
match variant {
185+
AbiVariant::GuestExportAsync => {
186+
return WasmSignature {
187+
params,
188+
indirect_params,
189+
results: vec![WasmType::Pointer],
190+
retptr: false,
191+
};
192+
}
193+
AbiVariant::GuestExportAsyncStackful => {
194+
return WasmSignature {
195+
params,
196+
indirect_params,
197+
results: Vec::new(),
198+
retptr: false,
199+
};
200+
}
201+
_ => {}
188202
}
189203

190204
let mut results = Vec::new();

0 commit comments

Comments
 (0)