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 reallocs (maximum `RuntimeReallocIndex`) needed to
145    /// instantiate this component.
146    ///
147    /// Note that this many function pointers will be stored in the
148    /// `VMComponentContext`.
149    pub num_runtime_reallocs: u32,
150
151    /// The number of runtime async callbacks (maximum `RuntimeCallbackIndex`)
152    /// needed to instantiate this component.
153    pub num_runtime_callbacks: u32,
154
155    /// Same as `num_runtime_reallocs`, but for post-return functions.
156    pub num_runtime_post_returns: u32,
157
158    /// WebAssembly type signature of all trampolines.
159    pub trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
160
161    /// The number of lowered host functions (maximum `LoweredIndex`) needed to
162    /// instantiate this component.
163    pub num_lowerings: u32,
164
165    /// Maximal number of tables required at runtime for resource-related
166    /// information in this component.
167    pub num_resource_tables: usize,
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 component
219///
220/// The variants of this enum are processed during the instantiation phase of
221/// a component in-order from front-to-back. These are otherwise emitted as a
222/// component is parsed and read and translated.
223//
224// FIXME(#2639) if processing this list is ever a bottleneck we could
225// theoretically use cranelift to compile an initialization function which
226// performs all of these duties for us and skips the overhead of interpreting
227// all of these instructions.
228#[derive(Debug, Serialize, Deserialize)]
229pub enum GlobalInitializer {
230    /// A core wasm module is being instantiated.
231    ///
232    /// This will result in a new core wasm instance being created, which may
233    /// involve running the `start` function of the instance as well if it's
234    /// specified. This largely delegates to the same standard instantiation
235    /// process as the rest of the core wasm machinery already uses.
236    InstantiateModule(InstantiateModule),
237
238    /// A host function is being lowered, creating a core wasm function.
239    ///
240    /// This initializer entry is intended to be used to fill out the
241    /// `VMComponentContext` and information about this lowering such as the
242    /// cranelift-compiled trampoline function pointer, the host function
243    /// pointer the trampoline calls, and the canonical ABI options.
244    LowerImport {
245        /// The index of the lowered function that's being created.
246        ///
247        /// This is guaranteed to be the `n`th `LowerImport` instruction
248        /// if the index is `n`.
249        index: LoweredIndex,
250
251        /// The index of the imported host function that is being lowered.
252        ///
253        /// It's guaranteed that this `RuntimeImportIndex` points to a function.
254        import: RuntimeImportIndex,
255    },
256
257    /// A core wasm linear memory is going to be saved into the
258    /// `VMComponentContext`.
259    ///
260    /// This instruction indicates that the `index`th core wasm linear memory
261    /// needs to be extracted from the `export` specified, a pointer to a
262    /// previously created module instance, and stored into the
263    /// `VMComponentContext` at the `index` specified. This lowering is then
264    /// used in the future by 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    /// Declares a new defined resource within this component.
280    ///
281    /// Contains information about the destructor, for example.
282    Resource(Resource),
283}
284
285/// Metadata for extraction of a memory of what's being extracted and where it's
286/// going.
287#[derive(Debug, Serialize, Deserialize)]
288pub struct ExtractMemory {
289    /// The index of the memory being defined.
290    pub index: RuntimeMemoryIndex,
291    /// Where this memory is being extracted from.
292    pub export: CoreExport<MemoryIndex>,
293}
294
295/// Same as `ExtractMemory` but for the `realloc` canonical option.
296#[derive(Debug, Serialize, Deserialize)]
297pub struct ExtractRealloc {
298    /// The index of the realloc being defined.
299    pub index: RuntimeReallocIndex,
300    /// Where this realloc is being extracted from.
301    pub def: CoreDef,
302}
303
304/// Same as `ExtractMemory` but for the `callback` canonical option.
305#[derive(Debug, Serialize, Deserialize)]
306pub struct ExtractCallback {
307    /// The index of the callback being defined.
308    pub index: RuntimeCallbackIndex,
309    /// Where this callback is being extracted from.
310    pub def: CoreDef,
311}
312
313/// Same as `ExtractMemory` but for the `post-return` canonical option.
314#[derive(Debug, Serialize, Deserialize)]
315pub struct ExtractPostReturn {
316    /// The index of the post-return being defined.
317    pub index: RuntimePostReturnIndex,
318    /// Where this post-return is being extracted from.
319    pub def: CoreDef,
320}
321
322/// Different methods of instantiating a core wasm module.
323#[derive(Debug, Serialize, Deserialize)]
324pub enum InstantiateModule {
325    /// A module defined within this component is being instantiated.
326    ///
327    /// Note that this is distinct from the case of imported modules because the
328    /// order of imports required is statically known and can be pre-calculated
329    /// to avoid string lookups related to names at runtime, represented by the
330    /// flat list of arguments here.
331    Static(StaticModuleIndex, Box<[CoreDef]>),
332
333    /// An imported module is being instantiated.
334    ///
335    /// This is similar to `Upvar` but notably the imports are provided as a
336    /// two-level named map since import resolution order needs to happen at
337    /// runtime.
338    Import(
339        RuntimeImportIndex,
340        IndexMap<String, IndexMap<String, CoreDef>>,
341    ),
342}
343
344/// Definition of a core wasm item and where it can come from within a
345/// component.
346///
347/// Note that this is sort of a result of data-flow-like analysis on a component
348/// during compile time of the component itself. References to core wasm items
349/// are "compiled" to either referring to a previous instance or to some sort of
350/// lowered host import.
351#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
352pub enum CoreDef {
353    /// This item refers to an export of a previously instantiated core wasm
354    /// instance.
355    Export(CoreExport<EntityIndex>),
356    /// This is a reference to a wasm global which represents the
357    /// runtime-managed flags for a wasm instance.
358    InstanceFlags(RuntimeComponentInstanceIndex),
359    /// This is a reference to a Cranelift-generated trampoline which is
360    /// described in the `trampolines` array.
361    Trampoline(TrampolineIndex),
362}
363
364impl<T> From<CoreExport<T>> for CoreDef
365where
366    EntityIndex: From<T>,
367{
368    fn from(export: CoreExport<T>) -> CoreDef {
369        CoreDef::Export(export.map_index(|i| i.into()))
370    }
371}
372
373/// Identifier of an exported item from a core WebAssembly module instance.
374///
375/// Note that the `T` here is the index type for exports which can be
376/// identified by index. The `T` is monomorphized with types like
377/// [`EntityIndex`] or [`FuncIndex`].
378#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
379pub struct CoreExport<T> {
380    /// The instance that this item is located within.
381    ///
382    /// Note that this is intended to index the `instances` map within a
383    /// component. It's validated ahead of time that all instance pointers
384    /// refer only to previously-created instances.
385    pub instance: RuntimeInstanceIndex,
386
387    /// The item that this export is referencing, either by name or by index.
388    pub item: ExportItem<T>,
389}
390
391impl<T> CoreExport<T> {
392    /// Maps the index type `T` to another type `U` if this export item indeed
393    /// refers to an index `T`.
394    pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
395        CoreExport {
396            instance: self.instance,
397            item: match self.item {
398                ExportItem::Index(i) => ExportItem::Index(f(i)),
399                ExportItem::Name(s) => ExportItem::Name(s),
400            },
401        }
402    }
403}
404
405/// An index at which to find an item within a runtime instance.
406#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]
407pub enum ExportItem<T> {
408    /// An exact index that the target can be found at.
409    ///
410    /// This is used where possible to avoid name lookups at runtime during the
411    /// instantiation process. This can only be used on instances where the
412    /// module was statically known at compile time, however.
413    Index(T),
414
415    /// An item which is identified by a name, so at runtime we need to
416    /// perform a name lookup to determine the index that the item is located
417    /// at.
418    ///
419    /// This is used for instantiations of imported modules, for example, since
420    /// the precise shape of the module is not known.
421    Name(String),
422}
423
424/// Possible exports from a component.
425#[derive(Debug, Clone, Serialize, Deserialize)]
426pub enum Export {
427    /// A lifted function being exported which is an adaptation of a core wasm
428    /// function.
429    LiftedFunction {
430        /// The component function type of the function being created.
431        ty: TypeFuncIndex,
432        /// Which core WebAssembly export is being lifted.
433        func: CoreDef,
434        /// Any options, if present, associated with this lifting.
435        options: CanonicalOptions,
436    },
437    /// A module defined within this component is exported.
438    ModuleStatic {
439        /// The type of this module
440        ty: TypeModuleIndex,
441        /// Which module this is referring to.
442        index: StaticModuleIndex,
443    },
444    /// A module imported into this component is exported.
445    ModuleImport {
446        /// Module type index
447        ty: TypeModuleIndex,
448        /// Module runtime import index
449        import: RuntimeImportIndex,
450    },
451    /// A nested instance is being exported which has recursively defined
452    /// `Export` items.
453    Instance {
454        /// Instance type index, if such is assigned
455        ty: TypeComponentInstanceIndex,
456        /// Instance export map
457        exports: NameMap<String, ExportIndex>,
458    },
459    /// An exported type from a component or instance, currently only
460    /// informational.
461    Type(TypeDef),
462}
463
464/// Canonical ABI options associated with a lifted or lowered function.
465#[derive(Debug, Clone, Serialize, Deserialize)]
466pub struct CanonicalOptions {
467    /// The component instance that this bundle was associated with.
468    pub instance: RuntimeComponentInstanceIndex,
469
470    /// The encoding used for strings.
471    pub string_encoding: StringEncoding,
472
473    /// The memory used by these options, if specified.
474    pub memory: Option<RuntimeMemoryIndex>,
475
476    /// The realloc function used by these options, if specified.
477    pub realloc: Option<RuntimeReallocIndex>,
478
479    /// The async callback function used by these options, if specified.
480    pub callback: Option<RuntimeCallbackIndex>,
481
482    /// The post-return function used by these options, if specified.
483    pub post_return: Option<RuntimePostReturnIndex>,
484
485    /// Whether to use the async ABI for lifting or lowering.
486    pub async_: bool,
487}
488
489/// Possible encodings of strings within the component model.
490#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]
491#[allow(missing_docs, reason = "self-describing variants")]
492pub enum StringEncoding {
493    Utf8,
494    Utf16,
495    CompactUtf16,
496}
497
498impl StringEncoding {
499    /// Decodes the `u8` provided back into a `StringEncoding`, if it's valid.
500    pub fn from_u8(val: u8) -> Option<StringEncoding> {
501        if val == StringEncoding::Utf8 as u8 {
502            return Some(StringEncoding::Utf8);
503        }
504        if val == StringEncoding::Utf16 as u8 {
505            return Some(StringEncoding::Utf16);
506        }
507        if val == StringEncoding::CompactUtf16 as u8 {
508            return Some(StringEncoding::CompactUtf16);
509        }
510        None
511    }
512}
513
514/// Possible transcoding operations that must be provided by the host.
515///
516/// Note that each transcoding operation may have a unique signature depending
517/// on the precise operation.
518#[allow(missing_docs, reason = "self-describing variants")]
519#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
520pub enum Transcode {
521    Copy(FixedEncoding),
522    Latin1ToUtf16,
523    Latin1ToUtf8,
524    Utf16ToCompactProbablyUtf16,
525    Utf16ToCompactUtf16,
526    Utf16ToLatin1,
527    Utf16ToUtf8,
528    Utf8ToCompactUtf16,
529    Utf8ToLatin1,
530    Utf8ToUtf16,
531}
532
533impl Transcode {
534    /// Get this transcoding's symbol fragment.
535    pub fn symbol_fragment(&self) -> &'static str {
536        match self {
537            Transcode::Copy(x) => match x {
538                FixedEncoding::Utf8 => "copy_utf8",
539                FixedEncoding::Utf16 => "copy_utf16",
540                FixedEncoding::Latin1 => "copy_latin1",
541            },
542            Transcode::Latin1ToUtf16 => "latin1_to_utf16",
543            Transcode::Latin1ToUtf8 => "latin1_to_utf8",
544            Transcode::Utf16ToCompactProbablyUtf16 => "utf16_to_compact_probably_utf16",
545            Transcode::Utf16ToCompactUtf16 => "utf16_to_compact_utf16",
546            Transcode::Utf16ToLatin1 => "utf16_to_latin1",
547            Transcode::Utf16ToUtf8 => "utf16_to_utf8",
548            Transcode::Utf8ToCompactUtf16 => "utf8_to_compact_utf16",
549            Transcode::Utf8ToLatin1 => "utf8_to_latin1",
550            Transcode::Utf8ToUtf16 => "utf8_to_utf16",
551        }
552    }
553
554    /// Returns a human-readable description for this transcoding operation.
555    pub fn desc(&self) -> &'static str {
556        match self {
557            Transcode::Copy(FixedEncoding::Utf8) => "utf8-to-utf8",
558            Transcode::Copy(FixedEncoding::Utf16) => "utf16-to-utf16",
559            Transcode::Copy(FixedEncoding::Latin1) => "latin1-to-latin1",
560            Transcode::Latin1ToUtf16 => "latin1-to-utf16",
561            Transcode::Latin1ToUtf8 => "latin1-to-utf8",
562            Transcode::Utf16ToCompactProbablyUtf16 => "utf16-to-compact-probably-utf16",
563            Transcode::Utf16ToCompactUtf16 => "utf16-to-compact-utf16",
564            Transcode::Utf16ToLatin1 => "utf16-to-latin1",
565            Transcode::Utf16ToUtf8 => "utf16-to-utf8",
566            Transcode::Utf8ToCompactUtf16 => "utf8-to-compact-utf16",
567            Transcode::Utf8ToLatin1 => "utf8-to-latin1",
568            Transcode::Utf8ToUtf16 => "utf8-to-utf16",
569        }
570    }
571}
572
573#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
574#[allow(missing_docs, reason = "self-describing variants")]
575pub enum FixedEncoding {
576    Utf8,
577    Utf16,
578    Latin1,
579}
580
581impl FixedEncoding {
582    /// Returns the byte width of unit loads/stores for this encoding, for
583    /// example the unit length is multiplied by this return value to get the
584    /// byte width of a string.
585    pub fn width(&self) -> u8 {
586        match self {
587            FixedEncoding::Utf8 => 1,
588            FixedEncoding::Utf16 => 2,
589            FixedEncoding::Latin1 => 1,
590        }
591    }
592}
593
594/// Description of a new resource declared in a `GlobalInitializer::Resource`
595/// variant.
596///
597/// This will have the effect of initializing runtime state for this resource,
598/// namely the destructor is fetched and stored.
599#[derive(Debug, Serialize, Deserialize)]
600pub struct Resource {
601    /// The local index of the resource being defined.
602    pub index: DefinedResourceIndex,
603    /// Core wasm representation of this resource.
604    pub rep: WasmValType,
605    /// Optionally-specified destructor and where it comes from.
606    pub dtor: Option<CoreDef>,
607    /// Which component instance this resource logically belongs to.
608    pub instance: RuntimeComponentInstanceIndex,
609}
610
611/// A list of all possible trampolines that may be required to compile a
612/// component completely.
613///
614/// These trampolines are used often as core wasm definitions and require
615/// Cranelift support to generate these functions. Each trampoline serves a
616/// different purpose for implementing bits and pieces of the component model.
617///
618/// All trampolines have a core wasm function signature associated with them
619/// which is stored in the `Component::trampolines` array.
620///
621/// Note that this type does not implement `Serialize` or `Deserialize` and
622/// that's intentional as this isn't stored in the final compilation artifact.
623pub enum Trampoline {
624    /// Description of a lowered import used in conjunction with
625    /// `GlobalInitializer::LowerImport`.
626    LowerImport {
627        /// The runtime lowering state that this trampoline will access.
628        index: LoweredIndex,
629
630        /// The type of the function that is being lowered, as perceived by the
631        /// component doing the lowering.
632        lower_ty: TypeFuncIndex,
633
634        /// The canonical ABI options used when lowering this function specified
635        /// in the original component.
636        options: CanonicalOptions,
637    },
638
639    /// Information about a string transcoding function required by an adapter
640    /// module.
641    ///
642    /// A transcoder is used when strings are passed between adapter modules,
643    /// optionally changing string encodings at the same time. The transcoder is
644    /// implemented in a few different layers:
645    ///
646    /// * Each generated adapter module has some glue around invoking the
647    ///   transcoder represented by this item. This involves bounds-checks and
648    ///   handling `realloc` for example.
649    /// * Each transcoder gets a cranelift-generated trampoline which has the
650    ///   appropriate signature for the adapter module in question. Existence of
651    ///   this initializer indicates that this should be compiled by Cranelift.
652    /// * The cranelift-generated trampoline will invoke a "transcoder libcall"
653    ///   which is implemented natively in Rust that has a signature independent
654    ///   of memory64 configuration options for example.
655    Transcoder {
656        /// The transcoding operation being performed.
657        op: Transcode,
658        /// The linear memory that the string is being read from.
659        from: RuntimeMemoryIndex,
660        /// Whether or not the source linear memory is 64-bit or not.
661        from64: bool,
662        /// The linear memory that the string is being written to.
663        to: RuntimeMemoryIndex,
664        /// Whether or not the destination linear memory is 64-bit or not.
665        to64: bool,
666    },
667
668    /// A small adapter which simply traps, used for degenerate lift/lower
669    /// combinations.
670    AlwaysTrap,
671
672    /// A `resource.new` intrinsic which will inject a new resource into the
673    /// table specified.
674    ResourceNew(TypeResourceTableIndex),
675
676    /// Same as `ResourceNew`, but for the `resource.rep` intrinsic.
677    ResourceRep(TypeResourceTableIndex),
678
679    /// Same as `ResourceNew`, but for the `resource.drop` intrinsic.
680    ResourceDrop(TypeResourceTableIndex),
681
682    /// A `task.backpressure` intrinsic, which tells the host to enable or
683    /// disable backpressure for the caller's instance.
684    TaskBackpressure {
685        /// The specific component instance which is calling the intrinsic.
686        instance: RuntimeComponentInstanceIndex,
687    },
688
689    /// A `task.return` intrinsic, which returns a result to the caller of a
690    /// lifted export function.  This allows the callee to continue executing
691    /// after returning a result.
692    TaskReturn,
693
694    /// A `task.wait` intrinsic, which waits for at least one outstanding async
695    /// task/stream/future to make progress, returning the first such event.
696    TaskWait {
697        /// The specific component instance which is calling the intrinsic.
698        instance: RuntimeComponentInstanceIndex,
699        /// If `true`, indicates the caller instance maybe reentered.
700        async_: bool,
701        /// Memory to use when storing the event.
702        memory: RuntimeMemoryIndex,
703    },
704
705    /// A `task.poll` intrinsic, which checks whether any outstanding async
706    /// task/stream/future has made progress.  Unlike `task.wait`, this does not
707    /// block and may return nothing if no such event has occurred.
708    TaskPoll {
709        /// The specific component instance which is calling the intrinsic.
710        instance: RuntimeComponentInstanceIndex,
711        /// If `true`, indicates the caller instance maybe reentered.
712        async_: bool,
713        /// Memory to use when storing the event.
714        memory: RuntimeMemoryIndex,
715    },
716
717    /// A `task.yield` intrinsic, which yields control to the host so that other
718    /// tasks are able to make progress, if any.
719    TaskYield {
720        /// If `true`, indicates the caller instance maybe reentered.
721        async_: bool,
722    },
723
724    /// A `subtask.drop` intrinsic to drop a specified task which has completed.
725    SubtaskDrop {
726        /// The specific component instance which is calling the intrinsic.
727        instance: RuntimeComponentInstanceIndex,
728    },
729
730    /// A `stream.new` intrinsic to create a new `stream` handle of the
731    /// specified type.
732    StreamNew {
733        /// The table index for the specific `stream` type and caller instance.
734        ty: TypeStreamTableIndex,
735    },
736
737    /// A `stream.read` intrinsic to read from a `stream` of the specified type.
738    StreamRead {
739        /// The table index for the specific `stream` type and caller instance.
740        ty: TypeStreamTableIndex,
741        /// Any options (e.g. string encoding) to use when storing values to
742        /// memory.
743        options: CanonicalOptions,
744    },
745
746    /// A `stream.write` intrinsic to write to a `stream` of the specified type.
747    StreamWrite {
748        /// The table index for the specific `stream` type and caller instance.
749        ty: TypeStreamTableIndex,
750        /// Any options (e.g. string encoding) to use when storing values to
751        /// memory.
752        options: CanonicalOptions,
753    },
754
755    /// A `stream.cancel-read` intrinsic to cancel an in-progress read from a
756    /// `stream` of the specified type.
757    StreamCancelRead {
758        /// The table index for the specific `stream` type and caller instance.
759        ty: TypeStreamTableIndex,
760        /// If `false`, block until cancellation completes rather than return
761        /// `BLOCKED`.
762        async_: bool,
763    },
764
765    /// A `stream.cancel-write` intrinsic to cancel an in-progress write from a
766    /// `stream` of the specified type.
767    StreamCancelWrite {
768        /// The table index for the specific `stream` type and caller instance.
769        ty: TypeStreamTableIndex,
770        /// If `false`, block until cancellation completes rather than return
771        /// `BLOCKED`.
772        async_: bool,
773    },
774
775    /// A `stream.close-readable` intrinsic to close the readable end of a
776    /// `stream` of the specified type.
777    StreamCloseReadable {
778        /// The table index for the specific `stream` type and caller instance.
779        ty: TypeStreamTableIndex,
780    },
781
782    /// A `stream.close-writable` intrinsic to close the writable end of a
783    /// `stream` of the specified type.
784    StreamCloseWritable {
785        /// The table index for the specific `stream` type and caller instance.
786        ty: TypeStreamTableIndex,
787    },
788
789    /// A `future.new` intrinsic to create a new `future` handle of the
790    /// specified type.
791    FutureNew {
792        /// The table index for the specific `future` type and caller instance.
793        ty: TypeFutureTableIndex,
794    },
795
796    /// A `future.read` intrinsic to read from a `future` of the specified type.
797    FutureRead {
798        /// The table index for the specific `future` type and caller instance.
799        ty: TypeFutureTableIndex,
800        /// Any options (e.g. string encoding) to use when storing values to
801        /// memory.
802        options: CanonicalOptions,
803    },
804
805    /// A `future.write` intrinsic to write to a `future` of the specified type.
806    FutureWrite {
807        /// The table index for the specific `future` type and caller instance.
808        ty: TypeFutureTableIndex,
809        /// Any options (e.g. string encoding) to use when storing values to
810        /// memory.
811        options: CanonicalOptions,
812    },
813
814    /// A `future.cancel-read` intrinsic to cancel an in-progress read from a
815    /// `future` of the specified type.
816    FutureCancelRead {
817        /// The table index for the specific `future` type and caller instance.
818        ty: TypeFutureTableIndex,
819        /// If `false`, block until cancellation completes rather than return
820        /// `BLOCKED`.
821        async_: bool,
822    },
823
824    /// A `future.cancel-write` intrinsic to cancel an in-progress write from a
825    /// `future` of the specified type.
826    FutureCancelWrite {
827        /// The table index for the specific `future` type and caller instance.
828        ty: TypeFutureTableIndex,
829        /// If `false`, block until cancellation completes rather than return
830        /// `BLOCKED`.
831        async_: bool,
832    },
833
834    /// A `future.close-readable` intrinsic to close the readable end of a
835    /// `future` of the specified type.
836    FutureCloseReadable {
837        /// The table index for the specific `future` type and caller instance.
838        ty: TypeFutureTableIndex,
839    },
840
841    /// A `future.close-writable` intrinsic to close the writable end of a
842    /// `future` of the specified type.
843    FutureCloseWritable {
844        /// The table index for the specific `future` type and caller instance.
845        ty: TypeFutureTableIndex,
846    },
847
848    /// A `error-context.new` intrinsic to create a new `error-context` with a
849    /// specified debug message.
850    ErrorContextNew {
851        /// The table index for the `error-context` type in the caller instance.
852        ty: TypeComponentLocalErrorContextTableIndex,
853        /// String encoding, memory, etc. to use when loading debug message.
854        options: CanonicalOptions,
855    },
856
857    /// A `error-context.debug-message` intrinsic to get the debug message for a
858    /// specified `error-context`.
859    ///
860    /// Note that the debug message might not necessarily match what was passed
861    /// to `error.new`.
862    ErrorContextDebugMessage {
863        /// The table index for the `error-context` type in the caller instance.
864        ty: TypeComponentLocalErrorContextTableIndex,
865        /// String encoding, memory, etc. to use when storing debug message.
866        options: CanonicalOptions,
867    },
868
869    /// A `error-context.drop` intrinsic to drop a specified `error-context`.
870    ErrorContextDrop {
871        /// The table index for the `error-context` type in the caller instance.
872        ty: TypeComponentLocalErrorContextTableIndex,
873    },
874
875    /// An intrinsic used by FACT-generated modules which will transfer an owned
876    /// resource from one table to another. Used in component-to-component
877    /// adapter trampolines.
878    ResourceTransferOwn,
879
880    /// Same as `ResourceTransferOwn` but for borrows.
881    ResourceTransferBorrow,
882
883    /// An intrinsic used by FACT-generated modules which indicates that a call
884    /// is being entered and resource-related metadata needs to be configured.
885    ///
886    /// Note that this is currently only invoked when borrowed resources are
887    /// detected, otherwise this is "optimized out".
888    ResourceEnterCall,
889
890    /// Same as `ResourceEnterCall` except for when exiting a call.
891    ResourceExitCall,
892
893    /// An intrinsic used by FACT-generated modules to begin a call to an
894    /// async-lowered import function.
895    AsyncEnterCall,
896
897    /// An intrinsic used by FACT-generated modules to complete a call to an
898    /// async-lowered import function.
899    ///
900    /// Note that `AsyncEnterCall` and `AsyncExitCall` could theoretically be
901    /// combined into a single `AsyncCall` intrinsic, but we separate them to
902    /// allow the FACT-generated module to optionally call the callee directly
903    /// without an intermediate host stack frame.
904    AsyncExitCall {
905        /// The callee's callback, if any.
906        callback: Option<RuntimeCallbackIndex>,
907
908        /// The callee's post-return function, if any.
909        post_return: Option<RuntimePostReturnIndex>,
910    },
911
912    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
913    /// ownership of a `future`.
914    ///
915    /// Transfering a `future` can either mean giving away the readable end
916    /// while retaining the writable end or only the former, depending on the
917    /// ownership status of the `future`.
918    FutureTransfer,
919
920    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
921    /// ownership of a `stream`.
922    ///
923    /// Transfering a `stream` can either mean giving away the readable end
924    /// while retaining the writable end or only the former, depending on the
925    /// ownership status of the `stream`.
926    StreamTransfer,
927
928    /// An intrinisic used by FACT-generated modules to (partially or entirely) transfer
929    /// ownership of an `error-context`.
930    ///
931    /// Unlike futures, streams, and resource handles, `error-context` handles
932    /// are reference counted, meaning that sharing the handle with another
933    /// component does not invalidate the handle in the original component.
934    ErrorContextTransfer,
935}
936
937impl Trampoline {
938    /// Returns the name to use for the symbol of this trampoline in the final
939    /// compiled artifact
940    pub fn symbol_name(&self) -> String {
941        use Trampoline::*;
942        match self {
943            LowerImport { index, .. } => {
944                format!("component-lower-import[{}]", index.as_u32())
945            }
946            Transcoder {
947                op, from64, to64, ..
948            } => {
949                let op = op.symbol_fragment();
950                let from = if *from64 { "64" } else { "32" };
951                let to = if *to64 { "64" } else { "32" };
952                format!("component-transcode-{op}-m{from}-m{to}")
953            }
954            AlwaysTrap => format!("component-always-trap"),
955            ResourceNew(i) => format!("component-resource-new[{}]", i.as_u32()),
956            ResourceRep(i) => format!("component-resource-rep[{}]", i.as_u32()),
957            ResourceDrop(i) => format!("component-resource-drop[{}]", i.as_u32()),
958            TaskBackpressure { .. } => format!("task-backpressure"),
959            TaskReturn => format!("task-return"),
960            TaskWait { .. } => format!("task-wait"),
961            TaskPoll { .. } => format!("task-poll"),
962            TaskYield { .. } => format!("task-yield"),
963            SubtaskDrop { .. } => format!("subtask-drop"),
964            StreamNew { .. } => format!("stream-new"),
965            StreamRead { .. } => format!("stream-read"),
966            StreamWrite { .. } => format!("stream-write"),
967            StreamCancelRead { .. } => format!("stream-cancel-read"),
968            StreamCancelWrite { .. } => format!("stream-cancel-write"),
969            StreamCloseReadable { .. } => format!("stream-close-readable"),
970            StreamCloseWritable { .. } => format!("stream-close-writable"),
971            FutureNew { .. } => format!("future-new"),
972            FutureRead { .. } => format!("future-read"),
973            FutureWrite { .. } => format!("future-write"),
974            FutureCancelRead { .. } => format!("future-cancel-read"),
975            FutureCancelWrite { .. } => format!("future-cancel-write"),
976            FutureCloseReadable { .. } => format!("future-close-readable"),
977            FutureCloseWritable { .. } => format!("future-close-writable"),
978            ErrorContextNew { .. } => format!("error-context-new"),
979            ErrorContextDebugMessage { .. } => format!("error-context-debug-message"),
980            ErrorContextDrop { .. } => format!("error-context-drop"),
981            ResourceTransferOwn => format!("component-resource-transfer-own"),
982            ResourceTransferBorrow => format!("component-resource-transfer-borrow"),
983            ResourceEnterCall => format!("component-resource-enter-call"),
984            ResourceExitCall => format!("component-resource-exit-call"),
985            AsyncEnterCall => format!("component-async-enter-call"),
986            AsyncExitCall { .. } => format!("component-async-exit-call"),
987            FutureTransfer => format!("future-transfer"),
988            StreamTransfer => format!("stream-transfer"),
989            ErrorContextTransfer => format!("error-context-transfer"),
990        }
991    }
992}