Skip to main content

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