Skip to content

Commit b0f6fd8

Browse files
jsturtevantdicej
andauthored
c#: Remove Copy of data during import call for base types (#1122)
* When calling an import we don't need to copy data to a new structure for cannoncal types. This avoid the extra copy of data in this scenario Signed-off-by: James Sturtevant <[email protected]> * Use a pinned gc handle to get a pointer to the list Using a span and fixed keyword won't work with variants due to the fact that the external import call requires different types. Nesting of the fixed commands also become unwiedly Signed-off-by: James Sturtevant <[email protected]> * Apply suggestions from code review Co-authored-by: Joel Dice <[email protected]> --------- Signed-off-by: James Sturtevant <[email protected]> Co-authored-by: Joel Dice <[email protected]>
1 parent 0bb8697 commit b0f6fd8

File tree

1 file changed

+14
-12
lines changed

1 file changed

+14
-12
lines changed

crates/csharp/src/function.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -723,21 +723,24 @@ impl Bindgen for FunctionBindgen<'_, '_> {
723723
}
724724

725725
Instruction::ListCanonLower { element, realloc } => {
726-
let list = &operands[0];
727-
let (_size, ty) = list_element_info(element);
728-
726+
let list: &String = &operands[0];
729727
match self.interface_gen.direction {
730728
Direction::Import => {
731-
let buffer: String = self.locals.tmp("buffer");
729+
let ptr: String = self.locals.tmp("listPtr");
730+
let handle: String = self.locals.tmp("gcHandle");
731+
// Despite the name GCHandle.Alloc here this does not actually allocate memory on the heap.
732+
// It pins the array with the garbage collector so that it can be passed to unmanaged code.
733+
// It is required to free the pin after use which is done in the Cleanup section.
732734
uwrite!(
733735
self.src,
734736
"
735-
void* {buffer} = stackalloc {ty}[({list}).Length];
736-
{list}.AsSpan<{ty}>().CopyTo(new Span<{ty}>({buffer}, {list}.Length));
737+
var {handle} = GCHandle.Alloc({list}, GCHandleType.Pinned);
738+
var {ptr} = {handle}.AddrOfPinnedObject();
737739
"
738740
);
739-
results.push(format!("(int){buffer}"));
741+
results.push(format!("{ptr}"));
740742
results.push(format!("({list}).Length"));
743+
self.cleanup.push(Cleanup { address: handle });
741744
}
742745
Direction::Export => {
743746
let address = self.locals.tmp("address");
@@ -1013,7 +1016,6 @@ impl Bindgen for FunctionBindgen<'_, '_> {
10131016
uwriteln!(self.src, "return ({results});")
10141017
}
10151018
}
1016-
10171019
// Close all the fixed blocks.
10181020
for _ in 0..self.fixed {
10191021
uwriteln!(self.src, "}}");
@@ -1103,7 +1105,7 @@ impl Bindgen for FunctionBindgen<'_, '_> {
11031105

11041106
match direction {
11051107
Direction::Import => {
1106-
let import_name = self.interface_gen.type_name_with_qualifier(&Type::Id(id), true);
1108+
let import_name = self.interface_gen.type_name_with_qualifier(&Type::Id(id), true);
11071109

11081110
if let FunctionKind::Constructor(_) = self.kind {
11091111
resource = "this".to_owned();
@@ -1122,13 +1124,13 @@ impl Bindgen for FunctionBindgen<'_, '_> {
11221124
Direction::Export => {
11231125
self.interface_gen.csharp_gen.needs_rep_table = true;
11241126

1125-
let export_name = self.interface_gen.csharp_gen.all_resources[&id].export_impl_name();
1127+
let export_name = self.interface_gen.csharp_gen.all_resources[&id].export_impl_name();
11261128
if is_own {
11271129
uwriteln!(
11281130
self.src,
11291131
"var {resource} = ({export_name}) {export_name}.repTable.Get\
1130-
({export_name}.WasmInterop.wasmImportResourceRep({op}));
1131-
{resource}.Handle = {op};"
1132+
({export_name}.WasmInterop.wasmImportResourceRep({op}));
1133+
{resource}.Handle = {op};"
11321134
);
11331135
} else {
11341136
uwriteln!(self.src, "var {resource} = ({export_name}) {export_name}.repTable.Get({op});");

0 commit comments

Comments
 (0)