1 use crate::component::matching::InstanceType; 2 use crate::component::types; 3 use crate::prelude::*; 4 use crate::runtime::vm::component::ComponentRuntimeInfo; 5 use crate::runtime::vm::{ 6 VMArrayCallFunction, VMFuncRef, VMFunctionBody, VMNativeCallFunction, VMWasmCallFunction, 7 }; 8 use crate::{ 9 code::CodeObject, code_memory::CodeMemory, type_registry::TypeCollection, Engine, Module, 10 ResourcesRequired, 11 }; 12 use crate::{FuncType, ValType}; 13 use alloc::sync::Arc; 14 use anyhow::Result; 15 use core::any::Any; 16 use core::mem; 17 use core::ops::Range; 18 use core::ptr::NonNull; 19 #[cfg(feature = "std")] 20 use std::path::Path; 21 use wasmtime_environ::component::{ 22 AllCallFunc, CompiledComponentInfo, ComponentArtifacts, ComponentTypes, GlobalInitializer, 23 InstantiateModule, StaticModuleIndex, TrampolineIndex, TypeComponentIndex, VMComponentOffsets, 24 }; 25 use wasmtime_environ::{FunctionLoc, HostPtr, ObjectKind, PrimaryMap}; 26 27 /// A compiled WebAssembly Component. 28 /// 29 /// This structure represents a compiled component that is ready to be 30 /// instantiated. This owns a region of virtual memory which contains executable 31 /// code compiled from a WebAssembly binary originally. This is the analog of 32 /// [`Module`](crate::Module) in the component embedding API. 33 /// 34 /// A [`Component`] can be turned into an 35 /// [`Instance`](crate::component::Instance) through a 36 /// [`Linker`](crate::component::Linker). [`Component`]s are safe to share 37 /// across threads. The compilation model of a component is the same as that of 38 /// [a module](crate::Module) which is to say: 39 /// 40 /// * Compilation happens synchronously during [`Component::new`]. 41 /// * The result of compilation can be saved into storage with 42 /// [`Component::serialize`]. 43 /// * A previously compiled artifact can be parsed with 44 /// [`Component::deserialize`]. 45 /// * No compilation happens at runtime for a component — everything is done 46 /// by the time [`Component::new`] returns. 47 /// 48 /// ## Components and `Clone` 49 /// 50 /// Using `clone` on a `Component` is a cheap operation. It will not create an 51 /// entirely new component, but rather just a new reference to the existing 52 /// component. In other words it's a shallow copy, not a deep copy. 53 /// 54 /// ## Examples 55 /// 56 /// For example usage see the documentation of [`Module`](crate::Module) as 57 /// [`Component`] has the same high-level API. 58 #[derive(Clone)] 59 pub struct Component { 60 inner: Arc<ComponentInner>, 61 } 62 63 struct ComponentInner { 64 /// Component type index 65 ty: TypeComponentIndex, 66 67 /// Core wasm modules that the component defined internally, indexed by the 68 /// compile-time-assigned `ModuleUpvarIndex`. 69 static_modules: PrimaryMap<StaticModuleIndex, Module>, 70 71 /// Code-related information such as the compiled artifact, type 72 /// information, etc. 73 /// 74 /// Note that the `Arc` here is used to share this allocation with internal 75 /// modules. 76 code: Arc<CodeObject>, 77 78 /// Metadata produced during compilation. 79 info: CompiledComponentInfo, 80 81 /// A cached handle to the `wasmtime::FuncType` for the canonical ABI's 82 /// `realloc`, to avoid the need to look up types in the registry and take 83 /// locks when calling `realloc` via `TypedFunc::call_raw`. 84 realloc_func_type: Arc<dyn Any + Send + Sync>, 85 } 86 87 pub(crate) struct AllCallFuncPointers { 88 pub wasm_call: NonNull<VMWasmCallFunction>, 89 pub array_call: VMArrayCallFunction, 90 pub native_call: NonNull<VMNativeCallFunction>, 91 } 92 93 impl Component { 94 /// Compiles a new WebAssembly component from the in-memory list of bytes 95 /// provided. 96 /// 97 /// The `bytes` provided can either be the binary or text format of a 98 /// [WebAssembly component]. Note that the text format requires the `wat` 99 /// feature of this crate to be enabled. This API does not support 100 /// streaming compilation. 101 /// 102 /// This function will synchronously validate the entire component, 103 /// including all core modules, and then compile all components, modules, 104 /// etc., found within the provided bytes. 105 /// 106 /// [WebAssembly component]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md 107 /// 108 /// # Errors 109 /// 110 /// This function may fail and return an error. Errors may include 111 /// situations such as: 112 /// 113 /// * The binary provided could not be decoded because it's not a valid 114 /// WebAssembly binary 115 /// * The WebAssembly binary may not validate (e.g. contains type errors) 116 /// * Implementation-specific limits were exceeded with a valid binary (for 117 /// example too many locals) 118 /// * The wasm binary may use features that are not enabled in the 119 /// configuration of `engine` 120 /// * If the `wat` feature is enabled and the input is text, then it may be 121 /// rejected if it fails to parse. 122 /// 123 /// The error returned should contain full information about why compilation 124 /// failed. 125 /// 126 /// # Examples 127 /// 128 /// The `new` function can be invoked with a in-memory array of bytes: 129 /// 130 /// ```no_run 131 /// # use wasmtime::*; 132 /// # use wasmtime::component::Component; 133 /// # fn main() -> anyhow::Result<()> { 134 /// # let engine = Engine::default(); 135 /// # let wasm_bytes: Vec<u8> = Vec::new(); 136 /// let component = Component::new(&engine, &wasm_bytes)?; 137 /// # Ok(()) 138 /// # } 139 /// ``` 140 /// 141 /// Or you can also pass in a string to be parsed as the wasm text 142 /// format: 143 /// 144 /// ``` 145 /// # use wasmtime::*; 146 /// # use wasmtime::component::Component; 147 /// # fn main() -> anyhow::Result<()> { 148 /// # let engine = Engine::default(); 149 /// let component = Component::new(&engine, "(component (core module))")?; 150 /// # Ok(()) 151 /// # } 152 #[cfg(any(feature = "cranelift", feature = "winch"))] 153 pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> { 154 crate::CodeBuilder::new(engine) 155 .wasm(bytes.as_ref(), None)? 156 .compile_component() 157 } 158 159 /// Compiles a new WebAssembly component from a wasm file on disk pointed 160 /// to by `file`. 161 /// 162 /// This is a convenience function for reading the contents of `file` on 163 /// disk and then calling [`Component::new`]. 164 #[cfg(all(feature = "std", any(feature = "cranelift", feature = "winch")))] 165 pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Component> { 166 crate::CodeBuilder::new(engine) 167 .wasm_file(file.as_ref())? 168 .compile_component() 169 } 170 171 /// Compiles a new WebAssembly component from the in-memory wasm image 172 /// provided. 173 /// 174 /// This function is the same as [`Component::new`] except that it does not 175 /// accept the text format of WebAssembly. Even if the `wat` feature 176 /// is enabled an error will be returned here if `binary` is the text 177 /// format. 178 /// 179 /// For more information on semantics and errors see [`Component::new`]. 180 #[cfg(any(feature = "cranelift", feature = "winch"))] 181 pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component> { 182 crate::CodeBuilder::new(engine) 183 .wasm(binary, None)? 184 .wat(false)? 185 .compile_component() 186 } 187 188 /// Same as [`Module::deserialize`], but for components. 189 /// 190 /// Note that the bytes referenced here must contain contents previously 191 /// produced by [`Engine::precompile_component`] or 192 /// [`Component::serialize`]. 193 /// 194 /// For more information see the [`Module::deserialize`] method. 195 /// 196 /// # Unsafety 197 /// 198 /// The unsafety of this method is the same as that of the 199 /// [`Module::deserialize`] method. 200 /// 201 /// [`Module::deserialize`]: crate::Module::deserialize 202 pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> { 203 let code = engine.load_code_bytes(bytes.as_ref(), ObjectKind::Component)?; 204 Component::from_parts(engine, code, None) 205 } 206 207 /// Same as [`Module::deserialize_file`], but for components. 208 /// 209 /// Note that the file referenced here must contain contents previously 210 /// produced by [`Engine::precompile_component`] or 211 /// [`Component::serialize`]. 212 /// 213 /// For more information see the [`Module::deserialize_file`] method. 214 /// 215 /// # Unsafety 216 /// 217 /// The unsafety of this method is the same as that of the 218 /// [`Module::deserialize_file`] method. 219 /// 220 /// [`Module::deserialize_file`]: crate::Module::deserialize_file 221 #[cfg(feature = "std")] 222 pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Component> { 223 let code = engine.load_code_file(path.as_ref(), ObjectKind::Component)?; 224 Component::from_parts(engine, code, None) 225 } 226 227 /// Returns the type of this component as a [`types::Component`]. 228 /// 229 /// This method enables runtime introspection of the type of a component 230 /// before instantiation, if necessary. 231 /// 232 /// ## Component types and Resources 233 /// 234 /// An important point to note here is that the precise type of imports and 235 /// exports of a component change when it is instantiated with respect to 236 /// resources. For example a [`Component`] represents an un-instantiated 237 /// component meaning that its imported resources are represeted as abstract 238 /// resource types. These abstract types are not equal to any other 239 /// component's types. 240 /// 241 /// For example: 242 /// 243 /// ``` 244 /// # use wasmtime::Engine; 245 /// # use wasmtime::component::Component; 246 /// # use wasmtime::component::types::ComponentItem; 247 /// # fn main() -> wasmtime::Result<()> { 248 /// # let engine = Engine::default(); 249 /// let a = Component::new(&engine, r#" 250 /// (component (import "x" (type (sub resource)))) 251 /// "#)?; 252 /// let b = Component::new(&engine, r#" 253 /// (component (import "x" (type (sub resource)))) 254 /// "#)?; 255 /// 256 /// let (_, a_ty) = a.component_type().imports(&engine).next().unwrap(); 257 /// let (_, b_ty) = b.component_type().imports(&engine).next().unwrap(); 258 /// 259 /// let a_ty = match a_ty { 260 /// ComponentItem::Resource(ty) => ty, 261 /// _ => unreachable!(), 262 /// }; 263 /// let b_ty = match b_ty { 264 /// ComponentItem::Resource(ty) => ty, 265 /// _ => unreachable!(), 266 /// }; 267 /// assert!(a_ty != b_ty); 268 /// # Ok(()) 269 /// # } 270 /// ``` 271 /// 272 /// Additionally, however, these abstract types are "substituted" during 273 /// instantiation meaning that a component type will appear to have changed 274 /// once it is instantiated. 275 /// 276 /// ``` 277 /// # use wasmtime::{Engine, Store}; 278 /// # use wasmtime::component::{Component, Linker, ResourceType}; 279 /// # use wasmtime::component::types::ComponentItem; 280 /// # fn main() -> wasmtime::Result<()> { 281 /// # let engine = Engine::default(); 282 /// // Here this component imports a resource and then exports it as-is 283 /// // which means that the export is equal to the import. 284 /// let a = Component::new(&engine, r#" 285 /// (component 286 /// (import "x" (type $x (sub resource))) 287 /// (export "x" (type $x)) 288 /// ) 289 /// "#)?; 290 /// 291 /// let (_, import) = a.component_type().imports(&engine).next().unwrap(); 292 /// let (_, export) = a.component_type().exports(&engine).next().unwrap(); 293 /// 294 /// let import = match import { 295 /// ComponentItem::Resource(ty) => ty, 296 /// _ => unreachable!(), 297 /// }; 298 /// let export = match export { 299 /// ComponentItem::Resource(ty) => ty, 300 /// _ => unreachable!(), 301 /// }; 302 /// assert_eq!(import, export); 303 /// 304 /// // However after instantiation the resource type "changes" 305 /// let mut store = Store::new(&engine, ()); 306 /// let mut linker = Linker::new(&engine); 307 /// linker.root().resource("x", ResourceType::host::<()>(), |_, _| Ok(()))?; 308 /// let instance = linker.instantiate(&mut store, &a)?; 309 /// let instance_ty = instance.exports(&mut store).root().resource("x").unwrap(); 310 /// 311 /// // Here `instance_ty` is not the same as either `import` or `export`, 312 /// // but it is equal to what we provided as an import. 313 /// assert!(instance_ty != import); 314 /// assert!(instance_ty != export); 315 /// assert!(instance_ty == ResourceType::host::<()>()); 316 /// # Ok(()) 317 /// # } 318 /// ``` 319 /// 320 /// Finally, each instantiation of an exported resource from a component is 321 /// considered "fresh" for all instantiations meaning that different 322 /// instantiations will have different exported resource types: 323 /// 324 /// ``` 325 /// # use wasmtime::{Engine, Store}; 326 /// # use wasmtime::component::{Component, Linker}; 327 /// # fn main() -> wasmtime::Result<()> { 328 /// # let engine = Engine::default(); 329 /// let a = Component::new(&engine, r#" 330 /// (component 331 /// (type $x (resource (rep i32))) 332 /// (export "x" (type $x)) 333 /// ) 334 /// "#)?; 335 /// 336 /// let mut store = Store::new(&engine, ()); 337 /// let linker = Linker::new(&engine); 338 /// let instance1 = linker.instantiate(&mut store, &a)?; 339 /// let instance2 = linker.instantiate(&mut store, &a)?; 340 /// 341 /// let x1 = instance1.exports(&mut store).root().resource("x").unwrap(); 342 /// let x2 = instance2.exports(&mut store).root().resource("x").unwrap(); 343 /// 344 /// // Despite these two resources being the same export of the same 345 /// // component they come from two different instances meaning that their 346 /// // types will be unique. 347 /// assert!(x1 != x2); 348 /// # Ok(()) 349 /// # } 350 /// ``` 351 pub fn component_type(&self) -> types::Component { 352 let resources = Arc::new(PrimaryMap::new()); 353 types::Component::from( 354 self.inner.ty, 355 &InstanceType { 356 types: self.types(), 357 resources: &resources, 358 }, 359 ) 360 } 361 362 /// Final assembly step for a component from its in-memory representation. 363 /// 364 /// If the `artifacts` are specified as `None` here then they will be 365 /// deserialized from `code_memory`. 366 pub(crate) fn from_parts( 367 engine: &Engine, 368 code_memory: Arc<CodeMemory>, 369 artifacts: Option<ComponentArtifacts>, 370 ) -> Result<Component> { 371 let ComponentArtifacts { 372 ty, 373 info, 374 types, 375 static_modules, 376 } = match artifacts { 377 Some(artifacts) => artifacts, 378 None => postcard::from_bytes(code_memory.wasmtime_info()).err2anyhow()?, 379 }; 380 381 // Validate that the component can be used with the current instance 382 // allocator. 383 engine.allocator().validate_component( 384 &info.component, 385 &VMComponentOffsets::new(HostPtr, &info.component), 386 &|module_index| &static_modules[module_index].module, 387 )?; 388 389 // Create a signature registration with the `Engine` for all trampolines 390 // and core wasm types found within this component, both for the 391 // component and for all included core wasm modules. 392 let signatures = TypeCollection::new_for_module(engine, types.module_types()); 393 394 // Assemble the `CodeObject` artifact which is shared by all core wasm 395 // modules as well as the final component. 396 let types = Arc::new(types); 397 let code = Arc::new(CodeObject::new(code_memory, signatures, types.into())); 398 399 // Convert all information about static core wasm modules into actual 400 // `Module` instances by converting each `CompiledModuleInfo`, the 401 // `types` type information, and the code memory to a runtime object. 402 let static_modules = static_modules 403 .into_iter() 404 .map(|(_, info)| Module::from_parts_raw(engine, code.clone(), info, false)) 405 .collect::<Result<_>>()?; 406 407 let realloc_func_type = Arc::new(FuncType::new( 408 engine, 409 [ValType::I32, ValType::I32, ValType::I32, ValType::I32], 410 [ValType::I32], 411 )) as _; 412 413 Ok(Component { 414 inner: Arc::new(ComponentInner { 415 ty, 416 static_modules, 417 code, 418 info, 419 realloc_func_type, 420 }), 421 }) 422 } 423 424 pub(crate) fn ty(&self) -> TypeComponentIndex { 425 self.inner.ty 426 } 427 428 pub(crate) fn env_component(&self) -> &wasmtime_environ::component::Component { 429 &self.inner.info.component 430 } 431 432 pub(crate) fn static_module(&self, idx: StaticModuleIndex) -> &Module { 433 &self.inner.static_modules[idx] 434 } 435 436 #[inline] 437 pub(crate) fn types(&self) -> &Arc<ComponentTypes> { 438 self.inner.component_types() 439 } 440 441 pub(crate) fn signatures(&self) -> &TypeCollection { 442 self.inner.code.signatures() 443 } 444 445 pub(crate) fn text(&self) -> &[u8] { 446 self.inner.code.code_memory().text() 447 } 448 449 pub(crate) fn trampoline_ptrs(&self, index: TrampolineIndex) -> AllCallFuncPointers { 450 let AllCallFunc { 451 wasm_call, 452 array_call, 453 native_call, 454 } = &self.inner.info.trampolines[index]; 455 AllCallFuncPointers { 456 wasm_call: self.func(wasm_call).cast(), 457 array_call: unsafe { 458 mem::transmute::<NonNull<VMFunctionBody>, VMArrayCallFunction>( 459 self.func(array_call), 460 ) 461 }, 462 native_call: self.func(native_call).cast(), 463 } 464 } 465 466 fn func(&self, loc: &FunctionLoc) -> NonNull<VMFunctionBody> { 467 let text = self.text(); 468 let trampoline = &text[loc.start as usize..][..loc.length as usize]; 469 NonNull::new(trampoline.as_ptr() as *mut VMFunctionBody).unwrap() 470 } 471 472 pub(crate) fn code_object(&self) -> &Arc<CodeObject> { 473 &self.inner.code 474 } 475 476 /// Same as [`Module::serialize`], except for a component. 477 /// 478 /// Note that the artifact produced here must be passed to 479 /// [`Component::deserialize`] and is not compatible for use with 480 /// [`Module`]. 481 /// 482 /// [`Module::serialize`]: crate::Module::serialize 483 /// [`Module`]: crate::Module 484 pub fn serialize(&self) -> Result<Vec<u8>> { 485 Ok(self.code_object().code_memory().mmap().to_vec()) 486 } 487 488 pub(crate) fn runtime_info(&self) -> Arc<dyn ComponentRuntimeInfo> { 489 self.inner.clone() 490 } 491 492 /// Creates a new `VMFuncRef` with all fields filled out for the destructor 493 /// specified. 494 /// 495 /// The `dtor`'s own `VMFuncRef` won't have `wasm_call` filled out but this 496 /// component may have `resource_drop_wasm_to_native_trampoline` filled out 497 /// if necessary in which case it's filled in here. 498 pub(crate) fn resource_drop_func_ref(&self, dtor: &crate::func::HostFunc) -> VMFuncRef { 499 // Host functions never have their `wasm_call` filled in at this time. 500 assert!(dtor.func_ref().wasm_call.is_none()); 501 502 // Note that if `resource_drop_wasm_to_native_trampoline` is not present 503 // then this can't be called by the component, so it's ok to leave it 504 // blank. 505 let wasm_call = self 506 .inner 507 .info 508 .resource_drop_wasm_to_native_trampoline 509 .as_ref() 510 .map(|i| self.func(i).cast()); 511 VMFuncRef { 512 wasm_call, 513 ..*dtor.func_ref() 514 } 515 } 516 517 /// Returns a summary of the resources required to instantiate this 518 /// [`Component`][crate::component::Component]. 519 /// 520 /// Note that when a component imports and instantiates another component or 521 /// core module, we cannot determine ahead of time how many resources 522 /// instantiating this component will require, and therefore this method 523 /// will return `None` in these scenarios. 524 /// 525 /// Potential uses of the returned information: 526 /// 527 /// * Determining whether your pooling allocator configuration supports 528 /// instantiating this component. 529 /// 530 /// * Deciding how many of which `Component` you want to instantiate within 531 /// a fixed amount of resources, e.g. determining whether to create 5 532 /// instances of component X or 10 instances of component Y. 533 /// 534 /// # Example 535 /// 536 /// ``` 537 /// # fn main() -> wasmtime::Result<()> { 538 /// use wasmtime::{Config, Engine, component::Component}; 539 /// 540 /// let mut config = Config::new(); 541 /// config.wasm_multi_memory(true); 542 /// config.wasm_component_model(true); 543 /// let engine = Engine::new(&config)?; 544 /// 545 /// let component = Component::new(&engine, &r#" 546 /// (component 547 /// ;; Define a core module that uses two memories. 548 /// (core module $m 549 /// (memory 1) 550 /// (memory 6) 551 /// ) 552 /// 553 /// ;; Instantiate that core module three times. 554 /// (core instance $i1 (instantiate (module $m))) 555 /// (core instance $i2 (instantiate (module $m))) 556 /// (core instance $i3 (instantiate (module $m))) 557 /// ) 558 /// "#)?; 559 /// 560 /// let resources = component.resources_required() 561 /// .expect("this component does not import any core modules or instances"); 562 /// 563 /// // Instantiating the component will require allocating two memories per 564 /// // core instance, and there are three instances, so six total memories. 565 /// assert_eq!(resources.num_memories, 6); 566 /// assert_eq!(resources.max_initial_memory_size, Some(6)); 567 /// 568 /// // The component doesn't need any tables. 569 /// assert_eq!(resources.num_tables, 0); 570 /// assert_eq!(resources.max_initial_table_size, None); 571 /// # Ok(()) } 572 /// ``` 573 pub fn resources_required(&self) -> Option<ResourcesRequired> { 574 let mut resources = ResourcesRequired { 575 num_memories: 0, 576 max_initial_memory_size: None, 577 num_tables: 0, 578 max_initial_table_size: None, 579 }; 580 for init in &self.env_component().initializers { 581 match init { 582 GlobalInitializer::InstantiateModule(inst) => match inst { 583 InstantiateModule::Static(index, _) => { 584 let module = self.static_module(*index); 585 resources.add(&module.resources_required()); 586 } 587 InstantiateModule::Import(_, _) => { 588 // We can't statically determine the resources required 589 // to instantiate this component. 590 return None; 591 } 592 }, 593 GlobalInitializer::LowerImport { .. } 594 | GlobalInitializer::ExtractMemory(_) 595 | GlobalInitializer::ExtractRealloc(_) 596 | GlobalInitializer::ExtractPostReturn(_) 597 | GlobalInitializer::Resource(_) => {} 598 } 599 } 600 Some(resources) 601 } 602 603 /// Returns the range, in the host's address space, that this module's 604 /// compiled code resides at. 605 /// 606 /// For more information see 607 /// [`Module::image_range`](crate::Module::image_range). 608 pub fn image_range(&self) -> Range<*const u8> { 609 self.inner.code.code_memory().mmap().image_range() 610 } 611 } 612 613 impl ComponentRuntimeInfo for ComponentInner { 614 fn component(&self) -> &wasmtime_environ::component::Component { 615 &self.info.component 616 } 617 618 fn component_types(&self) -> &Arc<ComponentTypes> { 619 match self.code.types() { 620 crate::code::Types::Component(types) => types, 621 // The only creator of a `Component` is itself which uses the other 622 // variant, so this shouldn't be possible. 623 crate::code::Types::Module(_) => unreachable!(), 624 } 625 } 626 627 fn realloc_func_type(&self) -> &Arc<dyn Any + Send + Sync> { 628 &self.realloc_func_type 629 } 630 } 631 632 #[cfg(test)] 633 mod tests { 634 use crate::component::Component; 635 use crate::{Config, Engine}; 636 use wasmtime_environ::MemoryInitialization; 637 638 #[test] 639 fn cow_on_by_default() { 640 let mut config = Config::new(); 641 config.wasm_component_model(true); 642 let engine = Engine::new(&config).unwrap(); 643 let component = Component::new( 644 &engine, 645 r#" 646 (component 647 (core module 648 (memory 1) 649 (data (i32.const 100) "abcd") 650 ) 651 ) 652 "#, 653 ) 654 .unwrap(); 655 656 for (_, module) in component.inner.static_modules.iter() { 657 let init = &module.env_module().memory_initialization; 658 assert!(matches!(init, MemoryInitialization::Static { .. })); 659 } 660 } 661 } 662