1use crate::component::func::HostFunc;
2use crate::component::matching::InstanceType;
3use crate::component::store::{ComponentInstanceId, StoreComponentInstanceId};
4use crate::component::{
5 Component, ComponentExportIndex, ComponentNamedList, Func, Lift, Lower, ResourceType,
6 TypedFunc, types::ComponentItem,
7};
8use crate::instance::OwnedImports;
9use crate::linker::DefinitionType;
10use crate::prelude::*;
11use crate::runtime::vm::VMFuncRef;
12use crate::runtime::vm::component::{
13 CallContexts, ComponentInstance, OwnedComponentInstance, ResourceTables, TypedResource,
14 TypedResourceIndex,
15};
16use crate::store::StoreOpaque;
17use crate::{AsContext, AsContextMut, Engine, Module, StoreContextMut};
18use alloc::sync::Arc;
19use core::marker;
20use core::ptr::NonNull;
21use wasmtime_environ::{EngineOrModuleTypeIndex, component::*};
22use wasmtime_environ::{EntityType, PrimaryMap};
23
24#[derive(Copy, Clone, Debug)]
39#[repr(transparent)]
40pub struct Instance {
41 id: StoreComponentInstanceId,
42}
43
44const _: () = {
47 #[repr(C)]
48 struct C(u64, u32);
49 assert!(core::mem::size_of::<C>() == core::mem::size_of::<Instance>());
50 assert!(core::mem::align_of::<C>() == core::mem::align_of::<Instance>());
51 assert!(core::mem::offset_of!(Instance, id) == 0);
52};
53
54impl Instance {
55 pub(crate) fn from_wasmtime(store: &StoreOpaque, id: ComponentInstanceId) -> Instance {
57 Instance {
58 id: StoreComponentInstanceId::new(store.id(), id),
59 }
60 }
61
62 pub fn get_func(
157 &self,
158 mut store: impl AsContextMut,
159 name: impl InstanceExportLookup,
160 ) -> Option<Func> {
161 let store = store.as_context_mut().0;
162 let instance = &store[self.id];
163 let component = instance.component();
164
165 let index = name.lookup(component)?;
167
168 match &component.env_component().export_items[index] {
170 Export::LiftedFunction { .. } => {}
171 _ => return None,
172 }
173
174 Some(Func::from_lifted_func(*self, index))
176 }
177
178 pub fn get_typed_func<Params, Results>(
190 &self,
191 mut store: impl AsContextMut,
192 name: impl InstanceExportLookup,
193 ) -> Result<TypedFunc<Params, Results>>
194 where
195 Params: ComponentNamedList + Lower,
196 Results: ComponentNamedList + Lift,
197 {
198 let f = self
199 .get_func(store.as_context_mut(), name)
200 .ok_or_else(|| anyhow!("failed to find function export"))?;
201 Ok(f.typed::<Params, Results>(store)
202 .with_context(|| format!("failed to convert function to given type"))?)
203 }
204
205 pub fn get_module(
222 &self,
223 mut store: impl AsContextMut,
224 name: impl InstanceExportLookup,
225 ) -> Option<Module> {
226 let store = store.as_context_mut().0;
227 let (instance, export) = self.lookup_export(store, name)?;
228 match export {
229 Export::ModuleStatic { index, .. } => {
230 Some(instance.component().static_module(*index).clone())
231 }
232 Export::ModuleImport { import, .. } => match instance.runtime_import(*import) {
233 RuntimeImport::Module(m) => Some(m.clone()),
234 _ => unreachable!(),
235 },
236 _ => None,
237 }
238 }
239
240 pub fn get_resource(
257 &self,
258 mut store: impl AsContextMut,
259 name: impl InstanceExportLookup,
260 ) -> Option<ResourceType> {
261 let store = store.as_context_mut().0;
262 let (instance, export) = self.lookup_export(store, name)?;
263 match export {
264 Export::Type(TypeDef::Resource(id)) => {
265 Some(InstanceType::new(instance).resource_type(*id))
266 }
267 Export::Type(_)
268 | Export::LiftedFunction { .. }
269 | Export::ModuleStatic { .. }
270 | Export::ModuleImport { .. }
271 | Export::Instance { .. } => None,
272 }
273 }
274
275 pub fn get_export(
291 &self,
292 mut store: impl AsContextMut,
293 instance: Option<&ComponentExportIndex>,
294 name: &str,
295 ) -> Option<(ComponentItem, ComponentExportIndex)> {
296 self._get_export(store.as_context_mut().0, instance, name)
297 }
298
299 fn _get_export(
300 &self,
301 store: &StoreOpaque,
302 instance: Option<&ComponentExportIndex>,
303 name: &str,
304 ) -> Option<(ComponentItem, ComponentExportIndex)> {
305 let data = &store[self.id()];
306 let component = data.component();
307 let index = component.lookup_export_index(instance, name)?;
308 let item = ComponentItem::from_export(
309 &store.engine(),
310 &component.env_component().export_items[index],
311 &InstanceType::new(data),
312 );
313 Some((
314 item,
315 ComponentExportIndex {
316 id: data.component().id(),
317 index,
318 },
319 ))
320 }
321
322 pub fn get_export_index(
336 &self,
337 mut store: impl AsContextMut,
338 instance: Option<&ComponentExportIndex>,
339 name: &str,
340 ) -> Option<ComponentExportIndex> {
341 let data = &store.as_context_mut()[self.id()];
342 let index = data.component().lookup_export_index(instance, name)?;
343 Some(ComponentExportIndex {
344 id: data.component().id(),
345 index,
346 })
347 }
348
349 fn lookup_export<'a>(
350 &self,
351 store: &'a StoreOpaque,
352 name: impl InstanceExportLookup,
353 ) -> Option<(&'a ComponentInstance, &'a Export)> {
354 let data = &store[self.id()];
355 let index = name.lookup(data.component())?;
356 Some((data, &data.component().env_component().export_items[index]))
357 }
358
359 pub fn instance_pre<T>(&self, store: impl AsContext<Data = T>) -> InstancePre<T> {
361 let data = &store.as_context()[self.id()];
364
365 unsafe { data.instance_pre() }
370 }
371
372 pub(crate) fn instance_ptr(&self, store: &StoreOpaque) -> NonNull<ComponentInstance> {
375 self.id.assert_belongs_to(store.id());
376 store.component_instance_ptr(self.id.instance())
377 }
378
379 pub(crate) fn id(&self) -> StoreComponentInstanceId {
380 self.id
381 }
382
383 pub(crate) fn resource_new32(
386 self,
387 store: &mut StoreOpaque,
388 ty: TypeResourceTableIndex,
389 rep: u32,
390 ) -> Result<u32> {
391 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
392 resource_tables(calls, instance).resource_new(TypedResource::Component { ty, rep })
393 }
394
395 pub(crate) fn resource_rep32(
398 self,
399 store: &mut StoreOpaque,
400 ty: TypeResourceTableIndex,
401 index: u32,
402 ) -> Result<u32> {
403 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
404 resource_tables(calls, instance).resource_rep(TypedResourceIndex::Component { ty, index })
405 }
406
407 pub(crate) fn resource_drop(
409 self,
410 store: &mut StoreOpaque,
411 ty: TypeResourceTableIndex,
412 index: u32,
413 ) -> Result<Option<u32>> {
414 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
415 resource_tables(calls, instance).resource_drop(TypedResourceIndex::Component { ty, index })
416 }
417
418 pub(crate) fn resource_transfer_own(
419 self,
420 store: &mut StoreOpaque,
421 index: u32,
422 src: TypeResourceTableIndex,
423 dst: TypeResourceTableIndex,
424 ) -> Result<u32> {
425 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
426 let mut tables = resource_tables(calls, instance);
427 let rep = tables.resource_lift_own(TypedResourceIndex::Component { ty: src, index })?;
428 tables.resource_lower_own(TypedResource::Component { ty: dst, rep })
429 }
430
431 pub(crate) fn resource_transfer_borrow(
432 self,
433 store: &mut StoreOpaque,
434 index: u32,
435 src: TypeResourceTableIndex,
436 dst: TypeResourceTableIndex,
437 ) -> Result<u32> {
438 let dst_owns_resource = store[self.id()].resource_owned_by_own_instance(dst);
439 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
440 let mut tables = resource_tables(calls, instance);
441 let rep = tables.resource_lift_borrow(TypedResourceIndex::Component { ty: src, index })?;
442 if dst_owns_resource {
451 return Ok(rep);
452 }
453 tables.resource_lower_borrow(TypedResource::Component { ty: dst, rep })
454 }
455
456 pub(crate) fn resource_enter_call(self, store: &mut StoreOpaque) {
457 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
458 resource_tables(calls, instance).enter_call()
459 }
460
461 pub(crate) fn resource_exit_call(self, store: &mut StoreOpaque) -> Result<()> {
462 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
463 resource_tables(calls, instance).exit_call()
464 }
465}
466
467fn resource_tables<'a>(
468 calls: &'a mut CallContexts,
469 instance: &'a mut ComponentInstance,
470) -> ResourceTables<'a> {
471 ResourceTables {
472 host_table: None,
473 calls,
474 guest: Some(instance.guest_tables()),
475 }
476}
477
478pub trait InstanceExportLookup {
490 #[doc(hidden)]
491 fn lookup(&self, component: &Component) -> Option<ExportIndex>;
492}
493
494impl<T> InstanceExportLookup for &T
495where
496 T: InstanceExportLookup + ?Sized,
497{
498 fn lookup(&self, component: &Component) -> Option<ExportIndex> {
499 T::lookup(self, component)
500 }
501}
502
503impl InstanceExportLookup for str {
504 fn lookup(&self, component: &Component) -> Option<ExportIndex> {
505 component
506 .env_component()
507 .exports
508 .get(self, &NameMapNoIntern)
509 .copied()
510 }
511}
512
513impl InstanceExportLookup for String {
514 fn lookup(&self, component: &Component) -> Option<ExportIndex> {
515 str::lookup(self, component)
516 }
517}
518
519struct Instantiator<'a> {
520 component: &'a Component,
521 id: ComponentInstanceId,
522 core_imports: OwnedImports,
523 imports: &'a PrimaryMap<RuntimeImportIndex, RuntimeImport>,
524}
525
526pub(crate) enum RuntimeImport {
527 Func(Arc<HostFunc>),
528 Module(Module),
529 Resource {
530 ty: ResourceType,
531
532 _dtor: Arc<crate::func::HostFunc>,
542
543 dtor_funcref: VMFuncRef,
547 },
548}
549
550pub type ImportedResources = PrimaryMap<ResourceIndex, ResourceType>;
551
552impl<'a> Instantiator<'a> {
553 fn new(
554 component: &'a Component,
555 store: &mut StoreOpaque,
556 imports: &'a Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
557 ) -> Instantiator<'a> {
558 let env_component = component.env_component();
559 store.modules_mut().register_component(component);
560 let imported_resources: ImportedResources =
561 PrimaryMap::with_capacity(env_component.imported_resources.len());
562
563 let instance = OwnedComponentInstance::new(
564 store.store_data().components.next_component_instance_id(),
565 component,
566 Arc::new(imported_resources),
567 imports,
568 store.traitobj(),
569 );
570 let id = store.store_data_mut().push_component_instance(instance);
571
572 Instantiator {
573 component,
574 imports,
575 core_imports: OwnedImports::empty(),
576 id,
577 }
578 }
579
580 fn run<T>(&mut self, store: &mut StoreContextMut<'_, T>) -> Result<()> {
581 let env_component = self.component.env_component();
582
583 for (idx, import) in env_component.imported_resources.iter() {
587 let (ty, func_ref) = match &self.imports[*import] {
588 RuntimeImport::Resource {
589 ty, dtor_funcref, ..
590 } => (*ty, NonNull::from(dtor_funcref)),
591 _ => unreachable!(),
592 };
593 let i = self.instance_resource_types_mut(store.0).push(ty);
594 assert_eq!(i, idx);
595 self.instance_mut(store.0)
596 .set_resource_destructor(idx, Some(func_ref));
597 }
598
599 for (idx, sig) in env_component.trampolines.iter() {
604 let ptrs = self.component.trampoline_ptrs(idx);
605 let signature = match self.component.signatures().shared_type(*sig) {
606 Some(s) => s,
607 None => panic!("found unregistered signature: {sig:?}"),
608 };
609
610 self.instance_mut(store.0).set_trampoline(
611 idx,
612 ptrs.wasm_call,
613 ptrs.array_call,
614 signature,
615 );
616 }
617
618 for initializer in env_component.initializers.iter() {
619 match initializer {
620 GlobalInitializer::InstantiateModule(m) => {
621 let module;
622 let imports = match m {
623 InstantiateModule::Static(idx, args) => {
626 module = self.component.static_module(*idx);
627 self.build_imports(store.0, module, args.iter())
628 }
629
630 InstantiateModule::Import(idx, args) => {
639 module = match &self.imports[*idx] {
640 RuntimeImport::Module(m) => m,
641 _ => unreachable!(),
642 };
643 let args = module
644 .imports()
645 .map(|import| &args[import.module()][import.name()]);
646 self.build_imports(store.0, module, args)
647 }
648 };
649
650 let i = unsafe {
660 crate::Instance::new_started_impl(store, module, imports.as_ref())?
661 };
662 self.instance_mut(store.0).push_instance_id(i.id());
663 }
664
665 GlobalInitializer::LowerImport { import, index } => {
666 let func = match &self.imports[*import] {
667 RuntimeImport::Func(func) => func,
668 _ => unreachable!(),
669 };
670 self.instance_mut(store.0)
671 .set_lowering(*index, func.lowering());
672 }
673
674 GlobalInitializer::ExtractTable(table) => self.extract_table(store.0, table),
675
676 GlobalInitializer::ExtractMemory(mem) => self.extract_memory(store.0, mem),
677
678 GlobalInitializer::ExtractRealloc(realloc) => {
679 self.extract_realloc(store.0, realloc)
680 }
681
682 GlobalInitializer::ExtractCallback(callback) => {
683 self.extract_callback(store.0, callback)
684 }
685
686 GlobalInitializer::ExtractPostReturn(post_return) => {
687 self.extract_post_return(store.0, post_return)
688 }
689
690 GlobalInitializer::Resource(r) => self.resource(store.0, r),
691 }
692 }
693 Ok(())
694 }
695
696 fn resource(&mut self, store: &mut StoreOpaque, resource: &Resource) {
697 let instance = self.instance(store);
698 let dtor = resource
699 .dtor
700 .as_ref()
701 .map(|dtor| instance.lookup_def(store, dtor));
702 let dtor = dtor.map(|export| match export {
703 crate::runtime::vm::Export::Function(f) => f.func_ref,
704 _ => unreachable!(),
705 });
706 let index = self
707 .component
708 .env_component()
709 .resource_index(resource.index);
710 let ty = ResourceType::guest(store.id(), instance, resource.index);
711 self.instance_mut(store)
712 .set_resource_destructor(index, dtor);
713 let i = self.instance_resource_types_mut(store).push(ty);
714 debug_assert_eq!(i, index);
715 }
716
717 fn extract_memory(&mut self, store: &mut StoreOpaque, memory: &ExtractMemory) {
718 let mem = match self.instance(store).lookup_export(store, &memory.export) {
719 crate::runtime::vm::Export::Memory(m) => m,
720 _ => unreachable!(),
721 };
722 self.instance_mut(store)
723 .set_runtime_memory(memory.index, mem.definition);
724 }
725
726 fn extract_realloc(&mut self, store: &mut StoreOpaque, realloc: &ExtractRealloc) {
727 let func_ref = match self.instance(store).lookup_def(store, &realloc.def) {
728 crate::runtime::vm::Export::Function(f) => f.func_ref,
729 _ => unreachable!(),
730 };
731 self.instance_mut(store)
732 .set_runtime_realloc(realloc.index, func_ref);
733 }
734
735 fn extract_callback(&mut self, store: &mut StoreOpaque, callback: &ExtractCallback) {
736 let func_ref = match self.instance(store).lookup_def(store, &callback.def) {
737 crate::runtime::vm::Export::Function(f) => f.func_ref,
738 _ => unreachable!(),
739 };
740 self.instance_mut(store)
741 .set_runtime_callback(callback.index, func_ref);
742 }
743
744 fn extract_post_return(&mut self, store: &mut StoreOpaque, post_return: &ExtractPostReturn) {
745 let func_ref = match self.instance(store).lookup_def(store, &post_return.def) {
746 crate::runtime::vm::Export::Function(f) => f.func_ref,
747 _ => unreachable!(),
748 };
749 self.instance_mut(store)
750 .set_runtime_post_return(post_return.index, func_ref);
751 }
752
753 fn extract_table(&mut self, store: &mut StoreOpaque, table: &ExtractTable) {
754 let export = match self.instance(store).lookup_export(store, &table.export) {
755 crate::runtime::vm::Export::Table(t) => t,
756 _ => unreachable!(),
757 };
758 self.instance_mut(store).set_runtime_table(
759 table.index,
760 export.definition,
761 export.vmctx,
762 export.index,
763 );
764 }
765
766 fn build_imports<'b>(
767 &mut self,
768 store: &StoreOpaque,
769 module: &Module,
770 args: impl Iterator<Item = &'b CoreDef>,
771 ) -> &OwnedImports {
772 self.core_imports.clear();
773 self.core_imports.reserve(module);
774 let mut imports = module.compiled_module().module().imports();
775
776 for arg in args {
777 if cfg!(debug_assertions) {
783 let (imp_module, imp_name, expected) = imports.next().unwrap();
784 self.assert_type_matches(store, module, arg, imp_module, imp_name, expected);
785 }
786
787 let export = self.instance(store).lookup_def(store, arg);
791 unsafe {
792 self.core_imports.push_export(&export);
793 }
794 }
795 debug_assert!(imports.next().is_none());
796
797 &self.core_imports
798 }
799
800 fn assert_type_matches(
801 &self,
802 store: &StoreOpaque,
803 module: &Module,
804 arg: &CoreDef,
805 imp_module: &str,
806 imp_name: &str,
807 expected: EntityType,
808 ) {
809 let export = self.instance(store).lookup_def(store, arg);
810
811 if let crate::runtime::vm::Export::Function(f) = &export {
816 let expected = match expected.unwrap_func() {
817 EngineOrModuleTypeIndex::Engine(e) => Some(e),
818 EngineOrModuleTypeIndex::Module(m) => module.signatures().shared_type(m),
819 EngineOrModuleTypeIndex::RecGroup(_) => unreachable!(),
820 };
821 let actual = unsafe { f.func_ref.as_ref().type_index };
822 assert_eq!(
823 expected,
824 Some(actual),
825 "type mismatch for import {imp_module:?} {imp_name:?}!!!\n\n\
826 expected {:#?}\n\n\
827 found {:#?}",
828 expected.and_then(|e| store.engine().signatures().borrow(e)),
829 store.engine().signatures().borrow(actual)
830 );
831 return;
832 }
833
834 let val = unsafe { crate::Extern::from_wasmtime_export(export, store) };
835 let ty = DefinitionType::from(store, &val);
836 crate::types::matching::MatchCx::new(module.engine())
837 .definition(&expected, &ty)
838 .expect("unexpected typecheck failure");
839 }
840
841 fn instance<'b>(&self, store: &'b StoreOpaque) -> &'b ComponentInstance {
844 store.store_data().component_instance(self.id)
845 }
846
847 fn instance_mut<'b>(&self, store: &'b mut StoreOpaque) -> &'b mut ComponentInstance {
849 store.store_data_mut().component_instance_mut(self.id)
850 }
851
852 fn instance_resource_types_mut<'b>(
858 &self,
859 store: &'b mut StoreOpaque,
860 ) -> &'b mut ImportedResources {
861 Arc::get_mut(self.instance_mut(store).resource_types_mut()).unwrap()
862 }
863}
864
865pub struct InstancePre<T: 'static> {
874 component: Component,
875 imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
876 resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
877 _marker: marker::PhantomData<fn() -> T>,
878}
879
880impl<T: 'static> Clone for InstancePre<T> {
882 fn clone(&self) -> Self {
883 Self {
884 component: self.component.clone(),
885 imports: self.imports.clone(),
886 resource_types: self.resource_types.clone(),
887 _marker: self._marker,
888 }
889 }
890}
891
892impl<T: 'static> InstancePre<T> {
893 pub(crate) unsafe fn new_unchecked(
900 component: Component,
901 imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
902 resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
903 ) -> InstancePre<T> {
904 InstancePre {
905 component,
906 imports,
907 resource_types,
908 _marker: marker::PhantomData,
909 }
910 }
911
912 pub fn component(&self) -> &Component {
914 &self.component
915 }
916
917 #[doc(hidden)]
918 pub fn instance_type(&self) -> InstanceType<'_> {
922 InstanceType {
923 types: &self.component.types(),
924 resources: &self.resource_types,
925 }
926 }
927
928 pub fn engine(&self) -> &Engine {
930 self.component.engine()
931 }
932
933 pub fn instantiate(&self, store: impl AsContextMut<Data = T>) -> Result<Instance> {
937 assert!(
938 !store.as_context().async_support(),
939 "must use async instantiation when async support is enabled"
940 );
941 self.instantiate_impl(store)
942 }
943 #[cfg(feature = "async")]
949 pub async fn instantiate_async(
950 &self,
951 mut store: impl AsContextMut<Data = T>,
952 ) -> Result<Instance>
953 where
954 T: Send,
955 {
956 let mut store = store.as_context_mut();
957 assert!(
958 store.0.async_support(),
959 "must use sync instantiation when async support is disabled"
960 );
961 store.on_fiber(|store| self.instantiate_impl(store)).await?
962 }
963
964 fn instantiate_impl(&self, mut store: impl AsContextMut<Data = T>) -> Result<Instance> {
965 let mut store = store.as_context_mut();
966 store
967 .engine()
968 .allocator()
969 .increment_component_instance_count()?;
970 let mut instantiator = Instantiator::new(&self.component, store.0, &self.imports);
971 instantiator.run(&mut store).map_err(|e| {
972 store
973 .engine()
974 .allocator()
975 .decrement_component_instance_count();
976 e
977 })?;
978 let instance = Instance::from_wasmtime(store.0, instantiator.id);
979 store.0.push_component_instance(instance);
980 Ok(instance)
981 }
982}