Skip to main content

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}