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