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}