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 = "wamr")]
43            BackendStore::Wamr(_) => Ok(Self::Wamr(
44                crate::backend::wamr::entities::table::Table::new(store, ty, init)?,
45            )),
46            #[cfg(feature = "wasmi")]
47            BackendStore::Wasmi(_) => Ok(Self::Wasmi(
48                crate::backend::wasmi::entities::table::Table::new(store, ty, init)?,
49            )),
50            #[cfg(feature = "v8")]
51            BackendStore::V8(_) => Ok(Self::V8(crate::backend::v8::entities::table::Table::new(
52                store, ty, init,
53            )?)),
54            #[cfg(feature = "js")]
55            BackendStore::Js(_) => Ok(Self::Js(crate::backend::js::entities::table::Table::new(
56                store, ty, init,
57            )?)),
58            #[cfg(feature = "jsc")]
59            BackendStore::Jsc(_) => Ok(Self::Jsc(
60                crate::backend::jsc::entities::table::Table::new(store, ty, init)?,
61            )),
62        }
63    }
64
65    /// Returns the [`TableType`] of the table.
66    #[inline]
67    pub fn ty(&self, store: &impl AsStoreRef) -> TableType {
68        match_rt!(on self => s {
69            s.ty(store)
70        })
71    }
72
73    /// Retrieves an element of the table at the provided `index`.
74    #[inline]
75    pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option<Value> {
76        match_rt!(on self => s {
77            s.get(store, index)
78        })
79    }
80
81    /// Sets an element `val` in the Table at the provided `index`.
82    #[inline]
83    pub fn set(
84        &self,
85        store: &mut impl AsStoreMut,
86        index: u32,
87        val: Value,
88    ) -> Result<(), RuntimeError> {
89        match_rt!(on self => s {
90            s.set(store, index, val)
91        })
92    }
93
94    /// Retrieves the size of the `Table` (in elements)
95    #[inline]
96    pub fn size(&self, store: &impl AsStoreRef) -> u32 {
97        match_rt!(on self => s {
98            s.size(store)
99        })
100    }
101
102    /// Grows the size of the `Table` by `delta`, initializating
103    /// the elements with the provided `init` value.
104    ///
105    /// It returns the previous size of the `Table` in case is able
106    /// to grow the Table successfully.
107    ///
108    /// # Errors
109    ///
110    /// Returns an error if the `delta` is out of bounds for the table.
111    #[inline]
112    pub fn grow(
113        &self,
114        store: &mut impl AsStoreMut,
115        delta: u32,
116        init: Value,
117    ) -> Result<u32, RuntimeError> {
118        match_rt!(on self => s {
119            s.grow(store, delta, init)
120        })
121    }
122
123    /// Copies the `len` elements of `src_table` starting at `src_index`
124    /// to the destination table `dst_table` at index `dst_index`.
125    ///
126    /// # Errors
127    ///
128    /// Returns an error if the range is out of bounds of either the source or
129    /// destination tables.
130    #[inline]
131    pub fn copy(
132        store: &mut impl AsStoreMut,
133        dst_table: &Self,
134        dst_index: u32,
135        src_table: &Self,
136        src_index: u32,
137        len: u32,
138    ) -> Result<(), RuntimeError> {
139        match &store.as_store_mut().inner.store {
140            #[cfg(feature = "sys")]
141            BackendStore::Sys(_) => crate::backend::sys::entities::table::Table::copy(
142                store,
143                dst_table.as_sys(),
144                dst_index,
145                src_table.as_sys(),
146                src_index,
147                len,
148            ),
149            #[cfg(feature = "wamr")]
150            BackendStore::Wamr(_) => crate::backend::wamr::entities::table::Table::copy(
151                store,
152                dst_table.as_wamr(),
153                dst_index,
154                src_table.as_wamr(),
155                src_index,
156                len,
157            ),
158            #[cfg(feature = "wasmi")]
159            BackendStore::Wasmi(_) => crate::backend::wasmi::entities::table::Table::copy(
160                store,
161                dst_table.as_wasmi(),
162                dst_index,
163                src_table.as_wasmi(),
164                src_index,
165                len,
166            ),
167
168            #[cfg(feature = "v8")]
169            BackendStore::V8(_) => crate::backend::v8::entities::table::Table::copy(
170                store,
171                dst_table.as_v8(),
172                dst_index,
173                src_table.as_v8(),
174                src_index,
175                len,
176            ),
177            #[cfg(feature = "js")]
178            BackendStore::Js(_) => crate::backend::js::entities::table::Table::copy(
179                store,
180                dst_table.as_js(),
181                dst_index,
182                src_table.as_js(),
183                src_index,
184                len,
185            ),
186            #[cfg(feature = "jsc")]
187            BackendStore::Jsc(_) => crate::backend::jsc::entities::table::Table::copy(
188                store,
189                dst_table.as_jsc(),
190                dst_index,
191                src_table.as_jsc(),
192                src_index,
193                len,
194            ),
195        }
196    }
197
198    #[inline]
199    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, ext: VMExternTable) -> Self {
200        match &store.as_store_mut().inner.store {
201            #[cfg(feature = "sys")]
202            BackendStore::Sys(_) => Self::Sys(
203                crate::backend::sys::entities::table::Table::from_vm_extern(store, ext),
204            ),
205            #[cfg(feature = "wamr")]
206            BackendStore::Wamr(_) => {
207                Self::Wamr(crate::backend::wamr::entities::table::Table::from_vm_extern(store, ext))
208            }
209            #[cfg(feature = "wasmi")]
210            BackendStore::Wasmi(_) => Self::Wasmi(
211                crate::backend::wasmi::entities::table::Table::from_vm_extern(store, ext),
212            ),
213            #[cfg(feature = "v8")]
214            BackendStore::V8(_) => Self::V8(
215                crate::backend::v8::entities::table::Table::from_vm_extern(store, ext),
216            ),
217            #[cfg(feature = "js")]
218            BackendStore::Js(_) => Self::Js(
219                crate::backend::js::entities::table::Table::from_vm_extern(store, ext),
220            ),
221            #[cfg(feature = "jsc")]
222            BackendStore::Jsc(_) => Self::Jsc(
223                crate::backend::jsc::entities::table::Table::from_vm_extern(store, ext),
224            ),
225        }
226    }
227
228    /// Checks whether this `Table` can be used with the given context.
229    #[inline]
230    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
231        match_rt!(on self => s {
232            s.is_from_store(store)
233        })
234    }
235
236    #[inline]
237    pub(crate) fn to_vm_extern(&self) -> VMExtern {
238        match_rt!(on self => s {
239            s.to_vm_extern()
240        })
241    }
242}
243
244#[cfg(test)]
245mod test {
246    /// Check the example from <https://github.com/wasmerio/wasmer/issues/3197>.
247    #[test]
248    #[cfg_attr(
249        feature = "wamr",
250        ignore = "wamr does not support direct calls to grow table"
251    )]
252    #[cfg_attr(feature = "wasmi", ignore = "wasmi does not support funcrefs")]
253    #[cfg_attr(
254        feature = "v8",
255        ignore = "growing tables in v8 is not currently supported"
256    )]
257    fn table_grow_issue_3197() {
258        use crate::{Instance, Module, Store, Table, TableType, Type, Value, imports};
259
260        const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#;
261
262        // Tests that the table type of `table` is compatible with the export in the WAT
263        // This tests that `wasmer_types::types::is_table_compatible` works as expected.
264        let mut store = Store::default();
265        let module = Module::new(&store, WAT).unwrap();
266        let ty = TableType::new(Type::FuncRef, 0, None);
267        let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap();
268        table.grow(&mut store, 100, Value::FuncRef(None)).unwrap();
269        assert_eq!(table.ty(&store).minimum, 0);
270        let imports = imports! {"env" => {"table" => table}};
271        let _instance = Instance::new(&mut store, &module, &imports).unwrap();
272    }
273}