wasmer/entities/table/
inner.rs

1use wasmer_types::TableType;
2
3use crate::{
4    AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, Value,
5    error::RuntimeError,
6    macros::backend::{gen_rt_ty, match_rt},
7    store::BackendStore,
8    vm::{VMExtern, VMExternTable},
9};
10/// A WebAssembly `table` instance.
11///
12/// The `Table` struct is an array-like structure representing a WebAssembly Table,
13/// which stores function references.
14///
15/// A table created by the host or in WebAssembly code will be accessible and
16/// mutable from both host and WebAssembly.
17///
18/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
19gen_rt_ty! {
20    #[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
21    #[derive(Debug, Clone, PartialEq, Eq, derive_more::From)]
22    pub BackendTable(entities::table::Table);
23}
24
25impl BackendTable {
26    /// Creates a new table with the provided [`TableType`] definition.
27    ///
28    /// All the elements in the table will be set to the `init` value.
29    ///
30    /// This function will construct the table using the store `BaseTunables`.
31    #[inline]
32    pub fn new(
33        store: &mut impl AsStoreMut,
34        ty: TableType,
35        init: Value,
36    ) -> Result<Self, RuntimeError> {
37        match &store.as_store_mut().inner.store {
38            #[cfg(feature = "sys")]
39            BackendStore::Sys(_) => Ok(Self::Sys(
40                crate::backend::sys::entities::table::Table::new(store, ty, init)?,
41            )),
42            #[cfg(feature = "v8")]
43            BackendStore::V8(_) => Ok(Self::V8(crate::backend::v8::entities::table::Table::new(
44                store, ty, init,
45            )?)),
46            #[cfg(feature = "js")]
47            BackendStore::Js(_) => Ok(Self::Js(crate::backend::js::entities::table::Table::new(
48                store, ty, init,
49            )?)),
50        }
51    }
52
53    /// Returns the [`TableType`] of the table.
54    #[inline]
55    pub fn ty(&self, store: &impl AsStoreRef) -> TableType {
56        match_rt!(on self => s {
57            s.ty(store)
58        })
59    }
60
61    /// Retrieves an element of the table at the provided `index`.
62    #[inline]
63    pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option<Value> {
64        match_rt!(on self => s {
65            s.get(store, index)
66        })
67    }
68
69    /// Sets an element `val` in the Table at the provided `index`.
70    #[inline]
71    pub fn set(
72        &self,
73        store: &mut impl AsStoreMut,
74        index: u32,
75        val: Value,
76    ) -> Result<(), RuntimeError> {
77        match_rt!(on self => s {
78            s.set(store, index, val)
79        })
80    }
81
82    /// Retrieves the size of the `Table` (in elements)
83    #[inline]
84    pub fn size(&self, store: &impl AsStoreRef) -> u32 {
85        match_rt!(on self => s {
86            s.size(store)
87        })
88    }
89
90    /// Grows the size of the `Table` by `delta`, initializing
91    /// the elements with the provided `init` value.
92    ///
93    /// It returns the previous size of the `Table` in case is able
94    /// to grow the Table successfully.
95    ///
96    /// # Errors
97    ///
98    /// Returns an error if the `delta` is out of bounds for the table.
99    #[inline]
100    pub fn grow(
101        &self,
102        store: &mut impl AsStoreMut,
103        delta: u32,
104        init: Value,
105    ) -> Result<u32, RuntimeError> {
106        match_rt!(on self => s {
107            s.grow(store, delta, init)
108        })
109    }
110
111    /// Copies the `len` elements of `src_table` starting at `src_index`
112    /// to the destination table `dst_table` at index `dst_index`.
113    ///
114    /// # Errors
115    ///
116    /// Returns an error if the range is out of bounds of either the source or
117    /// destination tables.
118    #[inline]
119    pub fn copy(
120        store: &mut impl AsStoreMut,
121        dst_table: &Self,
122        dst_index: u32,
123        src_table: &Self,
124        src_index: u32,
125        len: u32,
126    ) -> Result<(), RuntimeError> {
127        match &store.as_store_mut().inner.store {
128            #[cfg(feature = "sys")]
129            BackendStore::Sys(_) => crate::backend::sys::entities::table::Table::copy(
130                store,
131                dst_table.as_sys(),
132                dst_index,
133                src_table.as_sys(),
134                src_index,
135                len,
136            ),
137
138            #[cfg(feature = "v8")]
139            BackendStore::V8(_) => crate::backend::v8::entities::table::Table::copy(
140                store,
141                dst_table.as_v8(),
142                dst_index,
143                src_table.as_v8(),
144                src_index,
145                len,
146            ),
147            #[cfg(feature = "js")]
148            BackendStore::Js(_) => crate::backend::js::entities::table::Table::copy(
149                store,
150                dst_table.as_js(),
151                dst_index,
152                src_table.as_js(),
153                src_index,
154                len,
155            ),
156        }
157    }
158
159    #[inline]
160    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, ext: VMExternTable) -> Self {
161        match &store.as_store_mut().inner.store {
162            #[cfg(feature = "sys")]
163            BackendStore::Sys(_) => Self::Sys(
164                crate::backend::sys::entities::table::Table::from_vm_extern(store, ext),
165            ),
166            #[cfg(feature = "v8")]
167            BackendStore::V8(_) => Self::V8(
168                crate::backend::v8::entities::table::Table::from_vm_extern(store, ext),
169            ),
170            #[cfg(feature = "js")]
171            BackendStore::Js(_) => Self::Js(
172                crate::backend::js::entities::table::Table::from_vm_extern(store, ext),
173            ),
174        }
175    }
176
177    /// Checks whether this `Table` can be used with the given context.
178    #[inline]
179    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
180        match_rt!(on self => s {
181            s.is_from_store(store)
182        })
183    }
184
185    #[inline]
186    pub(crate) fn to_vm_extern(&self) -> VMExtern {
187        match_rt!(on self => s {
188            s.to_vm_extern()
189        })
190    }
191}
192
193#[cfg(test)]
194mod test {
195    /// Check the example from <https://github.com/wasmerio/wasmer/issues/3197>.
196    #[test]
197    #[cfg_attr(
198        feature = "v8",
199        ignore = "growing tables in v8 is not currently supported"
200    )]
201    fn table_grow_issue_3197() {
202        use crate::{Instance, Module, Store, Table, TableType, Type, Value, imports};
203
204        const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#;
205
206        // Tests that the table type of `table` is compatible with the export in the WAT
207        // This tests that `wasmer_types::types::is_table_compatible` works as expected.
208        let mut store = Store::default();
209        let module = Module::new(&store, WAT).unwrap();
210        let ty = TableType::new(Type::FuncRef, 0, None);
211        let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap();
212        table.grow(&mut store, 100, Value::FuncRef(None)).unwrap();
213        assert_eq!(table.ty(&store).minimum, 0);
214        let imports = imports! {"env" => {"table" => table}};
215        let _instance = Instance::new(&mut store, &module, &imports).unwrap();
216    }
217}