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