Skip to content

Commit 1e00529

Browse files
authored
preserve cabi_post_ exports when appropriate (#965)
* preserve `cabi_post_` exports when appropriate Also, consider `canonical_abi_realloc` import equivalent to `cabi_realloc` when scanning adapter imports. This helps when adapting older modules. Signed-off-by: Joel Dice <joel.dice@fermyon.com> * add `adapt-export-with-post-return` test Signed-off-by: Joel Dice <joel.dice@fermyon.com> --------- Signed-off-by: Joel Dice <joel.dice@fermyon.com>
1 parent 7108f55 commit 1e00529

7 files changed

Lines changed: 161 additions & 1 deletion

File tree

crates/wit-component/src/gc.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@ pub fn run(
3535
}
3636
let mut not_required = IndexSet::new();
3737
for name in module.exports.keys().copied() {
38+
// If we need `name` then we also need cabi_post_`name`:
39+
let name = if let Some(suffix) = name.strip_prefix("cabi_post_") {
40+
suffix
41+
} else {
42+
name
43+
};
44+
3845
if !required.contains_key(name) && !always_keep(name) {
3946
not_required.insert(name);
4047
}
@@ -620,7 +627,8 @@ impl<'a> Module<'a> {
620627
// afterwards actually map the body of all functions so the `map` of all
621628
// index mappings is fully populated before instructions are mapped.
622629

623-
let is_realloc = |m, n| m == "__main_module__" && n == "cabi_realloc";
630+
let is_realloc =
631+
|m, n| m == "__main_module__" && matches!(n, "canonical_abi_realloc" | "cabi_realloc");
624632

625633
let (imported, local) =
626634
self.live_funcs()
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
;; This example represents adapting modules which use an early version of the
2+
;; canonical ABI, back when `cabi_realloc` was named `canonical_abi_realloc` and
3+
;; had a friend named `canonical_abi_free`. Such modules are pretty easy to
4+
;; adapt since the adapter can use the main module's allocator for both lowering
5+
;; and post-return functions.
6+
;;
7+
;; See https://github.com/fermyon/spin-componentize for a real-world example.
8+
9+
(module
10+
(import "__main_module__" "canonical_abi_realloc" (func $realloc (param i32 i32 i32 i32) (result i32)))
11+
(import "__main_module__" "canonical_abi_free" (func $free (param i32 i32 i32)))
12+
(import "env" "memory" (memory 0))
13+
(global $__stack_pointer (mut i32) i32.const 0)
14+
(global $allocation_state (mut i32) i32.const 0)
15+
16+
(func (export "new#foo") (result i32)
17+
;; This is a dummy, non-working implementation, just to make gc.rs do what
18+
;; we want, which is to treat this adapter as if it uses the main module's
19+
;; allocator to allocate and free memory.
20+
21+
global.get $__stack_pointer
22+
global.get $allocation_state
23+
(call $realloc (i32.const 0) (i32.const 0) (i32.const 0) (i32.const 0))
24+
unreachable
25+
)
26+
27+
(func (export "cabi_post_new#foo") (param i32)
28+
;; another dummy implementation
29+
30+
(call $free (i32.const 0) (i32.const 0) (i32.const 0))
31+
unreachable
32+
)
33+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface new {
2+
foo: func() -> string
3+
}
4+
5+
default world brave-new-world {
6+
export new: self.new
7+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
(component
2+
(core module (;0;)
3+
(type (;0;) (func (param i32 i32 i32 i32) (result i32)))
4+
(type (;1;) (func (param i32 i32 i32)))
5+
(func (;0;) (type 0) (param i32 i32 i32 i32) (result i32)
6+
unreachable
7+
)
8+
(func (;1;) (type 1) (param i32 i32 i32)
9+
unreachable
10+
)
11+
(memory (;0;) 1)
12+
(export "canonical_abi_realloc" (func 0))
13+
(export "canonical_abi_free" (func 1))
14+
(export "memory" (memory 0))
15+
)
16+
(core module (;1;)
17+
(type (;0;) (func (param i32 i32 i32 i32) (result i32)))
18+
(type (;1;) (func (param i32 i32 i32)))
19+
(type (;2;) (func (result i32)))
20+
(type (;3;) (func (param i32)))
21+
(type (;4;) (func))
22+
(import "__main_module__" "canonical_abi_realloc" (func $realloc (;0;) (type 0)))
23+
(import "__main_module__" "canonical_abi_free" (func $free (;1;) (type 1)))
24+
(func (;2;) (type 2) (result i32)
25+
call $allocate_stack
26+
global.get $__stack_pointer
27+
global.get $allocation_state
28+
i32.const 0
29+
i32.const 0
30+
i32.const 0
31+
i32.const 0
32+
call $realloc
33+
unreachable
34+
)
35+
(func (;3;) (type 3) (param i32)
36+
call $allocate_stack
37+
i32.const 0
38+
i32.const 0
39+
i32.const 0
40+
call $free
41+
unreachable
42+
)
43+
(func $allocate_stack (;4;) (type 4)
44+
global.get $allocation_state
45+
i32.const 0
46+
i32.eq
47+
if ;; label = @1
48+
i32.const 1
49+
global.set $allocation_state
50+
i32.const 0
51+
i32.const 0
52+
i32.const 8
53+
i32.const 65536
54+
call $realloc
55+
i32.const 65536
56+
i32.add
57+
global.set $__stack_pointer
58+
i32.const 2
59+
global.set $allocation_state
60+
end
61+
)
62+
(global $__stack_pointer (;0;) (mut i32) i32.const 0)
63+
(global $allocation_state (;1;) (mut i32) i32.const 0)
64+
(export "new#foo" (func 2))
65+
(export "cabi_post_new#foo" (func 3))
66+
)
67+
(core instance (;0;) (instantiate 0))
68+
(alias core export 0 "memory" (core memory (;0;)))
69+
(alias core export 0 "canonical_abi_realloc" (core func (;0;)))
70+
(alias core export 0 "canonical_abi_realloc" (core func (;1;)))
71+
(alias core export 0 "canonical_abi_free" (core func (;2;)))
72+
(core instance (;1;)
73+
(export "canonical_abi_realloc" (func 1))
74+
(export "canonical_abi_free" (func 2))
75+
)
76+
(core instance (;2;) (instantiate 1
77+
(with "__main_module__" (instance 1))
78+
)
79+
)
80+
(type (;0;) (func (result string)))
81+
(alias core export 2 "new#foo" (core func (;3;)))
82+
(alias core export 2 "cabi_post_new#foo" (core func (;4;)))
83+
(func (;0;) (type 0) (canon lift (core func 3) (memory 0) string-encoding=utf8 (post-return 4)))
84+
(component (;0;)
85+
(alias outer 1 0 (type (;0;)))
86+
(import "import-foo" (func (;0;) (type 0)))
87+
(type (;1;) (func (result string)))
88+
(export (;1;) "foo" (func 0) (func (type 1)))
89+
)
90+
(instance (;0;) (instantiate 0
91+
(with "import-foo" (func 0))
92+
)
93+
)
94+
(export (;1;) "new" (instance 0))
95+
)
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
interface new {
2+
foo: func() -> string
3+
}
4+
5+
default world component {
6+
export new: self.new
7+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
(module
2+
(func (export "canonical_abi_realloc") (param i32 i32 i32 i32) (result i32)
3+
unreachable
4+
)
5+
(func (export "canonical_abi_free") (param i32 i32 i32)
6+
unreachable
7+
)
8+
(memory (export "memory") 1)
9+
)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
default world foo {}

0 commit comments

Comments
 (0)