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.result.trampolines.push((
654                    *ty,
655                    dfg::Trampoline::ResourceNew {
656                        instance: frame.instance,
657                        ty: id,
658                    },
659                ));
660                frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));
661            }
662            ResourceRep(id, ty) => {
663                let id = types.resource_id(id.resource());
664                let index = self.result.trampolines.push((
665                    *ty,
666                    dfg::Trampoline::ResourceRep {
667                        instance: frame.instance,
668                        ty: id,
669                    },
670                ));
671                frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));
672            }
673            ResourceDrop(id, ty) => {
674                let id = types.resource_id(id.resource());
675                let index = self.result.trampolines.push((
676                    *ty,
677                    dfg::Trampoline::ResourceDrop {
678                        instance: frame.instance,
679                        ty: id,
680                    },
681                ));
682                frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));
683            }
684            BackpressureSet { func } => {
685                let index = self.result.trampolines.push((
686                    *func,
687                    dfg::Trampoline::BackpressureSet {
688                        instance: frame.instance,
689                    },
690                ));
691                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
692            }
693            BackpressureInc { func } => {
694                let index = self.result.trampolines.push((
695                    *func,
696                    dfg::Trampoline::BackpressureInc {
697                        instance: frame.instance,
698                    },
699                ));
700                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
701            }
702            BackpressureDec { func } => {
703                let index = self.result.trampolines.push((
704                    *func,
705                    dfg::Trampoline::BackpressureDec {
706                        instance: frame.instance,
707                    },
708                ));
709                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
710            }
711            TaskReturn { result, options } => {
712                let results = result
713                    .iter()
714                    .map(|ty| types.valtype(frame.translation.types_ref(), ty))
715                    .collect::<Result<_>>()?;
716                let results = types.new_tuple_type(results);
717                let func = options.core_type;
718                let options = self.adapter_options(frame, types, options);
719                let options = self.canonical_options(options);
720                let index = self.result.trampolines.push((
721                    func,
722                    dfg::Trampoline::TaskReturn {
723                        instance: frame.instance,
724                        results,
725                        options,
726                    },
727                ));
728                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
729            }
730            TaskCancel { func } => {
731                let index = self.result.trampolines.push((
732                    *func,
733                    dfg::Trampoline::TaskCancel {
734                        instance: frame.instance,
735                    },
736                ));
737                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
738            }
739            WaitableSetNew { func } => {
740                let index = self.result.trampolines.push((
741                    *func,
742                    dfg::Trampoline::WaitableSetNew {
743                        instance: frame.instance,
744                    },
745                ));
746                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
747            }
748            WaitableSetWait { options } => {
749                let func = options.core_type;
750                let options = self.adapter_options(frame, types, options);
751                let options = self.canonical_options(options);
752                let index = self.result.trampolines.push((
753                    func,
754                    dfg::Trampoline::WaitableSetWait {
755                        instance: frame.instance,
756                        options,
757                    },
758                ));
759                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
760            }
761            WaitableSetPoll { options } => {
762                let func = options.core_type;
763                let options = self.adapter_options(frame, types, options);
764                let options = self.canonical_options(options);
765                let index = self.result.trampolines.push((
766                    func,
767                    dfg::Trampoline::WaitableSetPoll {
768                        instance: frame.instance,
769                        options,
770                    },
771                ));
772                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
773            }
774            WaitableSetDrop { func } => {
775                let index = self.result.trampolines.push((
776                    *func,
777                    dfg::Trampoline::WaitableSetDrop {
778                        instance: frame.instance,
779                    },
780                ));
781                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
782            }
783            WaitableJoin { func } => {
784                let index = self.result.trampolines.push((
785                    *func,
786                    dfg::Trampoline::WaitableJoin {
787                        instance: frame.instance,
788                    },
789                ));
790                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
791            }
792            ThreadYield { func, cancellable } => {
793                let index = self.result.trampolines.push((
794                    *func,
795                    dfg::Trampoline::ThreadYield {
796                        instance: frame.instance,
797                        cancellable: *cancellable,
798                    },
799                ));
800                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
801            }
802            SubtaskDrop { func } => {
803                let index = self.result.trampolines.push((
804                    *func,
805                    dfg::Trampoline::SubtaskDrop {
806                        instance: frame.instance,
807                    },
808                ));
809                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
810            }
811            SubtaskCancel { func, async_ } => {
812                let index = self.result.trampolines.push((
813                    *func,
814                    dfg::Trampoline::SubtaskCancel {
815                        instance: frame.instance,
816                        async_: *async_,
817                    },
818                ));
819                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
820            }
821            StreamNew { ty, func } => {
822                let InterfaceType::Stream(ty) =
823                    types.defined_type(frame.translation.types_ref(), *ty)?
824                else {
825                    unreachable!()
826                };
827                let index = self.result.trampolines.push((
828                    *func,
829                    dfg::Trampoline::StreamNew {
830                        instance: frame.instance,
831                        ty,
832                    },
833                ));
834                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
835            }
836            StreamRead { ty, options } => {
837                let InterfaceType::Stream(ty) =
838                    types.defined_type(frame.translation.types_ref(), *ty)?
839                else {
840                    unreachable!()
841                };
842                let func = options.core_type;
843                let options = self.adapter_options(frame, types, options);
844                let options = self.canonical_options(options);
845                let index = self.result.trampolines.push((
846                    func,
847                    dfg::Trampoline::StreamRead {
848                        instance: frame.instance,
849                        ty,
850                        options,
851                    },
852                ));
853                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
854            }
855            StreamWrite { ty, options } => {
856                let InterfaceType::Stream(ty) =
857                    types.defined_type(frame.translation.types_ref(), *ty)?
858                else {
859                    unreachable!()
860                };
861                let func = options.core_type;
862                let options = self.adapter_options(frame, types, options);
863                let options = self.canonical_options(options);
864                let index = self.result.trampolines.push((
865                    func,
866                    dfg::Trampoline::StreamWrite {
867                        instance: frame.instance,
868                        ty,
869                        options,
870                    },
871                ));
872                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
873            }
874            StreamCancelRead { ty, func, async_ } => {
875                let InterfaceType::Stream(ty) =
876                    types.defined_type(frame.translation.types_ref(), *ty)?
877                else {
878                    unreachable!()
879                };
880                let index = self.result.trampolines.push((
881                    *func,
882                    dfg::Trampoline::StreamCancelRead {
883                        instance: frame.instance,
884                        ty,
885                        async_: *async_,
886                    },
887                ));
888                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
889            }
890            StreamCancelWrite { ty, func, async_ } => {
891                let InterfaceType::Stream(ty) =
892                    types.defined_type(frame.translation.types_ref(), *ty)?
893                else {
894                    unreachable!()
895                };
896                let index = self.result.trampolines.push((
897                    *func,
898                    dfg::Trampoline::StreamCancelWrite {
899                        instance: frame.instance,
900                        ty,
901                        async_: *async_,
902                    },
903                ));
904                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
905            }
906            StreamDropReadable { ty, func } => {
907                let InterfaceType::Stream(ty) =
908                    types.defined_type(frame.translation.types_ref(), *ty)?
909                else {
910                    unreachable!()
911                };
912                let index = self.result.trampolines.push((
913                    *func,
914                    dfg::Trampoline::StreamDropReadable {
915                        instance: frame.instance,
916                        ty,
917                    },
918                ));
919                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
920            }
921            StreamDropWritable { ty, func } => {
922                let InterfaceType::Stream(ty) =
923                    types.defined_type(frame.translation.types_ref(), *ty)?
924                else {
925                    unreachable!()
926                };
927                let index = self.result.trampolines.push((
928                    *func,
929                    dfg::Trampoline::StreamDropWritable {
930                        instance: frame.instance,
931                        ty,
932                    },
933                ));
934                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
935            }
936            FutureNew { ty, func } => {
937                let InterfaceType::Future(ty) =
938                    types.defined_type(frame.translation.types_ref(), *ty)?
939                else {
940                    unreachable!()
941                };
942                let index = self.result.trampolines.push((
943                    *func,
944                    dfg::Trampoline::FutureNew {
945                        instance: frame.instance,
946                        ty,
947                    },
948                ));
949                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
950            }
951            FutureRead { ty, options } => {
952                let InterfaceType::Future(ty) =
953                    types.defined_type(frame.translation.types_ref(), *ty)?
954                else {
955                    unreachable!()
956                };
957                let func = options.core_type;
958                let options = self.adapter_options(frame, types, options);
959                let options = self.canonical_options(options);
960                let index = self.result.trampolines.push((
961                    func,
962                    dfg::Trampoline::FutureRead {
963                        instance: frame.instance,
964                        ty,
965                        options,
966                    },
967                ));
968                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
969            }
970            FutureWrite { ty, options } => {
971                let InterfaceType::Future(ty) =
972                    types.defined_type(frame.translation.types_ref(), *ty)?
973                else {
974                    unreachable!()
975                };
976                let func = options.core_type;
977                let options = self.adapter_options(frame, types, options);
978                let options = self.canonical_options(options);
979                let index = self.result.trampolines.push((
980                    func,
981                    dfg::Trampoline::FutureWrite {
982                        instance: frame.instance,
983                        ty,
984                        options,
985                    },
986                ));
987                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
988            }
989            FutureCancelRead { ty, func, async_ } => {
990                let InterfaceType::Future(ty) =
991                    types.defined_type(frame.translation.types_ref(), *ty)?
992                else {
993                    unreachable!()
994                };
995                let index = self.result.trampolines.push((
996                    *func,
997                    dfg::Trampoline::FutureCancelRead {
998                        instance: frame.instance,
999                        ty,
1000                        async_: *async_,
1001                    },
1002                ));
1003                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1004            }
1005            FutureCancelWrite { ty, func, async_ } => {
1006                let InterfaceType::Future(ty) =
1007                    types.defined_type(frame.translation.types_ref(), *ty)?
1008                else {
1009                    unreachable!()
1010                };
1011                let index = self.result.trampolines.push((
1012                    *func,
1013                    dfg::Trampoline::FutureCancelWrite {
1014                        instance: frame.instance,
1015                        ty,
1016                        async_: *async_,
1017                    },
1018                ));
1019                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1020            }
1021            FutureDropReadable { ty, func } => {
1022                let InterfaceType::Future(ty) =
1023                    types.defined_type(frame.translation.types_ref(), *ty)?
1024                else {
1025                    unreachable!()
1026                };
1027                let index = self.result.trampolines.push((
1028                    *func,
1029                    dfg::Trampoline::FutureDropReadable {
1030                        instance: frame.instance,
1031                        ty,
1032                    },
1033                ));
1034                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1035            }
1036            FutureDropWritable { ty, func } => {
1037                let InterfaceType::Future(ty) =
1038                    types.defined_type(frame.translation.types_ref(), *ty)?
1039                else {
1040                    unreachable!()
1041                };
1042                let index = self.result.trampolines.push((
1043                    *func,
1044                    dfg::Trampoline::FutureDropWritable {
1045                        instance: frame.instance,
1046                        ty,
1047                    },
1048                ));
1049                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1050            }
1051            ErrorContextNew { options } => {
1052                let ty = types.error_context_table_type()?;
1053                let func = options.core_type;
1054                let options = self.adapter_options(frame, types, options);
1055                let options = self.canonical_options(options);
1056                let index = self.result.trampolines.push((
1057                    func,
1058                    dfg::Trampoline::ErrorContextNew {
1059                        instance: frame.instance,
1060                        ty,
1061                        options,
1062                    },
1063                ));
1064                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
1065            }
1066            ErrorContextDebugMessage { options } => {
1067                let ty = types.error_context_table_type()?;
1068                let func = options.core_type;
1069                let options = self.adapter_options(frame, types, options);
1070                let options = self.canonical_options(options);
1071                let index = self.result.trampolines.push((
1072                    func,
1073                    dfg::Trampoline::ErrorContextDebugMessage {
1074                        instance: frame.instance,
1075                        ty,
1076                        options,
1077                    },
1078                ));
1079                frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));
1080            }
1081            ErrorContextDrop { func } => {
1082                let ty = types.error_context_table_type()?;
1083                let index = self.result.trampolines.push((
1084                    *func,
1085                    dfg::Trampoline::ErrorContextDrop {
1086                        instance: frame.instance,
1087                        ty,
1088                    },
1089                ));
1090                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1091            }
1092            ContextGet { func, i } => {
1093                let index = self.result.trampolines.push((
1094                    *func,
1095                    dfg::Trampoline::ContextGet {
1096                        instance: frame.instance,
1097                        slot: *i,
1098                    },
1099                ));
1100                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1101            }
1102            ContextSet { func, i } => {
1103                let index = self.result.trampolines.push((
1104                    *func,
1105                    dfg::Trampoline::ContextSet {
1106                        instance: frame.instance,
1107                        slot: *i,
1108                    },
1109                ));
1110                frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1111            }
1112
1113            ModuleStatic(idx, ty) => {
1114                frame.modules.push(ModuleDef::Static(*idx, *ty));
1115            }
1116
1117            // Instantiation of a module is one of the meatier initializers that
1118            // we'll generate. The main magic here is that for a statically
1119            // known module we can order the imports as a list to exactly what
1120            // the static module needs to be instantiated. For imported modules,
1121            // however, the runtime string resolution must happen at runtime so
1122            // that is deferred here by organizing the arguments as a two-layer
1123            // `IndexMap` of what we're providing.
1124            //
1125            // In both cases though a new `RuntimeInstanceIndex` is allocated
1126            // and an initializer is recorded to indicate that it's being
1127            // instantiated.
1128            ModuleInstantiate(module, args) => {
1129                let (instance_module, init) = match &frame.modules[*module] {
1130                    ModuleDef::Static(idx, _ty) => {
1131                        let mut defs = Vec::new();
1132                        for (module, name, _ty) in self.nested_modules[*idx].module.imports() {
1133                            let instance = args[module];
1134                            defs.push(
1135                                self.core_def_of_module_instance_export(frame, instance, name),
1136                            );
1137                        }
1138                        (
1139                            InstanceModule::Static(*idx),
1140                            dfg::Instance::Static(*idx, defs.into()),
1141                        )
1142                    }
1143                    ModuleDef::Import(path, ty) => {
1144                        let mut defs = IndexMap::new();
1145                        for ((module, name), _) in types[*ty].imports.iter() {
1146                            let instance = args[module.as_str()];
1147                            let def =
1148                                self.core_def_of_module_instance_export(frame, instance, name);
1149                            defs.entry(module.to_string())
1150                                .or_insert(IndexMap::new())
1151                                .insert(name.to_string(), def);
1152                        }
1153                        let index = self.runtime_import(path);
1154                        (
1155                            InstanceModule::Import(*ty),
1156                            dfg::Instance::Import(index, defs),
1157                        )
1158                    }
1159                };
1160
1161                let instance = self.result.instances.push(init);
1162                let instance2 = self.runtime_instances.push(instance_module);
1163                assert_eq!(instance, instance2);
1164
1165                self.result
1166                    .side_effects
1167                    .push(dfg::SideEffect::Instance(instance));
1168
1169                frame
1170                    .module_instances
1171                    .push(ModuleInstanceDef::Instantiated(instance, *module));
1172            }
1173
1174            ModuleSynthetic(map) => {
1175                frame
1176                    .module_instances
1177                    .push(ModuleInstanceDef::Synthetic(map));
1178            }
1179
1180            // This is one of the stages of the "magic" of implementing outer
1181            // aliases to components and modules. For more information on this
1182            // see the documentation on `LexicalScope`. This stage of the
1183            // implementation of outer aliases is where the `ClosedOverVars` is
1184            // transformed into a `ComponentClosure` state using the current
1185            // `InlinerFrame`'s state. This will capture the "runtime" state of
1186            // outer components and upvars and such naturally as part of the
1187            // inlining process.
1188            ComponentStatic(index, vars) => {
1189                frame.components.push(ComponentDef {
1190                    index: *index,
1191                    closure: ComponentClosure {
1192                        modules: vars
1193                            .modules
1194                            .iter()
1195                            .map(|(_, m)| frame.closed_over_module(m))
1196                            .collect(),
1197                        components: vars
1198                            .components
1199                            .iter()
1200                            .map(|(_, m)| frame.closed_over_component(m))
1201                            .collect(),
1202                    },
1203                });
1204            }
1205
1206            // Like module instantiation is this is a "meaty" part, and don't be
1207            // fooled by the relative simplicity of this case. This is
1208            // implemented primarily by the `Inliner` structure and the design
1209            // of this entire module, so the "easy" step here is to simply
1210            // create a new inliner frame and return it to get pushed onto the
1211            // stack.
1212            ComponentInstantiate(component, args, ty) => {
1213                let component: &ComponentDef<'a> = &frame.components[*component];
1214                let index = RuntimeComponentInstanceIndex::from_u32(
1215                    self.result.num_runtime_component_instances,
1216                );
1217                self.result.num_runtime_component_instances += 1;
1218                let frame = InlinerFrame::new(
1219                    index,
1220                    &self.nested_components[component.index],
1221                    component.closure.clone(),
1222                    args.iter()
1223                        .map(|(name, item)| Ok((*name, frame.item(*item, types)?)))
1224                        .collect::<Result<_>>()?,
1225                    Some(*ty),
1226                );
1227                return Ok(Some(frame));
1228            }
1229
1230            ComponentSynthetic(map, ty) => {
1231                let items = map
1232                    .iter()
1233                    .map(|(name, index)| Ok((*name, frame.item(*index, types)?)))
1234                    .collect::<Result<_>>()?;
1235                let types_ref = frame.translation.types_ref();
1236                let ty = types.convert_instance(types_ref, *ty)?;
1237                frame
1238                    .component_instances
1239                    .push(ComponentInstanceDef::Items(items, ty));
1240            }
1241
1242            // Core wasm aliases, this and the cases below, are creating
1243            // `CoreExport` items primarily to insert into the index space so we
1244            // can create a unique identifier pointing to each core wasm export
1245            // with the instance and relevant index/name as necessary.
1246            AliasExportFunc(instance, name) => {
1247                let (ty, def) = match &frame.module_instances[*instance] {
1248                    ModuleInstanceDef::Instantiated(instance, module) => {
1249                        let (ty, item) = match &frame.modules[*module] {
1250                            ModuleDef::Static(idx, _ty) => {
1251                                let entity = self.nested_modules[*idx].module.exports[*name];
1252                                let ty = match entity {
1253                                    EntityIndex::Function(f) => {
1254                                        self.nested_modules[*idx].module.functions[f]
1255                                            .signature
1256                                            .unwrap_module_type_index()
1257                                    }
1258                                    _ => unreachable!(),
1259                                };
1260                                (ty, ExportItem::Index(entity))
1261                            }
1262                            ModuleDef::Import(_path, module_ty) => {
1263                                let module_ty = &types.component_types()[*module_ty];
1264                                let entity_ty = &module_ty.exports[&**name];
1265                                let ty = entity_ty.unwrap_func().unwrap_module_type_index();
1266                                (ty, ExportItem::Name((*name).to_string()))
1267                            }
1268                        };
1269                        let def = dfg::CoreExport {
1270                            instance: *instance,
1271                            item,
1272                        }
1273                        .into();
1274                        (ty, def)
1275                    }
1276                    ModuleInstanceDef::Synthetic(instance) => match instance[*name] {
1277                        EntityIndex::Function(i) => frame.funcs[i].clone(),
1278                        _ => unreachable!(),
1279                    },
1280                };
1281                frame.funcs.push((ty, def));
1282            }
1283
1284            AliasExportTable(instance, name) => {
1285                frame.tables.push(
1286                    match self.core_def_of_module_instance_export(frame, *instance, *name) {
1287                        dfg::CoreDef::Export(e) => e,
1288                        _ => unreachable!(),
1289                    },
1290                );
1291            }
1292
1293            AliasExportGlobal(instance, name) => {
1294                frame.globals.push(
1295                    match self.core_def_of_module_instance_export(frame, *instance, *name) {
1296                        dfg::CoreDef::Export(e) => e,
1297                        _ => unreachable!(),
1298                    },
1299                );
1300            }
1301
1302            AliasExportMemory(instance, name) => {
1303                frame.memories.push(
1304                    match self.core_def_of_module_instance_export(frame, *instance, *name) {
1305                        dfg::CoreDef::Export(e) => e,
1306                        _ => unreachable!(),
1307                    },
1308                );
1309            }
1310
1311            AliasExportTag(instance, name) => {
1312                frame.tags.push(
1313                    match self.core_def_of_module_instance_export(frame, *instance, *name) {
1314                        dfg::CoreDef::Export(e) => e,
1315                        _ => unreachable!(),
1316                    },
1317                );
1318            }
1319
1320            AliasComponentExport(instance, name) => {
1321                match &frame.component_instances[*instance] {
1322                    // Aliasing an export from an imported instance means that
1323                    // we're extending the `ImportPath` by one name, represented
1324                    // with the clone + push here. Afterwards an appropriate
1325                    // item is then pushed in the relevant index space.
1326                    ComponentInstanceDef::Import(path, ty) => {
1327                        let path = path.push(*name);
1328                        let def = ComponentItemDef::from_import(path, types[*ty].exports[*name])?;
1329                        frame.push_item(def);
1330                    }
1331
1332                    // Given a component instance which was either created
1333                    // through instantiation of a component or through a
1334                    // synthetic renaming of items we just schlep around the
1335                    // definitions of various items here.
1336                    ComponentInstanceDef::Items(map, _) => frame.push_item(map[*name].clone()),
1337                }
1338            }
1339
1340            // For more information on these see `LexicalScope` but otherwise
1341            // this is just taking a closed over variable and inserting the
1342            // actual definition into the local index space since this
1343            // represents an outer alias to a module/component
1344            AliasModule(idx) => {
1345                frame.modules.push(frame.closed_over_module(idx));
1346            }
1347            AliasComponent(idx) => {
1348                frame.components.push(frame.closed_over_component(idx));
1349            }
1350
1351            Export(item) => match item {
1352                ComponentItem::Func(i) => {
1353                    frame
1354                        .component_funcs
1355                        .push(frame.component_funcs[*i].clone());
1356                }
1357                ComponentItem::Module(i) => {
1358                    frame.modules.push(frame.modules[*i].clone());
1359                }
1360                ComponentItem::Component(i) => {
1361                    frame.components.push(frame.components[*i].clone());
1362                }
1363                ComponentItem::ComponentInstance(i) => {
1364                    frame
1365                        .component_instances
1366                        .push(frame.component_instances[*i].clone());
1367                }
1368
1369                // Type index spaces aren't maintained during this inlining pass
1370                // so ignore this.
1371                ComponentItem::Type(_) => {}
1372            },
1373        }
1374
1375        Ok(None)
1376    }
1377
1378    /// "Commits" a path of an import to an actual index which is something that
1379    /// will be calculated at runtime.
1380    ///
1381    /// Note that the cost of calculating an item for a `RuntimeImportIndex` at
1382    /// runtime is amortized with an `InstancePre` which represents "all the
1383    /// runtime imports are lined up" and after that no more name resolution is
1384    /// necessary.
1385    fn runtime_import(&mut self, path: &ImportPath<'a>) -> RuntimeImportIndex {
1386        *self
1387            .import_path_interner
1388            .entry(path.clone())
1389            .or_insert_with(|| {
1390                self.result.imports.push((
1391                    path.index,
1392                    path.path.iter().map(|s| s.to_string()).collect(),
1393                ))
1394            })
1395    }
1396
1397    /// Returns the `CoreDef`, the canonical definition for a core wasm item,
1398    /// for the export `name` of `instance` within `frame`.
1399    fn core_def_of_module_instance_export(
1400        &self,
1401        frame: &InlinerFrame<'a>,
1402        instance: ModuleInstanceIndex,
1403        name: &'a str,
1404    ) -> dfg::CoreDef {
1405        match &frame.module_instances[instance] {
1406            // Instantiations of a statically known module means that we can
1407            // refer to the exported item by a precise index, skipping name
1408            // lookups at runtime.
1409            //
1410            // Instantiations of an imported module, however, must do name
1411            // lookups at runtime since we don't know the structure ahead of
1412            // time here.
1413            ModuleInstanceDef::Instantiated(instance, module) => {
1414                let item = match frame.modules[*module] {
1415                    ModuleDef::Static(idx, _ty) => {
1416                        let entity = self.nested_modules[idx].module.exports[name];
1417                        ExportItem::Index(entity)
1418                    }
1419                    ModuleDef::Import(..) => ExportItem::Name(name.to_string()),
1420                };
1421                dfg::CoreExport {
1422                    instance: *instance,
1423                    item,
1424                }
1425                .into()
1426            }
1427
1428            // This is a synthetic instance so the canonical definition of the
1429            // original item is returned.
1430            ModuleInstanceDef::Synthetic(instance) => match instance[name] {
1431                EntityIndex::Function(i) => frame.funcs[i].1.clone(),
1432                EntityIndex::Table(i) => frame.tables[i].clone().into(),
1433                EntityIndex::Global(i) => frame.globals[i].clone().into(),
1434                EntityIndex::Memory(i) => frame.memories[i].clone().into(),
1435                EntityIndex::Tag(_) => todo!(), // FIXME: #10252 support for tags in the component model
1436            },
1437        }
1438    }
1439
1440    fn memory(
1441        &mut self,
1442        frame: &InlinerFrame<'a>,
1443        types: &ComponentTypesBuilder,
1444        memory: MemoryIndex,
1445    ) -> (dfg::CoreExport<MemoryIndex>, bool) {
1446        let memory = frame.memories[memory].clone().map_index(|i| match i {
1447            EntityIndex::Memory(i) => i,
1448            _ => unreachable!(),
1449        });
1450        let memory64 = match &self.runtime_instances[memory.instance] {
1451            InstanceModule::Static(idx) => match &memory.item {
1452                ExportItem::Index(i) => {
1453                    let ty = &self.nested_modules[*idx].module.memories[*i];
1454                    match ty.idx_type {
1455                        IndexType::I32 => false,
1456                        IndexType::I64 => true,
1457                    }
1458                }
1459                ExportItem::Name(_) => unreachable!(),
1460            },
1461            InstanceModule::Import(ty) => match &memory.item {
1462                ExportItem::Name(name) => match types[*ty].exports[name] {
1463                    EntityType::Memory(m) => match m.idx_type {
1464                        IndexType::I32 => false,
1465                        IndexType::I64 => true,
1466                    },
1467                    _ => unreachable!(),
1468                },
1469                ExportItem::Index(_) => unreachable!(),
1470            },
1471        };
1472        (memory, memory64)
1473    }
1474
1475    /// Translates a `LocalCanonicalOptions` which indexes into the `frame`
1476    /// specified into a runtime representation.
1477    fn adapter_options(
1478        &mut self,
1479        frame: &InlinerFrame<'a>,
1480        types: &ComponentTypesBuilder,
1481        options: &LocalCanonicalOptions,
1482    ) -> AdapterOptions {
1483        let data_model = match options.data_model {
1484            LocalDataModel::Gc {} => DataModel::Gc {},
1485            LocalDataModel::LinearMemory { memory, realloc } => {
1486                let (memory, memory64) = memory
1487                    .map(|i| {
1488                        let (memory, memory64) = self.memory(frame, types, i);
1489                        (Some(memory), memory64)
1490                    })
1491                    .unwrap_or((None, false));
1492                let realloc = realloc.map(|i| frame.funcs[i].1.clone());
1493                DataModel::LinearMemory {
1494                    memory,
1495                    memory64,
1496                    realloc,
1497                }
1498            }
1499        };
1500        let callback = options.callback.map(|i| frame.funcs[i].1.clone());
1501        let post_return = options.post_return.map(|i| frame.funcs[i].1.clone());
1502        AdapterOptions {
1503            instance: frame.instance,
1504            string_encoding: options.string_encoding,
1505            callback,
1506            post_return,
1507            async_: options.async_,
1508            cancellable: options.cancellable,
1509            core_type: options.core_type,
1510            data_model,
1511        }
1512    }
1513
1514    /// Translatees an `AdapterOptions` into a `CanonicalOptions` where
1515    /// memories/functions are inserted into the global initializer list for
1516    /// use at runtime. This is only used for lowered host functions and lifted
1517    /// functions exported to the host.
1518    fn canonical_options(&mut self, options: AdapterOptions) -> dfg::OptionsId {
1519        let data_model = match options.data_model {
1520            DataModel::Gc {} => dfg::CanonicalOptionsDataModel::Gc {},
1521            DataModel::LinearMemory {
1522                memory,
1523                memory64: _,
1524                realloc,
1525            } => dfg::CanonicalOptionsDataModel::LinearMemory {
1526                memory: memory.map(|export| self.result.memories.push(export)),
1527                realloc: realloc.map(|def| self.result.reallocs.push(def)),
1528            },
1529        };
1530        let callback = options.callback.map(|def| self.result.callbacks.push(def));
1531        let post_return = options
1532            .post_return
1533            .map(|def| self.result.post_returns.push(def));
1534        self.result.options.push(dfg::CanonicalOptions {
1535            instance: options.instance,
1536            string_encoding: options.string_encoding,
1537            callback,
1538            post_return,
1539            async_: options.async_,
1540            cancellable: options.cancellable,
1541            core_type: options.core_type,
1542            data_model,
1543        })
1544    }
1545
1546    fn record_export(
1547        &mut self,
1548        name: &str,
1549        def: ComponentItemDef<'a>,
1550        types: &'a ComponentTypesBuilder,
1551        map: &mut IndexMap<String, dfg::Export>,
1552    ) -> Result<()> {
1553        let export = match def {
1554            // Exported modules are currently saved in a `PrimaryMap`, at
1555            // runtime, so an index (`RuntimeModuleIndex`) is assigned here and
1556            // then an initializer is recorded about where the module comes
1557            // from.
1558            ComponentItemDef::Module(module) => match module {
1559                ModuleDef::Static(index, ty) => dfg::Export::ModuleStatic { ty, index },
1560                ModuleDef::Import(path, ty) => dfg::Export::ModuleImport {
1561                    ty,
1562                    import: self.runtime_import(&path),
1563                },
1564            },
1565
1566            ComponentItemDef::Func(func) => match func {
1567                // If this is a lifted function from something lowered in this
1568                // component then the configured options are plumbed through
1569                // here.
1570                ComponentFuncDef::Lifted { ty, func, options } => {
1571                    let options = self.canonical_options(options);
1572                    dfg::Export::LiftedFunction { ty, func, options }
1573                }
1574
1575                // Currently reexported functions from an import are not
1576                // supported. Being able to actually call these functions is
1577                // somewhat tricky and needs something like temporary scratch
1578                // space that isn't implemented.
1579                ComponentFuncDef::Import(_) => {
1580                    bail!(
1581                        "component export `{name}` is a reexport of an imported function which is not implemented"
1582                    )
1583                }
1584            },
1585
1586            ComponentItemDef::Instance(instance) => {
1587                let mut exports = IndexMap::new();
1588                match instance {
1589                    // If this instance is one that was originally imported by
1590                    // the component itself then the imports are translated here
1591                    // by converting to a `ComponentItemDef` and then
1592                    // recursively recording the export as a reexport.
1593                    //
1594                    // Note that for now this would only work with
1595                    // module-exporting instances.
1596                    ComponentInstanceDef::Import(path, ty) => {
1597                        for (name, ty) in types[ty].exports.iter() {
1598                            let path = path.push(name);
1599                            let def = ComponentItemDef::from_import(path, *ty)?;
1600                            self.record_export(name, def, types, &mut exports)?;
1601                        }
1602                        dfg::Export::Instance { ty, exports }
1603                    }
1604
1605                    // An exported instance which is itself a bag of items is
1606                    // translated recursively here to our `exports` map which is
1607                    // the bag of items we're exporting.
1608                    ComponentInstanceDef::Items(map, ty) => {
1609                        for (name, def) in map {
1610                            self.record_export(name, def, types, &mut exports)?;
1611                        }
1612                        dfg::Export::Instance { ty, exports }
1613                    }
1614                }
1615            }
1616
1617            // FIXME(#4283) should make an official decision on whether this is
1618            // the final treatment of this or not.
1619            ComponentItemDef::Component(_) => {
1620                bail!("exporting a component from the root component is not supported")
1621            }
1622
1623            ComponentItemDef::Type(def) => dfg::Export::Type(def),
1624        };
1625
1626        map.insert(name.to_string(), export);
1627        Ok(())
1628    }
1629}
1630
1631impl<'a> InlinerFrame<'a> {
1632    fn new(
1633        instance: RuntimeComponentInstanceIndex,
1634        translation: &'a Translation<'a>,
1635        closure: ComponentClosure<'a>,
1636        args: HashMap<&'a str, ComponentItemDef<'a>>,
1637        instance_ty: Option<ComponentInstanceTypeId>,
1638    ) -> Self {
1639        // FIXME: should iterate over the initializers of `translation` and
1640        // calculate the size of each index space to use `with_capacity` for
1641        // all the maps below. Given that doing such would be wordy and compile
1642        // time is otherwise not super crucial it's not done at this time.
1643        InlinerFrame {
1644            instance,
1645            translation,
1646            closure,
1647            args,
1648            instance_ty,
1649            initializers: translation.initializers.iter(),
1650
1651            funcs: Default::default(),
1652            memories: Default::default(),
1653            tables: Default::default(),
1654            globals: Default::default(),
1655            tags: Default::default(),
1656
1657            component_instances: Default::default(),
1658            component_funcs: Default::default(),
1659            module_instances: Default::default(),
1660            components: Default::default(),
1661            modules: Default::default(),
1662        }
1663    }
1664
1665    fn item(
1666        &self,
1667        index: ComponentItem,
1668        types: &mut ComponentTypesBuilder,
1669    ) -> Result<ComponentItemDef<'a>> {
1670        Ok(match index {
1671            ComponentItem::Func(i) => ComponentItemDef::Func(self.component_funcs[i].clone()),
1672            ComponentItem::Component(i) => ComponentItemDef::Component(self.components[i].clone()),
1673            ComponentItem::ComponentInstance(i) => {
1674                ComponentItemDef::Instance(self.component_instances[i].clone())
1675            }
1676            ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()),
1677            ComponentItem::Type(t) => {
1678                let types_ref = self.translation.types_ref();
1679                ComponentItemDef::Type(types.convert_type(types_ref, t)?)
1680            }
1681        })
1682    }
1683
1684    /// Pushes the component `item` definition provided into the appropriate
1685    /// index space within this component.
1686    fn push_item(&mut self, item: ComponentItemDef<'a>) {
1687        match item {
1688            ComponentItemDef::Func(i) => {
1689                self.component_funcs.push(i);
1690            }
1691            ComponentItemDef::Module(i) => {
1692                self.modules.push(i);
1693            }
1694            ComponentItemDef::Component(i) => {
1695                self.components.push(i);
1696            }
1697            ComponentItemDef::Instance(i) => {
1698                self.component_instances.push(i);
1699            }
1700
1701            // In short, type definitions aren't tracked here.
1702            //
1703            // The longer form explanation for this is that structural types
1704            // like lists and records don't need to be tracked at all and the
1705            // only significant type which needs tracking is resource types
1706            // themselves. Resource types, however, are tracked within the
1707            // `ResourcesBuilder` state rather than an `InlinerFrame` so they're
1708            // ignored here as well. The general reason for that is that type
1709            // information is everywhere and this `InlinerFrame` is not
1710            // everywhere so it seemed like it would make sense to split the
1711            // two.
1712            //
1713            // Note though that this case is actually frequently hit, so it
1714            // can't be `unreachable!()`. Instead callers are responsible for
1715            // handling this appropriately with respect to resources.
1716            ComponentItemDef::Type(_ty) => {}
1717        }
1718    }
1719
1720    fn closed_over_module(&self, index: &ClosedOverModule) -> ModuleDef<'a> {
1721        match *index {
1722            ClosedOverModule::Local(i) => self.modules[i].clone(),
1723            ClosedOverModule::Upvar(i) => self.closure.modules[i].clone(),
1724        }
1725    }
1726
1727    fn closed_over_component(&self, index: &ClosedOverComponent) -> ComponentDef<'a> {
1728        match *index {
1729            ClosedOverComponent::Local(i) => self.components[i].clone(),
1730            ClosedOverComponent::Upvar(i) => self.closure.components[i].clone(),
1731        }
1732    }
1733
1734    /// Completes the instantiation of a subcomponent and records type
1735    /// information for the instance that was produced.
1736    ///
1737    /// This method is invoked when an `InlinerFrame` finishes for a
1738    /// subcomponent. The `def` provided represents the instance that was
1739    /// produced from instantiation, and `ty` is the wasmparser-defined type of
1740    /// the instance produced.
1741    ///
1742    /// The purpose of this method is to record type information about resources
1743    /// in the instance produced. In the component model all instantiations of a
1744    /// component produce fresh new types for all resources which are unequal to
1745    /// all prior resources. This means that if wasmparser's `ty` type
1746    /// information references a unique resource within `def` that has never
1747    /// been registered before then that means it's a defined resource within
1748    /// the component that was just instantiated (as opposed to an imported
1749    /// resource which was reexported).
1750    ///
1751    /// Further type translation after this instantiation can refer to these
1752    /// resource types and a mapping from those types to the wasmtime-internal
1753    /// types is required, so this method builds up those mappings.
1754    ///
1755    /// Essentially what happens here is that the `ty` type is registered and
1756    /// any new unique resources are registered so new tables can be introduced
1757    /// along with origin information about the actual underlying resource type
1758    /// and which component instantiated it.
1759    fn finish_instantiate(
1760        &mut self,
1761        exports: IndexMap<&'a str, ComponentItemDef<'a>>,
1762        ty: ComponentInstanceTypeId,
1763        types: &mut ComponentTypesBuilder,
1764    ) -> Result<()> {
1765        let types_ref = self.translation.types_ref();
1766        {
1767            let (resources, types) = types.resources_mut_and_types();
1768            let mut path = Vec::new();
1769            resources.register_component_entity_type(
1770                &types_ref,
1771                ComponentEntityType::Instance(ty),
1772                &mut path,
1773                &mut |path| match path {
1774                    [] => unreachable!(),
1775                    [name, rest @ ..] => exports[name].lookup_resource(rest, types),
1776                },
1777            );
1778        }
1779        let ty = types.convert_instance(types_ref, ty)?;
1780        let def = ComponentInstanceDef::Items(exports, ty);
1781        let arg = ComponentItemDef::Instance(def);
1782        self.push_item(arg);
1783        Ok(())
1784    }
1785}
1786
1787impl<'a> ImportPath<'a> {
1788    fn root(index: ImportIndex) -> ImportPath<'a> {
1789        ImportPath {
1790            index,
1791            path: Vec::new(),
1792        }
1793    }
1794
1795    fn push(&self, s: impl Into<Cow<'a, str>>) -> ImportPath<'a> {
1796        let mut new = self.clone();
1797        new.path.push(s.into());
1798        new
1799    }
1800}
1801
1802impl<'a> ComponentItemDef<'a> {
1803    fn from_import(path: ImportPath<'a>, ty: TypeDef) -> Result<ComponentItemDef<'a>> {
1804        let item = match ty {
1805            TypeDef::Module(ty) => ComponentItemDef::Module(ModuleDef::Import(path, ty)),
1806            TypeDef::ComponentInstance(ty) => {
1807                ComponentItemDef::Instance(ComponentInstanceDef::Import(path, ty))
1808            }
1809            TypeDef::ComponentFunc(_ty) => ComponentItemDef::Func(ComponentFuncDef::Import(path)),
1810            // FIXME(#4283) should commit one way or another to how this
1811            // should be treated.
1812            TypeDef::Component(_ty) => bail!("root-level component imports are not supported"),
1813            TypeDef::Interface(_) | TypeDef::Resource(_) => ComponentItemDef::Type(ty),
1814            TypeDef::CoreFunc(_) => unreachable!(),
1815        };
1816        Ok(item)
1817    }
1818
1819    /// Walks the `path` within `self` to find a resource at that path.
1820    ///
1821    /// This method is used when resources are found within wasmparser's type
1822    /// information and they need to be correlated with actual concrete
1823    /// definitions from this inlining pass. The `path` here is a list of
1824    /// instance export names (or empty) to walk to reach down into the final
1825    /// definition which should refer to a resource itself.
1826    fn lookup_resource(&self, path: &[&str], types: &ComponentTypes) -> ResourceIndex {
1827        let mut cur = self.clone();
1828
1829        // Each element of `path` represents unwrapping a layer of an instance
1830        // type, so handle those here by updating `cur` iteratively.
1831        for element in path.iter().copied() {
1832            let instance = match cur {
1833                ComponentItemDef::Instance(def) => def,
1834                _ => unreachable!(),
1835            };
1836            cur = match instance {
1837                // If this instance is a "bag of things" then this is as easy as
1838                // looking up the name in the bag of names.
1839                ComponentInstanceDef::Items(names, _) => names[element].clone(),
1840
1841                // If, however, this instance is an imported instance then this
1842                // is a further projection within the import with one more path
1843                // element. The `types` type information is used to lookup the
1844                // type of `element` within the instance type, and that's used
1845                // in conjunction with a one-longer `path` to produce a new item
1846                // definition.
1847                ComponentInstanceDef::Import(path, ty) => {
1848                    ComponentItemDef::from_import(path.push(element), types[ty].exports[element])
1849                        .unwrap()
1850                }
1851            };
1852        }
1853
1854        // Once `path` has been iterated over it must be the case that the final
1855        // item is a resource type, in which case a lookup can be performed.
1856        match cur {
1857            ComponentItemDef::Type(TypeDef::Resource(idx)) => types[idx].ty,
1858            _ => unreachable!(),
1859        }
1860    }
1861}
1862
1863#[derive(Clone, Copy)]
1864enum InstanceModule {
1865    Static(StaticModuleIndex),
1866    Import(TypeModuleIndex),
1867}