wasmer/backend/sys/entities/
table.rs1use 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))]
14pub 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 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 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 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 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 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 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 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}