wasmtime_environ/component/
dfg.rs

1//! A dataflow-graph-like intermediate representation of a component
2//!
3//! This module contains `ComponentDfg` which is an intermediate step towards
4//! becoming a full-fledged `Component`. The main purpose for the existence of
5//! this representation of a component is to track dataflow between various
6//! items within a component and support edits to them after the initial inlined
7//! translation of a component.
8//!
9//! Currently fused adapters are represented with a core WebAssembly module
10//! which gets "injected" into the final component as-if the component already
11//! bundled it. In doing so the adapter modules need to be partitioned and
12//! inserted into the final sequence of modules to instantiate. While this is
13//! possible to do with a flat `GlobalInitializer` list it gets unwieldy really
14//! quickly especially when other translation features are added.
15//!
16//! This module is largely a duplicate of the `component::info` module in this
17//! crate. The hierarchy here uses `*Id` types instead of `*Index` types to
18//! represent that they don't have any necessary implicit ordering. Additionally
19//! nothing is kept in an ordered list and instead this is worked with in a
20//! general dataflow fashion where dependencies are walked during processing.
21//!
22//! The `ComponentDfg::finish` method will convert the dataflow graph to a
23//! linearized `GlobalInitializer` list which is intended to not be edited after
24//! it's created.
25//!
26//! The `ComponentDfg` is created as part of the `component::inline` phase of
27//! translation where the dataflow performed there allows identification of
28//! fused adapters, what arguments make their way to core wasm modules, etc.
29
30use crate::component::*;
31use crate::prelude::*;
32use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType};
33use anyhow::Result;
34use cranelift_entity::packed_option::PackedOption;
35use indexmap::IndexMap;
36use info::LinearMemoryOptions;
37use std::collections::HashMap;
38use std::hash::Hash;
39use std::ops::Index;
40use wasmparser::component_types::ComponentCoreModuleTypeId;
41
42/// High-level representation of a component as a "data-flow graph".
43#[derive(Default)]
44pub struct ComponentDfg {
45    /// Same as `Component::import_types`
46    pub import_types: PrimaryMap<ImportIndex, (String, TypeDef)>,
47
48    /// Same as `Component::imports`
49    pub imports: PrimaryMap<RuntimeImportIndex, (ImportIndex, Vec<String>)>,
50
51    /// Same as `Component::exports`
52    pub exports: IndexMap<String, Export>,
53
54    /// All trampolines and their type signature which will need to get
55    /// compiled by Cranelift.
56    pub trampolines: Intern<TrampolineIndex, (ModuleInternedTypeIndex, Trampoline)>,
57
58    /// A map from `UnsafeIntrinsic::index()` to that intrinsic's
59    /// module-interned type.
60    pub unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],
61
62    /// Know reallocation functions which are used by `lowerings` (e.g. will be
63    /// used by the host)
64    pub reallocs: Intern<ReallocId, CoreDef>,
65
66    /// Same as `reallocs`, but for async-lifted functions.
67    pub callbacks: Intern<CallbackId, CoreDef>,
68
69    /// Same as `reallocs`, but for post-return.
70    pub post_returns: Intern<PostReturnId, CoreDef>,
71
72    /// Same as `reallocs`, but for memories.
73    pub memories: Intern<MemoryId, CoreExport<MemoryIndex>>,
74
75    /// Same as `reallocs`, but for tables.
76    pub tables: Intern<TableId, CoreExport<TableIndex>>,
77
78    /// Metadata about identified fused adapters.
79    ///
80    /// Note that this list is required to be populated in-order where the
81    /// "left" adapters cannot depend on "right" adapters. Currently this falls
82    /// out of the inlining pass of translation.
83    pub adapters: Intern<AdapterId, Adapter>,
84
85    /// Metadata about all known core wasm instances created.
86    ///
87    /// This is mostly an ordered list and is not deduplicated based on contents
88    /// unlike the items above. Creation of an `Instance` is side-effectful and
89    /// all instances here are always required to be created. These are
90    /// considered "roots" in dataflow.
91    pub instances: PrimaryMap<InstanceId, Instance>,
92
93    /// Number of component instances that were created during the inlining
94    /// phase (this is not edited after creation).
95    pub num_runtime_component_instances: u32,
96
97    /// Known adapter modules and how they are instantiated.
98    ///
99    /// This map is not filled in on the initial creation of a `ComponentDfg`.
100    /// Instead these modules are filled in by the `inline::adapt` phase where
101    /// adapter modules are identified and filled in here.
102    ///
103    /// The payload here is the static module index representing the core wasm
104    /// adapter module that was generated as well as the arguments to the
105    /// instantiation of the adapter module.
106    pub adapter_modules: PrimaryMap<AdapterModuleId, (StaticModuleIndex, Vec<CoreDef>)>,
107
108    /// Metadata about where adapters can be found within their respective
109    /// adapter modules.
110    ///
111    /// Like `adapter_modules` this is not filled on the initial creation of
112    /// `ComponentDfg` but rather is created alongside `adapter_modules` during
113    /// the `inline::adapt` phase of translation.
114    ///
115    /// The values here are the module that the adapter is present within along
116    /// as the core wasm index of the export corresponding to the lowered
117    /// version of the adapter.
118    pub adapter_partitionings: PrimaryMap<AdapterId, (AdapterModuleId, EntityIndex)>,
119
120    /// Defined resources in this component sorted by index with metadata about
121    /// each resource.
122    ///
123    /// Note that each index here is a unique resource, and that may mean it was
124    /// the same component instantiated twice for example.
125    pub resources: PrimaryMap<DefinedResourceIndex, Resource>,
126
127    /// Metadata about all imported resources into this component. This records
128    /// both how many imported resources there are (the size of this map) along
129    /// with what the corresponding runtime import is.
130    pub imported_resources: PrimaryMap<ResourceIndex, RuntimeImportIndex>,
131
132    /// The total number of future tables that will be used by this component.
133    pub num_future_tables: usize,
134
135    /// The total number of stream tables that will be used by this component.
136    pub num_stream_tables: usize,
137
138    /// The total number of error-context tables that will be used by this
139    /// component.
140    pub num_error_context_tables: usize,
141
142    /// An ordered list of side effects induced by instantiating this component.
143    ///
144    /// Currently all side effects are either instantiating core wasm modules or
145    /// declaring a resource. These side effects affect the dataflow processing
146    /// of this component by idnicating what order operations should be
147    /// performed during instantiation.
148    pub side_effects: Vec<SideEffect>,
149
150    /// Interned map of id-to-`CanonicalOptions`, or all sets-of-options used by
151    /// this component.
152    pub options: Intern<OptionsId, CanonicalOptions>,
153}
154
155/// Possible side effects that are possible with instantiating this component.
156pub enum SideEffect {
157    /// A core wasm instance was created.
158    ///
159    /// Instantiation is side-effectful due to the presence of constructs such
160    /// as traps and the core wasm `start` function which may call component
161    /// imports. Instantiation order from the original component must be done in
162    /// the same order.
163    Instance(InstanceId),
164
165    /// A resource was declared in this component.
166    ///
167    /// This is a bit less side-effectful than instantiation but this serves as
168    /// the order in which resources are initialized in a component with their
169    /// destructors. Destructors are loaded from core wasm instances (or
170    /// lowerings) which are produced by prior side-effectful operations.
171    Resource(DefinedResourceIndex),
172}
173
174/// A sound approximation of a particular module's set of instantiations.
175///
176/// This type forms a simple lattice that we can use in static analyses that in
177/// turn let us specialize a module's compilation to exactly the imports it is
178/// given.
179#[derive(Clone, Copy, Default)]
180pub enum AbstractInstantiations<'a> {
181    /// The associated module is instantiated many times.
182    Many,
183
184    /// The module is instantiated exactly once, with the given definitions as
185    /// arguments to that instantiation.
186    One(&'a [info::CoreDef]),
187
188    /// The module is never instantiated.
189    #[default]
190    None,
191}
192
193impl AbstractInstantiations<'_> {
194    /// Join two facts about a particular module's instantiation together.
195    ///
196    /// This is the least-upper-bound operation on the lattice.
197    pub fn join(&mut self, other: Self) {
198        *self = match (*self, other) {
199            (Self::Many, _) | (_, Self::Many) => Self::Many,
200            (Self::One(a), Self::One(b)) if a == b => Self::One(a),
201            (Self::One(_), Self::One(_)) => Self::Many,
202            (Self::One(a), Self::None) | (Self::None, Self::One(a)) => Self::One(a),
203            (Self::None, Self::None) => Self::None,
204        }
205    }
206}
207
208macro_rules! id {
209    ($(pub struct $name:ident(u32);)*) => ($(
210        #[derive(Debug, Copy, Clone, Hash, Eq, PartialEq)]
211        #[expect(missing_docs, reason = "tedious to document")]
212        pub struct $name(u32);
213        cranelift_entity::entity_impl!($name);
214    )*)
215}
216
217id! {
218    pub struct InstanceId(u32);
219    pub struct MemoryId(u32);
220    pub struct TableId(u32);
221    pub struct ReallocId(u32);
222    pub struct CallbackId(u32);
223    pub struct AdapterId(u32);
224    pub struct PostReturnId(u32);
225    pub struct AdapterModuleId(u32);
226    pub struct OptionsId(u32);
227}
228
229/// Same as `info::InstantiateModule`
230#[expect(missing_docs, reason = "tedious to document variants")]
231pub enum Instance {
232    Static(StaticModuleIndex, Box<[CoreDef]>),
233    Import(
234        RuntimeImportIndex,
235        IndexMap<String, IndexMap<String, CoreDef>>,
236    ),
237}
238
239/// Same as `info::Export`
240#[expect(missing_docs, reason = "tedious to document variants")]
241pub enum Export {
242    LiftedFunction {
243        ty: TypeFuncIndex,
244        func: CoreDef,
245        options: OptionsId,
246    },
247    ModuleStatic {
248        ty: ComponentCoreModuleTypeId,
249        index: StaticModuleIndex,
250    },
251    ModuleImport {
252        ty: TypeModuleIndex,
253        import: RuntimeImportIndex,
254    },
255    Instance {
256        ty: TypeComponentInstanceIndex,
257        exports: IndexMap<String, Export>,
258    },
259    Type(TypeDef),
260}
261
262/// Same as `info::CoreDef`, except has an extra `Adapter` variant.
263#[derive(Debug, Clone, Hash, Eq, PartialEq)]
264#[expect(missing_docs, reason = "tedious to document variants")]
265pub enum CoreDef {
266    Export(CoreExport<EntityIndex>),
267    InstanceFlags(RuntimeComponentInstanceIndex),
268    Trampoline(TrampolineIndex),
269    UnsafeIntrinsic(ModuleInternedTypeIndex, UnsafeIntrinsic),
270
271    /// This is a special variant not present in `info::CoreDef` which
272    /// represents that this definition refers to a fused adapter function. This
273    /// adapter is fully processed after the initial translation and
274    /// identification of adapters.
275    ///
276    /// During translation into `info::CoreDef` this variant is erased and
277    /// replaced by `info::CoreDef::Export` since adapters are always
278    /// represented as the exports of a core wasm instance.
279    Adapter(AdapterId),
280}
281
282impl<T> From<CoreExport<T>> for CoreDef
283where
284    EntityIndex: From<T>,
285{
286    fn from(export: CoreExport<T>) -> CoreDef {
287        CoreDef::Export(export.map_index(|i| i.into()))
288    }
289}
290
291/// Same as `info::CoreExport`
292#[derive(Debug, Clone, Hash, Eq, PartialEq)]
293#[expect(missing_docs, reason = "self-describing fields")]
294pub struct CoreExport<T> {
295    pub instance: InstanceId,
296    pub item: ExportItem<T>,
297}
298
299impl<T> CoreExport<T> {
300    #[expect(missing_docs, reason = "self-describing function")]
301    pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
302        CoreExport {
303            instance: self.instance,
304            item: match self.item {
305                ExportItem::Index(i) => ExportItem::Index(f(i)),
306                ExportItem::Name(s) => ExportItem::Name(s),
307            },
308        }
309    }
310}
311
312/// Same as `info::Trampoline`
313#[derive(Clone, PartialEq, Eq, Hash)]
314#[expect(missing_docs, reason = "self-describing fields")]
315pub enum Trampoline {
316    LowerImport {
317        import: RuntimeImportIndex,
318        options: OptionsId,
319        lower_ty: TypeFuncIndex,
320    },
321    Transcoder {
322        op: Transcode,
323        from: MemoryId,
324        from64: bool,
325        to: MemoryId,
326        to64: bool,
327    },
328    AlwaysTrap,
329    ResourceNew {
330        instance: RuntimeComponentInstanceIndex,
331        ty: TypeResourceTableIndex,
332    },
333    ResourceRep {
334        instance: RuntimeComponentInstanceIndex,
335        ty: TypeResourceTableIndex,
336    },
337    ResourceDrop {
338        instance: RuntimeComponentInstanceIndex,
339        ty: TypeResourceTableIndex,
340    },
341    BackpressureSet {
342        instance: RuntimeComponentInstanceIndex,
343    },
344    BackpressureInc {
345        instance: RuntimeComponentInstanceIndex,
346    },
347    BackpressureDec {
348        instance: RuntimeComponentInstanceIndex,
349    },
350    TaskReturn {
351        instance: RuntimeComponentInstanceIndex,
352        results: TypeTupleIndex,
353        options: OptionsId,
354    },
355    TaskCancel {
356        instance: RuntimeComponentInstanceIndex,
357    },
358    WaitableSetNew {
359        instance: RuntimeComponentInstanceIndex,
360    },
361    WaitableSetWait {
362        instance: RuntimeComponentInstanceIndex,
363        options: OptionsId,
364    },
365    WaitableSetPoll {
366        instance: RuntimeComponentInstanceIndex,
367        options: OptionsId,
368    },
369    WaitableSetDrop {
370        instance: RuntimeComponentInstanceIndex,
371    },
372    WaitableJoin {
373        instance: RuntimeComponentInstanceIndex,
374    },
375    ThreadYield {
376        instance: RuntimeComponentInstanceIndex,
377        cancellable: bool,
378    },
379    SubtaskDrop {
380        instance: RuntimeComponentInstanceIndex,
381    },
382    SubtaskCancel {
383        instance: RuntimeComponentInstanceIndex,
384        async_: bool,
385    },
386    StreamNew {
387        instance: RuntimeComponentInstanceIndex,
388        ty: TypeStreamTableIndex,
389    },
390    StreamRead {
391        instance: RuntimeComponentInstanceIndex,
392        ty: TypeStreamTableIndex,
393        options: OptionsId,
394    },
395    StreamWrite {
396        instance: RuntimeComponentInstanceIndex,
397        ty: TypeStreamTableIndex,
398        options: OptionsId,
399    },
400    StreamCancelRead {
401        instance: RuntimeComponentInstanceIndex,
402        ty: TypeStreamTableIndex,
403        async_: bool,
404    },
405    StreamCancelWrite {
406        instance: RuntimeComponentInstanceIndex,
407        ty: TypeStreamTableIndex,
408        async_: bool,
409    },
410    StreamDropReadable {
411        instance: RuntimeComponentInstanceIndex,
412        ty: TypeStreamTableIndex,
413    },
414    StreamDropWritable {
415        instance: RuntimeComponentInstanceIndex,
416        ty: TypeStreamTableIndex,
417    },
418    FutureNew {
419        instance: RuntimeComponentInstanceIndex,
420        ty: TypeFutureTableIndex,
421    },
422    FutureRead {
423        instance: RuntimeComponentInstanceIndex,
424        ty: TypeFutureTableIndex,
425        options: OptionsId,
426    },
427    FutureWrite {
428        instance: RuntimeComponentInstanceIndex,
429        ty: TypeFutureTableIndex,
430        options: OptionsId,
431    },
432    FutureCancelRead {
433        instance: RuntimeComponentInstanceIndex,
434        ty: TypeFutureTableIndex,
435        async_: bool,
436    },
437    FutureCancelWrite {
438        instance: RuntimeComponentInstanceIndex,
439        ty: TypeFutureTableIndex,
440        async_: bool,
441    },
442    FutureDropReadable {
443        instance: RuntimeComponentInstanceIndex,
444        ty: TypeFutureTableIndex,
445    },
446    FutureDropWritable {
447        instance: RuntimeComponentInstanceIndex,
448        ty: TypeFutureTableIndex,
449    },
450    ErrorContextNew {
451        instance: RuntimeComponentInstanceIndex,
452        ty: TypeComponentLocalErrorContextTableIndex,
453        options: OptionsId,
454    },
455    ErrorContextDebugMessage {
456        instance: RuntimeComponentInstanceIndex,
457        ty: TypeComponentLocalErrorContextTableIndex,
458        options: OptionsId,
459    },
460    ErrorContextDrop {
461        instance: RuntimeComponentInstanceIndex,
462        ty: TypeComponentLocalErrorContextTableIndex,
463    },
464    ResourceTransferOwn,
465    ResourceTransferBorrow,
466    ResourceEnterCall,
467    ResourceExitCall,
468    PrepareCall {
469        memory: Option<MemoryId>,
470    },
471    SyncStartCall {
472        callback: Option<CallbackId>,
473    },
474    AsyncStartCall {
475        callback: Option<CallbackId>,
476        post_return: Option<PostReturnId>,
477    },
478    FutureTransfer,
479    StreamTransfer,
480    ErrorContextTransfer,
481    ContextGet {
482        instance: RuntimeComponentInstanceIndex,
483        slot: u32,
484    },
485    ContextSet {
486        instance: RuntimeComponentInstanceIndex,
487        slot: u32,
488    },
489    ThreadIndex,
490    ThreadNewIndirect {
491        instance: RuntimeComponentInstanceIndex,
492        start_func_ty_idx: ComponentTypeIndex,
493        start_func_table_id: TableId,
494    },
495    ThreadSwitchTo {
496        instance: RuntimeComponentInstanceIndex,
497        cancellable: bool,
498    },
499    ThreadSuspend {
500        instance: RuntimeComponentInstanceIndex,
501        cancellable: bool,
502    },
503    ThreadResumeLater {
504        instance: RuntimeComponentInstanceIndex,
505    },
506    ThreadYieldTo {
507        instance: RuntimeComponentInstanceIndex,
508        cancellable: bool,
509    },
510}
511
512#[derive(Copy, Clone, Hash, Eq, PartialEq)]
513#[expect(missing_docs, reason = "self-describing fields")]
514pub struct FutureInfo {
515    pub instance: RuntimeComponentInstanceIndex,
516    pub payload_type: Option<InterfaceType>,
517}
518
519#[derive(Copy, Clone, Hash, Eq, PartialEq)]
520#[expect(missing_docs, reason = "self-describing fields")]
521pub struct StreamInfo {
522    pub instance: RuntimeComponentInstanceIndex,
523    pub payload_type: InterfaceType,
524}
525
526/// Same as `info::CanonicalOptionsDataModel`.
527#[derive(Clone, Hash, Eq, PartialEq)]
528#[expect(missing_docs, reason = "self-describing fields")]
529pub enum CanonicalOptionsDataModel {
530    Gc {},
531    LinearMemory {
532        memory: Option<MemoryId>,
533        realloc: Option<ReallocId>,
534    },
535}
536
537/// Same as `info::CanonicalOptions`
538#[derive(Clone, Hash, Eq, PartialEq)]
539#[expect(missing_docs, reason = "self-describing fields")]
540pub struct CanonicalOptions {
541    pub instance: RuntimeComponentInstanceIndex,
542    pub string_encoding: StringEncoding,
543    pub callback: Option<CallbackId>,
544    pub post_return: Option<PostReturnId>,
545    pub async_: bool,
546    pub cancellable: bool,
547    pub core_type: ModuleInternedTypeIndex,
548    pub data_model: CanonicalOptionsDataModel,
549}
550
551/// Same as `info::Resource`
552#[expect(missing_docs, reason = "self-describing fields")]
553pub struct Resource {
554    pub rep: WasmValType,
555    pub dtor: Option<CoreDef>,
556    pub instance: RuntimeComponentInstanceIndex,
557}
558
559/// A helper structure to "intern" and deduplicate values of type `V` with an
560/// identifying key `K`.
561///
562/// Note that this can also be used where `V` can't be intern'd to represent a
563/// flat list of items.
564pub struct Intern<K: EntityRef, V> {
565    intern_map: HashMap<V, K>,
566    key_map: PrimaryMap<K, V>,
567}
568
569impl<K, V> Intern<K, V>
570where
571    K: EntityRef,
572{
573    /// Inserts the `value` specified into this set, returning either a fresh
574    /// key `K` if this value hasn't been seen before or otherwise returning the
575    /// previous `K` used to represent value.
576    ///
577    /// Note that this should only be used for component model items where the
578    /// creation of `value` is not side-effectful.
579    pub fn push(&mut self, value: V) -> K
580    where
581        V: Hash + Eq + Clone,
582    {
583        *self
584            .intern_map
585            .entry(value.clone())
586            .or_insert_with(|| self.key_map.push(value))
587    }
588
589    /// Returns an iterator of all the values contained within this set.
590    pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
591        self.key_map.iter()
592    }
593}
594
595impl<K: EntityRef, V> Index<K> for Intern<K, V> {
596    type Output = V;
597    fn index(&self, key: K) -> &V {
598        &self.key_map[key]
599    }
600}
601
602impl<K: EntityRef, V> Default for Intern<K, V> {
603    fn default() -> Intern<K, V> {
604        Intern {
605            intern_map: HashMap::new(),
606            key_map: PrimaryMap::new(),
607        }
608    }
609}
610
611impl ComponentDfg {
612    /// Consumes the intermediate `ComponentDfg` to produce a final `Component`
613    /// with a linear initializer list.
614    pub fn finish(
615        self,
616        wasmtime_types: &mut ComponentTypesBuilder,
617        wasmparser_types: wasmparser::types::TypesRef<'_>,
618    ) -> Result<ComponentTranslation> {
619        let mut linearize = LinearizeDfg {
620            dfg: &self,
621            initializers: Vec::new(),
622            runtime_memories: Default::default(),
623            runtime_tables: Default::default(),
624            runtime_post_return: Default::default(),
625            runtime_reallocs: Default::default(),
626            runtime_callbacks: Default::default(),
627            runtime_instances: Default::default(),
628            num_lowerings: 0,
629            unsafe_intrinsics: Default::default(),
630            trampolines: Default::default(),
631            trampoline_defs: Default::default(),
632            trampoline_map: Default::default(),
633            options: Default::default(),
634            options_map: Default::default(),
635        };
636
637        // Handle all side effects of this component in the order that they're
638        // defined. This will, for example, process all instantiations necessary
639        // of core wasm modules.
640        for item in linearize.dfg.side_effects.iter() {
641            linearize.side_effect(item);
642        }
643
644        // Next the exports of the instance are handled which will likely end up
645        // creating some lowered imports, perhaps some saved modules, etc.
646        let mut export_items = PrimaryMap::new();
647        let mut exports = NameMap::default();
648        for (name, export) in self.exports.iter() {
649            let export =
650                linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
651            exports.insert(name, &mut NameMapNoIntern, false, export)?;
652        }
653
654        // With all those pieces done the results of the dataflow-based
655        // linearization are recorded into the `Component`. The number of
656        // runtime values used for each index space is used from the `linearize`
657        // result.
658        Ok(ComponentTranslation {
659            trampolines: linearize.trampoline_defs,
660            component: Component {
661                exports,
662                export_items,
663                initializers: linearize.initializers,
664                unsafe_intrinsics: linearize.unsafe_intrinsics,
665                trampolines: linearize.trampolines,
666                num_lowerings: linearize.num_lowerings,
667                options: linearize.options,
668
669                num_runtime_memories: linearize.runtime_memories.len() as u32,
670                num_runtime_tables: linearize.runtime_tables.len() as u32,
671                num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
672                num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
673                num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
674                num_runtime_instances: linearize.runtime_instances.len() as u32,
675                imports: self.imports,
676                import_types: self.import_types,
677                num_runtime_component_instances: self.num_runtime_component_instances,
678                num_future_tables: self.num_future_tables,
679                num_stream_tables: self.num_stream_tables,
680                num_error_context_tables: self.num_error_context_tables,
681                num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
682                imported_resources: self.imported_resources,
683                defined_resource_instances: self
684                    .resources
685                    .iter()
686                    .map(|(_, r)| r.instance)
687                    .collect(),
688            },
689        })
690    }
691
692    /// Converts the provided defined index into a normal index, adding in the
693    /// number of imported resources.
694    pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
695        ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
696    }
697}
698
699struct LinearizeDfg<'a> {
700    dfg: &'a ComponentDfg,
701    initializers: Vec<GlobalInitializer>,
702    unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],
703    trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
704    trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
705    options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,
706    trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
707    runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
708    runtime_tables: HashMap<TableId, RuntimeTableIndex>,
709    runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
710    runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
711    runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
712    runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
713    options_map: HashMap<OptionsId, OptionsIndex>,
714    num_lowerings: u32,
715}
716
717#[derive(Copy, Clone, Hash, Eq, PartialEq)]
718enum RuntimeInstance {
719    Normal(InstanceId),
720    Adapter(AdapterModuleId),
721}
722
723impl LinearizeDfg<'_> {
724    fn side_effect(&mut self, effect: &SideEffect) {
725        match effect {
726            SideEffect::Instance(i) => {
727                self.instantiate(*i, &self.dfg.instances[*i]);
728            }
729            SideEffect::Resource(i) => {
730                self.resource(*i, &self.dfg.resources[*i]);
731            }
732        }
733    }
734
735    fn instantiate(&mut self, instance: InstanceId, args: &Instance) {
736        log::trace!("creating instance {instance:?}");
737        let instantiation = match args {
738            Instance::Static(index, args) => InstantiateModule::Static(
739                *index,
740                args.iter().map(|def| self.core_def(def)).collect(),
741            ),
742            Instance::Import(index, args) => InstantiateModule::Import(
743                *index,
744                args.iter()
745                    .map(|(module, values)| {
746                        let values = values
747                            .iter()
748                            .map(|(name, def)| (name.clone(), self.core_def(def)))
749                            .collect();
750                        (module.clone(), values)
751                    })
752                    .collect(),
753            ),
754        };
755        let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
756        self.initializers
757            .push(GlobalInitializer::InstantiateModule(instantiation));
758        let prev = self
759            .runtime_instances
760            .insert(RuntimeInstance::Normal(instance), index);
761        assert!(prev.is_none());
762    }
763
764    fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
765        let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
766        self.initializers
767            .push(GlobalInitializer::Resource(info::Resource {
768                dtor,
769                index,
770                rep: resource.rep,
771                instance: resource.instance,
772            }));
773    }
774
775    fn export(
776        &mut self,
777        export: &Export,
778        items: &mut PrimaryMap<ExportIndex, info::Export>,
779        wasmtime_types: &mut ComponentTypesBuilder,
780        wasmparser_types: wasmparser::types::TypesRef<'_>,
781    ) -> Result<ExportIndex> {
782        let item = match export {
783            Export::LiftedFunction { ty, func, options } => {
784                let func = self.core_def(func);
785                let options = self.options(*options);
786                info::Export::LiftedFunction {
787                    ty: *ty,
788                    func,
789                    options,
790                }
791            }
792            Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
793                ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
794                index: *index,
795            },
796            Export::ModuleImport { ty, import } => info::Export::ModuleImport {
797                ty: *ty,
798                import: *import,
799            },
800            Export::Instance { ty, exports } => info::Export::Instance {
801                ty: *ty,
802                exports: {
803                    let mut map = NameMap::default();
804                    for (name, export) in exports {
805                        let export =
806                            self.export(export, items, wasmtime_types, wasmparser_types)?;
807                        map.insert(name, &mut NameMapNoIntern, false, export)?;
808                    }
809                    map
810                },
811            },
812            Export::Type(def) => info::Export::Type(*def),
813        };
814        Ok(items.push(item))
815    }
816
817    fn options(&mut self, options: OptionsId) -> OptionsIndex {
818        self.intern_no_init(
819            options,
820            |me| &mut me.options_map,
821            |me, options| me.convert_options(options),
822        )
823    }
824
825    fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {
826        let options = &self.dfg.options[options];
827        let data_model = match options.data_model {
828            CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},
829            CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {
830                info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {
831                    memory: memory.map(|mem| self.runtime_memory(mem)),
832                    realloc: realloc.map(|mem| self.runtime_realloc(mem)),
833                })
834            }
835        };
836        let callback = options.callback.map(|mem| self.runtime_callback(mem));
837        let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
838        let options = info::CanonicalOptions {
839            instance: options.instance,
840            string_encoding: options.string_encoding,
841            callback,
842            post_return,
843            async_: options.async_,
844            cancellable: options.cancellable,
845            core_type: options.core_type,
846            data_model,
847        };
848        self.options.push(options)
849    }
850
851    fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
852        self.intern(
853            mem,
854            |me| &mut me.runtime_memories,
855            |me, mem| me.core_export(&me.dfg.memories[mem]),
856            |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
857        )
858    }
859
860    fn runtime_table(&mut self, table: TableId) -> RuntimeTableIndex {
861        self.intern(
862            table,
863            |me| &mut me.runtime_tables,
864            |me, table| me.core_export(&me.dfg.tables[table]),
865            |index, export| GlobalInitializer::ExtractTable(ExtractTable { index, export }),
866        )
867    }
868
869    fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
870        self.intern(
871            realloc,
872            |me| &mut me.runtime_reallocs,
873            |me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
874            |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
875        )
876    }
877
878    fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
879        self.intern(
880            callback,
881            |me| &mut me.runtime_callbacks,
882            |me, callback| me.core_def(&me.dfg.callbacks[callback]),
883            |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
884        )
885    }
886
887    fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
888        self.intern(
889            post_return,
890            |me| &mut me.runtime_post_return,
891            |me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
892            |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
893        )
894    }
895
896    fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
897        match def {
898            CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
899            CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
900            CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
901            CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
902            CoreDef::UnsafeIntrinsic(ty, i) => {
903                let index = usize::try_from(i.index()).unwrap();
904                if self.unsafe_intrinsics[index].is_none() {
905                    self.unsafe_intrinsics[index] = Some(*ty).into();
906                }
907                info::CoreDef::UnsafeIntrinsic(*i)
908            }
909        }
910    }
911
912    fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
913        if let Some(idx) = self.trampoline_map.get(&index) {
914            return *idx;
915        }
916        let (signature, trampoline) = &self.dfg.trampolines[index];
917        let trampoline = match trampoline {
918            Trampoline::LowerImport {
919                import,
920                options,
921                lower_ty,
922            } => {
923                let index = LoweredIndex::from_u32(self.num_lowerings);
924                self.num_lowerings += 1;
925                self.initializers.push(GlobalInitializer::LowerImport {
926                    index,
927                    import: *import,
928                });
929                info::Trampoline::LowerImport {
930                    index,
931                    options: self.options(*options),
932                    lower_ty: *lower_ty,
933                }
934            }
935            Trampoline::Transcoder {
936                op,
937                from,
938                from64,
939                to,
940                to64,
941            } => info::Trampoline::Transcoder {
942                op: *op,
943                from: self.runtime_memory(*from),
944                from64: *from64,
945                to: self.runtime_memory(*to),
946                to64: *to64,
947            },
948            Trampoline::AlwaysTrap => info::Trampoline::AlwaysTrap,
949            Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew {
950                instance: *instance,
951                ty: *ty,
952            },
953            Trampoline::ResourceDrop { instance, ty } => info::Trampoline::ResourceDrop {
954                instance: *instance,
955                ty: *ty,
956            },
957            Trampoline::ResourceRep { instance, ty } => info::Trampoline::ResourceRep {
958                instance: *instance,
959                ty: *ty,
960            },
961            Trampoline::BackpressureSet { instance } => info::Trampoline::BackpressureSet {
962                instance: *instance,
963            },
964            Trampoline::BackpressureInc { instance } => info::Trampoline::BackpressureInc {
965                instance: *instance,
966            },
967            Trampoline::BackpressureDec { instance } => info::Trampoline::BackpressureDec {
968                instance: *instance,
969            },
970            Trampoline::TaskReturn {
971                instance,
972                results,
973                options,
974            } => info::Trampoline::TaskReturn {
975                instance: *instance,
976                results: *results,
977                options: self.options(*options),
978            },
979            Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {
980                instance: *instance,
981            },
982            Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
983                instance: *instance,
984            },
985            Trampoline::WaitableSetWait { instance, options } => {
986                info::Trampoline::WaitableSetWait {
987                    instance: *instance,
988                    options: self.options(*options),
989                }
990            }
991            Trampoline::WaitableSetPoll { instance, options } => {
992                info::Trampoline::WaitableSetPoll {
993                    instance: *instance,
994                    options: self.options(*options),
995                }
996            }
997            Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
998                instance: *instance,
999            },
1000            Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
1001                instance: *instance,
1002            },
1003            Trampoline::ThreadYield {
1004                instance,
1005                cancellable,
1006            } => info::Trampoline::ThreadYield {
1007                instance: *instance,
1008                cancellable: *cancellable,
1009            },
1010            Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
1011                instance: *instance,
1012            },
1013            Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {
1014                instance: *instance,
1015                async_: *async_,
1016            },
1017            Trampoline::StreamNew { instance, ty } => info::Trampoline::StreamNew {
1018                instance: *instance,
1019                ty: *ty,
1020            },
1021            Trampoline::StreamRead {
1022                instance,
1023                ty,
1024                options,
1025            } => info::Trampoline::StreamRead {
1026                instance: *instance,
1027                ty: *ty,
1028                options: self.options(*options),
1029            },
1030            Trampoline::StreamWrite {
1031                instance,
1032                ty,
1033                options,
1034            } => info::Trampoline::StreamWrite {
1035                instance: *instance,
1036                ty: *ty,
1037                options: self.options(*options),
1038            },
1039            Trampoline::StreamCancelRead {
1040                instance,
1041                ty,
1042                async_,
1043            } => info::Trampoline::StreamCancelRead {
1044                instance: *instance,
1045                ty: *ty,
1046                async_: *async_,
1047            },
1048            Trampoline::StreamCancelWrite {
1049                instance,
1050                ty,
1051                async_,
1052            } => info::Trampoline::StreamCancelWrite {
1053                instance: *instance,
1054                ty: *ty,
1055                async_: *async_,
1056            },
1057            Trampoline::StreamDropReadable { instance, ty } => {
1058                info::Trampoline::StreamDropReadable {
1059                    instance: *instance,
1060                    ty: *ty,
1061                }
1062            }
1063            Trampoline::StreamDropWritable { instance, ty } => {
1064                info::Trampoline::StreamDropWritable {
1065                    instance: *instance,
1066                    ty: *ty,
1067                }
1068            }
1069            Trampoline::FutureNew { instance, ty } => info::Trampoline::FutureNew {
1070                instance: *instance,
1071                ty: *ty,
1072            },
1073            Trampoline::FutureRead {
1074                instance,
1075                ty,
1076                options,
1077            } => info::Trampoline::FutureRead {
1078                instance: *instance,
1079                ty: *ty,
1080                options: self.options(*options),
1081            },
1082            Trampoline::FutureWrite {
1083                instance,
1084                ty,
1085                options,
1086            } => info::Trampoline::FutureWrite {
1087                instance: *instance,
1088                ty: *ty,
1089                options: self.options(*options),
1090            },
1091            Trampoline::FutureCancelRead {
1092                instance,
1093                ty,
1094                async_,
1095            } => info::Trampoline::FutureCancelRead {
1096                instance: *instance,
1097                ty: *ty,
1098                async_: *async_,
1099            },
1100            Trampoline::FutureCancelWrite {
1101                instance,
1102                ty,
1103                async_,
1104            } => info::Trampoline::FutureCancelWrite {
1105                instance: *instance,
1106                ty: *ty,
1107                async_: *async_,
1108            },
1109            Trampoline::FutureDropReadable { instance, ty } => {
1110                info::Trampoline::FutureDropReadable {
1111                    instance: *instance,
1112                    ty: *ty,
1113                }
1114            }
1115            Trampoline::FutureDropWritable { instance, ty } => {
1116                info::Trampoline::FutureDropWritable {
1117                    instance: *instance,
1118                    ty: *ty,
1119                }
1120            }
1121            Trampoline::ErrorContextNew {
1122                instance,
1123                ty,
1124                options,
1125            } => info::Trampoline::ErrorContextNew {
1126                instance: *instance,
1127                ty: *ty,
1128                options: self.options(*options),
1129            },
1130            Trampoline::ErrorContextDebugMessage {
1131                instance,
1132                ty,
1133                options,
1134            } => info::Trampoline::ErrorContextDebugMessage {
1135                instance: *instance,
1136                ty: *ty,
1137                options: self.options(*options),
1138            },
1139            Trampoline::ErrorContextDrop { instance, ty } => info::Trampoline::ErrorContextDrop {
1140                instance: *instance,
1141                ty: *ty,
1142            },
1143            Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
1144            Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
1145            Trampoline::ResourceEnterCall => info::Trampoline::ResourceEnterCall,
1146            Trampoline::ResourceExitCall => info::Trampoline::ResourceExitCall,
1147            Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {
1148                memory: memory.map(|v| self.runtime_memory(v)),
1149            },
1150            Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall {
1151                callback: callback.map(|v| self.runtime_callback(v)),
1152            },
1153            Trampoline::AsyncStartCall {
1154                callback,
1155                post_return,
1156            } => info::Trampoline::AsyncStartCall {
1157                callback: callback.map(|v| self.runtime_callback(v)),
1158                post_return: post_return.map(|v| self.runtime_post_return(v)),
1159            },
1160            Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
1161            Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
1162            Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
1163            Trampoline::ContextGet { instance, slot } => info::Trampoline::ContextGet {
1164                instance: *instance,
1165                slot: *slot,
1166            },
1167            Trampoline::ContextSet { instance, slot } => info::Trampoline::ContextSet {
1168                instance: *instance,
1169                slot: *slot,
1170            },
1171            Trampoline::ThreadIndex => info::Trampoline::ThreadIndex,
1172            Trampoline::ThreadNewIndirect {
1173                instance,
1174                start_func_ty_idx,
1175                start_func_table_id,
1176            } => info::Trampoline::ThreadNewIndirect {
1177                instance: *instance,
1178                start_func_ty_idx: *start_func_ty_idx,
1179                start_func_table_idx: self.runtime_table(*start_func_table_id),
1180            },
1181            Trampoline::ThreadSwitchTo {
1182                instance,
1183                cancellable,
1184            } => info::Trampoline::ThreadSwitchTo {
1185                instance: *instance,
1186                cancellable: *cancellable,
1187            },
1188            Trampoline::ThreadSuspend {
1189                instance,
1190                cancellable,
1191            } => info::Trampoline::ThreadSuspend {
1192                instance: *instance,
1193                cancellable: *cancellable,
1194            },
1195            Trampoline::ThreadResumeLater { instance } => info::Trampoline::ThreadResumeLater {
1196                instance: *instance,
1197            },
1198            Trampoline::ThreadYieldTo {
1199                instance,
1200                cancellable,
1201            } => info::Trampoline::ThreadYieldTo {
1202                instance: *instance,
1203                cancellable: *cancellable,
1204            },
1205        };
1206        let i1 = self.trampolines.push(*signature);
1207        let i2 = self.trampoline_defs.push(trampoline);
1208        assert_eq!(i1, i2);
1209        self.trampoline_map.insert(index, i1);
1210        i1
1211    }
1212
1213    fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
1214    where
1215        T: Clone,
1216    {
1217        let instance = export.instance;
1218        log::trace!("referencing export of {instance:?}");
1219        info::CoreExport {
1220            instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
1221            item: export.item.clone(),
1222        }
1223    }
1224
1225    fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
1226        let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
1227
1228        // Instantiates the adapter module if it hasn't already been
1229        // instantiated or otherwise returns the index that the module was
1230        // already instantiated at.
1231        let instance = self.adapter_module(adapter_module);
1232
1233        // This adapter is always an export of the instance.
1234        info::CoreExport {
1235            instance,
1236            item: ExportItem::Index(entity_index),
1237        }
1238    }
1239
1240    fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
1241        self.intern(
1242            RuntimeInstance::Adapter(adapter_module),
1243            |me| &mut me.runtime_instances,
1244            |me, _| {
1245                log::debug!("instantiating {adapter_module:?}");
1246                let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
1247                let args = args.iter().map(|arg| me.core_def(arg)).collect();
1248                let instantiate = InstantiateModule::Static(*module_index, args);
1249                GlobalInitializer::InstantiateModule(instantiate)
1250            },
1251            |_, init| init,
1252        )
1253    }
1254
1255    /// Helper function to manage interning of results to avoid duplicate
1256    /// initializers being inserted into the final list.
1257    ///
1258    /// * `key` - the key being referenced which is used to deduplicate.
1259    /// * `map` - a closure to access the interning map on `Self`
1260    /// * `gen` - a closure to generate an intermediate value with `Self` from
1261    ///   `K`. This is only used if `key` hasn't previously been seen. This
1262    ///   closure can recursively intern other values possibly.
1263    /// * `init` - a closure to use the result of `gen` to create the final
1264    ///   initializer now that the index `V` of the runtime item is known.
1265    ///
1266    /// This is used by all the other interning methods above to lazily append
1267    /// initializers on-demand and avoid pushing more than one initializer at a
1268    /// time.
1269    fn intern<K, V, T>(
1270        &mut self,
1271        key: K,
1272        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1273        generate: impl FnOnce(&mut Self, K) -> T,
1274        init: impl FnOnce(V, T) -> GlobalInitializer,
1275    ) -> V
1276    where
1277        K: Hash + Eq + Copy,
1278        V: EntityRef,
1279    {
1280        self.intern_(key, map, generate, |me, key, val| {
1281            me.initializers.push(init(key, val));
1282        })
1283    }
1284
1285    fn intern_no_init<K, V, T>(
1286        &mut self,
1287        key: K,
1288        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1289        generate: impl FnOnce(&mut Self, K) -> T,
1290    ) -> V
1291    where
1292        K: Hash + Eq + Copy,
1293        V: EntityRef,
1294    {
1295        self.intern_(key, map, generate, |_me, _key, _val| {})
1296    }
1297
1298    fn intern_<K, V, T>(
1299        &mut self,
1300        key: K,
1301        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1302        generate: impl FnOnce(&mut Self, K) -> T,
1303        init: impl FnOnce(&mut Self, V, T),
1304    ) -> V
1305    where
1306        K: Hash + Eq + Copy,
1307        V: EntityRef,
1308    {
1309        if let Some(val) = map(self).get(&key) {
1310            return *val;
1311        }
1312        let tmp = generate(self, key);
1313        let index = V::new(map(self).len());
1314        init(self, index, tmp);
1315        let prev = map(self).insert(key, index);
1316        assert!(prev.is_none());
1317        index
1318    }
1319}