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