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