Skip to content

Commit e859dd7

Browse files
fix(moonbit): make ffi builtin collection explicit and leak-free
1 parent 518ea22 commit e859dd7

2 files changed

Lines changed: 133 additions & 97 deletions

File tree

crates/moonbit/src/async_support.rs

Lines changed: 76 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,16 @@ impl AsyncSupport {
100100
}
101101
}
102102

103-
/// lift func name, lift, lower func name, lower
104-
pub(crate) struct AsyncBinding(pub HashMap<TypeId, (String, String, String, String)>);
103+
pub(crate) struct AsyncBindingEntry {
104+
pub lift_name: String,
105+
pub lift_src: String,
106+
pub lift_builtins: HashSet<&'static str>,
107+
pub lower_name: String,
108+
pub lower_src: String,
109+
pub lower_builtins: HashSet<&'static str>,
110+
}
111+
112+
pub(crate) struct AsyncBinding(pub HashMap<TypeId, AsyncBindingEntry>);
105113

106114
/// Async-specific helpers used by `InterfaceGenerator` to keep the main
107115
/// visitor implementation focused on shared lowering/lifting logic.
@@ -250,7 +258,10 @@ defer {cleanup_params}()\n{async_pkg}suspend_for_subtask({subtask}, cleanup_afte
250258
uwriteln!(bindgen.src, "return {lifted}");
251259
}
252260

253-
bindgen.src
261+
let builtins = bindgen.take_local_ffi_imports();
262+
let src = bindgen.src;
263+
self.ffi_imports.extend(builtins);
264+
src
254265
}
255266

