Path: blob/main/crates/environ/src/component/translate/inline.rs
3081 views
//! Implementation of "inlining" a component into a flat list of initializers.1//!2//! After the first phase of compiling a component we're left with a single3//! root `Translation` for the original component along with a "static" list of4//! child components. Each `Translation` has a list of `LocalInitializer` items5//! inside of it which is a primitive representation of how the component6//! should be constructed with effectively one initializer per item in the7//! index space of a component. This "local initializer" list would be8//! relatively inefficient to process at runtime and more importantly doesn't9//! convey enough information to understand what trampolines need to be10//! compiled or what fused adapters need to be generated. This consequently is11//! the motivation for this file.12//!13//! The second phase of compilation, inlining here, will in a sense interpret14//! the initializers, at compile time, into a new list of `GlobalInitializer` entries15//! which are a sort of "global initializer". The generated `GlobalInitializer` is16//! much more specific than the `LocalInitializer` and additionally far fewer17//! `GlobalInitializer` structures are generated (in theory) than there are local18//! initializers.19//!20//! The "inlining" portion of the name of this module indicates how the21//! instantiation of a component is interpreted as calling a function. The22//! function's arguments are the imports provided to the instantiation of a23//! component, and further nested function calls happen on a stack when a24//! nested component is instantiated. The inlining then refers to how this25//! stack of instantiations is flattened to one list of `GlobalInitializer`26//! entries to represent the process of instantiating a component graph,27//! similar to how function inlining removes call instructions and creates one28//! giant function for a call graph. Here there are no inlining heuristics or29//! anything like that, we simply inline everything into the root component's30//! list of initializers.31//!32//! Another primary task this module performs is a form of dataflow analysis33//! to represent items in each index space with their definition rather than34//! references of relative indices. These definitions (all the `*Def` types in35//! this module) are not local to any one nested component and instead36//! represent state available at runtime tracked in the final `Component`37//! produced.38//!39//! With all this pieced together the general idea is relatively40//! straightforward. All of a component's initializers are processed in sequence41//! where instantiating a nested component pushes a "frame" onto a stack to42//! start executing and we resume at the old one when we're done. Items are43//! tracked where they come from and at the end after processing only the44//! side-effectful initializers are emitted to the `GlobalInitializer` list in the45//! final `Component`.4647use crate::component::translate::*;48use crate::{EntityType, IndexType};49use core::str::FromStr;50use std::borrow::Cow;51use wasmparser::component_types::{ComponentAnyTypeId, ComponentCoreModuleTypeId};5253pub(super) fn run(54types: &mut ComponentTypesBuilder,55result: &Translation<'_>,56nested_modules: &PrimaryMap<StaticModuleIndex, ModuleTranslation<'_>>,57nested_components: &PrimaryMap<StaticComponentIndex, Translation<'_>>,58) -> Result<dfg::ComponentDfg> {59let mut inliner = Inliner {60nested_modules,61nested_components,62result: Default::default(),63import_path_interner: Default::default(),64runtime_instances: PrimaryMap::default(),65};6667let index = RuntimeComponentInstanceIndex::from_u32(0);6869// The initial arguments to the root component are all host imports. This70// means that they're all using the `ComponentItemDef::Host` variant. Here71// an `ImportIndex` is allocated for each item and then the argument is72// recorded.73//74// Note that this is represents the abstract state of a host import of an75// item since we don't know the precise structure of the host import.76let mut args = HashMap::with_capacity(result.exports.len());77let mut path = Vec::new();78types.resources_mut().set_current_instance(index);79let types_ref = result.types_ref();80for init in result.initializers.iter() {81let (name, ty) = match *init {82LocalInitializer::Import(name, ty) => (name, ty),83_ => continue,84};8586// Before `convert_component_entity_type` below all resource types87// introduced by this import need to be registered and have indexes88// assigned to them. Any fresh new resource type referred to by imports89// is a brand new introduction of a resource which needs to have a type90// allocated to it, so new runtime imports are injected for each91// resource along with updating the `imported_resources` map.92let index = inliner.result.import_types.next_key();93types.resources_mut().register_component_entity_type(94&types_ref,95ty,96&mut path,97&mut |path| {98let index = inliner.runtime_import(&ImportPath {99index,100path: path.iter().copied().map(Into::into).collect(),101});102inliner.result.imported_resources.push(index)103},104);105106// With resources all taken care of it's now possible to convert this107// into Wasmtime's type system.108let ty = types.convert_component_entity_type(types_ref, ty)?;109110// Imports of types that aren't resources are not required to be111// specified by the host since it's just for type information within112// the component.113if let TypeDef::Interface(_) = ty {114continue;115}116let index = inliner.result.import_types.push((name.0.to_string(), ty));117let path = ImportPath::root(index);118args.insert(name.0, ComponentItemDef::from_import(path, ty)?);119}120121// This will run the inliner to completion after being seeded with the122// initial frame. When the inliner finishes it will return the exports of123// the root frame which are then used for recording the exports of the124// component.125inliner.result.num_runtime_component_instances += 1;126let frame = InlinerFrame::new(index, result, ComponentClosure::default(), args, None);127let resources_snapshot = types.resources_mut().clone();128let mut frames = vec![(frame, resources_snapshot)];129let exports = inliner.run(types, &mut frames)?;130assert!(frames.is_empty());131132let mut export_map = Default::default();133for (name, def) in exports {134inliner.record_export(name, def, types, &mut export_map)?;135}136inliner.result.exports = export_map;137inliner.result.num_future_tables = types.num_future_tables();138inliner.result.num_stream_tables = types.num_stream_tables();139inliner.result.num_error_context_tables = types.num_error_context_tables();140141Ok(inliner.result)142}143144struct Inliner<'a> {145/// The list of static modules that were found during initial translation of146/// the component.147///148/// This is used during the instantiation of these modules to ahead-of-time149/// order the arguments precisely according to what the module is defined as150/// needing which avoids the need to do string lookups or permute arguments151/// at runtime.152nested_modules: &'a PrimaryMap<StaticModuleIndex, ModuleTranslation<'a>>,153154/// The list of static components that were found during initial translation of155/// the component.156///157/// This is used when instantiating nested components to push a new158/// `InlinerFrame` with the `Translation`s here.159nested_components: &'a PrimaryMap<StaticComponentIndex, Translation<'a>>,160161/// The final `Component` that is being constructed and returned from this162/// inliner.163result: dfg::ComponentDfg,164165// Maps used to "intern" various runtime items to only save them once at166// runtime instead of multiple times.167import_path_interner: HashMap<ImportPath<'a>, RuntimeImportIndex>,168169/// Origin information about where each runtime instance came from170runtime_instances: PrimaryMap<dfg::InstanceId, InstanceModule>,171}172173/// A "stack frame" as part of the inlining process, or the progress through174/// instantiating a component.175///176/// All instantiations of a component will create an `InlinerFrame` and are177/// incrementally processed via the `initializers` list here. Note that the178/// inliner frames are stored on the heap to avoid recursion based on user179/// input.180struct InlinerFrame<'a> {181instance: RuntimeComponentInstanceIndex,182183/// The remaining initializers to process when instantiating this component.184initializers: std::slice::Iter<'a, LocalInitializer<'a>>,185186/// The component being instantiated.187translation: &'a Translation<'a>,188189/// The "closure arguments" to this component, or otherwise the maps indexed190/// by `ModuleUpvarIndex` and `ComponentUpvarIndex`. This is created when191/// a component is created and stored as part of a component's state during192/// inlining.193closure: ComponentClosure<'a>,194195/// The arguments to the creation of this component.196///197/// At the root level these are all imports from the host and between198/// components this otherwise tracks how all the arguments are defined.199args: HashMap<&'a str, ComponentItemDef<'a>>,200201// core wasm index spaces202funcs: PrimaryMap<FuncIndex, (ModuleInternedTypeIndex, dfg::CoreDef)>,203memories: PrimaryMap<MemoryIndex, dfg::CoreExport<EntityIndex>>,204tables: PrimaryMap<TableIndex, dfg::CoreExport<EntityIndex>>,205globals: PrimaryMap<GlobalIndex, dfg::CoreExport<EntityIndex>>,206tags: PrimaryMap<TagIndex, dfg::CoreExport<EntityIndex>>,207modules: PrimaryMap<ModuleIndex, ModuleDef<'a>>,208209// component model index spaces210component_funcs: PrimaryMap<ComponentFuncIndex, ComponentFuncDef<'a>>,211module_instances: PrimaryMap<ModuleInstanceIndex, ModuleInstanceDef<'a>>,212component_instances: PrimaryMap<ComponentInstanceIndex, ComponentInstanceDef<'a>>,213components: PrimaryMap<ComponentIndex, ComponentDef<'a>>,214215/// The type of instance produced by completing the instantiation of this216/// frame.217///218/// This is a wasmparser-relative piece of type information which is used to219/// register resource types after instantiation has completed.220///221/// This is `Some` for all subcomponents and `None` for the root component.222instance_ty: Option<ComponentInstanceTypeId>,223}224225/// "Closure state" for a component which is resolved from the `ClosedOverVars`226/// state that was calculated during translation.227//228// FIXME: this is cloned quite a lot and given the internal maps if this is a229// perf issue we may want to `Rc` these fields. Note that this is only a perf230// hit at compile-time though which we in general don't pay too much231// attention to.232#[derive(Default, Clone)]233struct ComponentClosure<'a> {234modules: PrimaryMap<ModuleUpvarIndex, ModuleDef<'a>>,235components: PrimaryMap<ComponentUpvarIndex, ComponentDef<'a>>,236}237238/// Representation of a "path" into an import.239///240/// Imports from the host at this time are one of three things:241///242/// * Functions243/// * Core wasm modules244/// * "Instances" of these three items245///246/// The "base" values are functions and core wasm modules, but the abstraction247/// of an instance allows embedding functions/modules deeply within other248/// instances. This "path" represents optionally walking through a host instance249/// to get to the final desired item. At runtime instances are just maps of250/// values and so this is used to ensure that we primarily only deal with251/// individual functions and modules instead of synthetic instances.252#[derive(Clone, PartialEq, Hash, Eq)]253struct ImportPath<'a> {254index: ImportIndex,255path: Vec<Cow<'a, str>>,256}257258/// Representation of all items which can be defined within a component.259///260/// This is the "value" of an item defined within a component and is used to261/// represent both imports and exports.262#[derive(Clone)]263enum ComponentItemDef<'a> {264Component(ComponentDef<'a>),265Instance(ComponentInstanceDef<'a>),266Func(ComponentFuncDef<'a>),267Module(ModuleDef<'a>),268Type(TypeDef),269}270271#[derive(Clone)]272enum ModuleDef<'a> {273/// A core wasm module statically defined within the original component.274///275/// The `StaticModuleIndex` indexes into the `static_modules` map in the276/// `Inliner`.277Static(StaticModuleIndex, ComponentCoreModuleTypeId),278279/// A core wasm module that was imported from the host.280Import(ImportPath<'a>, TypeModuleIndex),281}282283// Note that unlike all other `*Def` types which are not allowed to have local284// indices this type does indeed have local indices. That is represented with285// the lack of a `Clone` here where once this is created it's never moved across286// components because module instances always stick within one component.287enum ModuleInstanceDef<'a> {288/// A core wasm module instance was created through the instantiation of a289/// module.290///291/// The `RuntimeInstanceIndex` was the index allocated as this was the292/// `n`th instantiation and the `ModuleIndex` points into an293/// `InlinerFrame`'s local index space.294Instantiated(dfg::InstanceId, ModuleIndex),295296/// A "synthetic" core wasm module which is just a bag of named indices.297///298/// Note that this can really only be used for passing as an argument to299/// another module's instantiation and is used to rename arguments locally.300Synthetic(&'a HashMap<&'a str, EntityIndex>),301}302303#[derive(Clone)]304enum ComponentFuncDef<'a> {305/// A compile-time builtin intrinsic.306UnsafeIntrinsic(UnsafeIntrinsic),307308/// A host-imported component function.309Import(ImportPath<'a>),310311/// A core wasm function was lifted into a component function.312Lifted {313/// The component function type.314ty: TypeFuncIndex,315/// The core Wasm function.316func: dfg::CoreDef,317/// Canonical options.318options: AdapterOptions,319},320}321322#[derive(Clone)]323enum ComponentInstanceDef<'a> {324/// The `__wasmtime_intrinsics` instance that exports all of our325/// compile-time builtin intrinsics.326Intrinsics,327328/// A host-imported instance.329///330/// This typically means that it's "just" a map of named values. It's not331/// actually supported to take a `wasmtime::component::Instance` and pass it332/// to another instance at this time.333Import(ImportPath<'a>, TypeComponentInstanceIndex),334335/// A concrete map of values.336///337/// This is used for both instantiated components as well as "synthetic"338/// components. This variant can be used for both because both are339/// represented by simply a bag of items within the entire component340/// instantiation process.341//342// FIXME: same as the issue on `ComponentClosure` where this is cloned a lot343// and may need `Rc`.344Items(345IndexMap<&'a str, ComponentItemDef<'a>>,346TypeComponentInstanceIndex,347),348}349350#[derive(Clone)]351struct ComponentDef<'a> {352index: StaticComponentIndex,353closure: ComponentClosure<'a>,354}355356impl<'a> Inliner<'a> {357/// Symbolically instantiates a component using the type information and358/// `frames` provided.359///360/// The `types` provided is the type information for the entire component361/// translation process. This is a distinct output artifact separate from362/// the component metadata.363///364/// The `frames` argument is storage to handle a "call stack" of components365/// instantiating one another. The youngest frame (last element) of the366/// frames list is a component that's currently having its initializers367/// processed. The second element of each frame is a snapshot of the368/// resource-related information just before the frame was translated. For369/// more information on this snapshotting see the documentation on370/// `ResourcesBuilder`.371fn run(372&mut self,373types: &mut ComponentTypesBuilder,374frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,375) -> Result<IndexMap<&'a str, ComponentItemDef<'a>>> {376// This loop represents the execution of the instantiation of a377// component. This is an iterative process which is finished once all378// initializers are processed. Currently this is modeled as an infinite379// loop which drives the top-most iterator of the `frames` stack380// provided as an argument to this function.381loop {382let (frame, _) = frames.last_mut().unwrap();383types.resources_mut().set_current_instance(frame.instance);384match frame.initializers.next() {385// Process the initializer and if it started the instantiation386// of another component then we push that frame on the stack to387// continue onwards.388Some(init) => match self.initializer(frames, types, init)? {389Some(new_frame) => {390frames.push((new_frame, types.resources_mut().clone()));391}392None => {}393},394395// If there are no more initializers for this frame then the396// component it represents has finished instantiation. The397// exports of the component are collected and then the entire398// frame is discarded. The exports are then either pushed in the399// parent frame, if any, as a new component instance or they're400// returned from this function for the root set of exports.401None => {402let exports = frame403.translation404.exports405.iter()406.map(|(name, item)| Ok((*name, frame.item(*item, types)?)))407.collect::<Result<_>>()?;408let instance_ty = frame.instance_ty;409let (_, snapshot) = frames.pop().unwrap();410*types.resources_mut() = snapshot;411match frames.last_mut() {412Some((parent, _)) => {413parent.finish_instantiate(exports, instance_ty.unwrap(), types)?;414}415None => break Ok(exports),416}417}418}419}420}421422fn initializer(423&mut self,424frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,425types: &mut ComponentTypesBuilder,426initializer: &'a LocalInitializer,427) -> Result<Option<InlinerFrame<'a>>> {428use LocalInitializer::*;429430let (frame, _) = frames.last_mut().unwrap();431match initializer {432// When a component imports an item the actual definition of the433// item is looked up here (not at runtime) via its name. The434// arguments provided in our `InlinerFrame` describe how each435// argument was defined, so we simply move it from there into the436// correct index space.437//438// Note that for the root component this will add `*::Import` items439// but for sub-components this will do resolution to connect what440// was provided as an import at the instantiation-site to what was441// needed during the component's instantiation.442Import(name, ty) => {443let arg = match frame.args.get(name.0) {444Some(arg) => arg,445446// Not all arguments need to be provided for instantiation,447// namely the root component in Wasmtime doesn't require448// structural type imports to be satisfied. These type449// imports are relevant for bindings generators and such but450// as a runtime there's not really a definition to fit in.451//452// If no argument was provided for `name` then it's asserted453// that this is a type import and additionally it's not a454// resource type import (which indeed must be provided). If455// all that passes then this initializer is effectively456// skipped.457None => {458match ty {459ComponentEntityType::Type {460created: ComponentAnyTypeId::Resource(_),461..462} => unreachable!(),463ComponentEntityType::Type { .. } => {}464_ => unreachable!(),465}466return Ok(None);467}468};469470// Next resource types need to be handled. For example if a471// resource is imported into this component then it needs to be472// assigned a unique table to provide the isolation guarantees473// of resources (this component's table is shared with no474// others). Here `register_component_entity_type` will find475// imported resources and then `lookup_resource` will find the476// resource within `arg` as necessary to lookup the original477// true definition of this resource.478//479// This is what enables tracking true resource origins480// throughout component translation while simultaneously also481// tracking unique tables for each resource in each component.482let mut path = Vec::new();483let (resources, types) = types.resources_mut_and_types();484resources.register_component_entity_type(485&frame.translation.types_ref(),486*ty,487&mut path,488&mut |path| arg.lookup_resource(path, types),489);490491// And now with all the type information out of the way the492// `arg` definition is moved into its corresponding index space.493frame.push_item(arg.clone());494}495496IntrinsicsImport => {497frame498.component_instances499.push(ComponentInstanceDef::Intrinsics);500}501502// Lowering a component function to a core wasm function is503// generally what "triggers compilation". Here various metadata is504// recorded and then the final component gets an initializer505// recording the lowering.506//507// NB: at this time only lowered imported functions are supported.508Lower {509func,510options,511lower_ty,512} => {513let lower_ty =514types.convert_component_func_type(frame.translation.types_ref(), *lower_ty)?;515let options_lower = self.adapter_options(frames, types, options);516let (frame, _) = frames.last_mut().unwrap();517let lower_core_type = options_lower.core_type;518let func = match &frame.component_funcs[*func] {519// If this component function was originally a host import520// then this is a lowered host function which needs a521// trampoline to enter WebAssembly. That's recorded here522// with all relevant information.523ComponentFuncDef::Import(path) => {524let import = self.runtime_import(path);525let options = self.canonical_options(options_lower);526let index = self.result.trampolines.push((527lower_core_type,528dfg::Trampoline::LowerImport {529import,530options,531lower_ty,532},533));534dfg::CoreDef::Trampoline(index)535}536537// Lowering a lifted functio means that a "fused adapter"538// was just identified.539//540// Metadata about this fused adapter is recorded in the541// `Adapters` output of this compilation pass. Currently the542// implementation of fused adapters is to generate a core543// wasm module which is instantiated with relevant imports544// and the exports are used as the fused adapters. At this545// time we don't know when precisely the instance will be546// created but we do know that the result of this will be an547// export from a previously-created instance.548//549// To model this the result of this arm is a550// `CoreDef::Export`. The actual indices listed within the551// export are "fake indices" in the sense of they're not552// resolved yet. This resolution will happen at a later553// compilation phase. Any usages of the `CoreDef::Export`554// here will be detected and rewritten to an actual runtime555// instance created.556//557// The `instance` field of the `CoreExport` has a marker558// which indicates that it's a fused adapter. The `item` is559// a function where the function index corresponds to the560// `adapter_idx` which contains the metadata about this561// adapter being created. The metadata is used to learn562// about the dependencies and when the adapter module can563// be instantiated.564ComponentFuncDef::Lifted {565ty: lift_ty,566func,567options: options_lift,568} => {569let adapter_idx = self.result.adapters.push(Adapter {570lift_ty: *lift_ty,571lift_options: options_lift.clone(),572lower_ty,573lower_options: options_lower,574func: func.clone(),575});576dfg::CoreDef::Adapter(adapter_idx)577}578579ComponentFuncDef::UnsafeIntrinsic(intrinsic) => {580dfg::CoreDef::UnsafeIntrinsic(options.core_type, *intrinsic)581}582};583frame.funcs.push((lower_core_type, func));584}585586// Lifting a core wasm function is relatively easy for now in that587// some metadata about the lifting is simply recorded. This'll get588// plumbed through to exports or a fused adapter later on.589Lift(ty, func, options) => {590let ty = types.convert_component_func_type(frame.translation.types_ref(), *ty)?;591let options = self.adapter_options(frames, types, options);592let (frame, _) = frames.last_mut().unwrap();593let func = frame.funcs[*func].1.clone();594frame595.component_funcs596.push(ComponentFuncDef::Lifted { ty, func, options });597}598599// A new resource type is being introduced, so it's recorded as a600// brand new resource in the final `resources` array. Additionally601// for now resource introductions are considered side effects to602// know when to register their destructors so that's recorded as603// well.604//605// Note that this has the effect of when a component is instantiated606// twice it will produce unique types for the resources from each607// instantiation. That's the intended runtime semantics and608// implementation here, however.609Resource(ty, rep, dtor) => {610let idx = self.result.resources.push(dfg::Resource {611rep: *rep,612dtor: dtor.map(|i| frame.funcs[i].1.clone()),613instance: frame.instance,614});615self.result616.side_effects617.push(dfg::SideEffect::Resource(idx));618619// Register with type translation that all future references to620// `ty` will refer to `idx`.621//622// Note that this registration information is lost when this623// component finishes instantiation due to the snapshotting624// behavior in the frame processing loop above. This is also625// intended, though, since `ty` can't be referred to outside of626// this component.627let idx = self.result.resource_index(idx);628types.resources_mut().register_resource(ty.resource(), idx);629}630631// Resource-related intrinsics are generally all the same.632// Wasmparser type information is converted to wasmtime type633// information and then new entries for each intrinsic are recorded.634ResourceNew(id, ty) => {635let id = types.resource_id(id.resource());636let index = self.result.trampolines.push((637*ty,638dfg::Trampoline::ResourceNew {639instance: frame.instance,640ty: id,641},642));643frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));644}645ResourceRep(id, ty) => {646let id = types.resource_id(id.resource());647let index = self.result.trampolines.push((648*ty,649dfg::Trampoline::ResourceRep {650instance: frame.instance,651ty: id,652},653));654frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));655}656ResourceDrop(id, ty) => {657let id = types.resource_id(id.resource());658let index = self.result.trampolines.push((659*ty,660dfg::Trampoline::ResourceDrop {661instance: frame.instance,662ty: id,663},664));665frame.funcs.push((*ty, dfg::CoreDef::Trampoline(index)));666}667BackpressureInc { func } => {668let index = self.result.trampolines.push((669*func,670dfg::Trampoline::BackpressureInc {671instance: frame.instance,672},673));674frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));675}676BackpressureDec { func } => {677let index = self.result.trampolines.push((678*func,679dfg::Trampoline::BackpressureDec {680instance: frame.instance,681},682));683frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));684}685TaskReturn { result, options } => {686let results = result687.iter()688.map(|ty| types.valtype(frame.translation.types_ref(), ty))689.collect::<Result<_>>()?;690let results = types.new_tuple_type(results);691let func = options.core_type;692let options = self.adapter_options(frames, types, options);693let (frame, _) = frames.last_mut().unwrap();694let options = self.canonical_options(options);695let index = self.result.trampolines.push((696func,697dfg::Trampoline::TaskReturn {698instance: frame.instance,699results,700options,701},702));703frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));704}705TaskCancel { func } => {706let index = self.result.trampolines.push((707*func,708dfg::Trampoline::TaskCancel {709instance: frame.instance,710},711));712frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));713}714WaitableSetNew { func } => {715let index = self.result.trampolines.push((716*func,717dfg::Trampoline::WaitableSetNew {718instance: frame.instance,719},720));721frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));722}723WaitableSetWait { options } => {724let func = options.core_type;725let options = self.adapter_options(frames, types, options);726let (frame, _) = frames.last_mut().unwrap();727let options = self.canonical_options(options);728let index = self.result.trampolines.push((729func,730dfg::Trampoline::WaitableSetWait {731instance: frame.instance,732options,733},734));735frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));736}737WaitableSetPoll { options } => {738let func = options.core_type;739let options = self.adapter_options(frames, types, options);740let (frame, _) = frames.last_mut().unwrap();741let options = self.canonical_options(options);742let index = self.result.trampolines.push((743func,744dfg::Trampoline::WaitableSetPoll {745instance: frame.instance,746options,747},748));749frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));750}751WaitableSetDrop { func } => {752let index = self.result.trampolines.push((753*func,754dfg::Trampoline::WaitableSetDrop {755instance: frame.instance,756},757));758frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));759}760WaitableJoin { func } => {761let index = self.result.trampolines.push((762*func,763dfg::Trampoline::WaitableJoin {764instance: frame.instance,765},766));767frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));768}769ThreadYield { func, cancellable } => {770let index = self.result.trampolines.push((771*func,772dfg::Trampoline::ThreadYield {773instance: frame.instance,774cancellable: *cancellable,775},776));777frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));778}779SubtaskDrop { func } => {780let index = self.result.trampolines.push((781*func,782dfg::Trampoline::SubtaskDrop {783instance: frame.instance,784},785));786frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));787}788SubtaskCancel { func, async_ } => {789let index = self.result.trampolines.push((790*func,791dfg::Trampoline::SubtaskCancel {792instance: frame.instance,793async_: *async_,794},795));796frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));797}798StreamNew { ty, func } => {799let InterfaceType::Stream(ty) =800types.defined_type(frame.translation.types_ref(), *ty)?801else {802unreachable!()803};804let index = self.result.trampolines.push((805*func,806dfg::Trampoline::StreamNew {807instance: frame.instance,808ty,809},810));811frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));812}813StreamRead { ty, options } => {814let InterfaceType::Stream(ty) =815types.defined_type(frame.translation.types_ref(), *ty)?816else {817unreachable!()818};819let func = options.core_type;820let options = self.adapter_options(frames, types, options);821let (frame, _) = frames.last_mut().unwrap();822let options = self.canonical_options(options);823let index = self.result.trampolines.push((824func,825dfg::Trampoline::StreamRead {826instance: frame.instance,827ty,828options,829},830));831frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));832}833StreamWrite { ty, options } => {834let InterfaceType::Stream(ty) =835types.defined_type(frame.translation.types_ref(), *ty)?836else {837unreachable!()838};839let func = options.core_type;840let options = self.adapter_options(frames, types, options);841let (frame, _) = frames.last_mut().unwrap();842let options = self.canonical_options(options);843let index = self.result.trampolines.push((844func,845dfg::Trampoline::StreamWrite {846instance: frame.instance,847ty,848options,849},850));851frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));852}853StreamCancelRead { ty, func, async_ } => {854let InterfaceType::Stream(ty) =855types.defined_type(frame.translation.types_ref(), *ty)?856else {857unreachable!()858};859let index = self.result.trampolines.push((860*func,861dfg::Trampoline::StreamCancelRead {862instance: frame.instance,863ty,864async_: *async_,865},866));867frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));868}869StreamCancelWrite { ty, func, async_ } => {870let InterfaceType::Stream(ty) =871types.defined_type(frame.translation.types_ref(), *ty)?872else {873unreachable!()874};875let index = self.result.trampolines.push((876*func,877dfg::Trampoline::StreamCancelWrite {878instance: frame.instance,879ty,880async_: *async_,881},882));883frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));884}885StreamDropReadable { ty, func } => {886let InterfaceType::Stream(ty) =887types.defined_type(frame.translation.types_ref(), *ty)?888else {889unreachable!()890};891let index = self.result.trampolines.push((892*func,893dfg::Trampoline::StreamDropReadable {894instance: frame.instance,895ty,896},897));898frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));899}900StreamDropWritable { ty, func } => {901let InterfaceType::Stream(ty) =902types.defined_type(frame.translation.types_ref(), *ty)?903else {904unreachable!()905};906let index = self.result.trampolines.push((907*func,908dfg::Trampoline::StreamDropWritable {909instance: frame.instance,910ty,911},912));913frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));914}915FutureNew { ty, func } => {916let InterfaceType::Future(ty) =917types.defined_type(frame.translation.types_ref(), *ty)?918else {919unreachable!()920};921let index = self.result.trampolines.push((922*func,923dfg::Trampoline::FutureNew {924instance: frame.instance,925ty,926},927));928frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));929}930FutureRead { ty, options } => {931let InterfaceType::Future(ty) =932types.defined_type(frame.translation.types_ref(), *ty)?933else {934unreachable!()935};936let func = options.core_type;937let options = self.adapter_options(frames, types, options);938let (frame, _) = frames.last_mut().unwrap();939let options = self.canonical_options(options);940let index = self.result.trampolines.push((941func,942dfg::Trampoline::FutureRead {943instance: frame.instance,944ty,945options,946},947));948frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));949}950FutureWrite { ty, options } => {951let InterfaceType::Future(ty) =952types.defined_type(frame.translation.types_ref(), *ty)?953else {954unreachable!()955};956let func = options.core_type;957let options = self.adapter_options(frames, types, options);958let (frame, _) = frames.last_mut().unwrap();959let options = self.canonical_options(options);960let index = self.result.trampolines.push((961func,962dfg::Trampoline::FutureWrite {963instance: frame.instance,964ty,965options,966},967));968frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));969}970FutureCancelRead { ty, func, async_ } => {971let InterfaceType::Future(ty) =972types.defined_type(frame.translation.types_ref(), *ty)?973else {974unreachable!()975};976let index = self.result.trampolines.push((977*func,978dfg::Trampoline::FutureCancelRead {979instance: frame.instance,980ty,981async_: *async_,982},983));984frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));985}986FutureCancelWrite { ty, func, async_ } => {987let InterfaceType::Future(ty) =988types.defined_type(frame.translation.types_ref(), *ty)?989else {990unreachable!()991};992let index = self.result.trampolines.push((993*func,994dfg::Trampoline::FutureCancelWrite {995instance: frame.instance,996ty,997async_: *async_,998},999));1000frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1001}1002FutureDropReadable { ty, func } => {1003let InterfaceType::Future(ty) =1004types.defined_type(frame.translation.types_ref(), *ty)?1005else {1006unreachable!()1007};1008let index = self.result.trampolines.push((1009*func,1010dfg::Trampoline::FutureDropReadable {1011instance: frame.instance,1012ty,1013},1014));1015frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1016}1017FutureDropWritable { ty, func } => {1018let InterfaceType::Future(ty) =1019types.defined_type(frame.translation.types_ref(), *ty)?1020else {1021unreachable!()1022};1023let index = self.result.trampolines.push((1024*func,1025dfg::Trampoline::FutureDropWritable {1026instance: frame.instance,1027ty,1028},1029));1030frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1031}1032ErrorContextNew { options } => {1033let ty = types.error_context_table_type()?;1034let func = options.core_type;1035let options = self.adapter_options(frames, types, options);1036let (frame, _) = frames.last_mut().unwrap();1037let options = self.canonical_options(options);1038let index = self.result.trampolines.push((1039func,1040dfg::Trampoline::ErrorContextNew {1041instance: frame.instance,1042ty,1043options,1044},1045));1046frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));1047}1048ErrorContextDebugMessage { options } => {1049let ty = types.error_context_table_type()?;1050let func = options.core_type;1051let options = self.adapter_options(frames, types, options);1052let (frame, _) = frames.last_mut().unwrap();1053let options = self.canonical_options(options);1054let index = self.result.trampolines.push((1055func,1056dfg::Trampoline::ErrorContextDebugMessage {1057instance: frame.instance,1058ty,1059options,1060},1061));1062frame.funcs.push((func, dfg::CoreDef::Trampoline(index)));1063}1064ErrorContextDrop { func } => {1065let ty = types.error_context_table_type()?;1066let index = self.result.trampolines.push((1067*func,1068dfg::Trampoline::ErrorContextDrop {1069instance: frame.instance,1070ty,1071},1072));1073frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1074}1075ContextGet { func, i } => {1076let index = self.result.trampolines.push((1077*func,1078dfg::Trampoline::ContextGet {1079instance: frame.instance,1080slot: *i,1081},1082));1083frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1084}1085ContextSet { func, i } => {1086let index = self.result.trampolines.push((1087*func,1088dfg::Trampoline::ContextSet {1089instance: frame.instance,1090slot: *i,1091},1092));1093frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1094}1095ThreadIndex { func } => {1096let index = self1097.result1098.trampolines1099.push((*func, dfg::Trampoline::ThreadIndex));1100frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1101}1102ThreadNewIndirect {1103func,1104start_func_table_index,1105start_func_ty,1106} => {1107let table_export = frame.tables[*start_func_table_index]1108.clone()1109.map_index(|i| match i {1110EntityIndex::Table(i) => i,1111_ => unreachable!(),1112});11131114let table_id = self.result.tables.push(table_export);1115let index = self.result.trampolines.push((1116*func,1117dfg::Trampoline::ThreadNewIndirect {1118instance: frame.instance,1119start_func_ty_idx: *start_func_ty,1120start_func_table_id: table_id,1121},1122));1123frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1124}1125ThreadSwitchTo { func, cancellable } => {1126let index = self.result.trampolines.push((1127*func,1128dfg::Trampoline::ThreadSwitchTo {1129instance: frame.instance,1130cancellable: *cancellable,1131},1132));1133frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1134}1135ThreadSuspend { func, cancellable } => {1136let index = self.result.trampolines.push((1137*func,1138dfg::Trampoline::ThreadSuspend {1139instance: frame.instance,1140cancellable: *cancellable,1141},1142));1143frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1144}1145ThreadResumeLater { func } => {1146let index = self.result.trampolines.push((1147*func,1148dfg::Trampoline::ThreadResumeLater {1149instance: frame.instance,1150},1151));1152frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1153}1154ThreadYieldTo { func, cancellable } => {1155let index = self.result.trampolines.push((1156*func,1157dfg::Trampoline::ThreadYieldTo {1158instance: frame.instance,1159cancellable: *cancellable,1160},1161));1162frame.funcs.push((*func, dfg::CoreDef::Trampoline(index)));1163}1164ModuleStatic(idx, ty) => {1165frame.modules.push(ModuleDef::Static(*idx, *ty));1166}11671168// Instantiation of a module is one of the meatier initializers that1169// we'll generate. The main magic here is that for a statically1170// known module we can order the imports as a list to exactly what1171// the static module needs to be instantiated. For imported modules,1172// however, the runtime string resolution must happen at runtime so1173// that is deferred here by organizing the arguments as a two-layer1174// `IndexMap` of what we're providing.1175//1176// In both cases though a new `RuntimeInstanceIndex` is allocated1177// and an initializer is recorded to indicate that it's being1178// instantiated.1179ModuleInstantiate(module, args) => {1180let (instance_module, init) = match &frame.modules[*module] {1181ModuleDef::Static(idx, _ty) => {1182let mut defs = Vec::new();1183for (module, name, _ty) in self.nested_modules[*idx].module.imports() {1184let instance = args[module];1185defs.push(1186self.core_def_of_module_instance_export(frame, instance, name),1187);1188}1189(1190InstanceModule::Static(*idx),1191dfg::Instance::Static(*idx, defs.into()),1192)1193}1194ModuleDef::Import(path, ty) => {1195let mut defs = IndexMap::new();1196for ((module, name), _) in types[*ty].imports.iter() {1197let instance = args[module.as_str()];1198let def =1199self.core_def_of_module_instance_export(frame, instance, name);1200defs.entry(module.to_string())1201.or_insert(IndexMap::new())1202.insert(name.to_string(), def);1203}1204let index = self.runtime_import(path);1205(1206InstanceModule::Import(*ty),1207dfg::Instance::Import(index, defs),1208)1209}1210};12111212let instance = self.result.instances.push(init);1213let instance2 = self.runtime_instances.push(instance_module);1214assert_eq!(instance, instance2);12151216self.result1217.side_effects1218.push(dfg::SideEffect::Instance(instance, frame.instance));12191220frame1221.module_instances1222.push(ModuleInstanceDef::Instantiated(instance, *module));1223}12241225ModuleSynthetic(map) => {1226frame1227.module_instances1228.push(ModuleInstanceDef::Synthetic(map));1229}12301231// This is one of the stages of the "magic" of implementing outer1232// aliases to components and modules. For more information on this1233// see the documentation on `LexicalScope`. This stage of the1234// implementation of outer aliases is where the `ClosedOverVars` is1235// transformed into a `ComponentClosure` state using the current1236// `InlinerFrame`'s state. This will capture the "runtime" state of1237// outer components and upvars and such naturally as part of the1238// inlining process.1239ComponentStatic(index, vars) => {1240frame.components.push(ComponentDef {1241index: *index,1242closure: ComponentClosure {1243modules: vars1244.modules1245.iter()1246.map(|(_, m)| frame.closed_over_module(m))1247.collect(),1248components: vars1249.components1250.iter()1251.map(|(_, m)| frame.closed_over_component(m))1252.collect(),1253},1254});1255}12561257// Like module instantiation is this is a "meaty" part, and don't be1258// fooled by the relative simplicity of this case. This is1259// implemented primarily by the `Inliner` structure and the design1260// of this entire module, so the "easy" step here is to simply1261// create a new inliner frame and return it to get pushed onto the1262// stack.1263ComponentInstantiate(component, args, ty) => {1264let component: &ComponentDef<'a> = &frame.components[*component];1265let index = RuntimeComponentInstanceIndex::from_u32(1266self.result.num_runtime_component_instances,1267);1268self.result.num_runtime_component_instances += 1;1269let frame = InlinerFrame::new(1270index,1271&self.nested_components[component.index],1272component.closure.clone(),1273args.iter()1274.map(|(name, item)| Ok((*name, frame.item(*item, types)?)))1275.collect::<Result<_>>()?,1276Some(*ty),1277);1278return Ok(Some(frame));1279}12801281ComponentSynthetic(map, ty) => {1282let items = map1283.iter()1284.map(|(name, index)| Ok((*name, frame.item(*index, types)?)))1285.collect::<Result<_>>()?;1286let types_ref = frame.translation.types_ref();1287let ty = types.convert_instance(types_ref, *ty)?;1288frame1289.component_instances1290.push(ComponentInstanceDef::Items(items, ty));1291}12921293// Core wasm aliases, this and the cases below, are creating1294// `CoreExport` items primarily to insert into the index space so we1295// can create a unique identifier pointing to each core wasm export1296// with the instance and relevant index/name as necessary.1297AliasExportFunc(instance, name) => {1298let (ty, def) = match &frame.module_instances[*instance] {1299ModuleInstanceDef::Instantiated(instance, module) => {1300let (ty, item) = match &frame.modules[*module] {1301ModuleDef::Static(idx, _ty) => {1302let entity = self.nested_modules[*idx].module.exports[*name];1303let ty = match entity {1304EntityIndex::Function(f) => {1305self.nested_modules[*idx].module.functions[f]1306.signature1307.unwrap_module_type_index()1308}1309_ => unreachable!(),1310};1311(ty, ExportItem::Index(entity))1312}1313ModuleDef::Import(_path, module_ty) => {1314let module_ty = &types.component_types()[*module_ty];1315let entity_ty = &module_ty.exports[&**name];1316let ty = entity_ty.unwrap_func().unwrap_module_type_index();1317(ty, ExportItem::Name((*name).to_string()))1318}1319};1320let def = dfg::CoreExport {1321instance: *instance,1322item,1323}1324.into();1325(ty, def)1326}1327ModuleInstanceDef::Synthetic(instance) => match instance[*name] {1328EntityIndex::Function(i) => frame.funcs[i].clone(),1329_ => unreachable!(),1330},1331};1332frame.funcs.push((ty, def));1333}13341335AliasExportTable(instance, name) => {1336frame.tables.push(1337match self.core_def_of_module_instance_export(frame, *instance, *name) {1338dfg::CoreDef::Export(e) => e,1339_ => unreachable!(),1340},1341);1342}13431344AliasExportGlobal(instance, name) => {1345frame.globals.push(1346match self.core_def_of_module_instance_export(frame, *instance, *name) {1347dfg::CoreDef::Export(e) => e,1348_ => unreachable!(),1349},1350);1351}13521353AliasExportMemory(instance, name) => {1354frame.memories.push(1355match self.core_def_of_module_instance_export(frame, *instance, *name) {1356dfg::CoreDef::Export(e) => e,1357_ => unreachable!(),1358},1359);1360}13611362AliasExportTag(instance, name) => {1363frame.tags.push(1364match self.core_def_of_module_instance_export(frame, *instance, *name) {1365dfg::CoreDef::Export(e) => e,1366_ => unreachable!(),1367},1368);1369}13701371AliasComponentExport(instance, name) => {1372match &frame.component_instances[*instance] {1373ComponentInstanceDef::Intrinsics => {1374frame.push_item(ComponentItemDef::Func(ComponentFuncDef::UnsafeIntrinsic(1375UnsafeIntrinsic::from_str(name)?,1376)));1377}13781379// Aliasing an export from an imported instance means that1380// we're extending the `ImportPath` by one name, represented1381// with the clone + push here. Afterwards an appropriate1382// item is then pushed in the relevant index space.1383ComponentInstanceDef::Import(path, ty) => {1384let path = path.push(*name);1385let def = ComponentItemDef::from_import(path, types[*ty].exports[*name])?;1386frame.push_item(def);1387}13881389// Given a component instance which was either created1390// through instantiation of a component or through a1391// synthetic renaming of items we just schlep around the1392// definitions of various items here.1393ComponentInstanceDef::Items(map, _) => frame.push_item(map[*name].clone()),1394}1395}13961397// For more information on these see `LexicalScope` but otherwise1398// this is just taking a closed over variable and inserting the1399// actual definition into the local index space since this1400// represents an outer alias to a module/component1401AliasModule(idx) => {1402frame.modules.push(frame.closed_over_module(idx));1403}1404AliasComponent(idx) => {1405frame.components.push(frame.closed_over_component(idx));1406}14071408Export(item) => match item {1409ComponentItem::Func(i) => {1410frame1411.component_funcs1412.push(frame.component_funcs[*i].clone());1413}1414ComponentItem::Module(i) => {1415frame.modules.push(frame.modules[*i].clone());1416}1417ComponentItem::Component(i) => {1418frame.components.push(frame.components[*i].clone());1419}1420ComponentItem::ComponentInstance(i) => {1421frame1422.component_instances1423.push(frame.component_instances[*i].clone());1424}14251426// Type index spaces aren't maintained during this inlining pass1427// so ignore this.1428ComponentItem::Type(_) => {}1429},1430}14311432Ok(None)1433}14341435/// "Commits" a path of an import to an actual index which is something that1436/// will be calculated at runtime.1437///1438/// Note that the cost of calculating an item for a `RuntimeImportIndex` at1439/// runtime is amortized with an `InstancePre` which represents "all the1440/// runtime imports are lined up" and after that no more name resolution is1441/// necessary.1442fn runtime_import(&mut self, path: &ImportPath<'a>) -> RuntimeImportIndex {1443*self1444.import_path_interner1445.entry(path.clone())1446.or_insert_with(|| {1447self.result.imports.push((1448path.index,1449path.path.iter().map(|s| s.to_string()).collect(),1450))1451})1452}14531454/// Returns the `CoreDef`, the canonical definition for a core wasm item,1455/// for the export `name` of `instance` within `frame`.1456fn core_def_of_module_instance_export(1457&self,1458frame: &InlinerFrame<'a>,1459instance: ModuleInstanceIndex,1460name: &'a str,1461) -> dfg::CoreDef {1462match &frame.module_instances[instance] {1463// Instantiations of a statically known module means that we can1464// refer to the exported item by a precise index, skipping name1465// lookups at runtime.1466//1467// Instantiations of an imported module, however, must do name1468// lookups at runtime since we don't know the structure ahead of1469// time here.1470ModuleInstanceDef::Instantiated(instance, module) => {1471let item = match frame.modules[*module] {1472ModuleDef::Static(idx, _ty) => {1473let entity = self.nested_modules[idx].module.exports[name];1474ExportItem::Index(entity)1475}1476ModuleDef::Import(..) => ExportItem::Name(name.to_string()),1477};1478dfg::CoreExport {1479instance: *instance,1480item,1481}1482.into()1483}14841485// This is a synthetic instance so the canonical definition of the1486// original item is returned.1487ModuleInstanceDef::Synthetic(instance) => match instance[name] {1488EntityIndex::Function(i) => frame.funcs[i].1.clone(),1489EntityIndex::Table(i) => frame.tables[i].clone().into(),1490EntityIndex::Global(i) => frame.globals[i].clone().into(),1491EntityIndex::Memory(i) => frame.memories[i].clone().into(),1492EntityIndex::Tag(i) => frame.tags[i].clone().into(),1493},1494}1495}14961497fn memory(1498&mut self,1499frame: &InlinerFrame<'a>,1500types: &ComponentTypesBuilder,1501memory: MemoryIndex,1502) -> (dfg::CoreExport<MemoryIndex>, bool) {1503let memory = frame.memories[memory].clone().map_index(|i| match i {1504EntityIndex::Memory(i) => i,1505_ => unreachable!(),1506});1507let memory64 = match &self.runtime_instances[memory.instance] {1508InstanceModule::Static(idx) => match &memory.item {1509ExportItem::Index(i) => {1510let ty = &self.nested_modules[*idx].module.memories[*i];1511match ty.idx_type {1512IndexType::I32 => false,1513IndexType::I64 => true,1514}1515}1516ExportItem::Name(_) => unreachable!(),1517},1518InstanceModule::Import(ty) => match &memory.item {1519ExportItem::Name(name) => match types[*ty].exports[name] {1520EntityType::Memory(m) => match m.idx_type {1521IndexType::I32 => false,1522IndexType::I64 => true,1523},1524_ => unreachable!(),1525},1526ExportItem::Index(_) => unreachable!(),1527},1528};1529(memory, memory64)1530}15311532/// Translates a `LocalCanonicalOptions` which indexes into the `frame`1533/// specified into a runtime representation.1534fn adapter_options(1535&mut self,1536frames: &mut Vec<(InlinerFrame<'a>, ResourcesBuilder)>,1537types: &ComponentTypesBuilder,1538options: &LocalCanonicalOptions,1539) -> AdapterOptions {1540let (frame, _) = frames.last_mut().unwrap();1541let data_model = match options.data_model {1542LocalDataModel::Gc {} => DataModel::Gc {},1543LocalDataModel::LinearMemory { memory, realloc } => {1544let (memory, memory64) = memory1545.map(|i| {1546let (memory, memory64) = self.memory(frame, types, i);1547(Some(memory), memory64)1548})1549.unwrap_or((None, false));1550let realloc = realloc.map(|i| frame.funcs[i].1.clone());1551DataModel::LinearMemory {1552memory,1553memory64,1554realloc,1555}1556}1557};1558let callback = options.callback.map(|i| frame.funcs[i].1.clone());1559let post_return = options.post_return.map(|i| frame.funcs[i].1.clone());1560AdapterOptions {1561instance: frame.instance,1562ancestors: frames1563.iter()1564.rev()1565.skip(1)1566.map(|(frame, _)| frame.instance)1567.collect(),1568string_encoding: options.string_encoding,1569callback,1570post_return,1571async_: options.async_,1572cancellable: options.cancellable,1573core_type: options.core_type,1574data_model,1575}1576}15771578/// Translates an `AdapterOptions` into a `CanonicalOptions` where1579/// memories/functions are inserted into the global initializer list for1580/// use at runtime. This is only used for lowered host functions and lifted1581/// functions exported to the host.1582fn canonical_options(&mut self, options: AdapterOptions) -> dfg::OptionsId {1583let data_model = match options.data_model {1584DataModel::Gc {} => dfg::CanonicalOptionsDataModel::Gc {},1585DataModel::LinearMemory {1586memory,1587memory64: _,1588realloc,1589} => dfg::CanonicalOptionsDataModel::LinearMemory {1590memory: memory.map(|export| self.result.memories.push(export)),1591realloc: realloc.map(|def| self.result.reallocs.push(def)),1592},1593};1594let callback = options.callback.map(|def| self.result.callbacks.push(def));1595let post_return = options1596.post_return1597.map(|def| self.result.post_returns.push(def));1598self.result.options.push(dfg::CanonicalOptions {1599instance: options.instance,1600string_encoding: options.string_encoding,1601callback,1602post_return,1603async_: options.async_,1604cancellable: options.cancellable,1605core_type: options.core_type,1606data_model,1607})1608}16091610fn record_export(1611&mut self,1612name: &str,1613def: ComponentItemDef<'a>,1614types: &'a ComponentTypesBuilder,1615map: &mut IndexMap<String, dfg::Export>,1616) -> Result<()> {1617let export = match def {1618// Exported modules are currently saved in a `PrimaryMap`, at1619// runtime, so an index (`RuntimeModuleIndex`) is assigned here and1620// then an initializer is recorded about where the module comes1621// from.1622ComponentItemDef::Module(module) => match module {1623ModuleDef::Static(index, ty) => dfg::Export::ModuleStatic { ty, index },1624ModuleDef::Import(path, ty) => dfg::Export::ModuleImport {1625ty,1626import: self.runtime_import(&path),1627},1628},16291630ComponentItemDef::Func(func) => match func {1631// If this is a lifted function from something lowered in this1632// component then the configured options are plumbed through1633// here.1634ComponentFuncDef::Lifted { ty, func, options } => {1635let options = self.canonical_options(options);1636dfg::Export::LiftedFunction { ty, func, options }1637}16381639// Currently reexported functions from an import are not1640// supported. Being able to actually call these functions is1641// somewhat tricky and needs something like temporary scratch1642// space that isn't implemented.1643ComponentFuncDef::Import(_) => {1644bail!(1645"component export `{name}` is a reexport of an imported function which is not implemented"1646)1647}16481649ComponentFuncDef::UnsafeIntrinsic(_) => {1650bail!(1651"component export `{name}` is a reexport of an intrinsic function which is not supported"1652)1653}1654},16551656ComponentItemDef::Instance(instance) => {1657let mut exports = IndexMap::new();1658match instance {1659ComponentInstanceDef::Intrinsics => {1660bail!(1661"component export `{name}` is a reexport of the intrinsics instance which is not supported"1662)1663}16641665// If this instance is one that was originally imported by1666// the component itself then the imports are translated here1667// by converting to a `ComponentItemDef` and then1668// recursively recording the export as a reexport.1669//1670// Note that for now this would only work with1671// module-exporting instances.1672ComponentInstanceDef::Import(path, ty) => {1673for (name, ty) in types[ty].exports.iter() {1674let path = path.push(name);1675let def = ComponentItemDef::from_import(path, *ty)?;1676self.record_export(name, def, types, &mut exports)?;1677}1678dfg::Export::Instance { ty, exports }1679}16801681// An exported instance which is itself a bag of items is1682// translated recursively here to our `exports` map which is1683// the bag of items we're exporting.1684ComponentInstanceDef::Items(map, ty) => {1685for (name, def) in map {1686self.record_export(name, def, types, &mut exports)?;1687}1688dfg::Export::Instance { ty, exports }1689}1690}1691}16921693// FIXME(#4283) should make an official decision on whether this is1694// the final treatment of this or not.1695ComponentItemDef::Component(_) => {1696bail!("exporting a component from the root component is not supported")1697}16981699ComponentItemDef::Type(def) => dfg::Export::Type(def),1700};17011702map.insert(name.to_string(), export);1703Ok(())1704}1705}17061707impl<'a> InlinerFrame<'a> {1708fn new(1709instance: RuntimeComponentInstanceIndex,1710translation: &'a Translation<'a>,1711closure: ComponentClosure<'a>,1712args: HashMap<&'a str, ComponentItemDef<'a>>,1713instance_ty: Option<ComponentInstanceTypeId>,1714) -> Self {1715// FIXME: should iterate over the initializers of `translation` and1716// calculate the size of each index space to use `with_capacity` for1717// all the maps below. Given that doing such would be wordy and compile1718// time is otherwise not super crucial it's not done at this time.1719InlinerFrame {1720instance,1721translation,1722closure,1723args,1724instance_ty,1725initializers: translation.initializers.iter(),17261727funcs: Default::default(),1728memories: Default::default(),1729tables: Default::default(),1730globals: Default::default(),1731tags: Default::default(),17321733component_instances: Default::default(),1734component_funcs: Default::default(),1735module_instances: Default::default(),1736components: Default::default(),1737modules: Default::default(),1738}1739}17401741fn item(1742&self,1743index: ComponentItem,1744types: &mut ComponentTypesBuilder,1745) -> Result<ComponentItemDef<'a>> {1746Ok(match index {1747ComponentItem::Func(i) => ComponentItemDef::Func(self.component_funcs[i].clone()),1748ComponentItem::Component(i) => ComponentItemDef::Component(self.components[i].clone()),1749ComponentItem::ComponentInstance(i) => {1750ComponentItemDef::Instance(self.component_instances[i].clone())1751}1752ComponentItem::Module(i) => ComponentItemDef::Module(self.modules[i].clone()),1753ComponentItem::Type(t) => {1754let types_ref = self.translation.types_ref();1755ComponentItemDef::Type(types.convert_type(types_ref, t)?)1756}1757})1758}17591760/// Pushes the component `item` definition provided into the appropriate1761/// index space within this component.1762fn push_item(&mut self, item: ComponentItemDef<'a>) {1763match item {1764ComponentItemDef::Func(i) => {1765self.component_funcs.push(i);1766}1767ComponentItemDef::Module(i) => {1768self.modules.push(i);1769}1770ComponentItemDef::Component(i) => {1771self.components.push(i);1772}1773ComponentItemDef::Instance(i) => {1774self.component_instances.push(i);1775}17761777// In short, type definitions aren't tracked here.1778//1779// The longer form explanation for this is that structural types1780// like lists and records don't need to be tracked at all and the1781// only significant type which needs tracking is resource types1782// themselves. Resource types, however, are tracked within the1783// `ResourcesBuilder` state rather than an `InlinerFrame` so they're1784// ignored here as well. The general reason for that is that type1785// information is everywhere and this `InlinerFrame` is not1786// everywhere so it seemed like it would make sense to split the1787// two.1788//1789// Note though that this case is actually frequently hit, so it1790// can't be `unreachable!()`. Instead callers are responsible for1791// handling this appropriately with respect to resources.1792ComponentItemDef::Type(_ty) => {}1793}1794}17951796fn closed_over_module(&self, index: &ClosedOverModule) -> ModuleDef<'a> {1797match *index {1798ClosedOverModule::Local(i) => self.modules[i].clone(),1799ClosedOverModule::Upvar(i) => self.closure.modules[i].clone(),1800}1801}18021803fn closed_over_component(&self, index: &ClosedOverComponent) -> ComponentDef<'a> {1804match *index {1805ClosedOverComponent::Local(i) => self.components[i].clone(),1806ClosedOverComponent::Upvar(i) => self.closure.components[i].clone(),1807}1808}18091810/// Completes the instantiation of a subcomponent and records type1811/// information for the instance that was produced.1812///1813/// This method is invoked when an `InlinerFrame` finishes for a1814/// subcomponent. The `def` provided represents the instance that was1815/// produced from instantiation, and `ty` is the wasmparser-defined type of1816/// the instance produced.1817///1818/// The purpose of this method is to record type information about resources1819/// in the instance produced. In the component model all instantiations of a1820/// component produce fresh new types for all resources which are unequal to1821/// all prior resources. This means that if wasmparser's `ty` type1822/// information references a unique resource within `def` that has never1823/// been registered before then that means it's a defined resource within1824/// the component that was just instantiated (as opposed to an imported1825/// resource which was reexported).1826///1827/// Further type translation after this instantiation can refer to these1828/// resource types and a mapping from those types to the wasmtime-internal1829/// types is required, so this method builds up those mappings.1830///1831/// Essentially what happens here is that the `ty` type is registered and1832/// any new unique resources are registered so new tables can be introduced1833/// along with origin information about the actual underlying resource type1834/// and which component instantiated it.1835fn finish_instantiate(1836&mut self,1837exports: IndexMap<&'a str, ComponentItemDef<'a>>,1838ty: ComponentInstanceTypeId,1839types: &mut ComponentTypesBuilder,1840) -> Result<()> {1841let types_ref = self.translation.types_ref();1842{1843let (resources, types) = types.resources_mut_and_types();1844let mut path = Vec::new();1845resources.register_component_entity_type(1846&types_ref,1847ComponentEntityType::Instance(ty),1848&mut path,1849&mut |path| match path {1850[] => unreachable!(),1851[name, rest @ ..] => exports[name].lookup_resource(rest, types),1852},1853);1854}1855let ty = types.convert_instance(types_ref, ty)?;1856let def = ComponentInstanceDef::Items(exports, ty);1857let arg = ComponentItemDef::Instance(def);1858self.push_item(arg);1859Ok(())1860}1861}18621863impl<'a> ImportPath<'a> {1864fn root(index: ImportIndex) -> ImportPath<'a> {1865ImportPath {1866index,1867path: Vec::new(),1868}1869}18701871fn push(&self, s: impl Into<Cow<'a, str>>) -> ImportPath<'a> {1872let mut new = self.clone();1873new.path.push(s.into());1874new1875}1876}18771878impl<'a> ComponentItemDef<'a> {1879fn from_import(path: ImportPath<'a>, ty: TypeDef) -> Result<ComponentItemDef<'a>> {1880let item = match ty {1881TypeDef::Module(ty) => ComponentItemDef::Module(ModuleDef::Import(path, ty)),1882TypeDef::ComponentInstance(ty) => {1883ComponentItemDef::Instance(ComponentInstanceDef::Import(path, ty))1884}1885TypeDef::ComponentFunc(_ty) => ComponentItemDef::Func(ComponentFuncDef::Import(path)),1886// FIXME(#4283) should commit one way or another to how this1887// should be treated.1888TypeDef::Component(_ty) => bail!("root-level component imports are not supported"),1889TypeDef::Interface(_) | TypeDef::Resource(_) => ComponentItemDef::Type(ty),1890TypeDef::CoreFunc(_) => unreachable!(),1891};1892Ok(item)1893}18941895/// Walks the `path` within `self` to find a resource at that path.1896///1897/// This method is used when resources are found within wasmparser's type1898/// information and they need to be correlated with actual concrete1899/// definitions from this inlining pass. The `path` here is a list of1900/// instance export names (or empty) to walk to reach down into the final1901/// definition which should refer to a resource itself.1902fn lookup_resource(&self, path: &[&str], types: &ComponentTypes) -> ResourceIndex {1903let mut cur = self.clone();19041905// Each element of `path` represents unwrapping a layer of an instance1906// type, so handle those here by updating `cur` iteratively.1907for element in path.iter().copied() {1908let instance = match cur {1909ComponentItemDef::Instance(def) => def,1910_ => unreachable!(),1911};1912cur = match instance {1913// If this instance is a "bag of things" then this is as easy as1914// looking up the name in the bag of names.1915ComponentInstanceDef::Items(names, _) => names[element].clone(),19161917// If, however, this instance is an imported instance then this1918// is a further projection within the import with one more path1919// element. The `types` type information is used to lookup the1920// type of `element` within the instance type, and that's used1921// in conjunction with a one-longer `path` to produce a new item1922// definition.1923ComponentInstanceDef::Import(path, ty) => {1924ComponentItemDef::from_import(path.push(element), types[ty].exports[element])1925.unwrap()1926}1927ComponentInstanceDef::Intrinsics => {1928unreachable!("intrinsics do not define resources")1929}1930};1931}19321933// Once `path` has been iterated over it must be the case that the final1934// item is a resource type, in which case a lookup can be performed.1935match cur {1936ComponentItemDef::Type(TypeDef::Resource(idx)) => types[idx].unwrap_concrete_ty(),1937_ => unreachable!(),1938}1939}1940}19411942#[derive(Clone, Copy)]1943enum InstanceModule {1944Static(StaticModuleIndex),1945Import(TypeModuleIndex),1946}194719481949