1 use crate::component::func::HostFunc; 2 use crate::component::matching::InstanceType; 3 use crate::component::{Component, ComponentNamedList, Func, Lift, Lower, ResourceType, TypedFunc}; 4 use crate::instance::OwnedImports; 5 use crate::linker::DefinitionType; 6 use crate::prelude::*; 7 use crate::runtime::vm::component::{ComponentInstance, OwnedComponentInstance}; 8 use crate::runtime::vm::VMFuncRef; 9 use crate::store::{StoreOpaque, Stored}; 10 use crate::{AsContextMut, Module, StoreContextMut}; 11 use alloc::sync::Arc; 12 use anyhow::{anyhow, Context, Result}; 13 use core::marker; 14 use core::ptr::{self, NonNull}; 15 use wasmtime_environ::{component::*, EngineOrModuleTypeIndex}; 16 use wasmtime_environ::{EntityIndex, EntityType, Global, PrimaryMap, WasmValType}; 17 18 /// An instantiated component. 19 /// 20 /// This type represents an instantiated [`Component`](super::Component). 21 /// Instances have exports which can be accessed through functions such as 22 /// [`Instance::get_func`] or [`Instance::exports`]. Instances are owned by a 23 /// [`Store`](crate::Store) and all methods require a handle to the store. 24 /// 25 /// Component instances are created through 26 /// [`Linker::instantiate`](super::Linker::instantiate) and its family of 27 /// methods. 28 /// 29 /// This type is similar to the core wasm version 30 /// [`wasmtime::Instance`](crate::Instance) except that it represents an 31 /// instantiated component instead of an instantiated module. 32 #[derive(Copy, Clone)] 33 pub struct Instance(pub(crate) Stored<Option<Box<InstanceData>>>); 34 35 pub(crate) struct InstanceData { 36 instances: PrimaryMap<RuntimeInstanceIndex, crate::Instance>, 37 38 // NB: in the future if necessary it would be possible to avoid storing an 39 // entire `Component` here and instead storing only information such as: 40 // 41 // * Some reference to `Arc<ComponentTypes>` 42 // * Necessary references to closed-over modules which are exported from the 43 // component itself. 44 // 45 // Otherwise the full guts of this component should only ever be used during 46 // the instantiation of this instance, meaning that after instantiation much 47 // of the component can be thrown away (theoretically). 48 component: Component, 49 50 state: OwnedComponentInstance, 51 52 /// Arguments that this instance used to be instantiated. 53 /// 54 /// Strong references are stored to these arguments since pointers are saved 55 /// into the structures such as functions within the 56 /// `OwnedComponentInstance` but it's our job to keep them alive. 57 /// 58 /// One purpose of this storage is to enable embedders to drop a `Linker`, 59 /// for example, after a component is instantiated. In that situation if the 60 /// arguments weren't held here then they might be dropped, and structures 61 /// such as `.lowering()` which point back into the original function would 62 /// become stale and use-after-free conditions when used. By preserving the 63 /// entire list here though we're guaranteed that nothing is lost for the 64 /// duration of the lifetime of this instance. 65 imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>, 66 } 67 68 impl Instance { 69 /// Returns information about the exports of this instance. 70 /// 71 /// This method can be used to extract exported values from this component 72 /// instance. The argument to this method be a handle to the store that 73 /// this instance was instantiated into. 74 /// 75 /// The returned [`Exports`] value can be used to lookup exported items by 76 /// name. 77 /// 78 /// # Panics 79 /// 80 /// Panics if `store` does not own this instance. 81 pub fn exports<'a, T: 'a>(&self, store: impl Into<StoreContextMut<'a, T>>) -> Exports<'a> { 82 let store = store.into(); 83 Exports::new(store.0, self) 84 } 85 86 /// Looks up a function by name within this [`Instance`]. 87 /// 88 /// This is a convenience method for calling [`Instance::exports`] followed 89 /// by [`ExportInstance::func`]. 90 /// 91 /// # Panics 92 /// 93 /// Panics if `store` does not own this instance. 94 pub fn get_func(&self, mut store: impl AsContextMut, name: &str) -> Option<Func> { 95 self.exports(store.as_context_mut()).root().func(name) 96 } 97 98 /// Looks up an exported [`Func`] value by name and with its type. 99 /// 100 /// This function is a convenience wrapper over [`Instance::get_func`] and 101 /// [`Func::typed`]. For more information see the linked documentation. 102 /// 103 /// Returns an error if `name` isn't a function export or if the export's 104 /// type did not match `Params` or `Results` 105 /// 106 /// # Panics 107 /// 108 /// Panics if `store` does not own this instance. 109 pub fn get_typed_func<Params, Results>( 110 &self, 111 mut store: impl AsContextMut, 112 name: &str, 113 ) -> Result<TypedFunc<Params, Results>> 114 where 115 Params: ComponentNamedList + Lower, 116 Results: ComponentNamedList + Lift, 117 { 118 let f = self 119 .get_func(store.as_context_mut(), name) 120 .ok_or_else(|| anyhow!("failed to find function export `{}`", name))?; 121 Ok(f.typed::<Params, Results>(store) 122 .with_context(|| format!("failed to convert function `{}` to given type", name))?) 123 } 124 125 /// Looks up a module by name within this [`Instance`]. 126 /// 127 /// The `store` specified must be the store that this instance lives within 128 /// and `name` is the name of the function to lookup. If the module is 129 /// found `Some` is returned otherwise `None` is returned. 130 /// 131 /// # Panics 132 /// 133 /// Panics if `store` does not own this instance. 134 pub fn get_module(&self, mut store: impl AsContextMut, name: &str) -> Option<Module> { 135 self.exports(store.as_context_mut()) 136 .root() 137 .module(name) 138 .cloned() 139 } 140 141 /// Looks up an exported resource type by name within this [`Instance`]. 142 /// 143 /// The `store` specified must be the store that this instance lives within 144 /// and `name` is the name of the function to lookup. If the resource type 145 /// is found `Some` is returned otherwise `None` is returned. 146 /// 147 /// # Panics 148 /// 149 /// Panics if `store` does not own this instance. 150 pub fn get_resource(&self, mut store: impl AsContextMut, name: &str) -> Option<ResourceType> { 151 self.exports(store.as_context_mut()).root().resource(name) 152 } 153 } 154 155 impl InstanceData { 156 pub fn lookup_def(&self, store: &mut StoreOpaque, def: &CoreDef) -> crate::runtime::vm::Export { 157 match def { 158 CoreDef::Export(e) => self.lookup_export(store, e), 159 CoreDef::Trampoline(idx) => { 160 crate::runtime::vm::Export::Function(crate::runtime::vm::ExportFunction { 161 func_ref: self.state.trampoline_func_ref(*idx), 162 }) 163 } 164 CoreDef::InstanceFlags(idx) => { 165 crate::runtime::vm::Export::Global(crate::runtime::vm::ExportGlobal { 166 definition: self.state.instance_flags(*idx).as_raw(), 167 vmctx: ptr::null_mut(), 168 global: Global { 169 wasm_ty: WasmValType::I32, 170 mutability: true, 171 }, 172 }) 173 } 174 } 175 } 176 177 pub fn lookup_export<T>( 178 &self, 179 store: &mut StoreOpaque, 180 item: &CoreExport<T>, 181 ) -> crate::runtime::vm::Export 182 where 183 T: Copy + Into<EntityIndex>, 184 { 185 let instance = &self.instances[item.instance]; 186 let id = instance.id(store); 187 let instance = store.instance_mut(id); 188 let idx = match &item.item { 189 ExportItem::Index(idx) => (*idx).into(), 190 191 // FIXME: ideally at runtime we don't actually do any name lookups 192 // here. This will only happen when the host supplies an imported 193 // module so while the structure can't be known at compile time we 194 // do know at `InstancePre` time, for example, what all the host 195 // imports are. In theory we should be able to, as part of 196 // `InstancePre` construction, perform all name=>index mappings 197 // during that phase so the actual instantiation of an `InstancePre` 198 // skips all string lookups. This should probably only be 199 // investigated if this becomes a performance issue though. 200 ExportItem::Name(name) => instance.module().exports[name], 201 }; 202 instance.get_export_by_index(idx) 203 } 204 205 #[inline] 206 pub fn instance(&self) -> &ComponentInstance { 207 &self.state 208 } 209 210 #[inline] 211 pub fn instance_ptr(&self) -> *mut ComponentInstance { 212 self.state.instance_ptr() 213 } 214 215 #[inline] 216 pub fn component_types(&self) -> &Arc<ComponentTypes> { 217 self.component.types() 218 } 219 220 #[inline] 221 pub fn ty(&self) -> InstanceType<'_> { 222 InstanceType::new(self.instance()) 223 } 224 225 // NB: This method is only intended to be called during the instantiation 226 // process because the `Arc::get_mut` here is fallible and won't generally 227 // succeed once the instance has been handed to the embedder. Before that 228 // though it should be guaranteed that the single owning reference currently 229 // lives within the `ComponentInstance` that's being built. 230 fn resource_types_mut(&mut self) -> &mut ImportedResources { 231 Arc::get_mut(self.state.resource_types_mut()) 232 .unwrap() 233 .downcast_mut() 234 .unwrap() 235 } 236 } 237 238 struct Instantiator<'a> { 239 component: &'a Component, 240 data: InstanceData, 241 core_imports: OwnedImports, 242 imports: &'a PrimaryMap<RuntimeImportIndex, RuntimeImport>, 243 } 244 245 pub(crate) enum RuntimeImport { 246 Func(Arc<HostFunc>), 247 Module(Module), 248 Resource { 249 ty: ResourceType, 250 251 // A strong reference to the host function that represents the 252 // destructor for this resource. At this time all resources here are 253 // host-defined resources. Note that this is itself never read because 254 // the funcref below points to it. 255 // 256 // Also note that the `Arc` here is used to support the same host 257 // function being used across multiple instances simultaneously. Or 258 // otherwise this makes `InstancePre::instantiate` possible to create 259 // separate instances all sharing the same host function. 260 _dtor: Arc<crate::func::HostFunc>, 261 262 // A raw function which is filled out (including `wasm_call`) which 263 // points to the internals of the `_dtor` field. This is read and 264 // possibly executed by wasm. 265 dtor_funcref: VMFuncRef, 266 }, 267 } 268 269 pub type ImportedResources = PrimaryMap<ResourceIndex, ResourceType>; 270 271 impl<'a> Instantiator<'a> { 272 fn new( 273 component: &'a Component, 274 store: &mut StoreOpaque, 275 imports: &'a Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>, 276 ) -> Instantiator<'a> { 277 let env_component = component.env_component(); 278 store.modules_mut().register_component(component); 279 let imported_resources: ImportedResources = 280 PrimaryMap::with_capacity(env_component.imported_resources.len()); 281 Instantiator { 282 component, 283 imports, 284 core_imports: OwnedImports::empty(), 285 data: InstanceData { 286 instances: PrimaryMap::with_capacity(env_component.num_runtime_instances as usize), 287 component: component.clone(), 288 state: OwnedComponentInstance::new( 289 component.runtime_info(), 290 Arc::new(imported_resources), 291 store.traitobj(), 292 ), 293 imports: imports.clone(), 294 }, 295 } 296 } 297 298 fn run<T>(&mut self, store: &mut StoreContextMut<'_, T>) -> Result<()> { 299 let env_component = self.component.env_component(); 300 301 // Before all initializers are processed configure all destructors for 302 // host-defined resources. No initializer will correspond to these and 303 // it's required to happen before they're needed, so execute this first. 304 for (idx, import) in env_component.imported_resources.iter() { 305 let (ty, func_ref) = match &self.imports[*import] { 306 RuntimeImport::Resource { 307 ty, dtor_funcref, .. 308 } => (*ty, NonNull::from(dtor_funcref)), 309 _ => unreachable!(), 310 }; 311 let i = self.data.resource_types_mut().push(ty); 312 assert_eq!(i, idx); 313 self.data.state.set_resource_destructor(idx, Some(func_ref)); 314 } 315 316 // Next configure all `VMFuncRef`s for trampolines that this component 317 // will require. These functions won't actually get used until their 318 // associated state has been initialized through the global initializers 319 // below, but the funcrefs can all be configured here. 320 for (idx, sig) in env_component.trampolines.iter() { 321 let ptrs = self.component.trampoline_ptrs(idx); 322 let signature = match self.component.signatures().shared_type(*sig) { 323 Some(s) => s, 324 None => panic!("found unregistered signature: {sig:?}"), 325 }; 326 327 self.data.state.set_trampoline( 328 idx, 329 ptrs.wasm_call, 330 ptrs.native_call, 331 ptrs.array_call, 332 signature, 333 ); 334 } 335 336 for initializer in env_component.initializers.iter() { 337 match initializer { 338 GlobalInitializer::InstantiateModule(m) => { 339 let module; 340 let imports = match m { 341 // Since upvars are statically know we know that the 342 // `args` list is already in the right order. 343 InstantiateModule::Static(idx, args) => { 344 module = self.component.static_module(*idx); 345 self.build_imports(store.0, module, args.iter()) 346 } 347 348 // With imports, unlike upvars, we need to do runtime 349 // lookups with strings to determine the order of the 350 // imports since it's whatever the actual module 351 // requires. 352 // 353 // FIXME: see the note in `ExportItem::Name` handling 354 // above for how we ideally shouldn't do string lookup 355 // here. 356 InstantiateModule::Import(idx, args) => { 357 module = match &self.imports[*idx] { 358 RuntimeImport::Module(m) => m, 359 _ => unreachable!(), 360 }; 361 let args = module 362 .imports() 363 .map(|import| &args[import.module()][import.name()]); 364 self.build_imports(store.0, module, args) 365 } 366 }; 367 368 // Note that the unsafety here should be ok because the 369 // validity of the component means that type-checks have 370 // already been performed. This means that the unsafety due 371 // to imports having the wrong type should not happen here. 372 // 373 // Also note we are calling new_started_impl because we have 374 // already checked for asyncness and are running on a fiber 375 // if required. 376 377 let i = unsafe { 378 crate::Instance::new_started_impl(store, module, imports.as_ref())? 379 }; 380 self.data.instances.push(i); 381 } 382 383 GlobalInitializer::LowerImport { import, index } => { 384 let func = match &self.imports[*import] { 385 RuntimeImport::Func(func) => func, 386 _ => unreachable!(), 387 }; 388 self.data.state.set_lowering(*index, func.lowering()); 389 } 390 391 GlobalInitializer::ExtractMemory(mem) => self.extract_memory(store.0, mem), 392 393 GlobalInitializer::ExtractRealloc(realloc) => { 394 self.extract_realloc(store.0, realloc) 395 } 396 397 GlobalInitializer::ExtractPostReturn(post_return) => { 398 self.extract_post_return(store.0, post_return) 399 } 400 401 GlobalInitializer::Resource(r) => self.resource(store.0, r), 402 } 403 } 404 Ok(()) 405 } 406 407 fn resource(&mut self, store: &mut StoreOpaque, resource: &Resource) { 408 let dtor = resource 409 .dtor 410 .as_ref() 411 .map(|dtor| self.data.lookup_def(store, dtor)); 412 let dtor = dtor.map(|export| match export { 413 crate::runtime::vm::Export::Function(f) => f.func_ref, 414 _ => unreachable!(), 415 }); 416 let index = self 417 .component 418 .env_component() 419 .resource_index(resource.index); 420 self.data.state.set_resource_destructor(index, dtor); 421 let ty = ResourceType::guest(store.id(), &self.data.state, resource.index); 422 let i = self.data.resource_types_mut().push(ty); 423 debug_assert_eq!(i, index); 424 } 425 426 fn extract_memory(&mut self, store: &mut StoreOpaque, memory: &ExtractMemory) { 427 let mem = match self.data.lookup_export(store, &memory.export) { 428 crate::runtime::vm::Export::Memory(m) => m, 429 _ => unreachable!(), 430 }; 431 self.data 432 .state 433 .set_runtime_memory(memory.index, mem.definition); 434 } 435 436 fn extract_realloc(&mut self, store: &mut StoreOpaque, realloc: &ExtractRealloc) { 437 let func_ref = match self.data.lookup_def(store, &realloc.def) { 438 crate::runtime::vm::Export::Function(f) => f.func_ref, 439 _ => unreachable!(), 440 }; 441 self.data.state.set_runtime_realloc(realloc.index, func_ref); 442 } 443 444 fn extract_post_return(&mut self, store: &mut StoreOpaque, post_return: &ExtractPostReturn) { 445 let func_ref = match self.data.lookup_def(store, &post_return.def) { 446 crate::runtime::vm::Export::Function(f) => f.func_ref, 447 _ => unreachable!(), 448 }; 449 self.data 450 .state 451 .set_runtime_post_return(post_return.index, func_ref); 452 } 453 454 fn build_imports<'b>( 455 &mut self, 456 store: &mut StoreOpaque, 457 module: &Module, 458 args: impl Iterator<Item = &'b CoreDef>, 459 ) -> &OwnedImports { 460 self.core_imports.clear(); 461 self.core_imports.reserve(module); 462 let mut imports = module.compiled_module().module().imports(); 463 464 for arg in args { 465 // The general idea of Wasmtime is that at runtime type-checks for 466 // core wasm instantiations internally within a component are 467 // unnecessary and superfluous. Naturally though mistakes may be 468 // made, so double-check this property of wasmtime in debug mode. 469 470 if cfg!(debug_assertions) { 471 let (imp_module, imp_name, expected) = imports.next().unwrap(); 472 self.assert_type_matches(store, module, arg, imp_module, imp_name, expected); 473 } 474 475 // The unsafety here should be ok since the `export` is loaded 476 // directly from an instance which should only give us valid export 477 // items. 478 let export = self.data.lookup_def(store, arg); 479 unsafe { 480 self.core_imports.push_export(&export); 481 } 482 } 483 debug_assert!(imports.next().is_none()); 484 485 &self.core_imports 486 } 487 488 fn assert_type_matches( 489 &self, 490 store: &mut StoreOpaque, 491 module: &Module, 492 arg: &CoreDef, 493 imp_module: &str, 494 imp_name: &str, 495 expected: EntityType, 496 ) { 497 let export = self.data.lookup_def(store, arg); 498 499 // If this value is a core wasm function then the type check is inlined 500 // here. This can otherwise fail `Extern::from_wasmtime_export` because 501 // there's no guarantee that there exists a trampoline for `f` so this 502 // can't fall through to the case below 503 if let crate::runtime::vm::Export::Function(f) = &export { 504 let expected = match expected.unwrap_func() { 505 EngineOrModuleTypeIndex::Engine(e) => Some(e), 506 EngineOrModuleTypeIndex::Module(m) => module.signatures().shared_type(m), 507 EngineOrModuleTypeIndex::RecGroup(_) => unreachable!(), 508 }; 509 let actual = unsafe { f.func_ref.as_ref().type_index }; 510 assert_eq!( 511 expected, 512 Some(actual), 513 "type mismatch for import {imp_module:?} {imp_name:?}!!!\n\n\ 514 expected {:#?}\n\n\ 515 found {:#?}", 516 expected.and_then(|e| store.engine().signatures().borrow(e)), 517 store.engine().signatures().borrow(actual) 518 ); 519 return; 520 } 521 522 let val = unsafe { crate::Extern::from_wasmtime_export(export, store) }; 523 let ty = DefinitionType::from(store, &val); 524 crate::types::matching::MatchCx::new(module.engine()) 525 .definition(&expected, &ty) 526 .expect("unexpected typecheck failure"); 527 } 528 } 529 530 /// A "pre-instantiated" [`Instance`] which has all of its arguments already 531 /// supplied and is ready to instantiate. 532 /// 533 /// This structure represents an efficient form of instantiation where import 534 /// type-checking and import lookup has all been resolved by the time that this 535 /// type is created. This type is primarily created through the 536 /// [`Linker::instantiate_pre`](crate::component::Linker::instantiate_pre) 537 /// method. 538 pub struct InstancePre<T> { 539 component: Component, 540 imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>, 541 _marker: marker::PhantomData<fn() -> T>, 542 } 543 544 // `InstancePre`'s clone does not require `T: Clone` 545 impl<T> Clone for InstancePre<T> { 546 fn clone(&self) -> Self { 547 Self { 548 component: self.component.clone(), 549 imports: self.imports.clone(), 550 _marker: self._marker, 551 } 552 } 553 } 554 555 impl<T> InstancePre<T> { 556 /// This function is `unsafe` since there's no guarantee that the 557 /// `RuntimeImport` items provided are guaranteed to work with the `T` of 558 /// the store. 559 /// 560 /// Additionally there is no static guarantee that the `imports` provided 561 /// satisfy the imports of the `component` provided. 562 pub(crate) unsafe fn new_unchecked( 563 component: Component, 564 imports: PrimaryMap<RuntimeImportIndex, RuntimeImport>, 565 ) -> InstancePre<T> { 566 InstancePre { 567 component, 568 imports: Arc::new(imports), 569 _marker: marker::PhantomData, 570 } 571 } 572 573 /// Returns the underlying component that will be instantiated. 574 pub fn component(&self) -> &Component { 575 &self.component 576 } 577 578 /// Performs the instantiation process into the store specified. 579 // 580 // TODO: needs more docs 581 pub fn instantiate(&self, store: impl AsContextMut<Data = T>) -> Result<Instance> { 582 assert!( 583 !store.as_context().async_support(), 584 "must use async instantiation when async support is enabled" 585 ); 586 self.instantiate_impl(store) 587 } 588 /// Performs the instantiation process into the store specified. 589 /// 590 /// Exactly like [`Self::instantiate`] except for use on async stores. 591 // 592 // TODO: needs more docs 593 #[cfg(feature = "async")] 594 pub async fn instantiate_async( 595 &self, 596 mut store: impl AsContextMut<Data = T>, 597 ) -> Result<Instance> 598 where 599 T: Send, 600 { 601 let mut store = store.as_context_mut(); 602 assert!( 603 store.0.async_support(), 604 "must use sync instantiation when async support is disabled" 605 ); 606 store.on_fiber(|store| self.instantiate_impl(store)).await? 607 } 608 609 fn instantiate_impl(&self, mut store: impl AsContextMut<Data = T>) -> Result<Instance> { 610 let mut store = store.as_context_mut(); 611 store 612 .engine() 613 .allocator() 614 .increment_component_instance_count()?; 615 let mut instantiator = Instantiator::new(&self.component, store.0, &self.imports); 616 instantiator.run(&mut store).map_err(|e| { 617 store 618 .engine() 619 .allocator() 620 .decrement_component_instance_count(); 621 e 622 })?; 623 let data = Box::new(instantiator.data); 624 let instance = Instance(store.0.store_data_mut().insert(Some(data))); 625 store.0.push_component_instance(instance); 626 Ok(instance) 627 } 628 } 629 630 /// Description of the exports of an [`Instance`]. 631 /// 632 /// This structure is created through the [`Instance::exports`] method and is 633 /// used lookup exports by name from within an instance. 634 pub struct Exports<'store> { 635 store: &'store mut StoreOpaque, 636 data: Option<Box<InstanceData>>, 637 instance: Instance, 638 } 639 640 impl<'store> Exports<'store> { 641 fn new(store: &'store mut StoreOpaque, instance: &Instance) -> Exports<'store> { 642 // Note that the `InstanceData` is `take`n from the store here. That's 643 // to ease with the various liftimes in play here where we often need 644 // simultaneous borrows into the `store` and the `data`. 645 // 646 // To put the data back into the store the `Drop for Exports<'_>` will 647 // restore the state of the world. 648 Exports { 649 data: store[instance.0].take(), 650 store, 651 instance: *instance, 652 } 653 } 654 655 /// Returns the "root" instance of this set of exports, or the items that 656 /// are directly exported from the instance that this was created from. 657 pub fn root(&mut self) -> ExportInstance<'_, '_> { 658 let data = self.data.as_ref().unwrap(); 659 ExportInstance { 660 exports: &data.component.env_component().exports, 661 instance: &self.instance, 662 data, 663 store: self.store, 664 } 665 } 666 667 /// Returns the items that the named instance exports. 668 /// 669 /// This method will lookup the exported instance with the name `name` from 670 /// this list of exports and return a descriptin of that instance's 671 /// exports. 672 pub fn instance(&mut self, name: &str) -> Option<ExportInstance<'_, '_>> { 673 self.root().into_instance(name) 674 } 675 676 // FIXME: should all the func/module/typed_func methods below be mirrored 677 // here as well? They're already mirrored on `Instance` and otherwise 678 // this is attempting to look like the `Linker` API "but in reverse" 679 // somewhat. 680 } 681 682 impl Drop for Exports<'_> { 683 fn drop(&mut self) { 684 // See `Exports::new` for where this data was originally extracted, and 685 // this is just restoring the state of the world. 686 self.store[self.instance.0] = self.data.take(); 687 } 688 } 689 690 /// Description of the exports of a single instance. 691 /// 692 /// This structure is created from [`Exports`] via the [`Exports::root`] or 693 /// [`Exports::instance`] methods. This type provides access to the first layer 694 /// of exports within an instance. The [`ExportInstance::instance`] method 695 /// can be used to provide nested access to sub-instances. 696 pub struct ExportInstance<'a, 'store> { 697 exports: &'a IndexMap<String, Export>, 698 instance: &'a Instance, 699 data: &'a InstanceData, 700 store: &'store mut StoreOpaque, 701 } 702 703 impl<'a, 'store> ExportInstance<'a, 'store> { 704 /// Same as [`Instance::get_func`] 705 pub fn func(&mut self, name: &str) -> Option<Func> { 706 match self.exports.get(name)? { 707 Export::LiftedFunction { ty, func, options } => Some(Func::from_lifted_func( 708 self.store, 709 self.instance, 710 self.data, 711 *ty, 712 func, 713 options, 714 )), 715 Export::ModuleStatic(_) 716 | Export::ModuleImport { .. } 717 | Export::Instance { .. } 718 | Export::Type(_) => None, 719 } 720 } 721 722 /// Same as [`Instance::get_typed_func`] 723 pub fn typed_func<Params, Results>(&mut self, name: &str) -> Result<TypedFunc<Params, Results>> 724 where 725 Params: ComponentNamedList + Lower, 726 Results: ComponentNamedList + Lift, 727 { 728 let func = self 729 .func(name) 730 .ok_or_else(|| anyhow!("failed to find function export `{}`", name))?; 731 Ok(func 732 ._typed::<Params, Results>(self.store, Some(self.data)) 733 .with_context(|| format!("failed to convert function `{}` to given type", name))?) 734 } 735 736 /// Same as [`Instance::get_module`] 737 pub fn module(&mut self, name: &str) -> Option<&'a Module> { 738 match self.exports.get(name)? { 739 Export::ModuleStatic(idx) => Some(&self.data.component.static_module(*idx)), 740 Export::ModuleImport { import, .. } => Some(match &self.data.imports[*import] { 741 RuntimeImport::Module(m) => m, 742 _ => unreachable!(), 743 }), 744 _ => None, 745 } 746 } 747 748 /// Same as [`Instance::get_resource`] 749 pub fn resource(&mut self, name: &str) -> Option<ResourceType> { 750 match self.exports.get(name)? { 751 Export::Type(TypeDef::Resource(id)) => Some(self.data.ty().resource_type(*id)), 752 Export::Type(_) 753 | Export::LiftedFunction { .. } 754 | Export::ModuleStatic(_) 755 | Export::ModuleImport { .. } 756 | Export::Instance { .. } => None, 757 } 758 } 759 760 /// Returns an iterator of all of the exported modules that this instance 761 /// contains. 762 // 763 // FIXME: this should probably be generalized in some form to something else 764 // that either looks like: 765 // 766 // * an iterator over all exports 767 // * an iterator for a `Component` with type information followed by a 768 // `get_module` function here 769 // 770 // For now this is just quick-and-dirty to get wast support for iterating 771 // over exported modules to work. 772 pub fn modules(&self) -> impl Iterator<Item = (&'a str, &'a Module)> + '_ { 773 self.exports.iter().filter_map(|(name, export)| { 774 let module = match *export { 775 Export::ModuleStatic(idx) => self.data.component.static_module(idx), 776 Export::ModuleImport { import, .. } => match &self.data.imports[import] { 777 RuntimeImport::Module(m) => m, 778 _ => unreachable!(), 779 }, 780 _ => return None, 781 }; 782 Some((name.as_str(), module)) 783 }) 784 } 785 786 fn as_mut(&mut self) -> ExportInstance<'a, '_> { 787 ExportInstance { 788 exports: self.exports, 789 instance: self.instance, 790 data: self.data, 791 store: self.store, 792 } 793 } 794 795 /// Looks up the exported instance with the `name` specified and returns 796 /// a description of its exports. 797 pub fn instance(&mut self, name: &str) -> Option<ExportInstance<'a, '_>> { 798 self.as_mut().into_instance(name) 799 } 800 801 /// Same as [`ExportInstance::instance`] but consumes self to yield a 802 /// return value with the same lifetimes. 803 pub fn into_instance(self, name: &str) -> Option<ExportInstance<'a, 'store>> { 804 match self.exports.get(name)? { 805 Export::Instance { exports, .. } => Some(ExportInstance { 806 exports, 807 instance: self.instance, 808 data: self.data, 809 store: self.store, 810 }), 811 _ => None, 812 } 813 } 814 } 815