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