1use crate::store::MaybeInstanceOwned;
9use crate::vmcontext::VMTableDefinition;
10use crate::Trap;
11use crate::VMExternRef;
12use crate::VMFuncRef;
13use derivative::Derivative;
14use std::cell::UnsafeCell;
15use std::convert::TryFrom;
16use std::fmt;
17use std::ptr::NonNull;
18use wasmer_types::TableStyle;
19use wasmer_types::{TableType, TrapCode, Type as ValType};
20
21#[derive(Debug, Clone)]
23pub enum TableElement {
24 ExternRef(Option<VMExternRef>),
26 FuncRef(Option<VMFuncRef>),
28}
29
30impl From<TableElement> for RawTableElement {
31 fn from(other: TableElement) -> Self {
32 match other {
33 TableElement::ExternRef(extern_ref) => Self { extern_ref },
34 TableElement::FuncRef(func_ref) => Self { func_ref },
35 }
36 }
37}
38
39#[repr(C)]
40#[derive(Clone, Copy)]
41pub union RawTableElement {
42 pub(crate) extern_ref: Option<VMExternRef>,
43 pub(crate) func_ref: Option<VMFuncRef>,
44}
45
46#[cfg(test)]
47#[test]
48fn table_element_size_test() {
49 use std::mem::size_of;
50 assert_eq!(size_of::<RawTableElement>(), size_of::<VMExternRef>());
51 assert_eq!(size_of::<RawTableElement>(), size_of::<VMFuncRef>());
52}
53
54impl fmt::Debug for RawTableElement {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 f.debug_struct("RawTableElement").finish()
57 }
58}
59
60impl Default for RawTableElement {
61 fn default() -> Self {
62 Self { func_ref: None }
63 }
64}
65
66impl Default for TableElement {
67 fn default() -> Self {
68 Self::FuncRef(None)
69 }
70}
71
72#[derive(Derivative)]
74#[derivative(Debug)]
75pub struct VMTable {
76 #[derivative(Debug = "ignore")]
77 vec: Vec<RawTableElement>,
78 maximum: Option<u32>,
79 table: TableType,
81 style: TableStyle,
83 #[derivative(Debug = "ignore")]
84 vm_table_definition: MaybeInstanceOwned<VMTableDefinition>,
85}
86
87impl VMTable {
88 pub fn new(table: &TableType, style: &TableStyle) -> Result<Self, String> {
93 unsafe { Self::new_inner(table, style, None) }
94 }
95
96 pub fn get_runtime_size(&self) -> u32 {
98 self.vec.len() as u32
99 }
100
101 pub unsafe fn from_definition(
109 table: &TableType,
110 style: &TableStyle,
111 vm_table_location: NonNull<VMTableDefinition>,
112 ) -> Result<Self, String> {
113 Self::new_inner(table, style, Some(vm_table_location))
114 }
115
116 unsafe fn new_inner(
118 table: &TableType,
119 style: &TableStyle,
120 vm_table_location: Option<NonNull<VMTableDefinition>>,
121 ) -> Result<Self, String> {
122 match table.ty {
123 ValType::FuncRef | ValType::ExternRef => (),
124 ty => {
125 return Err(format!(
126 "tables of types other than funcref or externref ({})",
127 ty
128 ))
129 }
130 };
131 if let Some(max) = table.maximum {
132 if max < table.minimum {
133 return Err(format!(
134 "Table minimum ({}) is larger than maximum ({})!",
135 table.minimum, max
136 ));
137 }
138 }
139 let table_minimum = usize::try_from(table.minimum)
140 .map_err(|_| "Table minimum is bigger than usize".to_string())?;
141 let mut vec = vec![RawTableElement::default(); table_minimum];
142 let base = vec.as_mut_ptr();
143 match style {
144 TableStyle::CallerChecksSignature => Ok(Self {
145 vec,
146 maximum: table.maximum,
147 table: *table,
148 style: style.clone(),
149 vm_table_definition: if let Some(table_loc) = vm_table_location {
150 {
151 let mut ptr = table_loc;
152 let td = ptr.as_mut();
153 td.base = base as _;
154 td.current_elements = table_minimum as _;
155 }
156 MaybeInstanceOwned::Instance(table_loc)
157 } else {
158 MaybeInstanceOwned::Host(Box::new(UnsafeCell::new(VMTableDefinition {
159 base: base as _,
160 current_elements: table_minimum as _,
161 })))
162 },
163 }),
164 }
165 }
166
167 fn get_vm_table_definition(&self) -> NonNull<VMTableDefinition> {
169 self.vm_table_definition.as_ptr()
170 }
171
172 pub fn ty(&self) -> &TableType {
174 &self.table
175 }
176
177 pub fn style(&self) -> &TableStyle {
179 &self.style
180 }
181
182 pub fn size(&self) -> u32 {
184 unsafe {
186 let td_ptr = self.get_vm_table_definition();
187 let td = td_ptr.as_ref();
188 td.current_elements
189 }
190 }
191
192 pub fn grow(&mut self, delta: u32, init_value: TableElement) -> Option<u32> {
197 let size = self.size();
198 let new_len = size.checked_add(delta)?;
199 if self.maximum.map_or(false, |max| new_len > max) {
200 return None;
201 }
202 if new_len == size {
203 debug_assert_eq!(delta, 0);
204 return Some(size);
205 }
206
207 self.vec
208 .resize(usize::try_from(new_len).unwrap(), init_value.into());
209
210 unsafe {
212 let mut td_ptr = self.get_vm_table_definition();
213 let td = td_ptr.as_mut();
214 td.current_elements = new_len;
215 td.base = self.vec.as_mut_ptr() as _;
216 }
217 Some(size)
218 }
219
220 pub fn get(&self, index: u32) -> Option<TableElement> {
224 let raw_data = self.vec.get(index as usize).cloned()?;
225 Some(match self.table.ty {
226 ValType::ExternRef => TableElement::ExternRef(unsafe { raw_data.extern_ref }),
227 ValType::FuncRef => TableElement::FuncRef(unsafe { raw_data.func_ref }),
228 _ => todo!("getting invalid type from table, handle this error"),
229 })
230 }
231
232 pub fn set(&mut self, index: u32, reference: TableElement) -> Result<(), Trap> {
238 match self.vec.get_mut(index as usize) {
239 Some(slot) => {
240 match (self.table.ty, reference) {
241 (ValType::ExternRef, r @ TableElement::ExternRef(_)) => {
242 *slot = r.into();
243 }
244 (ValType::FuncRef, r @ TableElement::FuncRef(_)) => {
245 *slot = r.into();
246 }
247 (ty, v) => {
250 panic!(
251 "Attempted to set a table of type {} with the value {:?}",
252 ty, v
253 )
254 }
255 };
256
257 Ok(())
258 }
259 None => Err(Trap::lib(TrapCode::TableAccessOutOfBounds)),
260 }
261 }
262
263 pub fn vmtable(&self) -> NonNull<VMTableDefinition> {
265 self.get_vm_table_definition()
266 }
267
268 pub fn copy(
275 &mut self,
276 src_table: &Self,
277 dst_index: u32,
278 src_index: u32,
279 len: u32,
280 ) -> Result<(), Trap> {
281 if src_index
284 .checked_add(len)
285 .map_or(true, |n| n > src_table.size())
286 {
287 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
288 }
289
290 if dst_index.checked_add(len).map_or(true, |m| m > self.size()) {
291 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
292 }
293
294 let srcs = src_index..src_index + len;
295 let dsts = dst_index..dst_index + len;
296
297 if dst_index <= src_index {
302 for (s, d) in (srcs).zip(dsts) {
303 self.set(d, src_table.get(s).unwrap())?;
304 }
305 } else {
306 for (s, d) in srcs.rev().zip(dsts.rev()) {
307 self.set(d, src_table.get(s).unwrap())?;
308 }
309 }
310
311 Ok(())
312 }
313
314 pub fn copy_on_write(&self) -> Result<Self, String> {
316 let mut ret = Self::new(&self.table, &self.style)?;
317 ret.copy(self, 0, 0, self.size())
318 .map_err(|trap| format!("failed to copy the table - {:?}", trap))?;
319 Ok(ret)
320 }
321
322 pub fn copy_within(&mut self, dst_index: u32, src_index: u32, len: u32) -> Result<(), Trap> {
329 if src_index.checked_add(len).map_or(true, |n| n > self.size()) {
332 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
333 }
334
335 if dst_index.checked_add(len).map_or(true, |m| m > self.size()) {
336 return Err(Trap::lib(TrapCode::TableAccessOutOfBounds));
337 }
338
339 let srcs = src_index..src_index + len;
340 let dsts = dst_index..dst_index + len;
341
342 if dst_index <= src_index {
347 for (s, d) in (srcs).zip(dsts) {
348 self.set(d, self.get(s).unwrap())?;
349 }
350 } else {
351 for (s, d) in srcs.rev().zip(dsts.rev()) {
352 self.set(d, self.get(s).unwrap())?;
353 }
354 }
355
356 Ok(())
357 }
358}