Skip to content

Commit 89f6d36

Browse files
c: Use drop-flags when auto-dropping borrows (#809)
* Use drop-flags when auto-dropping borrows * Fix codegen errors in the Rust generator --------- Co-authored-by: Alex Crichton <[email protected]>
1 parent 9af4d20 commit 89f6d36

File tree

4 files changed

+73
-14
lines changed

4 files changed

+73
-14
lines changed

crates/c/src/lib.rs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1967,6 +1967,11 @@ impl InterfaceGenerator<'_> {
19671967
}
19681968
}
19691969

1970+
struct DroppableBorrow {
1971+
name: String,
1972+
ty: TypeId,
1973+
}
1974+
19701975
struct FunctionBindgen<'a, 'b> {
19711976
gen: &'a mut InterfaceGenerator<'b>,
19721977
locals: Ns,
@@ -1984,7 +1989,10 @@ struct FunctionBindgen<'a, 'b> {
19841989

19851990
/// Borrows observed during lifting an export, that will need to be dropped when the guest
19861991
/// function exits.
1987-
borrows: Vec<(String, TypeId)>,
1992+
borrows: Vec<DroppableBorrow>,
1993+
1994+
/// Forward declarations for temporary storage of borrow copies.
1995+
borrow_decls: wit_bindgen_core::Source,
19881996
}
19891997

19901998
impl<'a, 'b> FunctionBindgen<'a, 'b> {
@@ -2007,6 +2015,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
20072015
ret_store_cnt: 0,
20082016
import_return_pointer_area_size: 0,
20092017
import_return_pointer_area_align: 0,
2018+
borrow_decls: Default::default(),
20102019
borrows: Vec::new(),
20112020
}
20122021
}
@@ -2264,8 +2273,13 @@ impl Bindgen for FunctionBindgen<'_, '_> {
22642273
if !self.gen.in_import && self.gen.autodrop_enabled() {
22652274
// Here we've received a borrow of an imported resource, which is the
22662275
// kind we'll need to drop when the exported function is returning.
2267-
let target = dealias(self.gen.resolve, *id);
2268-
self.borrows.push((op.clone(), target));
2276+
let ty = dealias(self.gen.resolve, *id);
2277+
2278+
let name = self.locals.tmp("borrow");
2279+
uwriteln!(self.borrow_decls, "int32_t {name} = 0;");
2280+
uwriteln!(self.src, "{name} = {op};");
2281+
2282+
self.borrows.push(DroppableBorrow { name, ty });
22692283
}
22702284
}
22712285
}
@@ -2372,10 +2386,6 @@ impl Bindgen for FunctionBindgen<'_, '_> {
23722386
for (i, (case, (block, block_results))) in
23732387
variant.cases.iter().zip(blocks).enumerate()
23742388
{
2375-
if let Some(ty) = case.ty.as_ref() {
2376-
self.assert_no_droppable_borrows("variant", ty);
2377-
}
2378-
23792389
uwriteln!(self.src, "case {}: {{", i);
23802390
self.src.push_str(&block);
23812391
assert!(block_results.len() == (case.ty.is_some() as usize));
@@ -2431,8 +2441,6 @@ impl Bindgen for FunctionBindgen<'_, '_> {
24312441
}
24322442

24332443
Instruction::OptionLift { ty, .. } => {
2434-
self.assert_no_droppable_borrows("option", &Type::Id(*ty));
2435-
24362444
let (mut some, some_results) = self.blocks.pop().unwrap();
24372445
let (mut none, none_results) = self.blocks.pop().unwrap();
24382446
assert!(none_results.len() == 0);
@@ -2520,8 +2528,6 @@ impl Bindgen for FunctionBindgen<'_, '_> {
25202528
}
25212529

25222530
Instruction::ResultLift { result, ty, .. } => {
2523-
self.assert_no_droppable_borrows("result", &Type::Id(*ty));
2524-
25252531
let (mut err, err_results) = self.blocks.pop().unwrap();
25262532
assert!(err_results.len() == (result.err.is_some() as usize));
25272533
let (mut ok, ok_results) = self.blocks.pop().unwrap();
@@ -2837,8 +2843,15 @@ impl Bindgen for FunctionBindgen<'_, '_> {
28372843
}
28382844
},
28392845
Instruction::Return { amt, .. } => {
2840-
for (op, ty) in self.borrows.iter() {
2841-
uwriteln!(self.src, "{}({op});", self.gen.gen.resources[ty].drop_fn);
2846+
// Emit all temporary borrow decls
2847+
let src = std::mem::replace(&mut self.src, std::mem::take(&mut self.borrow_decls));
2848+
self.src.append_src(&src);
2849+
2850+
for DroppableBorrow { name, ty } in self.borrows.iter() {
2851+
let drop_fn = self.gen.gen.resources[ty].drop_fn.as_str();
2852+
uwriteln!(self.src, "if ({name} != 0) {{");
2853+
uwriteln!(self.src, " {drop_fn}({name});");
2854+
uwriteln!(self.src, "}}");
28422855
}
28432856

28442857
assert!(*amt <= 1);

crates/rust/src/bindgen.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ pub(super) struct FunctionBindgen<'a, 'b> {
1616
cleanup: Vec<(String, String)>,
1717
pub import_return_pointer_area_size: usize,
1818
pub import_return_pointer_area_align: usize,
19+
pub handle_decls: Vec<String>,
1920
}
2021

2122
impl<'a, 'b> FunctionBindgen<'a, 'b> {
@@ -34,6 +35,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
3435
cleanup: Vec::new(),
3536
import_return_pointer_area_size: 0,
3637
import_return_pointer_area_align: 0,
38+
handle_decls: Vec::new(),
3739
}
3840
}
3941

@@ -451,9 +453,19 @@ impl Bindgen for FunctionBindgen<'_, '_> {
451453
format!("{name}::from_handle({op} as u32)")
452454
}
453455
}
456+
} else if prefix == "" {
457+
let name = self.gen.type_path(resource, true);
458+
format!("{name}::from_handle({op} as u32)")
454459
} else {
460+
let tmp = format!("handle{}", self.tmp());
461+
self.handle_decls.push(format!("let {tmp};"));
455462
let name = self.gen.type_path(resource, true);
456-
format!("{prefix}{name}::from_handle({op} as u32)")
463+
format!(
464+
"{{\n
465+
{tmp} = {name}::from_handle({op} as u32);
466+
{prefix}{tmp}
467+
}}"
468+
)
457469
},
458470
);
459471
}

