wasmer/entities/table/
mod.rs

1use wasmer_types::TableType;
2
3pub(crate) mod inner;
4pub(crate) use inner::*;
5
6use crate::{
7    AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, Value,
8    error::RuntimeError,
9    store::BackendStore,
10    vm::{VMExtern, VMExternTable},
11};
12
13/// A WebAssembly `table` instance.
14///
15/// The `Table` struct is an array-like structure representing a WebAssembly Table,
16/// which stores function references.
17///
18/// A table created by the host or in WebAssembly code will be accessible and
19/// mutable from both host and WebAssembly.
20///
21/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
22#[derive(Debug, Clone, PartialEq, Eq, derive_more::From)]
23#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
24pub struct Table(pub(crate) BackendTable);
25
26impl Table {
27    /// Creates a new table with the provided [`TableType`] definition.
28    ///
29    /// All the elements in the table will be set to the `init` value.
30    ///
31    /// This function will construct the table using the store `BaseTunables`.
32    pub fn new(
33        store: &mut impl AsStoreMut,
34        ty: TableType,
35        init: Value,
36    ) -> Result<Self, RuntimeError> {
37        BackendTable::new(store, ty, init).map(Self)
38    }
39
40    /// Returns the [`TableType`] of the table.
41    pub fn ty(&self, store: &impl AsStoreRef) -> TableType {
42        self.0.ty(store)
43    }
44
45    /// Retrieves an element of the table at the provided `index`.
46    pub fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option<Value> {
47        self.0.get(store, index)
48    }
49
50    /// Sets an element `val` in the Table at the provided `index`.
51    pub fn set(
52        &self,
53        store: &mut impl AsStoreMut,
54        index: u32,
55        val: Value,
56    ) -> Result<(), RuntimeError> {
57        self.0.set(store, index, val)
58    }
59
60    /// Retrieves the size of the `Table` (in elements)
61    pub fn size(&self, store: &impl AsStoreRef) -> u32 {
62        self.0.size(store)
63    }
64
65    /// Grows the size of the `Table` by `delta`, initializating
66    /// the elements with the provided `init` value.
67    ///
68    /// It returns the previous size of the `Table` in case is able
69    /// to grow the Table successfully.
70    ///
71    /// # Errors
72    ///
73    /// Returns an error if the `delta` is out of bounds for the table.
74    pub fn grow(
75        &self,
76        store: &mut impl AsStoreMut,
77        delta: u32,
78        init: Value,
79    ) -> Result<u32, RuntimeError> {
80        self.0.grow(store, delta, init)
81    }
82
83    /// Copies the `len` elements of `src_table` starting at `src_index`
84    /// to the destination table `dst_table` at index `dst_index`.
85    ///
86    /// # Errors
87    ///
88    /// Returns an error if the range is out of bounds of either the source or
89    /// destination tables.
90    pub fn copy(
91        store: &mut impl AsStoreMut,
92        dst_table: &Self,
93        dst_index: u32,
94        src_table: &Self,
95        src_index: u32,
96        len: u32,
97    ) -> Result<(), RuntimeError> {
98        BackendTable::copy(store, &dst_table.0, dst_index, &src_table.0, src_index, len)
99    }
100
101    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, ext: VMExternTable) -> Self {
102        Self(BackendTable::from_vm_extern(store, ext))
103    }
104
105    /// Checks whether this `Table` can be used with the given context.
106    pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
107        self.0.is_from_store(store)
108    }
109
110    pub(crate) fn to_vm_extern(&self) -> VMExtern {
111        self.0.to_vm_extern()
112    }
113}
114
115impl<'a> Exportable<'a> for Table {
116    fn get_self_from_extern(ext: &'a Extern) -> Result<&'a Self, ExportError> {
117        match ext {
118            Extern::Table(table) => Ok(table),
119            _ => Err(ExportError::IncompatibleType),
120        }
121    }
122}
123
124#[cfg(test)]
125mod test {
126    /// Check the example from <https://github.com/wasmerio/wasmer/issues/3197>.
127    #[test]
128    #[cfg_attr(
129        feature = "wamr",
130        ignore = "wamr does not support direct calls to grow table"
131    )]
132    #[cfg_attr(feature = "wasmi", ignore = "wasmi does not support funcrefs")]
133    #[cfg_attr(
134        feature = "v8",
135        ignore = "growing tables in v8 is not currently supported"
136    )]
137    fn table_grow_issue_3197() {
138        use crate::{Instance, Module, Store, Table, TableType, Type, Value, imports};
139
140        const WAT: &str = r#"(module (table (import "env" "table") 100 funcref))"#;
141
142        // Tests that the table type of `table` is compatible with the export in the WAT
143        // This tests that `wasmer_types::types::is_table_compatible` works as expected.
144        let mut store = Store::default();
145        let module = Module::new(&store, WAT).unwrap();
146        let ty = TableType::new(Type::FuncRef, 0, None);
147        let table = Table::new(&mut store, ty, Value::FuncRef(None)).unwrap();
148        table.grow(&mut store, 100, Value::FuncRef(None)).unwrap();
149        assert_eq!(table.ty(&store).minimum, 0);
150        let imports = imports! {"env" => {"table" => table}};
151        let _instance = Instance::new(&mut store, &module, &imports).unwrap();
152    }
153}