Path: blob/main/crates/environ/src/component/dfg.rs
3081 views
//! A dataflow-graph-like intermediate representation of a component1//!2//! This module contains `ComponentDfg` which is an intermediate step towards3//! becoming a full-fledged `Component`. The main purpose for the existence of4//! this representation of a component is to track dataflow between various5//! items within a component and support edits to them after the initial inlined6//! translation of a component.7//!8//! Currently fused adapters are represented with a core WebAssembly module9//! which gets "injected" into the final component as-if the component already10//! bundled it. In doing so the adapter modules need to be partitioned and11//! inserted into the final sequence of modules to instantiate. While this is12//! possible to do with a flat `GlobalInitializer` list it gets unwieldy really13//! quickly especially when other translation features are added.14//!15//! This module is largely a duplicate of the `component::info` module in this16//! crate. The hierarchy here uses `*Id` types instead of `*Index` types to17//! represent that they don't have any necessary implicit ordering. Additionally18//! nothing is kept in an ordered list and instead this is worked with in a19//! general dataflow fashion where dependencies are walked during processing.20//!21//! The `ComponentDfg::finish` method will convert the dataflow graph to a22//! linearized `GlobalInitializer` list which is intended to not be edited after23//! it's created.24//!25//! The `ComponentDfg` is created as part of the `component::inline` phase of26//! translation where the dataflow performed there allows identification of27//! fused adapters, what arguments make their way to core wasm modules, etc.2829use crate::component::*;30use crate::error::Result;31use crate::prelude::*;32use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType};33use cranelift_entity::packed_option::PackedOption;34use indexmap::IndexMap;35use info::LinearMemoryOptions;36use std::collections::HashMap;37use std::hash::Hash;38use std::ops::Index;39use wasmparser::component_types::ComponentCoreModuleTypeId;4041/// High-level representation of a component as a "data-flow graph".42#[derive(Default)]43pub struct ComponentDfg {44/// Same as `Component::import_types`45pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,4647/// Same as `Component::imports`48pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,4950/// Same as `Component::exports`51pub exports: IndexMap<String, Export>,5253/// All trampolines and their type signature which will need to get54/// compiled by Cranelift.55pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,5657/// A map from `UnsafeIntrinsic::index()` to that intrinsic's58/// module-interned type.59pub unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],6061/// Know reallocation functions which are used by `lowerings` (e.g. will be62/// used by the host)63pub reallocs: Intern<ReallocId, CoreDef>,6465/// Same as `reallocs`, but for async-lifted functions.66pub callbacks: Intern<CallbackId, CoreDef>,6768/// Same as `reallocs`, but for post-return.69pub post_returns: Intern<PostReturnId, CoreDef>,7071/// Same as `reallocs`, but for memories.72pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,7374/// Same as `reallocs`, but for tables.75pub tables: Intern<TableId, CoreExport<TableIndex>>,7677/// Metadata about identified fused adapters.78///79/// Note that this list is required to be populated in-order where the80/// "left" adapters cannot depend on "right" adapters. Currently this falls81/// out of the inlining pass of translation.82pub adapters: Intern<AdapterId, Adapter>,8384/// Metadata about all known core wasm instances created.85///86/// This is mostly an ordered list and is not deduplicated based on contents87/// unlike the items above. Creation of an `Instance` is side-effectful and88/// all instances here are always required to be created. These are89/// considered "roots" in dataflow.90pub instances: PrimaryMap<InstanceId, Instance>,9192/// Number of component instances that were created during the inlining93/// phase (this is not edited after creation).94pub num_runtime_component_instances: u32,9596/// Known adapter modules and how they are instantiated.97///98/// This map is not filled in on the initial creation of a `ComponentDfg`.99/// Instead these modules are filled in by the `inline::adapt` phase where100/// adapter modules are identified and filled in here.101///102/// The payload here is the static module index representing the core wasm103/// adapter module that was generated as well as the arguments to the104/// instantiation of the adapter module.105pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,106107/// Metadata about where adapters can be found within their respective108/// adapter modules.109///110/// Like `adapter_modules` this is not filled on the initial creation of111/// `ComponentDfg` but rather is created alongside `adapter_modules` during112/// the `inline::adapt` phase of translation.113///114/// The values here are the module that the adapter is present within along115/// as the core wasm index of the export corresponding to the lowered116/// version of the adapter.117pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,118119/// Defined resources in this component sorted by index with metadata about120/// each resource.121///122/// Note that each index here is a unique resource, and that may mean it was123/// the same component instantiated twice for example.124pub resources: PrimaryMap<DefinedResourceIndex, Resource>,125126/// Metadata about all imported resources into this component. This records127/// both how many imported resources there are (the size of this map) along128/// with what the corresponding runtime import is.129pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,130131/// The total number of future tables that will be used by this component.132pub num_future_tables: usize,133134/// The total number of stream tables that will be used by this component.135pub num_stream_tables: usize,136137/// The total number of error-context tables that will be used by this138/// component.139pub num_error_context_tables: usize,140141/// An ordered list of side effects induced by instantiating this component.142///143/// Currently all side effects are either instantiating core wasm modules or144/// declaring a resource. These side effects affect the dataflow processing145/// of this component by idnicating what order operations should be146/// performed during instantiation.147pub side_effects: Vec<SideEffect>,148149/// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by150/// this component.151pub options: Intern<OptionsId, CanonicalOptions>,152}153154/// Possible side effects that are possible with instantiating this component.155pub enum SideEffect {156/// A core wasm instance was created.157///158/// Instantiation is side-effectful due to the presence of constructs such159/// as traps and the core wasm `start` function which may call component160/// imports. Instantiation order from the original component must be done in161/// the same order.162Instance(InstanceId, RuntimeComponentInstanceIndex),163164/// A resource was declared in this component.165///166/// This is a bit less side-effectful than instantiation but this serves as167/// the order in which resources are initialized in a component with their168/// destructors. Destructors are loaded from core wasm instances (or169/// lowerings) which are produced by prior side-effectful operations.170Resource(DefinedResourceIndex),171}172173/// A sound approximation of a particular module's set of instantiations.174///175/// This type forms a simple lattice that we can use in static analyses that in176/// turn let us specialize a module's compilation to exactly the imports it is177/// given.178#[derive(Clone, Copy, Default)]179pub enum AbstractInstantiations<'a> {180/// The associated module is instantiated many times.181Many,182183/// The module is instantiated exactly once, with the given definitions as184/// arguments to that instantiation.185One(&'a [info::CoreDef]),186187/// The module is never instantiated.188#[default]189None,190}191192impl AbstractInstantiations<'_> {193/// Join two facts about a particular module's instantiation together.194///195/// This is the least-upper-bound operation on the lattice.196pub fn join(&mut self, other: Self) {197*self = match (*self, other) {198(Self::Many, _) | (_, Self::Many) => Self::Many,199(Self::One(a), Self::One(b)) if a == b => Self::One(a),200(Self::One(_), Self::One(_)) => Self::Many,201(Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a),202(Self::None, Self::None) => Self::None,203}204}205}206207macro_rules! id {208($(pub struct $name:ident(u32);)*) => ($(209#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]210#[expect(missing_docs, reason = "tedious to document")]211pub struct $name(u32);212cranelift_entity::entity_impl!($name);213)*)214}215216id! {217pub struct InstanceId(u32);218pub struct MemoryId(u32);219pub struct TableId(u32);220pub struct ReallocId(u32);221pub struct CallbackId(u32);222pub struct AdapterId(u32);223pub struct PostReturnId(u32);224pub struct AdapterModuleId(u32);225pub struct OptionsId(u32);226}227228/// Same as `info::InstantiateModule`229#[expect(missing_docs, reason = "tedious to document variants")]230pub enum Instance {231Static(StaticModuleIndex, Box<[CoreDef]>),232Import(233RuntimeImportIndex,234IndexMap<String, IndexMap<String, CoreDef>>,235),236}237238/// Same as `info::Export`239#[expect(missing_docs, reason = "tedious to document variants")]240pub enum Export {241LiftedFunction {242ty: TypeFuncIndex,243func: CoreDef,244options: OptionsId,245},246ModuleStatic {247ty: ComponentCoreModuleTypeId,248index: StaticModuleIndex,249},250ModuleImport {251ty: TypeModuleIndex,252import: RuntimeImportIndex,253},254Instance {255ty: TypeComponentInstanceIndex,256exports: IndexMap<String, Export>,257},258Type(TypeDef),259}260261/// Same as `info::CoreDef`, except has an extra `Adapter` variant.262#[derive(Debug, Clone, Hash, Eq, PartialEq)]263#[expect(missing_docs, reason = "tedious to document variants")]264pub enum CoreDef {265Export(CoreExport<EntityIndex>),266InstanceFlags(RuntimeComponentInstanceIndex),267Trampoline(TrampolineIndex),268UnsafeIntrinsic(ModuleInternedTypeIndex, UnsafeIntrinsic),269TaskMayBlock,270271/// This is a special variant not present in `info::CoreDef` which272/// represents that this definition refers to a fused adapter function. This273/// adapter is fully processed after the initial translation and274/// identification of adapters.275///276/// During translation into `info::CoreDef` this variant is erased and277/// replaced by `info::CoreDef::Export` since adapters are always278/// represented as the exports of a core wasm instance.279Adapter(AdapterId),280}281282impl<T> From<CoreExport<T>> for CoreDef283where284EntityIndex: From<T>,285{286fn from(export: CoreExport<T>) -> CoreDef {287CoreDef::Export(export.map_index(|i| i.into()))288}289}290291/// Same as `info::CoreExport`292#[derive(Debug, Clone, Hash, Eq, PartialEq)]293#[expect(missing_docs, reason = "self-describing fields")]294pub struct CoreExport<T> {295pub instance: InstanceId,296pub item: ExportItem<T>,297}298299impl<T> CoreExport<T> {300#[expect(missing_docs, reason = "self-describing function")]301pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {302CoreExport {303instance: self.instance,304item: match self.item {305ExportItem::Index(i) => ExportItem::Index(f(i)),306ExportItem::Name(s) => ExportItem::Name(s),307},308}309}310}311312/// Same as `info::Trampoline`313#[derive(Clone, PartialEq, Eq, Hash)]314#[expect(missing_docs, reason = "self-describing fields")]315pub enum Trampoline {316LowerImport {317import: RuntimeImportIndex,318options: OptionsId,319lower_ty: TypeFuncIndex,320},321Transcoder {322op: Transcode,323from: MemoryId,324from64: bool,325to: MemoryId,326to64: bool,327},328ResourceNew {329instance: RuntimeComponentInstanceIndex,330ty: TypeResourceTableIndex,331},332ResourceRep {333instance: RuntimeComponentInstanceIndex,334ty: TypeResourceTableIndex,335},336ResourceDrop {337instance: RuntimeComponentInstanceIndex,338ty: TypeResourceTableIndex,339},340BackpressureInc {341instance: RuntimeComponentInstanceIndex,342},343BackpressureDec {344instance: RuntimeComponentInstanceIndex,345},346TaskReturn {347instance: RuntimeComponentInstanceIndex,348results: TypeTupleIndex,349options: OptionsId,350},351TaskCancel {352instance: RuntimeComponentInstanceIndex,353},354WaitableSetNew {355instance: RuntimeComponentInstanceIndex,356},357WaitableSetWait {358instance: RuntimeComponentInstanceIndex,359options: OptionsId,360},361WaitableSetPoll {362instance: RuntimeComponentInstanceIndex,363options: OptionsId,364},365WaitableSetDrop {366instance: RuntimeComponentInstanceIndex,367},368WaitableJoin {369instance: RuntimeComponentInstanceIndex,370},371ThreadYield {372instance: RuntimeComponentInstanceIndex,373cancellable: bool,374},375SubtaskDrop {376instance: RuntimeComponentInstanceIndex,377},378SubtaskCancel {379instance: RuntimeComponentInstanceIndex,380async_: bool,381},382StreamNew {383instance: RuntimeComponentInstanceIndex,384ty: TypeStreamTableIndex,385},386StreamRead {387instance: RuntimeComponentInstanceIndex,388ty: TypeStreamTableIndex,389options: OptionsId,390},391StreamWrite {392instance: RuntimeComponentInstanceIndex,393ty: TypeStreamTableIndex,394options: OptionsId,395},396StreamCancelRead {397instance: RuntimeComponentInstanceIndex,398ty: TypeStreamTableIndex,399async_: bool,400},401StreamCancelWrite {402instance: RuntimeComponentInstanceIndex,403ty: TypeStreamTableIndex,404async_: bool,405},406StreamDropReadable {407instance: RuntimeComponentInstanceIndex,408ty: TypeStreamTableIndex,409},410StreamDropWritable {411instance: RuntimeComponentInstanceIndex,412ty: TypeStreamTableIndex,413},414FutureNew {415instance: RuntimeComponentInstanceIndex,416ty: TypeFutureTableIndex,417},418FutureRead {419instance: RuntimeComponentInstanceIndex,420ty: TypeFutureTableIndex,421options: OptionsId,422},423FutureWrite {424instance: RuntimeComponentInstanceIndex,425ty: TypeFutureTableIndex,426options: OptionsId,427},428FutureCancelRead {429instance: RuntimeComponentInstanceIndex,430ty: TypeFutureTableIndex,431async_: bool,432},433FutureCancelWrite {434instance: RuntimeComponentInstanceIndex,435ty: TypeFutureTableIndex,436async_: bool,437},438FutureDropReadable {439instance: RuntimeComponentInstanceIndex,440ty: TypeFutureTableIndex,441},442FutureDropWritable {443instance: RuntimeComponentInstanceIndex,444ty: TypeFutureTableIndex,445},446ErrorContextNew {447instance: RuntimeComponentInstanceIndex,448ty: TypeComponentLocalErrorContextTableIndex,449options: OptionsId,450},451ErrorContextDebugMessage {452instance: RuntimeComponentInstanceIndex,453ty: TypeComponentLocalErrorContextTableIndex,454options: OptionsId,455},456ErrorContextDrop {457instance: RuntimeComponentInstanceIndex,458ty: TypeComponentLocalErrorContextTableIndex,459},460ResourceTransferOwn,461ResourceTransferBorrow,462PrepareCall {463memory: Option<MemoryId>,464},465SyncStartCall {466callback: Option<CallbackId>,467},468AsyncStartCall {469callback: Option<CallbackId>,470post_return: Option<PostReturnId>,471},472FutureTransfer,473StreamTransfer,474ErrorContextTransfer,475Trap,476EnterSyncCall,477ExitSyncCall,478ContextGet {479instance: RuntimeComponentInstanceIndex,480slot: u32,481},482ContextSet {483instance: RuntimeComponentInstanceIndex,484slot: u32,485},486ThreadIndex,487ThreadNewIndirect {488instance: RuntimeComponentInstanceIndex,489start_func_ty_idx: ComponentTypeIndex,490start_func_table_id: TableId,491},492ThreadSwitchTo {493instance: RuntimeComponentInstanceIndex,494cancellable: bool,495},496ThreadSuspend {497instance: RuntimeComponentInstanceIndex,498cancellable: bool,499},500ThreadResumeLater {501instance: RuntimeComponentInstanceIndex,502},503ThreadYieldTo {504instance: RuntimeComponentInstanceIndex,505cancellable: bool,506},507}508509#[derive(Copy, Clone, Hash, Eq, PartialEq)]510#[expect(missing_docs, reason = "self-describing fields")]511pub struct FutureInfo {512pub instance: RuntimeComponentInstanceIndex,513pub payload_type: Option<InterfaceType>,514}515516#[derive(Copy, Clone, Hash, Eq, PartialEq)]517#[expect(missing_docs, reason = "self-describing fields")]518pub struct StreamInfo {519pub instance: RuntimeComponentInstanceIndex,520pub payload_type: InterfaceType,521}522523/// Same as `info::CanonicalOptionsDataModel`.524#[derive(Clone, Hash, Eq, PartialEq)]525#[expect(missing_docs, reason = "self-describing fields")]526pub enum CanonicalOptionsDataModel {527Gc {},528LinearMemory {529memory: Option<MemoryId>,530realloc: Option<ReallocId>,531},532}533534/// Same as `info::CanonicalOptions`535#[derive(Clone, Hash, Eq, PartialEq)]536#[expect(missing_docs, reason = "self-describing fields")]537pub struct CanonicalOptions {538pub instance: RuntimeComponentInstanceIndex,539pub string_encoding: StringEncoding,540pub callback: Option<CallbackId>,541pub post_return: Option<PostReturnId>,542pub async_: bool,543pub cancellable: bool,544pub core_type: ModuleInternedTypeIndex,545pub data_model: CanonicalOptionsDataModel,546}547548/// Same as `info::Resource`549#[expect(missing_docs, reason = "self-describing fields")]550pub struct Resource {551pub rep: WasmValType,552pub dtor: Option<CoreDef>,553pub instance: RuntimeComponentInstanceIndex,554}555556/// A helper structure to "intern" and deduplicate values of type `V` with an557/// identifying key `K`.558///559/// Note that this can also be used where `V` can't be intern'd to represent a560/// flat list of items.561pub struct Intern<K: EntityRef, V> {562intern_map: HashMap<V, K>,563key_map: PrimaryMap<K, V>,564}565566impl<K, V> Intern<K, V>567where568K: EntityRef,569{570/// Inserts the `value` specified into this set, returning either a fresh571/// key `K` if this value hasn't been seen before or otherwise returning the572/// previous `K` used to represent value.573///574/// Note that this should only be used for component model items where the575/// creation of `value` is not side-effectful.576pub fn push(&mut self, value: V) -> K577where578V: Hash + Eq + Clone,579{580*self581.intern_map582.entry(value.clone())583.or_insert_with(|| self.key_map.push(value))584}585586/// Returns an iterator of all the values contained within this set.587pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {588self.key_map.iter()589}590}591592impl<K: EntityRef, V> Index<K> for Intern<K, V> {593type Output = V;594fn index(&self, key: K) -> &V {595&self.key_map[key]596}597}598599impl<K: EntityRef, V> Default for Intern<K, V> {600fn default() -> Intern<K, V> {601Intern {602intern_map: HashMap::new(),603key_map: PrimaryMap::new(),604}605}606}607608impl ComponentDfg {609/// Consumes the intermediate `ComponentDfg` to produce a final `Component`610/// with a linear initializer list.611pub fn finish(612self,613wasmtime_types: &mut ComponentTypesBuilder,614wasmparser_types: wasmparser::types::TypesRef<'_>,615) -> Result<ComponentTranslation> {616let mut linearize = LinearizeDfg {617dfg: &self,618initializers: Vec::new(),619runtime_memories: Default::default(),620runtime_tables: Default::default(),621runtime_post_return: Default::default(),622runtime_reallocs: Default::default(),623runtime_callbacks: Default::default(),624runtime_instances: Default::default(),625num_lowerings: 0,626unsafe_intrinsics: Default::default(),627trampolines: Default::default(),628trampoline_defs: Default::default(),629trampoline_map: Default::default(),630options: Default::default(),631options_map: Default::default(),632};633634// Handle all side effects of this component in the order that they're635// defined. This will, for example, process all instantiations necessary636// of core wasm modules.637for item in linearize.dfg.side_effects.iter() {638linearize.side_effect(item);639}640641// Next the exports of the instance are handled which will likely end up642// creating some lowered imports, perhaps some saved modules, etc.643let mut export_items = PrimaryMap::new();644let mut exports = NameMap::default();645for (name, export) in self.exports.iter() {646let export =647linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;648exports.insert(name, &mut NameMapNoIntern, false, export)?;649}650651// With all those pieces done the results of the dataflow-based652// linearization are recorded into the `Component`. The number of653// runtime values used for each index space is used from the `linearize`654// result.655Ok(ComponentTranslation {656trampolines: linearize.trampoline_defs,657component: Component {658exports,659export_items,660initializers: linearize.initializers,661unsafe_intrinsics: linearize.unsafe_intrinsics,662trampolines: linearize.trampolines,663num_lowerings: linearize.num_lowerings,664options: linearize.options,665666num_runtime_memories: linearize.runtime_memories.len() as u32,667num_runtime_tables: linearize.runtime_tables.len() as u32,668num_runtime_post_returns: linearize.runtime_post_return.len() as u32,669num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,670num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,671num_runtime_instances: linearize.runtime_instances.len() as u32,672imports: self.imports,673import_types: self.import_types,674num_runtime_component_instances: self.num_runtime_component_instances,675num_future_tables: self.num_future_tables,676num_stream_tables: self.num_stream_tables,677num_error_context_tables: self.num_error_context_tables,678num_resources: (self.resources.len() + self.imported_resources.len()) as u32,679imported_resources: self.imported_resources,680defined_resource_instances: self681.resources682.iter()683.map(|(_, r)| r.instance)684.collect(),685},686})687}688689/// Converts the provided defined index into a normal index, adding in the690/// number of imported resources.691pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {692ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))693}694}695696struct LinearizeDfg<'a> {697dfg: &'a ComponentDfg,698initializers: Vec<GlobalInitializer>,699unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],700trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,701trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,702options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,703trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,704runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,705runtime_tables: HashMap<TableId, RuntimeTableIndex>,706runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,707runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,708runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,709runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,710options_map: HashMap<OptionsId, OptionsIndex>,711num_lowerings: u32,712}713714#[derive(Copy, Clone, Hash, Eq, PartialEq)]715enum RuntimeInstance {716Normal(InstanceId),717Adapter(AdapterModuleId),718}719720impl LinearizeDfg<'_> {721fn side_effect(&mut self, effect: &SideEffect) {722match effect {723SideEffect::Instance(i, ci) => {724self.instantiate(*i, &self.dfg.instances[*i], *ci);725}726SideEffect::Resource(i) => {727self.resource(*i, &self.dfg.resources[*i]);728}729}730}731732fn instantiate(733&mut self,734instance: InstanceId,735args: &Instance,736component_instance: RuntimeComponentInstanceIndex,737) {738log::trace!("creating instance {instance:?}");739let instantiation = match args {740Instance::Static(index, args) => InstantiateModule::Static(741*index,742args.iter().map(|def| self.core_def(def)).collect(),743),744Instance::Import(index, args) => InstantiateModule::Import(745*index,746args.iter()747.map(|(module, values)| {748let values = values749.iter()750.map(|(name, def)| (name.clone(), self.core_def(def)))751.collect();752(module.clone(), values)753})754.collect(),755),756};757let index = RuntimeInstanceIndex::new(self.runtime_instances.len());758self.initializers.push(GlobalInitializer::InstantiateModule(759instantiation,760Some(component_instance),761));762let prev = self763.runtime_instances764.insert(RuntimeInstance::Normal(instance), index);765assert!(prev.is_none());766}767768fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {769let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));770self.initializers771.push(GlobalInitializer::Resource(info::Resource {772dtor,773index,774rep: resource.rep,775instance: resource.instance,776}));777}778779fn export(780&mut self,781export: &Export,782items: &mut PrimaryMap<ExportIndex, info::Export>,783wasmtime_types: &mut ComponentTypesBuilder,784wasmparser_types: wasmparser::types::TypesRef<'_>,785) -> Result<ExportIndex> {786let item = match export {787Export::LiftedFunction { ty, func, options } => {788let func = self.core_def(func);789let options = self.options(*options);790info::Export::LiftedFunction {791ty: *ty,792func,793options,794}795}796Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {797ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,798index: *index,799},800Export::ModuleImport { ty, import } => info::Export::ModuleImport {801ty: *ty,802import: *import,803},804Export::Instance { ty, exports } => info::Export::Instance {805ty: *ty,806exports: {807let mut map = NameMap::default();808for (name, export) in exports {809let export =810self.export(export, items, wasmtime_types, wasmparser_types)?;811map.insert(name, &mut NameMapNoIntern, false, export)?;812}813map814},815},816Export::Type(def) => info::Export::Type(*def),817};818Ok(items.push(item))819}820821fn options(&mut self, options: OptionsId) -> OptionsIndex {822self.intern_no_init(823options,824|me| &mut me.options_map,825|me, options| me.convert_options(options),826)827}828829fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {830let options = &self.dfg.options[options];831let data_model = match options.data_model {832CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},833CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {834info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {835memory: memory.map(|mem| self.runtime_memory(mem)),836realloc: realloc.map(|mem| self.runtime_realloc(mem)),837})838}839};840let callback = options.callback.map(|mem| self.runtime_callback(mem));841let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));842let options = info::CanonicalOptions {843instance: options.instance,844string_encoding: options.string_encoding,845callback,846post_return,847async_: options.async_,848cancellable: options.cancellable,849core_type: options.core_type,850data_model,851};852self.options.push(options)853}854855fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {856self.intern(857mem,858|me| &mut me.runtime_memories,859|me, mem| me.core_export(&me.dfg.memories[mem]),860|index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),861)862}863864fn runtime_table(&mut self, table: TableId) -> RuntimeTableIndex {865self.intern(866table,867|me| &mut me.runtime_tables,868|me, table| me.core_export(&me.dfg.tables[table]),869|index, export| GlobalInitializer::ExtractTable(ExtractTable { index, export }),870)871}872873fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {874self.intern(875realloc,876|me| &mut me.runtime_reallocs,877|me, realloc| me.core_def(&me.dfg.reallocs[realloc]),878|index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),879)880}881882fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {883self.intern(884callback,885|me| &mut me.runtime_callbacks,886|me, callback| me.core_def(&me.dfg.callbacks[callback]),887|index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),888)889}890891fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {892self.intern(893post_return,894|me| &mut me.runtime_post_return,895|me, post_return| me.core_def(&me.dfg.post_returns[post_return]),896|index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),897)898}899900fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {901match def {902CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),903CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),904CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),905CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),906CoreDef::UnsafeIntrinsic(ty, i) => {907let index = usize::try_from(i.index()).unwrap();908if self.unsafe_intrinsics[index].is_none() {909self.unsafe_intrinsics[index] = Some(*ty).into();910}911info::CoreDef::UnsafeIntrinsic(*i)912}913CoreDef::TaskMayBlock => info::CoreDef::TaskMayBlock,914}915}916917fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {918if let Some(idx) = self.trampoline_map.get(&index) {919return *idx;920}921let (signature, trampoline) = &self.dfg.trampolines[index];922let trampoline = match trampoline {923Trampoline::LowerImport {924import,925options,926lower_ty,927} => {928let index = LoweredIndex::from_u32(self.num_lowerings);929self.num_lowerings += 1;930self.initializers.push(GlobalInitializer::LowerImport {931index,932import: *import,933});934info::Trampoline::LowerImport {935index,936options: self.options(*options),937lower_ty: *lower_ty,938}939}940Trampoline::Transcoder {941op,942from,943from64,944to,945to64,946} => info::Trampoline::Transcoder {947op: *op,948from: self.runtime_memory(*from),949from64: *from64,950to: self.runtime_memory(*to),951to64: *to64,952},953Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew {954instance: *instance,955ty: *ty,956},957Trampoline::ResourceDrop { instance, ty } => info::Trampoline::ResourceDrop {958instance: *instance,959ty: *ty,960},961Trampoline::ResourceRep { instance, ty } => info::Trampoline::ResourceRep {962instance: *instance,963ty: *ty,964},965Trampoline::BackpressureInc { instance } => info::Trampoline::BackpressureInc {966instance: *instance,967},968Trampoline::BackpressureDec { instance } => info::Trampoline::BackpressureDec {969instance: *instance,970},971Trampoline::TaskReturn {972instance,973results,974options,975} => info::Trampoline::TaskReturn {976instance: *instance,977results: *results,978options: self.options(*options),979},980Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {981instance: *instance,982},983Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {984instance: *instance,985},986Trampoline::WaitableSetWait { instance, options } => {987info::Trampoline::WaitableSetWait {988instance: *instance,989options: self.options(*options),990}991}992Trampoline::WaitableSetPoll { instance, options } => {993info::Trampoline::WaitableSetPoll {994instance: *instance,995options: self.options(*options),996}997}998Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {999instance: *instance,1000},1001Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {1002instance: *instance,1003},1004Trampoline::ThreadYield {1005instance,1006cancellable,1007} => info::Trampoline::ThreadYield {1008instance: *instance,1009cancellable: *cancellable,1010},1011Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {1012instance: *instance,1013},1014Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {1015instance: *instance,1016async_: *async_,1017},1018Trampoline::StreamNew { instance, ty } => info::Trampoline::StreamNew {1019instance: *instance,1020ty: *ty,1021},1022Trampoline::StreamRead {1023instance,1024ty,1025options,1026} => info::Trampoline::StreamRead {1027instance: *instance,1028ty: *ty,1029options: self.options(*options),1030},1031Trampoline::StreamWrite {1032instance,1033ty,1034options,1035} => info::Trampoline::StreamWrite {1036instance: *instance,1037ty: *ty,1038options: self.options(*options),1039},1040Trampoline::StreamCancelRead {1041instance,1042ty,1043async_,1044} => info::Trampoline::StreamCancelRead {1045instance: *instance,1046ty: *ty,1047async_: *async_,1048},1049Trampoline::StreamCancelWrite {1050instance,1051ty,1052async_,1053} => info::Trampoline::StreamCancelWrite {1054instance: *instance,1055ty: *ty,1056async_: *async_,1057},1058Trampoline::StreamDropReadable { instance, ty } => {1059info::Trampoline::StreamDropReadable {1060instance: *instance,1061ty: *ty,1062}1063}1064Trampoline::StreamDropWritable { instance, ty } => {1065info::Trampoline::StreamDropWritable {1066instance: *instance,1067ty: *ty,1068}1069}1070Trampoline::FutureNew { instance, ty } => info::Trampoline::FutureNew {1071instance: *instance,1072ty: *ty,1073},1074Trampoline::FutureRead {1075instance,1076ty,1077options,1078} => info::Trampoline::FutureRead {1079instance: *instance,1080ty: *ty,1081options: self.options(*options),1082},1083Trampoline::FutureWrite {1084instance,1085ty,1086options,1087} => info::Trampoline::FutureWrite {1088instance: *instance,1089ty: *ty,1090options: self.options(*options),1091},1092Trampoline::FutureCancelRead {1093instance,1094ty,1095async_,1096} => info::Trampoline::FutureCancelRead {1097instance: *instance,1098ty: *ty,1099async_: *async_,1100},1101Trampoline::FutureCancelWrite {1102instance,1103ty,1104async_,1105} => info::Trampoline::FutureCancelWrite {1106instance: *instance,1107ty: *ty,1108async_: *async_,1109},1110Trampoline::FutureDropReadable { instance, ty } => {1111info::Trampoline::FutureDropReadable {1112instance: *instance,1113ty: *ty,1114}1115}1116Trampoline::FutureDropWritable { instance, ty } => {1117info::Trampoline::FutureDropWritable {1118instance: *instance,1119ty: *ty,1120}1121}1122Trampoline::ErrorContextNew {1123instance,1124ty,1125options,1126} => info::Trampoline::ErrorContextNew {1127instance: *instance,1128ty: *ty,1129options: self.options(*options),1130},1131Trampoline::ErrorContextDebugMessage {1132instance,1133ty,1134options,1135} => info::Trampoline::ErrorContextDebugMessage {1136instance: *instance,1137ty: *ty,1138options: self.options(*options),1139},1140Trampoline::ErrorContextDrop { instance, ty } => info::Trampoline::ErrorContextDrop {1141instance: *instance,1142ty: *ty,1143},1144Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,1145Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,1146Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {1147memory: memory.map(|v| self.runtime_memory(v)),1148},1149Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall {1150callback: callback.map(|v| self.runtime_callback(v)),1151},1152Trampoline::AsyncStartCall {1153callback,1154post_return,1155} => info::Trampoline::AsyncStartCall {1156callback: callback.map(|v| self.runtime_callback(v)),1157post_return: post_return.map(|v| self.runtime_post_return(v)),1158},1159Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,1160Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,1161Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,1162Trampoline::Trap => info::Trampoline::Trap,1163Trampoline::EnterSyncCall => info::Trampoline::EnterSyncCall,1164Trampoline::ExitSyncCall => info::Trampoline::ExitSyncCall,1165Trampoline::ContextGet { instance, slot } => info::Trampoline::ContextGet {1166instance: *instance,1167slot: *slot,1168},1169Trampoline::ContextSet { instance, slot } => info::Trampoline::ContextSet {1170instance: *instance,1171slot: *slot,1172},1173Trampoline::ThreadIndex => info::Trampoline::ThreadIndex,1174Trampoline::ThreadNewIndirect {1175instance,1176start_func_ty_idx,1177start_func_table_id,1178} => info::Trampoline::ThreadNewIndirect {1179instance: *instance,1180start_func_ty_idx: *start_func_ty_idx,1181start_func_table_idx: self.runtime_table(*start_func_table_id),1182},1183Trampoline::ThreadSwitchTo {1184instance,1185cancellable,1186} => info::Trampoline::ThreadSwitchTo {1187instance: *instance,1188cancellable: *cancellable,1189},1190Trampoline::ThreadSuspend {1191instance,1192cancellable,1193} => info::Trampoline::ThreadSuspend {1194instance: *instance,1195cancellable: *cancellable,1196},1197Trampoline::ThreadResumeLater { instance } => info::Trampoline::ThreadResumeLater {1198instance: *instance,1199},1200Trampoline::ThreadYieldTo {1201instance,1202cancellable,1203} => info::Trampoline::ThreadYieldTo {1204instance: *instance,1205cancellable: *cancellable,1206},1207};1208let i1 = self.trampolines.push(*signature);1209let i2 = self.trampoline_defs.push(trampoline);1210assert_eq!(i1, i2);1211self.trampoline_map.insert(index, i1);1212i11213}12141215fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>1216where1217T: Clone,1218{1219let instance = export.instance;1220log::trace!("referencing export of {instance:?}");1221info::CoreExport {1222instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],1223item: export.item.clone(),1224}1225}12261227fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {1228let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];12291230// Instantiates the adapter module if it hasn't already been1231// instantiated or otherwise returns the index that the module was1232// already instantiated at.1233let instance = self.adapter_module(adapter_module);12341235// This adapter is always an export of the instance.1236info::CoreExport {1237instance,1238item: ExportItem::Index(entity_index),1239}1240}12411242fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {1243self.intern(1244RuntimeInstance::Adapter(adapter_module),1245|me| &mut me.runtime_instances,1246|me, _| {1247log::debug!("instantiating {adapter_module:?}");1248let (module_index, args) = &me.dfg.adapter_modules[adapter_module];1249let args = args.iter().map(|arg| me.core_def(arg)).collect();1250let instantiate = InstantiateModule::Static(*module_index, args);1251GlobalInitializer::InstantiateModule(instantiate, None)1252},1253|_, init| init,1254)1255}12561257/// Helper function to manage interning of results to avoid duplicate1258/// initializers being inserted into the final list.1259///1260/// * `key` - the key being referenced which is used to deduplicate.1261/// * `map` - a closure to access the interning map on `Self`1262/// * `gen` - a closure to generate an intermediate value with `Self` from1263/// `K`. This is only used if `key` hasn't previously been seen. This1264/// closure can recursively intern other values possibly.1265/// * `init` - a closure to use the result of `gen` to create the final1266/// initializer now that the index `V` of the runtime item is known.1267///1268/// This is used by all the other interning methods above to lazily append1269/// initializers on-demand and avoid pushing more than one initializer at a1270/// time.1271fn intern<K, V, T>(1272&mut self,1273key: K,1274map: impl Fn(&mut Self) -> &mut HashMap<K, V>,1275generate: impl FnOnce(&mut Self, K) -> T,1276init: impl FnOnce(V, T) -> GlobalInitializer,1277) -> V1278where1279K: Hash + Eq + Copy,1280V: EntityRef,1281{1282self.intern_(key, map, generate, |me, key, val| {1283me.initializers.push(init(key, val));1284})1285}12861287fn intern_no_init<K, V, T>(1288&mut self,1289key: K,1290map: impl Fn(&mut Self) -> &mut HashMap<K, V>,1291generate: impl FnOnce(&mut Self, K) -> T,1292) -> V1293where1294K: Hash + Eq + Copy,1295V: EntityRef,1296{1297self.intern_(key, map, generate, |_me, _key, _val| {})1298}12991300fn intern_<K, V, T>(1301&mut self,1302key: K,1303map: impl Fn(&mut Self) -> &mut HashMap<K, V>,1304generate: impl FnOnce(&mut Self, K) -> T,1305init: impl FnOnce(&mut Self, V, T),1306) -> V1307where1308K: Hash + Eq + Copy,1309V: EntityRef,1310{1311if let Some(val) = map(self).get(&key) {1312return *val;1313}1314let tmp = generate(self, key);1315let index = V::new(map(self).len());1316init(self, index, tmp);1317let prev = map(self).insert(key, index);1318assert!(prev.is_none());1319index1320}1321}132213231324