Skip to main content

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::error::Result;
32use crate::prelude::*;
33use crate::{EntityIndex, EntityRef, ModuleInternedTypeIndex, PrimaryMap, WasmValType};
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, RuntimeComponentInstanceIndex),
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    TaskMayBlock,
271
272    /// This is a special variant not present in `info::CoreDef` which
273    /// represents that this definition refers to a fused adapter function. This
274    /// adapter is fully processed after the initial translation and
275    /// identification of adapters.
276    ///
277    /// During translation into `info::CoreDef` this variant is erased and
278    /// replaced by `info::CoreDef::Export` since adapters are always
279    /// represented as the exports of a core wasm instance.
280    Adapter(AdapterId),
281}
282
283impl<T> From<CoreExport<T>> for CoreDef
284where
285    EntityIndex: From<T>,
286{
287    fn from(export: CoreExport<T>) -> CoreDef {
288        CoreDef::Export(export.map_index(|i| i.into()))
289    }
290}
291
292/// Same as `info::CoreExport`
293#[derive(Debug, Clone, Hash, Eq, PartialEq)]
294#[expect(missing_docs, reason = "self-describing fields")]
295pub struct CoreExport<T> {
296    pub instance: InstanceId,
297    pub item: ExportItem<T>,
298}
299
300impl<T> CoreExport<T> {
301    #[expect(missing_docs, reason = "self-describing function")]
302    pub fn map_index<U>(self, f: impl FnOnce(T) -> U) -> CoreExport<U> {
303        CoreExport {
304            instance: self.instance,
305            item: match self.item {
306                ExportItem::Index(i) => ExportItem::Index(f(i)),
307                ExportItem::Name(s) => ExportItem::Name(s),
308            },
309        }
310    }
311}
312
313/// Same as `info::Trampoline`
314#[derive(Clone, PartialEq, Eq, Hash)]
315#[expect(missing_docs, reason = "self-describing fields")]
316pub enum Trampoline {
317    LowerImport {
318        import: RuntimeImportIndex,
319        options: OptionsId,
320        lower_ty: TypeFuncIndex,
321    },
322    Transcoder {
323        op: Transcode,
324        from: MemoryId,
325        from64: bool,
326        to: MemoryId,
327        to64: bool,
328    },
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    BackpressureInc {
342        instance: RuntimeComponentInstanceIndex,
343    },
344    BackpressureDec {
345        instance: RuntimeComponentInstanceIndex,
346    },
347    TaskReturn {
348        instance: RuntimeComponentInstanceIndex,
349        results: TypeTupleIndex,
350        options: OptionsId,
351    },
352    TaskCancel {
353        instance: RuntimeComponentInstanceIndex,
354    },
355    WaitableSetNew {
356        instance: RuntimeComponentInstanceIndex,
357    },
358    WaitableSetWait {
359        instance: RuntimeComponentInstanceIndex,
360        options: OptionsId,
361    },
362    WaitableSetPoll {
363        instance: RuntimeComponentInstanceIndex,
364        options: OptionsId,
365    },
366    WaitableSetDrop {
367        instance: RuntimeComponentInstanceIndex,
368    },
369    WaitableJoin {
370        instance: RuntimeComponentInstanceIndex,
371    },
372    ThreadYield {
373        instance: RuntimeComponentInstanceIndex,
374        cancellable: bool,
375    },
376    SubtaskDrop {
377        instance: RuntimeComponentInstanceIndex,
378    },
379    SubtaskCancel {
380        instance: RuntimeComponentInstanceIndex,
381        async_: bool,
382    },
383    StreamNew {
384        instance: RuntimeComponentInstanceIndex,
385        ty: TypeStreamTableIndex,
386    },
387    StreamRead {
388        instance: RuntimeComponentInstanceIndex,
389        ty: TypeStreamTableIndex,
390        options: OptionsId,
391    },
392    StreamWrite {
393        instance: RuntimeComponentInstanceIndex,
394        ty: TypeStreamTableIndex,
395        options: OptionsId,
396    },
397    StreamCancelRead {
398        instance: RuntimeComponentInstanceIndex,
399        ty: TypeStreamTableIndex,
400        async_: bool,
401    },
402    StreamCancelWrite {
403        instance: RuntimeComponentInstanceIndex,
404        ty: TypeStreamTableIndex,
405        async_: bool,
406    },
407    StreamDropReadable {
408        instance: RuntimeComponentInstanceIndex,
409        ty: TypeStreamTableIndex,
410    },
411    StreamDropWritable {
412        instance: RuntimeComponentInstanceIndex,
413        ty: TypeStreamTableIndex,
414    },
415    FutureNew {
416        instance: RuntimeComponentInstanceIndex,
417        ty: TypeFutureTableIndex,
418    },
419    FutureRead {
420        instance: RuntimeComponentInstanceIndex,
421        ty: TypeFutureTableIndex,
422        options: OptionsId,
423    },
424    FutureWrite {
425        instance: RuntimeComponentInstanceIndex,
426        ty: TypeFutureTableIndex,
427        options: OptionsId,
428    },
429    FutureCancelRead {
430        instance: RuntimeComponentInstanceIndex,
431        ty: TypeFutureTableIndex,
432        async_: bool,
433    },
434    FutureCancelWrite {
435        instance: RuntimeComponentInstanceIndex,
436        ty: TypeFutureTableIndex,
437        async_: bool,
438    },
439    FutureDropReadable {
440        instance: RuntimeComponentInstanceIndex,
441        ty: TypeFutureTableIndex,
442    },
443    FutureDropWritable {
444        instance: RuntimeComponentInstanceIndex,
445        ty: TypeFutureTableIndex,
446    },
447    ErrorContextNew {
448        instance: RuntimeComponentInstanceIndex,
449        ty: TypeComponentLocalErrorContextTableIndex,
450        options: OptionsId,
451    },
452    ErrorContextDebugMessage {
453        instance: RuntimeComponentInstanceIndex,
454        ty: TypeComponentLocalErrorContextTableIndex,
455        options: OptionsId,
456    },
457    ErrorContextDrop {
458        instance: RuntimeComponentInstanceIndex,
459        ty: TypeComponentLocalErrorContextTableIndex,
460    },
461    ResourceTransferOwn,
462    ResourceTransferBorrow,
463    PrepareCall {
464        memory: Option<MemoryId>,
465    },
466    SyncStartCall {
467        callback: Option<CallbackId>,
468    },
469    AsyncStartCall {
470        callback: Option<CallbackId>,
471        post_return: Option<PostReturnId>,
472    },
473    FutureTransfer,
474    StreamTransfer,
475    ErrorContextTransfer,
476    Trap,
477    EnterSyncCall,
478    ExitSyncCall,
479    ThreadIndex,
480    ThreadNewIndirect {
481        instance: RuntimeComponentInstanceIndex,
482        start_func_ty_idx: ComponentTypeIndex,
483        start_func_table_id: TableId,
484    },
485    ThreadSuspendToSuspended {
486        instance: RuntimeComponentInstanceIndex,
487        cancellable: bool,
488    },
489    ThreadSuspend {
490        instance: RuntimeComponentInstanceIndex,
491        cancellable: bool,
492    },
493    ThreadSuspendTo {
494        instance: RuntimeComponentInstanceIndex,
495        cancellable: bool,
496    },
497    ThreadUnsuspend {
498        instance: RuntimeComponentInstanceIndex,
499    },
500    ThreadYieldToSuspended {
501        instance: RuntimeComponentInstanceIndex,
502        cancellable: bool,
503    },
504}
505
506#[derive(Copy, Clone, Hash, Eq, PartialEq)]
507#[expect(missing_docs, reason = "self-describing fields")]
508pub struct FutureInfo {
509    pub instance: RuntimeComponentInstanceIndex,
510    pub payload_type: Option<InterfaceType>,
511}
512
513#[derive(Copy, Clone, Hash, Eq, PartialEq)]
514#[expect(missing_docs, reason = "self-describing fields")]
515pub struct StreamInfo {
516    pub instance: RuntimeComponentInstanceIndex,
517    pub payload_type: InterfaceType,
518}
519
520/// Same as `info::CanonicalOptionsDataModel`.
521#[derive(Clone, Hash, Eq, PartialEq)]
522#[expect(missing_docs, reason = "self-describing fields")]
523pub enum CanonicalOptionsDataModel {
524    Gc {},
525    LinearMemory {
526        memory: Option<MemoryId>,
527        realloc: Option<ReallocId>,
528    },
529}
530
531/// Same as `info::CanonicalOptions`
532#[derive(Clone, Hash, Eq, PartialEq)]
533#[expect(missing_docs, reason = "self-describing fields")]
534pub struct CanonicalOptions {
535    pub instance: RuntimeComponentInstanceIndex,
536    pub string_encoding: StringEncoding,
537    pub callback: Option<CallbackId>,
538    pub post_return: Option<PostReturnId>,
539    pub async_: bool,
540    pub cancellable: bool,
541    pub core_type: ModuleInternedTypeIndex,
542    pub data_model: CanonicalOptionsDataModel,
543}
544
545/// Same as `info::Resource`
546#[expect(missing_docs, reason = "self-describing fields")]
547pub struct Resource {
548    pub rep: WasmValType,
549    pub dtor: Option<CoreDef>,
550    pub instance: RuntimeComponentInstanceIndex,
551}
552
553/// A helper structure to "intern" and deduplicate values of type `V` with an
554/// identifying key `K`.
555///
556/// Note that this can also be used where `V` can't be intern'd to represent a
557/// flat list of items.
558pub struct Intern<K: EntityRef, V> {
559    intern_map: HashMap<V, K>,
560    key_map: PrimaryMap<K, V>,
561}
562
563impl<K, V> Intern<K, V>
564where
565    K: EntityRef,
566{
567    /// Inserts the `value` specified into this set, returning either a fresh
568    /// key `K` if this value hasn't been seen before or otherwise returning the
569    /// previous `K` used to represent value.
570    ///
571    /// Note that this should only be used for component model items where the
572    /// creation of `value` is not side-effectful.
573    pub fn push(&mut self, value: V) -> K
574    where
575        V: Hash + Eq + Clone,
576    {
577        *self
578            .intern_map
579            .entry(value.clone())
580            .or_insert_with(|| self.key_map.push(value))
581    }
582
583    /// Returns an iterator of all the values contained within this set.
584    pub fn iter(&self) -> impl Iterator<Item = (K, &V)> {
585        self.key_map.iter()
586    }
587}
588
589impl<K: EntityRef, V> Index<K> for Intern<K, V> {
590    type Output = V;
591    fn index(&self, key: K) -> &V {
592        &self.key_map[key]
593    }
594}
595
596impl<K: EntityRef, V> Default for Intern<K, V> {
597    fn default() -> Intern<K, V> {
598        Intern {
599            intern_map: HashMap::new(),
600            key_map: PrimaryMap::new(),
601        }
602    }
603}
604
605impl ComponentDfg {
606    /// Consumes the intermediate `ComponentDfg` to produce a final `Component`
607    /// with a linear initializer list.
608    pub fn finish(
609        self,
610        wasmtime_types: &mut ComponentTypesBuilder,
611        wasmparser_types: wasmparser::types::TypesRef<'_>,
612    ) -> Result<ComponentTranslation> {
613        let mut linearize = LinearizeDfg {
614            dfg: &self,
615            initializers: Vec::new(),
616            runtime_memories: Default::default(),
617            runtime_tables: Default::default(),
618            runtime_post_return: Default::default(),
619            runtime_reallocs: Default::default(),
620            runtime_callbacks: Default::default(),
621            runtime_instances: Default::default(),
622            num_lowerings: 0,
623            unsafe_intrinsics: Default::default(),
624            trampolines: Default::default(),
625            trampoline_defs: Default::default(),
626            trampoline_map: Default::default(),
627            options: Default::default(),
628            options_map: Default::default(),
629        };
630
631        // Handle all side effects of this component in the order that they're
632        // defined. This will, for example, process all instantiations necessary
633        // of core wasm modules.
634        for item in linearize.dfg.side_effects.iter() {
635            linearize.side_effect(item);
636        }
637
638        // Next the exports of the instance are handled which will likely end up
639        // creating some lowered imports, perhaps some saved modules, etc.
640        let mut export_items = PrimaryMap::new();
641        let mut exports = NameMap::default();
642        for (name, export) in self.exports.iter() {
643            let export =
644                linearize.export(export, &mut export_items, wasmtime_types, wasmparser_types)?;
645            exports.insert(name, &mut NameMapNoIntern, false, export)?;
646        }
647
648        // With all those pieces done the results of the dataflow-based
649        // linearization are recorded into the `Component`. The number of
650        // runtime values used for each index space is used from the `linearize`
651        // result.
652        Ok(ComponentTranslation {
653            trampolines: linearize.trampoline_defs,
654            component: Component {
655                exports,
656                export_items,
657                initializers: linearize.initializers,
658                unsafe_intrinsics: linearize.unsafe_intrinsics,
659                trampolines: linearize.trampolines,
660                num_lowerings: linearize.num_lowerings,
661                options: linearize.options,
662
663                num_runtime_memories: linearize.runtime_memories.len() as u32,
664                num_runtime_tables: linearize.runtime_tables.len() as u32,
665                num_runtime_post_returns: linearize.runtime_post_return.len() as u32,
666                num_runtime_reallocs: linearize.runtime_reallocs.len() as u32,
667                num_runtime_callbacks: linearize.runtime_callbacks.len() as u32,
668                num_runtime_instances: linearize.runtime_instances.len() as u32,
669                imports: self.imports,
670                import_types: self.import_types,
671                num_runtime_component_instances: self.num_runtime_component_instances,
672                num_future_tables: self.num_future_tables,
673                num_stream_tables: self.num_stream_tables,
674                num_error_context_tables: self.num_error_context_tables,
675                num_resources: (self.resources.len() + self.imported_resources.len()) as u32,
676                imported_resources: self.imported_resources,
677                defined_resource_instances: self
678                    .resources
679                    .iter()
680                    .map(|(_, r)| r.instance)
681                    .collect(),
682            },
683        })
684    }
685
686    /// Converts the provided defined index into a normal index, adding in the
687    /// number of imported resources.
688    pub fn resource_index(&self, defined: DefinedResourceIndex) -> ResourceIndex {
689        ResourceIndex::from_u32(defined.as_u32() + (self.imported_resources.len() as u32))
690    }
691}
692
693struct LinearizeDfg<'a> {
694    dfg: &'a ComponentDfg,
695    initializers: Vec<GlobalInitializer>,
696    unsafe_intrinsics: [PackedOption<ModuleInternedTypeIndex>; UnsafeIntrinsic::len() as usize],
697    trampolines: PrimaryMap<TrampolineIndex, ModuleInternedTypeIndex>,
698    trampoline_defs: PrimaryMap<TrampolineIndex, info::Trampoline>,
699    options: PrimaryMap<OptionsIndex, info::CanonicalOptions>,
700    trampoline_map: HashMap<TrampolineIndex, TrampolineIndex>,
701    runtime_memories: HashMap<MemoryId, RuntimeMemoryIndex>,
702    runtime_tables: HashMap<TableId, RuntimeTableIndex>,
703    runtime_reallocs: HashMap<ReallocId, RuntimeReallocIndex>,
704    runtime_callbacks: HashMap<CallbackId, RuntimeCallbackIndex>,
705    runtime_post_return: HashMap<PostReturnId, RuntimePostReturnIndex>,
706    runtime_instances: HashMap<RuntimeInstance, RuntimeInstanceIndex>,
707    options_map: HashMap<OptionsId, OptionsIndex>,
708    num_lowerings: u32,
709}
710
711#[derive(Copy, Clone, Hash, Eq, PartialEq)]
712enum RuntimeInstance {
713    Normal(InstanceId),
714    Adapter(AdapterModuleId),
715}
716
717impl LinearizeDfg<'_> {
718    fn side_effect(&mut self, effect: &SideEffect) {
719        match effect {
720            SideEffect::Instance(i, ci) => {
721                self.instantiate(*i, &self.dfg.instances[*i], *ci);
722            }
723            SideEffect::Resource(i) => {
724                self.resource(*i, &self.dfg.resources[*i]);
725            }
726        }
727    }
728
729    fn instantiate(
730        &mut self,
731        instance: InstanceId,
732        args: &Instance,
733        component_instance: RuntimeComponentInstanceIndex,
734    ) {
735        log::trace!("creating instance {instance:?}");
736        let instantiation = match args {
737            Instance::Static(index, args) => InstantiateModule::Static(
738                *index,
739                args.iter().map(|def| self.core_def(def)).collect(),
740            ),
741            Instance::Import(index, args) => InstantiateModule::Import(
742                *index,
743                args.iter()
744                    .map(|(module, values)| {
745                        let values = values
746                            .iter()
747                            .map(|(name, def)| (name.clone(), self.core_def(def)))
748                            .collect();
749                        (module.clone(), values)
750                    })
751                    .collect(),
752            ),
753        };
754        let index = RuntimeInstanceIndex::new(self.runtime_instances.len());
755        self.initializers.push(GlobalInitializer::InstantiateModule(
756            instantiation,
757            Some(component_instance),
758        ));
759        let prev = self
760            .runtime_instances
761            .insert(RuntimeInstance::Normal(instance), index);
762        assert!(prev.is_none());
763    }
764
765    fn resource(&mut self, index: DefinedResourceIndex, resource: &Resource) {
766        let dtor = resource.dtor.as_ref().map(|dtor| self.core_def(dtor));
767        self.initializers
768            .push(GlobalInitializer::Resource(info::Resource {
769                dtor,
770                index,
771                rep: resource.rep,
772                instance: resource.instance,
773            }));
774    }
775
776    fn export(
777        &mut self,
778        export: &Export,
779        items: &mut PrimaryMap<ExportIndex, info::Export>,
780        wasmtime_types: &mut ComponentTypesBuilder,
781        wasmparser_types: wasmparser::types::TypesRef<'_>,
782    ) -> Result<ExportIndex> {
783        let item = match export {
784            Export::LiftedFunction { ty, func, options } => {
785                let func = self.core_def(func);
786                let options = self.options(*options);
787                info::Export::LiftedFunction {
788                    ty: *ty,
789                    func,
790                    options,
791                }
792            }
793            Export::ModuleStatic { ty, index } => info::Export::ModuleStatic {
794                ty: wasmtime_types.convert_module(wasmparser_types, *ty)?,
795                index: *index,
796            },
797            Export::ModuleImport { ty, import } => info::Export::ModuleImport {
798                ty: *ty,
799                import: *import,
800            },
801            Export::Instance { ty, exports } => info::Export::Instance {
802                ty: *ty,
803                exports: {
804                    let mut map = NameMap::default();
805                    for (name, export) in exports {
806                        let export =
807                            self.export(export, items, wasmtime_types, wasmparser_types)?;
808                        map.insert(name, &mut NameMapNoIntern, false, export)?;
809                    }
810                    map
811                },
812            },
813            Export::Type(def) => info::Export::Type(*def),
814        };
815        Ok(items.push(item))
816    }
817
818    fn options(&mut self, options: OptionsId) -> OptionsIndex {
819        self.intern_no_init(
820            options,
821            |me| &mut me.options_map,
822            |me, options| me.convert_options(options),
823        )
824    }
825
826    fn convert_options(&mut self, options: OptionsId) -> OptionsIndex {
827        let options = &self.dfg.options[options];
828        let data_model = match options.data_model {
829            CanonicalOptionsDataModel::Gc {} => info::CanonicalOptionsDataModel::Gc {},
830            CanonicalOptionsDataModel::LinearMemory { memory, realloc } => {
831                info::CanonicalOptionsDataModel::LinearMemory(LinearMemoryOptions {
832                    memory: memory.map(|mem| self.runtime_memory(mem)),
833                    realloc: realloc.map(|mem| self.runtime_realloc(mem)),
834                })
835            }
836        };
837        let callback = options.callback.map(|mem| self.runtime_callback(mem));
838        let post_return = options.post_return.map(|mem| self.runtime_post_return(mem));
839        let options = info::CanonicalOptions {
840            instance: options.instance,
841            string_encoding: options.string_encoding,
842            callback,
843            post_return,
844            async_: options.async_,
845            cancellable: options.cancellable,
846            core_type: options.core_type,
847            data_model,
848        };
849        self.options.push(options)
850    }
851
852    fn runtime_memory(&mut self, mem: MemoryId) -> RuntimeMemoryIndex {
853        self.intern(
854            mem,
855            |me| &mut me.runtime_memories,
856            |me, mem| me.core_export(&me.dfg.memories[mem]),
857            |index, export| GlobalInitializer::ExtractMemory(ExtractMemory { index, export }),
858        )
859    }
860
861    fn runtime_table(&mut self, table: TableId) -> RuntimeTableIndex {
862        self.intern(
863            table,
864            |me| &mut me.runtime_tables,
865            |me, table| me.core_export(&me.dfg.tables[table]),
866            |index, export| GlobalInitializer::ExtractTable(ExtractTable { index, export }),
867        )
868    }
869
870    fn runtime_realloc(&mut self, realloc: ReallocId) -> RuntimeReallocIndex {
871        self.intern(
872            realloc,
873            |me| &mut me.runtime_reallocs,
874            |me, realloc| me.core_def(&me.dfg.reallocs[realloc]),
875            |index, def| GlobalInitializer::ExtractRealloc(ExtractRealloc { index, def }),
876        )
877    }
878
879    fn runtime_callback(&mut self, callback: CallbackId) -> RuntimeCallbackIndex {
880        self.intern(
881            callback,
882            |me| &mut me.runtime_callbacks,
883            |me, callback| me.core_def(&me.dfg.callbacks[callback]),
884            |index, def| GlobalInitializer::ExtractCallback(ExtractCallback { index, def }),
885        )
886    }
887
888    fn runtime_post_return(&mut self, post_return: PostReturnId) -> RuntimePostReturnIndex {
889        self.intern(
890            post_return,
891            |me| &mut me.runtime_post_return,
892            |me, post_return| me.core_def(&me.dfg.post_returns[post_return]),
893            |index, def| GlobalInitializer::ExtractPostReturn(ExtractPostReturn { index, def }),
894        )
895    }
896
897    fn core_def(&mut self, def: &CoreDef) -> info::CoreDef {
898        match def {
899            CoreDef::Export(e) => info::CoreDef::Export(self.core_export(e)),
900            CoreDef::InstanceFlags(i) => info::CoreDef::InstanceFlags(*i),
901            CoreDef::Adapter(id) => info::CoreDef::Export(self.adapter(*id)),
902            CoreDef::Trampoline(index) => info::CoreDef::Trampoline(self.trampoline(*index)),
903            CoreDef::UnsafeIntrinsic(ty, i) => {
904                let index = usize::try_from(i.index()).unwrap();
905                if self.unsafe_intrinsics[index].is_none() {
906                    self.unsafe_intrinsics[index] = Some(*ty).into();
907                }
908                info::CoreDef::UnsafeIntrinsic(*i)
909            }
910            CoreDef::TaskMayBlock => info::CoreDef::TaskMayBlock,
911        }
912    }
913
914    fn trampoline(&mut self, index: TrampolineIndex) -> TrampolineIndex {
915        if let Some(idx) = self.trampoline_map.get(&index) {
916            return *idx;
917        }
918        let (signature, trampoline) = &self.dfg.trampolines[index];
919        let trampoline = match trampoline {
920            Trampoline::LowerImport {
921                import,
922                options,
923                lower_ty,
924            } => {
925                let index = LoweredIndex::from_u32(self.num_lowerings);
926                self.num_lowerings += 1;
927                self.initializers.push(GlobalInitializer::LowerImport {
928                    index,
929                    import: *import,
930                });
931                info::Trampoline::LowerImport {
932                    index,
933                    options: self.options(*options),
934                    lower_ty: *lower_ty,
935                }
936            }
937            Trampoline::Transcoder {
938                op,
939                from,
940                from64,
941                to,
942                to64,
943            } => info::Trampoline::Transcoder {
944                op: *op,
945                from: self.runtime_memory(*from),
946                from64: *from64,
947                to: self.runtime_memory(*to),
948                to64: *to64,
949            },
950            Trampoline::ResourceNew { instance, ty } => info::Trampoline::ResourceNew {
951                instance: *instance,
952                ty: *ty,
953            },
954            Trampoline::ResourceDrop { instance, ty } => info::Trampoline::ResourceDrop {
955                instance: *instance,
956                ty: *ty,
957            },
958            Trampoline::ResourceRep { instance, ty } => info::Trampoline::ResourceRep {
959                instance: *instance,
960                ty: *ty,
961            },
962            Trampoline::BackpressureInc { instance } => info::Trampoline::BackpressureInc {
963                instance: *instance,
964            },
965            Trampoline::BackpressureDec { instance } => info::Trampoline::BackpressureDec {
966                instance: *instance,
967            },
968            Trampoline::TaskReturn {
969                instance,
970                results,
971                options,
972            } => info::Trampoline::TaskReturn {
973                instance: *instance,
974                results: *results,
975                options: self.options(*options),
976            },
977            Trampoline::TaskCancel { instance } => info::Trampoline::TaskCancel {
978                instance: *instance,
979            },
980            Trampoline::WaitableSetNew { instance } => info::Trampoline::WaitableSetNew {
981                instance: *instance,
982            },
983            Trampoline::WaitableSetWait { instance, options } => {
984                info::Trampoline::WaitableSetWait {
985                    instance: *instance,
986                    options: self.options(*options),
987                }
988            }
989            Trampoline::WaitableSetPoll { instance, options } => {
990                info::Trampoline::WaitableSetPoll {
991                    instance: *instance,
992                    options: self.options(*options),
993                }
994            }
995            Trampoline::WaitableSetDrop { instance } => info::Trampoline::WaitableSetDrop {
996                instance: *instance,
997            },
998            Trampoline::WaitableJoin { instance } => info::Trampoline::WaitableJoin {
999                instance: *instance,
1000            },
1001            Trampoline::ThreadYield {
1002                instance,
1003                cancellable,
1004            } => info::Trampoline::ThreadYield {
1005                instance: *instance,
1006                cancellable: *cancellable,
1007            },
1008            Trampoline::SubtaskDrop { instance } => info::Trampoline::SubtaskDrop {
1009                instance: *instance,
1010            },
1011            Trampoline::SubtaskCancel { instance, async_ } => info::Trampoline::SubtaskCancel {
1012                instance: *instance,
1013                async_: *async_,
1014            },
1015            Trampoline::StreamNew { instance, ty } => info::Trampoline::StreamNew {
1016                instance: *instance,
1017                ty: *ty,
1018            },
1019            Trampoline::StreamRead {
1020                instance,
1021                ty,
1022                options,
1023            } => info::Trampoline::StreamRead {
1024                instance: *instance,
1025                ty: *ty,
1026                options: self.options(*options),
1027            },
1028            Trampoline::StreamWrite {
1029                instance,
1030                ty,
1031                options,
1032            } => info::Trampoline::StreamWrite {
1033                instance: *instance,
1034                ty: *ty,
1035                options: self.options(*options),
1036            },
1037            Trampoline::StreamCancelRead {
1038                instance,
1039                ty,
1040                async_,
1041            } => info::Trampoline::StreamCancelRead {
1042                instance: *instance,
1043                ty: *ty,
1044                async_: *async_,
1045            },
1046            Trampoline::StreamCancelWrite {
1047                instance,
1048                ty,
1049                async_,
1050            } => info::Trampoline::StreamCancelWrite {
1051                instance: *instance,
1052                ty: *ty,
1053                async_: *async_,
1054            },
1055            Trampoline::StreamDropReadable { instance, ty } => {
1056                info::Trampoline::StreamDropReadable {
1057                    instance: *instance,
1058                    ty: *ty,
1059                }
1060            }
1061            Trampoline::StreamDropWritable { instance, ty } => {
1062                info::Trampoline::StreamDropWritable {
1063                    instance: *instance,
1064                    ty: *ty,
1065                }
1066            }
1067            Trampoline::FutureNew { instance, ty } => info::Trampoline::FutureNew {
1068                instance: *instance,
1069                ty: *ty,
1070            },
1071            Trampoline::FutureRead {
1072                instance,
1073                ty,
1074                options,
1075            } => info::Trampoline::FutureRead {
1076                instance: *instance,
1077                ty: *ty,
1078                options: self.options(*options),
1079            },
1080            Trampoline::FutureWrite {
1081                instance,
1082                ty,
1083                options,
1084            } => info::Trampoline::FutureWrite {
1085                instance: *instance,
1086                ty: *ty,
1087                options: self.options(*options),
1088            },
1089            Trampoline::FutureCancelRead {
1090                instance,
1091                ty,
1092                async_,
1093            } => info::Trampoline::FutureCancelRead {
1094                instance: *instance,
1095                ty: *ty,
1096                async_: *async_,
1097            },
1098            Trampoline::FutureCancelWrite {
1099                instance,
1100                ty,
1101                async_,
1102            } => info::Trampoline::FutureCancelWrite {
1103                instance: *instance,
1104                ty: *ty,
1105                async_: *async_,
1106            },
1107            Trampoline::FutureDropReadable { instance, ty } => {
1108                info::Trampoline::FutureDropReadable {
1109                    instance: *instance,
1110                    ty: *ty,
1111                }
1112            }
1113            Trampoline::FutureDropWritable { instance, ty } => {
1114                info::Trampoline::FutureDropWritable {
1115                    instance: *instance,
1116                    ty: *ty,
1117                }
1118            }
1119            Trampoline::ErrorContextNew {
1120                instance,
1121                ty,
1122                options,
1123            } => info::Trampoline::ErrorContextNew {
1124                instance: *instance,
1125                ty: *ty,
1126                options: self.options(*options),
1127            },
1128            Trampoline::ErrorContextDebugMessage {
1129                instance,
1130                ty,
1131                options,
1132            } => info::Trampoline::ErrorContextDebugMessage {
1133                instance: *instance,
1134                ty: *ty,
1135                options: self.options(*options),
1136            },
1137            Trampoline::ErrorContextDrop { instance, ty } => info::Trampoline::ErrorContextDrop {
1138                instance: *instance,
1139                ty: *ty,
1140            },
1141            Trampoline::ResourceTransferOwn => info::Trampoline::ResourceTransferOwn,
1142            Trampoline::ResourceTransferBorrow => info::Trampoline::ResourceTransferBorrow,
1143            Trampoline::PrepareCall { memory } => info::Trampoline::PrepareCall {
1144                memory: memory.map(|v| self.runtime_memory(v)),
1145            },
1146            Trampoline::SyncStartCall { callback } => info::Trampoline::SyncStartCall {
1147                callback: callback.map(|v| self.runtime_callback(v)),
1148            },
1149            Trampoline::AsyncStartCall {
1150                callback,
1151                post_return,
1152            } => info::Trampoline::AsyncStartCall {
1153                callback: callback.map(|v| self.runtime_callback(v)),
1154                post_return: post_return.map(|v| self.runtime_post_return(v)),
1155            },
1156            Trampoline::FutureTransfer => info::Trampoline::FutureTransfer,
1157            Trampoline::StreamTransfer => info::Trampoline::StreamTransfer,
1158            Trampoline::ErrorContextTransfer => info::Trampoline::ErrorContextTransfer,
1159            Trampoline::Trap => info::Trampoline::Trap,
1160            Trampoline::EnterSyncCall => info::Trampoline::EnterSyncCall,
1161            Trampoline::ExitSyncCall => info::Trampoline::ExitSyncCall,
1162            Trampoline::ThreadIndex => info::Trampoline::ThreadIndex,
1163            Trampoline::ThreadNewIndirect {
1164                instance,
1165                start_func_ty_idx,
1166                start_func_table_id,
1167            } => info::Trampoline::ThreadNewIndirect {
1168                instance: *instance,
1169                start_func_ty_idx: *start_func_ty_idx,
1170                start_func_table_idx: self.runtime_table(*start_func_table_id),
1171            },
1172            Trampoline::ThreadSuspendToSuspended {
1173                instance,
1174                cancellable,
1175            } => info::Trampoline::ThreadSuspendToSuspended {
1176                instance: *instance,
1177                cancellable: *cancellable,
1178            },
1179            Trampoline::ThreadSuspendTo {
1180                instance,
1181                cancellable,
1182            } => info::Trampoline::ThreadSuspendTo {
1183                instance: *instance,
1184                cancellable: *cancellable,
1185            },
1186            Trampoline::ThreadSuspend {
1187                instance,
1188                cancellable,
1189            } => info::Trampoline::ThreadSuspend {
1190                instance: *instance,
1191                cancellable: *cancellable,
1192            },
1193            Trampoline::ThreadUnsuspend { instance } => info::Trampoline::ThreadUnsuspend {
1194                instance: *instance,
1195            },
1196            Trampoline::ThreadYieldToSuspended {
1197                instance,
1198                cancellable,
1199            } => info::Trampoline::ThreadYieldToSuspended {
1200                instance: *instance,
1201                cancellable: *cancellable,
1202            },
1203        };
1204        let i1 = self.trampolines.push(*signature);
1205        let i2 = self.trampoline_defs.push(trampoline);
1206        assert_eq!(i1, i2);
1207        self.trampoline_map.insert(index, i1);
1208        i1
1209    }
1210
1211    fn core_export<T>(&mut self, export: &CoreExport<T>) -> info::CoreExport<T>
1212    where
1213        T: Clone,
1214    {
1215        let instance = export.instance;
1216        log::trace!("referencing export of {instance:?}");
1217        info::CoreExport {
1218            instance: self.runtime_instances[&RuntimeInstance::Normal(instance)],
1219            item: export.item.clone(),
1220        }
1221    }
1222
1223    fn adapter(&mut self, adapter: AdapterId) -> info::CoreExport<EntityIndex> {
1224        let (adapter_module, entity_index) = self.dfg.adapter_partitionings[adapter];
1225
1226        // Instantiates the adapter module if it hasn't already been
1227        // instantiated or otherwise returns the index that the module was
1228        // already instantiated at.
1229        let instance = self.adapter_module(adapter_module);
1230
1231        // This adapter is always an export of the instance.
1232        info::CoreExport {
1233            instance,
1234            item: ExportItem::Index(entity_index),
1235        }
1236    }
1237
1238    fn adapter_module(&mut self, adapter_module: AdapterModuleId) -> RuntimeInstanceIndex {
1239        self.intern(
1240            RuntimeInstance::Adapter(adapter_module),
1241            |me| &mut me.runtime_instances,
1242            |me, _| {
1243                log::debug!("instantiating {adapter_module:?}");
1244                let (module_index, args) = &me.dfg.adapter_modules[adapter_module];
1245                let args = args.iter().map(|arg| me.core_def(arg)).collect();
1246                let instantiate = InstantiateModule::Static(*module_index, args);
1247                GlobalInitializer::InstantiateModule(instantiate, None)
1248            },
1249            |_, init| init,
1250        )
1251    }
1252
1253    /// Helper function to manage interning of results to avoid duplicate
1254    /// initializers being inserted into the final list.
1255    ///
1256    /// * `key` - the key being referenced which is used to deduplicate.
1257    /// * `map` - a closure to access the interning map on `Self`
1258    /// * `gen` - a closure to generate an intermediate value with `Self` from
1259    ///   `K`. This is only used if `key` hasn't previously been seen. This
1260    ///   closure can recursively intern other values possibly.
1261    /// * `init` - a closure to use the result of `gen` to create the final
1262    ///   initializer now that the index `V` of the runtime item is known.
1263    ///
1264    /// This is used by all the other interning methods above to lazily append
1265    /// initializers on-demand and avoid pushing more than one initializer at a
1266    /// time.
1267    fn intern<K, V, T>(
1268        &mut self,
1269        key: K,
1270        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1271        generate: impl FnOnce(&mut Self, K) -> T,
1272        init: impl FnOnce(V, T) -> GlobalInitializer,
1273    ) -> V
1274    where
1275        K: Hash + Eq + Copy,
1276        V: EntityRef,
1277    {
1278        self.intern_(key, map, generate, |me, key, val| {
1279            me.initializers.push(init(key, val));
1280        })
1281    }
1282
1283    fn intern_no_init<K, V, T>(
1284        &mut self,
1285        key: K,
1286        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1287        generate: impl FnOnce(&mut Self, K) -> T,
1288    ) -> V
1289    where
1290        K: Hash + Eq + Copy,
1291        V: EntityRef,
1292    {
1293        self.intern_(key, map, generate, |_me, _key, _val| {})
1294    }
1295
1296    fn intern_<K, V, T>(
1297        &mut self,
1298        key: K,
1299        map: impl Fn(&mut Self) -> &mut HashMap<K, V>,
1300        generate: impl FnOnce(&mut Self, K) -> T,
1301        init: impl FnOnce(&mut Self, V, T),
1302    ) -> V
1303    where
1304        K: Hash + Eq + Copy,
1305        V: EntityRef,
1306    {
1307        if let Some(val) = map(self).get(&key) {
1308            return *val;
1309        }
1310        let tmp = generate(self, key);
1311        let index = V::new(map(self).len());
1312        init(self, index, tmp);
1313        let prev = map(self).insert(key, index);
1314        assert!(prev.is_none());
1315        index
1316    }
1317}