1use crate::prelude::*;
6use crate::runtime::store::StoreResourceLimiter;
7use crate::runtime::vm::stack_switching::VMContObj;
8use crate::runtime::vm::vmcontext::{VMFuncRef, VMTableDefinition};
9use crate::runtime::vm::{GcStore, SendSyncPtr, VMGcRef, VmPtr};
10use core::alloc::Layout;
11use core::mem;
12use core::ops::Range;
13use core::ptr::NonNull;
14use core::slice;
15use core::{cmp, usize};
16use wasmtime_environ::{
17 FUNCREF_INIT_BIT, FUNCREF_MASK, IndexType, Trap, Tunables, WasmHeapTopType, WasmRefType,
18};
19
20#[derive(Copy, Clone, PartialEq, Eq, Debug)]
21pub enum TableElementType {
22 Func,
23 GcRef,
24 Cont,
25}
26
27impl TableElementType {
28 pub fn element_size(&self) -> usize {
30 match self {
31 TableElementType::Func => core::mem::size_of::<FuncTableElem>(),
32 TableElementType::GcRef => core::mem::size_of::<Option<VMGcRef>>(),
33 TableElementType::Cont => core::mem::size_of::<ContTableElem>(),
34 }
35 }
36}
37
38#[derive(Copy, Clone)]
52#[repr(transparent)]
53struct MaybeTaggedFuncRef(Option<VmPtr<VMFuncRef>>);
54
55impl MaybeTaggedFuncRef {
56 fn from(ptr: Option<NonNull<VMFuncRef>>, lazy_init: bool) -> Self {
59 let maybe_tagged = if lazy_init {
60 Some(match ptr {
61 Some(ptr) => ptr.map_addr(|a| a | FUNCREF_INIT_BIT),
62 None => NonNull::new(core::ptr::without_provenance_mut(FUNCREF_INIT_BIT)).unwrap(),
63 })
64 } else {
65 ptr
66 };
67 MaybeTaggedFuncRef(maybe_tagged.map(Into::into))
68 }
69
70 fn into_funcref(self, lazy_init: bool) -> Option<Option<NonNull<VMFuncRef>>> {
73 let ptr = self.0;
74 if lazy_init && ptr.is_none() {
75 None
76 } else {
77 Some(ptr.and_then(|ptr| NonNull::new(ptr.as_ptr().map_addr(|a| a & FUNCREF_MASK))))
80 }
81 }
82}
83
84pub type FuncTableElem = Option<SendSyncPtr<VMFuncRef>>;
85pub type ContTableElem = Option<VMContObj>;
86
87#[cfg(feature = "pooling-allocator")]
89pub const NOMINAL_MAX_TABLE_ELEM_SIZE: usize = {
90 let sizes = [
92 core::mem::size_of::<FuncTableElem>(),
93 core::mem::size_of::<Option<VMGcRef>>(),
94 ];
95
96 const fn slice_max(data: &[usize]) -> usize {
99 match data {
100 [] => 0,
101 [head, tail @ ..] => {
102 let tail_max = slice_max(tail);
103 if *head >= tail_max { *head } else { tail_max }
104 }
105 }
106 }
107
108 slice_max(&sizes)
109};
110
111pub enum StaticTable {
112 Func(StaticFuncTable),
113 GcRef(StaticGcRefTable),
114 Cont(StaticContTable),
115}
116
117impl From<StaticFuncTable> for StaticTable {
118 fn from(value: StaticFuncTable) -> Self {
119 Self::Func(value)
120 }
121}
122
123impl From<StaticGcRefTable> for StaticTable {
124 fn from(value: StaticGcRefTable) -> Self {
125 Self::GcRef(value)
126 }
127}
128
129impl From<StaticContTable> for StaticTable {
130 fn from(value: StaticContTable) -> Self {
131 Self::Cont(value)
132 }
133}
134
135pub struct StaticFuncTable {
136 data: SendSyncPtr<[FuncTableElem]>,
139 size: usize,
141 lazy_init: bool,
143}
144
145pub struct StaticGcRefTable {
146 data: SendSyncPtr<[Option<VMGcRef>]>,
149 size: usize,
151}
152
153pub struct StaticContTable {
154 data: SendSyncPtr<[ContTableElem]>,
157 size: usize,
159}
160
161pub enum DynamicTable {
162 Func(DynamicFuncTable),
163 GcRef(DynamicGcRefTable),
164 Cont(DynamicContTable),
165}
166
167impl From<DynamicFuncTable> for DynamicTable {
168 fn from(value: DynamicFuncTable) -> Self {
169 Self::Func(value)
170 }
171}
172
173impl From<DynamicGcRefTable> for DynamicTable {
174 fn from(value: DynamicGcRefTable) -> Self {
175 Self::GcRef(value)
176 }
177}
178
179impl From<DynamicContTable> for DynamicTable {
180 fn from(value: DynamicContTable) -> Self {
181 Self::Cont(value)
182 }
183}
184
185pub struct DynamicFuncTable {
186 elements: TryVec<FuncTableElem>,
189 maximum: Option<usize>,
191 lazy_init: bool,
193}
194
195pub struct DynamicGcRefTable {
196 elements: TryVec<Option<VMGcRef>>,
199 maximum: Option<usize>,
201}
202
203pub struct DynamicContTable {
204 elements: TryVec<ContTableElem>,
207 maximum: Option<usize>,
209}
210
211pub enum Table {
213 Static(StaticTable),
216 Dynamic(DynamicTable),
219}
220
221impl From<StaticTable> for Table {
222 fn from(value: StaticTable) -> Self {
223 Self::Static(value)
224 }
225}
226
227impl From<StaticFuncTable> for Table {
228 fn from(value: StaticFuncTable) -> Self {
229 let t: StaticTable = value.into();
230 t.into()
231 }
232}
233
234impl From<StaticGcRefTable> for Table {
235 fn from(value: StaticGcRefTable) -> Self {
236 let t: StaticTable = value.into();
237 t.into()
238 }
239}
240
241impl From<StaticContTable> for Table {
242 fn from(value: StaticContTable) -> Self {
243 let t: StaticTable = value.into();
244 t.into()
245 }
246}
247
248impl From<DynamicTable> for Table {
249 fn from(value: DynamicTable) -> Self {
250 Self::Dynamic(value)
251 }
252}
253
254impl From<DynamicFuncTable> for Table {
255 fn from(value: DynamicFuncTable) -> Self {
256 let t: DynamicTable = value.into();
257 t.into()
258 }
259}
260
261impl From<DynamicGcRefTable> for Table {
262 fn from(value: DynamicGcRefTable) -> Self {
263 let t: DynamicTable = value.into();
264 t.into()
265 }
266}
267
268impl From<DynamicContTable> for Table {
269 fn from(value: DynamicContTable) -> Self {
270 let t: DynamicTable = value.into();
271 t.into()
272 }
273}
274
275pub(crate) fn wasm_to_table_type(ty: WasmRefType) -> TableElementType {
276 match ty.heap_type.top() {
277 WasmHeapTopType::Func => TableElementType::Func,
278 WasmHeapTopType::Any | WasmHeapTopType::Extern => TableElementType::GcRef,
279 WasmHeapTopType::Cont => TableElementType::Cont,
280 WasmHeapTopType::Exn => TableElementType::GcRef,
281 }
282}
283
284unsafe fn alloc_dynamic_table_elements<T>(len: usize) -> Result<TryVec<Option<T>>> {
295 debug_assert!(
296 unsafe {
297 core::mem::MaybeUninit::<Option<T>>::zeroed()
298 .assume_init()
299 .is_none()
300 },
301 "null table elements are represented with zeroed memory"
302 );
303
304 if len == 0 {
305 return Ok(TryVec::new());
306 }
307
308 let align = mem::align_of::<Option<T>>();
309
310 let size = mem::size_of::<Option<T>>();
311 let size = size.next_multiple_of(align);
312 let size = size
313 .checked_mul(len)
314 .ok_or_else(|| format_err!("overflow calculating table allocation size"))?;
315
316 let layout = Layout::from_size_align(size, align)?;
317
318 let ptr = unsafe { alloc::alloc::alloc_zeroed(layout) };
319 if ptr.is_null() {
320 return Err(OutOfMemory::new(size).into());
321 }
322
323 let elems = unsafe { TryVec::<Option<T>>::from_raw_parts(ptr.cast(), len, len) };
324 debug_assert!(elems.iter().all(|e| e.is_none()));
325
326 Ok(elems)
327}
328
329impl Table {
330 pub async fn new_dynamic(
332 ty: &wasmtime_environ::Table,
333 tunables: &Tunables,
334 limiter: Option<&mut StoreResourceLimiter<'_>>,
335 ) -> Result<Self> {
336 let (minimum, maximum) = Self::limit_new(ty, limiter).await?;
337 match wasm_to_table_type(ty.ref_type) {
338 TableElementType::Func => Ok(Self::from(DynamicFuncTable {
339 elements: unsafe { alloc_dynamic_table_elements(minimum)? },
340 maximum,
341 lazy_init: tunables.table_lazy_init,
342 })),
343 TableElementType::GcRef => Ok(Self::from(DynamicGcRefTable {
344 elements: unsafe { alloc_dynamic_table_elements(minimum)? },
345 maximum,
346 })),
347 TableElementType::Cont => {
348 let mut elements = TryVec::new();
349 elements.resize_with(minimum, || None)?;
350 Ok(Self::from(DynamicContTable { elements, maximum }))
351 }
352 }
353 }
354
355 pub async unsafe fn new_static(
357 ty: &wasmtime_environ::Table,
358 tunables: &Tunables,
359 data: SendSyncPtr<[u8]>,
360 limiter: Option<&mut StoreResourceLimiter<'_>>,
361 ) -> Result<Self> {
362 let (minimum, maximum) = Self::limit_new(ty, limiter).await?;
363 let size = minimum;
364 let max = maximum.unwrap_or(usize::MAX);
365
366 match wasm_to_table_type(ty.ref_type) {
367 TableElementType::Func => {
368 let len = {
369 let (before, data, after) = unsafe {
370 let data = data.as_non_null().as_ref();
371 data.align_to::<FuncTableElem>()
372 };
373 assert!(before.is_empty());
374 assert!(after.is_empty());
375 data.len()
376 };
377 ensure!(
378 usize::try_from(ty.limits.min).unwrap() <= len,
379 "initial table size of {} exceeds the pooling allocator's \
380 configured maximum table size of {len} elements",
381 ty.limits.min,
382 );
383 let data = SendSyncPtr::new(NonNull::slice_from_raw_parts(
384 data.as_non_null().cast::<FuncTableElem>(),
385 cmp::min(len, max),
386 ));
387 Ok(Self::from(StaticFuncTable {
388 data,
389 size,
390 lazy_init: tunables.table_lazy_init,
391 }))
392 }
393 TableElementType::GcRef => {
394 let len = {
395 let (before, data, after) = unsafe {
396 let data = data.as_non_null().as_ref();
397 data.align_to::<Option<VMGcRef>>()
398 };
399 assert!(before.is_empty());
400 assert!(after.is_empty());
401 data.len()
402 };
403 ensure!(
404 usize::try_from(ty.limits.min).unwrap() <= len,
405 "initial table size of {} exceeds the pooling allocator's \
406 configured maximum table size of {len} elements",
407 ty.limits.min,
408 );
409 let data = SendSyncPtr::new(NonNull::slice_from_raw_parts(
410 data.as_non_null().cast::<Option<VMGcRef>>(),
411 cmp::min(len, max),
412 ));
413 Ok(Self::from(StaticGcRefTable { data, size }))
414 }
415 TableElementType::Cont => {
416 let len = {
417 let (before, data, after) = unsafe {
418 let data = data.as_non_null().as_ref();
419 data.align_to::<ContTableElem>()
420 };
421 assert!(before.is_empty());
422 assert!(after.is_empty());
423 data.len()
424 };
425 ensure!(
426 usize::try_from(ty.limits.min).unwrap() <= len,
427 "initial table size of {} exceeds the pooling allocator's \
428 configured maximum table size of {len} elements",
429 ty.limits.min,
430 );
431 let data = SendSyncPtr::new(NonNull::slice_from_raw_parts(
432 data.as_non_null().cast::<ContTableElem>(),
433 cmp::min(len, max),
434 ));
435 Ok(Self::from(StaticContTable { data, size }))
436 }
437 }
438 }
439
440 async fn limit_new(
444 ty: &wasmtime_environ::Table,
445 limiter: Option<&mut StoreResourceLimiter<'_>>,
446 ) -> Result<(usize, Option<usize>)> {
447 let absolute_max = usize::MAX;
450
451 let minimum = usize::try_from(ty.limits.min).ok();
454
455 let maximum = match (ty.limits.max, ty.idx_type) {
460 (Some(max), _) => usize::try_from(max).ok(),
461 (None, IndexType::I64) => usize::try_from(u64::MAX).ok(),
462 (None, IndexType::I32) => usize::try_from(u32::MAX).ok(),
463 };
464
465 if let Some(limiter) = limiter {
467 if !limiter
468 .table_growing(0, minimum.unwrap_or(absolute_max), maximum)
469 .await?
470 {
471 bail!(
472 "table minimum size of {} elements exceeds table limits",
473 ty.limits.min
474 );
475 }
476 }
477
478 let minimum = minimum.ok_or_else(|| {
481 format_err!(
482 "table minimum size of {} elements exceeds table limits",
483 ty.limits.min
484 )
485 })?;
486 Ok((minimum, maximum))
487 }
488
489 pub fn element_type(&self) -> TableElementType {
491 match self {
492 Table::Static(StaticTable::Func(_)) | Table::Dynamic(DynamicTable::Func(_)) => {
493 TableElementType::Func
494 }
495 Table::Static(StaticTable::GcRef(_)) | Table::Dynamic(DynamicTable::GcRef(_)) => {
496 TableElementType::GcRef
497 }
498 Table::Static(StaticTable::Cont(_)) | Table::Dynamic(DynamicTable::Cont(_)) => {
499 TableElementType::Cont
500 }
501 }
502 }
503
504 #[cfg(feature = "pooling-allocator")]
506 pub(crate) fn is_static(&self) -> bool {
507 matches!(self, Table::Static(_))
508 }
509
510 pub fn size(&self) -> usize {
512 match self {
513 Table::Static(StaticTable::Func(StaticFuncTable { size, .. })) => *size,
514 Table::Static(StaticTable::GcRef(StaticGcRefTable { size, .. })) => *size,
515 Table::Static(StaticTable::Cont(StaticContTable { size, .. })) => *size,
516 Table::Dynamic(DynamicTable::Func(DynamicFuncTable { elements, .. })) => elements.len(),
517 Table::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => {
518 elements.len()
519 }
520 Table::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => elements.len(),
521 }
522 }
523
524 pub fn maximum(&self) -> Option<usize> {
531 match self {
532 Table::Static(StaticTable::Cont(StaticContTable { data, .. })) => Some(data.len()),
533 Table::Static(StaticTable::Func(StaticFuncTable { data, .. })) => Some(data.len()),
534 Table::Static(StaticTable::GcRef(StaticGcRefTable { data, .. })) => Some(data.len()),
535 Table::Dynamic(DynamicTable::Func(DynamicFuncTable { maximum, .. })) => *maximum,
536 Table::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { maximum, .. })) => *maximum,
537 Table::Dynamic(DynamicTable::Cont(DynamicContTable { maximum, .. })) => *maximum,
538 }
539 }
540
541 pub fn fill_func(
549 &mut self,
550 dst: u64,
551 val: Option<NonNull<VMFuncRef>>,
552 len: u64,
553 ) -> Result<(), Trap> {
554 let range = self.validate_fill(dst, len)?;
555 let (funcrefs, lazy_init) = self.funcrefs_mut();
556 funcrefs[range].fill(MaybeTaggedFuncRef::from(val, lazy_init));
557 Ok(())
558 }
559
560 pub fn fill_gc_ref(
566 &mut self,
567 mut gc_store: Option<&mut GcStore>,
568 dst: u64,
569 val: Option<&VMGcRef>,
570 len: u64,
571 ) -> Result<()> {
572 let range = self.validate_fill(dst, len)?;
573
574 for slot in &mut self.gc_refs_mut()[range] {
576 GcStore::write_gc_ref_optional_store(gc_store.as_deref_mut(), slot, val)?;
577 }
578
579 Ok(())
580 }
581 pub fn fill_cont(&mut self, dst: u64, val: Option<VMContObj>, len: u64) -> Result<(), Trap> {
583 let range = self.validate_fill(dst, len)?;
584 self.contrefs_mut()[range].fill(val);
585 Ok(())
586 }
587
588 fn validate_fill(&mut self, dst: u64, len: u64) -> Result<Range<usize>, Trap> {
589 let start = usize::try_from(dst).map_err(|_| Trap::TableOutOfBounds)?;
590 let len = usize::try_from(len).map_err(|_| Trap::TableOutOfBounds)?;
591 let end = start
592 .checked_add(len)
593 .ok_or_else(|| Trap::TableOutOfBounds)?;
594
595 if end > self.size() {
596 return Err(Trap::TableOutOfBounds);
597 }
598 Ok(start..end)
599 }
600
601 pub async unsafe fn grow(
624 &mut self,
625 mut limiter: Option<&mut StoreResourceLimiter<'_>>,
626 delta: u64,
627 ) -> Result<Option<usize>, Error> {
628 let old_size = self.size();
629
630 if delta == 0 {
633 return Ok(Some(old_size));
634 }
635 let delta = usize::try_from(delta).map_err(|_| Trap::TableOutOfBounds)?;
636
637 let new_size = match old_size.checked_add(delta) {
638 Some(s) => s,
639 None => {
640 if let Some(limiter) = limiter {
641 limiter
642 .table_grow_failed(format_err!("overflow calculating new table size"))?;
643 }
644 return Ok(None);
645 }
646 };
647
648 if let Some(limiter) = &mut limiter {
649 if !limiter
650 .table_growing(old_size, new_size, self.maximum())
651 .await?
652 {
653 return Ok(None);
654 }
655 }
656
657 if let Some(max) = self.maximum() {
661 if new_size > max {
662 if let Some(limiter) = limiter {
663 limiter.table_grow_failed(format_err!("Table maximum size exceeded"))?;
664 }
665 return Ok(None);
666 }
667 }
668
669 match self {
671 Table::Static(StaticTable::Func(StaticFuncTable { data, size, .. })) => {
672 unsafe {
673 debug_assert!(data.as_ref()[*size..new_size].iter().all(|x| x.is_none()));
674 }
675 *size = new_size;
676 }
677 Table::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => {
678 unsafe {
679 debug_assert!(data.as_ref()[*size..new_size].iter().all(|x| x.is_none()));
680 }
681 *size = new_size;
682 }
683 Table::Static(StaticTable::Cont(StaticContTable { data, size })) => {
684 unsafe {
685 debug_assert!(data.as_ref()[*size..new_size].iter().all(|x| x.is_none()));
686 }
687 *size = new_size;
688 }
689
690 Table::Dynamic(DynamicTable::Func(DynamicFuncTable { elements, .. })) => {
698 elements.resize_with(new_size, || None)?;
699 }
700 Table::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => {
701 elements.resize_with(new_size, || None)?;
702 }
703 Table::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => {
704 elements.resize_with(new_size, || None)?;
705 }
706 }
707
708 Ok(Some(old_size))
709 }
710
711 pub fn get_func(&self, index: u64) -> Result<Option<NonNull<VMFuncRef>>, Trap> {
718 match self.get_func_maybe_init(index)? {
719 Some(elem) => Ok(elem),
720 None => panic!("function index should have been initialized"),
721 }
722 }
723
724 pub fn get_func_maybe_init(
728 &self,
729 index: u64,
730 ) -> Result<Option<Option<NonNull<VMFuncRef>>>, Trap> {
731 let index = usize::try_from(index).map_err(|_| Trap::TableOutOfBounds)?;
732 let (funcrefs, lazy_init) = self.funcrefs();
733 Ok(funcrefs
734 .get(index)
735 .ok_or(Trap::TableOutOfBounds)?
736 .into_funcref(lazy_init))
737 }
738
739 pub fn get_gc_ref(&self, index: u64) -> Result<Option<&VMGcRef>, Trap> {
741 let index = usize::try_from(index).map_err(|_| Trap::TableOutOfBounds)?;
742 let gcref = self.gc_refs().get(index).ok_or(Trap::TableOutOfBounds)?;
743 Ok(gcref.as_ref())
744 }
745
746 pub fn get_cont(&self, index: u64) -> Result<Option<VMContObj>, Trap> {
748 let index = usize::try_from(index).map_err(|_| Trap::TableOutOfBounds)?;
749 let cont = self.contrefs().get(index).ok_or(Trap::TableOutOfBounds)?;
750 Ok(*cont)
751 }
752
753 pub fn set_func(&mut self, index: u64, elem: Option<NonNull<VMFuncRef>>) -> Result<(), Trap> {
764 let trap = Trap::TableOutOfBounds;
765 let index: usize = index.try_into().map_err(|_| trap)?;
766 let (funcrefs, lazy_init) = self.funcrefs_mut();
767 *funcrefs.get_mut(index).ok_or(trap)? = MaybeTaggedFuncRef::from(elem, lazy_init);
768 Ok(())
769 }
770
771 pub fn set_gc_ref(
773 &mut self,
774 store: Option<&mut GcStore>,
775 index: u64,
776 elem: Option<&VMGcRef>,
777 ) -> Result<()> {
778 let trap = Trap::TableOutOfBounds;
779 let index: usize = index.try_into().map_err(|_| trap)?;
780 GcStore::write_gc_ref_optional_store(
781 store,
782 self.gc_refs_mut().get_mut(index).ok_or(trap)?,
783 elem,
784 )?;
785 Ok(())
786 }
787
788 pub fn vmtable(&mut self) -> VMTableDefinition {
790 match self {
791 Table::Static(StaticTable::Func(StaticFuncTable { data, size, .. })) => {
792 VMTableDefinition {
793 base: data.cast().into(),
794 current_elements: *size,
795 }
796 }
797 Table::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => {
798 VMTableDefinition {
799 base: data.cast().into(),
800 current_elements: *size,
801 }
802 }
803 Table::Static(StaticTable::Cont(StaticContTable { data, size })) => VMTableDefinition {
804 base: data.cast().into(),
805 current_elements: *size,
806 },
807 Table::Dynamic(DynamicTable::Func(DynamicFuncTable { elements, .. })) => {
808 VMTableDefinition {
809 base: NonNull::new(elements.as_mut_ptr()).unwrap().cast().into(),
810 current_elements: elements.len(),
811 }
812 }
813 Table::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => {
814 VMTableDefinition {
815 base: NonNull::new(elements.as_mut_ptr()).unwrap().cast().into(),
816 current_elements: elements.len(),
817 }
818 }
819 Table::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => {
820 VMTableDefinition {
821 base: NonNull::new(elements.as_mut_ptr()).unwrap().cast().into(),
822 current_elements: elements.len(),
823 }
824 }
825 }
826 }
827
828 fn funcrefs(&self) -> (&[MaybeTaggedFuncRef], bool) {
829 assert_eq!(self.element_type(), TableElementType::Func);
830 match self {
831 Self::Dynamic(DynamicTable::Func(DynamicFuncTable {
832 elements,
833 lazy_init,
834 ..
835 })) => (
836 unsafe { slice::from_raw_parts(elements.as_ptr().cast(), elements.len()) },
837 *lazy_init,
838 ),
839 Self::Static(StaticTable::Func(StaticFuncTable {
840 data,
841 size,
842 lazy_init,
843 })) => (
844 unsafe { slice::from_raw_parts(data.as_ptr().cast(), *size) },
845 *lazy_init,
846 ),
847 _ => unreachable!(),
848 }
849 }
850
851 fn funcrefs_mut(&mut self) -> (&mut [MaybeTaggedFuncRef], bool) {
852 assert_eq!(self.element_type(), TableElementType::Func);
853 match self {
854 Self::Dynamic(DynamicTable::Func(DynamicFuncTable {
855 elements,
856 lazy_init,
857 ..
858 })) => (
859 unsafe { slice::from_raw_parts_mut(elements.as_mut_ptr().cast(), elements.len()) },
860 *lazy_init,
861 ),
862 Self::Static(StaticTable::Func(StaticFuncTable {
863 data,
864 size,
865 lazy_init,
866 })) => (
867 unsafe { slice::from_raw_parts_mut(data.as_ptr().cast(), *size) },
868 *lazy_init,
869 ),
870 _ => unreachable!(),
871 }
872 }
873
874 fn gc_refs(&self) -> &[Option<VMGcRef>] {
875 assert_eq!(self.element_type(), TableElementType::GcRef);
876 match self {
877 Self::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => elements,
878 Self::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => unsafe {
879 &data.as_non_null().as_ref()[..*size]
880 },
881 _ => unreachable!(),
882 }
883 }
884
885 fn contrefs(&self) -> &[Option<VMContObj>] {
886 assert_eq!(self.element_type(), TableElementType::Cont);
887 match self {
888 Self::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => unsafe {
889 slice::from_raw_parts(elements.as_ptr().cast(), elements.len())
890 },
891 Self::Static(StaticTable::Cont(StaticContTable { data, size })) => unsafe {
892 slice::from_raw_parts(data.as_ptr().cast(), *size)
893 },
894 _ => unreachable!(),
895 }
896 }
897
898 fn contrefs_mut(&mut self) -> &mut [Option<VMContObj>] {
899 assert_eq!(self.element_type(), TableElementType::Cont);
900 match self {
901 Self::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => unsafe {
902 slice::from_raw_parts_mut(elements.as_mut_ptr().cast(), elements.len())
903 },
904 Self::Static(StaticTable::Cont(StaticContTable { data, size })) => unsafe {
905 slice::from_raw_parts_mut(data.as_ptr().cast(), *size)
906 },
907 _ => unreachable!(),
908 }
909 }
910
911 pub fn gc_refs_mut(&mut self) -> &mut [Option<VMGcRef>] {
915 assert_eq!(self.element_type(), TableElementType::GcRef);
916 match self {
917 Self::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => elements,
918 Self::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => unsafe {
919 &mut data.as_non_null().as_mut()[..*size]
920 },
921 _ => unreachable!(),
922 }
923 }
924
925 pub fn manually_memset_zeros(&mut self) {
931 match self.element_type() {
932 TableElementType::Func => {
933 let (funcrefs, _lazy_init) = self.funcrefs_mut();
934 funcrefs.fill(MaybeTaggedFuncRef(None));
935 }
936 TableElementType::GcRef => {
937 for r in self.gc_refs_mut() {
941 *r = None;
942 }
943 }
944 TableElementType::Cont => {
945 self.contrefs_mut().fill(None);
946 }
947 }
948 }
949
950 pub fn debug_assert_all_zero(&self) {
951 match self.element_type() {
952 TableElementType::Func => {
953 let (funcrefs, _lazy_init) = self.funcrefs();
954 debug_assert!(funcrefs.iter().all(|f| f.0.is_none()));
955 }
956 TableElementType::GcRef => {
957 debug_assert!(self.gc_refs().iter().all(|r| r.is_none()));
958 }
959 TableElementType::Cont => {
960 debug_assert!(self.contrefs().iter().all(|c| c.is_none()));
961 }
962 }
963 }
964}
965
966impl Default for Table {
968 fn default() -> Self {
969 Self::from(StaticFuncTable {
970 data: SendSyncPtr::new(NonNull::from(&mut [])),
971 size: 0,
972 lazy_init: false,
973 })
974 }
975}