1use crate::func_data_registry::VMFuncRef;
9use crate::trap::{Trap, TrapCode};
10use crate::vmcontext::VMTableDefinition;
11use crate::VMExternRef;
12use std::borrow::{Borrow, BorrowMut};
13use std::cell::UnsafeCell;
14use std::convert::TryFrom;
15use std::fmt;
16use std::ptr::NonNull;
17use std::sync::Mutex;
18use wasmer_types::{ExternRef, TableType, Type as ValType};
19
20#[derive(Debug, Clone, Hash, PartialEq, Eq, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
22pub enum TableStyle {
23 CallerChecksSignature,
25}
26
27pub trait Table: fmt::Debug + Send + Sync {
29 fn style(&self) -> &TableStyle;
31
32 fn ty(&self) -> &TableType;
34
35 fn size(&self) -> u32;
37
38 fn grow(&self, delta: u32, init_value: TableElement) -> Option<u32>;
43
44 fn get(&self, index: u32) -> Option<TableElement>;
48
49 fn set(&self, index: u32, reference: TableElement) -> Result<(), Trap>;
55
56 fn vmtable(&self) -> NonNull<VMTableDefinition>;
58
59 fn copy(
66 &self,
67 src_table: &dyn Table,
68 dst_index: u32,
69 src_index: u32,
70 len: u32,
71 ) -> Result<(), Trap> {
72 if src_index
75 .checked_add(len)
76 .map_or(true, |n| n > src_table.size())
77 {
78 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
79 }
80
81 if dst_index.checked_add(len).map_or(true, |m| m > self.size()) {
82 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
83 }
84
85 let srcs = src_index..src_index + len;
86 let dsts = dst_index..dst_index + len;
87
88 if dst_index <= src_index {
93 for (s, d) in (srcs).zip(dsts) {
94 self.set(d, src_table.get(s).unwrap())?;
95 }
96 } else {
97 for (s, d) in srcs.rev().zip(dsts.rev()) {
98 self.set(d, src_table.get(s).unwrap())?;
99 }
100 }
101
102 Ok(())
103 }
104}
105
106#[derive(Debug, Clone)]
108pub enum TableElement {
109 ExternRef(ExternRef),
113 FuncRef(VMFuncRef),
115}
116
117impl From<TableElement> for RawTableElement {
118 fn from(other: TableElement) -> Self {
119 match other {
120 TableElement::ExternRef(extern_ref) => Self {
121 extern_ref: extern_ref.into(),
122 },
123 TableElement::FuncRef(func_ref) => Self { func_ref },
124 }
125 }
126}
127
128#[repr(C)]
129#[derive(Clone, Copy)]
130pub union RawTableElement {
131 pub(crate) extern_ref: VMExternRef,
132 pub(crate) func_ref: VMFuncRef,
133}
134
135#[cfg(test)]
136#[test]
137fn table_element_size_test() {
138 use std::mem::size_of;
139 assert_eq!(size_of::<RawTableElement>(), size_of::<VMExternRef>());
140 assert_eq!(size_of::<RawTableElement>(), size_of::<VMFuncRef>());
141}
142
143impl fmt::Debug for RawTableElement {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 f.debug_struct("RawTableElement").finish()
146 }
147}
148
149impl Default for RawTableElement {
150 fn default() -> Self {
151 Self {
152 func_ref: VMFuncRef::null(),
153 }
154 }
155}
156
157impl Default for TableElement {
158 fn default() -> Self {
159 Self::FuncRef(VMFuncRef::null())
160 }
161}
162
163#[derive(Debug)]
165pub struct LinearTable {
166 vec: Mutex<Vec<RawTableElement>>,
168 maximum: Option<u32>,
169 table: TableType,
171 style: TableStyle,
173 vm_table_definition: VMTableDefinitionOwnership,
174}
175
176#[derive(Debug)]
179enum VMTableDefinitionOwnership {
180 VMOwned(NonNull<VMTableDefinition>),
183 HostOwned(Box<UnsafeCell<VMTableDefinition>>),
187}
188
189unsafe impl Send for LinearTable {}
191unsafe impl Sync for LinearTable {}
193
194impl LinearTable {
195 pub fn new(table: &TableType, style: &TableStyle) -> Result<Self, String> {
200 unsafe { Self::new_inner(table, style, None) }
201 }
202
203 pub unsafe fn from_definition(
211 table: &TableType,
212 style: &TableStyle,
213 vm_table_location: NonNull<VMTableDefinition>,
214 ) -> Result<Self, String> {
215 Self::new_inner(table, style, Some(vm_table_location))
216 }
217
218 unsafe fn new_inner(
220 table: &TableType,
221 style: &TableStyle,
222 vm_table_location: Option<NonNull<VMTableDefinition>>,
223 ) -> Result<Self, String> {
224 match table.ty {
225 ValType::FuncRef | ValType::ExternRef => (),
226 ty => {
227 return Err(format!(
228 "tables of types other than funcref or externref ({})",
229 ty
230 ))
231 }
232 };
233 if let Some(max) = table.maximum {
234 if max < table.minimum {
235 return Err(format!(
236 "Table minimum ({}) is larger than maximum ({})!",
237 table.minimum, max
238 ));
239 }
240 }
241 let table_minimum = usize::try_from(table.minimum)
242 .map_err(|_| "Table minimum is bigger than usize".to_string())?;
243 let mut vec = vec![RawTableElement::default(); table_minimum];
244 let base = vec.as_mut_ptr();
245 match style {
246 TableStyle::CallerChecksSignature => Ok(Self {
247 vec: Mutex::new(vec),
248 maximum: table.maximum,
249 table: *table,
250 style: style.clone(),
251 vm_table_definition: if let Some(table_loc) = vm_table_location {
252 {
253 let mut ptr = table_loc;
254 let td = ptr.as_mut();
255 td.base = base as _;
256 td.current_elements = table_minimum as _;
257 }
258 VMTableDefinitionOwnership::VMOwned(table_loc)
259 } else {
260 VMTableDefinitionOwnership::HostOwned(Box::new(UnsafeCell::new(
261 VMTableDefinition {
262 base: base as _,
263 current_elements: table_minimum as _,
264 },
265 )))
266 },
267 }),
268 }
269 }
270
271 unsafe fn get_vm_table_definition(&self) -> NonNull<VMTableDefinition> {
277 match &self.vm_table_definition {
278 VMTableDefinitionOwnership::VMOwned(ptr) => *ptr,
279 VMTableDefinitionOwnership::HostOwned(boxed_ptr) => {
280 NonNull::new_unchecked(boxed_ptr.get())
281 }
282 }
283 }
284}
285
286impl Table for LinearTable {
287 fn ty(&self) -> &TableType {
289 &self.table
290 }
291
292 fn style(&self) -> &TableStyle {
294 &self.style
295 }
296
297 fn size(&self) -> u32 {
299 unsafe {
301 let td_ptr = self.get_vm_table_definition();
302 let td = td_ptr.as_ref();
303 td.current_elements
304 }
305 }
306
307 fn grow(&self, delta: u32, init_value: TableElement) -> Option<u32> {
312 let mut vec_guard = self.vec.lock().unwrap();
313 let vec = vec_guard.borrow_mut();
314 let size = self.size();
315 let new_len = size.checked_add(delta)?;
316 if self.maximum.map_or(false, |max| new_len > max) {
317 return None;
318 }
319 if new_len == size {
320 debug_assert_eq!(delta, 0);
321 return Some(size);
322 }
323
324 let element = match init_value {
326 TableElement::ExternRef(extern_ref) => {
327 let extern_ref: VMExternRef = extern_ref.into();
328 if let Some(val) = (new_len as usize).checked_sub(size as usize + 1) {
331 extern_ref.ref_inc_by(val);
332 }
333 RawTableElement { extern_ref }
334 }
335 TableElement::FuncRef(func_ref) => RawTableElement { func_ref },
336 };
337
338 vec.resize(usize::try_from(new_len).unwrap(), element);
339
340 unsafe {
342 let mut td_ptr = self.get_vm_table_definition();
343 let td = td_ptr.as_mut();
344 td.current_elements = new_len;
345 td.base = vec.as_mut_ptr() as _;
346 }
347 Some(size)
348 }
349
350 fn get(&self, index: u32) -> Option<TableElement> {
354 let vec_guard = self.vec.lock().unwrap();
355 let raw_data = vec_guard.borrow().get(index as usize).cloned()?;
356 Some(match self.table.ty {
357 ValType::ExternRef => {
358 TableElement::ExternRef(unsafe { raw_data.extern_ref.ref_clone() }.into())
359 }
360 ValType::FuncRef => TableElement::FuncRef(unsafe { raw_data.func_ref }),
361 _ => todo!("getting invalid type from table, handle this error"),
362 })
363 }
364
365 fn set(&self, index: u32, reference: TableElement) -> Result<(), Trap> {
371 let mut vec_guard = self.vec.lock().unwrap();
372 let vec = vec_guard.borrow_mut();
373 match vec.get_mut(index as usize) {
374 Some(slot) => {
375 match (self.table.ty, reference) {
376 (ValType::ExternRef, TableElement::ExternRef(extern_ref)) => {
377 let extern_ref = extern_ref.into();
378 unsafe {
379 let elem = &mut *slot;
380 elem.extern_ref.ref_drop();
381 elem.extern_ref = extern_ref
382 }
383 }
384 (ValType::FuncRef, r @ TableElement::FuncRef(_)) => {
385 let element_data = r.into();
386 *slot = element_data;
387 }
388 (ty, v) => {
391 panic!(
392 "Attempted to set a table of type {} with the value {:?}",
393 ty, v
394 )
395 }
396 };
397
398 Ok(())
399 }
400 None => Err(Trap::lib(TrapCode::TableAccessOutOfBounds)),
401 }
402 }
403
404 fn vmtable(&self) -> NonNull<VMTableDefinition> {
406 let _vec_guard = self.vec.lock().unwrap();
407 unsafe { self.get_vm_table_definition() }
408 }
409}