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