wasmer/backend/sys/entities/
table.rs

1//! Data types, functions and traits for `sys` runtime's `Table` implementation.
2use crate::{
3    BackendTable, ExternRef, Function, Value,
4    backend::sys::entities::engine::NativeEngineExt,
5    entities::store::{AsStoreMut, AsStoreRef},
6    error::RuntimeError,
7    vm::{VMExtern, VMExternTable},
8};
9use wasmer_types::TableType;
10use wasmer_vm::{StoreHandle, TableElement, Trap, VMTable};
11
12#[derive(Debug, Clone)]
13#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
14/// A WebAssembly `table` in the `sys` runtime.
15pub struct Table {
16    handle: StoreHandle<VMTable>,
17}
18
19fn set_table_item(
20    table: &mut VMTable,
21    item_index: u32,
22    item: TableElement,
23) -> Result<(), RuntimeError> {
24    table
25        .set(item_index, item)
26        .map_err(Into::<RuntimeError>::into)
27}
28
29fn value_to_table_element(
30    store: &mut impl AsStoreMut,
31    val: Value,
32) -> Result<wasmer_vm::TableElement, RuntimeError> {
33    if !val.is_from_store(store) {
34        return Err(RuntimeError::new("cannot pass Value across contexts"));
35    }
36    Ok(match val {
37        Value::ExternRef(extern_ref) => {
38            wasmer_vm::TableElement::ExternRef(extern_ref.map(|e| e.vm_externref().unwrap_sys()))
39        }
40        Value::FuncRef(func_ref) => {
41            wasmer_vm::TableElement::FuncRef(func_ref.map(|f| f.vm_funcref(store).unwrap_sys()))
42        }
43        _ => return Err(RuntimeError::new("val is not reference")),
44    })
45}
46
47fn value_from_table_element(store: &mut impl AsStoreMut, item: wasmer_vm::TableElement) -> Value {
48    match item {
49        wasmer_vm::TableElement::FuncRef(funcref) => Value::FuncRef(
50            funcref
51                .map(|f| unsafe { Function::from_vm_funcref(store, crate::vm::VMFuncRef::Sys(f)) }),
52        ),
53        wasmer_vm::TableElement::ExternRef(extern_ref) => {
54            Value::ExternRef(extern_ref.map(|e| unsafe {
55                ExternRef::from_vm_externref(store, crate::vm::VMExternRef::Sys(e))
56            }))
57        }
58    }
59}
60
61impl Table {
62    pub(crate) fn new(
63        mut store: &mut impl AsStoreMut,
64        ty: TableType,
65        init: Value,
66    ) -> Result<Self, RuntimeError> {
67        let item = value_to_table_element(&mut store, init)?;
68        let mut store = store.as_store_mut();
69        let tunables = store.engine().tunables();
70        let style = tunables.table_style(&ty);
71        let mut table = tunables
72            .create_host_table(&ty, &style)
73            .map_err(RuntimeError::new)?;
74
75        let num_elements = table.size();
76        for i in 0..num_elements {
77            set_table_item(&mut table, i, item.clone())?;
78        }
79
80        Ok(Self {
81            handle: StoreHandle::new(store.objects_mut().as_sys_mut(), table),
82        })
83    }
84
85    pub(crate) fn ty(&self, store: &impl AsStoreRef) -> TableType {
86        *self
87            .handle
88            .get(store.as_store_ref().objects().as_sys())
89            .ty()
90    }
91
92    pub(crate) fn get(&self, store: &mut impl AsStoreMut, index: u32) -> Option<Value> {
93        let item = self
94            .handle
95            .get(store.as_store_ref().objects().as_sys())
96            .get(index)?;
97        Some(value_from_table_element(store, item))
98    }
99
100    pub(crate) fn set(
101        &self,
102        store: &mut impl AsStoreMut,
103        index: u32,
104        val: Value,
105    ) -> Result<(), RuntimeError> {
106        let item = value_to_table_element(store, val)?;
107        set_table_item(
108            self.handle.get_mut(store.objects_mut().as_sys_mut()),
109            index,
110            item,
111        )
112    }
113
114    pub(crate) fn size(&self, store: &impl AsStoreRef) -> u32 {
115        self.handle
116            .get(store.as_store_ref().objects().as_sys())
117            .size()
118    }
119
120    pub(crate) fn grow(
121        &self,
122        store: &mut impl AsStoreMut,
123        delta: u32,
124        init: Value,
125    ) -> Result<u32, RuntimeError> {
126        let item = value_to_table_element(store, init)?;
127        let obj_mut = store.objects_mut().as_sys_mut();
128
129        self.handle
130            .get_mut(obj_mut)
131            .grow(delta, item)
132            .ok_or_else(|| RuntimeError::new(format!("failed to grow table by `{delta}`")))
133    }
134
135    pub(crate) fn copy(
136        store: &mut impl AsStoreMut,
137        dst_table: &Self,
138        dst_index: u32,
139        src_table: &Self,
140        src_index: u32,
141        len: u32,
142    ) -> Result<(), RuntimeError> {
143        if dst_table.handle.store_id() != src_table.handle.store_id() {
144            return Err(RuntimeError::new(
145                "cross-`Store` table copies are not supported",
146            ));
147        }
148        if dst_table.handle.internal_handle() == src_table.handle.internal_handle() {
149            let table = dst_table.handle.get_mut(store.objects_mut().as_sys_mut());
150            table.copy_within(dst_index, src_index, len)
151        } else {
152            let (src_table, dst_table) = store.objects_mut().as_sys_mut().get_2_mut(
153                src_table.handle.internal_handle(),
154                dst_table.handle.internal_handle(),
155            );
156            VMTable::copy(dst_table, src_table, dst_index, src_index, len)
157        }
158        .map_err(Into::<RuntimeError>::into)?;
159        Ok(())
160    }
161
162    pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternTable) -> Self {
163        Self {
164            handle: unsafe {
165                StoreHandle::from_internal(
166                    store.as_store_ref().objects().id(),
167                    vm_extern.unwrap_sys(),
168                )
169            },
170        }
171    }
172
173    /// Checks whether this `Table` can be used with the given context.
174    pub(crate) fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
175        self.handle.store_id() == store.as_store_ref().objects().id()
176    }
177
178    pub(crate) fn to_vm_extern(&self) -> VMExtern {
179        VMExtern::Sys(wasmer_vm::VMExtern::Table(self.handle.internal_handle()))
180    }
181}
182
183impl std::cmp::PartialEq for Table {
184    fn eq(&self, other: &Self) -> bool {
185        self.handle == other.handle
186    }
187}
188
189impl std::cmp::Eq for Table {}
190
191impl crate::Table {
192    /// Consume [`self`] into [`crate::backend::sys::table::Table`].
193    pub fn into_sys(self) -> crate::backend::sys::table::Table {
194        match self.0 {
195            BackendTable::Sys(s) => s,
196            _ => panic!("Not a `sys` table!"),
197        }
198    }
199
200    /// Convert a reference to [`self`] into a reference [`crate::backend::sys::table::Table`].
201    pub fn as_sys(&self) -> &crate::backend::sys::table::Table {
202        match &self.0 {
203            BackendTable::Sys(s) => s,
204            _ => panic!("Not a `sys` table!"),
205        }
206    }
207
208    /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::table::Table`].
209    pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::table::Table {
210        match &mut self.0 {
211            BackendTable::Sys(s) => s,
212            _ => panic!("Not a `sys` table!"),
213        }
214    }
215}
216
217impl crate::BackendTable {
218    /// Consume [`self`] into [`crate::backend::sys::table::Table`].
219    pub fn into_sys(self) -> crate::backend::sys::table::Table {
220        match self {
221            Self::Sys(s) => s,
222            _ => panic!("Not a `sys` table!"),
223        }
224    }
225
226    /// Convert a reference to [`self`] into a reference [`crate::backend::sys::table::Table`].
227    pub fn as_sys(&self) -> &crate::backend::sys::table::Table {
228        match self {
229            Self::Sys(s) => s,
230            _ => panic!("Not a `sys` table!"),
231        }
232    }
233
234    /// Convert a mutable reference to [`self`] into a mutable reference [`crate::backend::sys::table::Table`].
235    pub fn as_sys_mut(&mut self) -> &mut crate::backend::sys::table::Table {
236        match self {
237            Self::Sys(s) => s,
238            _ => panic!("Not a `sys` table!"),
239        }
240    }
241}