1 use anyhow::Result;
2 use component_test_util::{async_engine, engine, TypedFuncExt};
3 use std::fmt::Write;
4 use std::iter;
5 use wasmtime::component::Component;
6 use wasmtime_component_util::REALLOC_AND_FREE;
7 
8 mod aot;
9 mod r#async;
10 mod bindgen;
11 mod dynamic;
12 mod func;
13 mod import;
14 mod instance;
15 mod linker;
16 mod macros;
17 mod nested;
18 mod post_return;
19 mod resources;
20 mod strings;
21 
22 #[test]
23 #[cfg_attr(miri, ignore)]
24 fn components_importing_modules() -> Result<()> {
25     let engine = engine();
26 
27     // FIXME: these components should actually get instantiated in `*.wast`
28     // tests once supplying imports has actually been implemented.
29 
30     Component::new(
31         &engine,
32         r#"
33         (component
34             (import "a" (core module))
35         )
36         "#,
37     )?;
38 
39     Component::new(
40         &engine,
41         r#"
42         (component
43             (import "a" (core module $m1
44                 (import "" "" (func))
45                 (import "" "x" (global i32))
46 
47                 (export "a" (table 1 funcref))
48                 (export "b" (memory 1))
49                 (export "c" (func (result f32)))
50                 (export "d" (global i64))
51             ))
52 
53             (core module $m2
54                 (func (export ""))
55                 (global (export "x") i32 i32.const 0)
56             )
57             (core instance $i2 (instantiate (module $m2)))
58             (core instance $i1 (instantiate (module $m1) (with "" (instance $i2))))
59 
60             (core module $m3
61                 (import "mod" "1" (memory 1))
62                 (import "mod" "2" (table 1 funcref))
63                 (import "mod" "3" (global i64))
64                 (import "mod" "4" (func (result f32)))
65             )
66 
67             (core instance $i3 (instantiate (module $m3)
68                 (with "mod" (instance
69                     (export "1" (memory $i1 "b"))
70                     (export "2" (table $i1 "a"))
71                     (export "3" (global $i1 "d"))
72                     (export "4" (func $i1 "c"))
73                 ))
74             ))
75         )
76         "#,
77     )?;
78 
79     Ok(())
80 }
81 
82 #[derive(Copy, Clone, PartialEq, Eq)]
83 enum Type {
84     S8,
85     U8,
86     S16,
87     U16,
88     I32,
89     I64,
90     F32,
91     F64,
92 }
93 
94 impl Type {
95     fn store(&self) -> &'static str {
96         match self {
97             Self::S8 | Self::U8 => "store8",
98             Self::S16 | Self::U16 => "store16",
99             Self::I32 | Self::F32 | Self::I64 | Self::F64 => "store",
100         }
101     }
102 
103     fn primitive(&self) -> &'static str {
104         match self {
105             Self::S8 | Self::U8 | Self::S16 | Self::U16 | Self::I32 => "i32",
106             Self::I64 => "i64",
107             Self::F32 => "f32",
108             Self::F64 => "f64",
109         }
110     }
111 }
112 
113 #[derive(Copy, Clone, PartialEq, Eq)]
114 struct Param(Type, Option<usize>);
115 
116 fn make_echo_component(type_definition: &str, type_size: u32) -> String {
117     let mut offset = 0;
118     make_echo_component_with_params(
119         type_definition,
120         &iter::repeat(Type::I32)
121             .map(|ty| {
122                 let param = Param(ty, Some(offset));
123                 offset += 4;
124                 param
125             })
126             .take(usize::try_from(type_size).unwrap() / 4)
127             .collect::<Vec<_>>(),
128     )
129 }
130 
131 fn make_echo_component_with_params(type_definition: &str, params: &[Param]) -> String {
132     let func = if params.len() == 0 {
133         format!("(func (export \"echo\"))")
134     } else if params.len() == 1 || params.len() > 16 {
135         let primitive = if params.len() == 1 {
136             params[0].0.primitive()
137         } else {
138             "i32"
139         };
140 
141         format!(
142             r#"
143             (func (export "echo") (param {primitive}) (result {primitive})
144                  local.get 0
145             )"#,
146         )
147     } else {
148         let mut param_string = String::new();
149         let mut store = String::new();
150         let mut size = 8;
151 
152         for (index, Param(ty, offset)) in params.iter().enumerate() {
153             let primitive = ty.primitive();
154 
155             write!(&mut param_string, " {primitive}").unwrap();
156             if let Some(offset) = offset {
157                 write!(
158                     &mut store,
159                     "({primitive}.{} offset={offset} (local.get $base) (local.get {index}))",
160                     ty.store(),
161                 )
162                 .unwrap();
163 
164                 size = size.max(offset + 8);
165             }
166         }
167 
168         format!(
169             r#"
170             (func (export "echo") (param{param_string}) (result i32)
171                 (local $base i32)
172                 (local.set $base
173                     (call $realloc
174                         (i32.const 0)
175                         (i32.const 0)
176                         (i32.const 4)
177                         (i32.const {size})))
178                 {store}
179                 local.get $base
180             )"#
181         )
182     };
183 
184     let type_section = if type_definition.contains("(type ") {
185         type_definition.to_string()
186     } else {
187         format!("(type $Foo' {type_definition})")
188     };
189 
190     format!(
191         r#"
192         (component
193             (core module $m
194                 {func}
195 
196                 (memory (export "memory") 1)
197                 {REALLOC_AND_FREE}
198             )
199 
200             (core instance $i (instantiate $m))
201 
202             {type_section}
203             (export $Foo "foo" (type $Foo'))
204 
205             (func (export "echo") (param "a" $Foo) (result "b" $Foo)
206                 (canon lift
207                     (core func $i "echo")
208                     (memory $i "memory")
209                     (realloc (func $i "realloc"))
210                 )
211             )
212         )"#
213     )
214 }
215