wasmtime/runtime/component/component.rs
1use crate::component::matching::InstanceType;
2use crate::component::types;
3#[cfg(feature = "wit-parser")]
4use crate::component::wit_parser::ItemName;
5use crate::prelude::*;
6#[cfg(feature = "std")]
7use crate::runtime::vm::open_file_for_mmap;
8use crate::runtime::vm::{CompiledModuleId, VMArrayCallFunction, VMFuncRef, VMWasmCallFunction};
9use crate::{
10 Engine, Module, ResourcesRequired, code::EngineCode, code_memory::CodeMemory,
11 type_registry::TypeCollection,
12};
13use crate::{FuncType, ValType};
14use alloc::sync::Arc;
15use core::fmt;
16use core::ops::Range;
17use core::ptr::NonNull;
18#[cfg(feature = "std")]
19use std::path::Path;
20use wasmtime_environ::component::{
21 CompiledComponentInfo, ComponentArtifacts, ComponentTypes, CoreDef, Export, ExportIndex,
22 GlobalInitializer, InstantiateModule, NameMapNoIntern, OptionsIndex, StaticModuleIndex,
23 TrampolineIndex, TypeComponentIndex, TypeFuncIndex, UnsafeIntrinsic, VMComponentOffsets,
24};
25use wasmtime_environ::{Abi, CompiledFunctionsTable, FuncKey, TypeTrace, WasmChecksum};
26use wasmtime_environ::{FunctionLoc, HostPtr, ObjectKind, PrimaryMap};
27
28/// A compiled WebAssembly Component.
29///
30/// This structure represents a compiled component that is ready to be
31/// instantiated. This owns a region of virtual memory which contains executable
32/// code compiled from a WebAssembly binary originally. This is the analog of
33/// [`Module`](crate::Module) in the component embedding API.
34///
35/// A [`Component`] can be turned into an
36/// [`Instance`](crate::component::Instance) through a
37/// [`Linker`](crate::component::Linker). [`Component`]s are safe to share
38/// across threads. The compilation model of a component is the same as that of
39/// [a module](crate::Module) which is to say:
40///
41/// * Compilation happens synchronously during [`Component::new`].
42/// * The result of compilation can be saved into storage with
43/// [`Component::serialize`].
44/// * A previously compiled artifact can be parsed with
45/// [`Component::deserialize`].
46/// * No compilation happens at runtime for a component — everything is done
47/// by the time [`Component::new`] returns.
48///
49/// ## Components and `Clone`
50///
51/// Using `clone` on a `Component` is a cheap operation. It will not create an
52/// entirely new component, but rather just a new reference to the existing
53/// component. In other words it's a shallow copy, not a deep copy.
54///
55/// ## Examples
56///
57/// For example usage see the documentation of [`Module`](crate::Module) as
58/// [`Component`] has the same high-level API.
59#[derive(Clone)]
60pub struct Component {
61 inner: Arc<ComponentInner>,
62}
63
64struct ComponentInner {
65 /// Unique id for this component within this process.
66 ///
67 /// Note that this is repurposing ids for modules intentionally as there
68 /// shouldn't be an issue overlapping them.
69 id: CompiledModuleId,
70
71 /// The engine that this component belongs to.
72 engine: Engine,
73
74 /// Component type index
75 ty: TypeComponentIndex,
76
77 /// Core wasm modules that the component defined internally, indexed by the
78 /// compile-time-assigned `ModuleUpvarIndex`.
79 static_modules: PrimaryMap<StaticModuleIndex, Module>,
80
81 /// Code-related information such as the compiled artifact, type
82 /// information, etc.
83 ///
84 /// Note that the `Arc` here is used to share this allocation with internal
85 /// modules.
86 code: Arc<EngineCode>,
87
88 /// Metadata produced during compilation.
89 info: CompiledComponentInfo,
90
91 /// The index of compiled functions and their locations in the text section
92 /// for this component.
93 index: Arc<CompiledFunctionsTable>,
94
95 /// A cached handle to the `wasmtime::FuncType` for the canonical ABI's
96 /// `realloc`, to avoid the need to look up types in the registry and take
97 /// locks when calling `realloc` via `TypedFunc::call_raw`.
98 realloc_func_type: Arc<FuncType>,
99
100 /// The checksum of the source binary from which the module was compiled.
101 checksum: WasmChecksum,
102}
103
104impl fmt::Debug for Component {
105 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
106 f.debug_struct("Component").finish_non_exhaustive()
107 }
108}
109
110pub(crate) struct AllCallFuncPointers {
111 pub wasm_call: NonNull<VMWasmCallFunction>,
112 pub array_call: NonNull<VMArrayCallFunction>,
113}
114
115impl Component {
116 /// Compiles a new WebAssembly component from the in-memory list of bytes
117 /// provided.
118 ///
119 /// The `bytes` provided can either be the binary or text format of a
120 /// [WebAssembly component]. Note that the text format requires the `wat`
121 /// feature of this crate to be enabled. This API does not support
122 /// streaming compilation.
123 ///
124 /// This function will synchronously validate the entire component,
125 /// including all core modules, and then compile all components, modules,
126 /// etc., found within the provided bytes.
127 ///
128 /// [WebAssembly component]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md
129 ///
130 /// # Errors
131 ///
132 /// This function may fail and return an error. Errors may include
133 /// situations such as:
134 ///
135 /// * The binary provided could not be decoded because it's not a valid
136 /// WebAssembly binary
137 /// * The WebAssembly binary may not validate (e.g. contains type errors)
138 /// * Implementation-specific limits were exceeded with a valid binary (for
139 /// example too many locals)
140 /// * The wasm binary may use features that are not enabled in the
141 /// configuration of `engine`
142 /// * If the `wat` feature is enabled and the input is text, then it may be
143 /// rejected if it fails to parse.
144 ///
145 /// The error returned should contain full information about why compilation
146 /// failed.
147 ///
148 /// # Examples
149 ///
150 /// The `new` function can be invoked with a in-memory array of bytes:
151 ///
152 /// ```no_run
153 /// # use wasmtime::*;
154 /// # use wasmtime::component::Component;
155 /// # fn main() -> Result<()> {
156 /// # let engine = Engine::default();
157 /// # let wasm_bytes: Vec<u8> = Vec::new();
158 /// let component = Component::new(&engine, &wasm_bytes)?;
159 /// # Ok(())
160 /// # }
161 /// ```
162 ///
163 /// Or you can also pass in a string to be parsed as the wasm text
164 /// format:
165 ///
166 /// ```
167 /// # use wasmtime::*;
168 /// # use wasmtime::component::Component;
169 /// # fn main() -> Result<()> {
170 /// # let engine = Engine::default();
171 /// let component = Component::new(&engine, "(component (core module))")?;
172 /// # Ok(())
173 /// # }
174 #[cfg(any(feature = "cranelift", feature = "winch"))]
175 pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> {
176 crate::CodeBuilder::new(engine)
177 .wasm_binary_or_text(bytes.as_ref(), None)?
178 .compile_component()
179 }
180
181 /// Compiles a new WebAssembly component from a wasm file on disk pointed
182 /// to by `file`.
183 ///
184 /// This is a convenience function for reading the contents of `file` on
185 /// disk and then calling [`Component::new`].
186 #[cfg(all(feature = "std", any(feature = "cranelift", feature = "winch")))]
187 pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Component> {
188 crate::CodeBuilder::new(engine)
189 .wasm_binary_or_text_file(file.as_ref())?
190 .compile_component()
191 }
192
193 /// Compiles a new WebAssembly component from the in-memory wasm image
194 /// provided.
195 ///
196 /// This function is the same as [`Component::new`] except that it does not
197 /// accept the text format of WebAssembly. Even if the `wat` feature
198 /// is enabled an error will be returned here if `binary` is the text
199 /// format.
200 ///
201 /// For more information on semantics and errors see [`Component::new`].
202 #[cfg(any(feature = "cranelift", feature = "winch"))]
203 pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component> {
204 crate::CodeBuilder::new(engine)
205 .wasm_binary(binary, None)?
206 .compile_component()
207 }
208
209 /// Same as [`Module::deserialize`], but for components.
210 ///
211 /// Note that the bytes referenced here must contain contents previously
212 /// produced by [`Engine::precompile_component`] or
213 /// [`Component::serialize`].
214 ///
215 /// For more information see the [`Module::deserialize`] method.
216 ///
217 /// # Errors
218 ///
219 /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
220 /// memory allocation fails. See the `OutOfMemory` type's documentation for
221 /// details on Wasmtime's out-of-memory handling.
222 ///
223 /// # Unsafety
224 ///
225 /// The unsafety of this method is the same as that of the
226 /// [`Module::deserialize`] method.
227 ///
228 /// [`Module::deserialize`]: crate::Module::deserialize
229 pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> {
230 let code = engine.load_code_bytes(bytes.as_ref(), ObjectKind::Component)?;
231 Component::from_parts(engine, code, None)
232 }
233
234 /// Same as [`Module::deserialize_raw`], but for components.
235 ///
236 /// See [`Component::deserialize`] for additional information; this method
237 /// works identically except that it will not create a copy of the provided
238 /// memory but will use it directly.
239 ///
240 /// # Unsafety
241 ///
242 /// All of the safety notes from [`Component::deserialize`] apply here as well
243 /// with the additional constraint that the code memory provide by `memory`
244 /// lives for as long as the module and is nevery externally modified for
245 /// the lifetime of the deserialized module.
246 pub unsafe fn deserialize_raw(engine: &Engine, memory: NonNull<[u8]>) -> Result<Component> {
247 // SAFETY: the contract required by `load_code_raw` is the same as this
248 // function.
249 let code = unsafe { engine.load_code_raw(memory, ObjectKind::Component)? };
250 Component::from_parts(engine, code, None)
251 }
252
253 /// Same as [`Module::deserialize_file`], but for components.
254 ///
255 /// Note that the file referenced here must contain contents previously
256 /// produced by [`Engine::precompile_component`] or
257 /// [`Component::serialize`].
258 ///
259 /// For more information see the [`Module::deserialize_file`] method.
260 ///
261 /// # Unsafety
262 ///
263 /// The unsafety of this method is the same as that of the
264 /// [`Module::deserialize_file`] method.
265 ///
266 /// [`Module::deserialize_file`]: crate::Module::deserialize_file
267 #[cfg(feature = "std")]
268 pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Component> {
269 let file = open_file_for_mmap(path.as_ref())?;
270 let code = engine
271 .load_code_file(file, ObjectKind::Component)
272 .with_context(|| format!("failed to load code for: {}", path.as_ref().display()))?;
273 Component::from_parts(engine, code, None)
274 }
275
276 /// Returns the type of this component as a [`types::Component`].
277 ///
278 /// This method enables runtime introspection of the type of a component
279 /// before instantiation, if necessary.
280 ///
281 /// ## Component types and Resources
282 ///
283 /// An important point to note here is that the precise type of imports and
284 /// exports of a component change when it is instantiated with respect to
285 /// resources. For example a [`Component`] represents an un-instantiated
286 /// component meaning that its imported resources are represented as abstract
287 /// resource types. These abstract types are not equal to any other
288 /// component's types.
289 ///
290 /// For example:
291 ///
292 /// ```
293 /// # use wasmtime::Engine;
294 /// # use wasmtime::component::Component;
295 /// # use wasmtime::component::types::ComponentItem;
296 /// # fn main() -> wasmtime::Result<()> {
297 /// # let engine = Engine::default();
298 /// let a = Component::new(&engine, r#"
299 /// (component (import "x" (type (sub resource))))
300 /// "#)?;
301 /// let b = Component::new(&engine, r#"
302 /// (component (import "x" (type (sub resource))))
303 /// "#)?;
304 ///
305 /// let aty = a.component_type();
306 /// let bty = b.component_type();
307 /// let (_, a_ty) = aty.imports(&engine).next().unwrap();
308 /// let (_, b_ty) = bty.imports(&engine).next().unwrap();
309 ///
310 /// let a_ty = match a_ty.ty {
311 /// ComponentItem::Resource(ty) => ty,
312 /// _ => unreachable!(),
313 /// };
314 /// let b_ty = match b_ty.ty {
315 /// ComponentItem::Resource(ty) => ty,
316 /// _ => unreachable!(),
317 /// };
318 /// assert!(a_ty != b_ty);
319 /// # Ok(())
320 /// # }
321 /// ```
322 ///
323 /// Additionally, however, these abstract types are "substituted" during
324 /// instantiation meaning that a component type will appear to have changed
325 /// once it is instantiated.
326 ///
327 /// ```
328 /// # use wasmtime::{Engine, Store};
329 /// # use wasmtime::component::{Component, Linker, ResourceType};
330 /// # use wasmtime::component::types::ComponentItem;
331 /// # fn main() -> wasmtime::Result<()> {
332 /// # let engine = Engine::default();
333 /// // Here this component imports a resource and then exports it as-is
334 /// // which means that the export is equal to the import.
335 /// let a = Component::new(&engine, r#"
336 /// (component
337 /// (import "x" (type $x (sub resource)))
338 /// (export "x" (type $x))
339 /// )
340 /// "#)?;
341 ///
342 /// let ty = a.component_type();
343 /// let (_, import) = ty.imports(&engine).next().unwrap();
344 /// let (_, export) = ty.exports(&engine).next().unwrap();
345 ///
346 /// let import = match import.ty {
347 /// ComponentItem::Resource(ty) => ty,
348 /// _ => unreachable!(),
349 /// };
350 /// let export = match export.ty {
351 /// ComponentItem::Resource(ty) => ty,
352 /// _ => unreachable!(),
353 /// };
354 /// assert_eq!(import, export);
355 ///
356 /// // However after instantiation the resource type "changes"
357 /// let mut store = Store::new(&engine, ());
358 /// let mut linker = Linker::new(&engine);
359 /// linker.root().resource("x", ResourceType::host::<()>(), |_, _| Ok(()))?;
360 /// let instance = linker.instantiate(&mut store, &a)?;
361 /// let instance_ty = instance.get_resource(&mut store, "x").unwrap();
362 ///
363 /// // Here `instance_ty` is not the same as either `import` or `export`,
364 /// // but it is equal to what we provided as an import.
365 /// assert!(instance_ty != import);
366 /// assert!(instance_ty != export);
367 /// assert!(instance_ty == ResourceType::host::<()>());
368 /// # Ok(())
369 /// # }
370 /// ```
371 ///
372 /// Finally, each instantiation of an exported resource from a component is
373 /// considered "fresh" for all instantiations meaning that different
374 /// instantiations will have different exported resource types:
375 ///
376 /// ```
377 /// # use wasmtime::{Engine, Store};
378 /// # use wasmtime::component::{Component, Linker};
379 /// # fn main() -> wasmtime::Result<()> {
380 /// # let engine = Engine::default();
381 /// let a = Component::new(&engine, r#"
382 /// (component
383 /// (type $x (resource (rep i32)))
384 /// (export "x" (type $x))
385 /// )
386 /// "#)?;
387 ///
388 /// let mut store = Store::new(&engine, ());
389 /// let linker = Linker::new(&engine);
390 /// let instance1 = linker.instantiate(&mut store, &a)?;
391 /// let instance2 = linker.instantiate(&mut store, &a)?;
392 ///
393 /// let x1 = instance1.get_resource(&mut store, "x").unwrap();
394 /// let x2 = instance2.get_resource(&mut store, "x").unwrap();
395 ///
396 /// // Despite these two resources being the same export of the same
397 /// // component they come from two different instances meaning that their
398 /// // types will be unique.
399 /// assert!(x1 != x2);
400 /// # Ok(())
401 /// # }
402 /// ```
403 pub fn component_type(&self) -> types::Component {
404 self.with_uninstantiated_instance_type(|ty| types::Component::from(self.inner.ty, ty))
405 }
406
407 fn with_uninstantiated_instance_type<R>(&self, f: impl FnOnce(&InstanceType<'_>) -> R) -> R {
408 f(&InstanceType {
409 types: self.types(),
410 resources: None,
411 })
412 }
413
414 /// Final assembly step for a component from its in-memory representation.
415 ///
416 /// If the `artifacts` are specified as `None` here then they will be
417 /// deserialized from `code_memory`.
418 pub(crate) fn from_parts(
419 engine: &Engine,
420 code_memory: Arc<CodeMemory>,
421 artifacts: Option<ComponentArtifacts>,
422 ) -> Result<Component> {
423 let ComponentArtifacts {
424 ty,
425 info,
426 table: index,
427 mut types,
428 mut static_modules,
429 checksum,
430 } = match artifacts {
431 Some(artifacts) => artifacts,
432 None => postcard::from_bytes(code_memory.wasmtime_info())?,
433 };
434 let index = Arc::new(index);
435
436 // Validate that the component can be used with the current instance
437 // allocator.
438 engine.allocator().validate_component(
439 &info.component,
440 &VMComponentOffsets::new(HostPtr, &info.component),
441 &|module_index| &static_modules[module_index].module,
442 )?;
443
444 // Create a signature registration with the `Engine` for all trampolines
445 // and core wasm types found within this component, both for the
446 // component and for all included core wasm modules.
447 let signatures = engine.register_and_canonicalize_types(
448 types.module_types_mut(),
449 static_modules.iter_mut().map(|(_, m)| &mut m.module),
450 )?;
451 types.canonicalize_for_runtime_usage(&mut |idx| signatures.shared_type(idx).unwrap());
452
453 // Assemble the `EngineCode` artifact which is shared by all core wasm
454 // modules as well as the final component.
455 let types = Arc::new(types);
456 let code = Arc::new(EngineCode::new(code_memory, signatures, types.into())?);
457
458 // Convert all information about static core wasm modules into actual
459 // `Module` instances by converting each `CompiledModuleInfo`, the
460 // `types` type information, and the code memory to a runtime object.
461 let static_modules = static_modules
462 .into_iter()
463 .map(|(_, info)| {
464 Module::from_parts_raw(engine, code.clone(), info, index.clone(), false)
465 })
466 .collect::<Result<_>>()?;
467
468 let realloc_func_type = Arc::new(FuncType::new(
469 engine,
470 [ValType::I32, ValType::I32, ValType::I32, ValType::I32],
471 [ValType::I32],
472 ));
473
474 Ok(Component {
475 inner: Arc::new(ComponentInner {
476 id: CompiledModuleId::new(),
477 engine: engine.clone(),
478 ty,
479 static_modules,
480 code,
481 info,
482 index,
483 realloc_func_type,
484 checksum,
485 }),
486 })
487 }
488
489 pub(crate) fn ty(&self) -> TypeComponentIndex {
490 self.inner.ty
491 }
492
493 pub(crate) fn env_component(&self) -> &wasmtime_environ::component::Component {
494 &self.inner.info.component
495 }
496
497 pub(crate) fn static_module(&self, idx: StaticModuleIndex) -> &Module {
498 &self.inner.static_modules[idx]
499 }
500
501 #[cfg(any(feature = "profiling", feature = "debug"))]
502 pub(crate) fn static_modules(&self) -> impl Iterator<Item = &Module> {
503 self.inner.static_modules.values()
504 }
505
506 #[inline]
507 pub(crate) fn types(&self) -> &Arc<ComponentTypes> {
508 match self.inner.code.types() {
509 crate::code::Types::Component(types) => types,
510 // The only creator of a `Component` is itself which uses the other
511 // variant, so this shouldn't be possible.
512 crate::code::Types::Module(_) => unreachable!(),
513 }
514 }
515
516 pub(crate) fn signatures(&self) -> &TypeCollection {
517 self.inner.code.signatures()
518 }
519
520 pub(crate) fn trampoline_ptrs(&self, index: TrampolineIndex) -> AllCallFuncPointers {
521 let wasm_call = self
522 .store_invariant_func(FuncKey::ComponentTrampoline(Abi::Wasm, index))
523 .unwrap()
524 .cast();
525 let array_call = self
526 .store_invariant_func(FuncKey::ComponentTrampoline(Abi::Array, index))
527 .unwrap()
528 .cast();
529 AllCallFuncPointers {
530 wasm_call,
531 array_call,
532 }
533 }
534
535 pub(crate) fn unsafe_intrinsic_ptrs(
536 &self,
537 intrinsic: UnsafeIntrinsic,
538 ) -> Option<AllCallFuncPointers> {
539 let wasm_call = self
540 .store_invariant_func(FuncKey::UnsafeIntrinsic(Abi::Wasm, intrinsic))?
541 .cast();
542 let array_call = self
543 .store_invariant_func(FuncKey::UnsafeIntrinsic(Abi::Array, intrinsic))?
544 .cast();
545 Some(AllCallFuncPointers {
546 wasm_call,
547 array_call,
548 })
549 }
550
551 /// Look up a function in this component's text section by `FuncKey`.
552 ///
553 /// This supports only `FuncKey`s that do not invoke Wasm code,
554 /// i.e., code that is potentially Store-specific.
555 fn store_invariant_func(&self, key: FuncKey) -> Option<NonNull<u8>> {
556 assert!(key.is_store_invariant());
557 let loc = self.inner.index.func_loc(key)?;
558 Some(self.func_loc_to_pointer(loc))
559 }
560
561 /// Given a function location within this component's text section, get a
562 /// pointer to the function.
563 ///
564 /// This works only for Store-invariant functions.
565 ///
566 /// Panics on out-of-bounds function locations.
567 fn func_loc_to_pointer(&self, loc: &FunctionLoc) -> NonNull<u8> {
568 let text = self.engine_code().text();
569 let trampoline = &text[loc.start as usize..][..loc.length as usize];
570 NonNull::from(trampoline).cast()
571 }
572
573 pub(crate) fn engine_code(&self) -> &Arc<EngineCode> {
574 &self.inner.code
575 }
576
577 /// Get this component's code object's `.text` section, containing its
578 /// compiled executable code.
579 pub fn text(&self) -> &[u8] {
580 self.engine_code().text()
581 }
582
583 /// Get information about functions in this component's `.text` section:
584 /// their module index, function index, name, and offset+length.
585 pub fn functions(&self) -> impl Iterator<Item = crate::ModuleFunction> + '_ {
586 self.inner
587 .static_modules
588 .values()
589 .flat_map(|m| m.functions())
590 }
591
592 /// Get the address map for this component's `.text` section.
593 ///
594 /// See [`Module::address_map`] for more details.
595 pub fn address_map(&self) -> Option<impl Iterator<Item = (usize, Option<u32>)> + '_> {
596 Some(
597 wasmtime_environ::iterate_address_map(self.engine_code().address_map_data())?
598 .map(|(offset, file_pos)| (offset as usize, file_pos.file_offset())),
599 )
600 }
601
602 /// Same as [`Module::serialize`], except for a component.
603 ///
604 /// Note that the artifact produced here must be passed to
605 /// [`Component::deserialize`] and is not compatible for use with
606 /// [`Module`].
607 ///
608 /// [`Module::serialize`]: crate::Module::serialize
609 /// [`Module`]: crate::Module
610 pub fn serialize(&self) -> Result<Vec<u8>> {
611 let image = self.engine_code().image();
612 let mut v = TryVec::new();
613 v.reserve(image.len())?;
614 v.try_extend(image.iter().copied())?;
615 Ok(v.into())
616 }
617
618 /// Creates a new `VMFuncRef` with all fields filled out for the destructor
619 /// specified.
620 ///
621 /// The `dtor`'s own `VMFuncRef` won't have `wasm_call` filled out but this
622 /// component may have `resource_drop_wasm_to_native_trampoline` filled out
623 /// if necessary in which case it's filled in here.
624 pub(crate) fn resource_drop_func_ref(&self, dtor: &crate::func::HostFunc) -> VMFuncRef {
625 // Host functions never have their `wasm_call` filled in at this time.
626 assert!(dtor.func_ref().wasm_call.is_none());
627
628 // Note that if `resource_drop_wasm_to_native_trampoline` is not present
629 // then this can't be called by the component, so it's ok to leave it
630 // blank.
631 let wasm_call = self
632 .store_invariant_func(FuncKey::ResourceDropTrampoline)
633 .map(|f| f.cast().into());
634
635 VMFuncRef {
636 wasm_call,
637 ..*dtor.func_ref()
638 }
639 }
640
641 /// Returns a summary of the resources required to instantiate this
642 /// [`Component`][crate::component::Component].
643 ///
644 /// Note that when a component imports and instantiates another component or
645 /// core module, we cannot determine ahead of time how many resources
646 /// instantiating this component will require, and therefore this method
647 /// will return `None` in these scenarios.
648 ///
649 /// Potential uses of the returned information:
650 ///
651 /// * Determining whether your pooling allocator configuration supports
652 /// instantiating this component.
653 ///
654 /// * Deciding how many of which `Component` you want to instantiate within
655 /// a fixed amount of resources, e.g. determining whether to create 5
656 /// instances of component X or 10 instances of component Y.
657 ///
658 /// # Example
659 ///
660 /// ```
661 /// # fn main() -> wasmtime::Result<()> {
662 /// use wasmtime::{Config, Engine, component::Component};
663 ///
664 /// let mut config = Config::new();
665 /// config.wasm_multi_memory(true);
666 /// config.wasm_component_model(true);
667 /// let engine = Engine::new(&config)?;
668 ///
669 /// let component = Component::new(&engine, &r#"
670 /// (component
671 /// ;; Define a core module that uses two memories.
672 /// (core module $m
673 /// (memory 1)
674 /// (memory 6)
675 /// )
676 ///
677 /// ;; Instantiate that core module three times.
678 /// (core instance $i1 (instantiate (module $m)))
679 /// (core instance $i2 (instantiate (module $m)))
680 /// (core instance $i3 (instantiate (module $m)))
681 /// )
682 /// "#)?;
683 ///
684 /// let resources = component.resources_required()
685 /// .expect("this component does not import any core modules or instances");
686 ///
687 /// // Instantiating the component will require allocating two memories per
688 /// // core instance, and there are three instances, so six total memories.
689 /// assert_eq!(resources.num_memories, 6);
690 /// assert_eq!(resources.max_initial_memory_size, Some(6));
691 ///
692 /// // The component doesn't need any tables.
693 /// assert_eq!(resources.num_tables, 0);
694 /// assert_eq!(resources.max_initial_table_size, None);
695 /// # Ok(()) }
696 /// ```
697 pub fn resources_required(&self) -> Option<ResourcesRequired> {
698 let mut resources = ResourcesRequired {
699 num_memories: 0,
700 max_initial_memory_size: None,
701 num_tables: 0,
702 max_initial_table_size: None,
703 };
704 for init in &self.env_component().initializers {
705 match init {
706 GlobalInitializer::InstantiateModule(inst, _) => match inst {
707 InstantiateModule::Static(index, _) => {
708 let module = self.static_module(*index);
709 resources.add(&module.resources_required());
710 }
711 InstantiateModule::Import(_, _) => {
712 // We can't statically determine the resources required
713 // to instantiate this component.
714 return None;
715 }
716 },
717 GlobalInitializer::LowerImport { .. }
718 | GlobalInitializer::ExtractMemory(_)
719 | GlobalInitializer::ExtractTable(_)
720 | GlobalInitializer::ExtractRealloc(_)
721 | GlobalInitializer::ExtractCallback(_)
722 | GlobalInitializer::ExtractPostReturn(_)
723 | GlobalInitializer::Resource(_) => {}
724 }
725 }
726 Some(resources)
727 }
728
729 /// Returns the range, in the host's address space, that this module's
730 /// compiled code resides at.
731 ///
732 /// For more information see
733 /// [`Module::image_range`](crate::Module::image_range).
734 pub fn image_range(&self) -> Range<*const u8> {
735 self.inner.code.image().as_ptr_range()
736 }
737
738 /// Force initialization of copy-on-write images to happen here-and-now
739 /// instead of when they're requested during first instantiation.
740 ///
741 /// When [copy-on-write memory
742 /// initialization](crate::Config::memory_init_cow) is enabled then Wasmtime
743 /// will lazily create the initialization image for a component. This method
744 /// can be used to explicitly dictate when this initialization happens.
745 ///
746 /// Note that this largely only matters on Linux when memfd is used.
747 /// Otherwise the copy-on-write image typically comes from disk and in that
748 /// situation the creation of the image is trivial as the image is always
749 /// sourced from disk. On Linux, though, when memfd is used a memfd is
750 /// created and the initialization image is written to it.
751 ///
752 /// Also note that this method is not required to be called, it's available
753 /// as a performance optimization if required but is otherwise handled
754 /// automatically.
755 pub fn initialize_copy_on_write_image(&self) -> Result<()> {
756 for (_, module) in self.inner.static_modules.iter() {
757 module.initialize_copy_on_write_image()?;
758 }
759 Ok(())
760 }
761
762 /// Looks up a specific export of this component by `name` optionally nested
763 /// within the `instance` provided.
764 ///
765 /// See related method [`Self::get_export`] for additional docs and
766 /// examples.
767 ///
768 /// This method is primarily used to acquire a [`ComponentExportIndex`]
769 /// which can be used with [`Instance`](crate::component::Instance) when
770 /// looking up exports. Export lookup with [`ComponentExportIndex`] can
771 /// skip string lookups at runtime and instead use a more efficient
772 /// index-based lookup.
773 ///
774 /// This method only returns the [`ComponentExportIndex`]. If you need the
775 /// corresponding [`types::ComponentItem`], use the related function
776 /// [`Self::get_export`].
777 ///
778 ///
779 /// [`Instance`](crate::component::Instance) has a corresponding method
780 /// [`Instance::get_export_index`](crate::component::Instance::get_export_index).
781 pub fn get_export_index(
782 &self,
783 instance: Option<&ComponentExportIndex>,
784 name: impl ExportLookup,
785 ) -> Option<ComponentExportIndex> {
786 let index = self.lookup_export_index(instance, name)?;
787 Some(ComponentExportIndex {
788 id: self.inner.id,
789 index,
790 })
791 }
792
793 /// Looks up a specific export of this component by `name` optionally nested
794 /// within the `instance` provided.
795 ///
796 /// This method is primarily used to acquire a [`ComponentExportIndex`]
797 /// which can be used with [`Instance`](crate::component::Instance) when
798 /// looking up exports. Export lookup with [`ComponentExportIndex`] can
799 /// skip string lookups at runtime and instead use a more efficient
800 /// index-based lookup.
801 ///
802 /// This method takes a few arguments:
803 ///
804 /// * `engine` - the engine that was used to compile this component.
805 /// * `instance` - an optional "parent instance" for the export being looked
806 /// up. If this is `None` then the export is looked up on the root of the
807 /// component itself, and otherwise the export is looked up on the
808 /// `instance` specified. Note that `instance` must have come from a
809 /// previous invocation of this method.
810 /// * `name` - the name of the export that's being looked up.
811 ///
812 /// If the export is located then two values are returned: a
813 /// [`types::ComponentItem`] which enables introspection about the type of
814 /// the export and a [`ComponentExportIndex`]. The index returned notably
815 /// implements the [`ExportLookup`] trait which enables using it with
816 /// [`Instance::get_func`](crate::component::Instance::get_func) for
817 /// example.
818 ///
819 /// The returned [`types::ComponentItem`] is more expensive to calculate
820 /// than the [`ComponentExportIndex`]. If you only consume the
821 /// [`ComponentExportIndex`], use the related method
822 /// [`Self::get_export_index`] instead.
823 ///
824 /// [`Instance`](crate::component::Instance) has a corresponding method
825 /// [`Instance::get_export`](crate::component::Instance::get_export).
826 ///
827 /// # Examples
828 ///
829 /// ```
830 /// use wasmtime::{Engine, Store};
831 /// use wasmtime::component::{Component, Linker};
832 /// use wasmtime::component::types::ComponentItem;
833 ///
834 /// # fn main() -> wasmtime::Result<()> {
835 /// let engine = Engine::default();
836 /// let component = Component::new(
837 /// &engine,
838 /// r#"
839 /// (component
840 /// (core module $m
841 /// (func (export "f"))
842 /// )
843 /// (core instance $i (instantiate $m))
844 /// (func (export "f")
845 /// (canon lift (core func $i "f")))
846 /// )
847 /// "#,
848 /// )?;
849 ///
850 /// // Perform a lookup of the function "f" before instantiaton.
851 /// let (ty, export) = component.get_export(None, "f").unwrap();
852 /// assert!(matches!(ty, ComponentItem::ComponentFunc(_)));
853 ///
854 /// // After instantiation use `export` to lookup the function in question
855 /// // which notably does not do a string lookup at runtime.
856 /// let mut store = Store::new(&engine, ());
857 /// let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
858 /// let func = instance.get_typed_func::<(), ()>(&mut store, &export)?;
859 /// // ...
860 /// # Ok(())
861 /// # }
862 /// ```
863 pub fn get_export(
864 &self,
865 instance: Option<&ComponentExportIndex>,
866 name: impl ExportLookup,
867 ) -> Option<(types::ComponentItem, ComponentExportIndex)> {
868 let info = self.env_component();
869 let index = self.lookup_export_index(instance, name)?;
870 let item = self.with_uninstantiated_instance_type(|instance| {
871 types::ComponentItem::from_export(
872 &self.inner.engine,
873 &info.export_items[index],
874 instance,
875 )
876 });
877 Some((
878 item,
879 ComponentExportIndex {
880 id: self.inner.id,
881 index,
882 },
883 ))
884 }
885
886 pub(crate) fn lookup_export_index(
887 &self,
888 instance: Option<&ComponentExportIndex>,
889 name: impl ExportLookup,
890 ) -> Option<ExportIndex> {
891 if let Some(idx) = instance {
892 if idx.id != self.inner.id {
893 return None;
894 }
895 }
896 name.lookup(self, instance.map(|idx| &idx.index))
897 }
898
899 pub(crate) fn id(&self) -> CompiledModuleId {
900 self.inner.id
901 }
902
903 /// Returns the [`Engine`] that this [`Component`] was compiled by.
904 pub fn engine(&self) -> &Engine {
905 &self.inner.engine
906 }
907
908 pub(crate) fn realloc_func_ty(&self) -> &Arc<FuncType> {
909 &self.inner.realloc_func_type
910 }
911
912 #[allow(
913 unused,
914 reason = "used only for verification with wasmtime `rr` feature \
915 and requires a lot of unnecessary gating across crates"
916 )]
917 pub(crate) fn checksum(&self) -> &WasmChecksum {
918 &self.inner.checksum
919 }
920
921 /// Returns the `Export::LiftedFunction` metadata associated with `export`.
922 ///
923 /// # Panics
924 ///
925 /// Panics if `export` is out of bounds or if it isn't a `LiftedFunction`.
926 pub(crate) fn export_lifted_function(
927 &self,
928 export: ExportIndex,
929 ) -> (TypeFuncIndex, &CoreDef, OptionsIndex) {
930 let component = self.env_component();
931 match &component.export_items[export] {
932 Export::LiftedFunction { ty, func, options } => (*ty, func, *options),
933 _ => unreachable!(),
934 }
935 }
936
937 pub(crate) fn index(&self) -> &Arc<CompiledFunctionsTable> {
938 &self.inner.index
939 }
940}
941
942/// A value which represents a known export of a component.
943///
944/// This is the return value of [`Component::get_export`] and implements the
945/// [`ExportLookup`] trait to work with lookups like
946/// [`Instance::get_func`](crate::component::Instance::get_func).
947#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
948pub struct ComponentExportIndex {
949 pub(crate) id: CompiledModuleId,
950 pub(crate) index: ExportIndex,
951}
952
953/// Trait used to lookup the export of a component or instance.
954///
955/// This trait is used as an implementation detail of
956/// [`Instance::get_func`](crate::component::Instance::get_func).
957/// and related `get_*` methods, as well as [`Component::get_export`] and
958/// related `get_*` methods. Notable implementors of this trait are:
959///
960/// * `str`
961/// * `String`
962/// * [`ComponentExportIndex`]
963///
964/// Note that this is intended to be a `wasmtime`-sealed trait so it shouldn't
965/// need to be implemented externally.
966pub trait ExportLookup {
967 #[doc(hidden)]
968 fn lookup(&self, component: &Component, instance: Option<&ExportIndex>) -> Option<ExportIndex>;
969}
970
971impl<T> ExportLookup for &T
972where
973 T: ExportLookup + ?Sized,
974{
975 fn lookup(&self, component: &Component, instance: Option<&ExportIndex>) -> Option<ExportIndex> {
976 T::lookup(self, component, instance)
977 }
978}
979
980impl ExportLookup for str {
981 fn lookup(&self, component: &Component, instance: Option<&ExportIndex>) -> Option<ExportIndex> {
982 let info = component.env_component();
983 let exports = match instance {
984 Some(idx) => match &info.export_items[*idx] {
985 Export::Instance { exports, .. } => exports,
986 _ => return None,
987 },
988 None => &info.exports,
989 };
990 let (index, _) = exports.get(self, &NameMapNoIntern)?;
991 Some(*index)
992 }
993}
994
995impl ExportLookup for String {
996 fn lookup(&self, component: &Component, instance: Option<&ExportIndex>) -> Option<ExportIndex> {
997 str::lookup(self, component, instance)
998 }
999}
1000
1001impl ExportLookup for ComponentExportIndex {
1002 fn lookup(
1003 &self,
1004 component: &Component,
1005 _instance: Option<&ExportIndex>,
1006 ) -> Option<ExportIndex> {
1007 if component.inner.id == self.id {
1008 Some(self.index)
1009 } else {
1010 None
1011 }
1012 }
1013}
1014
1015#[cfg(feature = "wit-parser")]
1016impl ExportLookup for ItemName {
1017 fn lookup(&self, component: &Component, instance: Option<&ExportIndex>) -> Option<ExportIndex> {
1018 let instance = self
1019 .instance_name()
1020 .and_then(|instance_name| instance_name.lookup(component, instance));
1021 self.name.lookup(component, instance.as_ref())
1022 }
1023}
1024
1025#[cfg(test)]
1026mod tests {
1027 use crate::component::Component;
1028 use crate::{CodeBuilder, Config, Engine};
1029 use wasmtime_environ::MemoryInitialization;
1030 #[test]
1031 #[cfg_attr(miri, ignore)]
1032 fn cow_on_by_default() {
1033 let mut config = Config::new();
1034 config.wasm_component_model(true);
1035 let engine = Engine::new(&config).unwrap();
1036 let component = Component::new(
1037 &engine,
1038 r#"
1039 (component
1040 (core module
1041 (memory 1)
1042 (data (i32.const 100) "abcd")
1043 )
1044 )
1045 "#,
1046 )
1047 .unwrap();
1048
1049 for (_, module) in component.inner.static_modules.iter() {
1050 let init = &module.env_module().memory_initialization;
1051 assert!(matches!(init, MemoryInitialization::Static { .. }));
1052 }
1053 }
1054
1055 #[test]
1056 #[cfg_attr(miri, ignore)]
1057 fn image_range_is_whole_image() {
1058 let wat = r#"
1059 (component
1060 (core module
1061 (memory 1)
1062 (data (i32.const 0) "1234")
1063 (func (export "f") (param i32) (result i32)
1064 local.get 0)))
1065 "#;
1066 let engine = Engine::default();
1067 let mut builder = CodeBuilder::new(&engine);
1068 builder.wasm_binary_or_text(wat.as_bytes(), None).unwrap();
1069 let bytes = builder.compile_component_serialized().unwrap();
1070
1071 let comp = unsafe { Component::deserialize(&engine, &bytes).unwrap() };
1072 let image_range = comp.image_range();
1073 let len = image_range.end.addr() - image_range.start.addr();
1074 // Length may be strictly greater if it becomes page-aligned.
1075 assert!(len >= bytes.len());
1076 }
1077
1078 #[cfg(feature = "wit-parser")]
1079 #[test]
1080 fn component_export_lookup_item_name() {
1081 use crate::component::wit_parser::ItemName;
1082
1083 let mut config = Config::new();
1084 config.wasm_component_model(true);
1085 let engine = Engine::new(&config).unwrap();
1086 let component = Component::new(
1087 &engine,
1088 r#"
1089 (component
1090 (type $string string)
1091 (export "string-type" (type $string))
1092 (component $inner
1093 (type $a_tuple (tuple string string))
1094 (export "a-tuple" (type $a_tuple))
1095 )
1096 (instance $i (instantiate $inner))
1097 (export "an-instance" (instance $i))
1098 (export "my:test/iface" (instance $i))
1099 (export "my:test/other@0.1.0" (instance $i))
1100 )
1101 "#,
1102 )
1103 .unwrap();
1104
1105 // ItemName can address a top level export:
1106 assert!(component.get_export(None, "string-type").is_some());
1107 assert_eq!(
1108 component.get_export_index(None, "string-type"),
1109 component.get_export_index(None, "string-type".parse::<ItemName>().unwrap())
1110 );
1111
1112 // ItemName can address an export in an instance:
1113 assert!(component.get_export(None, "an-instance").is_some());
1114 let an_instance_index = component.get_export_index(None, "an-instance");
1115 assert!(
1116 component
1117 .get_export(an_instance_index.as_ref(), "a-tuple")
1118 .is_some()
1119 );
1120
1121 // ItemName can address an export in an instance with a package name
1122 assert!(component.get_export(None, "my:test/iface").is_some());
1123 let pkg_iface_index = component.get_export_index(None, "my:test/iface");
1124 assert_eq!(
1125 component.get_export_index(pkg_iface_index.as_ref(), "a-tuple"),
1126 component.get_export_index(None, "my:test/iface.a-tuple".parse::<ItemName>().unwrap())
1127 );
1128
1129 // ItemName can address an export in an instance with a package name
1130 // and a version
1131 assert!(component.get_export(None, "my:test/other@0.1.0").is_some());
1132 let pkg_iface_index = component.get_export_index(None, "my:test/other@0.1.0");
1133 assert_eq!(
1134 component.get_export_index(pkg_iface_index.as_ref(), "a-tuple"),
1135 component.get_export_index(
1136 None,
1137 "my:test/other.a-tuple@0.1.0".parse::<ItemName>().unwrap()
1138 )
1139 );
1140
1141 // Both mechanisms for lookup respect semver - patch version is
1142 // ignored because its a 0.x.y release
1143 assert!(component.get_export(None, "my:test/other@0.1.1").is_some());
1144 let pkg_iface_index = component.get_export_index(None, "my:test/other@0.1.1");
1145 assert_eq!(
1146 component.get_export_index(pkg_iface_index.as_ref(), "a-tuple"),
1147 component.get_export_index(
1148 None,
1149 "my:test/other.a-tuple@0.1.2".parse::<ItemName>().unwrap()
1150 )
1151 );
1152 }
1153}