wasmer_runtime_core_fl/table/
mod.rs

1//! The runtime table module contains data structures and functions used to create and update wasm
2//! tables.
3use crate::{
4    error::CreationError,
5    export::Export,
6    import::IsExport,
7    types::{ElementType, TableDescriptor},
8    vm,
9};
10use std::{
11    convert::TryFrom,
12    fmt, ptr,
13    sync::{Arc, Mutex},
14};
15
16mod anyfunc;
17
18pub use self::anyfunc::Anyfunc;
19pub(crate) use self::anyfunc::AnyfuncTable;
20use crate::error::GrowError;
21
22/// Error type indicating why a table access failed.
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum TableAccessError {
25    /// The index wasn't valid, so no element could be accessed.
26    IndexError,
27
28    // we'll need this error when we support tables holding more types
29    #[allow(dead_code)]
30    /// The type of the table was incorrect, so no element could be accessed.
31    TypeError,
32}
33
34/// Trait indicates types that can be stored in tables
35pub trait StorableInTable: Sized {
36    /// Attempt to lookup self in the given table.
37    fn unwrap_self(storage: &TableStorage, index: u32) -> Result<Self, TableAccessError>;
38
39    /// Wrap value to be stored in a table.
40    fn wrap_self(self, storage: &mut TableStorage, index: u32) -> Result<(), TableAccessError>;
41}
42
43impl<'a, F: Into<Anyfunc<'a>> + TryFrom<Anyfunc<'a>>> StorableInTable for F {
44    fn unwrap_self(storage: &TableStorage, index: u32) -> Result<Self, TableAccessError> {
45        match storage {
46            TableStorage::Anyfunc(ref anyfunc_table) => {
47                let anyfunc = anyfunc_table
48                    .get(index)
49                    .ok_or(TableAccessError::IndexError)?;
50                // Should this be a different error value because it's not a table type error?
51                F::try_from(anyfunc).map_err(|_| TableAccessError::TypeError)
52            }
53        }
54    }
55
56    fn wrap_self(self, storage: &mut TableStorage, index: u32) -> Result<(), TableAccessError> {
57        let anyfunc: Anyfunc = self.into();
58
59        match storage {
60            TableStorage::Anyfunc(ref mut anyfunc_table) => anyfunc_table
61                .set(index, anyfunc)
62                .map_err(|_| TableAccessError::IndexError),
63        }
64    }
65}
66
67/// Kind of table element.
68// note to implementors: all types in `Element` should implement `StorableInTable`.
69pub enum Element<'a> {
70    /// Anyfunc.
71    Anyfunc(Anyfunc<'a>),
72}
73
74// delegation implementation for `Element`
75impl<'a> StorableInTable for Element<'a> {
76    fn unwrap_self(storage: &TableStorage, index: u32) -> Result<Self, TableAccessError> {
77        match storage {
78            TableStorage::Anyfunc(ref anyfunc_table) => anyfunc_table
79                .get(index)
80                .map(Element::Anyfunc)
81                .ok_or(TableAccessError::IndexError),
82        }
83    }
84
85    fn wrap_self(self, storage: &mut TableStorage, index: u32) -> Result<(), TableAccessError> {
86        match self {
87            Element::Anyfunc(af) => af.wrap_self(storage, index),
88        }
89    }
90}
91
92/// Kind of table storage.
93// #[derive(Debug)]
94pub enum TableStorage {
95    /// This is intended to be a caller-checked Anyfunc.
96    Anyfunc(Box<AnyfuncTable>),
97}
98
99/// Container with a descriptor and a reference to a table storage.
100pub struct Table {
101    desc: TableDescriptor,
102    storage: Arc<Mutex<(TableStorage, vm::LocalTable)>>,
103}
104
105impl Table {
106    /// Create a new `Table` from a [`TableDescriptor`]
107    ///
108    /// [`TableDescriptor`]: struct.TableDescriptor.html
109    ///
110    /// Usage:
111    ///
112    /// ```
113    /// # use wasmer_runtime_core::types::{TableDescriptor, ElementType};
114    /// # use wasmer_runtime_core::table::Table;
115    /// # use wasmer_runtime_core::error::Result;
116    /// # fn create_table() -> Result<()> {
117    /// let descriptor = TableDescriptor {
118    ///     element: ElementType::Anyfunc,
119    ///     minimum: 10,
120    ///     maximum: None,
121    /// };
122    ///
123    /// let table = Table::new(descriptor)?;
124    /// # Ok(())
125    /// # }
126    /// ```
127    pub fn new(desc: TableDescriptor) -> Result<Self, CreationError> {
128        if let Some(max) = desc.maximum {
129            if max < desc.minimum {
130                return Err(CreationError::InvalidDescriptor(
131                    "Max table size is less than the minimum size".to_string(),
132                ));
133            }
134        }
135
136        let mut local = vm::LocalTable {
137            base: ptr::null_mut(),
138            count: 0,
139            table: ptr::null_mut(),
140        };
141
142        let storage = match desc.element {
143            ElementType::Anyfunc => TableStorage::Anyfunc(AnyfuncTable::new(desc, &mut local)?),
144        };
145
146        Ok(Self {
147            desc,
148            storage: Arc::new(Mutex::new((storage, local))),
149        })
150    }
151
152    /// Get the `TableDescriptor` used to create this `Table`.
153    pub fn descriptor(&self) -> TableDescriptor {
154        self.desc
155    }
156
157    // Made `pub(crate)` because this API is incomplete, see `anyfunc::AnyfuncTable::get`
158    // for more information.
159    #[allow(dead_code)]
160    /// Get the raw table value at index. A return value of `None` means either that
161    /// the index or the type wasn't valid.
162    pub(crate) fn get<T: StorableInTable>(&self, index: u32) -> Result<T, TableAccessError> {
163        let guard = self.storage.lock().unwrap();
164        let (storage, _) = &*guard;
165        T::unwrap_self(storage, index)
166    }
167
168    /// Set the element at index.
169    pub fn set<T: StorableInTable>(&self, index: u32, element: T) -> Result<(), TableAccessError> {
170        let mut guard = self.storage.lock().unwrap();
171        let (storage, _) = &mut *guard;
172        T::wrap_self(element, storage, index)
173    }
174
175    pub(crate) fn anyfunc_direct_access_mut<F, R>(&self, f: F) -> R
176    where
177        F: FnOnce(&mut [vm::Anyfunc]) -> R,
178    {
179        let mut storage = self.storage.lock().unwrap();
180        match &mut *storage {
181            (TableStorage::Anyfunc(ref mut anyfunc_table), _) => f(anyfunc_table.internal_buffer()),
182        }
183    }
184
185    /// The current size of this table.
186    pub fn size(&self) -> u32 {
187        let storage = self.storage.lock().unwrap();
188        match &*storage {
189            (TableStorage::Anyfunc(ref anyfunc_table), _) => anyfunc_table.current_size(),
190        }
191    }
192
193    /// Grow this table by `delta`.
194    pub fn grow(&self, delta: u32) -> Result<u32, GrowError> {
195        if delta == 0 {
196            return Ok(self.size());
197        }
198
199        let mut storage = self.storage.lock().unwrap();
200        match &mut *storage {
201            (TableStorage::Anyfunc(ref mut anyfunc_table), ref mut local) => anyfunc_table
202                .grow(delta, local)
203                .ok_or(GrowError::TableGrowError),
204        }
205    }
206
207    /// Get a mutable pointer to underlying table storage.
208    pub fn vm_local_table(&mut self) -> *mut vm::LocalTable {
209        let mut storage = self.storage.lock().unwrap();
210        &mut storage.1
211    }
212}
213
214impl IsExport for Table {
215    fn to_export(&self) -> Export {
216        Export::Table(self.clone())
217    }
218}
219
220impl Clone for Table {
221    fn clone(&self) -> Self {
222        Self {
223            desc: self.desc,
224            storage: Arc::clone(&self.storage),
225        }
226    }
227}
228
229impl fmt::Debug for Table {
230    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
231        f.debug_struct("Table")
232            .field("desc", &self.desc)
233            .field("size", &self.size())
234            .finish()
235    }
236}
237
238#[cfg(test)]
239mod table_tests {
240
241    use super::{ElementType, Table, TableDescriptor};
242
243    #[test]
244    fn test_initial_table_size() {
245        let table = Table::new(TableDescriptor {
246            element: ElementType::Anyfunc,
247            minimum: 10,
248            maximum: Some(20),
249        })
250        .unwrap();
251        assert_eq!(table.size(), 10);
252    }
253}