Path: blob/main/crates/environ/src/component/info.rs
3050 views
// General runtime type-information about a component.1//2// Compared to the `Module` structure for core wasm this type is pretty3// significantly different. The core wasm `Module` corresponds roughly 1-to-14// with the structure of the wasm module itself, but instead a `Component` is5// more of a "compiled" representation where the original structure is thrown6// away in favor of a more optimized representation. The considerations for this7// are:8//9// * This representation of a `Component` avoids the need to create a10// `PrimaryMap` of some form for each of the index spaces within a component.11// This is less so an issue about allocations and more so that this information12// generally just isn't needed any time after instantiation. Avoiding creating13// these altogether helps components be lighter weight at runtime and14// additionally accelerates instantiation.15//16// * Components can have arbitrary nesting and internally do instantiations via17// string-based matching. At instantiation-time, though, we want to do as few18// string-lookups in hash maps as much as we can since they're significantly19// slower than index-based lookups. Furthermore while the imports of a20// component are not statically known the rest of the structure of the21// component is statically known which enables the ability to track precisely22// what matches up where and do all the string lookups at compile time instead23// of instantiation time.24//25// * Finally by performing this sort of dataflow analysis we are capable of26// identifying what adapters need trampolines for compilation or fusion. For27// example this tracks when host functions are lowered which enables us to28// enumerate what trampolines are required to enter into a component.29// Additionally (eventually) this will track all of the "fused" adapter30// functions where a function from one component instance is lifted and then31// lowered into another component instance. Altogether this enables Wasmtime's32// AOT-compilation where the artifact from compilation is suitable for use in33// running the component without the support of a compiler at runtime.34//35// Note, however, that the current design of `Component` has fundamental36// limitations which it was not designed for. For example there is no feasible37// way to implement either importing or exporting a component itself from the38// root component. Currently we rely on the ability to have static knowledge of39// what's coming from the host which at this point can only be either functions40// or core wasm modules. Additionally one flat list of initializers for a41// component are produced instead of initializers-per-component which would42// otherwise be required to export a component from a component.43//44// For now this tradeoff is made as it aligns well with the intended use case45// for components in an embedding. This may need to be revisited though if the46// requirements of embeddings change over time.4748use crate::component::*;49use crate::prelude::*;50use crate::{EntityIndex, ModuleInternedTypeIndex, PrimaryMap, WasmValType};51use cranelift_entity::packed_option::PackedOption;52use serde_derive::{Deserialize, Serialize};5354/// Metadata as a result of compiling a component.55pub struct ComponentTranslation {56/// Serializable information that will be emitted into the final artifact.57pub component: Component,5859/// Metadata about required trampolines and what they're supposed to do.60pub trampolines: PrimaryMap<TrampolineIndex, Trampoline>,61}6263/// Run-time-type-information about a `Component`, its structure, and how to64/// instantiate it.65///66/// This type is intended to mirror the `Module` type in this crate which67/// provides all the runtime information about the structure of a module and68/// how it works.69///70/// NB: Lots of the component model is not yet implemented in the runtime so71/// 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 to77/// refer back to.78pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,7980/// A list of "flattened" imports that are used by this instance.81///82/// This import map represents extracting imports, as necessary, from the83/// general imported types by this component. The flattening here refers to84/// extracting items from instances. Currently the flat imports are either a85/// host function or a core wasm module.86///87/// For example if `ImportIndex(0)` pointed to an instance then this import88/// map represent extracting names from that map, for example extracting an89/// exported module or an exported function.90///91/// Each import item is keyed by a `RuntimeImportIndex` which is referred to92/// by types below whenever something refers to an import. The value for93/// each `RuntimeImportIndex` in this map is the `ImportIndex` for where94/// this items comes from (which can be associated with a name above in the95/// `import_types` array) as well as the list of export names if96/// `ImportIndex` refers to an instance. The export names array represents97/// recursively fetching names within an instance.98//99// TODO: this is probably a lot of `String` storage and may be something100// that needs optimization in the future. For example instead of lots of101// different `String` allocations this could instead be a pointer/length102// into one large string allocation for the entire component. Alternatively103// strings could otherwise be globally intern'd via some other mechanism to104// avoid `Linker`-specific intern-ing plus intern-ing here. Unsure what the105// best route is or whether such an optimization is even necessary here.106pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,107108/// This component's own root exports from the component itself.109pub exports: NameMap<String, ExportIndex>,110111/// 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.115pub export_items: PrimaryMap<ExportIndex, Export>,116117/// Initializers that must be processed when instantiating this component.118///119/// This list of initializers does not correspond directly to the component120/// itself. The general goal with this is that the recursive nature of121/// components is "flattened" with an array like this which is a linear122/// sequence of instructions of how to instantiate a component. This will123/// have instantiations, for example, in addition to entries which124/// initialize `VMComponentContext` fields with previously instantiated125/// instances.126pub initializers: Vec<GlobalInitializer>,127128/// The number of runtime instances (maximum `RuntimeInstanceIndex`) created129/// when instantiating this component.130pub num_runtime_instances: u32,131132/// Same as `num_runtime_instances`, but for `RuntimeComponentInstanceIndex`133/// instead.134pub num_runtime_component_instances: u32,135136/// The number of runtime memories (maximum `RuntimeMemoryIndex`) needed to137/// 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't141/// stored in two different locations).142pub num_runtime_memories: u32,143144/// The number of runtime tables (maximum `RuntimeTableIndex`) needed to145/// instantiate this component. See notes on `num_runtime_memories`.146pub num_runtime_tables: u32,147148/// The number of runtime reallocs (maximum `RuntimeReallocIndex`) needed to149/// instantiate this component.150///151/// Note that this many function pointers will be stored in the152/// `VMComponentContext`.153pub num_runtime_reallocs: u32,154155/// The number of runtime async callbacks (maximum `RuntimeCallbackIndex`)156/// needed to instantiate this component.157pub num_runtime_callbacks: u32,158159/// Same as `num_runtime_reallocs`, but for post-return functions.160pub num_runtime_post_returns: u32,161162/// WebAssembly type signature of all trampolines.163pub trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,164165/// A map from a `UnsafeIntrinsic::index()` to that intrinsic's166/// module-interned type.167pub unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],168169/// The number of lowered host functions (maximum `LoweredIndex`) needed to170/// instantiate this component.171pub num_lowerings: u32,172173/// Total number of resources both imported and defined within this174/// component.175pub num_resources: u32,176177/// Maximal number of tables required at runtime for future-related178/// information in this component.179pub num_future_tables: usize,180181/// Maximal number of tables required at runtime for stream-related182/// information in this component.183pub num_stream_tables: usize,184185/// Maximal number of tables required at runtime for error-context-related186/// information in this component.187pub num_error_context_tables: usize,188189/// Metadata about imported resources and where they are within the runtime190/// imports array.191///192/// This map is only as large as the number of imported resources.193pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,194195/// Metadata about which component instances defined each resource within196/// this component.197///198/// This is used to determine which set of instance flags are inspected when199/// testing reentrance.200pub defined_resource_instances: PrimaryMap<DefinedResourceIndex, RuntimeComponentInstanceIndex>,201202/// All canonical options used by this component. Stored as a table here203/// from index-to-options so the options can be consulted at runtime.204pub options: PrimaryMap<OptionsIndex, CanonicalOptions>,205}206207impl Component {208/// Attempts to convert a resource index into a defined index.209///210/// Returns `None` if `idx` is for an imported resource in this component or211/// `Some` if it's a locally defined resource.212pub fn defined_resource_index(&self, idx: ResourceIndex) -> Option<DefinedResourceIndex> {213let idx = idx214.as_u32()215.checked_sub(self.imported_resources.len() as u32)?;216Some(DefinedResourceIndex::from_u32(idx))217}218219/// Converts a defined resource index to a component-local resource index220/// which includes all imports.221pub fn resource_index(&self, idx: DefinedResourceIndex) -> ResourceIndex {222ResourceIndex::from_u32(self.imported_resources.len() as u32 + idx.as_u32())223}224}225226/// GlobalInitializer instructions to get processed when instantiating a227/// component.228///229/// The variants of this enum are processed during the instantiation phase of a230/// component in-order from front-to-back. These are otherwise emitted as a231/// component is parsed and read and translated.232//233// FIXME(#2639) if processing this list is ever a bottleneck we could234// theoretically use cranelift to compile an initialization function which235// performs all of these duties for us and skips the overhead of interpreting236// all of these instructions.237#[derive(Debug, Serialize, Deserialize)]238pub enum GlobalInitializer {239/// A core wasm module is being instantiated.240///241/// This will result in a new core wasm instance being created, which may242/// involve running the `start` function of the instance as well if it's243/// specified. This largely delegates to the same standard instantiation244/// process as the rest of the core wasm machinery already uses.245///246/// The second field represents the component instance to which the module247/// belongs, if applicable. This will be `None` for adapter modules.248InstantiateModule(InstantiateModule, Option<RuntimeComponentInstanceIndex>),249250/// A host function is being lowered, creating a core wasm function.251///252/// This initializer entry is intended to be used to fill out the253/// `VMComponentContext` and information about this lowering such as the254/// cranelift-compiled trampoline function pointer, the host function255/// pointer the trampoline calls, and the canonical ABI options.256LowerImport {257/// The index of the lowered function that's being created.258///259/// This is guaranteed to be the `n`th `LowerImport` instruction260/// if the index is `n`.261index: LoweredIndex,262263/// The index of the imported host function that is being lowered.264///265/// It's guaranteed that this `RuntimeImportIndex` points to a function.266import: RuntimeImportIndex,267},268269/// A core wasm linear memory is going to be saved into the270/// `VMComponentContext`.271///272/// This instruction indicates that a core wasm linear memory needs to be273/// extracted from the `export` and stored into the `VMComponentContext` at274/// the `index` specified. This lowering is then used in the future by275/// pointers from `CanonicalOptions`.276ExtractMemory(ExtractMemory),277278/// Same as `ExtractMemory`, except it's extracting a function pointer to be279/// used as a `realloc` function.280ExtractRealloc(ExtractRealloc),281282/// Same as `ExtractMemory`, except it's extracting a function pointer to be283/// used as an async `callback` function.284ExtractCallback(ExtractCallback),285286/// Same as `ExtractMemory`, except it's extracting a function pointer to be287/// used as a `post-return` function.288ExtractPostReturn(ExtractPostReturn),289290/// A core wasm table is going to be saved into the `VMComponentContext`.291///292/// This instruction indicates that s core wasm table needs to be extracted293/// from its `export` and stored into the `VMComponentContext` at the294/// `index` specified. During this extraction, we will also capture the295/// table's containing instance pointer to access the table at runtime. This296/// extraction is useful for `thread.spawn-indirect`.297ExtractTable(ExtractTable),298299/// Declares a new defined resource within this component.300///301/// Contains information about the destructor, for example.302Resource(Resource),303}304305/// Metadata for extraction of a memory; contains what's being extracted (the306/// memory at `export`) and where it's going (the `index` within a307/// `VMComponentContext`).308#[derive(Debug, Serialize, Deserialize)]309pub struct ExtractMemory {310/// The index of the memory being defined.311pub index: RuntimeMemoryIndex,312/// Where this memory is being extracted from.313pub export: CoreExport<MemoryIndex>,314}315316/// Same as `ExtractMemory` but for the `realloc` canonical option.317#[derive(Debug, Serialize, Deserialize)]318pub struct ExtractRealloc {319/// The index of the realloc being defined.320pub index: RuntimeReallocIndex,321/// Where this realloc is being extracted from.322pub def: CoreDef,323}324325/// Same as `ExtractMemory` but for the `callback` canonical option.326#[derive(Debug, Serialize, Deserialize)]327pub struct ExtractCallback {328/// The index of the callback being defined.329pub index: RuntimeCallbackIndex,330/// Where this callback is being extracted from.331pub def: CoreDef,332}333334/// Same as `ExtractMemory` but for the `post-return` canonical option.335#[derive(Debug, Serialize, Deserialize)]336pub struct ExtractPostReturn {337/// The index of the post-return being defined.338pub index: RuntimePostReturnIndex,339/// Where this post-return is being extracted from.340pub def: CoreDef,341}342343/// Metadata for extraction of a table.344#[derive(Debug, Serialize, Deserialize)]345pub struct ExtractTable {346/// The index of the table being defined in a `VMComponentContext`.347pub index: RuntimeTableIndex,348/// Where this table is being extracted from.349pub export: CoreExport<TableIndex>,350}351352/// Different methods of instantiating a core wasm module.353#[derive(Debug, Serialize, Deserialize)]354pub enum InstantiateModule {355/// A module defined within this component is being instantiated.356///357/// Note that this is distinct from the case of imported modules because the358/// order of imports required is statically known and can be pre-calculated359/// to avoid string lookups related to names at runtime, represented by the360/// flat list of arguments here.361Static(StaticModuleIndex, Box<[CoreDef]>),362363/// An imported module is being instantiated.364///365/// This is similar to `Upvar` but notably the imports are provided as a366/// two-level named map since import resolution order needs to happen at367/// runtime.368Import(369RuntimeImportIndex,370IndexMap<String, IndexMap<String, CoreDef>>,371),372}373374/// Definition of a core wasm item and where it can come from within a375/// component.376///377/// Note that this is sort of a result of data-flow-like analysis on a component378/// during compile time of the component itself. References to core wasm items379/// are "compiled" to either referring to a previous instance or to some sort of380/// lowered host import.381#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]382pub enum CoreDef {383/// This item refers to an export of a previously instantiated core wasm384/// instance.385Export(CoreExport<EntityIndex>),386/// This is a reference to a wasm global which represents the387/// runtime-managed flags for a wasm instance.388InstanceFlags(RuntimeComponentInstanceIndex),389/// This is a reference to a Cranelift-generated trampoline which is390/// described in the `trampolines` array.391Trampoline(TrampolineIndex),392/// An intrinsic for compile-time builtins.393UnsafeIntrinsic(UnsafeIntrinsic),394/// Reference to a wasm global which represents a runtime-managed boolean395/// indicating whether the currently-running task may perform a blocking396/// operation.397TaskMayBlock,398}399400impl<T> From<CoreExport<T>> for CoreDef401where402EntityIndex: From<T>,403{404fn from(export: CoreExport<T>) -> CoreDef {405CoreDef::Export(export.map_index(|i| i.into()))406}407}408409/// Identifier of an exported item from a core WebAssembly module instance.410///411/// Note that the `T` here is the index type for exports which can be412/// identified by index. The `T` is monomorphized with types like413/// [`EntityIndex`] or [`FuncIndex`].414#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]415pub struct CoreExport<T> {416/// The instance that this item is located within.417///418/// Note that this is intended to index the `instances` map within a419/// component. It's validated ahead of time that all instance pointers420/// refer only to previously-created instances.421pub instance: RuntimeInstanceIndex,422423/// The item that this export is referencing, either by name or by index.424pub item: ExportItem<T>,425}426427impl<T> CoreExport<T> {428/// Maps the index type `T` to another type `U` if this export item indeed429/// refers to an index `T`.430pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {431CoreExport {432instance: self.instance,433item: match self.item {434ExportItem::Index(i) => ExportItem::Index(f(i)),435ExportItem::Name(s) => ExportItem::Name(s),436},437}438}439}440441/// An index at which to find an item within a runtime instance.442#[derive(Debug, Clone, Serialize, Deserialize, Hash, Eq, PartialEq)]443pub enum ExportItem<T> {444/// An exact index that the target can be found at.445///446/// This is used where possible to avoid name lookups at runtime during the447/// instantiation process. This can only be used on instances where the448/// module was statically known at compile time, however.449Index(T),450451/// An item which is identified by a name, so at runtime we need to452/// perform a name lookup to determine the index that the item is located453/// at.454///455/// This is used for instantiations of imported modules, for example, since456/// the precise shape of the module is not known.457Name(String),458}459460/// Possible exports from a component.461#[derive(Debug, Clone, Serialize, Deserialize)]462pub enum Export {463/// A lifted function being exported which is an adaptation of a core wasm464/// function.465LiftedFunction {466/// The component function type of the function being created.467ty: TypeFuncIndex,468/// Which core WebAssembly export is being lifted.469func: CoreDef,470/// Any options, if present, associated with this lifting.471options: OptionsIndex,472},473/// A module defined within this component is exported.474ModuleStatic {475/// The type of this module476ty: TypeModuleIndex,477/// Which module this is referring to.478index: StaticModuleIndex,479},480/// A module imported into this component is exported.481ModuleImport {482/// Module type index483ty: TypeModuleIndex,484/// Module runtime import index485import: RuntimeImportIndex,486},487/// A nested instance is being exported which has recursively defined488/// `Export` items.489Instance {490/// Instance type index, if such is assigned491ty: TypeComponentInstanceIndex,492/// Instance export map493exports: NameMap<String, ExportIndex>,494},495/// An exported type from a component or instance, currently only496/// informational.497Type(TypeDef),498}499500#[derive(Debug, Clone, Copy, Serialize, Deserialize)]501/// Data is stored in a linear memory.502pub struct LinearMemoryOptions {503/// The memory used by these options, if specified.504pub memory: Option<RuntimeMemoryIndex>,505/// The realloc function used by these options, if specified.506pub realloc: Option<RuntimeReallocIndex>,507}508509/// The data model for objects that are not unboxed in locals.510#[derive(Debug, Clone, Copy, Serialize, Deserialize)]511pub enum CanonicalOptionsDataModel {512/// Data is stored in GC objects.513Gc {},514515/// Data is stored in a linear memory.516LinearMemory(LinearMemoryOptions),517}518519/// Canonical ABI options associated with a lifted or lowered function.520#[derive(Debug, Clone, Serialize, Deserialize)]521pub struct CanonicalOptions {522/// The component instance that this bundle was associated with.523pub instance: RuntimeComponentInstanceIndex,524525/// The encoding used for strings.526pub string_encoding: StringEncoding,527528/// The async callback function used by these options, if specified.529pub callback: Option<RuntimeCallbackIndex>,530531/// The post-return function used by these options, if specified.532pub post_return: Option<RuntimePostReturnIndex>,533534/// Whether to use the async ABI for lifting or lowering.535pub async_: bool,536537/// Whether or not this function can consume a task cancellation538/// notification.539pub cancellable: bool,540541/// The core function type that is being lifted from / lowered to.542pub core_type: ModuleInternedTypeIndex,543544/// The data model (GC objects or linear memory) used with these canonical545/// options.546pub data_model: CanonicalOptionsDataModel,547}548549impl CanonicalOptions {550/// Returns the memory referred to by these options, if any.551pub fn memory(&self) -> Option<RuntimeMemoryIndex> {552match self.data_model {553CanonicalOptionsDataModel::Gc {} => None,554CanonicalOptionsDataModel::LinearMemory(opts) => opts.memory,555}556}557}558559/// Possible encodings of strings within the component model.560#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)]561#[expect(missing_docs, reason = "self-describing variants")]562pub enum StringEncoding {563Utf8,564Utf16,565CompactUtf16,566}567568impl StringEncoding {569/// Decodes the `u8` provided back into a `StringEncoding`, if it's valid.570pub fn from_u8(val: u8) -> Option<StringEncoding> {571if val == StringEncoding::Utf8 as u8 {572return Some(StringEncoding::Utf8);573}574if val == StringEncoding::Utf16 as u8 {575return Some(StringEncoding::Utf16);576}577if val == StringEncoding::CompactUtf16 as u8 {578return Some(StringEncoding::CompactUtf16);579}580None581}582}583584/// Possible transcoding operations that must be provided by the host.585///586/// Note that each transcoding operation may have a unique signature depending587/// on the precise operation.588#[expect(missing_docs, reason = "self-describing variants")]589#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]590pub enum Transcode {591Copy(FixedEncoding),592Latin1ToUtf16,593Latin1ToUtf8,594Utf16ToCompactProbablyUtf16,595Utf16ToCompactUtf16,596Utf16ToLatin1,597Utf16ToUtf8,598Utf8ToCompactUtf16,599Utf8ToLatin1,600Utf8ToUtf16,601}602603impl Transcode {604/// Get this transcoding's symbol fragment.605pub fn symbol_fragment(&self) -> &'static str {606match self {607Transcode::Copy(x) => match x {608FixedEncoding::Utf8 => "copy_utf8",609FixedEncoding::Utf16 => "copy_utf16",610FixedEncoding::Latin1 => "copy_latin1",611},612Transcode::Latin1ToUtf16 => "latin1_to_utf16",613Transcode::Latin1ToUtf8 => "latin1_to_utf8",614Transcode::Utf16ToCompactProbablyUtf16 => "utf16_to_compact_probably_utf16",615Transcode::Utf16ToCompactUtf16 => "utf16_to_compact_utf16",616Transcode::Utf16ToLatin1 => "utf16_to_latin1",617Transcode::Utf16ToUtf8 => "utf16_to_utf8",618Transcode::Utf8ToCompactUtf16 => "utf8_to_compact_utf16",619Transcode::Utf8ToLatin1 => "utf8_to_latin1",620Transcode::Utf8ToUtf16 => "utf8_to_utf16",621}622}623624/// Returns a human-readable description for this transcoding operation.625pub fn desc(&self) -> &'static str {626match self {627Transcode::Copy(FixedEncoding::Utf8) => "utf8-to-utf8",628Transcode::Copy(FixedEncoding::Utf16) => "utf16-to-utf16",629Transcode::Copy(FixedEncoding::Latin1) => "latin1-to-latin1",630Transcode::Latin1ToUtf16 => "latin1-to-utf16",631Transcode::Latin1ToUtf8 => "latin1-to-utf8",632Transcode::Utf16ToCompactProbablyUtf16 => "utf16-to-compact-probably-utf16",633Transcode::Utf16ToCompactUtf16 => "utf16-to-compact-utf16",634Transcode::Utf16ToLatin1 => "utf16-to-latin1",635Transcode::Utf16ToUtf8 => "utf16-to-utf8",636Transcode::Utf8ToCompactUtf16 => "utf8-to-compact-utf16",637Transcode::Utf8ToLatin1 => "utf8-to-latin1",638Transcode::Utf8ToUtf16 => "utf8-to-utf16",639}640}641}642643#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]644#[expect(missing_docs, reason = "self-describing variants")]645pub enum FixedEncoding {646Utf8,647Utf16,648Latin1,649}650651impl FixedEncoding {652/// Returns the byte width of unit loads/stores for this encoding, for653/// example the unit length is multiplied by this return value to get the654/// byte width of a string.655pub fn width(&self) -> u8 {656match self {657FixedEncoding::Utf8 => 1,658FixedEncoding::Utf16 => 2,659FixedEncoding::Latin1 => 1,660}661}662}663664/// Description of a new resource declared in a `GlobalInitializer::Resource`665/// variant.666///667/// This will have the effect of initializing runtime state for this resource,668/// namely the destructor is fetched and stored.669#[derive(Debug, Serialize, Deserialize)]670pub struct Resource {671/// The local index of the resource being defined.672pub index: DefinedResourceIndex,673/// Core wasm representation of this resource.674pub rep: WasmValType,675/// Optionally-specified destructor and where it comes from.676pub dtor: Option<CoreDef>,677/// Which component instance this resource logically belongs to.678pub instance: RuntimeComponentInstanceIndex,679}680681/// A list of all possible trampolines that may be required to compile a682/// component completely.683///684/// These trampolines are used often as core wasm definitions and require685/// Cranelift support to generate these functions. Each trampoline serves a686/// different purpose for implementing bits and pieces of the component model.687///688/// All trampolines have a core wasm function signature associated with them689/// which is stored in the `Component::trampolines` array.690///691/// Note that this type does not implement `Serialize` or `Deserialize` and692/// that's intentional as this isn't stored in the final compilation artifact.693#[derive(Debug)]694pub enum Trampoline {695/// Description of a lowered import used in conjunction with696/// `GlobalInitializer::LowerImport`.697LowerImport {698/// The runtime lowering state that this trampoline will access.699index: LoweredIndex,700701/// The type of the function that is being lowered, as perceived by the702/// component doing the lowering.703lower_ty: TypeFuncIndex,704705/// The canonical ABI options used when lowering this function specified706/// in the original component.707options: OptionsIndex,708},709710/// Information about a string transcoding function required by an adapter711/// module.712///713/// A transcoder is used when strings are passed between adapter modules,714/// optionally changing string encodings at the same time. The transcoder is715/// implemented in a few different layers:716///717/// * Each generated adapter module has some glue around invoking the718/// transcoder represented by this item. This involves bounds-checks and719/// handling `realloc` for example.720/// * Each transcoder gets a cranelift-generated trampoline which has the721/// appropriate signature for the adapter module in question. Existence of722/// this initializer indicates that this should be compiled by Cranelift.723/// * The cranelift-generated trampoline will invoke a "transcoder libcall"724/// which is implemented natively in Rust that has a signature independent725/// of memory64 configuration options for example.726Transcoder {727/// The transcoding operation being performed.728op: Transcode,729/// The linear memory that the string is being read from.730from: RuntimeMemoryIndex,731/// Whether or not the source linear memory is 64-bit or not.732from64: bool,733/// The linear memory that the string is being written to.734to: RuntimeMemoryIndex,735/// Whether or not the destination linear memory is 64-bit or not.736to64: bool,737},738739/// A `resource.new` intrinsic which will inject a new resource into the740/// table specified.741ResourceNew {742/// The specific component instance which is calling the intrinsic.743instance: RuntimeComponentInstanceIndex,744/// The type of the resource.745ty: TypeResourceTableIndex,746},747748/// Same as `ResourceNew`, but for the `resource.rep` intrinsic.749ResourceRep {750/// The specific component instance which is calling the intrinsic.751instance: RuntimeComponentInstanceIndex,752/// The type of the resource.753ty: TypeResourceTableIndex,754},755756/// Same as `ResourceNew`, but for the `resource.drop` intrinsic.757ResourceDrop {758/// The specific component instance which is calling the intrinsic.759instance: RuntimeComponentInstanceIndex,760/// The type of the resource.761ty: TypeResourceTableIndex,762},763764/// A `backpressure.inc` intrinsic.765BackpressureInc {766/// The specific component instance which is calling the intrinsic.767instance: RuntimeComponentInstanceIndex,768},769770/// A `backpressure.dec` intrinsic.771BackpressureDec {772/// The specific component instance which is calling the intrinsic.773instance: RuntimeComponentInstanceIndex,774},775776/// A `task.return` intrinsic, which returns a result to the caller of a777/// lifted export function. This allows the callee to continue executing778/// after returning a result.779TaskReturn {780/// The specific component instance which is calling the intrinsic.781instance: RuntimeComponentInstanceIndex,782/// Tuple representing the result types this intrinsic accepts.783results: TypeTupleIndex,784/// The canonical ABI options specified for this intrinsic.785options: OptionsIndex,786},787788/// A `task.cancel` intrinsic, which acknowledges a `CANCELLED` event789/// delivered to a guest task previously created by a call to an async790/// export.791TaskCancel {792/// The specific component instance which is calling the intrinsic.793instance: RuntimeComponentInstanceIndex,794},795796/// A `waitable-set.new` intrinsic.797WaitableSetNew {798/// The specific component instance which is calling the intrinsic.799instance: RuntimeComponentInstanceIndex,800},801802/// A `waitable-set.wait` intrinsic, which waits for at least one803/// outstanding async task/stream/future to make progress, returning the804/// first such event.805WaitableSetWait {806/// The specific component instance which is calling the intrinsic.807instance: RuntimeComponentInstanceIndex,808/// Configuration options for this intrinsic call.809options: OptionsIndex,810},811812/// A `waitable-set.poll` intrinsic, which checks whether any outstanding813/// async task/stream/future has made progress. Unlike `task.wait`, this814/// does not block and may return nothing if no such event has occurred.815WaitableSetPoll {816/// The specific component instance which is calling the intrinsic.817instance: RuntimeComponentInstanceIndex,818/// Configuration options for this intrinsic call.819options: OptionsIndex,820},821822/// A `waitable-set.drop` intrinsic.823WaitableSetDrop {824/// The specific component instance which is calling the intrinsic.825instance: RuntimeComponentInstanceIndex,826},827828/// A `waitable.join` intrinsic.829WaitableJoin {830/// The specific component instance which is calling the intrinsic.831instance: RuntimeComponentInstanceIndex,832},833834/// A `thread.yield` intrinsic, which yields control to the host so that other835/// tasks are able to make progress, if any.836ThreadYield {837/// The specific component instance which is calling the intrinsic.838instance: RuntimeComponentInstanceIndex,839/// If `true`, indicates the caller instance may receive notification840/// of task cancellation.841cancellable: bool,842},843844/// A `subtask.drop` intrinsic to drop a specified task which has completed.845SubtaskDrop {846/// The specific component instance which is calling the intrinsic.847instance: RuntimeComponentInstanceIndex,848},849850/// A `subtask.cancel` intrinsic to drop an in-progress task.851SubtaskCancel {852/// The specific component instance which is calling the intrinsic.853instance: RuntimeComponentInstanceIndex,854/// If `false`, block until cancellation completes rather than return855/// `BLOCKED`.856async_: bool,857},858859/// A `stream.new` intrinsic to create a new `stream` handle of the860/// specified type.861StreamNew {862/// The specific component instance which is calling the intrinsic.863instance: RuntimeComponentInstanceIndex,864/// The table index for the specific `stream` type and caller instance.865ty: TypeStreamTableIndex,866},867868/// A `stream.read` intrinsic to read from a `stream` of the specified type.869StreamRead {870/// The specific component instance which is calling the intrinsic.871instance: RuntimeComponentInstanceIndex,872/// The table index for the specific `stream` type and caller instance.873ty: TypeStreamTableIndex,874/// Any options (e.g. string encoding) to use when storing values to875/// memory.876options: OptionsIndex,877},878879/// A `stream.write` intrinsic to write to a `stream` of the specified type.880StreamWrite {881/// The specific component instance which is calling the intrinsic.882instance: RuntimeComponentInstanceIndex,883/// The table index for the specific `stream` type and caller instance.884ty: TypeStreamTableIndex,885/// Any options (e.g. string encoding) to use when storing values to886/// memory.887options: OptionsIndex,888},889890/// A `stream.cancel-read` intrinsic to cancel an in-progress read from a891/// `stream` of the specified type.892StreamCancelRead {893/// The specific component instance which is calling the intrinsic.894instance: RuntimeComponentInstanceIndex,895/// The table index for the specific `stream` type and caller instance.896ty: TypeStreamTableIndex,897/// If `false`, block until cancellation completes rather than return898/// `BLOCKED`.899async_: bool,900},901902/// A `stream.cancel-write` intrinsic to cancel an in-progress write from a903/// `stream` of the specified type.904StreamCancelWrite {905/// The specific component instance which is calling the intrinsic.906instance: RuntimeComponentInstanceIndex,907/// The table index for the specific `stream` type and caller instance.908ty: TypeStreamTableIndex,909/// If `false`, block until cancellation completes rather than return910/// `BLOCKED`.911async_: bool,912},913914/// A `stream.drop-readable` intrinsic to drop the readable end of a915/// `stream` of the specified type.916StreamDropReadable {917/// The specific component instance which is calling the intrinsic.918instance: RuntimeComponentInstanceIndex,919/// The table index for the specific `stream` type and caller instance.920ty: TypeStreamTableIndex,921},922923/// A `stream.drop-writable` intrinsic to drop the writable end of a924/// `stream` of the specified type.925StreamDropWritable {926/// The specific component instance which is calling the intrinsic.927instance: RuntimeComponentInstanceIndex,928/// The table index for the specific `stream` type and caller instance.929ty: TypeStreamTableIndex,930},931932/// A `future.new` intrinsic to create a new `future` handle of the933/// specified type.934FutureNew {935/// The specific component instance which is calling the intrinsic.936instance: RuntimeComponentInstanceIndex,937/// The table index for the specific `future` type and caller instance.938ty: TypeFutureTableIndex,939},940941/// A `future.read` intrinsic to read from a `future` of the specified type.942FutureRead {943/// The specific component instance which is calling the intrinsic.944instance: RuntimeComponentInstanceIndex,945/// The table index for the specific `future` type and caller instance.946ty: TypeFutureTableIndex,947/// Any options (e.g. string encoding) to use when storing values to948/// memory.949options: OptionsIndex,950},951952/// A `future.write` intrinsic to write to a `future` of the specified type.953FutureWrite {954/// The specific component instance which is calling the intrinsic.955instance: RuntimeComponentInstanceIndex,956/// The table index for the specific `future` type and caller instance.957ty: TypeFutureTableIndex,958/// Any options (e.g. string encoding) to use when storing values to959/// memory.960options: OptionsIndex,961},962963/// A `future.cancel-read` intrinsic to cancel an in-progress read from a964/// `future` of the specified type.965FutureCancelRead {966/// The specific component instance which is calling the intrinsic.967instance: RuntimeComponentInstanceIndex,968/// The table index for the specific `future` type and caller instance.969ty: TypeFutureTableIndex,970/// If `false`, block until cancellation completes rather than return971/// `BLOCKED`.972async_: bool,973},974975/// A `future.cancel-write` intrinsic to cancel an in-progress write from a976/// `future` of the specified type.977FutureCancelWrite {978/// The specific component instance which is calling the intrinsic.979instance: RuntimeComponentInstanceIndex,980/// The table index for the specific `future` type and caller instance.981ty: TypeFutureTableIndex,982/// If `false`, block until cancellation completes rather than return983/// `BLOCKED`.984async_: bool,985},986987/// A `future.drop-readable` intrinsic to drop the readable end of a988/// `future` of the specified type.989FutureDropReadable {990/// The specific component instance which is calling the intrinsic.991instance: RuntimeComponentInstanceIndex,992/// The table index for the specific `future` type and caller instance.993ty: TypeFutureTableIndex,994},995996/// A `future.drop-writable` intrinsic to drop the writable end of a997/// `future` of the specified type.998FutureDropWritable {999/// The specific component instance which is calling the intrinsic.1000instance: RuntimeComponentInstanceIndex,1001/// The table index for the specific `future` type and caller instance.1002ty: TypeFutureTableIndex,1003},10041005/// A `error-context.new` intrinsic to create a new `error-context` with a1006/// specified debug message.1007ErrorContextNew {1008/// The specific component instance which is calling the intrinsic.1009instance: RuntimeComponentInstanceIndex,1010/// The table index for the `error-context` type in the caller instance.1011ty: TypeComponentLocalErrorContextTableIndex,1012/// String encoding, memory, etc. to use when loading debug message.1013options: OptionsIndex,1014},10151016/// A `error-context.debug-message` intrinsic to get the debug message for a1017/// specified `error-context`.1018///1019/// Note that the debug message might not necessarily match what was passed1020/// to `error.new`.1021ErrorContextDebugMessage {1022/// The specific component instance which is calling the intrinsic.1023instance: RuntimeComponentInstanceIndex,1024/// The table index for the `error-context` type in the caller instance.1025ty: TypeComponentLocalErrorContextTableIndex,1026/// String encoding, memory, etc. to use when storing debug message.1027options: OptionsIndex,1028},10291030/// A `error-context.drop` intrinsic to drop a specified `error-context`.1031ErrorContextDrop {1032/// The specific component instance which is calling the intrinsic.1033instance: RuntimeComponentInstanceIndex,1034/// The table index for the `error-context` type in the caller instance.1035ty: TypeComponentLocalErrorContextTableIndex,1036},10371038/// An intrinsic used by FACT-generated modules which will transfer an owned1039/// resource from one table to another. Used in component-to-component1040/// adapter trampolines.1041ResourceTransferOwn,10421043/// Same as `ResourceTransferOwn` but for borrows.1044ResourceTransferBorrow,10451046/// An intrinsic used by FACT-generated modules which indicates that a call1047/// is being entered and resource-related metadata needs to be configured.1048///1049/// Note that this is currently only invoked when borrowed resources are1050/// detected, otherwise this is "optimized out".1051ResourceEnterCall,10521053/// Same as `ResourceEnterCall` except for when exiting a call.1054ResourceExitCall,10551056/// An intrinsic used by FACT-generated modules to prepare a call involving1057/// an async-lowered import and/or an async-lifted export.1058PrepareCall {1059/// The memory used to verify that the memory specified for the1060/// `task.return` that is called at runtime matches the one specified in1061/// the lifted export.1062memory: Option<RuntimeMemoryIndex>,1063},10641065/// An intrinsic used by FACT-generated modules to start a call involving a1066/// sync-lowered import and async-lifted export.1067SyncStartCall {1068/// The callee's callback function, if any.1069callback: Option<RuntimeCallbackIndex>,1070},10711072/// An intrinsic used by FACT-generated modules to start a call involving1073/// an async-lowered import function.1074///1075/// Note that `AsyncPrepareCall` and `AsyncStartCall` could theoretically be1076/// combined into a single `AsyncCall` intrinsic, but we separate them to1077/// allow the FACT-generated module to optionally call the callee directly1078/// without an intermediate host stack frame.1079AsyncStartCall {1080/// The callee's callback, if any.1081callback: Option<RuntimeCallbackIndex>,1082/// The callee's post-return function, if any.1083post_return: Option<RuntimePostReturnIndex>,1084},10851086/// An intrinisic used by FACT-generated modules to (partially or entirely) transfer1087/// ownership of a `future`.1088///1089/// Transferring a `future` can either mean giving away the readable end1090/// while retaining the writable end or only the former, depending on the1091/// ownership status of the `future`.1092FutureTransfer,10931094/// An intrinisic used by FACT-generated modules to (partially or entirely) transfer1095/// ownership of a `stream`.1096///1097/// Transferring a `stream` can either mean giving away the readable end1098/// while retaining the writable end or only the former, depending on the1099/// ownership status of the `stream`.1100StreamTransfer,11011102/// An intrinisic used by FACT-generated modules to (partially or entirely) transfer1103/// ownership of an `error-context`.1104///1105/// Unlike futures, streams, and resource handles, `error-context` handles1106/// are reference counted, meaning that sharing the handle with another1107/// component does not invalidate the handle in the original component.1108ErrorContextTransfer,11091110/// An intrinsic used by FACT-generated modules to trap with a specified1111/// code.1112Trap,11131114/// An intrinsic used by FACT-generated modules to push a task onto the1115/// stack for a sync-to-sync, guest-to-guest call.1116EnterSyncCall,1117/// An intrinsic used by FACT-generated modules to pop the task previously1118/// pushed by `EnterSyncCall`.1119ExitSyncCall,11201121/// Intrinsic used to implement the `context.get` component model builtin.1122///1123/// The payload here represents that this is accessing the Nth slot of local1124/// storage.1125ContextGet {1126/// The specific component instance which is calling the intrinsic.1127instance: RuntimeComponentInstanceIndex,1128/// Which slot to access.1129slot: u32,1130},11311132/// Intrinsic used to implement the `context.set` component model builtin.1133///1134/// The payload here represents that this is accessing the Nth slot of local1135/// storage.1136ContextSet {1137/// The specific component instance which is calling the intrinsic.1138instance: RuntimeComponentInstanceIndex,1139/// Which slot to update.1140slot: u32,1141},11421143/// Intrinsic used to implement the `thread.index` component model builtin.1144ThreadIndex,11451146/// Intrinsic used to implement the `thread.new-indirect` component model builtin.1147ThreadNewIndirect {1148/// The specific component instance which is calling the intrinsic.1149instance: RuntimeComponentInstanceIndex,1150/// The type index for the start function of the thread.1151start_func_ty_idx: ComponentTypeIndex,1152/// The index of the table that stores the start function.1153start_func_table_idx: RuntimeTableIndex,1154},11551156/// Intrinsic used to implement the `thread.switch-to` component model builtin.1157ThreadSwitchTo {1158/// The specific component instance which is calling the intrinsic.1159instance: RuntimeComponentInstanceIndex,1160/// If `true`, indicates the caller instance may receive notification1161/// of task cancellation.1162cancellable: bool,1163},11641165/// Intrinsic used to implement the `thread.suspend` component model builtin.1166ThreadSuspend {1167/// The specific component instance which is calling the intrinsic.1168instance: RuntimeComponentInstanceIndex,1169/// If `true`, indicates the caller instance may receive notification1170/// of task cancellation.1171cancellable: bool,1172},11731174/// Intrinsic used to implement the `thread.resume-later` component model builtin.1175ThreadResumeLater {1176/// The specific component instance which is calling the intrinsic.1177instance: RuntimeComponentInstanceIndex,1178},11791180/// Intrinsic used to implement the `thread.yield-to` component model builtin.1181ThreadYieldTo {1182/// The specific component instance which is calling the intrinsic.1183instance: RuntimeComponentInstanceIndex,1184/// If `true`, indicates the caller instance may receive notification1185/// of task cancellation.1186cancellable: bool,1187},1188}11891190impl Trampoline {1191/// Returns the name to use for the symbol of this trampoline in the final1192/// compiled artifact1193pub fn symbol_name(&self) -> String {1194use Trampoline::*;1195match self {1196LowerImport { index, .. } => {1197format!("component-lower-import[{}]", index.as_u32())1198}1199Transcoder {1200op, from64, to64, ..1201} => {1202let op = op.symbol_fragment();1203let from = if *from64 { "64" } else { "32" };1204let to = if *to64 { "64" } else { "32" };1205format!("component-transcode-{op}-m{from}-m{to}")1206}1207ResourceNew { ty, .. } => format!("component-resource-new[{}]", ty.as_u32()),1208ResourceRep { ty, .. } => format!("component-resource-rep[{}]", ty.as_u32()),1209ResourceDrop { ty, .. } => format!("component-resource-drop[{}]", ty.as_u32()),1210BackpressureInc { .. } => format!("backpressure-inc"),1211BackpressureDec { .. } => format!("backpressure-dec"),1212TaskReturn { .. } => format!("task-return"),1213TaskCancel { .. } => format!("task-cancel"),1214WaitableSetNew { .. } => format!("waitable-set-new"),1215WaitableSetWait { .. } => format!("waitable-set-wait"),1216WaitableSetPoll { .. } => format!("waitable-set-poll"),1217WaitableSetDrop { .. } => format!("waitable-set-drop"),1218WaitableJoin { .. } => format!("waitable-join"),1219ThreadYield { .. } => format!("thread-yield"),1220SubtaskDrop { .. } => format!("subtask-drop"),1221SubtaskCancel { .. } => format!("subtask-cancel"),1222StreamNew { .. } => format!("stream-new"),1223StreamRead { .. } => format!("stream-read"),1224StreamWrite { .. } => format!("stream-write"),1225StreamCancelRead { .. } => format!("stream-cancel-read"),1226StreamCancelWrite { .. } => format!("stream-cancel-write"),1227StreamDropReadable { .. } => format!("stream-drop-readable"),1228StreamDropWritable { .. } => format!("stream-drop-writable"),1229FutureNew { .. } => format!("future-new"),1230FutureRead { .. } => format!("future-read"),1231FutureWrite { .. } => format!("future-write"),1232FutureCancelRead { .. } => format!("future-cancel-read"),1233FutureCancelWrite { .. } => format!("future-cancel-write"),1234FutureDropReadable { .. } => format!("future-drop-readable"),1235FutureDropWritable { .. } => format!("future-drop-writable"),1236ErrorContextNew { .. } => format!("error-context-new"),1237ErrorContextDebugMessage { .. } => format!("error-context-debug-message"),1238ErrorContextDrop { .. } => format!("error-context-drop"),1239ResourceTransferOwn => format!("component-resource-transfer-own"),1240ResourceTransferBorrow => format!("component-resource-transfer-borrow"),1241ResourceEnterCall => format!("component-resource-enter-call"),1242ResourceExitCall => format!("component-resource-exit-call"),1243PrepareCall { .. } => format!("component-prepare-call"),1244SyncStartCall { .. } => format!("component-sync-start-call"),1245AsyncStartCall { .. } => format!("component-async-start-call"),1246FutureTransfer => format!("future-transfer"),1247StreamTransfer => format!("stream-transfer"),1248ErrorContextTransfer => format!("error-context-transfer"),1249Trap => format!("trap"),1250EnterSyncCall => format!("enter-sync-call"),1251ExitSyncCall => format!("exit-sync-call"),1252ContextGet { .. } => format!("context-get"),1253ContextSet { .. } => format!("context-set"),1254ThreadIndex => format!("thread-index"),1255ThreadNewIndirect { .. } => format!("thread-new-indirect"),1256ThreadSwitchTo { .. } => format!("thread-switch-to"),1257ThreadSuspend { .. } => format!("thread-suspend"),1258ThreadResumeLater { .. } => format!("thread-resume-later"),1259ThreadYieldTo { .. } => format!("thread-yield-to"),1260}1261}1262}126312641265