Skip to content

Commit 050f13b

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 3cdaefa commit 050f13b

File tree

11 files changed

+610
-401
lines changed

11 files changed

+610
-401
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(\"{}_post_return\")))",
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: 103 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -528,23 +528,19 @@ 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_snake = func.name.to_snake_case();
532+
let name = match &iface.module {
533533
Some(module) => {
534-
self.src.push_str(module);
535-
self.src.push_str("#");
536-
self.src.push_str(&func.name);
534+
format!("{module}#{}", func.name)
537535
}
538-
None => {
539-
self.src.push_str(&self.opts.symbol_namespace);
540-
self.src.push_str(&func.name);
541-
}
542-
}
543-
self.src.push_str("\"]\n");
536+
None => format!("{}{}", self.opts.symbol_namespace, func.name),
537+
};
538+
539+
self.src.push_str(&format!("#[export_name = \"{name}\"]\n"));
544540
self.src.push_str("unsafe extern \"C\" fn __wit_bindgen_");
545541
self.src.push_str(&iface_name);
546542
self.src.push_str("_");
547-
self.src.push_str(&func.name.to_snake_case());
543+
self.src.push_str(&name_snake);
548544
self.src.push_str("(");
549545
let sig = iface.wasm_signature(AbiVariant::GuestExport, func);
550546
let mut params = Vec::new();
@@ -594,6 +590,35 @@ impl Generator for RustWasm {
594590
self.src.push_str(&String::from(src));
595591
self.src.push_str("}\n");
596592

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

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());
1322+
Instruction::ListCanonLift { .. } => {
13011323
let tmp = self.tmp();
13021324
let len = format!("len{}", tmp);
13031325
self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
@@ -1328,10 +1350,7 @@ impl Bindgen for FunctionBindgen<'_> {
13281350
results.push(len);
13291351
}
13301352

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());
1353+
Instruction::StringLift => {
13351354
let tmp = self.tmp();
13361355
let len = format!("len{}", tmp);
13371356
self.push_str(&format!("let {} = {} as usize;\n", len, operands[1]));
@@ -1387,10 +1406,7 @@ impl Bindgen for FunctionBindgen<'_> {
13871406
}
13881407
}
13891408

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());
1409+
Instruction::ListLift { element, .. } => {
13941410
let body = self.blocks.pop().unwrap();
13951411
let tmp = self.tmp();
13961412
let size = self.gen.sizes.size(element);
@@ -1425,7 +1441,7 @@ impl Bindgen for FunctionBindgen<'_> {
14251441
self.push_str("}\n");
14261442
results.push(result);
14271443
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",
1444+
"wit_bindgen_guest_rust::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
14291445
));
14301446
}
14311447

@@ -1575,16 +1591,72 @@ impl Bindgen for FunctionBindgen<'_> {
15751591
}
15761592

15771593
Instruction::Malloc { .. } => unimplemented!(),
1578-
Instruction::Free {
1579-
free: _,
1580-
size,
1581-
align,
1582-
} => {
1594+
1595+
Instruction::GuestDeallocate { size, align } => {
15831596
self.push_str(&format!(
1584-
"wit_bindgen_guest_rust::rt::canonical_abi_free({} as *mut u8, {}, {});\n",
1597+
"wit_bindgen_guest_rust::rt::dealloc({}, {}, {});\n",
15851598
operands[0], size, align
15861599
));
15871600
}
1601+
1602+
Instruction::GuestDeallocateString => {
1603+
self.push_str(&format!(
1604+
"wit_bindgen_guest_rust::rt::dealloc({}, ({}) as usize, 1);\n",
1605+
operands[0], operands[1],
1606+
));
1607+
}
1608+
1609+
Instruction::GuestDeallocateVariant { blocks } => {
1610+
let max = blocks - 1;
1611+
let blocks = self
1612+
.blocks
1613+
.drain(self.blocks.len() - blocks..)
1614+
.collect::<Vec<_>>();
1615+
let op0 = &operands[0];
1616+
self.src.push_str(&format!("match {op0} {{\n"));
1617+
for (i, block) in blocks.into_iter().enumerate() {
1618+
let pat = if i == max {
1619+
String::from("_")
1620+
} else {
1621+
i.to_string()
1622+
};
1623+
self.src.push_str(&format!("{pat} => {block},\n"));
1624+
}
1625+
self.src.push_str("}\n");
1626+
}
1627+
1628+
Instruction::GuestDeallocateList { element } => {
1629+
let body = self.blocks.pop().unwrap();
1630+
let tmp = self.tmp();
1631+
let size = self.gen.sizes.size(element);
1632+
let align = self.gen.sizes.align(element);
1633+
let len = format!("len{tmp}");
1634+
let base = format!("base{tmp}");
1635+
self.push_str(&format!(
1636+
"let {base} = {operand0};\n",
1637+
operand0 = operands[0]
1638+
));
1639+
self.push_str(&format!(
1640+
"let {len} = {operand1};\n",
1641+
operand1 = operands[1]
1642+
));
1643+
1644+
if body != "()" {
1645+
self.push_str("for i in 0..");
1646+
self.push_str(&len);
1647+
self.push_str(" {\n");
1648+
self.push_str("let base = ");
1649+
self.push_str(&base);
1650+
self.push_str(" + i *");
1651+
self.push_str(&size.to_string());
1652+
self.push_str(";\n");
1653+
self.push_str(&body);
1654+
self.push_str("\n}\n");
1655+
}
1656+
self.push_str(&format!(
1657+
"wit_bindgen_guest_rust::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
1658+
));
1659+
}
15881660
}
15891661
}
15901662
}

0 commit comments

Comments
 (0)