wasmtime_environ/component/translate/
inline.rs

1//! Implementation of "inlining" a component into a flat list of initializers.
2//!
3//! After the first phase of compiling a component we're left with a single
4//! root `Translation` for the original component along with a "static" list of
5//! child components. Each `Translation` has a list of `LocalInitializer` items
6//! inside of it which is a primitive representation of how the component
7//! should be constructed with effectively one initializer per item in the
8//! index space of a component. This "local initializer" list would be
9//! relatively inefficient to process at runtime and more importantly doesn't
10//! convey enough information to understand what trampolines need to be
11//! compiled or what fused adapters need to be generated. This consequently is
12//! the motivation for this file.
13//!
14//! The second phase of compilation, inlining here, will in a sense interpret
15//! the initializers, at compile time, into a new list of `GlobalInitializer` entries
16//! which are a sort of "global initializer". The generated `GlobalInitializer` is
17//! much more specific than the `LocalInitializer` and additionally far fewer
18//! `GlobalInitializer` structures are generated (in theory) than there are local
19//! initializers.
20//!
21//! The "inlining" portion of the name of this module indicates how the
22//! instantiation of a component is interpreted as calling a function. The
23//! function's arguments are the imports provided to the instantiation of a
24//! component, and further nested function calls happen on a stack when a
25//! nested component is instantiated. The inlining then refers to how this
26//! stack of instantiations is flattened to one list of `GlobalInitializer`
27//! entries to represent the process of instantiating a component graph,
28//! similar to how function inlining removes call instructions and creates one
29//! giant function for a call graph. Here there are no inlining heuristics or
30//! anything like that, we simply inline everything into the root component's
31//! list of initializers.
32//!
33//! Another primary task this module performs is a form of dataflow analysis
34//! to represent items in each index space with their definition rather than
35//! references of relative indices. These definitions (all the `*Def` types in
36//! this module) are not local to any one nested component and instead
37//! represent state available at runtime tracked in the final `Component`
38//! produced.
39//!
40//! With all this pieced together the general idea is relatively
41//! straightforward. All of a component's initializers are processed in sequence
42//! where instantiating a nested component pushes a "frame" onto a stack to
43//! start executing and we resume at the old one when we're done. Items are
44//! tracked where they come from and at the end after processing only the
45//! side-effectful initializers are emitted to the `GlobalInitializer` list in the
46//! final `Component`.
47
48use crate::component::translate::*;
49use crate::{EntityType, IndexType};
50use std::borrow::Cow;
51use wasmparser::component_types::{ComponentAnyTypeId, ComponentCoreModuleTypeId};
52
53pub(super) fn run(
54    types: &mut ComponentTypesBuilder,
55    result: &Translation<'_>,
56    nested_modules: &PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>,
57    nested_components: &PrimaryMap<StaticComponentIndex, Translation<'_>>,
58) -> Result<dfg::ComponentDfg> {
59    let mut inliner = Inliner {
60        nested_modules,
61        nested_components,
62        result: Default::default(),
63        import_path_interner: Default::default(),
64        runtime_instances: PrimaryMap::default(),
65    };
66
67    let index = RuntimeComponentInstanceIndex::from_u32(0);
68
69    // The initial arguments to the root component are all host imports. This
70    // means that they're all using the `ComponentItemDef::Host` variant. Here
71    // an `ImportIndex` is allocated for each item and then the argument is
72    // recorded.
73    //
74    // Note that this is represents the abstract state of a host import of an
75    // item since we don't know the precise structure of the host import.
76    let mut args = HashMap::with_capacity(result.exports.len());
77    let mut path = Vec::new();
78    types.resources_mut().set_current_instance(index);
79    let types_ref = result.types_ref();
80    for init in result.initializers.iter() {
81        let (name, ty) = match *init {
82            LocalInitializer::Import(name, ty) => (name, ty),
83            _ => continue,
84        };
85
86        // Before `convert_component_entity_type` below all resource types
87        // introduced by this import need to be registered and have indexes
88        // assigned to them. Any fresh new resource type referred to by imports
89        // is a brand new introduction of a resource which needs to have a type
90        // allocated to it, so new runtime imports are injected for each
91        // resource along with updating the `imported_resources` map.
92        let index = inliner.result.import_types.next_key();
93        types.resources_mut().register_component_entity_type(
94            &types_ref,
95            ty,
96            &mut path,
97            &mut |path| {
98                let index = inliner.runtime_import(&ImportPath {
99                    index,
100                    path: path.iter().copied().map(Into::into).collect(),
101                });
102                inliner.result.imported_resources.push(index)
103            },
104        );
105
106        // With resources all taken care of it's now possible to convert this
107        // into Wasmtime's type system.
108        let ty = types.convert_component_entity_type(types_ref, ty)?;
109
110        // Imports of types that aren't resources are not required to be
111        // specified by the host since it's just for type information within
112        // the component.
113        if let TypeDef::Interface(_) = ty {
114            continue;
115        }
116        let index = inliner.result.import_types.push((name.0.to_string(), ty));
117        let path = ImportPath::root(index);
118        args.insert(name.0, ComponentItemDef::from_import(path, ty)?);
119    }
120
121    // This will run the inliner to completion after being seeded with the
122    // initial frame. When the inliner finishes it will return the exports of
123    // the root frame which are then used for recording the exports of the
124    // component.
125    inliner.result.num_runtime_component_instances += 1;
126    let frame = InlinerFrame::new(index, result, ComponentClosure::default(), args, None);
127    let resources_snapshot = types.resources_mut().clone();
128    let mut frames = vec![(frame, resources_snapshot)];
129    let exports = inliner.run(types, &mut frames)?;
130    assert!(frames.is_empty());
131
132    let mut export_map = Default::default();
133    for (name, def) in exports {
134        inliner.record_export(name, def, types, &mut export_map)?;
135    }
136    inliner.result.exports = export_map;
137    inliner.result.num_resource_tables = types.num_resource_tables();
138    inliner.result.num_future_tables = types.num_future_tables();
139    inliner.result.num_stream_tables = types.num_stream_tables();
140    inliner.result.num_error_context_tables = types.num_error_context_tables();
141
142    Ok(inliner.result)
143}
144
145struct Inliner<'a> {
146    /// The list of static modules that were found during initial translation of
147    /// the component.
148    ///
149    /// This is used during the instantiation of these modules to ahead-of-time
150    /// order the arguments precisely according to what the module is defined as
151    /// needing which avoids the need to do string lookups or permute arguments
152    /// at runtime.
153    nested_modules: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,
154
155    /// The list of static components that were found during initial translation of
156    /// the component.
157    ///
158    /// This is used when instantiating nested components to push a new
159    /// `InlinerFrame` with the `Translation`s here.
160    nested_components: &'a PrimaryMap<StaticComponentIndex, Translation<'a>>,
161
162    /// The final `Component` that is being constructed and returned from this
163    /// inliner.
164    result: dfg::ComponentDfg,
165
166    // Maps used to "intern" various runtime items to only save them once at
167    // runtime instead of multiple times.
168    import_path_interner: HashMap<ImportPath<'a>, RuntimeImportIndex>,
169
170    /// Origin information about where each runtime instance came from
171    runtime_instances: PrimaryMap<dfg::InstanceId, InstanceModule>,
172}
173
174/// A "stack frame" as part of the inlining process, or the progress through
175/// instantiating a component.
176///
177/// All instantiations of a component will create an `InlinerFrame` and are
178/// incrementally processed via the `initializers` list here. Note that the
179/// inliner frames are stored on the heap to avoid recursion based on user
180/// input.
181struct InlinerFrame<'a> {
182    instance: RuntimeComponentInstanceIndex,
183
184    /// The remaining initializers to process when instantiating this component.
185    initializers: std::slice::Iter<'a, LocalInitializer<'a>>,
186
187    /// The component being instantiated.
188    translation: &'a Translation<'a>,
189
190    /// The "closure arguments" to this component, or otherwise the maps indexed
191    /// by `ModuleUpvarIndex` and `ComponentUpvarIndex`. This is created when
192    /// a component is created and stored as part of a component's state during
193    /// inlining.
194    closure: ComponentClosure<'a>,
195
196    /// The arguments to the creation of this component.
197    ///
198    /// At the root level these are all imports from the host and between
199    /// components this otherwise tracks how all the arguments are defined.
200    args: HashMap<&'a str, ComponentItemDef<'a>>,
201
202    // core wasm index spaces
203    funcs: PrimaryMap<FuncIndex, dfg::CoreDef>,
204    memories: PrimaryMap<MemoryIndex, dfg::CoreExport<EntityIndex>>,
205    tables: PrimaryMap<TableIndex, dfg::CoreExport<EntityIndex>>,
206    globals: PrimaryMap<GlobalIndex, dfg::CoreExport<EntityIndex>>,
207    modules: PrimaryMap<ModuleIndex, ModuleDef<'a>>,
208
209    // component model index spaces
210    component_funcs: PrimaryMap<ComponentFuncIndex, ComponentFuncDef<'a>>,
211    module_instances: PrimaryMap<ModuleInstanceIndex, ModuleInstanceDef<'a>>,
212    component_instances: PrimaryMap<ComponentInstanceIndex, ComponentInstanceDef<'a>>,
213    components: PrimaryMap<ComponentIndex, ComponentDef<'a>>,
214
215    /// The type of instance produced by completing the instantiation of this
216    /// frame.
217    ///
218    /// This is a wasmparser-relative piece of type information which is used to
219    /// register resource types after instantiation has completed.
220    ///
221    /// This is `Some` for all subcomponents and `None` for the root component.
222    instance_ty: Option<ComponentInstanceTypeId>,
223}
224
225/// "Closure state" for a component which is resolved from the `ClosedOverVars`
226/// state that was calculated during translation.
227//
228// FIXME: this is cloned quite a lot and given the internal maps if this is a
229// perf issue we may want to `Rc` these fields. Note that this is only a perf
230// hit at compile-time though which we in general don't pay too much
231// attention to.
232#[derive(Default, Clone)]
233struct ComponentClosure<'a> {
234    modules: PrimaryMap<ModuleUpvarIndex, ModuleDef<'a>>,
235    components: PrimaryMap<ComponentUpvarIndex, ComponentDef<'a>>,
236}
237
238/// Representation of a "path" into an import.
239///
240/// Imports from the host at this time are one of three things:
241///
242/// * Functions
243/// * Core wasm modules
244/// * "Instances" of these three items
245///
246/// The "base" values are functions and core wasm modules, but the abstraction
247/// of an instance allows embedding functions/modules deeply within other
248/// instances. This "path" represents optionally walking through a host instance
249/// to get to the final desired item. At runtime instances are just maps of
250/// values and so this is used to ensure that we primarily only deal with
251/// individual functions and modules instead of synthetic instances.
252#[derive(Clone, PartialEq, Hash, Eq)]
253struct ImportPath<'a> {
254    index: ImportIndex,
255    path: Vec<Cow<'a, str>>,
256}
257
258/// Representation of all items which can be defined within a component.
259///
260/// This is the "value" of an item defined within a component and is used to
261/// represent both imports and exports.
262#[derive(Clone)]
263enum ComponentItemDef<'a> {
264    Component(ComponentDef<'a>),
265    Instance(ComponentInstanceDef<'a>),
266    Func(ComponentFuncDef<'a>),
267    Module(ModuleDef<'a>),
268    Type(TypeDef),
269}
270
271#[derive(Clone)]
272enum ModuleDef<'a> {
273    /// A core wasm module statically defined within the original component.
274    ///
275    /// The `StaticModuleIndex` indexes into the `static_modules` map in the
276    /// `Inliner`.
277    Static(StaticModuleIndex, ComponentCoreModuleTypeId),
278
279    /// A core wasm module that was imported from the host.
280    Import(ImportPath<'a>, TypeModuleIndex),
281}
282
283// Note that unlike all other `*Def` types which are not allowed to have local
284// indices this type does indeed have local indices. That is represented with
285// the lack of a `Clone` here where once this is created it's never moved across
286// components because module instances always stick within one component.
287enum ModuleInstanceDef<'a> {
288    /// A core wasm module instance was created through the instantiation of a
289    /// module.
290    ///
291    /// The `RuntimeInstanceIndex` was the index allocated as this was the
292    /// `n`th instantiation and the `ModuleIndex` points into an
293    /// `InlinerFrame`'s local index space.
294    Instantiated(dfg::InstanceId, ModuleIndex),
295
296    /// A "synthetic" core wasm module which is just a bag of named indices.
297    ///
298    /// Note that this can really only be used for passing as an argument to
299    /// another module's instantiation and is used to rename arguments locally.
300    Synthetic(&'a HashMap<&'a str, EntityIndex>),
301}
302
303#[derive(Clone)]
304enum ComponentFuncDef<'a> {
305    /// A host-imported component function.
306    Import(ImportPath<'a>),
307
308    /// A core wasm function was lifted into a component function.
309    Lifted {
310        ty: TypeFuncIndex,
311        func: dfg::CoreDef,
312        options: AdapterOptions,
313    },
314}
315
316#[derive(Clone)]
317enum ComponentInstanceDef<'a> {
318    /// A host-imported instance.
319    ///
320    /// This typically means that it's "just" a map of named values. It's not
321    /// actually supported to take a `wasmtime::component::Instance` and pass it
322    /// to another instance at this time.
323    Import(ImportPath<'a>, TypeComponentInstanceIndex),
324
325    /// A concrete map of values.
326    ///
327    /// This is used for both instantiated components as well as "synthetic"
328    /// components. This variant can be used for both because both are
329    /// represented by simply a bag of items within the entire component
330    /// instantiation process.
331    //
332    // FIXME: same as the issue on `ComponentClosure` where this is cloned a lot
333    // and may need `Rc`.
334    Items(
335        IndexMap<&'a str, ComponentItemDef<'a>>,
336        TypeComponentInstanceIndex,
337    ),
338}
339
340#[derive(Clone)]
341struct ComponentDef<'a> {
342    index: StaticComponentIndex,
343    closure: ComponentClosure<'a>,
344}
345
346impl<'a> Inliner<'a> {
347    /// Symbolically instantiates a component using the type information and
348    /// `frames` provided.
349    ///
350    /// The `types` provided is the type information for the entire component
351    /// translation process. This is a distinct output artifact separate from
352    /// the component metadata.
353    ///
354    /// The `frames` argument is storage to handle a "call stack" of components
355    /// instantiating one another. The youngest frame (last element) of the
356    /// frames list is a component that's currently having its initializers
357    /// processed. The second element of each frame is a snapshot of the
358    /// resource-related information just before the frame was translated. For
359    /// more information on this snapshotting see the documentation on
360    /// `ResourcesBuilder`.
361    fn run(
362        &mut self,
363        types: &mut ComponentTypesBuilder,
364        frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,
365    ) -> Result<IndexMap<&'a str, ComponentItemDef<'a>>> {
366        // This loop represents the execution of the instantiation of a
367        // component. This is an iterative process which is finished once all
368        // initializers are processed. Currently this is modeled as an infinite
369        // loop which drives the top-most iterator of the `frames` stack
370        // provided as an argument to this function.
371        loop {
372            let (frame, _) = frames.last_mut().unwrap();
373            types.resources_mut().set_current_instance(frame.instance);
374            match frame.initializers.next() {
375                // Process the initializer and if it started the instantiation
376                // of another component then we push that frame on the stack to
377                // continue onwards.
378                Some(init) => match self.initializer(frame, types, init)? {
379                    Some(new_frame) => {
380                        frames.push((new_frame, types.resources_mut().clone()));
381                    }
382                    None => {}
383                },
384
385                // If there are no more initializers for this frame then the
386                // component it represents has finished instantiation. The
387                // exports of the component are collected and then the entire
388                // frame is discarded. The exports are then either pushed in the
389                // parent frame, if any, as a new component instance or they're
390                // returned from this function for the root set of exports.
391                None => {
392                    let exports = frame
393                        .translation
394                        .exports
395                        .iter()
396                        .map(|(name, item)| Ok((*name, frame.item(*item, types)?)))
397                        .collect::<Result<_>>()?;
398                    let instance_ty = frame.instance_ty;
399                    let (_, snapshot) = frames.pop().unwrap();
400                    *types.resources_mut() = snapshot;
401                    match frames.last_mut() {
402                        Some((parent, _)) => {
403                            parent.finish_instantiate(exports, instance_ty.unwrap(), types)?;
404                        }
405                        None => break Ok(exports),
406                    }
407                }
408            }
409        }
410    }
411
412    fn initializer(
413        &mut self,
414        frame: &mut InlinerFrame<'a>,
415        types: &mut ComponentTypesBuilder,
416        initializer: &'a LocalInitializer,
417    ) -> Result<Option<InlinerFrame<'a>>> {
418        use LocalInitializer::*;
419
420        match initializer {
421            // When a component imports an item the actual definition of the
422            // item is looked up here (not at runtime) via its name. The
423            // arguments provided in our `InlinerFrame` describe how each
424            // argument was defined, so we simply move it from there into the
425            // correct index space.
426            //
427            // Note that for the root component this will add `*::Import` items
428            // but for sub-components this will do resolution to connect what
429            // was provided as an import at the instantiation-site to what was
430            // needed during the component's instantiation.
431            Import(name, ty) => {
432                let arg = match frame.args.get(name.0) {
433                    Some(arg) => arg,
434
435                    // Not all arguments need to be provided for instantiation,
436                    // namely the root component in Wasmtime doesn't require
437                    // structural type imports to be satisfied. These type
438                    // imports are relevant for bindings generators and such but
439                    // as a runtime there's not really a definition to fit in.
440                    //
441                    // If no argument was provided for `name` then it's asserted
442                    // that this is a type import and additionally it's not a
443                    // resource type import (which indeed must be provided). If
444                    // all that passes then this initializer is effectively
445                    // skipped.
446                    None => {
447                        match ty {
448                            ComponentEntityType::Type {
449                                created: ComponentAnyTypeId::Resource(_),
450                                ..
451                            } => unreachable!(),
452                            ComponentEntityType::Type { .. } => {}
453                            _ => unreachable!(),
454                        }
455                        return Ok(None);
456                    }
457                };
458
459                // Next resource types need to be handled. For example if a
460                // resource is imported into this component then it needs to be
461                // assigned a unique table to provide the isolation guarantees
462                // of resources (this component's table is shared with no
463                // others). Here `register_component_entity_type` will find
464                // imported resources and then `lookup_resource` will find the
465                // resource within `arg` as necessary to lookup the original
466                // true definition of this resource.
467                //
468                // This is what enables tracking true resource origins
469                // throughout component translation while simultaneously also
470                // tracking unique tables for each resource in each component.
471                let mut path = Vec::new();
472                let (resources, types) = types.resources_mut_and_types();
473                resources.register_component_entity_type(
474                    &frame.translation.types_ref(),
475                    *ty,
476                    &mut path,
477                    &mut |path| arg.lookup_resource(path, types),
478                );
479
480                // And now with all the type information out of the way the
481                // `arg` definition is moved into its corresponding index space.
482                frame.push_item(arg.clone());
483            }
484
485            // Lowering a component function to a core wasm function is
486            // generally what "triggers compilation". Here various metadata is
487            // recorded and then the final component gets an initializer
488            // recording the lowering.
489            //
490            // NB: at this time only lowered imported functions are supported.
491            Lower {
492                func,
493                options,
494                canonical_abi,
495                lower_ty,
496            } => {
497                let lower_ty =
498                    types.convert_component_func_type(frame.translation.types_ref(), *lower_ty)?;
499                let options_lower = self.adapter_options(frame, types, options);
500                let func = match &frame.component_funcs[*func] {
501                    // If this component function was originally a host import
502                    // then this is a lowered host function which needs a
503                    // trampoline to enter WebAssembly. That's recorded here
504                    // with all relevant information.
505                    ComponentFuncDef::Import(path) => {
506                        let import = self.runtime_import(path);
507                        let options = self.canonical_options(options_lower);
508                        let index = self.result.trampolines.push((
509                            *canonical_abi,
510                            dfg::Trampoline::LowerImport {
511                                import,
512                                options,
513                                lower_ty,
514                            },
515                        ));
516                        dfg::CoreDef::Trampoline(index)
517                    }
518
519                    // This case handles when a lifted function is later
520                    // lowered, and both the lowering and the lifting are
521                    // happening within the same component instance.
522                    //
523                    // In this situation if the `canon.lower`'d function is
524                    // called then it immediately sets `may_enter` to `false`.
525                    // When calling the callee, however, that's `canon.lift`
526                    // which immediately traps if `may_enter` is `false`. That
527                    // means that this pairing of functions creates a function
528                    // that always traps.
529                    //
530                    // When closely reading the spec though the precise trap
531                    // that comes out can be somewhat variable. Technically the
532                    // function yielded here is one that should validate the
533                    // arguments by lifting them, and then trap. This means that
534                    // the trap could be different depending on whether all
535                    // arguments are valid for now. This was discussed in
536                    // WebAssembly/component-model#51 somewhat and the
537                    // conclusion was that we can probably get away with "always
538                    // trap" here.
539                    //
540                    // The `CoreDef::AlwaysTrap` variant here is used to
541                    // indicate that this function is valid but if something
542                    // actually calls it then it just generates a trap
543                    // immediately.
544                    ComponentFuncDef::Lifted {
545                        options: options_lift,
546                        ..
547                    } if options_lift.instance == options_lower.instance => {
548                        let index = self
549                            .result
550                            .trampolines
551                            .push((*canonical_abi, dfg::Trampoline::AlwaysTrap));
552                        dfg::CoreDef::Trampoline(index)
553                    }
554
555                    // Lowering a lifted function where the destination
556                    // component is different than the source component means
557                    // that a "fused adapter" was just identified.
558                    //
559                    // Metadata about this fused adapter is recorded in the
560                    // `Adapters` output of this compilation pass. Currently the
561                    // implementation of fused adapters is to generate a core
562                    // wasm module which is instantiated with relevant imports
563                    // and the exports are used as the fused adapters. At this
564                    // time we don't know when precisely the instance will be
565                    // created but we do know that the result of this will be an
566                    // export from a previously-created instance.
567                    //
568                    // To model this the result of this arm is a
569                    // `CoreDef::Export`. The actual indices listed within the
570                    // export are "fake indices" in the sense of they're not
571                    // resolved yet. This resolution will happen at a later
572                    // compilation phase. Any usages of the `CoreDef::Export`
573                    // here will be detected and rewritten to an actual runtime
574                    // instance created.
575                    //
576                    // The `instance` field of the `CoreExport` has a marker
577                    // which indicates that it's a fused adapter. The `item` is
578                    // a function where the function index corresponds to the
579                    // `adapter_idx` which contains the metadata about this
580                    // adapter being created. The metadata is used to learn
581                    // about the dependencies and when the adapter module can
582                    // be instantiated.
583                    ComponentFuncDef::Lifted {
584                        ty: lift_ty,
585                        func,
586                        options: options_lift,
587                    } => {
588                        let adapter_idx = self.result.adapters.push(Adapter {
589                            lift_ty: *lift_ty,
590                            lift_options: options_lift.clone(),
591                            lower_ty,
592                            lower_options: options_lower,
593                            func: func.clone(),
594                        });
595                        dfg::CoreDef::Adapter(adapter_idx)
596                    }
597                };
598                frame.funcs.push(func);
599            }
600
601            // Lifting a core wasm function is relatively easy for now in that
602            // some metadata about the lifting is simply recorded. This'll get
603            // plumbed through to exports or a fused adapter later on.
604            Lift(ty, func, options) => {
605                let ty = types.convert_component_func_type(frame.translation.types_ref(), *ty)?;
606                let options = self.adapter_options(frame, types, options);
607                frame.component_funcs.push(ComponentFuncDef::Lifted {
608                    ty,
609                    func: frame.funcs[*func].clone(),
610                    options,
611                });
612            }
613
614            // A new resource type is being introduced, so it's recorded as a
615            // brand new resource in the final `resources` array. Additionally
616            // for now resource introductions are considered side effects to
617            // know when to register their destructors so that's recorded as
618            // well.
619            //
620            // Note that this has the effect of when a component is instantiated
621            // twice it will produce unique types for the resources from each
622            // instantiation. That's the intended runtime semantics and
623            // implementation here, however.
624            Resource(ty, rep, dtor) => {
625                let idx = self.result.resources.push(dfg::Resource {
626                    rep: *rep,
627                    dtor: dtor.map(|i| frame.funcs[i].clone()),
628                    instance: frame.instance,
629                });
630                self.result
631                    .side_effects
632                    .push(dfg::SideEffect::Resource(idx));
633
634                // Register with type translation that all future references to
635                // `ty` will refer to `idx`.
636                //
637                // Note that this registration information is lost when this
638                // component finishes instantiation due to the snapshotting
639                // behavior in the frame processing loop above. This is also
640                // intended, though, since `ty` can't be referred to outside of
641                // this component.
642                let idx = self.result.resource_index(idx);
643                types.resources_mut().register_resource(ty.resource(), idx);
644            }
645
646            // Resource-related intrinsics are generally all the same.
647            // Wasmparser type information is converted to wasmtime type
648            // information and then new entries for each intrinsic are recorded.
649            ResourceNew(id, ty) => {
650                let id = types.resource_id(id.resource());
651                let index = self
652                    .result
653                    .trampolines
654                    .push((*ty, dfg::Trampoline::ResourceNew(id)));
655                frame.funcs.push(dfg::CoreDef::Trampoline(index));
656            }
657            ResourceRep(id, ty) => {
658                let id = types.resource_id(id.resource());
659                let index = self
660                    .result
661                    .trampolines
662                    .push((*ty, dfg::Trampoline::ResourceRep(id)));
663                frame.funcs.push(dfg::CoreDef::Trampoline(index));
664            }
665            ResourceDrop(id, ty) => {
666                let id = types.resource_id(id.resource());
667                let index = self
668                    .result
669                    .trampolines
670                    .push((*ty, dfg::Trampoline::ResourceDrop(id)));
671                frame.funcs.push(dfg::CoreDef::Trampoline(index));
672            }
673            BackpressureSet { func } => {
674                let index = self.result.trampolines.push((
675                    *func,
676                    dfg::Trampoline::BackpressureSet {
677                        instance: frame.instance,
678                    },
679                ));
680                frame.funcs.push(dfg::CoreDef::Trampoline(index));
681            }
682            TaskReturn {
683                func,
684                result,
685                options,
686            } => {
687                let results = result
688                    .iter()
689                    .map(|ty| types.valtype(frame.translation.types_ref(), ty))
690                    .collect::<Result<_>>()?;
691                let results = types.new_tuple_type(results);
692                let options = self.adapter_options(frame, types, options);
693                let options = self.canonical_options(options);
694                let index = self
695                    .result
696                    .trampolines
697                    .push((*func, dfg::Trampoline::TaskReturn { results, options }));
698                frame.funcs.push(dfg::CoreDef::Trampoline(index));
699            }
700            WaitableSetNew { func } => {
701                let index = self.result.trampolines.push((
702                    *func,
703                    dfg::Trampoline::WaitableSetNew {
704                        instance: frame.instance,
705                    },
706                ));
707                frame.funcs.push(dfg::CoreDef::Trampoline(index));
708            }
709            WaitableSetWait {
710                func,
711                async_,
712                memory,
713            } => {
714                let (memory, _) = self.memory(frame, types, *memory);
715                let memory = self.result.memories.push(memory);
716                let index = self.result.trampolines.push((
717                    *func,
718                    dfg::Trampoline::WaitableSetWait {
719                        instance: frame.instance,
720                        async_: *async_,
721                        memory,
722                    },
723                ));
724                frame.funcs.push(dfg::CoreDef::Trampoline(index));
725            }
726            WaitableSetPoll {
727                func,
728                async_,
729                memory,
730            } => {
731                let (memory, _) = self.memory(frame, types, *memory);
732                let memory = self.result.memories.push(memory);
733                let index = self.result.trampolines.push((
734                    *func,
735                    dfg::Trampoline::WaitableSetPoll {
736                        instance: frame.instance,
737                        async_: *async_,
738                        memory,
739                    },
740                ));
741                frame.funcs.push(dfg::CoreDef::Trampoline(index));
742            }
743            WaitableSetDrop { func } => {
744                let index = self.result.trampolines.push((
745                    *func,
746                    dfg::Trampoline::WaitableSetDrop {
747                        instance: frame.instance,
748                    },
749                ));
750                frame.funcs.push(dfg::CoreDef::Trampoline(index));
751            }
752            WaitableJoin { func } => {
753                let index = self.result.trampolines.push((
754                    *func,
755                    dfg::Trampoline::WaitableJoin {
756                        instance: frame.instance,
757                    },
758                ));
759                frame.funcs.push(dfg::CoreDef::Trampoline(index));
760            }
761            Yield { func, async_ } => {
762                let index = self
763                    .result
764                    .trampolines
765                    .push((*func, dfg::Trampoline::Yield { async_: *async_ }));
766                frame.funcs.push(dfg::CoreDef::Trampoline(index));
767            }
768            SubtaskDrop { func } => {
769                let index = self.result.trampolines.push((
770                    *func,
771                    dfg::Trampoline::SubtaskDrop {
772                        instance: frame.instance,
773                    },
774                ));
775                frame.funcs.push(dfg::CoreDef::Trampoline(index));
776            }
777            StreamNew { ty, func } => {
778                let InterfaceType::Stream(ty) =
779                    types.defined_type(frame.translation.types_ref(), *ty)?
780                else {
781                    unreachable!()
782                };
783                let index = self
784                    .result
785                    .trampolines
786                    .push((*func, dfg::Trampoline::StreamNew { ty }));
787                frame.funcs.push(dfg::CoreDef::Trampoline(index));
788            }
789            StreamRead { ty, func, options } => {
790                let InterfaceType::Stream(ty) =
791                    types.defined_type(frame.translation.types_ref(), *ty)?
792                else {
793                    unreachable!()
794                };
795                let err_ctx_ty = types.error_context_table_type()?;
796                let options = self.adapter_options(frame, types, options);
797                let options = self.canonical_options(options);
798                let index = self.result.trampolines.push((
799                    *func,
800                    dfg::Trampoline::StreamRead {
801                        ty,
802                        err_ctx_ty,
803                        options,
804                    },
805                ));
806                frame.funcs.push(dfg::CoreDef::Trampoline(index));
807            }
808            StreamWrite { ty, func, options } => {
809                let InterfaceType::Stream(ty) =
810                    types.defined_type(frame.translation.types_ref(), *ty)?
811                else {
812                    unreachable!()
813                };
814                let options = self.adapter_options(frame, types, options);
815                let options = self.canonical_options(options);
816                let index = self
817                    .result
818                    .trampolines
819                    .push((*func, dfg::Trampoline::StreamWrite { ty, options }));
820                frame.funcs.push(dfg::CoreDef::Trampoline(index));
821            }
822            StreamCancelRead { ty, func, async_ } => {
823                let InterfaceType::Stream(ty) =
824                    types.defined_type(frame.translation.types_ref(), *ty)?
825                else {
826                    unreachable!()
827                };
828                let index = self.result.trampolines.push((
829                    *func,
830                    dfg::Trampoline::StreamCancelRead {
831                        ty,
832                        async_: *async_,
833                    },
834                ));
835                frame.funcs.push(dfg::CoreDef::Trampoline(index));
836            }
837            StreamCancelWrite { ty, func, async_ } => {
838                let InterfaceType::Stream(ty) =
839                    types.defined_type(frame.translation.types_ref(), *ty)?
840                else {
841                    unreachable!()
842                };
843                let index = self.result.trampolines.push((
844                    *func,
845                    dfg::Trampoline::StreamCancelWrite {
846                        ty,
847                        async_: *async_,
848                    },
849                ));
850                frame.funcs.push(dfg::CoreDef::Trampoline(index));
851            }
852            StreamCloseReadable { ty, func } => {
853                let InterfaceType::Stream(ty) =
854                    types.defined_type(frame.translation.types_ref(), *ty)?
855                else {
856                    unreachable!()
857                };
858                let index = self
859                    .result
860                    .trampolines
861                    .push((*func, dfg::Trampoline::StreamCloseReadable { ty }));
862                frame.funcs.push(dfg::CoreDef::Trampoline(index));
863            }
864            StreamCloseWritable { ty, func } => {
865                let InterfaceType::Stream(ty) =
866                    types.defined_type(frame.translation.types_ref(), *ty)?
867                else {
868                    unreachable!()
869                };
870                let err_ctx_ty = types.error_context_table_type()?;
871                let index = self.result.trampolines.push((
872                    *func,
873                    dfg::Trampoline::StreamCloseWritable { ty, err_ctx_ty },
874                ));
875                frame.funcs.push(dfg::CoreDef::Trampoline(index));
876            }
877            FutureNew { ty, func } => {
878                let InterfaceType::Future(ty) =
879                    types.defined_type(frame.translation.types_ref(), *ty)?
880                else {
881                    unreachable!()
882                };
883                let index = self
884                    .result
885                    .trampolines
886                    .push((*func, dfg::Trampoline::FutureNew { ty }));
887                frame.funcs.push(dfg::CoreDef::Trampoline(index));
888            }
889            FutureRead { ty, func, options } => {
890                let InterfaceType::Future(ty) =
891                    types.defined_type(frame.translation.types_ref(), *ty)?
892                else {
893                    unreachable!()
894                };
895                let err_ctx_ty = types.error_context_table_type()?;
896                let options = self.adapter_options(frame, types, options);
897                let options = self.canonical_options(options);
898                let index = self.result.trampolines.push((
899                    *func,
900                    dfg::Trampoline::FutureRead {
901                        ty,
902                        err_ctx_ty,
903                        options,
904                    },
905                ));
906                frame.funcs.push(dfg::CoreDef::Trampoline(index));
907            }
908            FutureWrite { ty, func, options } => {
909                let InterfaceType::Future(ty) =
910                    types.defined_type(frame.translation.types_ref(), *ty)?
911                else {
912                    unreachable!()
913                };
914                let options = self.adapter_options(frame, types, options);
915                let options = self.canonical_options(options);
916                let index = self
917                    .result
918                    .trampolines
919                    .push((*func, dfg::Trampoline::FutureWrite { ty, options }));
920                frame.funcs.push(dfg::CoreDef::Trampoline(index));
921            }
922            FutureCancelRead { ty, func, async_ } => {
923                let InterfaceType::Future(ty) =
924                    types.defined_type(frame.translation.types_ref(), *ty)?
925                else {
926                    unreachable!()
927                };
928                let index = self.result.trampolines.push((
929                    *func,
930                    dfg::Trampoline::FutureCancelRead {
931                        ty,
932                        async_: *async_,
933                    },
934                ));
935                frame.funcs.push(dfg::CoreDef::Trampoline(index));
936            }
937            FutureCancelWrite { ty, func, async_ } => {
938                let InterfaceType::Future(ty) =
939                    types.defined_type(frame.translation.types_ref(), *ty)?
940                else {
941                    unreachable!()
942                };
943                let index = self.result.trampolines.push((
944                    *func,
945                    dfg::Trampoline::FutureCancelWrite {
946                        ty,
947                        async_: *async_,
948                    },
949                ));
950                frame.funcs.push(dfg::CoreDef::Trampoline(index));
951            }
952            FutureCloseReadable { ty, func } => {
953                let InterfaceType::Future(ty) =
954                    types.defined_type(frame.translation.types_ref(), *ty)?
955                else {
956                    unreachable!()
957                };
958                let index = self
959                    .result
960                    .trampolines
961                    .push((*func, dfg::Trampoline::FutureCloseReadable { ty }));
962                frame.funcs.push(dfg::CoreDef::Trampoline(index));
963            }
964            FutureCloseWritable { ty, func } => {
965                let InterfaceType::Future(ty) =
966                    types.defined_type(frame.translation.types_ref(), *ty)?
967                else {
968                    unreachable!()
969                };
970                let err_ctx_ty = types.error_context_table_type()?;
971                let index = self.result.trampolines.push((
972                    *func,
973                    dfg::Trampoline::FutureCloseWritable { ty, err_ctx_ty },
974                ));
975                frame.funcs.push(dfg::CoreDef::Trampoline(index));
976            }
977            ErrorContextNew { func, options } => {
978                let ty = types.error_context_table_type()?;
979                let options = self.adapter_options(frame, types, options);
980                let options = self.canonical_options(options);
981                let index = self
982                    .result
983                    .trampolines
984                    .push((*func, dfg::Trampoline::ErrorContextNew { ty, options }));
985                frame.funcs.push(dfg::CoreDef::Trampoline(index));
986            }
987            ErrorContextDebugMessage { func, options } => {
988                let ty = types.error_context_table_type()?;
989                let options = self.adapter_options(frame, types, options);
990                let options = self.canonical_options(options);
991                let index = self.result.trampolines.push((
992                    *func,
993                    dfg::Trampoline::ErrorContextDebugMessage { ty, options },
994                ));
995                frame.funcs.push(dfg::CoreDef::Trampoline(index));
996            }
997            ErrorContextDrop { func } => {
998                let ty = types.error_context_table_type()?;
999                let index = self
1000                    .result
1001                    .trampolines
1002                    .push((*func, dfg::Trampoline::ErrorContextDrop { ty }));
1003                frame.funcs.push(dfg::CoreDef::Trampoline(index));
1004            }
1005
1006            ModuleStatic(idx, ty) => {
1007                frame.modules.push(ModuleDef::Static(*idx, *ty));
1008            }
1009
1010            // Instantiation of a module is one of the meatier initializers that
1011            // we'll generate. The main magic here is that for a statically
1012            // known module we can order the imports as a list to exactly what
1013            // the static module needs to be instantiated. For imported modules,
1014            // however, the runtime string resolution must happen at runtime so
1015            // that is deferred here by organizing the arguments as a two-layer
1016            // `IndexMap` of what we're providing.
1017            //
1018            // In both cases though a new `RuntimeInstanceIndex` is allocated
1019            // and an initializer is recorded to indicate that it's being
1020            // instantiated.
1021            ModuleInstantiate(module, args) => {
1022                let instance_module;
1023                let init = match &frame.modules[*module] {
1024                    ModuleDef::Static(idx, _ty) => {
1025                        let mut defs = Vec::new();
1026                        for (module, name, _ty) in self.nested_modules[*idx].module.imports() {
1027                            let instance = args[module];
1028                            defs.push(
1029                                self.core_def_of_module_instance_export(frame, instance, name),
1030                            );
1031                        }
1032                        instance_module = InstanceModule::Static(*idx);
1033                        dfg::Instance::Static(*idx, defs.into())
1034                    }
1035                    ModuleDef::Import(path, ty) => {
1036                        let mut defs = IndexMap::new();
1037                        for ((module, name), _) in types[*ty].imports.iter() {
1038                            let instance = args[module.as_str()];
1039                            let def =
1040                                self.core_def_of_module_instance_export(frame, instance, name);
1041                            defs.entry(module.to_string())
1042                                .or_insert(IndexMap::new())
1043                                .insert(name.to_string(), def);
1044                        }
1045                        let index = self.runtime_import(path);
1046                        instance_module = InstanceModule::Import(*ty);
1047                        dfg::Instance::Import(index, defs)
1048                    }
1049                };
1050
1051                let idx = self.result.instances.push(init);
1052                self.result
1053                    .side_effects
1054                    .push(dfg::SideEffect::Instance(idx));
1055                let idx2 = self.runtime_instances.push(instance_module);
1056                assert_eq!(idx, idx2);
1057                frame
1058                    .module_instances
1059                    .push(ModuleInstanceDef::Instantiated(idx, *module));
1060            }
1061
1062            ModuleSynthetic(map) => {
1063                frame
1064                    .module_instances
1065                    .push(ModuleInstanceDef::Synthetic(map));
1066            }
1067
1068            // This is one of the stages of the "magic" of implementing outer
1069            // aliases to components and modules. For more information on this
1070            // see the documentation on `LexicalScope`. This stage of the
1071            // implementation of outer aliases is where the `ClosedOverVars` is
1072            // transformed into a `ComponentClosure` state using the current
1073            // `InlinerFrame`'s state. This will capture the "runtime" state of
1074            // outer components and upvars and such naturally as part of the
1075            // inlining process.
1076            ComponentStatic(index, vars) => {
1077                frame.components.push(ComponentDef {
1078                    index: *index,
1079                    closure: ComponentClosure {
1080                        modules: vars
1081                            .modules
1082                            .iter()
1083                            .map(|(_, m)| frame.closed_over_module(m))
1084                            .collect(),
1085                        components: vars
1086                            .components
1087                            .iter()
1088                            .map(|(_, m)| frame.closed_over_component(m))
1089                            .collect(),
1090                    },
1091                });
1092            }
1093
1094            // Like module instantiation is this is a "meaty" part, and don't be
1095            // fooled by the relative simplicity of this case. This is
1096            // implemented primarily by the `Inliner` structure and the design
1097            // of this entire module, so the "easy" step here is to simply
1098            // create a new inliner frame and return it to get pushed onto the
1099            // stack.
1100            ComponentInstantiate(component, args, ty) => {
1101                let component: &ComponentDef<'a> = &frame.components[*component];
1102                let index = RuntimeComponentInstanceIndex::from_u32(
1103                    self.result.num_runtime_component_instances,
1104                );
1105                self.result.num_runtime_component_instances += 1;
1106                let frame = InlinerFrame::new(
1107                    index,
1108                    &self.nested_components[component.index],
1109                    component.closure.clone(),
1110                    args.iter()
1111                        .map(|(name, item)| Ok((*name, frame.item(*item, types)?)))
1112                        .collect::<Result<_>>()?,
1113                    Some(*ty),
1114                );
1115                return Ok(Some(frame));
1116            }
1117
1118            ComponentSynthetic(map, ty) => {
1119                let items = map
1120                    .iter()
1121                    .map(|(name, index)| Ok((*name, frame.item(*index, types)?)))
1122                    .collect::<Result<_>>()?;
1123                let types_ref = frame.translation.types_ref();
1124                let ty = types.convert_instance(types_ref, *ty)?;
1125                frame
1126                    .component_instances
1127                    .push(ComponentInstanceDef::Items(items, ty));
1128            }
1129
1130            // Core wasm aliases, this and the cases below, are creating
1131            // `CoreExport` items primarily to insert into the index space so we
1132            // can create a unique identifier pointing to each core wasm export
1133            // with the instance and relevant index/name as necessary.
1134            AliasExportFunc(instance, name) => {
1135                frame
1136                    .funcs
1137                    .push(self.core_def_of_module_instance_export(frame, *instance, *name));
1138            }
1139
1140            AliasExportTable(instance, name) => {
1141                frame.tables.push(
1142                    match self.core_def_of_module_instance_export(frame, *instance, *name) {
1143                        dfg::CoreDef::Export(e) => e,
1144                        _ => unreachable!(),
1145                    },
1146                );
1147            }
1148
1149            AliasExportGlobal(instance, name) => {
1150                frame.globals.push(
1151                    match self.core_def_of_module_instance_export(frame, *instance, *name) {
1152                        dfg::CoreDef::Export(e) => e,
1153                        _ => unreachable!(),
1154                    },
1155                );
1156            }
1157
1158            AliasExportMemory(instance, name) => {
1159                frame.memories.push(
1160                    match self.core_def_of_module_instance_export(frame, *instance, *name) {
1161                        dfg::CoreDef::Export(e) => e,
1162                        _ => unreachable!(),
1163                    },
1164                );
1165            }
1166
1167            AliasComponentExport(instance, name) => {
1168                match &frame.component_instances[*instance] {
1169                    // Aliasing an export from an imported instance means that
1170                    // we're extending the `ImportPath` by one name, represented
1171                    // with the clone + push here. Afterwards an appropriate
1172                    // item is then pushed in the relevant index space.
1173                    ComponentInstanceDef::Import(path, ty) => {
1174                        let path = path.push(*name);
1175                        let def = ComponentItemDef::from_import(path, types[*ty].exports[*name])?;
1176                        frame.push_item(def);
1177                    }
1178
1179                    // Given a component instance which was either created
1180                    // through instantiation of a component or through a
1181                    // synthetic renaming of items we just schlep around the
1182                    // definitions of various items here.
1183                    ComponentInstanceDef::Items(map, _) => frame.push_item(map[*name].clone()),
1184                }
1185            }
1186
1187            // For more information on these see `LexicalScope` but otherwise
1188            // this is just taking a closed over variable and inserting the
1189            // actual definition into the local index space since this
1190            // represents an outer alias to a module/component
1191            AliasModule(idx) => {
1192                frame.modules.push(frame.closed_over_module(idx));
1193            }
1194            AliasComponent(idx) => {
1195                frame.components.push(frame.closed_over_component(idx));
1196            }
1197
1198            Export(item) => match item {
1199                ComponentItem::Func(i) => {
1200                    frame
1201                        .component_funcs
1202                        .push(frame.component_funcs[*i].clone());
1203                }
1204                ComponentItem::Module(i) => {
1205                    frame.modules.push(frame.modules[*i].clone());
1206                }
1207                ComponentItem::Component(i) => {
1208                    frame.components.push(frame.components[*i].clone());
1209                }
1210                ComponentItem::ComponentInstance(i) => {
1211                    frame
1212                        .component_instances
1213                        .push(frame.component_instances[*i].clone());
1214                }
1215
1216                // Type index spaces aren't maintained during this inlining pass
1217                // so ignore this.
1218                ComponentItem::Type(_) => {}
1219            },
1220        }
1221
1222        Ok(None)
1223    }
1224
1225    /// "Commits" a path of an import to an actual index which is something that
1226    /// will be calculated at runtime.
1227    ///
1228    /// Note that the cost of calculating an item for a `RuntimeImportIndex` at
1229    /// runtime is amortized with an `InstancePre` which represents "all the
1230    /// runtime imports are lined up" and after that no more name resolution is
1231    /// necessary.
1232    fn runtime_import(&mut self, path: &ImportPath<'a>) -> RuntimeImportIndex {
1233        *self
1234            .import_path_interner
1235            .entry(path.clone())
1236            .or_insert_with(|| {
1237                self.result.imports.push((
1238                    path.index,
1239                    path.path.iter().map(|s| s.to_string()).collect(),
1240                ))
1241            })
1242    }
1243
1244    /// Returns the `CoreDef`, the canonical definition for a core wasm item,
1245    /// for the export `name` of `instance` within `frame`.
1246    fn core_def_of_module_instance_export(
1247        &self,
1248        frame: &InlinerFrame<'a>,
1249        instance: ModuleInstanceIndex,
1250        name: &'a str,
1251    ) -> dfg::CoreDef {
1252        match &frame.module_instances[instance] {
1253            // Instantiations of a statically known module means that we can
1254            // refer to the exported item by a precise index, skipping name
1255            // lookups at runtime.
1256            //
1257            // Instantiations of an imported module, however, must do name
1258            // lookups at runtime since we don't know the structure ahead of
1259            // time here.
1260            ModuleInstanceDef::Instantiated(instance, module) => {
1261                let item = match frame.modules[*module] {
1262                    ModuleDef::Static(idx, _ty) => {
1263                        let entity = self.nested_modules[idx].module.exports[name];
1264                        ExportItem::Index(entity)
1265                    }
1266                    ModuleDef::Import(..) => ExportItem::Name(name.to_string()),
1267                };
1268                dfg::CoreExport {
1269                    instance: *instance,
1270                    item,
1271                }
1272                .into()
1273            }
1274
1275            // This is a synthetic instance so the canonical definition of the
1276            // original item is returned.
1277            ModuleInstanceDef::Synthetic(instance) => match instance[name] {
1278                EntityIndex::Function(i) => frame.funcs[i].clone(),
1279                EntityIndex::Table(i) => frame.tables[i].clone().into(),
1280                EntityIndex::Global(i) => frame.globals[i].clone().into(),
1281                EntityIndex::Memory(i) => frame.memories[i].clone().into(),
1282                EntityIndex::Tag(_) => todo!(), // FIXME: #10252 support for tags in the component model
1283            },
1284        }
1285    }
1286
1287    fn memory(
1288        &mut self,
1289        frame: &InlinerFrame<'a>,
1290        types: &ComponentTypesBuilder,
1291        memory: MemoryIndex,
1292    ) -> (dfg::CoreExport<MemoryIndex>, bool) {
1293        let memory = frame.memories[memory].clone().map_index(|i| match i {
1294            EntityIndex::Memory(i) => i,
1295            _ => unreachable!(),
1296        });
1297        let memory64 = match &self.runtime_instances[memory.instance] {
1298            InstanceModule::Static(idx) => match &memory.item {
1299                ExportItem::Index(i) => {
1300                    let ty = &self.nested_modules[*idx].module.memories[*i];
1301                    match ty.idx_type {
1302                        IndexType::I32 => false,
1303                        IndexType::I64 => true,
1304                    }
1305                }
1306                ExportItem::Name(_) => unreachable!(),
1307            },
1308            InstanceModule::Import(ty) => match &memory.item {
1309                ExportItem::Name(name) => match types[*ty].exports[name] {
1310                    EntityType::Memory(m) => match m.idx_type {
1311                        IndexType::I32 => false,
1312                        IndexType::I64 => true,
1313                    },
1314                    _ => unreachable!(),
1315                },
1316                ExportItem::Index(_) => unreachable!(),
1317            },
1318        };
1319        (memory, memory64)
1320    }
1321
1322    /// Translates a `LocalCanonicalOptions` which indexes into the `frame`
1323    /// specified into a runtime representation.
1324    fn adapter_options(
1325        &mut self,
1326        frame: &InlinerFrame<'a>,
1327        types: &ComponentTypesBuilder,
1328        options: &LocalCanonicalOptions,
1329    ) -> AdapterOptions {
1330        let (memory, memory64) = options
1331            .memory
1332            .map(|i| {
1333                let (memory, memory64) = self.memory(frame, types, i);
1334                (Some(memory), memory64)
1335            })
1336            .unwrap_or((None, false));
1337        let realloc = options.realloc.map(|i| frame.funcs[i].clone());
1338        let callback = options.callback.map(|i| frame.funcs[i].clone());
1339        let post_return = options.post_return.map(|i| frame.funcs[i].clone());
1340        AdapterOptions {
1341            instance: frame.instance,
1342            string_encoding: options.string_encoding,
1343            memory,
1344            memory64,
1345            realloc,
1346            callback,
1347            post_return,
1348            async_: options.async_,
1349        }
1350    }
1351
1352    /// Translatees an `AdapterOptions` into a `CanonicalOptions` where
1353    /// memories/functions are inserted into the global initializer list for
1354    /// use at runtime. This is only used for lowered host functions and lifted
1355    /// functions exported to the host.
1356    fn canonical_options(&mut self, options: AdapterOptions) -> dfg::CanonicalOptions {
1357        let memory = options
1358            .memory
1359            .map(|export| self.result.memories.push(export));
1360        let realloc = options.realloc.map(|def| self.result.reallocs.push(def));
1361        let callback = options.callback.map(|def| self.result.callbacks.push(def));
1362        let post_return = options
1363            .post_return
1364            .map(|def| self.result.post_returns.push(def));
1365        dfg::CanonicalOptions {
1366            instance: options.instance,
1367            string_encoding: options.string_encoding,
1368            memory,
1369            realloc,
1370            callback,
1371            post_return,
1372            async_: options.async_,
1373        }
1374    }
1375
1376    fn record_export(
1377        &mut self,
1378        name: &str,
1379        def: ComponentItemDef<'a>,
1380        types: &'a ComponentTypesBuilder,
1381        map: &mut IndexMap<String, dfg::Export>,
1382    ) -> Result<()> {
1383        let export = match def {
1384            // Exported modules are currently saved in a `PrimaryMap`, at
1385            // runtime, so an index (`RuntimeModuleIndex`) is assigned here and
1386            // then an initializer is recorded about where the module comes
1387            // from.
1388            ComponentItemDef::Module(module) => match module {
1389                ModuleDef::Static(index, ty) => dfg::Export::ModuleStatic { ty, index },
1390                ModuleDef::Import(path, ty) => dfg::Export::ModuleImport {
1391                    ty,
1392                    import: self.runtime_import(&path),
1393                },
1394            },
1395
1396            ComponentItemDef::Func(func) => match func {
1397                // If this is a lifted function from something lowered in this
1398                // component then the configured options are plumbed through
1399                // here.
1400                ComponentFuncDef::Lifted { ty, func, options } => {
1401                    let options = self.canonical_options(options);
1402                    dfg::Export::LiftedFunction { ty, func, options }
1403                }
1404
1405                // Currently reexported functions from an import are not
1406                // supported. Being able to actually call these functions is
1407                // somewhat tricky and needs something like temporary scratch
1408                // space that isn't implemented.
1409                ComponentFuncDef::Import(_) => {
1410                    bail!("component export `{name}` is a reexport of an imported function which is not implemented")
1411                }
1412            },
1413
1414            ComponentItemDef::Instance(instance) => {
1415                let mut exports = IndexMap::new();
1416                match instance {
1417                    // If this instance is one that was originally imported by
1418                    // the component itself then the imports are translated here
1419                    // by converting to a `ComponentItemDef` and then
1420                    // recursively recording the export as a reexport.
1421                    //
1422                    // Note that for now this would only work with
1423                    // module-exporting instances.
1424                    ComponentInstanceDef::Import(path, ty) => {
1425                        for (name, ty) in types[ty].exports.iter() {
1426                            let path = path.push(name);
1427                            let def = ComponentItemDef::from_import(path, *ty)?;
1428                            self.record_export(name, def, types, &mut exports)?;
1429                        }
1430                        dfg::Export::Instance { ty, exports }
1431                    }
1432
1433                    // An exported instance which is itself a bag of items is
1434                    // translated recursively here to our `exports` map which is
1435                    // the bag of items we're exporting.
1436                    ComponentInstanceDef::Items(map, ty) => {
1437                        for (name, def) in map {
1438                            self.record_export(name, def, types, &mut exports)?;
1439                        }
1440                        dfg::Export::Instance { ty, exports }
1441                    }
1442                }
1443            }
1444
1445            // FIXME(#4283) should make an official decision on whether this is
1446            // the final treatment of this or not.
1447            ComponentItemDef::Component(_) => {
1448                bail!("exporting a component from the root component is not supported")
1449            }
1450
1451            ComponentItemDef::Type(def) => dfg::Export::Type(def),
1452        };
1453
1454        map.insert(name.to_string(), export);
1455        Ok(())
1456    }
1457}
1458
1459impl<'a> InlinerFrame<'a> {
1460    fn new(
1461        instance: RuntimeComponentInstanceIndex,
1462        translation: &'a Translation<'a>,
1463        closure: ComponentClosure<'a>,
1464        args: HashMap<&'a str, ComponentItemDef<'a>>,
1465        instance_ty: Option<ComponentInstanceTypeId>,
1466    ) -> Self {
1467        // FIXME: should iterate over the initializers of `translation` and
1468        // calculate the size of each index space to use `with_capacity` for
1469        // all the maps below. Given that doing such would be wordy and compile
1470        // time is otherwise not super crucial it's not done at this time.
1471        InlinerFrame {
1472            instance,
1473            translation,
1474            closure,
1475            args,
1476            instance_ty,
1477            initializers: translation.initializers.iter(),
1478
1479            funcs: Default::default(),
1480            memories: Default::default(),
1481            tables: Default::default(),
1482            globals: Default::default(),
1483
1484            component_instances: Default::default(),
1485            component_funcs: Default::default(),
1486            module_instances: Default::default(),
1487            components: Default::default(),
1488            modules: Default::default(),
1489        }
1490    }
1491
1492    fn item(
1493        &self,
1494        index: ComponentItem,
1495        types: &mut ComponentTypesBuilder,
1496    ) -> Result<ComponentItemDef<'a>> {
1497        Ok(match index {
1498            ComponentItem::Func(i) => ComponentItemDef::Func(self.component_funcs[i].clone()),
1499            ComponentItem::Component(i) => ComponentItemDef::Component(self.components[i].clone()),
1500            ComponentItem::ComponentInstance(i) => {
1501                ComponentItemDef::Instance(self.component_instances[i].clone())
1502            }
1503            ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()),
1504            ComponentItem::Type(t) => {
1505                let types_ref = self.translation.types_ref();
1506                ComponentItemDef::Type(types.convert_type(types_ref, t)?)
1507            }
1508        })
1509    }
1510
1511    /// Pushes the component `item` definition provided into the appropriate
1512    /// index space within this component.
1513    fn push_item(&mut self, item: ComponentItemDef<'a>) {
1514        match item {
1515            ComponentItemDef::Func(i) => {
1516                self.component_funcs.push(i);
1517            }
1518            ComponentItemDef::Module(i) => {
1519                self.modules.push(i);
1520            }
1521            ComponentItemDef::Component(i) => {
1522                self.components.push(i);
1523            }
1524            ComponentItemDef::Instance(i) => {
1525                self.component_instances.push(i);
1526            }
1527
1528            // In short, type definitions aren't tracked here.
1529            //
1530            // The longer form explanation for this is that structural types
1531            // like lists and records don't need to be tracked at all and the
1532            // only significant type which needs tracking is resource types
1533            // themselves. Resource types, however, are tracked within the
1534            // `ResourcesBuilder` state rather than an `InlinerFrame` so they're
1535            // ignored here as well. The general reason for that is that type
1536            // information is everywhere and this `InlinerFrame` is not
1537            // everywhere so it seemed like it would make sense to split the
1538            // two.
1539            //
1540            // Note though that this case is actually frequently hit, so it
1541            // can't be `unreachable!()`. Instead callers are responsible for
1542            // handling this appropriately with respect to resources.
1543            ComponentItemDef::Type(_ty) => {}
1544        }
1545    }
1546
1547    fn closed_over_module(&self, index: &ClosedOverModule) -> ModuleDef<'a> {
1548        match *index {
1549            ClosedOverModule::Local(i) => self.modules[i].clone(),
1550            ClosedOverModule::Upvar(i) => self.closure.modules[i].clone(),
1551        }
1552    }
1553
1554    fn closed_over_component(&self, index: &ClosedOverComponent) -> ComponentDef<'a> {
1555        match *index {
1556            ClosedOverComponent::Local(i) => self.components[i].clone(),
1557            ClosedOverComponent::Upvar(i) => self.closure.components[i].clone(),
1558        }
1559    }
1560
1561    /// Completes the instantiation of a subcomponent and records type
1562    /// information for the instance that was produced.
1563    ///
1564    /// This method is invoked when an `InlinerFrame` finishes for a
1565    /// subcomponent. The `def` provided represents the instance that was
1566    /// produced from instantiation, and `ty` is the wasmparser-defined type of
1567    /// the instance produced.
1568    ///
1569    /// The purpose of this method is to record type information about resources
1570    /// in the instance produced. In the component model all instantiations of a
1571    /// component produce fresh new types for all resources which are unequal to
1572    /// all prior resources. This means that if wasmparser's `ty` type
1573    /// information references a unique resource within `def` that has never
1574    /// been registered before then that means it's a defined resource within
1575    /// the component that was just instantiated (as opposed to an imported
1576    /// resource which was reexported).
1577    ///
1578    /// Further type translation after this instantiation can refer to these
1579    /// resource types and a mapping from those types to the wasmtime-internal
1580    /// types is required, so this method builds up those mappings.
1581    ///
1582    /// Essentially what happens here is that the `ty` type is registered and
1583    /// any new unique resources are registered so new tables can be introduced
1584    /// along with origin information about the actual underlying resource type
1585    /// and which component instantiated it.
1586    fn finish_instantiate(
1587        &mut self,
1588        exports: IndexMap<&'a str, ComponentItemDef<'a>>,
1589        ty: ComponentInstanceTypeId,
1590        types: &mut ComponentTypesBuilder,
1591    ) -> Result<()> {
1592        let types_ref = self.translation.types_ref();
1593        {
1594            let (resources, types) = types.resources_mut_and_types();
1595            let mut path = Vec::new();
1596            resources.register_component_entity_type(
1597                &types_ref,
1598                ComponentEntityType::Instance(ty),
1599                &mut path,
1600                &mut |path| match path {
1601                    [] => unreachable!(),
1602                    [name, rest @ ..] => exports[name].lookup_resource(rest, types),
1603                },
1604            );
1605        }
1606        let ty = types.convert_instance(types_ref, ty)?;
1607        let def = ComponentInstanceDef::Items(exports, ty);
1608        let arg = ComponentItemDef::Instance(def);
1609        self.push_item(arg);
1610        Ok(())
1611    }
1612}
1613
1614impl<'a> ImportPath<'a> {
1615    fn root(index: ImportIndex) -> ImportPath<'a> {
1616        ImportPath {
1617            index,
1618            path: Vec::new(),
1619        }
1620    }
1621
1622    fn push(&self, s: impl Into<Cow<'a, str>>) -> ImportPath<'a> {
1623        let mut new = self.clone();
1624        new.path.push(s.into());
1625        new
1626    }
1627}
1628
1629impl<'a> ComponentItemDef<'a> {
1630    fn from_import(path: ImportPath<'a>, ty: TypeDef) -> Result<ComponentItemDef<'a>> {
1631        let item = match ty {
1632            TypeDef::Module(ty) => ComponentItemDef::Module(ModuleDef::Import(path, ty)),
1633            TypeDef::ComponentInstance(ty) => {
1634                ComponentItemDef::Instance(ComponentInstanceDef::Import(path, ty))
1635            }
1636            TypeDef::ComponentFunc(_ty) => ComponentItemDef::Func(ComponentFuncDef::Import(path)),
1637            // FIXME(#4283) should commit one way or another to how this
1638            // should be treated.
1639            TypeDef::Component(_ty) => bail!("root-level component imports are not supported"),
1640            TypeDef::Interface(_) | TypeDef::Resource(_) => ComponentItemDef::Type(ty),
1641            TypeDef::CoreFunc(_) => unreachable!(),
1642        };
1643        Ok(item)
1644    }
1645
1646    /// Walks the `path` within `self` to find a resource at that path.
1647    ///
1648    /// This method is used when resources are found within wasmparser's type
1649    /// information and they need to be correlated with actual concrete
1650    /// definitions from this inlining pass. The `path` here is a list of
1651    /// instance export names (or empty) to walk to reach down into the final
1652    /// definition which should refer to a resource itself.
1653    fn lookup_resource(&self, path: &[&str], types: &ComponentTypes) -> ResourceIndex {
1654        let mut cur = self.clone();
1655
1656        // Each element of `path` represents unwrapping a layer of an instance
1657        // type, so handle those here by updating `cur` iteratively.
1658        for element in path.iter().copied() {
1659            let instance = match cur {
1660                ComponentItemDef::Instance(def) => def,
1661                _ => unreachable!(),
1662            };
1663            cur = match instance {
1664                // If this instance is a "bag of things" then this is as easy as
1665                // looking up the name in the bag of names.
1666                ComponentInstanceDef::Items(names, _) => names[element].clone(),
1667
1668                // If, however, this instance is an imported instance then this
1669                // is a further projection within the import with one more path
1670                // element. The `types` type information is used to lookup the
1671                // type of `element` within the instance type, and that's used
1672                // in conjunction with a one-longer `path` to produce a new item
1673                // definition.
1674                ComponentInstanceDef::Import(path, ty) => {
1675                    ComponentItemDef::from_import(path.push(element), types[ty].exports[element])
1676                        .unwrap()
1677                }
1678            };
1679        }
1680
1681        // Once `path` has been iterated over it must be the case that the final
1682        // item is a resource type, in which case a lookup can be performed.
1683        match cur {
1684            ComponentItemDef::Type(TypeDef::Resource(idx)) => types[idx].ty,
1685            _ => unreachable!(),
1686        }
1687    }
1688}
1689
1690enum InstanceModule {
1691    Static(StaticModuleIndex),
1692    Import(TypeModuleIndex),
1693}