Skip to content

Commit a1b2228

Browse files
committed
Initial work towards getting post-return functions
This adds a few new pseudo-instructions plus a new method on `Interface` to generate a `post-return` function. For now these are simply named `{name}_post_return` and the integration point there will probably change as the component model shapes up. The integration here is intended to still be relatively primitive in that the actual component model integration will likely look different in the future. Given how `wit-bindgen` works today, though, this should at least get things part of the way there.
1 parent 9ef6717 commit a1b2228

File tree

11 files changed

+619
-407
lines changed

11 files changed

+619
-407
lines changed

crates/gen-guest-c/src/lib.rs

Lines changed: 81 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -423,15 +423,6 @@ impl C {
423423
abort();
424424
return ret;
425425
}
426-
427-
__attribute__((weak, export_name(\"canonical_abi_free\")))
428-
void canonical_abi_free(
429-
void *ptr,
430-
size_t size,
431-
size_t align
432-
) {
433-
free(ptr);
434-
}
435426
");
436427
}
437428

@@ -491,12 +482,9 @@ impl C {
491482
self.free(iface, t, "&ptr->ptr[i]");
492483
self.src.c("}\n");
493484
}
494-
uwriteln!(
495-
self.src.c,
496-
"canonical_abi_free(ptr->ptr, ptr->len * {}, {});",
497-
self.sizes.size(t),
498-
self.sizes.align(t),
499-
);
485+
uwriteln!(self.src.c, "if (ptr->len > 0) {{");
486+
uwriteln!(self.src.c, "free(ptr->ptr);");
487+
uwriteln!(self.src.c, "}}");
500488
}
501489

502490
TypeDefKind::Variant(v) => {
@@ -1105,6 +1093,42 @@ impl Generator for C {
11051093
self.src.c(&src);
11061094
self.src.c("}\n");
11071095

1096+
if iface.guest_export_needs_post_return(func) {
1097+
uwriteln!(
1098+
self.src.c,
1099+
"__attribute__((export_name(\"cabi_post_{}\")))",
1100+
func.name
1101+
);
1102+
uwrite!(self.src.c, "void {import_name}_post_return(");
1103+
1104+
let mut params = Vec::new();
1105+
let mut c_sig = CSig {
1106+
name: String::from("INVALID"),
1107+
sig: String::from("INVALID"),
1108+
params: Vec::new(),
1109+
ret: Return {
1110+
splat_tuple: false,
1111+
scalar: None,
1112+
retptrs: Vec::new(),
1113+
},
1114+
retptrs: Vec::new(),
1115+
};
1116+
for (i, result) in sig.results.iter().enumerate() {
1117+
let name = format!("arg{i}");
1118+
uwrite!(self.src.c, "{} {name}", wasm_type(*result));
1119+
c_sig.params.push((false, name.clone()));
1120+
params.push(name);
1121+
}
1122+
self.src.c.push_str(") {\n");
1123+
1124+
let mut f = FunctionBindgen::new(self, c_sig, &import_name);
1125+
f.params = params;
1126+
iface.post_return(func, &mut f);
1127+
let FunctionBindgen { src, .. } = f;
1128+
self.src.c(&src);
1129+
self.src.c("}\n");
1130+
}
1131+
11081132
let src = mem::replace(&mut self.src, prev);
11091133
self.funcs
11101134
.entry(iface.name.to_string())
@@ -1284,7 +1308,9 @@ impl Generator for C {
12841308
}}
12851309
12861310
void {0}_string_free({0}_string_t *ret) {{
1287-
canonical_abi_free(ret->ptr, ret->len, 1);
1311+
if (ret->len > 0) {{
1312+
free(ret->ptr);
1313+
}}
12881314
ret->ptr = NULL;
12891315
ret->len = 0;
12901316
}}
@@ -2205,9 +2231,47 @@ impl Bindgen for FunctionBindgen<'_> {
22052231
self.load_ext("int16_t", *offset, operands, results)
22062232
}
22072233

2208-
Instruction::Free { .. } => {
2234+
Instruction::GuestDeallocate { .. } => {
22092235
uwriteln!(self.src, "free((void*) ({}));", operands[0]);
22102236
}
2237+
Instruction::GuestDeallocateString => {
2238+
uwriteln!(self.src, "if (({}) > 0) {{", operands[1]);
2239+
uwriteln!(self.src, "free((void*) ({}));", operands[0]);
2240+
uwriteln!(self.src, "}}");
2241+
}
2242+
Instruction::GuestDeallocateVariant { blocks } => {
2243+
let blocks = self
2244+
.blocks
2245+
.drain(self.blocks.len() - blocks..)
2246+
.collect::<Vec<_>>();
2247+
2248+
uwriteln!(self.src, "switch ((int32_t) {}) {{", operands[0]);
2249+
for (i, (block, results)) in blocks.into_iter().enumerate() {
2250+
assert!(results.is_empty());
2251+
uwriteln!(self.src, "case {}: {{", i);
2252+
self.src.push_str(&block);
2253+
self.src.push_str("break;\n}\n");
2254+
}
2255+
self.src.push_str("}\n");
2256+
}
2257+
Instruction::GuestDeallocateList { element } => {
2258+
let (body, results) = self.blocks.pop().unwrap();
2259+
assert!(results.is_empty());
2260+
let ptr = self.locals.tmp("ptr");
2261+
let len = self.locals.tmp("len");
2262+
uwriteln!(self.src, "int32_t {ptr} = {};", operands[0]);
2263+
uwriteln!(self.src, "int32_t {len} = {};", operands[1]);
2264+
let i = self.locals.tmp("i");
2265+
uwriteln!(self.src, "for (int32_t {i} = 0; {i} < {len}; {i}++) {{");
2266+
let size = self.gen.sizes.size(element);
2267+
uwriteln!(self.src, "int32_t base = {ptr} + {i} * {size};");
2268+
uwriteln!(self.src, "(void) base;");
2269+
uwrite!(self.src, "{body}");
2270+
uwriteln!(self.src, "}}");
2271+
uwriteln!(self.src, "if ({len} > 0) {{");
2272+
uwriteln!(self.src, "free((void*) ({ptr}));");
2273+
uwriteln!(self.src, "}}");
2274+
}
22112275

22122276
i => unimplemented!("{:?}", i),
22132277
}

crates/gen-guest-rust/src/lib.rs

Lines changed: 106 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -528,23 +528,20 @@ impl Generator for RustWasm {
528528
fn export(&mut self, iface: &Interface, func: &Function) {
529529
let iface_name = iface.name.to_snake_case();
530530

531-
self.src.push_str("#[export_name = \"");
532-
match &iface.module {
531+
let name_mangled = iface.mangle_funcname(func);
532+
let name_snake = func.name.to_snake_case();
533+
let name = match &iface.module {
533534
Some(module) => {
534-
self.src.push_str(module);
535-
self.src.push_str("#");
536-
self.src.push_str(&iface.mangle_funcname(func));
535+
format!("{module}#{}", name_mangled)
537536
}
538-
None => {
539-
self.src.push_str(&self.opts.symbol_namespace);
540-
self.src.push_str(&iface.mangle_funcname(func));
541-
}
542-
}
543-
self.src.push_str("\"]\n");
537+
None => format!("{}{}", self.opts.symbol_namespace, name_mangled),
538+
};
539+
540+
self.src.push_str(&format!("#[export_name = \"{name}\"]\n"));
544541
self.src.push_str("unsafe extern \"C\" fn __wit_bindgen_");
545542
self.src.push_str(&iface_name);
546543
self.src.push_str("_");
547-
self.src.push_str(&func.name.to_snake_case());
544+
self.src.push_str(&name_snake);
548545
self.src.push_str("(");
549546
let sig = iface.wasm_signature(AbiVariant::GuestExport, func);
550547
let mut params = Vec::new();
@@ -594,6 +591,37 @@ impl Generator for RustWasm {
594591
self.src.push_str(&String::from(src));
595592
self.src.push_str("}\n");
596593

594+
if iface.guest_export_needs_post_return(func) {
595+
self.src.push_str(&format!(
596+
"#[export_name = \"{}cabi_post_{}\"]\n",
597+
self.opts.symbol_namespace, func.name,
598+
));
599+
self.src.push_str(&format!(
600+
"unsafe extern \"C\" fn __wit_bindgen_{iface_name}_{name_snake}_post_return("
601+
));
602+
let mut params = Vec::new();
603+
for (i, result) in sig.results.iter().enumerate() {
604+
let name = format!("arg{}", i);
605+
self.src.push_str(&name);
606+
self.src.push_str(": ");
607+
self.wasm_type(*result);
608+
self.src.push_str(", ");
609+
params.push(name);
610+
}
611+
self.src.push_str(") {\n");
612+
613+
let mut f = FunctionBindgen::new(self, params);
614+
iface.post_return(func, &mut f);
615+
let FunctionBindgen {
616+
needs_cleanup_list,
617+
src,
618+
..
619+
} = f;
620+
assert!(!needs_cleanup_list);
621+
self.src.push_str(&String::from(src));
622+
self.src.push_str("}\n");
623+
}
624+
597625
let prev = mem::take(&mut self.src);
598626
self.in_trait = true;
599627
let mut sig = FnSig::default();
@@ -1294,10 +1322,7 @@ impl Bindgen for FunctionBindgen<'_> {
12941322
results.push(len);
12951323
}
12961324

1297-
Instruction::ListCanonLift { free, .. } => {
1298-
// This only happens when we're receiving a list from the
1299-
// outside world, so `free` should always be `Some`.
1300-
assert!(free.is_some());
1325+
Instruction::ListCanonLift { .. } => {
13011326
let tmp = self.tmp();
13021327
let len = format!("len{}", tmp);
13031328
self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
@@ -1328,10 +1353,7 @@ impl Bindgen for FunctionBindgen<'_> {
13281353
results.push(len);
13291354
}
13301355

1331-
Instruction::StringLift { free, .. } => {
1332-
// This only happens when we're receiving a string from the
1333-
// outside world, so `free` should always be `Some`.
1334-
assert!(free.is_some());
1356+
Instruction::StringLift => {
13351357
let tmp = self.tmp();
13361358
let len = format!("len{}", tmp);
13371359
self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
@@ -1387,10 +1409,7 @@ impl Bindgen for FunctionBindgen<'_> {
13871409
}
13881410
}
13891411

1390-
Instruction::ListLift { element, free, .. } => {
1391-
// This only happens when we're receiving a list from the
1392-
// outside world, so `free` should always be `Some`.
1393-
assert!(free.is_some());
1412+
Instruction::ListLift { element, .. } => {
13941413
let body = self.blocks.pop().unwrap();
13951414
let tmp = self.tmp();
13961415
let size = self.gen.sizes.size(element);
@@ -1425,7 +1444,7 @@ impl Bindgen for FunctionBindgen<'_> {
14251444
self.push_str("}\n");
14261445
results.push(result);
14271446
self.push_str(&format!(
1428-
"if {len} != 0 {{\nstd::alloc::dealloc({base} as *mut _, std::alloc::Layout::from_size_align_unchecked(({len} as usize) * {size}, {align}));\n}}\n",
1447+
"wit_bindgen_guest_rust::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
14291448
));
14301449
}
14311450

@@ -1580,16 +1599,72 @@ impl Bindgen for FunctionBindgen<'_> {
15801599
}
15811600

15821601
Instruction::Malloc { .. } => unimplemented!(),
1583-
Instruction::Free {
1584-
free: _,
1585-
size,
1586-
align,
1587-
} => {
1602+
1603+
Instruction::GuestDeallocate { size, align } => {
15881604
self.push_str(&format!(
1589-
"wit_bindgen_guest_rust::rt::canonical_abi_free({} as *mut u8, {}, {});\n",
1605+
"wit_bindgen_guest_rust::rt::dealloc({}, {}, {});\n",
15901606
operands[0], size, align
15911607
));
15921608
}
1609+
1610+
Instruction::GuestDeallocateString => {
1611+
self.push_str(&format!(
1612+
"wit_bindgen_guest_rust::rt::dealloc({}, ({}) as usize, 1);\n",
1613+
operands[0], operands[1],
1614+
));
1615+
}
1616+
1617+
Instruction::GuestDeallocateVariant { blocks } => {
1618+
let max = blocks - 1;
1619+
let blocks = self
1620+
.blocks
1621+
.drain(self.blocks.len() - blocks..)
1622+
.collect::<Vec<_>>();
1623+
let op0 = &operands[0];
1624+
self.src.push_str(&format!("match {op0} {{\n"));
1625+
for (i, block) in blocks.into_iter().enumerate() {
1626+
let pat = if i == max {
1627+
String::from("_")
1628+
} else {
1629+
i.to_string()
1630+
};
1631+
self.src.push_str(&format!("{pat} => {block},\n"));
1632+
}
1633+
self.src.push_str("}\n");
1634+
}
1635+
1636+
Instruction::GuestDeallocateList { element } => {
1637+
let body = self.blocks.pop().unwrap();
1638+
let tmp = self.tmp();
1639+
let size = self.gen.sizes.size(element);
1640+
let align = self.gen.sizes.align(element);
1641+
let len = format!("len{tmp}");
1642+
let base = format!("base{tmp}");
1643+
self.push_str(&format!(
1644+
"let {base} = {operand0};\n",
1645+
operand0 = operands[0]
1646+
));
1647+
self.push_str(&format!(
1648+
"let {len} = {operand1};\n",
1649+
operand1 = operands[1]
1650+
));
1651+
1652+
if body != "()" {
1653+
self.push_str("for i in 0..");
1654+
self.push_str(&len);
1655+
self.push_str(" {\n");
1656+
self.push_str("let base = ");
1657+
self.push_str(&base);
1658+
self.push_str(" + i *");
1659+
self.push_str(&size.to_string());
1660+
self.push_str(";\n");
1661+
self.push_str(&body);
1662+
self.push_str("\n}\n");
1663+
}
1664+
self.push_str(&format!(
1665+
"wit_bindgen_guest_rust::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
1666+
));
1667+
}
15931668
}
15941669
}
15951670
}

0 commit comments

Comments
 (0)