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