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