1 use crate::Result; 2 use crate::runtime::types::TagType; 3 use crate::trampoline::generate_tag_export; 4 use crate::{ 5 AsContext, AsContextMut, 6 store::{StoreInstanceId, StoreOpaque}, 7 }; 8 use wasmtime_environ::DefinedTagIndex; 9 10 #[cfg(feature = "gc")] 11 use crate::store::InstanceId; 12 13 /// A WebAssembly `tag`. 14 #[derive(Copy, Clone, Debug)] 15 #[repr(C)] // here for the C API in the future 16 pub struct Tag { 17 instance: StoreInstanceId, 18 index: DefinedTagIndex, 19 } 20 21 impl Tag { from_raw(instance: StoreInstanceId, index: DefinedTagIndex) -> Tag22 pub(crate) fn from_raw(instance: StoreInstanceId, index: DefinedTagIndex) -> Tag { 23 Tag { instance, index } 24 } 25 26 /// Create a new tag instance from a given TagType. new(mut store: impl AsContextMut, ty: &TagType) -> Result<Tag>27 pub fn new(mut store: impl AsContextMut, ty: &TagType) -> Result<Tag> { 28 generate_tag_export(store.as_context_mut().0, ty) 29 } 30 31 /// Returns the underlying type of this `tag`. 32 /// 33 /// # Panics 34 /// 35 /// Panics if `store` does not own this tag. ty(&self, store: impl AsContext) -> TagType36 pub fn ty(&self, store: impl AsContext) -> TagType { 37 self._ty(store.as_context().0) 38 } 39 _ty(&self, store: &StoreOpaque) -> TagType40 pub(crate) fn _ty(&self, store: &StoreOpaque) -> TagType { 41 TagType::from_wasmtime_tag(store.engine(), self.wasmtime_ty(store)) 42 } 43 wasmtime_ty<'a>(&self, store: &'a StoreOpaque) -> &'a wasmtime_environ::Tag44 pub(crate) fn wasmtime_ty<'a>(&self, store: &'a StoreOpaque) -> &'a wasmtime_environ::Tag { 45 let module = store[self.instance].env_module(); 46 let index = module.tag_index(self.index); 47 &module.tags[index] 48 } 49 vmimport(&self, store: &StoreOpaque) -> crate::runtime::vm::VMTagImport50 pub(crate) fn vmimport(&self, store: &StoreOpaque) -> crate::runtime::vm::VMTagImport { 51 let instance = &store[self.instance]; 52 crate::runtime::vm::VMTagImport { 53 from: instance.tag_ptr(self.index).into(), 54 vmctx: instance.vmctx().into(), 55 index: self.index, 56 } 57 } 58 comes_from_same_store(&self, store: &StoreOpaque) -> bool59 pub(crate) fn comes_from_same_store(&self, store: &StoreOpaque) -> bool { 60 store.id() == self.instance.store_id() 61 } 62 63 /// Returns a stable identifier for this tag within its store. 64 /// 65 /// This allows distinguishing tags when introspecting them 66 /// e.g. via debug APIs. 67 #[cfg(feature = "debug")] debug_index_in_store(&self) -> u6468 pub fn debug_index_in_store(&self) -> u64 { 69 u64::from(self.instance.instance().as_u32()) << 32 | u64::from(self.index.as_u32()) 70 } 71 72 /// Determines whether this tag is reference equal to the other 73 /// given tag in the given store. 74 /// 75 /// # Panics 76 /// 77 /// Panics if either tag do not belong to the given `store`. eq(a: &Tag, b: &Tag, store: impl AsContext) -> bool78 pub fn eq(a: &Tag, b: &Tag, store: impl AsContext) -> bool { 79 // make sure both tags belong to the store 80 let store = store.as_context(); 81 let _ = &store[a.instance]; 82 let _ = &store[b.instance]; 83 84 // then compare to see if they have the same definition 85 a.instance == b.instance && a.index == b.index 86 } 87 88 /// Get the "index coordinates" for this `Tag`: the raw instance 89 /// ID and defined-tag index within that instance. This can be 90 /// used to "serialize" the tag as safe (tamper-proof, 91 /// bounds-checked) values, e.g. within the GC store for an 92 /// exception object. 93 #[cfg(feature = "gc")] to_raw_indices(&self) -> (InstanceId, DefinedTagIndex)94 pub(crate) fn to_raw_indices(&self) -> (InstanceId, DefinedTagIndex) { 95 (self.instance.instance(), self.index) 96 } 97 98 /// Create a new `Tag` from known raw indices as produced by 99 /// `to_raw_indices()`. 100 /// 101 /// # Panics 102 /// 103 /// Panics if the indices are out-of-bounds in the given store. 104 #[cfg(feature = "gc")] from_raw_indices( store: &StoreOpaque, instance: InstanceId, index: DefinedTagIndex, ) -> Tag105 pub(crate) fn from_raw_indices( 106 store: &StoreOpaque, 107 instance: InstanceId, 108 index: DefinedTagIndex, 109 ) -> Tag { 110 let instance = StoreInstanceId::new(store.id(), instance); 111 Tag { instance, index } 112 } 113 } 114