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.result.trampolines.push((
1096 *func,
1097 dfg::Trampoline::ThreadIndex {
1098 instance: frame.instance,
1099 },
1100 ));
1101 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1102 }
1103 ThreadNewIndirect {
1104 func,
1105 start_func_table_index,
1106 start_func_ty,
1107 } => {
1108 let table_export = frame.tables[*start_func_table_index]
1109 .clone()
1110 .map_index(|i| match i {
1111 EntityIndex::Table(i) => i,
1112 _ => unreachable!(),
1113 });
1114
1115 let table_id = self.result.tables.push(table_export);
1116 let index = self.result.trampolines.push((
1117 *func,
1118 dfg::Trampoline::ThreadNewIndirect {
1119 instance: frame.instance,
1120 start_func_ty_idx: *start_func_ty,
1121 start_func_table_id: table_id,
1122 },
1123 ));
1124 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1125 }
1126 ThreadResumeLater { func } => {
1127 let index = self.result.trampolines.push((
1128 *func,
1129 dfg::Trampoline::ThreadResumeLater {
1130 instance: frame.instance,
1131 },
1132 ));
1133 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1134 }
1135 ThreadSuspend { func, cancellable } => {
1136 let index = self.result.trampolines.push((
1137 *func,
1138 dfg::Trampoline::ThreadSuspend {
1139 instance: frame.instance,
1140 cancellable: *cancellable,
1141 },
1142 ));
1143 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1144 }
1145 ThreadYield { func, cancellable } => {
1146 let index = self.result.trampolines.push((
1147 *func,
1148 dfg::Trampoline::ThreadYield {
1149 instance: frame.instance,
1150 cancellable: *cancellable,
1151 },
1152 ));
1153 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1154 }
1155 ThreadSuspendThenResume { func, cancellable } => {
1156 let index = self.result.trampolines.push((
1157 *func,
1158 dfg::Trampoline::ThreadSuspendThenResume {
1159 instance: frame.instance,
1160 cancellable: *cancellable,
1161 },
1162 ));
1163 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1164 }
1165 ThreadYieldThenResume { func, cancellable } => {
1166 let index = self.result.trampolines.push((
1167 *func,
1168 dfg::Trampoline::ThreadYieldThenResume {
1169 instance: frame.instance,
1170 cancellable: *cancellable,
1171 },
1172 ));
1173 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1174 }
1175 ThreadSuspendThenPromote { func, cancellable } => {
1176 let index = self.result.trampolines.push((
1177 *func,
1178 dfg::Trampoline::ThreadSuspendThenPromote {
1179 instance: frame.instance,
1180 cancellable: *cancellable,
1181 },
1182 ));
1183 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1184 }
1185 ThreadYieldThenPromote { func, cancellable } => {
1186 let index = self.result.trampolines.push((
1187 *func,
1188 dfg::Trampoline::ThreadYieldThenPromote {
1189 instance: frame.instance,
1190 cancellable: *cancellable,
1191 },
1192 ));
1193 frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));
1194 }
1195 ModuleStatic(idx, ty) => {
1196 frame.modules.push(ModuleDef::Static(*idx, *ty));
1197 }
1198
1199 // Instantiation of a module is one of the meatier initializers that
1200 // we'll generate. The main magic here is that for a statically
1201 // known module we can order the imports as a list to exactly what
1202 // the static module needs to be instantiated. For imported modules,
1203 // however, the runtime string resolution must happen at runtime so
1204 // that is deferred here by organizing the arguments as a two-layer
1205 // `IndexMap` of what we're providing.
1206 //
1207 // In both cases though a new `RuntimeInstanceIndex` is allocated
1208 // and an initializer is recorded to indicate that it's being
1209 // instantiated.
1210 ModuleInstantiate(module, args) => {
1211 let (instance_module, init) = match &frame.modules[*module] {
1212 ModuleDef::Static(idx, _ty) => {
1213 let mut defs = Vec::new();
1214 for (module, name, _ty) in self.nested_modules[*idx].module.imports() {
1215 let instance = args[module];
1216 defs.push(
1217 self.core_def_of_module_instance_export(frame, instance, name),
1218 );
1219 }
1220 (
1221 InstanceModule::Static(*idx),
1222 dfg::Instance::Static(*idx, defs.into()),
1223 )
1224 }
1225 ModuleDef::Import(path, ty) => {
1226 let mut defs = IndexMap::new();
1227 for ((module, name), _) in types[*ty].imports.iter() {
1228 let instance = args[module.as_str()];
1229 let def =
1230 self.core_def_of_module_instance_export(frame, instance, name);
1231 defs.entry(module.to_string())
1232 .or_insert(IndexMap::new())
1233 .insert(name.to_string(), def);
1234 }
1235 let index = self.runtime_import(path);
1236 (
1237 InstanceModule::Import(*ty),
1238 dfg::Instance::Import(index, defs),
1239 )
1240 }
1241 };
1242
1243 let instance = self.result.instances.push(init);
1244 let instance2 = self.runtime_instances.push(instance_module);
1245 assert_eq!(instance, instance2);
1246
1247 self.result
1248 .side_effects
1249 .push(dfg::SideEffect::Instance(instance, frame.instance));
1250
1251 frame
1252 .module_instances
1253 .push(ModuleInstanceDef::Instantiated(instance, *module));
1254 }
1255
1256 ModuleSynthetic(map) => {
1257 frame
1258 .module_instances
1259 .push(ModuleInstanceDef::Synthetic(map));
1260 }
1261
1262 // This is one of the stages of the "magic" of implementing outer
1263 // aliases to components and modules. For more information on this
1264 // see the documentation on `LexicalScope`. This stage of the
1265 // implementation of outer aliases is where the `ClosedOverVars` is
1266 // transformed into a `ComponentClosure` state using the current
1267 // `InlinerFrame`'s state. This will capture the "runtime" state of
1268 // outer components and upvars and such naturally as part of the
1269 // inlining process.
1270 ComponentStatic(index, vars) => {
1271 frame.components.push(ComponentDef {
1272 index: *index,
1273 closure: ComponentClosure {
1274 modules: vars
1275 .modules
1276 .iter()
1277 .map(|(_, m)| frame.closed_over_module(m))
1278 .collect(),
1279 components: vars
1280 .components
1281 .iter()
1282 .map(|(_, m)| frame.closed_over_component(m))
1283 .collect(),
1284 },
1285 });
1286 }
1287
1288 // Like module instantiation is this is a "meaty" part, and don't be
1289 // fooled by the relative simplicity of this case. This is
1290 // implemented primarily by the `Inliner` structure and the design
1291 // of this entire module, so the "easy" step here is to simply
1292 // create a new inliner frame and return it to get pushed onto the
1293 // stack.
1294 ComponentInstantiate(component, args, ty) => {
1295 let component: &ComponentDef<'a> = &frame.components[*component];
1296 let index = RuntimeComponentInstanceIndex::from_u32(
1297 self.result.num_runtime_component_instances,
1298 );
1299 self.result.num_runtime_component_instances += 1;
1300 let frame = InlinerFrame::new(
1301 index,
1302 &self.nested_components[component.index],
1303 component.closure.clone(),
1304 args.iter()
1305 .map(|(name, item)| Ok((*name, frame.item(*item, types)?)))
1306 .collect::<Result<_>>()?,
1307 Some(*ty),
1308 );
1309 return Ok(Some(frame));
1310 }
1311
1312 ComponentSynthetic(map, ty) => {
1313 let items = map
1314 .iter()
1315 .map(|(name, (index, data))| Ok((*name, (frame.item(*index, types)?, *data))))
1316 .collect::<Result<_>>()?;
1317 let types_ref = frame.translation.types_ref();
1318 let ty = types.convert_instance(types_ref, *ty)?;
1319 frame
1320 .component_instances
1321 .push(ComponentInstanceDef::Items(items, ty));
1322 }
1323
1324 // Core wasm aliases, this and the cases below, are creating
1325 // `CoreExport` items primarily to insert into the index space so we
1326 // can create a unique identifier pointing to each core wasm export
1327 // with the instance and relevant index/name as necessary.
1328 AliasExportFunc(instance, name) => {
1329 let (ty, def) = match &frame.module_instances[*instance] {
1330 ModuleInstanceDef::Instantiated(instance, module) => {
1331 let (ty, item) = match &frame.modules[*module] {
1332 ModuleDef::Static(idx, _ty) => {
1333 let name = self.nested_modules[*idx]
1334 .module
1335 .strings
1336 .get_atom(name)
1337 .unwrap();
1338 let entity = self.nested_modules[*idx].module.exports[&name];
1339 let ty = match entity {
1340 EntityIndex::Function(f) => {
1341 self.nested_modules[*idx].module.functions[f]
1342 .signature
1343 .unwrap_module_type_index()
1344 }
1345 _ => unreachable!(),
1346 };
1347 (ty, ExportItem::Index(entity))
1348 }
1349 ModuleDef::Import(_path, module_ty) => {
1350 let module_ty = &types.component_types()[*module_ty];
1351 let entity_ty = &module_ty.exports[&**name];
1352 let ty = entity_ty.unwrap_func().unwrap_module_type_index();
1353 (ty, ExportItem::Name((*name).to_string()))
1354 }
1355 };
1356 let def = dfg::CoreExport {
1357 instance: *instance,
1358 item,
1359 }
1360 .into();
1361 (ty, def)
1362 }
1363 ModuleInstanceDef::Synthetic(instance) => match instance[*name] {
1364 EntityIndex::Function(i) => frame.funcs[i].clone(),
1365 _ => unreachable!(),
1366 },
1367 };
1368 frame.funcs.push((ty, def));
1369 }
1370
1371 AliasExportTable(instance, name) => {
1372 frame.tables.push(
1373 match self.core_def_of_module_instance_export(frame, *instance, *name) {
1374 dfg::CoreDef::Export(e) => e,
1375 _ => unreachable!(),
1376 },
1377 );
1378 }
1379
1380 AliasExportGlobal(instance, name) => {
1381 frame.globals.push(
1382 match self.core_def_of_module_instance_export(frame, *instance, *name) {
1383 dfg::CoreDef::Export(e) => e,
1384 _ => unreachable!(),
1385 },
1386 );
1387 }
1388
1389 AliasExportMemory(instance, name) => {
1390 frame.memories.push(
1391 match self.core_def_of_module_instance_export(frame, *instance, *name) {
1392 dfg::CoreDef::Export(e) => e,
1393 _ => unreachable!(),
1394 },
1395 );
1396 }
1397
1398 AliasExportTag(instance, name) => {
1399 frame.tags.push(
1400 match self.core_def_of_module_instance_export(frame, *instance, *name) {
1401 dfg::CoreDef::Export(e) => e,
1402 _ => unreachable!(),
1403 },
1404 );
1405 }
1406
1407 AliasComponentExport(instance, name) => {
1408 match &frame.component_instances[*instance] {
1409 ComponentInstanceDef::Intrinsics => {
1410 frame.push_item(ComponentItemDef::Func(ComponentFuncDef::UnsafeIntrinsic(
1411 UnsafeIntrinsic::from_str(name)?,
1412 )));
1413 }
1414
1415 // Aliasing an export from an imported instance means that
1416 // we're extending the `ImportPath` by one name, represented
1417 // with the clone + push here. Afterwards an appropriate
1418 // item is then pushed in the relevant index space.
1419 ComponentInstanceDef::Import(path, ty) => {
1420 let path = path.push(*name);
1421 let def =
1422 ComponentItemDef::from_import(path, types[*ty].exports[*name].ty)?;
1423 frame.push_item(def);
1424 }
1425
1426 // Given a component instance which was either created
1427 // through instantiation of a component or through a
1428 // synthetic renaming of items we just schlep around the
1429 // definitions of various items here.
1430 ComponentInstanceDef::Items(map, _) => frame.push_item(map[*name].0.clone()),
1431 }
1432 }
1433
1434 // For more information on these see `LexicalScope` but otherwise
1435 // this is just taking a closed over variable and inserting the
1436 // actual definition into the local index space since this
1437 // represents an outer alias to a module/component
1438 AliasModule(idx) => {
1439 frame.modules.push(frame.closed_over_module(idx));
1440 }
1441 AliasComponent(idx) => {
1442 frame.components.push(frame.closed_over_component(idx));
1443 }
1444
1445 Export(item) => match item {
1446 ComponentItem::Func(i) => {
1447 frame
1448 .component_funcs
1449 .push(frame.component_funcs[*i].clone());
1450 }
1451 ComponentItem::Module(i) => {
1452 frame.modules.push(frame.modules[*i].clone());
1453 }
1454 ComponentItem::Component(i) => {
1455 frame.components.push(frame.components[*i].clone());
1456 }
1457 ComponentItem::ComponentInstance(i) => {
1458 frame
1459 .component_instances
1460 .push(frame.component_instances[*i].clone());
1461 }
1462
1463 // Type index spaces aren't maintained during this inlining pass
1464 // so ignore this.
1465 ComponentItem::Type(_) => {}
1466 },
1467 }
1468
1469 Ok(None)
1470 }
1471
1472 /// "Commits" a path of an import to an actual index which is something that
1473 /// will be calculated at runtime.
1474 ///
1475 /// Note that the cost of calculating an item for a `RuntimeImportIndex` at
1476 /// runtime is amortized with an `InstancePre` which represents "all the
1477 /// runtime imports are lined up" and after that no more name resolution is
1478 /// necessary.
1479 fn runtime_import(&mut self, path: &ImportPath<'a>) -> RuntimeImportIndex {
1480 *self
1481 .import_path_interner
1482 .entry(path.clone())
1483 .or_insert_with(|| {
1484 self.result.imports.push((
1485 path.index,
1486 path.path.iter().map(|s| s.to_string()).collect(),
1487 ))
1488 })
1489 }
1490
1491 /// Returns the `CoreDef`, the canonical definition for a core wasm item,
1492 /// for the export `name` of `instance` within `frame`.
1493 fn core_def_of_module_instance_export(
1494 &self,
1495 frame: &InlinerFrame<'a>,
1496 instance: ModuleInstanceIndex,
1497 name: &'a str,
1498 ) -> dfg::CoreDef {
1499 match &frame.module_instances[instance] {
1500 // Instantiations of a statically known module means that we can
1501 // refer to the exported item by a precise index, skipping name
1502 // lookups at runtime.
1503 //
1504 // Instantiations of an imported module, however, must do name
1505 // lookups at runtime since we don't know the structure ahead of
1506 // time here.
1507 ModuleInstanceDef::Instantiated(instance, module) => {
1508 let item = match frame.modules[*module] {
1509 ModuleDef::Static(idx, _ty) => {
1510 let name = self.nested_modules[idx]
1511 .module
1512 .strings
1513 .get_atom(name)
1514 .unwrap();
1515 let entity = self.nested_modules[idx].module.exports[&name];
1516 ExportItem::Index(entity)
1517 }
1518 ModuleDef::Import(..) => ExportItem::Name(name.to_string()),
1519 };
1520 dfg::CoreExport {
1521 instance: *instance,
1522 item,
1523 }
1524 .into()
1525 }
1526
1527 // This is a synthetic instance so the canonical definition of the
1528 // original item is returned.
1529 ModuleInstanceDef::Synthetic(instance) => match instance[name] {
1530 EntityIndex::Function(i) => frame.funcs[i].1.clone(),
1531 EntityIndex::Table(i) => frame.tables[i].clone().into(),
1532 EntityIndex::Global(i) => frame.globals[i].clone().into(),
1533 EntityIndex::Memory(i) => frame.memories[i].clone().into(),
1534 EntityIndex::Tag(i) => frame.tags[i].clone().into(),
1535 },
1536 }
1537 }
1538
1539 fn memory(
1540 &mut self,
1541 frame: &InlinerFrame<'a>,
1542 types: &ComponentTypesBuilder,
1543 memory: MemoryIndex,
1544 ) -> (dfg::CoreExport<MemoryIndex>, Memory) {
1545 let memory = frame.memories[memory].clone().map_index(|i| match i {
1546 EntityIndex::Memory(i) => i,
1547 _ => unreachable!(),
1548 });
1549 let ty = match &self.runtime_instances[memory.instance] {
1550 InstanceModule::Static(idx) => match &memory.item {
1551 ExportItem::Index(i) => self.nested_modules[*idx].module.memories[*i],
1552 ExportItem::Name(_) => unreachable!(),
1553 },
1554 InstanceModule::Import(ty) => match &memory.item {
1555 ExportItem::Name(name) => match types[*ty].exports[name] {
1556 EntityType::Memory(m) => m,
1557 _ => unreachable!(),
1558 },
1559 ExportItem::Index(_) => unreachable!(),
1560 },
1561 };
1562 (memory, ty)
1563 }
1564
1565 /// Translates a `LocalCanonicalOptions` which indexes into the `frame`
1566 /// specified into a runtime representation.
1567 fn adapter_options(
1568 &mut self,
1569 frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,
1570 types: &ComponentTypesBuilder,
1571 options: &LocalCanonicalOptions,
1572 ) -> AdapterOptions {
1573 let (frame, _) = frames.last_mut().unwrap();
1574 let data_model = match options.data_model {
1575 LocalDataModel::Gc {} => DataModel::Gc {},
1576 LocalDataModel::LinearMemory { memory, realloc } => {
1577 let memory = memory.map(|i| self.memory(frame, types, i));
1578 let realloc = realloc.map(|i| frame.funcs[i].1.clone());
1579 DataModel::LinearMemory { memory, realloc }
1580 }
1581 };
1582 let callback = options.callback.map(|i| frame.funcs[i].1.clone());
1583 let post_return = options.post_return.map(|i| frame.funcs[i].1.clone());
1584 AdapterOptions {
1585 instance: frame.instance,
1586 string_encoding: options.string_encoding,
1587 callback,
1588 post_return,
1589 async_: options.async_,
1590 cancellable: options.cancellable,
1591 core_type: options.core_type,
1592 data_model,
1593 }
1594 }
1595
1596 /// Translates an `AdapterOptions` into a `CanonicalOptions` where
1597 /// memories/functions are inserted into the global initializer list for
1598 /// use at runtime. This is only used for lowered host functions and lifted
1599 /// functions exported to the host.
1600 fn canonical_options(&mut self, options: AdapterOptions) -> dfg::OptionsId {
1601 let data_model = match options.data_model {
1602 DataModel::Gc {} => dfg::CanonicalOptionsDataModel::Gc {},
1603 DataModel::LinearMemory { memory, realloc } => {
1604 dfg::CanonicalOptionsDataModel::LinearMemory {
1605 memory: memory.map(|(export, _)| self.result.memories.push(export)),
1606 realloc: realloc.map(|def| self.result.reallocs.push(def)),
1607 }
1608 }
1609 };
1610 let callback = options.callback.map(|def| self.result.callbacks.push(def));
1611 let post_return = options
1612 .post_return
1613 .map(|def| self.result.post_returns.push(def));
1614 self.result.options.push(dfg::CanonicalOptions {
1615 instance: options.instance,
1616 string_encoding: options.string_encoding,
1617 callback,
1618 post_return,
1619 async_: options.async_,
1620 cancellable: options.cancellable,
1621 core_type: options.core_type,
1622 data_model,
1623 })
1624 }
1625
1626 fn record_export(
1627 &mut self,
1628 name: &str,
1629 def: ComponentItemDef<'a>,
1630 data: ComponentExternData,
1631 types: &'a ComponentTypesBuilder,
1632 map: &mut IndexMap<String, (dfg::Export, ComponentExternData)>,
1633 ) -> Result<()> {
1634 let export = match def {
1635 // Exported modules are currently saved in a `PrimaryMap`, at
1636 // runtime, so an index (`RuntimeModuleIndex`) is assigned here and
1637 // then an initializer is recorded about where the module comes
1638 // from.
1639 ComponentItemDef::Module(module) => match module {
1640 ModuleDef::Static(index, ty) => dfg::Export::ModuleStatic { ty, index },
1641 ModuleDef::Import(path, ty) => dfg::Export::ModuleImport {
1642 ty,
1643 import: self.runtime_import(&path),
1644 },
1645 },
1646
1647 ComponentItemDef::Func(func) => match func {
1648 // If this is a lifted function from something lowered in this
1649 // component then the configured options are plumbed through
1650 // here.
1651 ComponentFuncDef::Lifted { ty, func, options } => {
1652 let options = self.canonical_options(options);
1653 dfg::Export::LiftedFunction { ty, func, options }
1654 }
1655
1656 // Currently reexported functions from an import are not
1657 // supported. Being able to actually call these functions is
1658 // somewhat tricky and needs something like temporary scratch
1659 // space that isn't implemented.
1660 ComponentFuncDef::Import(_) => {
1661 bail!(
1662 "component export `{name}` is a reexport of an imported function which is not implemented"
1663 )
1664 }
1665
1666 ComponentFuncDef::UnsafeIntrinsic(_) => {
1667 bail!(
1668 "component export `{name}` is a reexport of an intrinsic function which is not supported"
1669 )
1670 }
1671 },
1672
1673 ComponentItemDef::Instance(instance) => {
1674 let mut exports = IndexMap::new();
1675 match instance {
1676 ComponentInstanceDef::Intrinsics => {
1677 bail!(
1678 "component export `{name}` is a reexport of the intrinsics instance which is not supported"
1679 )
1680 }
1681
1682 // If this instance is one that was originally imported by
1683 // the component itself then the imports are translated here
1684 // by converting to a `ComponentItemDef` and then
1685 // recursively recording the export as a reexport.
1686 //
1687 // Note that for now this would only work with
1688 // module-exporting instances.
1689 ComponentInstanceDef::Import(path, ty) => {
1690 for (name, ty) in types[ty].exports.iter() {
1691 let path = path.push(name);
1692 let def = ComponentItemDef::from_import(path, ty.ty)?;
1693 self.record_export(name, def, ty.data.clone(), types, &mut exports)?;
1694 }
1695 dfg::Export::Instance { ty, exports }
1696 }
1697
1698 // An exported instance which is itself a bag of items is
1699 // translated recursively here to our `exports` map which is
1700 // the bag of items we're exporting.
1701 ComponentInstanceDef::Items(map, ty) => {
1702 for (name, (def, data)) in map {
1703 let data = ComponentExternData::new(data);
1704 self.record_export(name, def, data.clone(), types, &mut exports)?;
1705 }
1706 dfg::Export::Instance { ty, exports }
1707 }
1708 }
1709 }
1710
1711 // FIXME(#4283) should make an official decision on whether this is
1712 // the final treatment of this or not.
1713 ComponentItemDef::Component(_) => {
1714 bail!("exporting a component from the root component is not supported")
1715 }
1716
1717 ComponentItemDef::Type(def) => dfg::Export::Type(def),
1718 };
1719
1720 map.insert(name.to_string(), (export, data));
1721 Ok(())
1722 }
1723}
1724
1725impl<'a> InlinerFrame<'a> {
1726 fn new(
1727 instance: RuntimeComponentInstanceIndex,
1728 translation: &'a Translation<'a>,
1729 closure: ComponentClosure<'a>,
1730 args: HashMap<&'a str, ComponentItemDef<'a>>,
1731 instance_ty: Option<ComponentInstanceTypeId>,
1732 ) -> Self {
1733 // FIXME: should iterate over the initializers of `translation` and
1734 // calculate the size of each index space to use `with_capacity` for
1735 // all the maps below. Given that doing such would be wordy and compile
1736 // time is otherwise not super crucial it's not done at this time.
1737 InlinerFrame {
1738 instance,
1739 translation,
1740 closure,
1741 args,
1742 instance_ty,
1743 initializers: translation.initializers.iter(),
1744
1745 funcs: Default::default(),
1746 memories: Default::default(),
1747 tables: Default::default(),
1748 globals: Default::default(),
1749 tags: Default::default(),
1750
1751 component_instances: Default::default(),
1752 component_funcs: Default::default(),
1753 module_instances: Default::default(),
1754 components: Default::default(),
1755 modules: Default::default(),
1756 }
1757 }
1758
1759 fn item(
1760 &self,
1761 index: ComponentItem,
1762 types: &mut ComponentTypesBuilder,
1763 ) -> Result<ComponentItemDef<'a>> {
1764 Ok(match index {
1765 ComponentItem::Func(i) => ComponentItemDef::Func(self.component_funcs[i].clone()),
1766 ComponentItem::Component(i) => ComponentItemDef::Component(self.components[i].clone()),
1767 ComponentItem::ComponentInstance(i) => {
1768 ComponentItemDef::Instance(self.component_instances[i].clone())
1769 }
1770 ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()),
1771 ComponentItem::Type(t) => {
1772 let types_ref = self.translation.types_ref();
1773 ComponentItemDef::Type(types.convert_type(types_ref, t)?)
1774 }
1775 })
1776 }
1777
1778 /// Pushes the component `item` definition provided into the appropriate
1779 /// index space within this component.
1780 fn push_item(&mut self, item: ComponentItemDef<'a>) {
1781 match item {
1782 ComponentItemDef::Func(i) => {
1783 self.component_funcs.push(i);
1784 }
1785 ComponentItemDef::Module(i) => {
1786 self.modules.push(i);
1787 }
1788 ComponentItemDef::Component(i) => {
1789 self.components.push(i);
1790 }
1791 ComponentItemDef::Instance(i) => {
1792 self.component_instances.push(i);
1793 }
1794
1795 // In short, type definitions aren't tracked here.
1796 //
1797 // The longer form explanation for this is that structural types
1798 // like lists and records don't need to be tracked at all and the
1799 // only significant type which needs tracking is resource types
1800 // themselves. Resource types, however, are tracked within the
1801 // `ResourcesBuilder` state rather than an `InlinerFrame` so they're
1802 // ignored here as well. The general reason for that is that type
1803 // information is everywhere and this `InlinerFrame` is not
1804 // everywhere so it seemed like it would make sense to split the
1805 // two.
1806 //
1807 // Note though that this case is actually frequently hit, so it
1808 // can't be `unreachable!()`. Instead callers are responsible for
1809 // handling this appropriately with respect to resources.
1810 ComponentItemDef::Type(_ty) => {}
1811 }
1812 }
1813
1814 fn closed_over_module(&self, index: &ClosedOverModule) -> ModuleDef<'a> {
1815 match *index {
1816 ClosedOverModule::Local(i) => self.modules[i].clone(),
1817 ClosedOverModule::Upvar(i) => self.closure.modules[i].clone(),
1818 }
1819 }
1820
1821 fn closed_over_component(&self, index: &ClosedOverComponent) -> ComponentDef<'a> {
1822 match *index {
1823 ClosedOverComponent::Local(i) => self.components[i].clone(),
1824 ClosedOverComponent::Upvar(i) => self.closure.components[i].clone(),
1825 }
1826 }
1827
1828 /// Completes the instantiation of a subcomponent and records type
1829 /// information for the instance that was produced.
1830 ///
1831 /// This method is invoked when an `InlinerFrame` finishes for a
1832 /// subcomponent. The `def` provided represents the instance that was
1833 /// produced from instantiation, and `ty` is the wasmparser-defined type of
1834 /// the instance produced.
1835 ///
1836 /// The purpose of this method is to record type information about resources
1837 /// in the instance produced. In the component model all instantiations of a
1838 /// component produce fresh new types for all resources which are unequal to
1839 /// all prior resources. This means that if wasmparser's `ty` type
1840 /// information references a unique resource within `def` that has never
1841 /// been registered before then that means it's a defined resource within
1842 /// the component that was just instantiated (as opposed to an imported
1843 /// resource which was reexported).
1844 ///
1845 /// Further type translation after this instantiation can refer to these
1846 /// resource types and a mapping from those types to the wasmtime-internal
1847 /// types is required, so this method builds up those mappings.
1848 ///
1849 /// Essentially what happens here is that the `ty` type is registered and
1850 /// any new unique resources are registered so new tables can be introduced
1851 /// along with origin information about the actual underlying resource type
1852 /// and which component instantiated it.
1853 fn finish_instantiate(
1854 &mut self,
1855 exports: IndexMap<&'a str, (ComponentItemDef<'a>, wasmparser::ComponentExternName<'a>)>,
1856 ty: ComponentInstanceTypeId,
1857 types: &mut ComponentTypesBuilder,
1858 ) -> Result<()> {
1859 let types_ref = self.translation.types_ref();
1860 {
1861 let (resources, types) = types.resources_mut_and_types();
1862 let mut path = Vec::new();
1863 resources.register_component_entity_type(
1864 &types_ref,
1865 ComponentEntityType::Instance(ty),
1866 &mut path,
1867 &mut |path| match path {
1868 [] => unreachable!(),
1869 [name, rest @ ..] => exports[name].0.lookup_resource(rest, types),
1870 },
1871 );
1872 }
1873 let ty = types.convert_instance(types_ref, ty)?;
1874 let def = ComponentInstanceDef::Items(exports, ty);
1875 let arg = ComponentItemDef::Instance(def);
1876 self.push_item(arg);
1877 Ok(())
1878 }
1879}
1880
1881impl<'a> ImportPath<'a> {
1882 fn root(index: ImportIndex) -> ImportPath<'a> {
1883 ImportPath {
1884 index,
1885 path: Vec::new(),
1886 }
1887 }
1888
1889 fn push(&self, s: impl Into<Cow<'a, str>>) -> ImportPath<'a> {
1890 let mut new = self.clone();
1891 new.path.push(s.into());
1892 new
1893 }
1894}
1895
1896impl<'a> ComponentItemDef<'a> {
1897 fn from_import(path: ImportPath<'a>, ty: TypeDef) -> Result<ComponentItemDef<'a>> {
1898 let item = match ty {
1899 TypeDef::Module(ty) => ComponentItemDef::Module(ModuleDef::Import(path, ty)),
1900 TypeDef::ComponentInstance(ty) => {
1901 ComponentItemDef::Instance(ComponentInstanceDef::Import(path, ty))
1902 }
1903 TypeDef::ComponentFunc(_ty) => ComponentItemDef::Func(ComponentFuncDef::Import(path)),
1904 // FIXME(#4283) should commit one way or another to how this
1905 // should be treated.
1906 TypeDef::Component(_ty) => bail!("root-level component imports are not supported"),
1907 TypeDef::Interface(_) | TypeDef::Resource(_) => ComponentItemDef::Type(ty),
1908 TypeDef::CoreFunc(_) => unreachable!(),
1909 };
1910 Ok(item)
1911 }
1912
1913 /// Walks the `path` within `self` to find a resource at that path.
1914 ///
1915 /// This method is used when resources are found within wasmparser's type
1916 /// information and they need to be correlated with actual concrete
1917 /// definitions from this inlining pass. The `path` here is a list of
1918 /// instance export names (or empty) to walk to reach down into the final
1919 /// definition which should refer to a resource itself.
1920 fn lookup_resource(&self, path: &[&str], types: &ComponentTypes) -> ResourceIndex {
1921 let mut cur = self.clone();
1922
1923 // Each element of `path` represents unwrapping a layer of an instance
1924 // type, so handle those here by updating `cur` iteratively.
1925 for element in path.iter().copied() {
1926 let instance = match cur {
1927 ComponentItemDef::Instance(def) => def,
1928 _ => unreachable!(),
1929 };
1930 cur = match instance {
1931 // If this instance is a "bag of things" then this is as easy as
1932 // looking up the name in the bag of names.
1933 ComponentInstanceDef::Items(names, _) => names[element].0.clone(),
1934
1935 // If, however, this instance is an imported instance then this
1936 // is a further projection within the import with one more path
1937 // element. The `types` type information is used to lookup the
1938 // type of `element` within the instance type, and that's used
1939 // in conjunction with a one-longer `path` to produce a new item
1940 // definition.
1941 ComponentInstanceDef::Import(path, ty) => {
1942 ComponentItemDef::from_import(path.push(element), types[ty].exports[element].ty)
1943 .unwrap()
1944 }
1945 ComponentInstanceDef::Intrinsics => {
1946 unreachable!("intrinsics do not define resources")
1947 }
1948 };
1949 }
1950
1951 // Once `path` has been iterated over it must be the case that the final
1952 // item is a resource type, in which case a lookup can be performed.
1953 match cur {
1954 ComponentItemDef::Type(TypeDef::Resource(idx)) => types[idx].unwrap_concrete_ty(),
1955 _ => unreachable!(),
1956 }
1957 }
1958}
1959
1960#[derive(Clone, Copy)]
1961enum InstanceModule {
1962 Static(StaticModuleIndex),
1963 Import(TypeModuleIndex),
1964}
1965
1966impl ComponentExternData {
1967 fn new(data: wasmparser::ComponentExternName<'_>) -> Self {
1968 ComponentExternData {
1969 implements: data.implements.map(|s| s.to_string()),
1970 external_id: data.external_id.map(|s| s.to_string()),
1971 }
1972 }
1973}