Skip to content

Commit

Permalink
[c#] Align lists, free alloc'ed memory before return (bytecodeallianc…
Browse files Browse the repository at this point in the history
…e#1055)

* align lists, free alloc'ed memory before return

* revert ws change
  • Loading branch information
yowl authored Sep 18, 2024
1 parent dea39d0 commit 3e3877d
Showing 1 changed file with 22 additions and 13 deletions.
35 changes: 22 additions & 13 deletions crates/csharp/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,7 @@ struct FunctionBindgen<'a, 'b> {
blocks: Vec<Block>,
payloads: Vec<String>,
needs_cleanup_list: bool,
needs_native_alloc_list: bool,
cleanup: Vec<Cleanup>,
import_return_pointer_area_size: usize,
import_return_pointer_area_align: usize,
Expand Down Expand Up @@ -1989,6 +1990,7 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
blocks: Vec::new(),
payloads: Vec::new(),
needs_cleanup_list: false,
needs_native_alloc_list: false,
cleanup: Vec::new(),
import_return_pointer_area_size: 0,
import_return_pointer_area_align: 0,
Expand Down Expand Up @@ -2185,7 +2187,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
Instruction::F64Load { offset } => results.push(format!("BitConverter.ToDouble(new Span<byte>((void*)({} + {offset}), 8))",operands[0])),
Instruction::I32Store { offset }
| Instruction::PointerStore { offset }
| Instruction::LengthStore { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span<byte>((void*)({} + {offset}), 4), unchecked((int){}));", operands[1], operands[0]),
| Instruction::LengthStore { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span<byte>((void*)({} + {offset}), 4), {});", operands[1], operands[0]),
Instruction::I32Store8 { offset } => uwriteln!(self.src, "*(byte*)({} + {offset}) = (byte){};", operands[1], operands[0]),
Instruction::I32Store16 { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span<byte>((void*)({} + {offset}), 2), (short){});", operands[1], operands[0]),
Instruction::I64Store { offset } => uwriteln!(self.src, "BitConverter.TryWriteBytes(new Span<byte>((void*)({} + {offset}), 8), unchecked((long){}));", operands[1], operands[0]),
Expand Down Expand Up @@ -2601,16 +2603,18 @@ impl Bindgen for FunctionBindgen<'_, '_> {
let ty = self.gen.type_name_with_qualifier(element, true);
let index = self.locals.tmp("index");

let buffer: String = self.locals.tmp("buffer");
let gc_handle = self.locals.tmp("gcHandle");
let address = self.locals.tmp("address");
let buffer_size = self.locals.tmp("bufferSize");
//TODO: wasm64
let align = self.gen.gen.sizes.align(element).align_wasm32();
self.needs_native_alloc_list = true;

uwrite!(
self.src,
"
byte[] {buffer} = new byte[{size} * {list}.Count];
var {gc_handle} = GCHandle.Alloc({buffer}, GCHandleType.Pinned);
var {address} = {gc_handle}.AddrOfPinnedObject();
var {buffer_size} = {size} * (nuint){list}.Count;
var {address} = NativeMemory.AlignedAlloc({buffer_size}, {align});
nativeAllocs.Add((IntPtr){address});
for (int {index} = 0; {index} < {list}.Count; ++{index}) {{
{ty} {block_element} = {list}[{index}];
Expand All @@ -2620,12 +2624,6 @@ impl Bindgen for FunctionBindgen<'_, '_> {
"
);

if realloc.is_none() {
self.cleanup.push(Cleanup {
address: gc_handle.clone(),
});
}

results.push(format!("(int){address}"));
results.push(format!("{list}.Count"));
}
Expand Down Expand Up @@ -2829,6 +2827,17 @@ impl Bindgen for FunctionBindgen<'_, '_> {
uwriteln!(self.src, "{address}.Free();");
}

if self.needs_native_alloc_list {
self.src.insert_str(0, "var nativeAllocs = new List<IntPtr>();
");

uwriteln!(self.src, "\
foreach (var nativeAlloc in nativeAllocs)
{{
NativeMemory.AlignedFree((void*)nativeAlloc);
}}");
}

if !matches!((self.gen.direction, self.kind), (Direction::Import, FunctionKind::Constructor(_))) {
match func.results.len() {
0 => (),
Expand Down Expand Up @@ -2920,7 +2929,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
Direction::Export => {
self.gen.gen.needs_rep_table = true;
let local_rep = self.locals.tmp("localRep");
let export_name = self.gen.gen.all_resources[&id].export_impl_name();
let export_name = self.gen.gen.all_resources[&id].export_impl_name();
if is_own {
// Note that we set `{op}.Handle` to zero below to ensure that application code doesn't
// try to use the instance while the host has ownership. We'll set it back to non-zero
Expand Down

0 comments on commit 3e3877d

Please sign in to comment.