Skip to content

Commit d34b1ac

Browse files
committed
Sketch out async task cancellation
This commit is a sketch for what async task cancellation's implementation might look like in the Rust guest bindings generator.
1 parent 5708666 commit d34b1ac

8 files changed

Lines changed: 355 additions & 144 deletions

File tree

crates/core/src/abi.rs

Lines changed: 95 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,10 @@ def_instruction! {
551551
blocks: usize,
552552
} : [1] => [0],
553553

554+
/// Deallocates the language-specific handle representation on the top
555+
/// of the stack. Used for async imports.
556+
DropHandle { ty: &'a Type } : [1] => [0],
557+
554558
/// Generate code to run after `CallInterface` for an async-lifted export.
555559
///
556560
/// For example, this might include task management for the
@@ -783,33 +787,37 @@ pub fn post_return(resolve: &Resolve, func: &Function, bindgen: &mut impl Bindge
783787
/// a list or a string primarily.
784788
pub fn guest_export_needs_post_return(resolve: &Resolve, func: &Function) -> bool {
785789
func.result
786-
.map(|t| needs_post_return(resolve, &t))
790+
.map(|t| needs_deallocate(resolve, &t, Deallocate::Lists))
787791
.unwrap_or(false)
788792
}
789793

790-
fn needs_post_return(resolve: &Resolve, ty: &Type) -> bool {
794+
fn needs_deallocate(resolve: &Resolve, ty: &Type, what: Deallocate) -> bool {
791795
match ty {
792796
Type::String => true,
793797
Type::ErrorContext => true,
794798
Type::Id(id) => match &resolve.types[*id].kind {
795799
TypeDefKind::List(_) => true,
796-
TypeDefKind::Type(t) => needs_post_return(resolve, t),
797-
TypeDefKind::Handle(_) => false,
800+
TypeDefKind::Type(t) => needs_deallocate(resolve, t, what),
801+
TypeDefKind::Handle(Handle::Own(_)) => what.handles(),
802+
TypeDefKind::Handle(Handle::Borrow(_)) => false,
798803
TypeDefKind::Resource => false,
799-
TypeDefKind::Record(r) => r.fields.iter().any(|f| needs_post_return(resolve, &f.ty)),
800-
TypeDefKind::Tuple(t) => t.types.iter().any(|t| needs_post_return(resolve, t)),
804+
TypeDefKind::Record(r) => r
805+
.fields
806+
.iter()
807+
.any(|f| needs_deallocate(resolve, &f.ty, what)),
808+
TypeDefKind::Tuple(t) => t.types.iter().any(|t| needs_deallocate(resolve, t, what)),
801809
TypeDefKind::Variant(t) => t
802810
.cases
803811
.iter()
804812
.filter_map(|t| t.ty.as_ref())
805-
.any(|t| needs_post_return(resolve, t)),
806-
TypeDefKind::Option(t) => needs_post_return(resolve, t),
813+
.any(|t| needs_deallocate(resolve, t, what)),
814+
TypeDefKind::Option(t) => needs_deallocate(resolve, t, what),
807815
TypeDefKind::Result(t) => [&t.ok, &t.err]
808816
.iter()
809817
.filter_map(|t| t.as_ref())
810-
.any(|t| needs_post_return(resolve, t)),
818+
.any(|t| needs_deallocate(resolve, t, what)),
811819
TypeDefKind::Flags(_) | TypeDefKind::Enum(_) => false,
812-
TypeDefKind::Future(_) | TypeDefKind::Stream(_) => false,
820+
TypeDefKind::Future(_) | TypeDefKind::Stream(_) => what.handles(),
813821
TypeDefKind::Unknown => unreachable!(),
814822
},
815823

@@ -836,7 +844,18 @@ pub fn deallocate_lists_in_types<B: Bindgen>(
836844
ptr: B::Operand,
837845
bindgen: &mut B,
838846
) {
839-
Generator::new(resolve, bindgen).deallocate_lists_in_types(types, ptr);
847+
Generator::new(resolve, bindgen).deallocate_in_types(types, ptr, Deallocate::Lists);
848+
}
849+
850+
/// Generate instructions in `bindgen` to deallocate all lists in `ptr` where
851+
/// that's a pointer to a sequence of `types` stored in linear memory.
852+
pub fn deallocate_lists_and_own_in_types<B: Bindgen>(
853+
resolve: &Resolve,
854+
types: &[Type],
855+
ptr: B::Operand,
856+
bindgen: &mut B,
857+
) {
858+
Generator::new(resolve, bindgen).deallocate_in_types(types, ptr, Deallocate::ListsAndOwn);
840859
}
841860

842861
#[derive(Copy, Clone)]
@@ -845,6 +864,25 @@ pub enum Realloc {
845864
Export(&'static str),
846865
}
847866

867+
/// What to deallocate in various `deallocate_*` methods.
868+
#[derive(Copy, Clone)]
869+
enum Deallocate {
870+
/// Only deallocate lists.
871+
Lists,
872+
/// Deallocate lists and owned resources such as `own<T>` and
873+
/// futures/streams.
874+
ListsAndOwn,
875+
}
876+
877+
impl Deallocate {
878+
fn handles(&self) -> bool {
879+
match self {
880+
Deallocate::Lists => false,
881+
Deallocate::ListsAndOwn => true,
882+
}
883+
}
884+
}
885+
848886
struct Generator<'a, B: Bindgen> {
849887
bindgen: &'a mut B,
850888
resolve: &'a Resolve,
@@ -1169,14 +1207,14 @@ impl<'a, B: Bindgen> Generator<'a, B> {
11691207

11701208
let mut types = Vec::new();
11711209
types.extend(func.result);
1172-
self.deallocate_lists_in_types(&types, addr);
1210+
self.deallocate_in_types(&types, addr, Deallocate::Lists);
11731211

11741212
self.emit(&Instruction::Return { func, amt: 0 });
11751213
}
11761214

1177-
fn deallocate_lists_in_types(&mut self, types: &[Type], addr: B::Operand) {
1215+
fn deallocate_in_types(&mut self, types: &[Type], addr: B::Operand, what: Deallocate) {
11781216
for (offset, ty) in self.bindgen.sizes().field_offsets(types) {
1179-
self.deallocate(ty, addr.clone(), offset);
1217+
self.deallocate(ty, addr.clone(), offset, what);
11801218
}
11811219

11821220
assert!(
@@ -1976,12 +2014,18 @@ impl<'a, B: Bindgen> Generator<'a, B> {
19762014
});
19772015
}
19782016

1979-
fn deallocate(&mut self, ty: &Type, addr: B::Operand, offset: ArchitectureSize) {
2017+
fn deallocate(
2018+
&mut self,
2019+
ty: &Type,
2020+
addr: B::Operand,
2021+
offset: ArchitectureSize,
2022+
what: Deallocate,
2023+
) {
19802024
use Instruction::*;
19812025

19822026
// No need to execute any instructions if this type itself doesn't
19832027
// require any form of post-return.
1984-
if !needs_post_return(self.resolve, ty) {
2028+
if !needs_deallocate(self.resolve, ty, what) {
19852029
return;
19862030
}
19872031

@@ -2011,7 +2055,7 @@ impl<'a, B: Bindgen> Generator<'a, B> {
20112055
| Type::ErrorContext => {}
20122056

20132057
Type::Id(id) => match &self.resolve.types[id].kind {
2014-
TypeDefKind::Type(t) => self.deallocate(t, addr, offset),
2058+
TypeDefKind::Type(t) => self.deallocate(t, addr, offset, what),
20152059

20162060
TypeDefKind::List(element) => {
20172061
self.stack.push(addr.clone());
@@ -2024,30 +2068,36 @@ impl<'a, B: Bindgen> Generator<'a, B> {
20242068
self.push_block();
20252069
self.emit(&IterBasePointer);
20262070
let elemaddr = self.stack.pop().unwrap();
2027-
self.deallocate(element, elemaddr, Default::default());
2071+
self.deallocate(element, elemaddr, Default::default(), what);
20282072
self.finish_block(0);
20292073

20302074
self.emit(&Instruction::GuestDeallocateList { element });
20312075
}
20322076

2033-
TypeDefKind::Handle(_) => {
2034-
todo!()
2077+
TypeDefKind::Handle(Handle::Own(_))
2078+
| TypeDefKind::Future(_)
2079+
| TypeDefKind::Stream(_)
2080+
if what.handles() =>
2081+
{
2082+
self.read_from_memory(ty, addr, offset);
2083+
self.emit(&DropHandle { ty });
20352084
}
20362085

2037-
TypeDefKind::Resource => {
2038-
todo!()
2039-
}
2086+
TypeDefKind::Handle(Handle::Own(_)) => unreachable!(),
2087+
TypeDefKind::Handle(Handle::Borrow(_)) => unreachable!(),
2088+
TypeDefKind::Resource => unreachable!(),
20402089

20412090
TypeDefKind::Record(record) => {
20422091
self.deallocate_fields(
20432092
&record.fields.iter().map(|f| f.ty).collect::<Vec<_>>(),
20442093
addr,
20452094
offset,
2095+
what,
20462096
);
20472097
}
20482098

20492099
TypeDefKind::Tuple(tuple) => {
2050-
self.deallocate_fields(&tuple.types, addr, offset);
2100+
self.deallocate_fields(&tuple.types, addr, offset, what);
20512101
}
20522102

20532103
TypeDefKind::Flags(_) => {}
@@ -2058,26 +2108,33 @@ impl<'a, B: Bindgen> Generator<'a, B> {
20582108
addr,
20592109
variant.tag(),
20602110
variant.cases.iter().map(|c| c.ty.as_ref()),
2111+
what,
20612112
);
20622113
self.emit(&GuestDeallocateVariant {
20632114
blocks: variant.cases.len(),
20642115
});
20652116
}
20662117

20672118
TypeDefKind::Option(t) => {
2068-
self.deallocate_variant(offset, addr, Int::U8, [None, Some(t)]);
2119+
self.deallocate_variant(offset, addr, Int::U8, [None, Some(t)], what);
20692120
self.emit(&GuestDeallocateVariant { blocks: 2 });
20702121
}
20712122

20722123
TypeDefKind::Result(e) => {
2073-
self.deallocate_variant(offset, addr, Int::U8, [e.ok.as_ref(), e.err.as_ref()]);
2124+
self.deallocate_variant(
2125+
offset,
2126+
addr,
2127+
Int::U8,
2128+
[e.ok.as_ref(), e.err.as_ref()],
2129+
what,
2130+
);
20742131
self.emit(&GuestDeallocateVariant { blocks: 2 });
20752132
}
20762133

20772134
TypeDefKind::Enum(_) => {}
20782135

2079-
TypeDefKind::Future(_) => todo!("read future from memory"),
2080-
TypeDefKind::Stream(_) => todo!("read stream from memory"),
2136+
TypeDefKind::Future(_) => unreachable!(),
2137+
TypeDefKind::Stream(_) => unreachable!(),
20812138
TypeDefKind::Unknown => unreachable!(),
20822139
},
20832140
}
@@ -2089,22 +2146,29 @@ impl<'a, B: Bindgen> Generator<'a, B> {
20892146
addr: B::Operand,
20902147
tag: Int,
20912148
cases: impl IntoIterator<Item = Option<&'b Type>> + Clone,
2149+
what: Deallocate,
20922150
) {
20932151
self.stack.push(addr.clone());
20942152
self.load_intrepr(offset, tag);
20952153
let payload_offset = offset + (self.bindgen.sizes().payload_offset(tag, cases.clone()));
20962154
for ty in cases {
20972155
self.push_block();
20982156
if let Some(ty) = ty {
2099-
self.deallocate(ty, addr.clone(), payload_offset);
2157+
self.deallocate(ty, addr.clone(), payload_offset, what);
21002158
}
21012159
self.finish_block(0);
21022160
}
21032161
}
21042162

2105-
fn deallocate_fields(&mut self, tys: &[Type], addr: B::Operand, offset: ArchitectureSize) {
2163+
fn deallocate_fields(
2164+
&mut self,
2165+
tys: &[Type],
2166+
addr: B::Operand,
2167+
offset: ArchitectureSize,
2168+
what: Deallocate,
2169+
) {
21062170
for (field_offset, ty) in self.bindgen.sizes().field_offsets(tys) {
2107-
self.deallocate(ty, addr.clone(), offset + (field_offset));
2171+
self.deallocate(ty, addr.clone(), offset + (field_offset), what);
21082172
}
21092173
}
21102174
}

crates/csharp/src/function.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1263,7 +1263,9 @@ impl Bindgen for FunctionBindgen<'_, '_> {
12631263
| Instruction::StreamLower { .. }
12641264
| Instruction::StreamLift { .. }
12651265
| Instruction::ErrorContextLower { .. }
1266-
| Instruction::ErrorContextLift { .. } => todo!(),
1266+
| Instruction::ErrorContextLift { .. }
1267+
| Instruction::DropHandle { .. }
1268+
=> todo!(),
12671269
}
12681270
}
12691271

0 commit comments

Comments
 (0)