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