1use crate::Trap;
9use crate::VMExternRef;
10use crate::VMFuncRef;
11use crate::store::MaybeInstanceOwned;
12use crate::vmcontext::VMTableDefinition;
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 unsafe { 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 unsafe {
119 match table.ty {
120 ValType::FuncRef | ValType::ExternRef => (),
121 ty => {
122 return Err(format!(
123 "tables of types other than funcref or externref ({ty})",
124 ));
125 }
126 };
127 if let Some(max) = table.maximum {
128 if max < table.minimum {
129 return Err(format!(
130 "Table minimum ({}) is larger than maximum ({})!",
131 table.minimum, max
132 ));
133 }
134 }
135 let table_minimum = usize::try_from(table.minimum)
136 .map_err(|_| "Table minimum is bigger than usize".to_string())?;
137 let mut vec = vec![RawTableElement::default(); table_minimum];
138 let base = vec.as_mut_ptr();
139 match style {
140 TableStyle::CallerChecksSignature => Ok(Self {
141 vec,
142 maximum: table.maximum,
143 table: *table,
144 style: style.clone(),
145 vm_table_definition: if let Some(table_loc) = vm_table_location {
146 {
147 let mut ptr = table_loc;
148 let td = ptr.as_mut();
149 td.base = base as _;
150 td.current_elements = table_minimum as _;
151 }
152 MaybeInstanceOwned::Instance(table_loc)
153 } else {
154 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMTableDefinition {
155 base: base as _,
156 current_elements: table_minimum as _,
157 })))
158 },
159 }),
160 }
161 }
162 }
163
164 fn get_vm_table_definition(&self) -> NonNull<VMTableDefinition> {
166 self.vm_table_definition.as_ptr()
167 }
168
169 pub fn ty(&self) -> &TableType {
171 &self.table
172 }
173
174 pub fn style(&self) -> &TableStyle {
176 &self.style
177 }
178
179 pub fn size(&self) -> u32 {
181 unsafe {
183 let td_ptr = self.get_vm_table_definition();
184 let td = td_ptr.as_ref();
185 td.current_elements
186 }
187 }
188
189 pub fn grow(&mut self, delta: u32, init_value: TableElement) -> Option<u32> {
194 let size = self.size();
195 let new_len = size.checked_add(delta)?;
196 if self.maximum.is_some_and(|max| new_len > max) {
197 return None;
198 }
199 if new_len == size {
200 debug_assert_eq!(delta, 0);
201 return Some(size);
202 }
203
204 self.vec
205 .resize(usize::try_from(new_len).unwrap(), init_value.into());
206
207 unsafe {
209 let mut td_ptr = self.get_vm_table_definition();
210 let td = td_ptr.as_mut();
211 td.current_elements = new_len;
212 td.base = self.vec.as_mut_ptr() as _;
213 }
214 Some(size)
215 }
216
217 pub fn get(&self, index: u32) -> Option<TableElement> {
221 let raw_data = self.vec.get(index as usize).cloned()?;
222 Some(match self.table.ty {
223 ValType::ExternRef => TableElement::ExternRef(unsafe { raw_data.extern_ref }),
224 ValType::FuncRef => TableElement::FuncRef(unsafe { raw_data.func_ref }),
225 _ => todo!("getting invalid type from table, handle this error"),
226 })
227 }
228
229 pub fn set(&mut self, index: u32, reference: TableElement) -> Result<(), Trap> {
235 match self.vec.get_mut(index as usize) {
236 Some(slot) => {
237 match (self.table.ty, reference) {
238 (ValType::ExternRef, r @ TableElement::ExternRef(_)) => {
239 *slot = r.into();
240 }
241 (ValType::FuncRef, r @ TableElement::FuncRef(_)) => {
242 *slot = r.into();
243 }
244 (ty, v) => {
247 panic!("Attempted to set a table of type {ty} with the value {v:?}")
248 }
249 };
250
251 Ok(())
252 }
253 None => Err(Trap::lib(TrapCode::TableAccessOutOfBounds)),
254 }
255 }
256
257 pub fn vmtable(&self) -> NonNull<VMTableDefinition> {
259 self.get_vm_table_definition()
260 }
261
262 pub fn copy(
269 &mut self,
270 src_table: &Self,
271 dst_index: u32,
272 src_index: u32,
273 len: u32,
274 ) -> Result<(), Trap> {
275 if src_index
278 .checked_add(len)
279 .is_none_or(|n| n > src_table.size())
280 {
281 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
282 }
283
284 if dst_index.checked_add(len).is_none_or(|m| m > self.size()) {
285 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
286 }
287
288 let srcs = src_index..src_index + len;
289 let dsts = dst_index..dst_index + len;
290
291 if dst_index <= src_index {
296 for (s, d) in (srcs).zip(dsts) {
297 self.set(d, src_table.get(s).unwrap())?;
298 }
299 } else {
300 for (s, d) in srcs.rev().zip(dsts.rev()) {
301 self.set(d, src_table.get(s).unwrap())?;
302 }
303 }
304
305 Ok(())
306 }
307
308 pub fn copy_on_write(&self) -> Result<Self, String> {
310 let mut ret = Self::new(&self.table, &self.style)?;
311 ret.copy(self, 0, 0, self.size())
312 .map_err(|trap| format!("failed to copy the table - {trap:?}"))?;
313 Ok(ret)
314 }
315
316 pub fn copy_within(&mut self, dst_index: u32, src_index: u32, len: u32) -> Result<(), Trap> {
323 if src_index.checked_add(len).is_none_or(|n| n > self.size()) {
326 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
327 }
328
329 if dst_index.checked_add(len).is_none_or(|m| m > self.size()) {
330 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
331 }
332
333 let srcs = src_index..src_index + len;
334 let dsts = dst_index..dst_index + len;
335
336 if dst_index <= src_index {
341 for (s, d) in (srcs).zip(dsts) {
342 self.set(d, self.get(s).unwrap())?;
343 }
344 } else {
345 for (s, d) in srcs.rev().zip(dsts.rev()) {
346 self.set(d, self.get(s).unwrap())?;
347 }
348 }
349
350 Ok(())
351 }
352}