1use crate::store::MaybeInstanceOwned;
9use crate::vmcontext::VMTableDefinition;
10use crate::Trap;
11use crate::VMExternRef;
12use crate::VMFuncRef;
13use std::cell::UnsafeCell;
14use std::convert::TryFrom;
15use std::fmt;
16use std::ptr::NonNull;
17use wasmer_types::TableStyle;
18use wasmer_types::{TableType, TrapCode, Type as ValType};
19
20#[derive(Debug, Clone)]
22pub enum TableElement {
23 ExternRef(Option<VMExternRef>),
25 FuncRef(Option<VMFuncRef>),
27}
28
29impl From<TableElement> for RawTableElement {
30 fn from(other: TableElement) -> Self {
31 match other {
32 TableElement::ExternRef(extern_ref) => Self { extern_ref },
33 TableElement::FuncRef(func_ref) => Self { func_ref },
34 }
35 }
36}
37
38#[repr(C)]
39#[derive(Clone, Copy)]
40pub union RawTableElement {
41 pub(crate) extern_ref: Option<VMExternRef>,
42 pub(crate) func_ref: Option<VMFuncRef>,
43}
44
45#[cfg(test)]
46#[test]
47fn table_element_size_test() {
48 use std::mem::size_of;
49 assert_eq!(size_of::<RawTableElement>(), size_of::<VMExternRef>());
50 assert_eq!(size_of::<RawTableElement>(), size_of::<VMFuncRef>());
51}
52
53impl fmt::Debug for RawTableElement {
54 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
55 f.debug_struct("RawTableElement").finish()
56 }
57}
58
59impl Default for RawTableElement {
60 fn default() -> Self {
61 Self { func_ref: None }
62 }
63}
64
65impl Default for TableElement {
66 fn default() -> Self {
67 Self::FuncRef(None)
68 }
69}
70
71#[derive(Debug)]
73pub struct VMTable {
74 vec: Vec<RawTableElement>,
75 maximum: Option<u32>,
76 table: TableType,
78 style: TableStyle,
80 vm_table_definition: MaybeInstanceOwned<VMTableDefinition>,
81}
82
83impl VMTable {
84 pub fn new(table: &TableType, style: &TableStyle) -> Result<Self, String> {
89 unsafe { Self::new_inner(table, style, None) }
90 }
91
92 pub fn get_runtime_size(&self) -> u32 {
94 self.vec.len() as u32
95 }
96
97 pub unsafe fn from_definition(
105 table: &TableType,
106 style: &TableStyle,
107 vm_table_location: NonNull<VMTableDefinition>,
108 ) -> Result<Self, String> {
109 Self::new_inner(table, style, Some(vm_table_location))
110 }
111
112 unsafe fn new_inner(
114 table: &TableType,
115 style: &TableStyle,
116 vm_table_location: Option<NonNull<VMTableDefinition>>,
117 ) -> Result<Self, String> {
118 match table.ty {
119 ValType::FuncRef | ValType::ExternRef => (),
120 ty => {
121 return Err(format!(
122 "tables of types other than funcref or externref ({ty})",
123 ))
124 }
125 };
126 if let Some(max) = table.maximum {
127 if max < table.minimum {
128 return Err(format!(
129 "Table minimum ({}) is larger than maximum ({})!",
130 table.minimum, max
131 ));
132 }
133 }
134 let table_minimum = usize::try_from(table.minimum)
135 .map_err(|_| "Table minimum is bigger than usize".to_string())?;
136 let mut vec = vec![RawTableElement::default(); table_minimum];
137 let base = vec.as_mut_ptr();
138 match style {
139 TableStyle::CallerChecksSignature => Ok(Self {
140 vec,
141 maximum: table.maximum,
142 table: *table,
143 style: style.clone(),
144 vm_table_definition: if let Some(table_loc) = vm_table_location {
145 {
146 let mut ptr = table_loc;
147 let td = ptr.as_mut();
148 td.base = base as _;
149 td.current_elements = table_minimum as _;
150 }
151 MaybeInstanceOwned::Instance(table_loc)
152 } else {
153 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMTableDefinition {
154 base: base as _,
155 current_elements: table_minimum as _,
156 })))
157 },
158 }),
159 }
160 }
161
162 fn get_vm_table_definition(&self) -> NonNull<VMTableDefinition> {
164 self.vm_table_definition.as_ptr()
165 }
166
167 pub fn ty(&self) -> &TableType {
169 &self.table
170 }
171
172 pub fn style(&self) -> &TableStyle {
174 &self.style
175 }
176
177 pub fn size(&self) -> u32 {
179 unsafe {
181 let td_ptr = self.get_vm_table_definition();
182 let td = td_ptr.as_ref();
183 td.current_elements
184 }
185 }
186
187 pub fn grow(&mut self, delta: u32, init_value: TableElement) -> Option<u32> {
192 let size = self.size();
193 let new_len = size.checked_add(delta)?;
194 if self.maximum.map_or(false, |max| new_len > max) {
195 return None;
196 }
197 if new_len == size {
198 debug_assert_eq!(delta, 0);
199 return Some(size);
200 }
201
202 self.vec
203 .resize(usize::try_from(new_len).unwrap(), init_value.into());
204
205 unsafe {
207 let mut td_ptr = self.get_vm_table_definition();
208 let td = td_ptr.as_mut();
209 td.current_elements = new_len;
210 td.base = self.vec.as_mut_ptr() as _;
211 }
212 Some(size)
213 }
214
215 pub fn get(&self, index: u32) -> Option<TableElement> {
219 let raw_data = self.vec.get(index as usize).cloned()?;
220 Some(match self.table.ty {
221 ValType::ExternRef => TableElement::ExternRef(unsafe { raw_data.extern_ref }),
222 ValType::FuncRef => TableElement::FuncRef(unsafe { raw_data.func_ref }),
223 _ => todo!("getting invalid type from table, handle this error"),
224 })
225 }
226
227 pub fn set(&mut self, index: u32, reference: TableElement) -> Result<(), Trap> {
233 match self.vec.get_mut(index as usize) {
234 Some(slot) => {
235 match (self.table.ty, reference) {
236 (ValType::ExternRef, r @ TableElement::ExternRef(_)) => {
237 *slot = r.into();
238 }
239 (ValType::FuncRef, r @ TableElement::FuncRef(_)) => {
240 *slot = r.into();
241 }
242 (ty, v) => {
245 panic!("Attempted to set a table of type {ty} with the value {v:?}")
246 }
247 };
248
249 Ok(())
250 }
251 None => Err(Trap::lib(TrapCode::TableAccessOutOfBounds)),
252 }
253 }
254
255 pub fn vmtable(&self) -> NonNull<VMTableDefinition> {
257 self.get_vm_table_definition()
258 }
259
260 pub fn copy(
267 &mut self,
268 src_table: &Self,
269 dst_index: u32,
270 src_index: u32,
271 len: u32,
272 ) -> Result<(), Trap> {
273 if src_index
276 .checked_add(len)
277 .map_or(true, |n| n > src_table.size())
278 {
279 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
280 }
281
282 if dst_index.checked_add(len).map_or(true, |m| m > self.size()) {
283 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
284 }
285
286 let srcs = src_index..src_index + len;
287 let dsts = dst_index..dst_index + len;
288
289 if dst_index <= src_index {
294 for (s, d) in (srcs).zip(dsts) {
295 self.set(d, src_table.get(s).unwrap())?;
296 }
297 } else {
298 for (s, d) in srcs.rev().zip(dsts.rev()) {
299 self.set(d, src_table.get(s).unwrap())?;
300 }
301 }
302
303 Ok(())
304 }
305
306 pub fn copy_on_write(&self) -> Result<Self, String> {
308 let mut ret = Self::new(&self.table, &self.style)?;
309 ret.copy(self, 0, 0, self.size())
310 .map_err(|trap| format!("failed to copy the table - {trap:?}"))?;
311 Ok(ret)
312 }
313
314 pub fn copy_within(&mut self, dst_index: u32, src_index: u32, len: u32) -> Result<(), Trap> {
321 if src_index.checked_add(len).map_or(true, |n| n > self.size()) {
324 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
325 }
326
327 if dst_index.checked_add(len).map_or(true, |m| m > self.size()) {
328 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
329 }
330
331 let srcs = src_index..src_index + len;
332 let dsts = dst_index..dst_index + len;
333
334 if dst_index <= src_index {
339 for (s, d) in (srcs).zip(dsts) {
340 self.set(d, self.get(s).unwrap())?;
341 }
342 } else {
343 for (s, d) in srcs.rev().zip(dsts.rev()) {
344 self.set(d, self.get(s).unwrap())?;
345 }
346 }
347
348 Ok(())
349 }
350}