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