Skip to main content

wasmtime/runtime/externals/
tag.rs

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