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