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::component::{
12 CallContexts, ComponentInstance, ResourceTables, TypedResource, TypedResourceIndex,
13};
14use crate::runtime::vm::{self, ExportFunction, ExportGlobal, ExportGlobalKind, VMFuncRef};
15use crate::store::StoreOpaque;
16use crate::{AsContext, AsContextMut, Engine, Module, StoreContextMut};
17use alloc::sync::Arc;
18use core::marker;
19use core::pin::Pin;
20use core::ptr::NonNull;
21use wasmtime_environ::{EngineOrModuleTypeIndex, component::*};
22use wasmtime_environ::{EntityIndex, EntityType, Global, PrimaryMap, WasmValType};
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 = self.id.get(store);
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 = self.id().get(store);
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 = self.id().get(store.as_context_mut().0);
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 = self.id().get(store);
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 = self.id().get(store.as_context().0);
364
365 unsafe { data.instance_pre() }
370 }
371
372 pub(crate) fn id(&self) -> StoreComponentInstanceId {
373 self.id
374 }
375
376 pub(crate) fn resource_new32(
379 self,
380 store: &mut StoreOpaque,
381 ty: TypeResourceTableIndex,
382 rep: u32,
383 ) -> Result<u32> {
384 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
385 resource_tables(calls, instance).resource_new(TypedResource::Component { ty, rep })
386 }
387
388 pub(crate) fn resource_rep32(
391 self,
392 store: &mut StoreOpaque,
393 ty: TypeResourceTableIndex,
394 index: u32,
395 ) -> Result<u32> {
396 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
397 resource_tables(calls, instance).resource_rep(TypedResourceIndex::Component { ty, index })
398 }
399
400 pub(crate) fn resource_drop(
402 self,
403 store: &mut StoreOpaque,
404 ty: TypeResourceTableIndex,
405 index: u32,
406 ) -> Result<Option<u32>> {
407 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
408 resource_tables(calls, instance).resource_drop(TypedResourceIndex::Component { ty, index })
409 }
410
411 pub(crate) fn resource_transfer_own(
412 self,
413 store: &mut StoreOpaque,
414 index: u32,
415 src: TypeResourceTableIndex,
416 dst: TypeResourceTableIndex,
417 ) -> Result<u32> {
418 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
419 let mut tables = resource_tables(calls, instance);
420 let rep = tables.resource_lift_own(TypedResourceIndex::Component { ty: src, index })?;
421 tables.resource_lower_own(TypedResource::Component { ty: dst, rep })
422 }
423
424 pub(crate) fn resource_transfer_borrow(
425 self,
426 store: &mut StoreOpaque,
427 index: u32,
428 src: TypeResourceTableIndex,
429 dst: TypeResourceTableIndex,
430 ) -> Result<u32> {
431 let dst_owns_resource = self.id().get(store).resource_owned_by_own_instance(dst);
432 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
433 let mut tables = resource_tables(calls, instance);
434 let rep = tables.resource_lift_borrow(TypedResourceIndex::Component { ty: src, index })?;
435 if dst_owns_resource {
444 return Ok(rep);
445 }
446 tables.resource_lower_borrow(TypedResource::Component { ty: dst, rep })
447 }
448
449 pub(crate) fn resource_enter_call(self, store: &mut StoreOpaque) {
450 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
451 resource_tables(calls, instance).enter_call()
452 }
453
454 pub(crate) fn resource_exit_call(self, store: &mut StoreOpaque) -> Result<()> {
455 let (calls, _, _, instance) = store.component_resource_state_with_instance(self);
456 resource_tables(calls, instance).exit_call()
457 }
458
459 pub(crate) fn lookup_vmdef(&self, store: &mut StoreOpaque, def: &CoreDef) -> vm::Export {
460 lookup_vmdef(store, self.id.instance(), def)
461 }
462}
463
464pub(crate) fn lookup_vmdef(
467 store: &mut StoreOpaque,
468 id: ComponentInstanceId,
469 def: &CoreDef,
470) -> vm::Export {
471 match def {
472 CoreDef::Export(e) => lookup_vmexport(store, id, e),
473 CoreDef::Trampoline(idx) => vm::Export::Function(ExportFunction {
474 func_ref: store
475 .store_data_mut()
476 .component_instance_mut(id)
477 .trampoline_func_ref(*idx),
478 }),
479 CoreDef::InstanceFlags(idx) => {
480 let instance = store.store_data_mut().component_instance_mut(id);
481 vm::Export::Global(ExportGlobal {
482 definition: instance.instance_flags(*idx).as_raw(),
483 global: Global {
484 wasm_ty: WasmValType::I32,
485 mutability: true,
486 },
487 kind: ExportGlobalKind::ComponentFlags(instance.vmctx(), *idx),
488 })
489 }
490 }
491}
492
493pub(crate) fn lookup_vmexport<T>(
496 store: &mut StoreOpaque,
497 id: ComponentInstanceId,
498 item: &CoreExport<T>,
499) -> vm::Export
500where
501 T: Copy + Into<EntityIndex>,
502{
503 let id = store
504 .store_data_mut()
505 .component_instance_mut(id)
506 .instance(item.instance);
507 let instance = store.instance_mut(id);
508 let idx = match &item.item {
509 ExportItem::Index(idx) => (*idx).into(),
510
511 ExportItem::Name(name) => instance.env_module().exports[name],
521 };
522 instance.get_export_by_index_mut(idx)
523}
524
525fn resource_tables<'a>(
526 calls: &'a mut CallContexts,
527 instance: Pin<&'a mut ComponentInstance>,
528) -> ResourceTables<'a> {
529 ResourceTables {
530 host_table: None,
531 calls,
532 guest: Some(instance.guest_tables()),
533 }
534}
535
536pub trait InstanceExportLookup {
548 #[doc(hidden)]
549 fn lookup(&self, component: &Component) -> Option<ExportIndex>;
550}
551
552impl<T> InstanceExportLookup for &T
553where
554 T: InstanceExportLookup + ?Sized,
555{
556 fn lookup(&self, component: &Component) -> Option<ExportIndex> {
557 T::lookup(self, component)
558 }
559}
560
561impl InstanceExportLookup for str {
562 fn lookup(&self, component: &Component) -> Option<ExportIndex> {
563 component
564 .env_component()
565 .exports
566 .get(self, &NameMapNoIntern)
567 .copied()
568 }
569}
570
571impl InstanceExportLookup for String {
572 fn lookup(&self, component: &Component) -> Option<ExportIndex> {
573 str::lookup(self, component)
574 }
575}
576
577struct Instantiator<'a> {
578 component: &'a Component,
579 id: ComponentInstanceId,
580 core_imports: OwnedImports,
581 imports: &'a PrimaryMap<RuntimeImportIndex, RuntimeImport>,
582}
583
584pub(crate) enum RuntimeImport {
585 Func(Arc<HostFunc>),
586 Module(Module),
587 Resource {
588 ty: ResourceType,
589
590 _dtor: Arc<crate::func::HostFunc>,
600
601 dtor_funcref: VMFuncRef,
605 },
606}
607
608pub type ImportedResources = PrimaryMap<ResourceIndex, ResourceType>;
609
610impl<'a> Instantiator<'a> {
611 fn new(
612 component: &'a Component,
613 store: &mut StoreOpaque,
614 imports: &'a Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
615 ) -> Instantiator<'a> {
616 let env_component = component.env_component();
617 store.modules_mut().register_component(component);
618 let imported_resources: ImportedResources =
619 PrimaryMap::with_capacity(env_component.imported_resources.len());
620
621 let instance = ComponentInstance::new(
622 store.store_data().components.next_component_instance_id(),
623 component,
624 Arc::new(imported_resources),
625 imports,
626 store.traitobj(),
627 );
628 let id = store.store_data_mut().push_component_instance(instance);
629
630 Instantiator {
631 component,
632 imports,
633 core_imports: OwnedImports::empty(),
634 id,
635 }
636 }
637
638 fn run<T>(&mut self, store: &mut StoreContextMut<'_, T>) -> Result<()> {
639 let env_component = self.component.env_component();
640
641 for (idx, import) in env_component.imported_resources.iter() {
645 let (ty, func_ref) = match &self.imports[*import] {
646 RuntimeImport::Resource {
647 ty, dtor_funcref, ..
648 } => (*ty, NonNull::from(dtor_funcref)),
649 _ => unreachable!(),
650 };
651 let i = self.instance_resource_types_mut(store.0).push(ty);
652 assert_eq!(i, idx);
653 self.instance_mut(store.0)
654 .set_resource_destructor(idx, Some(func_ref));
655 }
656
657 for (idx, sig) in env_component.trampolines.iter() {
662 let ptrs = self.component.trampoline_ptrs(idx);
663 let signature = match self.component.signatures().shared_type(*sig) {
664 Some(s) => s,
665 None => panic!("found unregistered signature: {sig:?}"),
666 };
667
668 self.instance_mut(store.0).set_trampoline(
669 idx,
670 ptrs.wasm_call,
671 ptrs.array_call,
672 signature,
673 );
674 }
675
676 for initializer in env_component.initializers.iter() {
677 match initializer {
678 GlobalInitializer::InstantiateModule(m) => {
679 let module;
680 let imports = match m {
681 InstantiateModule::Static(idx, args) => {
684 module = self.component.static_module(*idx);
685 self.build_imports(store.0, module, args.iter())
686 }
687
688 InstantiateModule::Import(idx, args) => {
697 module = match &self.imports[*idx] {
698 RuntimeImport::Module(m) => m,
699 _ => unreachable!(),
700 };
701 let args = module
702 .imports()
703 .map(|import| &args[import.module()][import.name()]);
704 self.build_imports(store.0, module, args)
705 }
706 };
707
708 let i = unsafe {
718 crate::Instance::new_started_impl(store, module, imports.as_ref())?
719 };
720 self.instance_mut(store.0).push_instance_id(i.id());
721 }
722
723 GlobalInitializer::LowerImport { import, index } => {
724 let func = match &self.imports[*import] {
725 RuntimeImport::Func(func) => func,
726 _ => unreachable!(),
727 };
728 self.instance_mut(store.0)
729 .set_lowering(*index, func.lowering());
730 }
731
732 GlobalInitializer::ExtractTable(table) => self.extract_table(store.0, table),
733
734 GlobalInitializer::ExtractMemory(mem) => self.extract_memory(store.0, mem),
735
736 GlobalInitializer::ExtractRealloc(realloc) => {
737 self.extract_realloc(store.0, realloc)
738 }
739
740 GlobalInitializer::ExtractCallback(callback) => {
741 self.extract_callback(store.0, callback)
742 }
743
744 GlobalInitializer::ExtractPostReturn(post_return) => {
745 self.extract_post_return(store.0, post_return)
746 }
747
748 GlobalInitializer::Resource(r) => self.resource(store.0, r),
749 }
750 }
751 Ok(())
752 }
753
754 fn resource(&mut self, store: &mut StoreOpaque, resource: &Resource) {
755 let dtor = resource
756 .dtor
757 .as_ref()
758 .map(|dtor| lookup_vmdef(store, self.id, dtor));
759 let dtor = dtor.map(|export| match export {
760 crate::runtime::vm::Export::Function(f) => f.func_ref,
761 _ => unreachable!(),
762 });
763 let index = self
764 .component
765 .env_component()
766 .resource_index(resource.index);
767 let instance = self.instance(store);
768 let ty = ResourceType::guest(store.id(), instance, resource.index);
769 self.instance_mut(store)
770 .set_resource_destructor(index, dtor);
771 let i = self.instance_resource_types_mut(store).push(ty);
772 debug_assert_eq!(i, index);
773 }
774
775 fn extract_memory(&mut self, store: &mut StoreOpaque, memory: &ExtractMemory) {
776 let mem = match lookup_vmexport(store, self.id, &memory.export) {
777 crate::runtime::vm::Export::Memory(m) => m,
778 _ => unreachable!(),
779 };
780 self.instance_mut(store)
781 .set_runtime_memory(memory.index, mem.definition);
782 }
783
784 fn extract_realloc(&mut self, store: &mut StoreOpaque, realloc: &ExtractRealloc) {
785 let func_ref = match lookup_vmdef(store, self.id, &realloc.def) {
786 crate::runtime::vm::Export::Function(f) => f.func_ref,
787 _ => unreachable!(),
788 };
789 self.instance_mut(store)
790 .set_runtime_realloc(realloc.index, func_ref);
791 }
792
793 fn extract_callback(&mut self, store: &mut StoreOpaque, callback: &ExtractCallback) {
794 let func_ref = match lookup_vmdef(store, self.id, &callback.def) {
795 crate::runtime::vm::Export::Function(f) => f.func_ref,
796 _ => unreachable!(),
797 };
798 self.instance_mut(store)
799 .set_runtime_callback(callback.index, func_ref);
800 }
801
802 fn extract_post_return(&mut self, store: &mut StoreOpaque, post_return: &ExtractPostReturn) {
803 let func_ref = match lookup_vmdef(store, self.id, &post_return.def) {
804 crate::runtime::vm::Export::Function(f) => f.func_ref,
805 _ => unreachable!(),
806 };
807 self.instance_mut(store)
808 .set_runtime_post_return(post_return.index, func_ref);
809 }
810
811 fn extract_table(&mut self, store: &mut StoreOpaque, table: &ExtractTable) {
812 let export = match lookup_vmexport(store, self.id, &table.export) {
813 crate::runtime::vm::Export::Table(t) => t,
814 _ => unreachable!(),
815 };
816 self.instance_mut(store).set_runtime_table(
817 table.index,
818 export.definition,
819 export.vmctx,
820 export.index,
821 );
822 }
823
824 fn build_imports<'b>(
825 &mut self,
826 store: &mut StoreOpaque,
827 module: &Module,
828 args: impl Iterator<Item = &'b CoreDef>,
829 ) -> &OwnedImports {
830 self.core_imports.clear();
831 self.core_imports.reserve(module);
832 let mut imports = module.compiled_module().module().imports();
833
834 for arg in args {
835 if cfg!(debug_assertions) {
841 let (imp_module, imp_name, expected) = imports.next().unwrap();
842 self.assert_type_matches(store, module, arg, imp_module, imp_name, expected);
843 }
844
845 let export = lookup_vmdef(store, self.id, arg);
849 unsafe {
850 self.core_imports.push_export(&export);
851 }
852 }
853 debug_assert!(imports.next().is_none());
854
855 &self.core_imports
856 }
857
858 fn assert_type_matches(
859 &self,
860 store: &mut StoreOpaque,
861 module: &Module,
862 arg: &CoreDef,
863 imp_module: &str,
864 imp_name: &str,
865 expected: EntityType,
866 ) {
867 let export = lookup_vmdef(store, self.id, arg);
868
869 if let crate::runtime::vm::Export::Function(f) = &export {
874 let expected = match expected.unwrap_func() {
875 EngineOrModuleTypeIndex::Engine(e) => Some(e),
876 EngineOrModuleTypeIndex::Module(m) => module.signatures().shared_type(m),
877 EngineOrModuleTypeIndex::RecGroup(_) => unreachable!(),
878 };
879 let actual = unsafe { f.func_ref.as_ref().type_index };
880 assert_eq!(
881 expected,
882 Some(actual),
883 "type mismatch for import {imp_module:?} {imp_name:?}!!!\n\n\
884 expected {:#?}\n\n\
885 found {:#?}",
886 expected.and_then(|e| store.engine().signatures().borrow(e)),
887 store.engine().signatures().borrow(actual)
888 );
889 return;
890 }
891
892 let val = unsafe { crate::Extern::from_wasmtime_export(export, store) };
893 let ty = DefinitionType::from(store, &val);
894 crate::types::matching::MatchCx::new(module.engine())
895 .definition(&expected, &ty)
896 .expect("unexpected typecheck failure");
897 }
898
899 fn instance<'b>(&self, store: &'b StoreOpaque) -> &'b ComponentInstance {
902 store.store_data().component_instance(self.id)
903 }
904
905 fn instance_mut<'b>(&self, store: &'b mut StoreOpaque) -> Pin<&'b mut ComponentInstance> {
907 store.store_data_mut().component_instance_mut(self.id)
908 }
909
910 fn instance_resource_types_mut<'b>(
916 &self,
917 store: &'b mut StoreOpaque,
918 ) -> &'b mut ImportedResources {
919 Arc::get_mut(self.instance_mut(store).resource_types_mut()).unwrap()
920 }
921}
922
923pub struct InstancePre<T: 'static> {
932 component: Component,
933 imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
934 resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
935 _marker: marker::PhantomData<fn() -> T>,
936}
937
938impl<T: 'static> Clone for InstancePre<T> {
940 fn clone(&self) -> Self {
941 Self {
942 component: self.component.clone(),
943 imports: self.imports.clone(),
944 resource_types: self.resource_types.clone(),
945 _marker: self._marker,
946 }
947 }
948}
949
950impl<T: 'static> InstancePre<T> {
951 pub(crate) unsafe fn new_unchecked(
958 component: Component,
959 imports: Arc<PrimaryMap<RuntimeImportIndex, RuntimeImport>>,
960 resource_types: Arc<PrimaryMap<ResourceIndex, ResourceType>>,
961 ) -> InstancePre<T> {
962 InstancePre {
963 component,
964 imports,
965 resource_types,
966 _marker: marker::PhantomData,
967 }
968 }
969
970 pub fn component(&self) -> &Component {
972 &self.component
973 }
974
975 #[doc(hidden)]
976 pub fn instance_type(&self) -> InstanceType<'_> {
980 InstanceType {
981 types: &self.component.types(),
982 resources: &self.resource_types,
983 }
984 }
985
986 pub fn engine(&self) -> &Engine {
988 self.component.engine()
989 }
990
991 pub fn instantiate(&self, store: impl AsContextMut<Data = T>) -> Result<Instance> {
995 assert!(
996 !store.as_context().async_support(),
997 "must use async instantiation when async support is enabled"
998 );
999 self.instantiate_impl(store)
1000 }
1001 #[cfg(feature = "async")]
1007 pub async fn instantiate_async(
1008 &self,
1009 mut store: impl AsContextMut<Data = T>,
1010 ) -> Result<Instance>
1011 where
1012 T: Send,
1013 {
1014 let mut store = store.as_context_mut();
1015 assert!(
1016 store.0.async_support(),
1017 "must use sync instantiation when async support is disabled"
1018 );
1019 store.on_fiber(|store| self.instantiate_impl(store)).await?
1020 }
1021
1022 fn instantiate_impl(&self, mut store: impl AsContextMut<Data = T>) -> Result<Instance> {
1023 let mut store = store.as_context_mut();
1024 store
1025 .engine()
1026 .allocator()
1027 .increment_component_instance_count()?;
1028 let mut instantiator = Instantiator::new(&self.component, store.0, &self.imports);
1029 instantiator.run(&mut store).map_err(|e| {
1030 store
1031 .engine()
1032 .allocator()
1033 .decrement_component_instance_count();
1034 e
1035 })?;
1036 let instance = Instance::from_wasmtime(store.0, instantiator.id);
1037 store.0.push_component_instance(instance);
1038 Ok(instance)
1039 }
1040}