wasmtime_environ/component/
info.rs

1// General runtime type-information about a component.
2//
3// Compared to the `Module` structure for core wasm this type is pretty
4// significantly different. The core wasm `Module` corresponds roughly 1-to-1
5// with the structure of the wasm module itself, but instead a `Component` is
6// more of a "compiled" representation where the original structure is thrown
7// away in favor of a more optimized representation. The considerations for this
8// are:
9//
10// * This representation of a `Component` avoids the need to create a
11//   `PrimaryMap` of some form for each of the index spaces within a component.
12//   This is less so an issue about allocations and more so that this information
13//   generally just isn't needed any time after instantiation. Avoiding creating
14//   these altogether helps components be lighter weight at runtime and
15//   additionally accelerates instantiation.
16//
17// * Components can have arbitrary nesting and internally do instantiations via
18//   string-based matching. At instantiation-time, though, we want to do as few
19//   string-lookups in hash maps as much as we can since they're significantly
20//   slower than index-based lookups. Furthermore while the imports of a
21//   component are not statically known the rest of the structure of the
22//   component is statically known which enables the ability to track precisely
23//   what matches up where and do all the string lookups at compile time instead
24//   of instantiation time.
25//
26// * Finally by performing this sort of dataflow analysis we are capable of
27//   identifying what adapters need trampolines for compilation or fusion. For
28//   example this tracks when host functions are lowered which enables us to
29//   enumerate what trampolines are required to enter into a component.
30//   Additionally (eventually) this will track all of the "fused" adapter
31//   functions where a function from one component instance is lifted and then
32//   lowered into another component instance. Altogether this enables Wasmtime's
33//   AOT-compilation where the artifact from compilation is suitable for use in
34//   running the component without the support of a compiler at runtime.
35//
36// Note, however, that the current design of `Component` has fundamental
37// limitations which it was not designed for. For example there is no feasible
38// way to implement either importing or exporting a component itself from the
39// root component. Currently we rely on the ability to have static knowledge of
40// what's coming from the host which at this point can only be either functions
41// or core wasm modules. Additionally one flat list of initializers for a
42// component are produced instead of initializers-per-component which would
43// otherwise be required to export a component from a component.
44//
45// For now this tradeoff is made as it aligns well with the intended use case
46// for components in an embedding. This may need to be revisited though if the
47// requirements of embeddings change over time.
48
49use crate::component::*;
50use crate::prelude::*;
51use crate::{EntityIndex, ModuleInternedTypeIndex, PrimaryMap, WasmValType};
52use serde_derive::{Deserialize, Serialize};
53
54/// Metadata as a result of compiling a component.
55pub struct ComponentTranslation {
56    /// Serializable information that will be emitted into the final artifact.
57    pub component: Component,
58
59    /// Metadata about required trampolines and what they're supposed to do.
60    pub trampolines: PrimaryMap<TrampolineIndex, Trampoline>,
61}
62
63/// Run-time-type-information about a `Component`, its structure, and how to
64/// instantiate it.
65///
66/// This type is intended to mirror the `Module` type in this crate which
67/// provides all the runtime information about the structure of a module and
68/// how it works.
69///
70/// NB: Lots of the component model is not yet implemented in the runtime so
71/// this is going to undergo a lot of churn.
72#[derive(Default, Debug, Serialize, Deserialize)]
73pub struct Component {
74    /// A list of typed values that this component imports.
75    ///
76    /// Note that each name is given an `ImportIndex` here for the next map to
77    /// refer back to.
78    pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,
79
80    /// A list of "flattened" imports that are used by this instance.
81    ///
82    /// This import map represents extracting imports, as necessary, from the
83    /// general imported types by this component. The flattening here refers to
84    /// extracting items from instances. Currently the flat imports are either a
85    /// host function or a core wasm module.
86    ///
87    /// For example if `ImportIndex(0)` pointed to an instance then this import
88    /// map represent extracting names from that map, for example extracting an
89    /// exported module or an exported function.
90    ///
91    /// Each import item is keyed by a `RuntimeImportIndex` which is referred to
92    /// by types below whenever something refers to an import. The value for
93    /// each `RuntimeImportIndex` in this map is the `ImportIndex` for where
94    /// this items comes from (which can be associated with a name above in the
95    /// `import_types` array) as well as the list of export names if
96    /// `ImportIndex` refers to an instance. The export names array represents
97    /// recursively fetching names within an instance.
98    //
99    // TODO: this is probably a lot of `String` storage and may be something
100    // that needs optimization in the future. For example instead of lots of
101    // different `String` allocations this could instead be a pointer/length
102    // into one large string allocation for the entire component. Alternatively
103    // strings could otherwise be globally intern'd via some other mechanism to
104    // avoid `Linker`-specific intern-ing plus intern-ing here. Unsure what the
105    // best route is or whether such an optimization is even necessary here.
106    pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
107
108    /// This component's own root exports from the component itself.
109    pub exports: NameMap<String, ExportIndex>,
110
111    /// All exports of this component and exported instances of this component.
112    ///
113    /// This is indexed by `ExportIndex` for fast lookup and `Export::Instance`
114    /// will refer back into this list.
115    pub export_items: PrimaryMap<ExportIndex, Export>,
116
117    /// Initializers that must be processed when instantiating this component.
118    ///
119    /// This list of initializers does not correspond directly to the component
120    /// itself. The general goal with this is that the recursive nature of
121    /// components is "flattened" with an array like this which is a linear
122    /// sequence of instructions of how to instantiate a component. This will
123    /// have instantiations, for example, in addition to entries which
124    /// initialize `VMComponentContext` fields with previously instantiated
125    /// instances.
126    pub initializers: Vec<GlobalInitializer>,
127
128    /// The number of runtime instances (maximum `RuntimeInstanceIndex`) created
129    /// when instantiating this component.
130    pub num_runtime_instances: u32,
131
132    /// Same as `num_runtime_instances`, but for `RuntimeComponentInstanceIndex`
133    /// instead.
134    pub num_runtime_component_instances: u32,
135
136    /// The number of runtime memories (maximum `RuntimeMemoryIndex`) needed to
137    /// instantiate this component.
138    ///
139    /// Note that this many memories will be stored in the `VMComponentContext`
140    /// and each memory is intended to be unique (e.g. the same memory isn't
141    /// stored in two different locations).
142    pub num_runtime_memories: u32,
143
144    /// The number of runtime tables (maximum `RuntimeTableIndex`) needed to
145    /// instantiate this component. See notes on `num_runtime_memories`.
146    pub num_runtime_tables: u32,
147
148    /// The number of runtime reallocs (maximum `RuntimeReallocIndex`) needed to
149    /// instantiate this component.
150    ///
151    /// Note that this many function pointers will be stored in the
152    /// `VMComponentContext`.
153    pub num_runtime_reallocs: u32,
154
155    /// The number of runtime async callbacks (maximum `RuntimeCallbackIndex`)
156    /// needed to instantiate this component.
157    pub num_runtime_callbacks: u32,
158
159    /// Same as `num_runtime_reallocs`, but for post-return functions.
160    pub num_runtime_post_returns: u32,
161
162    /// WebAssembly type signature of all trampolines.
163    pub trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
164
165    /// The number of lowered host functions (maximum `LoweredIndex`) needed to
166    /// instantiate this component.
167    pub num_lowerings: u32,
168
169    /// Total number of resources both imported and defined within this
170    /// component.
171    pub num_resources: u32,
172
173    /// Maximal number of tables required at runtime for future-related
174    /// information in this component.
175    pub num_future_tables: usize,
176
177    /// Maximal number of tables required at runtime for stream-related
178    /// information in this component.
179    pub num_stream_tables: usize,
180
181    /// Maximal number of tables required at runtime for error-context-related
182    /// information in this component.
183    pub num_error_context_tables: usize,
184
185    /// Metadata about imported resources and where they are within the runtime
186    /// imports array.
187    ///
188    /// This map is only as large as the number of imported resources.
189    pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
190
191    /// Metadata about which component instances defined each resource within
192    /// this component.
193    ///
194    /// This is used to determine which set of instance flags are inspected when
195    /// testing reentrance.
196    pub defined_resource_instances: PrimaryMap<DefinedResourceIndex, RuntimeComponentInstanceIndex>,
197}
198
199impl Component {
200    /// Attempts to convert a resource index into a defined index.
201    ///
202    /// Returns `None` if `idx` is for an imported resource in this component or
203    /// `Some` if it's a locally defined resource.
204    pub fn defined_resource_index(&self, idx: ResourceIndex) -> Option<DefinedResourceIndex> {
205        let idx = idx
206            .as_u32()
207            .checked_sub(self.imported_resources.len() as u32)?;
208        Some(DefinedResourceIndex::from_u32(idx))
209    }
210
211    /// Converts a defined resource index to a component-local resource index
212    /// which includes all imports.
213    pub fn resource_index(&self, idx: DefinedResourceIndex) -> ResourceIndex {
214        ResourceIndex::from_u32(self.imported_resources.len() as u32 + idx.as_u32())
215    }
216}
217
218/// GlobalInitializer instructions to get processed when instantiating a
219/// component.
220///
221/// The variants of this enum are processed during the instantiation phase of a
222/// component in-order from front-to-back. These are otherwise emitted as a
223/// component is parsed and read and translated.
224//
225// FIXME(#2639) if processing this list is ever a bottleneck we could
226// theoretically use cranelift to compile an initialization function which
227// performs all of these duties for us and skips the overhead of interpreting
228// all of these instructions.
229#[derive(Debug, Serialize, Deserialize)]
230pub enum GlobalInitializer {
231    /// A core wasm module is being instantiated.
232    ///
233    /// This will result in a new core wasm instance being created, which may
234    /// involve running the `start` function of the instance as well if it's
235    /// specified. This largely delegates to the same standard instantiation
236    /// process as the rest of the core wasm machinery already uses.
237    InstantiateModule(InstantiateModule),
238
239    /// A host function is being lowered, creating a core wasm function.
240    ///
241    /// This initializer entry is intended to be used to fill out the
242    /// `VMComponentContext` and information about this lowering such as the
243    /// cranelift-compiled trampoline function pointer, the host function
244    /// pointer the trampoline calls, and the canonical ABI options.
245    LowerImport {
246        /// The index of the lowered function that's being created.
247        ///
248        /// This is guaranteed to be the `n`th `LowerImport` instruction
249        /// if the index is `n`.
250        index: LoweredIndex,
251
252        /// The index of the imported host function that is being lowered.
253        ///
254        /// It's guaranteed that this `RuntimeImportIndex` points to a function.
255        import: RuntimeImportIndex,
256    },
257
258    /// A core wasm linear memory is going to be saved into the
259    /// `VMComponentContext`.
260    ///
261    /// This instruction indicates that a core wasm linear memory needs to be
262    /// extracted from the `export` and stored into the `VMComponentContext` at
263    /// the `index` specified. This lowering is then used in the future by
264    /// pointers from `CanonicalOptions`.
265    ExtractMemory(ExtractMemory),
266
267    /// Same as `ExtractMemory`, except it's extracting a function pointer to be
268    /// used as a `realloc` function.
269    ExtractRealloc(ExtractRealloc),
270
271    /// Same as `ExtractMemory`, except it's extracting a function pointer to be
272    /// used as an async `callback` function.
273    ExtractCallback(ExtractCallback),
274
275    /// Same as `ExtractMemory`, except it's extracting a function pointer to be
276    /// used as a `post-return` function.
277    ExtractPostReturn(ExtractPostReturn),
278
279    /// A core wasm table is going to be saved into the `VMComponentContext`.
280    ///
281    /// This instruction indicates that s core wasm table needs to be extracted
282    /// from its `export` and stored into the `VMComponentContext` at the
283    /// `index` specified. During this extraction, we will also capture the
284    /// table's containing instance pointer to access the table at runtime. This
285    /// extraction is useful for `thread.spawn_indirect`.
286    ExtractTable(ExtractTable),
287
288    /// Declares a new defined resource within this component.
289    ///
290    /// Contains information about the destructor, for example.
291    Resource(Resource),
292}
293
294/// Metadata for extraction of a memory; contains what's being extracted (the
295/// memory at `export`) and where it's going (the `index` within a
296/// `VMComponentContext`).
297#[derive(Debug, Serialize, Deserialize)]
298pub struct ExtractMemory {
299    /// The index of the memory being defined.
300    pub index: RuntimeMemoryIndex,
301    /// Where this memory is being extracted from.
302    pub export: CoreExport<MemoryIndex>,
303}
304
305/// Same as `ExtractMemory` but for the `realloc` canonical option.
306#[derive(Debug, Serialize, Deserialize)]
307pub struct ExtractRealloc {
308    /// The index of the realloc being defined.
309    pub index: RuntimeReallocIndex,
310    /// Where this realloc is being extracted from.
311    pub def: CoreDef,
312}
313
314/// Same as `ExtractMemory` but for the `callback` canonical option.
315#[derive(Debug, Serialize, Deserialize)]
316pub struct ExtractCallback {
317    /// The index of the callback being defined.
318    pub index: RuntimeCallbackIndex,
319    /// Where this callback is being extracted from.
320    pub def: CoreDef,
321}
322
323/// Same as `ExtractMemory` but for the `post-return` canonical option.
324#[derive(Debug, Serialize, Deserialize)]
325pub struct ExtractPostReturn {
326    /// The index of the post-return being defined.
327    pub index: RuntimePostReturnIndex,
328    /// Where this post-return is being extracted from.
329    pub def: CoreDef,
330}
331
332/// Metadata for extraction of a table.
333#[derive(Debug, Serialize, Deserialize)]
334pub struct ExtractTable {
335    /// The index of the table being defined in a `VMComponentContext`.
336    pub index: RuntimeTableIndex,
337    /// Where this table is being extracted from.
338    pub export: CoreExport<TableIndex>,
339}
340
341/// Different methods of instantiating a core wasm module.
342#[derive(Debug, Serialize, Deserialize)]
343pub enum InstantiateModule {
344    /// A module defined within this component is being instantiated.
345    ///
346    /// Note that this is distinct from the case of imported modules because the
347    /// order of imports required is statically known and can be pre-calculated
348    /// to avoid string lookups related to names at runtime, represented by the
349    /// flat list of arguments here.
350    Static(StaticModuleIndex, Box<[CoreDef]>),
351
352    /// An imported module is being instantiated.
353    ///
354    /// This is similar to `Upvar` but notably the imports are provided as a
355    /// two-level named map since import resolution order needs to happen at
356    /// runtime.
357    Import(
358        RuntimeImportIndex,
359        IndexMap<String, IndexMap<String, CoreDef>>,
360    ),
361}
362
363/// Definition of a core wasm item and where it can come from within a
364/// component.
365///
366/// Note that this is sort of a result of data-flow-like analysis on a component
367/// during compile time of the component itself. References to core wasm items
368/// are "compiled" to either referring to a previous instance or to some sort of
369/// lowered host import.
370#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
371pub enum CoreDef {
372    /// This item refers to an export of a previously instantiated core wasm
373    /// instance.
374    Export(CoreExport<EntityIndex>),
375    /// This is a reference to a wasm global which represents the
376    /// runtime-managed flags for a wasm instance.
377    InstanceFlags(RuntimeComponentInstanceIndex),
378    /// This is a reference to a Cranelift-generated trampoline which is
379    /// described in the `trampolines` array.
380    Trampoline(TrampolineIndex),
381}
382
383impl<T> From<CoreExport<T>> for CoreDef
384where
385    EntityIndex: From<T>,
386{
387    fn from(export: CoreExport<T>) -> CoreDef {
388        CoreDef::Export(export.map_index(|i| i.into()))
389    }
390}
391
392/// Identifier of an exported item from a core WebAssembly module instance.
393///
394/// Note that the `T` here is the index type for exports which can be
395/// identified by index. The `T` is monomorphized with types like
396/// [`EntityIndex`] or [`FuncIndex`].
397#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
398pub struct CoreExport<T> {
399    /// The instance that this item is located within.
400    ///
401    /// Note that this is intended to index the `instances` map within a
402    /// component. It's validated ahead of time that all instance pointers
403    /// refer only to previously-created instances.
404    pub instance: RuntimeInstanceIndex,
405
406    /// The item that this export is referencing, either by name or by index.
407    pub item: ExportItem<T>,
408}
409
410impl<T> CoreExport<T> {
411    /// Maps the index type `T` to another type `U` if this export item indeed
412    /// refers to an index `T`.
413    pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
414        CoreExport {
415            instance: self.instance,
416            item: match self.item {
417                ExportItem::Index(i) => ExportItem::Index(f(i)),
418                ExportItem::Name(s) => ExportItem::Name(s),
419            },
420        }
421    }
422}
423
424/// An index at which to find an item within a runtime instance.
425#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
426pub enum ExportItem<T> {
427    /// An exact index that the target can be found at.
428    ///
429    /// This is used where possible to avoid name lookups at runtime during the
430    /// instantiation process. This can only be used on instances where the
431    /// module was statically known at compile time, however.
432    Index(T),
433
434    /// An item which is identified by a name, so at runtime we need to
435    /// perform a name lookup to determine the index that the item is located
436    /// at.
437    ///
438    /// This is used for instantiations of imported modules, for example, since
439    /// the precise shape of the module is not known.
440    Name(String),
441}
442
443/// Possible exports from a component.
444#[derive(Debug, Clone, Serialize, Deserialize)]
445pub enum Export {
446    /// A lifted function being exported which is an adaptation of a core wasm
447    /// function.
448    LiftedFunction {
449        /// The component function type of the function being created.
450        ty: TypeFuncIndex,
451        /// Which core WebAssembly export is being lifted.
452        func: CoreDef,
453        /// Any options, if present, associated with this lifting.
454        options: CanonicalOptions,
455    },
456    /// A module defined within this component is exported.
457    ModuleStatic {
458        /// The type of this module
459        ty: TypeModuleIndex,
460        /// Which module this is referring to.
461        index: StaticModuleIndex,
462    },
463    /// A module imported into this component is exported.
464    ModuleImport {
465        /// Module type index
466        ty: TypeModuleIndex,
467        /// Module runtime import index
468        import: RuntimeImportIndex,
469    },
470    /// A nested instance is being exported which has recursively defined
471    /// `Export` items.
472    Instance {
473        /// Instance type index, if such is assigned
474        ty: TypeComponentInstanceIndex,
475        /// Instance export map
476        exports: NameMap<String, ExportIndex>,
477    },
478    /// An exported type from a component or instance, currently only
479    /// informational.
480    Type(TypeDef),
481}
482
483#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
484/// Data is stored in a linear memory.
485pub struct LinearMemoryOptions {
486    /// The memory used by these options, if specified.
487    pub memory: Option<RuntimeMemoryIndex>,
488    /// The realloc function used by these options, if specified.
489    pub realloc: Option<RuntimeReallocIndex>,
490}
491
492/// The data model for objects that are not unboxed in locals.
493#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
494pub enum CanonicalOptionsDataModel {
495    /// Data is stored in GC objects.
496    Gc {},
497
498    /// Data is stored in a linear memory.
499    LinearMemory(LinearMemoryOptions),
500}
501
502/// Canonical ABI options associated with a lifted or lowered function.
503#[derive(Debug, Clone, Serialize, Deserialize)]
504pub struct CanonicalOptions {
505    /// The component instance that this bundle was associated with.
506    pub instance: RuntimeComponentInstanceIndex,
507
508    /// The encoding used for strings.
509    pub string_encoding: StringEncoding,
510
511    /// The async callback function used by these options, if specified.
512    pub callback: Option<RuntimeCallbackIndex>,
513
514    /// The post-return function used by these options, if specified.
515    pub post_return: Option<RuntimePostReturnIndex>,
516
517    /// Whether to use the async ABI for lifting or lowering.
518    pub async_: bool,
519
520    /// The core function type that is being lifted from / lowered to.
521    pub core_type: ModuleInternedTypeIndex,
522
523    /// The data model (GC objects or linear memory) used with these canonical
524    /// options.
525    pub data_model: CanonicalOptionsDataModel,
526}
527
528/// Possible encodings of strings within the component model.
529#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
530#[expect(missing_docs, reason = "self-describing variants")]
531pub enum StringEncoding {
532    Utf8,
533    Utf16,
534    CompactUtf16,
535}
536
537impl StringEncoding {
538    /// Decodes the `u8` provided back into a `StringEncoding`, if it's valid.
539    pub fn from_u8(val: u8) -> Option<StringEncoding> {
540        if val == StringEncoding::Utf8 as u8 {
541            return Some(StringEncoding::Utf8);
542        }
543        if val == StringEncoding::Utf16 as u8 {
544            return Some(StringEncoding::Utf16);
545        }
546        if val == StringEncoding::CompactUtf16 as u8 {
547            return Some(StringEncoding::CompactUtf16);
548        }
549        None
550    }
551}
552
553/// Possible transcoding operations that must be provided by the host.
554///
555/// Note that each transcoding operation may have a unique signature depending
556/// on the precise operation.
557#[expect(missing_docs, reason = "self-describing variants")]
558#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
559pub enum Transcode {
560    Copy(FixedEncoding),
561    Latin1ToUtf16,
562    Latin1ToUtf8,
563    Utf16ToCompactProbablyUtf16,
564    Utf16ToCompactUtf16,
565    Utf16ToLatin1,
566    Utf16ToUtf8,
567    Utf8ToCompactUtf16,
568    Utf8ToLatin1,
569    Utf8ToUtf16,
570}
571
572impl Transcode {
573    /// Get this transcoding's symbol fragment.
574    pub fn symbol_fragment(&self) -> &'static str {
575        match self {
576            Transcode::Copy(x) => match x {
577                FixedEncoding::Utf8 => "copy_utf8",
578                FixedEncoding::Utf16 => "copy_utf16",
579                FixedEncoding::Latin1 => "copy_latin1",
580            },
581            Transcode::Latin1ToUtf16 => "latin1_to_utf16",
582            Transcode::Latin1ToUtf8 => "latin1_to_utf8",
583            Transcode::Utf16ToCompactProbablyUtf16 => "utf16_to_compact_probably_utf16",
584            Transcode::Utf16ToCompactUtf16 => "utf16_to_compact_utf16",
585            Transcode::Utf16ToLatin1 => "utf16_to_latin1",
586            Transcode::Utf16ToUtf8 => "utf16_to_utf8",
587            Transcode::Utf8ToCompactUtf16 => "utf8_to_compact_utf16",
588            Transcode::Utf8ToLatin1 => "utf8_to_latin1",
589            Transcode::Utf8ToUtf16 => "utf8_to_utf16",
590        }
591    }
592
593    /// Returns a human-readable description for this transcoding operation.
594    pub fn desc(&self) -> &'static str {
595        match self {
596            Transcode::Copy(FixedEncoding::Utf8) => "utf8-to-utf8",
597            Transcode::Copy(FixedEncoding::Utf16) => "utf16-to-utf16",
598            Transcode::Copy(FixedEncoding::Latin1) => "latin1-to-latin1",
599            Transcode::Latin1ToUtf16 => "latin1-to-utf16",
600            Transcode::Latin1ToUtf8 => "latin1-to-utf8",
601            Transcode::Utf16ToCompactProbablyUtf16 => "utf16-to-compact-probably-utf16",
602            Transcode::Utf16ToCompactUtf16 => "utf16-to-compact-utf16",
603            Transcode::Utf16ToLatin1 => "utf16-to-latin1",
604            Transcode::Utf16ToUtf8 => "utf16-to-utf8",
605            Transcode::Utf8ToCompactUtf16 => "utf8-to-compact-utf16",
606            Transcode::Utf8ToLatin1 => "utf8-to-latin1",
607            Transcode::Utf8ToUtf16 => "utf8-to-utf16",
608        }
609    }
610}
611
612#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
613#[expect(missing_docs, reason = "self-describing variants")]
614pub enum FixedEncoding {
615    Utf8,
616    Utf16,
617    Latin1,
618}
619
620impl FixedEncoding {
621    /// Returns the byte width of unit loads/stores for this encoding, for
622    /// example the unit length is multiplied by this return value to get the
623    /// byte width of a string.
624    pub fn width(&self) -> u8 {
625        match self {
626            FixedEncoding::Utf8 => 1,
627            FixedEncoding::Utf16 => 2,
628            FixedEncoding::Latin1 => 1,
629        }
630    }
631}
632
633/// Description of a new resource declared in a `GlobalInitializer::Resource`
634/// variant.
635///
636/// This will have the effect of initializing runtime state for this resource,
637/// namely the destructor is fetched and stored.
638#[derive(Debug, Serialize, Deserialize)]
639pub struct Resource {
640    /// The local index of the resource being defined.
641    pub index: DefinedResourceIndex,
642    /// Core wasm representation of this resource.
643    pub rep: WasmValType,
644    /// Optionally-specified destructor and where it comes from.
645    pub dtor: Option<CoreDef>,
646    /// Which component instance this resource logically belongs to.
647    pub instance: RuntimeComponentInstanceIndex,
648}
649
650/// A list of all possible trampolines that may be required to compile a
651/// component completely.
652///
653/// These trampolines are used often as core wasm definitions and require
654/// Cranelift support to generate these functions. Each trampoline serves a
655/// different purpose for implementing bits and pieces of the component model.
656///
657/// All trampolines have a core wasm function signature associated with them
658/// which is stored in the `Component::trampolines` array.
659///
660/// Note that this type does not implement `Serialize` or `Deserialize` and
661/// that's intentional as this isn't stored in the final compilation artifact.
662#[derive(Debug)]
663pub enum Trampoline {
664    /// Description of a lowered import used in conjunction with
665    /// `GlobalInitializer::LowerImport`.
666    LowerImport {
667        /// The runtime lowering state that this trampoline will access.
668        index: LoweredIndex,
669
670        /// The type of the function that is being lowered, as perceived by the
671        /// component doing the lowering.
672        lower_ty: TypeFuncIndex,
673
674        /// The canonical ABI options used when lowering this function specified
675        /// in the original component.
676        options: CanonicalOptions,
677    },
678
679    /// Information about a string transcoding function required by an adapter
680    /// module.
681    ///
682    /// A transcoder is used when strings are passed between adapter modules,
683    /// optionally changing string encodings at the same time. The transcoder is
684    /// implemented in a few different layers:
685    ///
686    /// * Each generated adapter module has some glue around invoking the
687    ///   transcoder represented by this item. This involves bounds-checks and
688    ///   handling `realloc` for example.
689    /// * Each transcoder gets a cranelift-generated trampoline which has the
690    ///   appropriate signature for the adapter module in question. Existence of
691    ///   this initializer indicates that this should be compiled by Cranelift.
692    /// * The cranelift-generated trampoline will invoke a "transcoder libcall"
693    ///   which is implemented natively in Rust that has a signature independent
694    ///   of memory64 configuration options for example.
695    Transcoder {
696        /// The transcoding operation being performed.
697        op: Transcode,
698        /// The linear memory that the string is being read from.
699        from: RuntimeMemoryIndex,
700        /// Whether or not the source linear memory is 64-bit or not.
701        from64: bool,
702        /// The linear memory that the string is being written to.
703        to: RuntimeMemoryIndex,
704        /// Whether or not the destination linear memory is 64-bit or not.
705        to64: bool,
706    },
707
708    /// A small adapter which simply traps, used for degenerate lift/lower
709    /// combinations.
710    AlwaysTrap,
711
712    /// A `resource.new` intrinsic which will inject a new resource into the
713    /// table specified.
714    ResourceNew(TypeResourceTableIndex),
715
716    /// Same as `ResourceNew`, but for the `resource.rep` intrinsic.
717    ResourceRep(TypeResourceTableIndex),
718
719    /// Same as `ResourceNew`, but for the `resource.drop` intrinsic.
720    ResourceDrop(TypeResourceTableIndex),
721
722    /// A `backpressure.set` intrinsic, which tells the host to enable or
723    /// disable backpressure for the caller's instance.
724    BackpressureSet {
725        /// The specific component instance which is calling the intrinsic.
726        instance: RuntimeComponentInstanceIndex,
727    },
728
729    /// A `task.return` intrinsic, which returns a result to the caller of a
730    /// lifted export function.  This allows the callee to continue executing
731    /// after returning a result.
732    TaskReturn {
733        /// Tuple representing the result types this intrinsic accepts.
734        results: TypeTupleIndex,
735
736        /// The canonical ABI options specified for this intrinsic.
737        options: CanonicalOptions,
738    },
739
740    /// A `task.cancel` intrinsic, which acknowledges a `CANCELLED` event
741    /// delivered to a guest task previously created by a call to an async
742    /// export.
743    TaskCancel {
744        /// The specific component instance which is calling the intrinsic.
745        instance: RuntimeComponentInstanceIndex,
746    },
747
748    /// A `waitable-set.new` intrinsic.
749    WaitableSetNew {
750        /// The specific component instance which is calling the intrinsic.
751        instance: RuntimeComponentInstanceIndex,
752    },
753
754    /// A `waitable-set.wait` intrinsic, which waits for at least one
755    /// outstanding async task/stream/future to make progress, returning the
756    /// first such event.
757    WaitableSetWait {
758        /// The specific component instance which is calling the intrinsic.
759        instance: RuntimeComponentInstanceIndex,
760        /// If `true`, indicates the caller instance maybe reentered.
761        async_: bool,
762        /// Memory to use when storing the event.
763        memory: RuntimeMemoryIndex,
764    },
765
766    /// A `waitable-set.poll` intrinsic, which checks whether any outstanding
767    /// async task/stream/future has made progress.  Unlike `task.wait`, this
768    /// does not block and may return nothing if no such event has occurred.
769    WaitableSetPoll {
770        /// The specific component instance which is calling the intrinsic.
771        instance: RuntimeComponentInstanceIndex,
772        /// If `true`, indicates the caller instance maybe reentered.
773        async_: bool,
774        /// Memory to use when storing the event.
775        memory: RuntimeMemoryIndex,
776    },
777
778    /// A `waitable-set.drop` intrinsic.
779    WaitableSetDrop {
780        /// The specific component instance which is calling the intrinsic.
781        instance: RuntimeComponentInstanceIndex,
782    },
783
784    /// A `waitable.join` intrinsic.
785    WaitableJoin {
786        /// The specific component instance which is calling the intrinsic.
787        instance: RuntimeComponentInstanceIndex,
788    },
789
790    /// A `yield` intrinsic, which yields control to the host so that other
791    /// tasks are able to make progress, if any.
792    Yield {
793        /// If `true`, indicates the caller instance maybe reentered.
794        async_: bool,
795    },
796
797    /// A `subtask.drop` intrinsic to drop a specified task which has completed.
798    SubtaskDrop {
799        /// The specific component instance which is calling the intrinsic.
800        instance: RuntimeComponentInstanceIndex,
801    },
802
803    /// A `subtask.cancel` intrinsic to drop an in-progress task.
804    SubtaskCancel {
805        /// The specific component instance which is calling the intrinsic.
806        instance: RuntimeComponentInstanceIndex,
807        /// If `false`, block until cancellation completes rather than return
808        /// `BLOCKED`.
809        async_: bool,
810    },
811
812    /// A `stream.new` intrinsic to create a new `stream` handle of the
813    /// specified type.
814    StreamNew {
815        /// The table index for the specific `stream` type and caller instance.
816        ty: TypeStreamTableIndex,
817    },
818
819    /// A `stream.read` intrinsic to read from a `stream` of the specified type.
820    StreamRead {
821        /// The table index for the specific `stream` type and caller instance.
822        ty: TypeStreamTableIndex,
823
824        /// Any options (e.g. string encoding) to use when storing values to
825        /// memory.
826        options: CanonicalOptions,
827    },
828
829    /// A `stream.write` intrinsic to write to a `stream` of the specified type.
830    StreamWrite {
831        /// The table index for the specific `stream` type and caller instance.
832        ty: TypeStreamTableIndex,
833
834        /// Any options (e.g. string encoding) to use when storing values to
835        /// memory.
836        options: CanonicalOptions,
837    },
838
839    /// A `stream.cancel-read` intrinsic to cancel an in-progress read from a
840    /// `stream` of the specified type.
841    StreamCancelRead {
842        /// The table index for the specific `stream` type and caller instance.
843        ty: TypeStreamTableIndex,
844        /// If `false`, block until cancellation completes rather than return
845        /// `BLOCKED`.
846        async_: bool,
847    },
848
849    /// A `stream.cancel-write` intrinsic to cancel an in-progress write from a
850    /// `stream` of the specified type.
851    StreamCancelWrite {
852        /// The table index for the specific `stream` type and caller instance.
853        ty: TypeStreamTableIndex,
854        /// If `false`, block until cancellation completes rather than return
855        /// `BLOCKED`.
856        async_: bool,
857    },
858
859    /// A `stream.drop-readable` intrinsic to close the readable end of a
860    /// `stream` of the specified type.
861    StreamDropReadable {
862        /// The table index for the specific `stream` type and caller instance.
863        ty: TypeStreamTableIndex,
864    },
865
866    /// A `stream.drop-writable` intrinsic to close the writable end of a
867    /// `stream` of the specified type.
868    StreamDropWritable {
869        /// The table index for the specific `stream` type and caller instance.
870        ty: TypeStreamTableIndex,
871    },
872
873    /// A `future.new` intrinsic to create a new `future` handle of the
874    /// specified type.
875    FutureNew {
876        /// The table index for the specific `future` type and caller instance.
877        ty: TypeFutureTableIndex,
878    },
879
880    /// A `future.read` intrinsic to read from a `future` of the specified type.
881    FutureRead {
882        /// The table index for the specific `future` type and caller instance.
883        ty: TypeFutureTableIndex,
884
885        /// Any options (e.g. string encoding) to use when storing values to
886        /// memory.
887        options: CanonicalOptions,
888    },
889
890    /// A `future.write` intrinsic to write to a `future` of the specified type.
891    FutureWrite {
892        /// The table index for the specific `future` type and caller instance.
893        ty: TypeFutureTableIndex,
894
895        /// Any options (e.g. string encoding) to use when storing values to
896        /// memory.
897        options: CanonicalOptions,
898    },
899
900    /// A `future.cancel-read` intrinsic to cancel an in-progress read from a
901    /// `future` of the specified type.
902    FutureCancelRead {
903        /// The table index for the specific `future` type and caller instance.
904        ty: TypeFutureTableIndex,
905        /// If `false`, block until cancellation completes rather than return
906        /// `BLOCKED`.
907        async_: bool,
908    },
909
910    /// A `future.cancel-write` intrinsic to cancel an in-progress write from a
911    /// `future` of the specified type.
912    FutureCancelWrite {
913        /// The table index for the specific `future` type and caller instance.
914        ty: TypeFutureTableIndex,
915        /// If `false`, block until cancellation completes rather than return
916        /// `BLOCKED`.
917        async_: bool,
918    },
919
920    /// A `future.drop-readable` intrinsic to close the readable end of a
921    /// `future` of the specified type.
922    FutureDropReadable {
923        /// The table index for the specific `future` type and caller instance.
924        ty: TypeFutureTableIndex,
925    },
926
927    /// A `future.drop-writable` intrinsic to close the writable end of a
928    /// `future` of the specified type.
929    FutureDropWritable {
930        /// The table index for the specific `future` type and caller instance.
931        ty: TypeFutureTableIndex,
932    },
933
934    /// A `error-context.new` intrinsic to create a new `error-context` with a
935    /// specified debug message.
936    ErrorContextNew {
937        /// The table index for the `error-context` type in the caller instance.
938        ty: TypeComponentLocalErrorContextTableIndex,
939        /// String encoding, memory, etc. to use when loading debug message.
940        options: CanonicalOptions,
941    },
942
943    /// A `error-context.debug-message` intrinsic to get the debug message for a
944    /// specified `error-context`.
945    ///
946    /// Note that the debug message might not necessarily match what was passed
947    /// to `error.new`.
948    ErrorContextDebugMessage {
949        /// The table index for the `error-context` type in the caller instance.
950        ty: TypeComponentLocalErrorContextTableIndex,
951        /// String encoding, memory, etc. to use when storing debug message.
952        options: CanonicalOptions,
953    },
954
955    /// A `error-context.drop` intrinsic to drop a specified `error-context`.
956    ErrorContextDrop {
957        /// The table index for the `error-context` type in the caller instance.
958        ty: TypeComponentLocalErrorContextTableIndex,
959    },
960
961    /// An intrinsic used by FACT-generated modules which will transfer an owned
962    /// resource from one table to another. Used in component-to-component
963    /// adapter trampolines.
964    ResourceTransferOwn,
965
966    /// Same as `ResourceTransferOwn` but for borrows.
967    ResourceTransferBorrow,
968
969    /// An intrinsic used by FACT-generated modules which indicates that a call
970    /// is being entered and resource-related metadata needs to be configured.
971    ///
972    /// Note that this is currently only invoked when borrowed resources are
973    /// detected, otherwise this is "optimized out".
974    ResourceEnterCall,
975
976    /// Same as `ResourceEnterCall` except for when exiting a call.
977    ResourceExitCall,
978
979    /// An intrinsic used by FACT-generated modules to prepare a call involving
980    /// an async-lowered import and/or an async-lifted export.
981    PrepareCall {
982        /// The memory used to verify that the memory specified for the
983        /// `task.return` that is called at runtime matches the one specified in
984        /// the lifted export.
985        memory: Option<RuntimeMemoryIndex>,
986    },
987
988    /// An intrinsic used by FACT-generated modules to start a call involving a
989    /// sync-lowered import and async-lifted export.
990    SyncStartCall {
991        /// The callee's callback function, if any.
992        callback: Option<RuntimeCallbackIndex>,
993    },
994
995    /// An intrinsic used by FACT-generated modules to start a call involving
996    /// an async-lowered import function.
997    ///
998    /// Note that `AsyncPrepareCall` and `AsyncStartCall` could theoretically be
999    /// combined into a single `AsyncCall` intrinsic, but we separate them to
1000    /// allow the FACT-generated module to optionally call the callee directly
1001    /// without an intermediate host stack frame.
1002    AsyncStartCall {
1003        /// The callee's callback, if any.
1004        callback: Option<RuntimeCallbackIndex>,
1005
1006        /// The callee's post-return function, if any.
1007        post_return: Option<RuntimePostReturnIndex>,
1008    },
1009
1010    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
1011    /// ownership of a `future`.
1012    ///
1013    /// Transferring a `future` can either mean giving away the readable end
1014    /// while retaining the writable end or only the former, depending on the
1015    /// ownership status of the `future`.
1016    FutureTransfer,
1017
1018    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
1019    /// ownership of a `stream`.
1020    ///
1021    /// Transferring a `stream` can either mean giving away the readable end
1022    /// while retaining the writable end or only the former, depending on the
1023    /// ownership status of the `stream`.
1024    StreamTransfer,
1025
1026    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
1027    /// ownership of an `error-context`.
1028    ///
1029    /// Unlike futures, streams, and resource handles, `error-context` handles
1030    /// are reference counted, meaning that sharing the handle with another
1031    /// component does not invalidate the handle in the original component.
1032    ErrorContextTransfer,
1033
1034    /// Intrinsic used to implement the `context.get` component model builtin.
1035    ///
1036    /// The payload here represents that this is accessing the Nth slot of local
1037    /// storage.
1038    ContextGet(u32),
1039
1040    /// Intrinsic used to implement the `context.set` component model builtin.
1041    ///
1042    /// The payload here represents that this is accessing the Nth slot of local
1043    /// storage.
1044    ContextSet(u32),
1045}
1046
1047impl Trampoline {
1048    /// Returns the name to use for the symbol of this trampoline in the final
1049    /// compiled artifact
1050    pub fn symbol_name(&self) -> String {
1051        use Trampoline::*;
1052        match self {
1053            LowerImport { index, .. } => {
1054                format!("component-lower-import[{}]", index.as_u32())
1055            }
1056            Transcoder {
1057                op, from64, to64, ..
1058            } => {
1059                let op = op.symbol_fragment();
1060                let from = if *from64 { "64" } else { "32" };
1061                let to = if *to64 { "64" } else { "32" };
1062                format!("component-transcode-{op}-m{from}-m{to}")
1063            }
1064            AlwaysTrap => format!("component-always-trap"),
1065            ResourceNew(i) => format!("component-resource-new[{}]", i.as_u32()),
1066            ResourceRep(i) => format!("component-resource-rep[{}]", i.as_u32()),
1067            ResourceDrop(i) => format!("component-resource-drop[{}]", i.as_u32()),
1068            BackpressureSet { .. } => format!("backpressure-set"),
1069            TaskReturn { .. } => format!("task-return"),
1070            TaskCancel { .. } => format!("task-cancel"),
1071            WaitableSetNew { .. } => format!("waitable-set-new"),
1072            WaitableSetWait { .. } => format!("waitable-set-wait"),
1073            WaitableSetPoll { .. } => format!("waitable-set-poll"),
1074            WaitableSetDrop { .. } => format!("waitable-set-drop"),
1075            WaitableJoin { .. } => format!("waitable-join"),
1076            Yield { .. } => format!("yield"),
1077            SubtaskDrop { .. } => format!("subtask-drop"),
1078            SubtaskCancel { .. } => format!("subtask-cancel"),
1079            StreamNew { .. } => format!("stream-new"),
1080            StreamRead { .. } => format!("stream-read"),
1081            StreamWrite { .. } => format!("stream-write"),
1082            StreamCancelRead { .. } => format!("stream-cancel-read"),
1083            StreamCancelWrite { .. } => format!("stream-cancel-write"),
1084            StreamDropReadable { .. } => format!("stream.drop-readable"),
1085            StreamDropWritable { .. } => format!("stream.drop-writable"),
1086            FutureNew { .. } => format!("future-new"),
1087            FutureRead { .. } => format!("future-read"),
1088            FutureWrite { .. } => format!("future-write"),
1089            FutureCancelRead { .. } => format!("future-cancel-read"),
1090            FutureCancelWrite { .. } => format!("future-cancel-write"),
1091            FutureDropReadable { .. } => format!("future.drop-readable"),
1092            FutureDropWritable { .. } => format!("future.drop-writable"),
1093            ErrorContextNew { .. } => format!("error-context-new"),
1094            ErrorContextDebugMessage { .. } => format!("error-context-debug-message"),
1095            ErrorContextDrop { .. } => format!("error-context-drop"),
1096            ResourceTransferOwn => format!("component-resource-transfer-own"),
1097            ResourceTransferBorrow => format!("component-resource-transfer-borrow"),
1098            ResourceEnterCall => format!("component-resource-enter-call"),
1099            ResourceExitCall => format!("component-resource-exit-call"),
1100            PrepareCall { .. } => format!("component-prepare-call"),
1101            SyncStartCall { .. } => format!("component-sync-start-call"),
1102            AsyncStartCall { .. } => format!("component-async-start-call"),
1103            FutureTransfer => format!("future-transfer"),
1104            StreamTransfer => format!("stream-transfer"),
1105            ErrorContextTransfer => format!("error-context-transfer"),
1106            ContextGet(_) => format!("context-get"),
1107            ContextSet(_) => format!("context-set"),
1108        }
1109    }
1110}