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