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