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