256267
/// Generate the async bindings for this function.
@@ -290,7 +301,7 @@ defer {cleanup_params}()\n{async_pkg}suspend_for_subtask({subtask}, cleanup_afte
290301
index: usize,
291302
module: &str,
292303
func_name: &str,
293-
) -> (String, String, String, String) {
304+
) -> AsyncBindingEntry {
294305
let mut lift = Source::default();
295306
let mut lower = Source::default();
296307

@@ -400,17 +411,23 @@ fn wasmLift{camel_name}{index}(future_handle : Int) -> {lifted} {{
400411
result = {{
401412
"#
402413
);
403-
let operand = if let TypeDefKind::Future(Some(ty)) = self.resolve.types[ty].kind {
404-
// TODO : solve ownership
405-
let resolve = self.resolve.clone();
406-
let mut bindgen =
407-
FunctionBindgen::new(self, Box::new([]), Direction::Import, true, false);
408-
let operand = lift_from_memory(&resolve, &mut bindgen, "ptr".to_string(), &ty);
409-
uwriteln!(lift, "{}", bindgen.src);
410-
operand
411-
} else {
412-
"()".into()
413-
};
414+
let (operand, lift_builtins) =
415+
if let TypeDefKind::Future(Some(ty)) = self.resolve.types[ty].kind {
416+
// TODO : solve ownership
417+
let resolve = self.resolve.clone();
418+
let mut bindgen =
419+
FunctionBindgen::new(self, Box::new([]), Direction::Import, true, false);
420+
bindgen.use_ffi(ffi::MALLOC);
421+
bindgen.use_ffi(ffi::FREE);
422+
let operand = lift_from_memory(&resolve, &mut bindgen, "ptr".to_string(), &ty);
423+
uwriteln!(lift, "{}", bindgen.src);
424+
(operand, bindgen.take_local_ffi_imports())
425+
} else {
426+
let mut builtins = HashSet::new();
427+
builtins.insert(ffi::MALLOC);
428+
builtins.insert(ffi::FREE);
429+
("()".into(), builtins)
430+
};
414431

415432
// lift from memory if it were actual data
416433
uwriteln!(
@@ -458,7 +475,7 @@ fn wasmLower{camel_name}{index}(future : {lifted}) -> Int {{
458475
defer wasmLower{camel_name}{index}DropWritable(writable)"#
459476
);
460477

461-
if let Some(inner_ty) = inner_type {
478+
let lower_builtins = if let Some(inner_ty) = inner_type {
462479
let resolve = self.resolve.clone();
463480
let mut bindgen =
464481
FunctionBindgen::new(self, Box::new([]), Direction::Export, true, false);
@@ -484,6 +501,7 @@ fn wasmLower{camel_name}{index}(future : {lifted}) -> Int {{
484501
r#"
485502
let _ = {async_qualifier}suspend_for_future_write(writable, wasmLower{camel_name}{index}Write(writable, ret_area)) catch {{ _ => false }}"#
486503
);
504+
bindgen.take_local_ffi_imports()
487505
} else {
488506
// Unit type - no value to write, just complete the future
489507
uwriteln!(
@@ -492,7 +510,8 @@ fn wasmLower{camel_name}{index}(future : {lifted}) -> Int {{
492510
let _ = producer()
493511
let _ = {async_qualifier}suspend_for_future_write(writable, wasmLower{camel_name}{index}Write(writable, 0)) catch {{ _ => false }}"#
494512
);
495-
}
513+
HashSet::new()
514+
};
496515

497516
uwriteln!(
498517
lower,
@@ -503,12 +522,15 @@ fn wasmLower{camel_name}{index}(future : {lifted}) -> Int {{
503522
}}
504523
}}"#
505524
);
506-
(
507-
lifted_func_name,
508-
lift.to_string(),
509-
lowered_func_name,
510-
lower.to_string(),
511-
)
525+
let lower_src = lower.to_string();
526+
AsyncBindingEntry {
527+
lift_name: lifted_func_name,
528+
lift_src: lift.to_string(),
529+
lift_builtins,
530+
lower_name: lowered_func_name,
531+
lower_src,
532+
lower_builtins,
533+
}
512534
}
513535

514536
pub(crate) fn generate_stream_binding(
@@ -517,7 +539,7 @@ fn wasmLower{camel_name}{index}(future : {lifted}) -> Int {{
517539
index: usize,
518540
module: &str,
519541
func_name: &str,
520-
) -> (String, String, String, String) {
542+
) -> AsyncBindingEntry {
521543
let mut lift = Source::default();
522544
let mut lower = Source::default();
523545

@@ -594,10 +616,15 @@ fn wasmLift{camel_name}{index}(stream_handle : Int) -> {lifted} {{
594616
}}"#
595617
);
596618

597-
if let Some(inner_ty) = inner_type {
619+
let lift_builtins = if let Some(inner_ty) = inner_type {
598620
let resolve = self.resolve.clone();
599-
let mut lift_bindgen =
600-
FunctionBindgen::new(self, Box::new([]), Direction::Import, true, false);
621+
let mut lift_bindgen = FunctionBindgen::new(
622+
self,
623+
Box::new([]),
624+
Direction::Import,
625+
true,
626+
false,
627+
);
601628
lift_bindgen.use_ffi(ffi::MALLOC);
602629
lift_bindgen.use_ffi(ffi::FREE);
603630

@@ -641,6 +668,7 @@ fn wasmLift{camel_name}{index}(stream_handle : Int) -> {lifted} {{
641668
if end {{ close() }}
642669
Some(items[:])"#
643670
);
671+
lift_bindgen.take_local_ffi_imports()
644672
} else {
645673
// Unit type stream
646674
uwriteln!(
@@ -659,7 +687,8 @@ fn wasmLift{camel_name}{index}(stream_handle : Int) -> {lifted} {{
659687
if end {{ close() }}
660688
Some(result[:])"#
661689
);
662-
}
690+
HashSet::new()
691+
};
663692

664693
uwriteln!(
665694
lift,
@@ -705,11 +734,16 @@ fn wasmLower{camel_name}{index}(stream : {lifted}) -> Int {{
705734
}}"#
706735
);
707736

708-
if let Some(inner_ty) = inner_type {
737+
let lower_builtins = if let Some(inner_ty) = inner_type {
709738
let resolve = self.resolve.clone();
710739
let elem_type = self.world_gen.pkg_resolver.type_name(self.name, &inner_ty);
711-
let mut lower_bindgen =
712-
FunctionBindgen::new(self, Box::new([]), Direction::Export, true, false);
740+
let mut lower_bindgen = FunctionBindgen::new(
741+
self,
742+
Box::new([]),
743+
Direction::Export,
744+
true,
745+
false,
746+
);
713747
lower_bindgen.use_ffi(ffi::MALLOC);
714748
lower_bindgen.use_ffi(ffi::FREE);
715749

@@ -746,6 +780,7 @@ fn wasmLower{camel_name}{index}(stream : {lifted}) -> Int {{
746780
}}
747781
progress"#
748782
);
783+
lower_bindgen.take_local_ffi_imports()
749784
} else {
750785
// Unit type stream
751786
uwriteln!(
@@ -761,7 +796,8 @@ fn wasmLower{camel_name}{index}(stream : {lifted}) -> Int {{
761796
}}
762797
progress"#
763798
);
764-
}
799+
HashSet::new()
800+
};
765801

766802
uwriteln!(
767803
lower,
@@ -783,11 +819,13 @@ fn wasmLower{camel_name}{index}(stream : {lifted}) -> Int {{
783819
}}"#
784820
);
785821

786-
(
787-
lifted_func_name,
788-
lift.to_string(),
789-
lowered_func_name,
790-
lower.to_string(),
791-
)
822+
AsyncBindingEntry {
823+
lift_name: lifted_func_name,
824+
lift_src: lift.to_string(),
825+
lift_builtins,
826+
lower_name: lowered_func_name,
827+
lower_src: lower.to_string(),
828+
lower_builtins,
829+
}
792830
}
793831
}

0 commit comments

Comments
 (0)