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