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