Path: blob/main/crates/environ/src/component/dfg.rs
1692 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::prelude::*;31use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType};32use anyhow::Result;33use indexmap::IndexMap;34use info::LinearMemoryOptions;35use std::collections::HashMap;36use std::hash::Hash;37use std::ops::Index;38use wasmparser::component_types::ComponentCoreModuleTypeId;3940/// High-level representation of a component as a "data-flow graph".41#[derive(Default)]42pub struct ComponentDfg {43/// Same as `Component::import_types`44pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,4546/// Same as `Component::imports`47pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,4849/// Same as `Component::exports`50pub exports: IndexMap<String, Export>,5152/// All trampolines and their type signature which will need to get53/// compiled by Cranelift.54pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,5556/// Know reallocation functions which are used by `lowerings` (e.g. will be57/// used by the host)58pub reallocs: Intern<ReallocId, CoreDef>,5960/// Same as `reallocs`, but for async-lifted functions.61pub callbacks: Intern<CallbackId, CoreDef>,6263/// Same as `reallocs`, but for post-return.64pub post_returns: Intern<PostReturnId, CoreDef>,6566/// Same as `reallocs`, but for post-return.67pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,6869/// Metadata about identified fused adapters.70///71/// Note that this list is required to be populated in-order where the72/// "left" adapters cannot depend on "right" adapters. Currently this falls73/// out of the inlining pass of translation.74pub adapters: Intern<AdapterId, Adapter>,7576/// Metadata about all known core wasm instances created.77///78/// This is mostly an ordered list and is not deduplicated based on contents79/// unlike the items above. Creation of an `Instance` is side-effectful and80/// all instances here are always required to be created. These are81/// considered "roots" in dataflow.82pub instances: PrimaryMap<InstanceId, Instance>,8384/// Number of component instances that were created during the inlining85/// phase (this is not edited after creation).86pub num_runtime_component_instances: u32,8788/// Known adapter modules and how they are instantiated.89///90/// This map is not filled in on the initial creation of a `ComponentDfg`.91/// Instead these modules are filled in by the `inline::adapt` phase where92/// adapter modules are identified and filled in here.93///94/// The payload here is the static module index representing the core wasm95/// adapter module that was generated as well as the arguments to the96/// instantiation of the adapter module.97pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,9899/// Metadata about where adapters can be found within their respective100/// adapter modules.101///102/// Like `adapter_modules` this is not filled on the initial creation of103/// `ComponentDfg` but rather is created alongside `adapter_modules` during104/// the `inline::adapt` phase of translation.105///106/// The values here are the module that the adapter is present within along107/// as the core wasm index of the export corresponding to the lowered108/// version of the adapter.109pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,110111/// Defined resources in this component sorted by index with metadata about112/// each resource.113///114/// Note that each index here is a unique resource, and that may mean it was115/// the same component instantiated twice for example.116pub resources: PrimaryMap<DefinedResourceIndex, Resource>,117118/// Metadata about all imported resources into this component. This records119/// both how many imported resources there are (the size of this map) along120/// with what the corresponding runtime import is.121pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,122123/// The total number of future tables that will be used by this component.124pub num_future_tables: usize,125126/// The total number of stream tables that will be used by this component.127pub num_stream_tables: usize,128129/// The total number of error-context tables that will be used by this130/// component.131pub num_error_context_tables: usize,132133/// An ordered list of side effects induced by instantiating this component.134///135/// Currently all side effects are either instantiating core wasm modules or136/// declaring a resource. These side effects affect the dataflow processing137/// of this component by idnicating what order operations should be138/// performed during instantiation.139pub side_effects: Vec<SideEffect>,140141/// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by142/// this component.143pub options: Intern<OptionsId, CanonicalOptions>,144}145146/// Possible side effects that are possible with instantiating this component.147pub enum SideEffect {148/// A core wasm instance was created.149///150/// Instantiation is side-effectful due to the presence of constructs such151/// as traps and the core wasm `start` function which may call component152/// imports. Instantiation order from the original component must be done in153/// the same order.154Instance(InstanceId),155156/// A resource was declared in this component.157///158/// This is a bit less side-effectful than instantiation but this serves as159/// the order in which resources are initialized in a component with their160/// destructors. Destructors are loaded from core wasm instances (or161/// lowerings) which are produced by prior side-effectful operations.162Resource(DefinedResourceIndex),163}164165/// A sound approximation of a particular module's set of instantiations.166///167/// This type forms a simple lattice that we can use in static analyses that in168/// turn let us specialize a module's compilation to exactly the imports it is169/// given.170#[derive(Clone, Copy, Default)]171pub enum AbstractInstantiations<'a> {172/// The associated module is instantiated many times.173Many,174175/// The module is instantiated exactly once, with the given definitions as176/// arguments to that instantiation.177One(&'a [info::CoreDef]),178179/// The module is never instantiated.180#[default]181None,182}183184impl AbstractInstantiations<'_> {185/// Join two facts about a particular module's instantiation together.186///187/// This is the least-upper-bound operation on the lattice.188pub fn join(&mut self, other: Self) {189*self = match (*self, other) {190(Self::Many, _) | (_, Self::Many) => Self::Many,191(Self::One(a), Self::One(b)) if a == b => Self::One(a),192(Self::One(_), Self::One(_)) => Self::Many,193(Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a),194(Self::None, Self::None) => Self::None,195}196}197}198199macro_rules! id {200($(pub struct $name:ident(u32);)*) => ($(201#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]202#[expect(missing_docs, reason = "tedious to document")]203pub struct $name(u32);204cranelift_entity::entity_impl!($name);205)*)206}207208id! {209pub struct InstanceId(u32);210pub struct MemoryId(u32);211pub struct TableId(u32);212pub struct ReallocId(u32);213pub struct CallbackId(u32);214pub struct AdapterId(u32);215pub struct PostReturnId(u32);216pub struct AdapterModuleId(u32);217pub struct OptionsId(u32);218}219220/// Same as `info::InstantiateModule`221#[expect(missing_docs, reason = "tedious to document variants")]222pub enum Instance {223Static(StaticModuleIndex, Box<[CoreDef]>),224Import(225RuntimeImportIndex,226IndexMap<String, IndexMap<String, CoreDef>>,227),228}229230/// Same as `info::Export`231#[expect(missing_docs, reason = "tedious to document variants")]232pub enum Export {233LiftedFunction {234ty: TypeFuncIndex,235func: CoreDef,236options: OptionsId,237},238ModuleStatic {239ty: ComponentCoreModuleTypeId,240index: StaticModuleIndex,241},242ModuleImport {243ty: TypeModuleIndex,244import: RuntimeImportIndex,245},246Instance {247ty: TypeComponentInstanceIndex,248exports: IndexMap<String, Export>,249},250Type(TypeDef),251}252253/// Same as `info::CoreDef`, except has an extra `Adapter` variant.254#[derive(Debug, Clone, Hash, Eq, PartialEq)]255#[expect(missing_docs, reason = "tedious to document variants")]256pub enum CoreDef {257Export(CoreExport<EntityIndex>),258InstanceFlags(RuntimeComponentInstanceIndex),259Trampoline(TrampolineIndex),260/// This is a special variant not present in `info::CoreDef` which261/// represents that this definition refers to a fused adapter function. This262/// adapter is fully processed after the initial translation and263/// identification of adapters.264///265/// During translation into `info::CoreDef` this variant is erased and266/// replaced by `info::CoreDef::Export` since adapters are always267/// represented as the exports of a core wasm instance.268Adapter(AdapterId),269}270271impl<T> From<CoreExport<T>> for CoreDef272where273EntityIndex: From<T>,274{275fn from(export: CoreExport<T>) -> CoreDef {276CoreDef::Export(export.map_index(|i| i.into()))277}278}279280/// Same as `info::CoreExport`281#[derive(Debug, Clone, Hash, Eq, PartialEq)]282#[expect(missing_docs, reason = "self-describing fields")]283pub struct CoreExport<T> {284pub instance: InstanceId,285pub item: ExportItem<T>,286}287288impl<T> CoreExport<T> {289#[expect(missing_docs, reason = "self-describing function")]290pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {291CoreExport {292instance: self.instance,293item: match self.item {294ExportItem::Index(i) => ExportItem::Index(f(i)),295ExportItem::Name(s) => ExportItem::Name(s),296},297}298}299}300301/// Same as `info::Trampoline`302#[derive(Clone, PartialEq, Eq, Hash)]303#[expect(missing_docs, reason = "self-describing fields")]304pub enum Trampoline {305LowerImport {306import: RuntimeImportIndex,307options: OptionsId,308lower_ty: TypeFuncIndex,309},310Transcoder {311op: Transcode,312from: MemoryId,313from64: bool,314to: MemoryId,315to64: bool,316},317AlwaysTrap,318ResourceNew(TypeResourceTableIndex),319ResourceRep(TypeResourceTableIndex),320ResourceDrop(TypeResourceTableIndex),321BackpressureSet {322instance: RuntimeComponentInstanceIndex,323},324TaskReturn {325results: TypeTupleIndex,326options: OptionsId,327},328TaskCancel {329instance: RuntimeComponentInstanceIndex,330},331WaitableSetNew {332instance: RuntimeComponentInstanceIndex,333},334WaitableSetWait {335options: OptionsId,336},337WaitableSetPoll {338options: OptionsId,339},340WaitableSetDrop {341instance: RuntimeComponentInstanceIndex,342},343WaitableJoin {344instance: RuntimeComponentInstanceIndex,345},346Yield {347async_: bool,348},349SubtaskDrop {350instance: RuntimeComponentInstanceIndex,351},352SubtaskCancel {353instance: RuntimeComponentInstanceIndex,354async_: bool,355},356StreamNew {357ty: TypeStreamTableIndex,358},359StreamRead {360ty: TypeStreamTableIndex,361options: OptionsId,362},363StreamWrite {364ty: TypeStreamTableIndex,365options: OptionsId,366},367StreamCancelRead {368ty: TypeStreamTableIndex,369async_: bool,370},371StreamCancelWrite {372ty: TypeStreamTableIndex,373async_: bool,374},375StreamDropReadable {376ty: TypeStreamTableIndex,377},378StreamDropWritable {379ty: TypeStreamTableIndex,380},381FutureNew {382ty: TypeFutureTableIndex,383},384FutureRead {385ty: TypeFutureTableIndex,386options: OptionsId,387},388FutureWrite {389ty: TypeFutureTableIndex,390options: OptionsId,391},392FutureCancelRead {393ty: TypeFutureTableIndex,394async_: bool,395},396FutureCancelWrite {397ty: TypeFutureTableIndex,398async_: bool,399},400FutureDropReadable {401ty: TypeFutureTableIndex,402},403FutureDropWritable {404ty: TypeFutureTableIndex,405},406ErrorContextNew {407ty: TypeComponentLocalErrorContextTableIndex,408options: OptionsId,409},410ErrorContextDebugMessage {411ty: TypeComponentLocalErrorContextTableIndex,412options: OptionsId,413},414ErrorContextDrop {415ty: TypeComponentLocalErrorContextTableIndex,416},417ResourceTransferOwn,418ResourceTransferBorrow,419ResourceEnterCall,420ResourceExitCall,421PrepareCall {422memory: Option<MemoryId>,423},424SyncStartCall {425callback: Option<CallbackId>,426},427AsyncStartCall {428callback: Option<CallbackId>,429post_return: Option<PostReturnId>,430},431FutureTransfer,432StreamTransfer,433ErrorContextTransfer,434ContextGet(u32),435ContextSet(u32),436}437438#[derive(Copy, Clone, Hash, Eq, PartialEq)]439#[expect(missing_docs, reason = "self-describing fields")]440pub struct FutureInfo {441pub instance: RuntimeComponentInstanceIndex,442pub payload_type: Option<InterfaceType>,443}444445#[derive(Copy, Clone, Hash, Eq, PartialEq)]446#[expect(missing_docs, reason = "self-describing fields")]447pub struct StreamInfo {448pub instance: RuntimeComponentInstanceIndex,449pub payload_type: InterfaceType,450}451452/// Same as `info::CanonicalOptionsDataModel`.453#[derive(Clone, Hash, Eq, PartialEq)]454#[expect(missing_docs, reason = "self-describing fields")]455pub enum CanonicalOptionsDataModel {456Gc {},457LinearMemory {458memory: Option<MemoryId>,459realloc: Option<ReallocId>,460},461}462463/// Same as `info::CanonicalOptions`464#[derive(Clone, Hash, Eq, PartialEq)]465#[expect(missing_docs, reason = "self-describing fields")]466pub struct CanonicalOptions {467pub instance: RuntimeComponentInstanceIndex,468pub string_encoding: StringEncoding,469pub callback: Option<CallbackId>,470pub post_return: Option<PostReturnId>,471pub async_: bool,472pub core_type: ModuleInternedTypeIndex,473pub data_model: CanonicalOptionsDataModel,474}475476/// Same as `info::Resource`477#[expect(missing_docs, reason = "self-describing fields")]478pub struct Resource {479pub rep: WasmValType,480pub dtor: Option<CoreDef>,481pub instance: RuntimeComponentInstanceIndex,482}483484/// A helper structure to "intern" and deduplicate values of type `V` with an485/// identifying key `K`.486///487/// Note that this can also be used where `V` can't be intern'd to represent a488/// flat list of items.489pub struct Intern<K: EntityRef, V> {490intern_map: HashMap<V, K>,491key_map: PrimaryMap<K, V>,492}493494impl<K, V> Intern<K, V>495where496K: EntityRef,497{498/// Inserts the `value` specified into this set, returning either a fresh499/// key `K` if this value hasn't been seen before or otherwise returning the500/// previous `K` used to represent value.501///502/// Note that this should only be used for component model items where the503/// creation of `value` is not side-effectful.504pub fn push(&mut self, value: V) -> K505where506V: Hash + Eq + Clone,507{508*self509.intern_map510.entry(value.clone())511.or_insert_with(|| self.key_map.push(value))512}513514/// Returns an iterator of all the values contained within this set.515pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {516self.key_map.iter()517}518}519520impl<K: EntityRef, V> Index<K> for Intern<K, V> {521type Output = V;522fn index(&self, key: K) -> &V {523&self.key_map[key]524}525}526527impl<K: EntityRef, V> Default for Intern<K, V> {528fn default() -> Intern<K, V> {529Intern {530intern_map: HashMap::new(),531key_map: PrimaryMap::new(),532}533}534}535536impl ComponentDfg {537/// Consumes the intermediate `ComponentDfg` to produce a final `Component`538/// with a linear initializer list.539pub fn finish(540self,541wasmtime_types: &mut ComponentTypesBuilder,542wasmparser_types: wasmparser::types::TypesRef<'_>,543) -> Result<ComponentTranslation> {544let mut linearize = LinearizeDfg {545dfg: &self,546initializers: Vec::new(),547runtime_memories: Default::default(),548runtime_tables: Default::default(),549runtime_post_return: Default::default(),550runtime_reallocs: Default::default(),551runtime_callbacks: Default::default(),552runtime_instances: Default::default(),553num_lowerings: 0,554trampolines: Default::default(),555trampoline_defs: Default::default(),556trampoline_map: Default::default(),557options: Default::default(),558options_map: Default::default(),559};560561// Handle all side effects of this component in the order that they're562// defined. This will, for example, process all instantiations necessary563// of core wasm modules.564for item in linearize.dfg.side_effects.iter() {565linearize.side_effect(item);566}567568// Next the exports of the instance are handled which will likely end up569// creating some lowered imports, perhaps some saved modules, etc.570let mut export_items = PrimaryMap::new();571let mut exports = NameMap::default();572for (name, export) in self.exports.iter() {573let export =574linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;575exports.insert(name, &mut NameMapNoIntern, false, export)?;576}577578// With all those pieces done the results of the dataflow-based579// linearization are recorded into the `Component`. The number of580// runtime values used for each index space is used from the `linearize`581// result.582Ok(ComponentTranslation {583trampolines: linearize.trampoline_defs,584component: Component {585exports,586export_items,587initializers: linearize.initializers,588trampolines: linearize.trampolines,589num_lowerings: linearize.num_lowerings,590options: linearize.options,591592num_runtime_memories: linearize.runtime_memories.len() as u32,593num_runtime_tables: linearize.runtime_tables.len() as u32,594num_runtime_post_returns: linearize.runtime_post_return.len() as u32,595num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,596num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,597num_runtime_instances: linearize.runtime_instances.len() as u32,598imports: self.imports,599import_types: self.import_types,600num_runtime_component_instances: self.num_runtime_component_instances,601num_future_tables: self.num_future_tables,602num_stream_tables: self.num_stream_tables,603num_error_context_tables: self.num_error_context_tables,604num_resources: (self.resources.len() + self.imported_resources.len()) as u32,605imported_resources: self.imported_resources,606defined_resource_instances: self607.resources608.iter()609.map(|(_, r)| r.instance)610.collect(),611},612})613}614615/// Converts the provided defined index into a normal index, adding in the616/// number of imported resources.617pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {618ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))619}620}621622struct LinearizeDfg<'a> {623dfg: &'a ComponentDfg,624initializers: Vec<GlobalInitializer>,625trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,626trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,627options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,628trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,629runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,630runtime_tables: HashMap<TableId, RuntimeTableIndex>,631runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,632runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,633runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,634runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,635options_map: HashMap<OptionsId, OptionsIndex>,636num_lowerings: u32,637}638639#[derive(Copy, Clone, Hash, Eq, PartialEq)]640enum RuntimeInstance {641Normal(InstanceId),642Adapter(AdapterModuleId),643}644645impl LinearizeDfg<'_> {646fn side_effect(&mut self, effect: &SideEffect) {647match effect {648SideEffect::Instance(i) => {649self.instantiate(*i, &self.dfg.instances[*i]);650}651SideEffect::Resource(i) => {652self.resource(*i, &self.dfg.resources[*i]);653}654}655}656657fn instantiate(&mut self, instance: InstanceId, args: &Instance) {658log::trace!("creating instance {instance:?}");659let instantiation = match args {660Instance::Static(index, args) => InstantiateModule::Static(661*index,662args.iter().map(|def| self.core_def(def)).collect(),663),664Instance::Import(index, args) => InstantiateModule::Import(665*index,666args.iter()667.map(|(module, values)| {668let values = values669.iter()670.map(|(name, def)| (name.clone(), self.core_def(def)))671.collect();672(module.clone(), values)673})674.collect(),675),676};677let index = RuntimeInstanceIndex::new(self.runtime_instances.len());678self.initializers679.push(GlobalInitializer::InstantiateModule(instantiation));680let prev = self681.runtime_instances682.insert(RuntimeInstance::Normal(instance), index);683assert!(prev.is_none());684}685686fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {687let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));688self.initializers689.push(GlobalInitializer::Resource(info::Resource {690dtor,691index,692rep: resource.rep,693instance: resource.instance,694}));695}696697fn export(698&mut self,699export: &Export,700items: &mut PrimaryMap<ExportIndex, info::Export>,701wasmtime_types: &mut ComponentTypesBuilder,702wasmparser_types: wasmparser::types::TypesRef<'_>,703) -> Result<ExportIndex> {704let item = match export {705Export::LiftedFunction { ty, func, options } => {706let func = self.core_def(func);707let options = self.options(*options);708info::Export::LiftedFunction {709ty: *ty,710func,711options,712}713}714Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {715ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,716index: *index,717},718Export::ModuleImport { ty, import } => info::Export::ModuleImport {719ty: *ty,720import: *import,721},722Export::Instance { ty, exports } => info::Export::Instance {723ty: *ty,724exports: {725let mut map = NameMap::default();726for (name, export) in exports {727let export =728self.export(export, items, wasmtime_types, wasmparser_types)?;729map.insert(name, &mut NameMapNoIntern, false, export)?;730}731map732},733},734Export::Type(def) => info::Export::Type(*def),735};736Ok(items.push(item))737}738739fn options(&mut self, options: OptionsId) -> OptionsIndex {740self.intern_no_init(741options,742|me| &mut me.options_map,743|me, options| me.convert_options(options),744)745}746747fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {748let options = &self.dfg.options[options];749let data_model = match options.data_model {750CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},751CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {752info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {753memory: memory.map(|mem| self.runtime_memory(mem)),754realloc: realloc.map(|mem| self.runtime_realloc(mem)),755})756}757};758let callback = options.callback.map(|mem| self.runtime_callback(mem));759let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));760let options = info::CanonicalOptions {761instance: options.instance,762string_encoding: options.string_encoding,763callback,764post_return,765async_: options.async_,766core_type: options.core_type,767data_model,768};769self.options.push(options)770}771772fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {773self.intern(774mem,775|me| &mut me.runtime_memories,776|me, mem| me.core_export(&me.dfg.memories[mem]),777|index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),778)779}780781fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {782self.intern(783realloc,784|me| &mut me.runtime_reallocs,785|me, realloc| me.core_def(&me.dfg.reallocs[realloc]),786|index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),787)788}789790fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {791self.intern(792callback,793|me| &mut me.runtime_callbacks,794|me, callback| me.core_def(&me.dfg.callbacks[callback]),795|index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),796)797}798799fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {800self.intern(801post_return,802|me| &mut me.runtime_post_return,803|me, post_return| me.core_def(&me.dfg.post_returns[post_return]),804|index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),805)806}807808fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {809match def {810CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),811CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),812CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),813CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),814}815}816817fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {818if let Some(idx) = self.trampoline_map.get(&index) {819return *idx;820}821let (signature, trampoline) = &self.dfg.trampolines[index];822let trampoline = match trampoline {823Trampoline::LowerImport {824import,825options,826lower_ty,827} => {828let index = LoweredIndex::from_u32(self.num_lowerings);829self.num_lowerings += 1;830self.initializers.push(GlobalInitializer::LowerImport {831index,832import: *import,833});834info::Trampoline::LowerImport {835index,836options: self.options(*options),837lower_ty: *lower_ty,838}839}840Trampoline::Transcoder {841op,842from,843from64,844to,845to64,846} => info::Trampoline::Transcoder {847op: *op,848from: self.runtime_memory(*from),849from64: *from64,850to: self.runtime_memory(*to),851to64: *to64,852},853Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,854Trampoline::ResourceNew(ty) => info::Trampoline::ResourceNew(*ty),855Trampoline::ResourceDrop(ty) => info::Trampoline::ResourceDrop(*ty),856Trampoline::ResourceRep(ty) => info::Trampoline::ResourceRep(*ty),857Trampoline::BackpressureSet { instance } => info::Trampoline::BackpressureSet {858instance: *instance,859},860Trampoline::TaskReturn { results, options } => info::Trampoline::TaskReturn {861results: *results,862options: self.options(*options),863},864Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {865instance: *instance,866},867Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {868instance: *instance,869},870Trampoline::WaitableSetWait { options } => info::Trampoline::WaitableSetWait {871options: self.options(*options),872},873Trampoline::WaitableSetPoll { options } => info::Trampoline::WaitableSetPoll {874options: self.options(*options),875},876Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {877instance: *instance,878},879Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {880instance: *instance,881},882Trampoline::Yield { async_ } => info::Trampoline::Yield { async_: *async_ },883Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {884instance: *instance,885},886Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {887instance: *instance,888async_: *async_,889},890Trampoline::StreamNew { ty } => info::Trampoline::StreamNew { ty: *ty },891Trampoline::StreamRead { ty, options } => info::Trampoline::StreamRead {892ty: *ty,893options: self.options(*options),894},895Trampoline::StreamWrite { ty, options } => info::Trampoline::StreamWrite {896ty: *ty,897options: self.options(*options),898},899Trampoline::StreamCancelRead { ty, async_ } => info::Trampoline::StreamCancelRead {900ty: *ty,901async_: *async_,902},903Trampoline::StreamCancelWrite { ty, async_ } => info::Trampoline::StreamCancelWrite {904ty: *ty,905async_: *async_,906},907Trampoline::StreamDropReadable { ty } => {908info::Trampoline::StreamDropReadable { ty: *ty }909}910Trampoline::StreamDropWritable { ty } => {911info::Trampoline::StreamDropWritable { ty: *ty }912}913Trampoline::FutureNew { ty } => info::Trampoline::FutureNew { ty: *ty },914Trampoline::FutureRead { ty, options } => info::Trampoline::FutureRead {915ty: *ty,916options: self.options(*options),917},918Trampoline::FutureWrite { ty, options } => info::Trampoline::FutureWrite {919ty: *ty,920options: self.options(*options),921},922Trampoline::FutureCancelRead { ty, async_ } => info::Trampoline::FutureCancelRead {923ty: *ty,924async_: *async_,925},926Trampoline::FutureCancelWrite { ty, async_ } => info::Trampoline::FutureCancelWrite {927ty: *ty,928async_: *async_,929},930Trampoline::FutureDropReadable { ty } => {931info::Trampoline::FutureDropReadable { ty: *ty }932}933Trampoline::FutureDropWritable { ty } => {934info::Trampoline::FutureDropWritable { ty: *ty }935}936Trampoline::ErrorContextNew { ty, options } => info::Trampoline::ErrorContextNew {937ty: *ty,938options: self.options(*options),939},940Trampoline::ErrorContextDebugMessage { ty, options } => {941info::Trampoline::ErrorContextDebugMessage {942ty: *ty,943options: self.options(*options),944}945}946Trampoline::ErrorContextDrop { ty } => info::Trampoline::ErrorContextDrop { ty: *ty },947Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,948Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,949Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,950Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,951Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {952memory: memory.map(|v| self.runtime_memory(v)),953},954Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall {955callback: callback.map(|v| self.runtime_callback(v)),956},957Trampoline::AsyncStartCall {958callback,959post_return,960} => info::Trampoline::AsyncStartCall {961callback: callback.map(|v| self.runtime_callback(v)),962post_return: post_return.map(|v| self.runtime_post_return(v)),963},964Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,965Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,966Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,967Trampoline::ContextGet(i) => info::Trampoline::ContextGet(*i),968Trampoline::ContextSet(i) => info::Trampoline::ContextSet(*i),969};970let i1 = self.trampolines.push(*signature);971let i2 = self.trampoline_defs.push(trampoline);972assert_eq!(i1, i2);973self.trampoline_map.insert(index, i1);974i1975}976977fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>978where979T: Clone,980{981let instance = export.instance;982log::trace!("referencing export of {instance:?}");983info::CoreExport {984instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],985item: export.item.clone(),986}987}988989fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {990let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];991992// Instantiates the adapter module if it hasn't already been993// instantiated or otherwise returns the index that the module was994// already instantiated at.995let instance = self.adapter_module(adapter_module);996997// This adapter is always an export of the instance.998info::CoreExport {999instance,1000item: ExportItem::Index(entity_index),1001}1002}10031004fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {1005self.intern(1006RuntimeInstance::Adapter(adapter_module),1007|me| &mut me.runtime_instances,1008|me, _| {1009log::debug!("instantiating {adapter_module:?}");1010let (module_index, args) = &me.dfg.adapter_modules[adapter_module];1011let args = args.iter().map(|arg| me.core_def(arg)).collect();1012let instantiate = InstantiateModule::Static(*module_index, args);1013GlobalInitializer::InstantiateModule(instantiate)1014},1015|_, init| init,1016)1017}10181019/// Helper function to manage interning of results to avoid duplicate1020/// initializers being inserted into the final list.1021///1022/// * `key` - the key being referenced which is used to deduplicate.1023/// * `map` - a closure to access the interning map on `Self`1024/// * `gen` - a closure to generate an intermediate value with `Self` from1025/// `K`. This is only used if `key` hasn't previously been seen. This1026/// closure can recursively intern other values possibly.1027/// * `init` - a closure to use the result of `gen` to create the final1028/// initializer now that the index `V` of the runtime item is known.1029///1030/// This is used by all the other interning methods above to lazily append1031/// initializers on-demand and avoid pushing more than one initializer at a1032/// time.1033fn intern<K, V, T>(1034&mut self,1035key: K,1036map: impl Fn(&mut Self) -> &mut HashMap<K, V>,1037generate: impl FnOnce(&mut Self, K) -> T,1038init: impl FnOnce(V, T) -> GlobalInitializer,1039) -> V1040where1041K: Hash + Eq + Copy,1042V: EntityRef,1043{1044self.intern_(key, map, generate, |me, key, val| {1045me.initializers.push(init(key, val));1046})1047}10481049fn intern_no_init<K, V, T>(1050&mut self,1051key: K,1052map: impl Fn(&mut Self) -> &mut HashMap<K, V>,1053generate: impl FnOnce(&mut Self, K) -> T,1054) -> V1055where1056K: Hash + Eq + Copy,1057V: EntityRef,1058{1059self.intern_(key, map, generate, |_me, _key, _val| {})1060}10611062fn intern_<K, V, T>(1063&mut self,1064key: K,1065map: impl Fn(&mut Self) -> &mut HashMap<K, V>,1066generate: impl FnOnce(&mut Self, K) -> T,1067init: impl FnOnce(&mut Self, V, T),1068) -> V1069where1070K: Hash + Eq + Copy,1071V: EntityRef,1072{1073if let Some(val) = map(self).get(&key) {1074return *val;1075}1076let tmp = generate(self, key);1077let index = V::new(map(self).len());1078init(self, index, tmp);1079let prev = map(self).insert(key, index);1080assert!(prev.is_none());1081index1082}1083}108410851086