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