wasmtime/runtime/component/component.rs
1use crate::component::matching::InstanceType;
2use crate::component::types;
3use crate::component::InstanceExportLookup;
4use crate::prelude::*;
5use crate::runtime::vm::component::ComponentRuntimeInfo;
6#[cfg(feature = "std")]
7use crate::runtime::vm::open_file_for_mmap;
8use crate::runtime::vm::{
9 CompiledModuleId, VMArrayCallFunction, VMFuncRef, VMFunctionBody, VMWasmCallFunction,
10};
11use crate::{
12 code::CodeObject, code_memory::CodeMemory, type_registry::TypeCollection, Engine, Module,
13 ResourcesRequired,
14};
15use crate::{FuncType, ValType};
16use alloc::sync::Arc;
17use core::any::Any;
18use core::ops::Range;
19use core::ptr::NonNull;
20#[cfg(feature = "std")]
21use std::path::Path;
22use wasmtime_environ::component::{
23 AllCallFunc, CompiledComponentInfo, ComponentArtifacts, ComponentTypes, Export, ExportIndex,
24 GlobalInitializer, InstantiateModule, NameMapNoIntern, StaticModuleIndex, TrampolineIndex,
25 TypeComponentIndex, TypeDef, VMComponentOffsets,
26};
27use wasmtime_environ::TypeTrace;
28use wasmtime_environ::{FunctionLoc, HostPtr, ObjectKind, PrimaryMap};
29
30/// A compiled WebAssembly Component.
31///
32/// This structure represents a compiled component that is ready to be
33/// instantiated. This owns a region of virtual memory which contains executable
34/// code compiled from a WebAssembly binary originally. This is the analog of
35/// [`Module`](crate::Module) in the component embedding API.
36///
37/// A [`Component`] can be turned into an
38/// [`Instance`](crate::component::Instance) through a
39/// [`Linker`](crate::component::Linker). [`Component`]s are safe to share
40/// across threads. The compilation model of a component is the same as that of
41/// [a module](crate::Module) which is to say:
42///
43/// * Compilation happens synchronously during [`Component::new`].
44/// * The result of compilation can be saved into storage with
45/// [`Component::serialize`].
46/// * A previously compiled artifact can be parsed with
47/// [`Component::deserialize`].
48/// * No compilation happens at runtime for a component — everything is done
49/// by the time [`Component::new`] returns.
50///
51/// ## Components and `Clone`
52///
53/// Using `clone` on a `Component` is a cheap operation. It will not create an
54/// entirely new component, but rather just a new reference to the existing
55/// component. In other words it's a shallow copy, not a deep copy.
56///
57/// ## Examples
58///
59/// For example usage see the documentation of [`Module`](crate::Module) as
60/// [`Component`] has the same high-level API.
61#[derive(Clone)]
62pub struct Component {
63 inner: Arc<ComponentInner>,
64}
65
66struct ComponentInner {
67 /// Unique id for this component within this process.
68 ///
69 /// Note that this is repurposing ids for modules intentionally as there
70 /// shouldn't be an issue overlapping them.
71 id: CompiledModuleId,
72
73 /// The engine that this component belongs to.
74 engine: Engine,
75
76 /// Component type index
77 ty: TypeComponentIndex,
78
79 /// Core wasm modules that the component defined internally, indexed by the
80 /// compile-time-assigned `ModuleUpvarIndex`.
81 static_modules: PrimaryMap<StaticModuleIndex, Module>,
82
83 /// Code-related information such as the compiled artifact, type
84 /// information, etc.
85 ///
86 /// Note that the `Arc` here is used to share this allocation with internal
87 /// modules.
88 code: Arc<CodeObject>,
89
90 /// Metadata produced during compilation.
91 info: CompiledComponentInfo,
92
93 /// A cached handle to the `wasmtime::FuncType` for the canonical ABI's
94 /// `realloc`, to avoid the need to look up types in the registry and take
95 /// locks when calling `realloc` via `TypedFunc::call_raw`.
96 realloc_func_type: Arc<dyn Any + Send + Sync>,
97}
98
99pub(crate) struct AllCallFuncPointers {
100 pub wasm_call: NonNull<VMWasmCallFunction>,
101 pub array_call: NonNull<VMArrayCallFunction>,
102}
103
104impl Component {
105 /// Compiles a new WebAssembly component from the in-memory list of bytes
106 /// provided.
107 ///
108 /// The `bytes` provided can either be the binary or text format of a
109 /// [WebAssembly component]. Note that the text format requires the `wat`
110 /// feature of this crate to be enabled. This API does not support
111 /// streaming compilation.
112 ///
113 /// This function will synchronously validate the entire component,
114 /// including all core modules, and then compile all components, modules,
115 /// etc., found within the provided bytes.
116 ///
117 /// [WebAssembly component]: https://github.com/WebAssembly/component-model/blob/main/design/mvp/Binary.md
118 ///
119 /// # Errors
120 ///
121 /// This function may fail and return an error. Errors may include
122 /// situations such as:
123 ///
124 /// * The binary provided could not be decoded because it's not a valid
125 /// WebAssembly binary
126 /// * The WebAssembly binary may not validate (e.g. contains type errors)
127 /// * Implementation-specific limits were exceeded with a valid binary (for
128 /// example too many locals)
129 /// * The wasm binary may use features that are not enabled in the
130 /// configuration of `engine`
131 /// * If the `wat` feature is enabled and the input is text, then it may be
132 /// rejected if it fails to parse.
133 ///
134 /// The error returned should contain full information about why compilation
135 /// failed.
136 ///
137 /// # Examples
138 ///
139 /// The `new` function can be invoked with a in-memory array of bytes:
140 ///
141 /// ```no_run
142 /// # use wasmtime::*;
143 /// # use wasmtime::component::Component;
144 /// # fn main() -> anyhow::Result<()> {
145 /// # let engine = Engine::default();
146 /// # let wasm_bytes: Vec<u8> = Vec::new();
147 /// let component = Component::new(&engine, &wasm_bytes)?;
148 /// # Ok(())
149 /// # }
150 /// ```
151 ///
152 /// Or you can also pass in a string to be parsed as the wasm text
153 /// format:
154 ///
155 /// ```
156 /// # use wasmtime::*;
157 /// # use wasmtime::component::Component;
158 /// # fn main() -> anyhow::Result<()> {
159 /// # let engine = Engine::default();
160 /// let component = Component::new(&engine, "(component (core module))")?;
161 /// # Ok(())
162 /// # }
163 #[cfg(any(feature = "cranelift", feature = "winch"))]
164 pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> {
165 crate::CodeBuilder::new(engine)
166 .wasm_binary_or_text(bytes.as_ref(), None)?
167 .compile_component()
168 }
169
170 /// Compiles a new WebAssembly component from a wasm file on disk pointed
171 /// to by `file`.
172 ///
173 /// This is a convenience function for reading the contents of `file` on
174 /// disk and then calling [`Component::new`].
175 #[cfg(all(feature = "std", any(feature = "cranelift", feature = "winch")))]
176 pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Component> {
177 crate::CodeBuilder::new(engine)
178 .wasm_binary_or_text_file(file.as_ref())?
179 .compile_component()
180 }
181
182 /// Compiles a new WebAssembly component from the in-memory wasm image
183 /// provided.
184 ///
185 /// This function is the same as [`Component::new`] except that it does not
186 /// accept the text format of WebAssembly. Even if the `wat` feature
187 /// is enabled an error will be returned here if `binary` is the text
188 /// format.
189 ///
190 /// For more information on semantics and errors see [`Component::new`].
191 #[cfg(any(feature = "cranelift", feature = "winch"))]
192 pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Component> {
193 crate::CodeBuilder::new(engine)
194 .wasm_binary(binary, None)?
195 .compile_component()
196 }
197
198 /// Same as [`Module::deserialize`], but for components.
199 ///
200 /// Note that the bytes referenced here must contain contents previously
201 /// produced by [`Engine::precompile_component`] or
202 /// [`Component::serialize`].
203 ///
204 /// For more information see the [`Module::deserialize`] method.
205 ///
206 /// # Unsafety
207 ///
208 /// The unsafety of this method is the same as that of the
209 /// [`Module::deserialize`] method.
210 ///
211 /// [`Module::deserialize`]: crate::Module::deserialize
212 pub unsafe fn deserialize(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Component> {
213 let code = engine.load_code_bytes(bytes.as_ref(), ObjectKind::Component)?;
214 Component::from_parts(engine, code, None)
215 }
216
217 /// Same as [`Module::deserialize_file`], but for components.
218 ///
219 /// Note that the file referenced here must contain contents previously
220 /// produced by [`Engine::precompile_component`] or
221 /// [`Component::serialize`].
222 ///
223 /// For more information see the [`Module::deserialize_file`] method.
224 ///
225 /// # Unsafety
226 ///
227 /// The unsafety of this method is the same as that of the
228 /// [`Module::deserialize_file`] method.
229 ///
230 /// [`Module::deserialize_file`]: crate::Module::deserialize_file
231 #[cfg(feature = "std")]
232 pub unsafe fn deserialize_file(engine: &Engine, path: impl AsRef<Path>) -> Result<Component> {
233 let file = open_file_for_mmap(path.as_ref())?;
234 let code = engine
235 .load_code_file(file, ObjectKind::Component)
236 .with_context(|| format!("failed to load code for: {}", path.as_ref().display()))?;
237 Component::from_parts(engine, code, None)
238 }
239
240 /// Returns the type of this component as a [`types::Component`].
241 ///
242 /// This method enables runtime introspection of the type of a component
243 /// before instantiation, if necessary.
244 ///
245 /// ## Component types and Resources
246 ///
247 /// An important point to note here is that the precise type of imports and
248 /// exports of a component change when it is instantiated with respect to
249 /// resources. For example a [`Component`] represents an un-instantiated
250 /// component meaning that its imported resources are represented as abstract
251 /// resource types. These abstract types are not equal to any other
252 /// component's types.
253 ///
254 /// For example:
255 ///
256 /// ```
257 /// # use wasmtime::Engine;
258 /// # use wasmtime::component::Component;
259 /// # use wasmtime::component::types::ComponentItem;
260 /// # fn main() -> wasmtime::Result<()> {
261 /// # let engine = Engine::default();
262 /// let a = Component::new(&engine, r#"
263 /// (component (import "x" (type (sub resource))))
264 /// "#)?;
265 /// let b = Component::new(&engine, r#"
266 /// (component (import "x" (type (sub resource))))
267 /// "#)?;
268 ///
269 /// let (_, a_ty) = a.component_type().imports(&engine).next().unwrap();
270 /// let (_, b_ty) = b.component_type().imports(&engine).next().unwrap();
271 ///
272 /// let a_ty = match a_ty {
273 /// ComponentItem::Resource(ty) => ty,
274 /// _ => unreachable!(),
275 /// };
276 /// let b_ty = match b_ty {
277 /// ComponentItem::Resource(ty) => ty,
278 /// _ => unreachable!(),
279 /// };
280 /// assert!(a_ty != b_ty);
281 /// # Ok(())
282 /// # }
283 /// ```
284 ///
285 /// Additionally, however, these abstract types are "substituted" during
286 /// instantiation meaning that a component type will appear to have changed
287 /// once it is instantiated.
288 ///
289 /// ```
290 /// # use wasmtime::{Engine, Store};
291 /// # use wasmtime::component::{Component, Linker, ResourceType};
292 /// # use wasmtime::component::types::ComponentItem;
293 /// # fn main() -> wasmtime::Result<()> {
294 /// # let engine = Engine::default();
295 /// // Here this component imports a resource and then exports it as-is
296 /// // which means that the export is equal to the import.
297 /// let a = Component::new(&engine, r#"
298 /// (component
299 /// (import "x" (type $x (sub resource)))
300 /// (export "x" (type $x))
301 /// )
302 /// "#)?;
303 ///
304 /// let (_, import) = a.component_type().imports(&engine).next().unwrap();
305 /// let (_, export) = a.component_type().exports(&engine).next().unwrap();
306 ///
307 /// let import = match import {
308 /// ComponentItem::Resource(ty) => ty,
309 /// _ => unreachable!(),
310 /// };
311 /// let export = match export {
312 /// ComponentItem::Resource(ty) => ty,
313 /// _ => unreachable!(),
314 /// };
315 /// assert_eq!(import, export);
316 ///
317 /// // However after instantiation the resource type "changes"
318 /// let mut store = Store::new(&engine, ());
319 /// let mut linker = Linker::new(&engine);
320 /// linker.root().resource("x", ResourceType::host::<()>(), |_, _| Ok(()))?;
321 /// let instance = linker.instantiate(&mut store, &a)?;
322 /// let instance_ty = instance.get_resource(&mut store, "x").unwrap();
323 ///
324 /// // Here `instance_ty` is not the same as either `import` or `export`,
325 /// // but it is equal to what we provided as an import.
326 /// assert!(instance_ty != import);
327 /// assert!(instance_ty != export);
328 /// assert!(instance_ty == ResourceType::host::<()>());
329 /// # Ok(())
330 /// # }
331 /// ```
332 ///
333 /// Finally, each instantiation of an exported resource from a component is
334 /// considered "fresh" for all instantiations meaning that different
335 /// instantiations will have different exported resource types:
336 ///
337 /// ```
338 /// # use wasmtime::{Engine, Store};
339 /// # use wasmtime::component::{Component, Linker};
340 /// # fn main() -> wasmtime::Result<()> {
341 /// # let engine = Engine::default();
342 /// let a = Component::new(&engine, r#"
343 /// (component
344 /// (type $x (resource (rep i32)))
345 /// (export "x" (type $x))
346 /// )
347 /// "#)?;
348 ///
349 /// let mut store = Store::new(&engine, ());
350 /// let linker = Linker::new(&engine);
351 /// let instance1 = linker.instantiate(&mut store, &a)?;
352 /// let instance2 = linker.instantiate(&mut store, &a)?;
353 ///
354 /// let x1 = instance1.get_resource(&mut store, "x").unwrap();
355 /// let x2 = instance2.get_resource(&mut store, "x").unwrap();
356 ///
357 /// // Despite these two resources being the same export of the same
358 /// // component they come from two different instances meaning that their
359 /// // types will be unique.
360 /// assert!(x1 != x2);
361 /// # Ok(())
362 /// # }
363 /// ```
364 pub fn component_type(&self) -> types::Component {
365 self.with_uninstantiated_instance_type(|ty| types::Component::from(self.inner.ty, ty))
366 }
367
368 fn with_uninstantiated_instance_type<R>(&self, f: impl FnOnce(&InstanceType<'_>) -> R) -> R {
369 let resources = Arc::new(PrimaryMap::new());
370 f(&InstanceType {
371 types: self.types(),
372 resources: &resources,
373 })
374 }
375
376 /// Final assembly step for a component from its in-memory representation.
377 ///
378 /// If the `artifacts` are specified as `None` here then they will be
379 /// deserialized from `code_memory`.
380 pub(crate) fn from_parts(
381 engine: &Engine,
382 code_memory: Arc<CodeMemory>,
383 artifacts: Option<ComponentArtifacts>,
384 ) -> Result<Component> {
385 let ComponentArtifacts {
386 ty,
387 info,
388 mut types,
389 mut static_modules,
390 } = match artifacts {
391 Some(artifacts) => artifacts,
392 None => postcard::from_bytes(code_memory.wasmtime_info())?,
393 };
394
395 // Validate that the component can be used with the current instance
396 // allocator.
397 engine.allocator().validate_component(
398 &info.component,
399 &VMComponentOffsets::new(HostPtr, &info.component),
400 &|module_index| &static_modules[module_index].module,
401 )?;
402
403 // Create a signature registration with the `Engine` for all trampolines
404 // and core wasm types found within this component, both for the
405 // component and for all included core wasm modules.
406 let signatures = engine.register_and_canonicalize_types(
407 types.module_types_mut(),
408 static_modules.iter_mut().map(|(_, m)| &mut m.module),
409 );
410 types.canonicalize_for_runtime_usage(&mut |idx| signatures.shared_type(idx).unwrap());
411
412 // Assemble the `CodeObject` artifact which is shared by all core wasm
413 // modules as well as the final component.
414 let types = Arc::new(types);
415 let code = Arc::new(CodeObject::new(code_memory, signatures, types.into()));
416
417 // Convert all information about static core wasm modules into actual
418 // `Module` instances by converting each `CompiledModuleInfo`, the
419 // `types` type information, and the code memory to a runtime object.
420 let static_modules = static_modules
421 .into_iter()
422 .map(|(_, info)| Module::from_parts_raw(engine, code.clone(), info, false))
423 .collect::<Result<_>>()?;
424
425 let realloc_func_type = Arc::new(FuncType::new(
426 engine,
427 [ValType::I32, ValType::I32, ValType::I32, ValType::I32],
428 [ValType::I32],
429 )) as _;
430
431 Ok(Component {
432 inner: Arc::new(ComponentInner {
433 id: CompiledModuleId::new(),
434 engine: engine.clone(),
435 ty,
436 static_modules,
437 code,
438 info,
439 realloc_func_type,
440 }),
441 })
442 }
443
444 pub(crate) fn ty(&self) -> TypeComponentIndex {
445 self.inner.ty
446 }
447
448 pub(crate) fn env_component(&self) -> &wasmtime_environ::component::Component {
449 &self.inner.info.component
450 }
451
452 pub(crate) fn static_module(&self, idx: StaticModuleIndex) -> &Module {
453 &self.inner.static_modules[idx]
454 }
455
456 #[inline]
457 pub(crate) fn types(&self) -> &Arc<ComponentTypes> {
458 self.inner.component_types()
459 }
460
461 pub(crate) fn signatures(&self) -> &TypeCollection {
462 self.inner.code.signatures()
463 }
464
465 pub(crate) fn text(&self) -> &[u8] {
466 self.inner.code.code_memory().text()
467 }
468
469 pub(crate) fn trampoline_ptrs(&self, index: TrampolineIndex) -> AllCallFuncPointers {
470 let AllCallFunc {
471 wasm_call,
472 array_call,
473 } = &self.inner.info.trampolines[index];
474 AllCallFuncPointers {
475 wasm_call: self.func(wasm_call).cast(),
476 array_call: self.func(array_call).cast(),
477 }
478 }
479
480 fn func(&self, loc: &FunctionLoc) -> NonNull<VMFunctionBody> {
481 let text = self.text();
482 let trampoline = &text[loc.start as usize..][..loc.length as usize];
483 NonNull::new(trampoline.as_ptr() as *mut VMFunctionBody).unwrap()
484 }
485
486 pub(crate) fn code_object(&self) -> &Arc<CodeObject> {
487 &self.inner.code
488 }
489
490 /// Same as [`Module::serialize`], except for a component.
491 ///
492 /// Note that the artifact produced here must be passed to
493 /// [`Component::deserialize`] and is not compatible for use with
494 /// [`Module`].
495 ///
496 /// [`Module::serialize`]: crate::Module::serialize
497 /// [`Module`]: crate::Module
498 pub fn serialize(&self) -> Result<Vec<u8>> {
499 Ok(self.code_object().code_memory().mmap().to_vec())
500 }
501
502 pub(crate) fn runtime_info(&self) -> Arc<dyn ComponentRuntimeInfo> {
503 self.inner.clone()
504 }
505
506 /// Creates a new `VMFuncRef` with all fields filled out for the destructor
507 /// specified.
508 ///
509 /// The `dtor`'s own `VMFuncRef` won't have `wasm_call` filled out but this
510 /// component may have `resource_drop_wasm_to_native_trampoline` filled out
511 /// if necessary in which case it's filled in here.
512 pub(crate) fn resource_drop_func_ref(&self, dtor: &crate::func::HostFunc) -> VMFuncRef {
513 // Host functions never have their `wasm_call` filled in at this time.
514 assert!(dtor.func_ref().wasm_call.is_none());
515
516 // Note that if `resource_drop_wasm_to_native_trampoline` is not present
517 // then this can't be called by the component, so it's ok to leave it
518 // blank.
519 let wasm_call = self
520 .inner
521 .info
522 .resource_drop_wasm_to_array_trampoline
523 .as_ref()
524 .map(|i| self.func(i).cast().into());
525 VMFuncRef {
526 wasm_call,
527 ..*dtor.func_ref()
528 }
529 }
530
531 /// Returns a summary of the resources required to instantiate this
532 /// [`Component`][crate::component::Component].
533 ///
534 /// Note that when a component imports and instantiates another component or
535 /// core module, we cannot determine ahead of time how many resources
536 /// instantiating this component will require, and therefore this method
537 /// will return `None` in these scenarios.
538 ///
539 /// Potential uses of the returned information:
540 ///
541 /// * Determining whether your pooling allocator configuration supports
542 /// instantiating this component.
543 ///
544 /// * Deciding how many of which `Component` you want to instantiate within
545 /// a fixed amount of resources, e.g. determining whether to create 5
546 /// instances of component X or 10 instances of component Y.
547 ///
548 /// # Example
549 ///
550 /// ```
551 /// # fn main() -> wasmtime::Result<()> {
552 /// use wasmtime::{Config, Engine, component::Component};
553 ///
554 /// let mut config = Config::new();
555 /// config.wasm_multi_memory(true);
556 /// config.wasm_component_model(true);
557 /// let engine = Engine::new(&config)?;
558 ///
559 /// let component = Component::new(&engine, &r#"
560 /// (component
561 /// ;; Define a core module that uses two memories.
562 /// (core module $m
563 /// (memory 1)
564 /// (memory 6)
565 /// )
566 ///
567 /// ;; Instantiate that core module three times.
568 /// (core instance $i1 (instantiate (module $m)))
569 /// (core instance $i2 (instantiate (module $m)))
570 /// (core instance $i3 (instantiate (module $m)))
571 /// )
572 /// "#)?;
573 ///
574 /// let resources = component.resources_required()
575 /// .expect("this component does not import any core modules or instances");
576 ///
577 /// // Instantiating the component will require allocating two memories per
578 /// // core instance, and there are three instances, so six total memories.
579 /// assert_eq!(resources.num_memories, 6);
580 /// assert_eq!(resources.max_initial_memory_size, Some(6));
581 ///
582 /// // The component doesn't need any tables.
583 /// assert_eq!(resources.num_tables, 0);
584 /// assert_eq!(resources.max_initial_table_size, None);
585 /// # Ok(()) }
586 /// ```
587 pub fn resources_required(&self) -> Option<ResourcesRequired> {
588 let mut resources = ResourcesRequired {
589 num_memories: 0,
590 max_initial_memory_size: None,
591 num_tables: 0,
592 max_initial_table_size: None,
593 };
594 for init in &self.env_component().initializers {
595 match init {
596 GlobalInitializer::InstantiateModule(inst) => match inst {
597 InstantiateModule::Static(index, _) => {
598 let module = self.static_module(*index);
599 resources.add(&module.resources_required());
600 }
601 InstantiateModule::Import(_, _) => {
602 // We can't statically determine the resources required
603 // to instantiate this component.
604 return None;
605 }
606 },
607 GlobalInitializer::LowerImport { .. }
608 | GlobalInitializer::ExtractMemory(_)
609 | GlobalInitializer::ExtractRealloc(_)
610 | GlobalInitializer::ExtractCallback(_)
611 | GlobalInitializer::ExtractPostReturn(_)
612 | GlobalInitializer::Resource(_) => {}
613 }
614 }
615 Some(resources)
616 }
617
618 /// Returns the range, in the host's address space, that this module's
619 /// compiled code resides at.
620 ///
621 /// For more information see
622 /// [`Module::image_range`](crate::Module::image_range).
623 pub fn image_range(&self) -> Range<*const u8> {
624 self.inner.code.code_memory().mmap().image_range()
625 }
626
627 /// Force initialization of copy-on-write images to happen here-and-now
628 /// instead of when they're requested during first instantiation.
629 ///
630 /// When [copy-on-write memory
631 /// initialization](crate::Config::memory_init_cow) is enabled then Wasmtime
632 /// will lazily create the initialization image for a component. This method
633 /// can be used to explicitly dictate when this initialization happens.
634 ///
635 /// Note that this largely only matters on Linux when memfd is used.
636 /// Otherwise the copy-on-write image typically comes from disk and in that
637 /// situation the creation of the image is trivial as the image is always
638 /// sourced from disk. On Linux, though, when memfd is used a memfd is
639 /// created and the initialization image is written to it.
640 ///
641 /// Also note that this method is not required to be called, it's available
642 /// as a performance optimization if required but is otherwise handled
643 /// automatically.
644 pub fn initialize_copy_on_write_image(&self) -> Result<()> {
645 for (_, module) in self.inner.static_modules.iter() {
646 module.initialize_copy_on_write_image()?;
647 }
648 Ok(())
649 }
650
651 /// Looks up a specific export of this component by `name` optionally nested
652 /// within the `instance` provided.
653 ///
654 /// This method is primarily used to acquire a [`ComponentExportIndex`]
655 /// which can be used with [`Instance`](crate::component::Instance) when
656 /// looking up exports. Export lookup with [`ComponentExportIndex`] can
657 /// skip string lookups at runtime and instead use a more efficient
658 /// index-based lookup.
659 ///
660 /// This method takes a few arguments:
661 ///
662 /// * `engine` - the engine that was used to compile this component.
663 /// * `instance` - an optional "parent instance" for the export being looked
664 /// up. If this is `None` then the export is looked up on the root of the
665 /// component itself, and otherwise the export is looked up on the
666 /// `instance` specified. Note that `instance` must have come from a
667 /// previous invocation of this method.
668 /// * `name` - the name of the export that's being looked up.
669 ///
670 /// If the export is located then two values are returned: a
671 /// [`types::ComponentItem`] which enables introspection about the type of
672 /// the export and a [`ComponentExportIndex`]. The index returned notably
673 /// implements the [`InstanceExportLookup`] trait which enables using it
674 /// with [`Instance::get_func`](crate::component::Instance::get_func) for
675 /// example.
676 ///
677 /// # Examples
678 ///
679 /// ```
680 /// use wasmtime::{Engine, Store};
681 /// use wasmtime::component::{Component, Linker};
682 /// use wasmtime::component::types::ComponentItem;
683 ///
684 /// # fn main() -> wasmtime::Result<()> {
685 /// let engine = Engine::default();
686 /// let component = Component::new(
687 /// &engine,
688 /// r#"
689 /// (component
690 /// (core module $m
691 /// (func (export "f"))
692 /// )
693 /// (core instance $i (instantiate $m))
694 /// (func (export "f")
695 /// (canon lift (core func $i "f")))
696 /// )
697 /// "#,
698 /// )?;
699 ///
700 /// // Perform a lookup of the function "f" before instantiaton.
701 /// let (ty, export) = component.export_index(None, "f").unwrap();
702 /// assert!(matches!(ty, ComponentItem::ComponentFunc(_)));
703 ///
704 /// // After instantiation use `export` to lookup the function in question
705 /// // which notably does not do a string lookup at runtime.
706 /// let mut store = Store::new(&engine, ());
707 /// let instance = Linker::new(&engine).instantiate(&mut store, &component)?;
708 /// let func = instance.get_typed_func::<(), ()>(&mut store, &export)?;
709 /// // ...
710 /// # Ok(())
711 /// # }
712 /// ```
713 pub fn export_index(
714 &self,
715 instance: Option<&ComponentExportIndex>,
716 name: &str,
717 ) -> Option<(types::ComponentItem, ComponentExportIndex)> {
718 let info = self.env_component();
719 let index = self.lookup_export_index(instance, name)?;
720 let ty = match info.export_items[index] {
721 Export::Instance { ty, .. } => TypeDef::ComponentInstance(ty),
722 Export::LiftedFunction { ty, .. } => TypeDef::ComponentFunc(ty),
723 Export::ModuleStatic { ty, .. } | Export::ModuleImport { ty, .. } => {
724 TypeDef::Module(ty)
725 }
726 Export::Type(ty) => ty,
727 };
728 let item = self.with_uninstantiated_instance_type(|instance| {
729 types::ComponentItem::from(&self.inner.engine, &ty, instance)
730 });
731 Some((
732 item,
733 ComponentExportIndex {
734 id: self.inner.id,
735 index,
736 },
737 ))
738 }
739
740 pub(crate) fn lookup_export_index(
741 &self,
742 instance: Option<&ComponentExportIndex>,
743 name: &str,
744 ) -> Option<ExportIndex> {
745 let info = self.env_component();
746 let exports = match instance {
747 Some(idx) => {
748 if idx.id != self.inner.id {
749 return None;
750 }
751 match &info.export_items[idx.index] {
752 Export::Instance { exports, .. } => exports,
753 _ => return None,
754 }
755 }
756 None => &info.exports,
757 };
758 exports.get(name, &NameMapNoIntern).copied()
759 }
760
761 pub(crate) fn id(&self) -> CompiledModuleId {
762 self.inner.id
763 }
764
765 /// Returns the [`Engine`] that this [`Component`] was compiled by.
766 pub fn engine(&self) -> &Engine {
767 &self.inner.engine
768 }
769}
770
771/// A value which represents a known export of a component.
772///
773/// This is the return value of [`Component::export_index`] and implements the
774/// [`InstanceExportLookup`] trait to work with lookups like
775/// [`Instance::get_func`](crate::component::Instance::get_func).
776#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
777pub struct ComponentExportIndex {
778 pub(crate) id: CompiledModuleId,
779 pub(crate) index: ExportIndex,
780}
781
782impl InstanceExportLookup for ComponentExportIndex {
783 fn lookup(&self, component: &Component) -> Option<ExportIndex> {
784 if component.inner.id == self.id {
785 Some(self.index)
786 } else {
787 None
788 }
789 }
790}
791
792impl ComponentRuntimeInfo for ComponentInner {
793 fn component(&self) -> &wasmtime_environ::component::Component {
794 &self.info.component
795 }
796
797 fn component_types(&self) -> &Arc<ComponentTypes> {
798 match self.code.types() {
799 crate::code::Types::Component(types) => types,
800 // The only creator of a `Component` is itself which uses the other
801 // variant, so this shouldn't be possible.
802 crate::code::Types::Module(_) => unreachable!(),
803 }
804 }
805
806 fn realloc_func_type(&self) -> &Arc<dyn Any + Send + Sync> {
807 &self.realloc_func_type
808 }
809}
810
811#[cfg(test)]
812mod tests {
813 use crate::component::Component;
814 use crate::{Config, Engine};
815 use wasmtime_environ::MemoryInitialization;
816
817 #[test]
818 fn cow_on_by_default() {
819 let mut config = Config::new();
820 config.wasm_component_model(true);
821 let engine = Engine::new(&config).unwrap();
822 let component = Component::new(
823 &engine,
824 r#"
825 (component
826 (core module
827 (memory 1)
828 (data (i32.const 100) "abcd")
829 )
830 )
831 "#,
832 )
833 .unwrap();
834
835 for (_, module) in component.inner.static_modules.iter() {
836 let init = &module.env_module().memory_initialization;
837 assert!(matches!(init, MemoryInitialization::Static { .. }));
838 }
839 }
840}