Skip to content

Commit 2be426a

Browse files
authored
Add generic clean up to support variants and strings (#1137)
Signed-off-by: James Sturtevant <jsturtevant@gmail.com>
1 parent 9808631 commit 2be426a

File tree

3 files changed

+40
-67
lines changed

3 files changed

+40
-67
lines changed

crates/csharp/src/function.rs

Lines changed: 40 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,7 @@ pub(crate) struct FunctionBindgen<'a, 'b> {
2222
block_storage: Vec<BlockStorage>,
2323
blocks: Vec<Block>,
2424
payloads: Vec<String>,
25-
pub(crate) needs_cleanup_list: bool,
26-
needs_native_alloc_list: bool,
27-
cleanup: Vec<Cleanup>,
25+
pub(crate) needs_cleanup: bool,
2826
import_return_pointer_area_size: usize,
2927
import_return_pointer_area_align: usize,
3028
pub(crate) resource_drops: Vec<(String, String)>,
@@ -55,9 +53,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
5553
block_storage: Vec::new(),
5654
blocks: Vec::new(),
5755
payloads: Vec::new(),
58-
needs_cleanup_list: false,
59-
needs_native_alloc_list: false,
60-
cleanup: Vec::new(),
56+
needs_cleanup: false,
6157
import_return_pointer_area_size: 0,
6258
import_return_pointer_area_align: 0,
6359
resource_drops: Vec::new(),
@@ -729,16 +725,17 @@ impl Bindgen for FunctionBindgen<'_, '_> {
729725
// Despite the name GCHandle.Alloc here this does not actually allocate memory on the heap.
730726
// It pins the array with the garbage collector so that it can be passed to unmanaged code.
731727
// It is required to free the pin after use which is done in the Cleanup section.
728+
self.needs_cleanup = true;
732729
uwrite!(
733730
self.src,
734731
"
735732
var {handle} = GCHandle.Alloc({list}, GCHandleType.Pinned);
736733
var {ptr} = {handle}.AddrOfPinnedObject();
734+
cleanups.Add(()=> {handle}.Free());
737735
"
738736
);
739737
results.push(format!("{ptr}"));
740738
results.push(format!("({list}).Length"));
741-
self.cleanup.push(Cleanup { address: handle });
742739
}
743740
Direction::Export => {
744741
let address = self.locals.tmp("address");
@@ -756,9 +753,12 @@ impl Bindgen for FunctionBindgen<'_, '_> {
756753
);
757754

758755
if realloc.is_none() {
759-
self.cleanup.push(Cleanup {
760-
address: gc_handle.clone(),
761-
});
756+
self.needs_cleanup = true;
757+
uwrite!(
758+
self.src,
759+
"
760+
cleanups.Add(()=> {gc_handle}.Free());
761+
");
762762
}
763763
results.push(format!("((IntPtr)({address})).ToInt32()"));
764764
results.push(format!("{list}.Length"));
@@ -786,22 +786,39 @@ impl Bindgen for FunctionBindgen<'_, '_> {
786786
Instruction::StringLower { realloc } => {
787787
let op = &operands[0];
788788
let interop_string = self.locals.tmp("interopString");
789-
let result_var = self.locals.tmp("result");
789+
let utf8_bytes = self.locals.tmp("utf8Bytes");
790+
let length = self.locals.tmp("length");
791+
let gc_handle = self.locals.tmp("gcHandle");
790792
uwriteln!(
791793
self.src,
792794
"
793-
var {result_var} = {op};
794-
IntPtr {interop_string} = InteropString.FromString({result_var}, out int length{result_var});"
795+
var {utf8_bytes} = Encoding.UTF8.GetBytes({op});
796+
var {length} = {utf8_bytes}.Length;
797+
var {gc_handle} = GCHandle.Alloc({utf8_bytes}, GCHandleType.Pinned);
798+
var {interop_string} = {gc_handle}.AddrOfPinnedObject();
799+
"
795800
);
796801

797802
if realloc.is_none() {
798803
results.push(format!("{interop_string}.ToInt32()"));
804+
self.needs_cleanup = true;
805+
uwrite!(
806+
self.src,
807+
"
808+
cleanups.Add(()=> {gc_handle}.Free());
809+
");
799810
} else {
800811
results.push(format!("{interop_string}.ToInt32()"));
801812
}
802-
results.push(format!("length{result_var}"));
813+
results.push(format!("{length}"));
803814

804-
self.interface_gen.csharp_gen.needs_interop_string = true;
815+
if FunctionKind::Freestanding == *self.kind || self.interface_gen.direction == Direction::Export {
816+
self.interface_gen.require_interop_using("System.Text");
817+
self.interface_gen.require_interop_using("System.Runtime.InteropServices");
818+
} else {
819+
self.interface_gen.require_using("System.Text");
820+
self.interface_gen.require_using("System.Runtime.InteropServices");
821+
}
805822
}
806823

807824
Instruction::StringLift { .. } => {
@@ -835,14 +852,14 @@ impl Bindgen for FunctionBindgen<'_, '_> {
835852
let buffer_size = self.locals.tmp("bufferSize");
836853
//TODO: wasm64
837854
let align = self.interface_gen.csharp_gen.sizes.align(element).align_wasm32();
838-
self.needs_native_alloc_list = true;
839855

856+
self.needs_cleanup = true;
840857
uwrite!(
841858
self.src,
842859
"
843860
var {buffer_size} = {size} * (nuint){list}.Count;
844861
var {address} = NativeMemory.AlignedAlloc({buffer_size}, {align});
845-
nativeAllocs.Add((IntPtr){address});
862+
cleanups.Add(()=> NativeMemory.AlignedFree({address}));
846863
847864
for (int {index} = 0; {index} < {list}.Count; ++{index}) {{
848865
{ty} {block_element} = {list}[{index}];
@@ -988,19 +1005,15 @@ impl Bindgen for FunctionBindgen<'_, '_> {
9881005
}
9891006

9901007
Instruction::Return { amt: _, func } => {
991-
for Cleanup { address } in &self.cleanup {
992-
uwriteln!(self.src, "{address}.Free();");
993-
}
994-
995-
if self.needs_native_alloc_list {
996-
self.src.insert_str(0, "var nativeAllocs = new List<IntPtr>();
1008+
if self.needs_cleanup {
1009+
self.src.insert_str(0, "var cleanups = new List<Action>();
9971010
");
9981011

9991012
uwriteln!(self.src, "\
1000-
foreach (var nativeAlloc in nativeAllocs)
1001-
{{
1002-
NativeMemory.AlignedFree((void*)nativeAlloc);
1003-
}}");
1013+
foreach (var cleanup in cleanups)
1014+
{{
1015+
cleanup();
1016+
}}");
10041017
}
10051018

10061019
if !matches!((self.interface_gen.direction, self.kind), (Direction::Import, FunctionKind::Constructor(_))) {
@@ -1204,7 +1217,6 @@ impl Bindgen for FunctionBindgen<'_, '_> {
12041217
body: mem::take(&mut self.src),
12051218
element: self.locals.tmp("element"),
12061219
base: self.locals.tmp("basePtr"),
1207-
cleanup: mem::take(&mut self.cleanup),
12081220
});
12091221
}
12101222

@@ -1213,19 +1225,8 @@ impl Bindgen for FunctionBindgen<'_, '_> {
12131225
body,
12141226
element,
12151227
base,
1216-
cleanup,
12171228
} = self.block_storage.pop().unwrap();
12181229

1219-
if !self.cleanup.is_empty() {
1220-
//self.needs_cleanup_list = true;
1221-
1222-
for Cleanup { address } in &self.cleanup {
1223-
uwriteln!(self.src, "{address}.Free();");
1224-
}
1225-
}
1226-
1227-
self.cleanup = cleanup;
1228-
12291230
self.blocks.push(Block {
12301231
body: mem::replace(&mut self.src, body),
12311232
results: mem::take(operands),
@@ -1304,15 +1305,10 @@ struct Block {
13041305
base: String,
13051306
}
13061307

1307-
struct Cleanup {
1308-
address: String,
1309-
}
1310-
13111308
struct BlockStorage {
13121309
body: String,
13131310
element: String,
13141311
base: String,
1315-
cleanup: Vec<Cleanup>,
13161312
}
13171313

13181314
#[derive(Clone)]

crates/csharp/src/interface.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,8 +401,6 @@ impl InterfaceGenerator<'_> {
401401
false,
402402
);
403403

404-
assert!(!bindgen.needs_cleanup_list);
405-
406404
let src = bindgen.src;
407405

408406
let vars = bindgen

crates/csharp/src/world_generator.rs

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ pub struct CSharp {
3333
pub(crate) tuple_counts: HashSet<usize>,
3434
pub(crate) needs_result: bool,
3535
pub(crate) needs_option: bool,
36-
pub(crate) needs_interop_string: bool,
3736
pub(crate) needs_export_return_area: bool,
3837
pub(crate) needs_rep_table: bool,
3938
pub(crate) needs_wit_exception: bool,
@@ -456,26 +455,6 @@ impl WorldGenerator for CSharp {
456455
)
457456
}
458457

459-
if self.needs_interop_string {
460-
self.require_using("System.Text");
461-
self.require_using("System.Runtime.InteropServices");
462-
uwrite!(
463-
src,
464-
r#"
465-
{access} static class InteropString
466-
{{
467-
internal static IntPtr FromString(string input, out int length)
468-
{{
469-
var utf8Bytes = Encoding.UTF8.GetBytes(input);
470-
length = utf8Bytes.Length;
471-
var gcHandle = GCHandle.Alloc(utf8Bytes, GCHandleType.Pinned);
472-
return gcHandle.AddrOfPinnedObject();
473-
}}
474-
}}
475-
"#,
476-
)
477-
}
478-
479458
if self.needs_wit_exception {
480459
uwrite!(
481460
src,

0 commit comments

Comments
 (0)