1 //! Dummy implementations of things that a Wasm module can import. 2 3 use anyhow::Result; 4 use std::fmt::Write; 5 use wasmtime::*; 6 7 /// Create a set of dummy functions/globals/etc for the given imports. 8 pub fn dummy_linker<'module, T>(store: &mut Store<T>, module: &Module) -> Result<Linker<T>> { 9 let mut linker = Linker::new(store.engine()); 10 linker.allow_shadowing(true); 11 for import in module.imports() { 12 match import.name() { 13 Some(name) => { 14 linker 15 .define(import.module(), name, dummy_extern(store, import.ty())?) 16 .unwrap(); 17 } 18 None => match import.ty() { 19 ExternType::Instance(ty) => { 20 for ty in ty.exports() { 21 linker 22 .define(import.module(), ty.name(), dummy_extern(store, ty.ty())?) 23 .unwrap(); 24 } 25 } 26 other => { 27 linker 28 .define_name(import.module(), dummy_extern(store, other)?) 29 .unwrap(); 30 } 31 }, 32 } 33 } 34 Ok(linker) 35 } 36 37 /// Construct a dummy `Extern` from its type signature 38 pub fn dummy_extern<T>(store: &mut Store<T>, ty: ExternType) -> Result<Extern> { 39 Ok(match ty { 40 ExternType::Func(func_ty) => Extern::Func(dummy_func(store, func_ty)), 41 ExternType::Global(global_ty) => Extern::Global(dummy_global(store, global_ty)), 42 ExternType::Table(table_ty) => Extern::Table(dummy_table(store, table_ty)?), 43 ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(store, mem_ty)?), 44 ExternType::Instance(instance_ty) => Extern::Instance(dummy_instance(store, instance_ty)?), 45 ExternType::Module(module_ty) => Extern::Module(dummy_module(store.engine(), module_ty)), 46 }) 47 } 48 49 /// Construct a dummy function for the given function type 50 pub fn dummy_func<T>(store: &mut Store<T>, ty: FuncType) -> Func { 51 Func::new(store, ty.clone(), move |_, _, results| { 52 for (ret_ty, result) in ty.results().zip(results) { 53 *result = dummy_value(ret_ty); 54 } 55 Ok(()) 56 }) 57 } 58 59 /// Construct a dummy value for the given value type. 60 pub fn dummy_value(val_ty: ValType) -> Val { 61 match val_ty { 62 ValType::I32 => Val::I32(0), 63 ValType::I64 => Val::I64(0), 64 ValType::F32 => Val::F32(0), 65 ValType::F64 => Val::F64(0), 66 ValType::V128 => Val::V128(0), 67 ValType::ExternRef => Val::ExternRef(None), 68 ValType::FuncRef => Val::FuncRef(None), 69 } 70 } 71 72 /// Construct a sequence of dummy values for the given types. 73 pub fn dummy_values(val_tys: impl IntoIterator<Item = ValType>) -> Vec<Val> { 74 val_tys.into_iter().map(dummy_value).collect() 75 } 76 77 /// Construct a dummy global for the given global type. 78 pub fn dummy_global<T>(store: &mut Store<T>, ty: GlobalType) -> Global { 79 let val = dummy_value(ty.content().clone()); 80 Global::new(store, ty, val).unwrap() 81 } 82 83 /// Construct a dummy table for the given table type. 84 pub fn dummy_table<T>(store: &mut Store<T>, ty: TableType) -> Result<Table> { 85 let init_val = dummy_value(ty.element().clone()); 86 Table::new(store, ty, init_val) 87 } 88 89 /// Construct a dummy memory for the given memory type. 90 pub fn dummy_memory<T>(store: &mut Store<T>, ty: MemoryType) -> Result<Memory> { 91 Memory::new(store, ty) 92 } 93 94 /// Construct a dummy instance for the given instance type. 95 /// 96 /// This is done by using the expected type to generate a module on-the-fly 97 /// which we the instantiate. 98 pub fn dummy_instance<T>(store: &mut Store<T>, ty: InstanceType) -> Result<Instance> { 99 let mut wat = WatGenerator::new(); 100 for ty in ty.exports() { 101 wat.export(&ty); 102 } 103 let module = Module::new(store.engine(), &wat.finish()).unwrap(); 104 Instance::new(store, &module, &[]) 105 } 106 107 /// Construct a dummy module for the given module type. 108 /// 109 /// This is done by using the expected type to generate a module on-the-fly. 110 pub fn dummy_module(engine: &Engine, ty: ModuleType) -> Module { 111 let mut wat = WatGenerator::new(); 112 for ty in ty.imports() { 113 wat.import(&ty); 114 } 115 for ty in ty.exports() { 116 wat.export(&ty); 117 } 118 Module::new(engine, &wat.finish()).unwrap() 119 } 120 121 struct WatGenerator { 122 tmp: usize, 123 dst: String, 124 } 125 126 impl WatGenerator { 127 fn new() -> WatGenerator { 128 WatGenerator { 129 tmp: 0, 130 dst: String::from("(module\n"), 131 } 132 } 133 134 fn finish(mut self) -> String { 135 self.dst.push_str(")\n"); 136 self.dst 137 } 138 139 fn import(&mut self, ty: &ImportType<'_>) { 140 write!(self.dst, "(import ").unwrap(); 141 self.str(ty.module()); 142 write!(self.dst, " ").unwrap(); 143 if let Some(field) = ty.name() { 144 self.str(field); 145 write!(self.dst, " ").unwrap(); 146 } 147 self.item_ty(&ty.ty()); 148 writeln!(self.dst, ")").unwrap(); 149 } 150 151 fn item_ty(&mut self, ty: &ExternType) { 152 match ty { 153 ExternType::Memory(mem) => { 154 write!( 155 self.dst, 156 "(memory {} {})", 157 mem.limits().min(), 158 match mem.limits().max() { 159 Some(max) => max.to_string(), 160 None => String::new(), 161 } 162 ) 163 .unwrap(); 164 } 165 ExternType::Table(table) => { 166 write!( 167 self.dst, 168 "(table {} {} {})", 169 table.limits().min(), 170 match table.limits().max() { 171 Some(max) => max.to_string(), 172 None => String::new(), 173 }, 174 wat_ty(table.element()), 175 ) 176 .unwrap(); 177 } 178 ExternType::Global(ty) => { 179 if ty.mutability() == Mutability::Const { 180 write!(self.dst, "(global {})", wat_ty(ty.content())).unwrap(); 181 } else { 182 write!(self.dst, "(global (mut {}))", wat_ty(ty.content())).unwrap(); 183 } 184 } 185 ExternType::Func(ty) => { 186 write!(self.dst, "(func ").unwrap(); 187 self.func_sig(ty); 188 write!(self.dst, ")").unwrap(); 189 } 190 ExternType::Instance(ty) => { 191 writeln!(self.dst, "(instance").unwrap(); 192 for ty in ty.exports() { 193 write!(self.dst, "(export ").unwrap(); 194 self.str(ty.name()); 195 write!(self.dst, " ").unwrap(); 196 self.item_ty(&ty.ty()); 197 writeln!(self.dst, ")").unwrap(); 198 } 199 write!(self.dst, ")").unwrap(); 200 } 201 ExternType::Module(ty) => { 202 writeln!(self.dst, "(module").unwrap(); 203 for ty in ty.imports() { 204 self.import(&ty); 205 writeln!(self.dst, "").unwrap(); 206 } 207 for ty in ty.exports() { 208 write!(self.dst, "(export ").unwrap(); 209 self.str(ty.name()); 210 write!(self.dst, " ").unwrap(); 211 self.item_ty(&ty.ty()); 212 writeln!(self.dst, ")").unwrap(); 213 } 214 write!(self.dst, ")").unwrap(); 215 } 216 } 217 } 218 219 fn export(&mut self, ty: &ExportType<'_>) { 220 let wat_name = format!("item{}", self.tmp); 221 self.tmp += 1; 222 let item_ty = ty.ty(); 223 self.item(&wat_name, &item_ty); 224 225 write!(self.dst, "(export ").unwrap(); 226 self.str(ty.name()); 227 write!(self.dst, " (").unwrap(); 228 match item_ty { 229 ExternType::Memory(_) => write!(self.dst, "memory").unwrap(), 230 ExternType::Global(_) => write!(self.dst, "global").unwrap(), 231 ExternType::Func(_) => write!(self.dst, "func").unwrap(), 232 ExternType::Instance(_) => write!(self.dst, "instance").unwrap(), 233 ExternType::Table(_) => write!(self.dst, "table").unwrap(), 234 ExternType::Module(_) => write!(self.dst, "module").unwrap(), 235 } 236 writeln!(self.dst, " ${}))", wat_name).unwrap(); 237 } 238 239 fn item(&mut self, name: &str, ty: &ExternType) { 240 match ty { 241 ExternType::Memory(mem) => { 242 write!( 243 self.dst, 244 "(memory ${} {} {})\n", 245 name, 246 mem.limits().min(), 247 match mem.limits().max() { 248 Some(max) => max.to_string(), 249 None => String::new(), 250 } 251 ) 252 .unwrap(); 253 } 254 ExternType::Table(table) => { 255 write!( 256 self.dst, 257 "(table ${} {} {} {})\n", 258 name, 259 table.limits().min(), 260 match table.limits().max() { 261 Some(max) => max.to_string(), 262 None => String::new(), 263 }, 264 wat_ty(table.element()), 265 ) 266 .unwrap(); 267 } 268 ExternType::Global(ty) => { 269 write!(self.dst, "(global ${} ", name).unwrap(); 270 if ty.mutability() == Mutability::Var { 271 write!(self.dst, "(mut ").unwrap(); 272 } 273 write!(self.dst, "{}", wat_ty(ty.content())).unwrap(); 274 if ty.mutability() == Mutability::Var { 275 write!(self.dst, ")").unwrap(); 276 } 277 write!(self.dst, " (").unwrap(); 278 self.value(ty.content()); 279 writeln!(self.dst, "))").unwrap(); 280 } 281 ExternType::Func(ty) => { 282 write!(self.dst, "(func ${} ", name).unwrap(); 283 self.func_sig(ty); 284 for ty in ty.results() { 285 writeln!(self.dst, "").unwrap(); 286 self.value(&ty); 287 } 288 writeln!(self.dst, ")").unwrap(); 289 } 290 ExternType::Module(ty) => { 291 writeln!(self.dst, "(module ${}", name).unwrap(); 292 for ty in ty.imports() { 293 self.import(&ty); 294 } 295 for ty in ty.exports() { 296 self.export(&ty); 297 } 298 self.dst.push_str(")\n"); 299 } 300 ExternType::Instance(ty) => { 301 writeln!(self.dst, "(module ${}_module", name).unwrap(); 302 for ty in ty.exports() { 303 self.export(&ty); 304 } 305 self.dst.push_str(")\n"); 306 writeln!(self.dst, "(instance ${} (instantiate ${0}_module))", name).unwrap(); 307 } 308 } 309 } 310 311 fn func_sig(&mut self, ty: &FuncType) { 312 write!(self.dst, "(param ").unwrap(); 313 for ty in ty.params() { 314 write!(self.dst, "{} ", wat_ty(&ty)).unwrap(); 315 } 316 write!(self.dst, ") (result ").unwrap(); 317 for ty in ty.results() { 318 write!(self.dst, "{} ", wat_ty(&ty)).unwrap(); 319 } 320 write!(self.dst, ")").unwrap(); 321 } 322 323 fn value(&mut self, ty: &ValType) { 324 match ty { 325 ValType::I32 => write!(self.dst, "i32.const 0").unwrap(), 326 ValType::I64 => write!(self.dst, "i64.const 0").unwrap(), 327 ValType::F32 => write!(self.dst, "f32.const 0").unwrap(), 328 ValType::F64 => write!(self.dst, "f64.const 0").unwrap(), 329 ValType::V128 => write!(self.dst, "v128.const i32x4 0 0 0 0").unwrap(), 330 ValType::ExternRef => write!(self.dst, "ref.null extern").unwrap(), 331 ValType::FuncRef => write!(self.dst, "ref.null func").unwrap(), 332 } 333 } 334 335 fn str(&mut self, name: &str) { 336 let mut bytes = [0; 4]; 337 self.dst.push_str("\""); 338 for c in name.chars() { 339 let v = c as u32; 340 if v >= 0x20 && v < 0x7f && c != '"' && c != '\\' && v < 0xff { 341 self.dst.push(c); 342 } else { 343 for byte in c.encode_utf8(&mut bytes).as_bytes() { 344 self.hex_byte(*byte); 345 } 346 } 347 } 348 self.dst.push_str("\""); 349 } 350 351 fn hex_byte(&mut self, byte: u8) { 352 fn to_hex(b: u8) -> char { 353 if b < 10 { 354 (b'0' + b) as char 355 } else { 356 (b'a' + b - 10) as char 357 } 358 } 359 self.dst.push('\\'); 360 self.dst.push(to_hex((byte >> 4) & 0xf)); 361 self.dst.push(to_hex(byte & 0xf)); 362 } 363 } 364 365 fn wat_ty(ty: &ValType) -> &'static str { 366 match ty { 367 ValType::I32 => "i32", 368 ValType::I64 => "i64", 369 ValType::F32 => "f32", 370 ValType::F64 => "f64", 371 ValType::V128 => "v128", 372 ValType::ExternRef => "externref", 373 ValType::FuncRef => "funcref", 374 } 375 } 376 377 #[cfg(test)] 378 mod tests { 379 use super::*; 380 use std::collections::HashSet; 381 382 fn store() -> Store<()> { 383 let mut config = Config::default(); 384 config.wasm_module_linking(true); 385 config.wasm_multi_memory(true); 386 let engine = wasmtime::Engine::new(&config).unwrap(); 387 Store::new(&engine, ()) 388 } 389 390 #[test] 391 fn dummy_table_import() { 392 let mut store = store(); 393 let table = dummy_table( 394 &mut store, 395 TableType::new(ValType::ExternRef, Limits::at_least(10)), 396 ) 397 .unwrap(); 398 assert_eq!(table.size(&store), 10); 399 for i in 0..10 { 400 assert!(table 401 .get(&mut store, i) 402 .unwrap() 403 .unwrap_externref() 404 .is_none()); 405 } 406 } 407 408 #[test] 409 fn dummy_global_import() { 410 let mut store = store(); 411 let global = dummy_global(&mut store, GlobalType::new(ValType::I32, Mutability::Const)); 412 assert_eq!(*global.ty(&store).content(), ValType::I32); 413 assert_eq!(global.ty(&store).mutability(), Mutability::Const); 414 } 415 416 #[test] 417 fn dummy_memory_import() { 418 let mut store = store(); 419 let memory = dummy_memory(&mut store, MemoryType::new(Limits::at_least(1))).unwrap(); 420 assert_eq!(memory.size(&store), 1); 421 } 422 423 #[test] 424 fn dummy_function_import() { 425 let mut store = store(); 426 let func_ty = FuncType::new(vec![ValType::I32], vec![ValType::I64]); 427 let func = dummy_func(&mut store, func_ty.clone()); 428 assert_eq!(func.ty(&store), func_ty); 429 } 430 431 #[test] 432 fn dummy_instance_import() { 433 let mut store = store(); 434 435 let mut instance_ty = InstanceType::new(); 436 437 // Functions. 438 instance_ty.add_named_export("func0", FuncType::new(vec![ValType::I32], vec![]).into()); 439 instance_ty.add_named_export("func1", FuncType::new(vec![], vec![ValType::I64]).into()); 440 441 // Globals. 442 instance_ty.add_named_export( 443 "global0", 444 GlobalType::new(ValType::I32, Mutability::Const).into(), 445 ); 446 instance_ty.add_named_export( 447 "global1", 448 GlobalType::new(ValType::I64, Mutability::Var).into(), 449 ); 450 451 // Tables. 452 instance_ty.add_named_export( 453 "table0", 454 TableType::new(ValType::ExternRef, Limits::at_least(1)).into(), 455 ); 456 instance_ty.add_named_export( 457 "table1", 458 TableType::new(ValType::ExternRef, Limits::at_least(1)).into(), 459 ); 460 461 // Memories. 462 instance_ty.add_named_export("memory0", MemoryType::new(Limits::at_least(1)).into()); 463 instance_ty.add_named_export("memory1", MemoryType::new(Limits::at_least(1)).into()); 464 465 // Modules. 466 instance_ty.add_named_export("module0", ModuleType::new().into()); 467 instance_ty.add_named_export("module1", ModuleType::new().into()); 468 469 // Instances. 470 instance_ty.add_named_export("instance0", InstanceType::new().into()); 471 instance_ty.add_named_export("instance1", InstanceType::new().into()); 472 473 let instance = dummy_instance(&mut store, instance_ty.clone()).unwrap(); 474 475 let mut expected_exports = vec![ 476 "func0", 477 "func1", 478 "global0", 479 "global1", 480 "table0", 481 "table1", 482 "memory0", 483 "memory1", 484 "module0", 485 "module1", 486 "instance0", 487 "instance1", 488 ] 489 .into_iter() 490 .collect::<HashSet<_>>(); 491 for exp in instance.ty(&store).exports() { 492 let was_expected = expected_exports.remove(exp.name()); 493 assert!(was_expected); 494 } 495 assert!(expected_exports.is_empty()); 496 } 497 498 #[test] 499 fn dummy_module_import() { 500 let store = store(); 501 502 let mut module_ty = ModuleType::new(); 503 504 // Multiple exported and imported functions. 505 module_ty.add_named_export("func0", FuncType::new(vec![ValType::I32], vec![]).into()); 506 module_ty.add_named_export("func1", FuncType::new(vec![], vec![ValType::I64]).into()); 507 module_ty.add_named_import( 508 "func2", 509 None, 510 FuncType::new(vec![ValType::I64], vec![]).into(), 511 ); 512 module_ty.add_named_import( 513 "func3", 514 None, 515 FuncType::new(vec![], vec![ValType::I32]).into(), 516 ); 517 518 // Multiple exported and imported globals. 519 module_ty.add_named_export( 520 "global0", 521 GlobalType::new(ValType::I32, Mutability::Const).into(), 522 ); 523 module_ty.add_named_export( 524 "global1", 525 GlobalType::new(ValType::I64, Mutability::Var).into(), 526 ); 527 module_ty.add_named_import( 528 "global2", 529 None, 530 GlobalType::new(ValType::I32, Mutability::Var).into(), 531 ); 532 module_ty.add_named_import( 533 "global3", 534 None, 535 GlobalType::new(ValType::I64, Mutability::Const).into(), 536 ); 537 538 // Multiple exported and imported tables. 539 module_ty.add_named_export( 540 "table0", 541 TableType::new(ValType::ExternRef, Limits::at_least(1)).into(), 542 ); 543 module_ty.add_named_export( 544 "table1", 545 TableType::new(ValType::ExternRef, Limits::at_least(1)).into(), 546 ); 547 module_ty.add_named_import( 548 "table2", 549 None, 550 TableType::new(ValType::ExternRef, Limits::at_least(1)).into(), 551 ); 552 module_ty.add_named_import( 553 "table3", 554 None, 555 TableType::new(ValType::ExternRef, Limits::at_least(1)).into(), 556 ); 557 558 // Multiple exported and imported memories. 559 module_ty.add_named_export("memory0", MemoryType::new(Limits::at_least(1)).into()); 560 module_ty.add_named_export("memory1", MemoryType::new(Limits::at_least(1)).into()); 561 module_ty.add_named_import("memory2", None, MemoryType::new(Limits::at_least(1)).into()); 562 module_ty.add_named_import("memory3", None, MemoryType::new(Limits::at_least(1)).into()); 563 564 // An exported and an imported module. 565 module_ty.add_named_export("module0", ModuleType::new().into()); 566 module_ty.add_named_import("module1", None, ModuleType::new().into()); 567 568 // An exported and an imported instance. 569 module_ty.add_named_export("instance0", InstanceType::new().into()); 570 module_ty.add_named_import("instance1", None, InstanceType::new().into()); 571 572 // Create the module. 573 let module = dummy_module(store.engine(), module_ty); 574 575 // Check that we have the expected exports. 576 assert!(module.get_export("func0").is_some()); 577 assert!(module.get_export("func1").is_some()); 578 assert!(module.get_export("global0").is_some()); 579 assert!(module.get_export("global1").is_some()); 580 assert!(module.get_export("table0").is_some()); 581 assert!(module.get_export("table1").is_some()); 582 assert!(module.get_export("memory0").is_some()); 583 assert!(module.get_export("memory1").is_some()); 584 assert!(module.get_export("instance0").is_some()); 585 assert!(module.get_export("module0").is_some()); 586 587 // Check that we have the exported imports. 588 let mut expected_imports = vec![ 589 "func2", 590 "func3", 591 "global2", 592 "global3", 593 "table2", 594 "table3", 595 "memory2", 596 "memory3", 597 "instance1", 598 "module1", 599 ] 600 .into_iter() 601 .collect::<HashSet<_>>(); 602 for imp in module.imports() { 603 assert!(imp.name().is_none()); 604 let was_expected = expected_imports.remove(imp.module()); 605 assert!(was_expected); 606 } 607 assert!(expected_imports.is_empty()); 608 } 609 } 610