Skip to content

Commit 77332ee

Browse files
authored
Fix multiple return areas being generated for imports in one function (#466)
* Fix multiple return areas being generated for imports in one function This commit fixes the issues brought up in #444 and #454 by moving the generation of the local variable to outside the `FunctionBindgen` structure into just after the function has been generated. That way when two return areas are requested they'll get unified into one storage. Closes #444 Closes #454 * Exclude the new test on the teavm-java generator
1 parent 98c2b1e commit 77332ee

4 files changed

Lines changed: 65 additions & 22 deletions

File tree

crates/gen-guest-c/src/lib.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -790,7 +790,21 @@ impl InterfaceGenerator<'_> {
790790
&mut f,
791791
);
792792

793-
let FunctionBindgen { src, .. } = f;
793+
let FunctionBindgen {
794+
src,
795+
import_return_pointer_area_size,
796+
import_return_pointer_area_align,
797+
..
798+
} = f;
799+
800+
if import_return_pointer_area_size > 0 {
801+
self.src.c_adapters(&format!(
802+
"\
803+
__attribute__((aligned({import_return_pointer_area_align})))
804+
uint8_t ret_area[{import_return_pointer_area_size}];
805+
",
806+
));
807+
}
794808

795809
self.src.c_adapters(&String::from(src));
796810
self.src.c_adapters("}\n");
@@ -1527,6 +1541,8 @@ struct FunctionBindgen<'a, 'b> {
15271541
params: Vec<String>,
15281542
wasm_return: Option<String>,
15291543
ret_store_cnt: usize,
1544+
import_return_pointer_area_size: usize,
1545+
import_return_pointer_area_align: usize,
15301546
}
15311547

15321548
impl<'a, 'b> FunctionBindgen<'a, 'b> {
@@ -1547,6 +1563,8 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
15471563
params: Vec::new(),
15481564
wasm_return: None,
15491565
ret_store_cnt: 0,
1566+
import_return_pointer_area_size: 0,
1567+
import_return_pointer_area_align: 0,
15501568
}
15511569
}
15521570

@@ -1612,19 +1630,12 @@ impl Bindgen for FunctionBindgen<'_, '_> {
16121630
fn return_pointer(&mut self, size: usize, align: usize) -> String {
16131631
let ptr = self.locals.tmp("ptr");
16141632

1633+
// Use a stack-based return area for imports, because exports need
1634+
// their return area to be live until the post-return call.
16151635
if self.gen.in_import {
1616-
// Declare a stack-allocated return area. We only do this for
1617-
// imports, because exports need their return area to be live until
1618-
// the post-return call.
1619-
uwrite!(
1620-
self.src,
1621-
"\
1622-
__attribute__((aligned({})))
1623-
uint8_t ret_area[{}];
1624-
",
1625-
align,
1626-
size,
1627-
);
1636+
self.import_return_pointer_area_size = self.import_return_pointer_area_size.max(size);
1637+
self.import_return_pointer_area_align =
1638+
self.import_return_pointer_area_align.max(align);
16281639
uwriteln!(self.src, "int32_t {} = (int32_t) &ret_area;", ptr);
16291640
} else {
16301641
self.gen.gen.return_pointer_area_size = self.gen.gen.return_pointer_area_size.max(size);

crates/gen-guest-rust/src/lib.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -387,12 +387,24 @@ impl InterfaceGenerator<'_> {
387387
let FunctionBindgen {
388388
needs_cleanup_list,
389389
src,
390+
import_return_pointer_area_size,
391+
import_return_pointer_area_align,
390392
..
391393
} = f;
392394

393395
if needs_cleanup_list {
394396
self.src.push_str("let mut cleanup_list = Vec::new();\n");
395397
}
398+
if import_return_pointer_area_size > 0 {
399+
uwrite!(
400+
self.src,
401+
"
402+
#[repr(align({import_return_pointer_area_align}))]
403+
struct RetArea([u8; {import_return_pointer_area_size}]);
404+
let mut ret_area = core::mem::MaybeUninit::<RetArea>::uninit();
405+
",
406+
);
407+
}
396408
self.src.push_str(&String::from(src));
397409

398410
self.src.push_str("}\n");
@@ -708,6 +720,8 @@ struct FunctionBindgen<'a, 'b> {
708720
tmp: usize,
709721
needs_cleanup_list: bool,
710722
cleanup: Vec<(String, String)>,
723+
import_return_pointer_area_size: usize,
724+
import_return_pointer_area_align: usize,
711725
}
712726

713727
impl<'a, 'b> FunctionBindgen<'a, 'b> {
@@ -721,6 +735,8 @@ impl<'a, 'b> FunctionBindgen<'a, 'b> {
721735
tmp: 0,
722736
needs_cleanup_list: false,
723737
cleanup: Vec::new(),
738+
import_return_pointer_area_size: 0,
739+
import_return_pointer_area_align: 0,
724740
}
725741
}
726742

@@ -841,16 +857,15 @@ impl Bindgen for FunctionBindgen<'_, '_> {
841857
fn return_pointer(&mut self, size: usize, align: usize) -> String {
842858
let tmp = self.tmp();
843859

860+
// Imports get a per-function return area to facilitate using the
861+
// stack whereas exports use a per-module return area to cut down on
862+
// stack usage. Note that for imports this also facilitates "adapter
863+
// modules" for components to not have data segments.
844864
if self.gen.in_import {
845-
uwrite!(
846-
self.src,
847-
"
848-
#[repr(align({align}))]
849-
struct RetArea([u8; {size}]);
850-
let mut ret_area = core::mem::MaybeUninit::<RetArea>::uninit();
851-
let ptr{tmp} = ret_area.as_mut_ptr() as i32;
852-
",
853-
);
865+
self.import_return_pointer_area_size = self.import_return_pointer_area_size.max(size);
866+
self.import_return_pointer_area_align =
867+
self.import_return_pointer_area_align.max(align);
868+
uwrite!(self.src, "let ptr{tmp} = ret_area.as_mut_ptr() as i32;");
854869
} else {
855870
self.gen.return_pointer_area_size = self.gen.return_pointer_area_size.max(size);
856871
self.gen.return_pointer_area_align = self.gen.return_pointer_area_align.max(align);

crates/gen-guest-teavm-java/tests/codegen.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ use std::path::Path;
44
use std::process::Command;
55

66
macro_rules! codegen_test {
7+
// TODO: should remove this line and fix this test
8+
(ret_areas $($_:tt)*) => {};
9+
710
($id:ident $name:tt $test:tt) => {
811
#[test]
912
fn $id() {

tests/codegen/ret-areas.wit

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// This test generates multiple `RetArea` structs.
2+
3+
interface tcp {
4+
type ipv6-socket-address = tuple<u16, u16, u16, u16, u16, u16, u16, u16, u16, u16>
5+
6+
connect: func(
7+
local-address: ipv6-socket-address,
8+
remote-address: ipv6-socket-address,
9+
) -> tuple<u32, u32>
10+
}
11+
12+
default world wasi {
13+
import tcp: self.tcp
14+
}

0 commit comments

Comments
 (0)