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