crates/rust/src/interface.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,12 +284,14 @@ impl InterfaceGenerator<'_> {
284284
src,
285285
import_return_pointer_area_size,
286286
import_return_pointer_area_align,
287+
handle_decls,
287288
..
288289
} = f;
289290

290291
if needs_cleanup_list {
291292
self.src.push_str("let mut cleanup_list = Vec::new();\n");
292293
}
294+
assert!(handle_decls.is_empty());
293295
if import_return_pointer_area_size > 0 {
294296
uwrite!(
295297
self.src,
@@ -389,9 +391,14 @@ impl InterfaceGenerator<'_> {
389391
let FunctionBindgen {
390392
needs_cleanup_list,
391393
src,
394+
handle_decls,
392395
..
393396
} = f;
394397
assert!(!needs_cleanup_list);
398+
for decl in handle_decls {
399+
self.src.push_str(&decl);
400+
self.src.push_str("\n");
401+
}
395402
self.src.push_str(&String::from(src));
396403
self.src.push_str("}\n");
397404

@@ -420,9 +427,11 @@ impl InterfaceGenerator<'_> {
420427
let FunctionBindgen {
421428
needs_cleanup_list,
422429
src,
430+
handle_decls,
423431
..
424432
} = f;
425433
assert!(!needs_cleanup_list);
434+
assert!(handle_decls.is_empty());
426435
self.src.push_str(&String::from(src));
427436
self.src.push_str("}\n");
428437
self.src.push_str("};\n");

tests/codegen/resources.wit

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,31 @@ world resources {
1111

1212
export add: func(a: borrow<z>, b: borrow<z>) -> own<z>;
1313

14+
export maybe-with-z: func(a: option<borrow<z>>);
15+
16+
variant includes-borrow {
17+
a,
18+
b(borrow<z>),
19+
}
20+
21+
export variant-with-z: func(a: includes-borrow);
22+
export maybe-variant-with-z: func(a: option<includes-borrow>);
23+
24+
record big {
25+
x1: borrow<z>,
26+
x2: borrow<z>,
27+
x3: borrow<z>,
28+
x4: borrow<z>,
29+
x5: borrow<z>,
30+
x6: borrow<z>,
31+
x7: borrow<z>,
32+
x8: borrow<z>,
33+
x9: borrow<z>,
34+
x10: borrow<z>,
35+
}
36+
37+
export big-record: func(r: big);
38+
1439
export exports: interface {
1540
resource x {
1641
constructor(a: float64);

0 commit comments

Comments
 (0)