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