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::store::{StoreOpaque, Stored}; 7 use crate::{AsContextMut, Module, StoreContextMut}; 8 use anyhow::{anyhow, Context, Result}; 9 use indexmap::IndexMap; 10 use std::marker; 11 use std::ptr::NonNull; 12 use std::sync::Arc; 13 use wasmtime_environ::{component::*, EngineOrModuleTypeIndex}; 14 use wasmtime_environ::{EntityIndex, EntityType, Global, PrimaryMap, WasmValType}; 15 use wasmtime_runtime::component::{ComponentInstance, OwnedComponentInstance}; 16 use wasmtime_runtime::VMFuncRef; 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) -> wasmtime_runtime::Export { 157 match def { 158 CoreDef::Export(e) => self.lookup_export(store, e), 159 CoreDef::Trampoline(idx) => { 160 wasmtime_runtime::Export::Function(wasmtime_runtime::ExportFunction { 161 func_ref: self.state.trampoline_func_ref(*idx), 162 }) 163 } 164 CoreDef::InstanceFlags(idx) => { 165 wasmtime_runtime::Export::Global(wasmtime_runtime::ExportGlobal { 166 definition: self.state.instance_flags(*idx).as_raw(), 167 vmctx: std::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 ) -> wasmtime_runtime::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 wasmtime_runtime::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 wasmtime_runtime::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 wasmtime_runtime::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 wasmtime_runtime::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 wasmtime_runtime::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 #[cfg_attr(docsrs, doc(cfg(feature = "async")))] 595 pub async fn instantiate_async( 596 &self, 597 mut store: impl AsContextMut<Data = T>, 598 ) -> Result<Instance> 599 where 600 T: Send, 601 { 602 let mut store = store.as_context_mut(); 603 assert!( 604 store.0.async_support(), 605 "must use sync instantiation when async support is disabled" 606 ); 607 store.on_fiber(|store| self.instantiate_impl(store)).await? 608 } 609 610 fn instantiate_impl(&self, mut store: impl AsContextMut<Data = T>) -> Result<Instance> { 611 let mut store = store.as_context_mut(); 612 store 613 .engine() 614 .allocator() 615 .increment_component_instance_count()?; 616 let mut instantiator = Instantiator::new(&self.component, store.0, &self.imports); 617 instantiator.run(&mut store).map_err(|e| { 618 store 619 .engine() 620 .allocator() 621 .decrement_component_instance_count(); 622 e 623 })?; 624 let data = Box::new(instantiator.data); 625 let instance = Instance(store.0.store_data_mut().insert(Some(data))); 626 store.0.push_component_instance(instance); 627 Ok(instance) 628 } 629 } 630 631 /// Description of the exports of an [`Instance`]. 632 /// 633 /// This structure is created through the [`Instance::exports`] method and is 634 /// used lookup exports by name from within an instance. 635 pub struct Exports<'store> { 636 store: &'store mut StoreOpaque, 637 data: Option<Box<InstanceData>>, 638 instance: Instance, 639 } 640 641 impl<'store> Exports<'store> { 642 fn new(store: &'store mut StoreOpaque, instance: &Instance) -> Exports<'store> { 643 // Note that the `InstanceData` is `take`n from the store here. That's 644 // to ease with the various liftimes in play here where we often need 645 // simultaneous borrows into the `store` and the `data`. 646 // 647 // To put the data back into the store the `Drop for Exports<'_>` will 648 // restore the state of the world. 649 Exports { 650 data: store[instance.0].take(), 651 store, 652 instance: *instance, 653 } 654 } 655 656 /// Returns the "root" instance of this set of exports, or the items that 657 /// are directly exported from the instance that this was created from. 658 pub fn root(&mut self) -> ExportInstance<'_, '_> { 659 let data = self.data.as_ref().unwrap(); 660 ExportInstance { 661 exports: &data.component.env_component().exports, 662 instance: &self.instance, 663 data, 664 store: self.store, 665 } 666 } 667 668 /// Returns the items that the named instance exports. 669 /// 670 /// This method will lookup the exported instance with the name `name` from 671 /// this list of exports and return a descriptin of that instance's 672 /// exports. 673 pub fn instance(&mut self, name: &str) -> Option<ExportInstance<'_, '_>> { 674 self.root().into_instance(name) 675 } 676 677 // FIXME: should all the func/module/typed_func methods below be mirrored 678 // here as well? They're already mirrored on `Instance` and otherwise 679 // this is attempting to look like the `Linker` API "but in reverse" 680 // somewhat. 681 } 682 683 impl Drop for Exports<'_> { 684 fn drop(&mut self) { 685 // See `Exports::new` for where this data was originally extracted, and 686 // this is just restoring the state of the world. 687 self.store[self.instance.0] = self.data.take(); 688 } 689 } 690 691 /// Description of the exports of a single instance. 692 /// 693 /// This structure is created from [`Exports`] via the [`Exports::root`] or 694 /// [`Exports::instance`] methods. This type provides access to the first layer 695 /// of exports within an instance. The [`ExportInstance::instance`] method 696 /// can be used to provide nested access to sub-instances. 697 pub struct ExportInstance<'a, 'store> { 698 exports: &'a IndexMap<String, Export>, 699 instance: &'a Instance, 700 data: &'a InstanceData, 701 store: &'store mut StoreOpaque, 702 } 703 704 impl<'a, 'store> ExportInstance<'a, 'store> { 705 /// Same as [`Instance::get_func`] 706 pub fn func(&mut self, name: &str) -> Option<Func> { 707 match self.exports.get(name)? { 708 Export::LiftedFunction { ty, func, options } => Some(Func::from_lifted_func( 709 self.store, 710 self.instance, 711 self.data, 712 *ty, 713 func, 714 options, 715 )), 716 Export::ModuleStatic(_) 717 | Export::ModuleImport { .. } 718 | Export::Instance { .. } 719 | Export::Type(_) => None, 720 } 721 } 722 723 /// Same as [`Instance::get_typed_func`] 724 pub fn typed_func<Params, Results>(&mut self, name: &str) -> Result<TypedFunc<Params, Results>> 725 where 726 Params: ComponentNamedList + Lower, 727 Results: ComponentNamedList + Lift, 728 { 729 let func = self 730 .func(name) 731 .ok_or_else(|| anyhow!("failed to find function export `{}`", name))?; 732 Ok(func 733 ._typed::<Params, Results>(self.store, Some(self.data)) 734 .with_context(|| format!("failed to convert function `{}` to given type", name))?) 735 } 736 737 /// Same as [`Instance::get_module`] 738 pub fn module(&mut self, name: &str) -> Option<&'a Module> { 739 match self.exports.get(name)? { 740 Export::ModuleStatic(idx) => Some(&self.data.component.static_module(*idx)), 741 Export::ModuleImport { import, .. } => Some(match &self.data.imports[*import] { 742 RuntimeImport::Module(m) => m, 743 _ => unreachable!(), 744 }), 745 _ => None, 746 } 747 } 748 749 /// Same as [`Instance::get_resource`] 750 pub fn resource(&mut self, name: &str) -> Option<ResourceType> { 751 match self.exports.get(name)? { 752 Export::Type(TypeDef::Resource(id)) => Some(self.data.ty().resource_type(*id)), 753 Export::Type(_) 754 | Export::LiftedFunction { .. } 755 | Export::ModuleStatic(_) 756 | Export::ModuleImport { .. } 757 | Export::Instance { .. } => None, 758 } 759 } 760 761 /// Returns an iterator of all of the exported modules that this instance 762 /// contains. 763 // 764 // FIXME: this should probably be generalized in some form to something else 765 // that either looks like: 766 // 767 // * an iterator over all exports 768 // * an iterator for a `Component` with type information followed by a 769 // `get_module` function here 770 // 771 // For now this is just quick-and-dirty to get wast support for iterating 772 // over exported modules to work. 773 pub fn modules(&self) -> impl Iterator<Item = (&'a str, &'a Module)> + '_ { 774 self.exports.iter().filter_map(|(name, export)| { 775 let module = match *export { 776 Export::ModuleStatic(idx) => self.data.component.static_module(idx), 777 Export::ModuleImport { import, .. } => match &self.data.imports[import] { 778 RuntimeImport::Module(m) => m, 779 _ => unreachable!(), 780 }, 781 _ => return None, 782 }; 783 Some((name.as_str(), module)) 784 }) 785 } 786 787 fn as_mut(&mut self) -> ExportInstance<'a, '_> { 788 ExportInstance { 789 exports: self.exports, 790 instance: self.instance, 791 data: self.data, 792 store: self.store, 793 } 794 } 795 796 /// Looks up the exported instance with the `name` specified and returns 797 /// a description of its exports. 798 pub fn instance(&mut self, name: &str) -> Option<ExportInstance<'a, '_>> { 799 self.as_mut().into_instance(name) 800 } 801 802 /// Same as [`ExportInstance::instance`] but consumes self to yield a 803 /// return value with the same lifetimes. 804 pub fn into_instance(self, name: &str) -> Option<ExportInstance<'a, 'store>> { 805 match self.exports.get(name)? { 806 Export::Instance { exports, .. } => Some(ExportInstance { 807 exports, 808 instance: self.instance, 809 data: self.data, 810 store: self.store, 811 }), 812 _ => None, 813 } 814 } 815 } 816