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::cmp;
12use core::mem;
13use core::ops::Range;
14use core::ptr::NonNull;
15use core::slice;
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
636 let delta = usize::try_from(delta).unwrap_or(usize::MAX);
639
640 let new_size = match old_size.checked_add(delta) {
641 Some(s) => s,
642 None => {
643 if let Some(limiter) = limiter {
644 limiter
645 .table_grow_failed(format_err!("overflow calculating new table size"))?;
646 }
647 return Ok(None);
648 }
649 };
650
651 if let Some(limiter) = &mut limiter {
652 if !limiter
653 .table_growing(old_size, new_size, self.maximum())
654 .await?
655 {
656 return Ok(None);
657 }
658 }
659
660 if let Some(max) = self.maximum() {
664 if new_size > max {
665 if let Some(limiter) = limiter {
666 limiter.table_grow_failed(format_err!("Table maximum size exceeded"))?;
667 }
668 return Ok(None);
669 }
670 }
671
672 match self {
674 Table::Static(StaticTable::Func(StaticFuncTable { data, size, .. })) => {
675 unsafe {
676 debug_assert!(data.as_ref()[*size..new_size].iter().all(|x| x.is_none()));
677 }
678 *size = new_size;
679 }
680 Table::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => {
681 unsafe {
682 debug_assert!(data.as_ref()[*size..new_size].iter().all(|x| x.is_none()));
683 }
684 *size = new_size;
685 }
686 Table::Static(StaticTable::Cont(StaticContTable { data, size })) => {
687 unsafe {
688 debug_assert!(data.as_ref()[*size..new_size].iter().all(|x| x.is_none()));
689 }
690 *size = new_size;
691 }
692
693 Table::Dynamic(DynamicTable::Func(DynamicFuncTable { elements, .. })) => {
701 elements.resize_with(new_size, || None)?;
702 }
703 Table::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => {
704 elements.resize_with(new_size, || None)?;
705 }
706 Table::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => {
707 elements.resize_with(new_size, || None)?;
708 }
709 }
710
711 Ok(Some(old_size))
712 }
713
714 pub fn get_func(&self, index: u64) -> Result<Option<NonNull<VMFuncRef>>, Trap> {
721 match self.get_func_maybe_init(index)? {
722 Some(elem) => Ok(elem),
723 None => panic!("function index should have been initialized"),
724 }
725 }
726
727 pub fn get_func_maybe_init(
731 &self,
732 index: u64,
733 ) -> Result<Option<Option<NonNull<VMFuncRef>>>, Trap> {
734 let index = usize::try_from(index).map_err(|_| Trap::TableOutOfBounds)?;
735 let (funcrefs, lazy_init) = self.funcrefs();
736 Ok(funcrefs
737 .get(index)
738 .ok_or(Trap::TableOutOfBounds)?
739 .into_funcref(lazy_init))
740 }
741
742 pub fn get_gc_ref(&self, index: u64) -> Result<Option<&VMGcRef>, Trap> {
744 let index = usize::try_from(index).map_err(|_| Trap::TableOutOfBounds)?;
745 let gcref = self.gc_refs().get(index).ok_or(Trap::TableOutOfBounds)?;
746 Ok(gcref.as_ref())
747 }
748
749 pub fn get_cont(&self, index: u64) -> Result<Option<VMContObj>, Trap> {
751 let index = usize::try_from(index).map_err(|_| Trap::TableOutOfBounds)?;
752 let cont = self.contrefs().get(index).ok_or(Trap::TableOutOfBounds)?;
753 Ok(*cont)
754 }
755
756 pub fn set_func(&mut self, index: u64, elem: Option<NonNull<VMFuncRef>>) -> Result<(), Trap> {
767 let trap = Trap::TableOutOfBounds;
768 let index: usize = index.try_into().map_err(|_| trap)?;
769 let (funcrefs, lazy_init) = self.funcrefs_mut();
770 *funcrefs.get_mut(index).ok_or(trap)? = MaybeTaggedFuncRef::from(elem, lazy_init);
771 Ok(())
772 }
773
774 pub fn set_gc_ref(
776 &mut self,
777 store: Option<&mut GcStore>,
778 index: u64,
779 elem: Option<&VMGcRef>,
780 ) -> Result<()> {
781 let trap = Trap::TableOutOfBounds;
782 let index: usize = index.try_into().map_err(|_| trap)?;
783 GcStore::write_gc_ref_optional_store(
784 store,
785 self.gc_refs_mut().get_mut(index).ok_or(trap)?,
786 elem,
787 )?;
788 Ok(())
789 }
790
791 pub fn vmtable(&mut self) -> VMTableDefinition {
793 match self {
794 Table::Static(StaticTable::Func(StaticFuncTable { data, size, .. })) => {
795 VMTableDefinition {
796 base: data.cast().into(),
797 current_elements: *size,
798 }
799 }
800 Table::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => {
801 VMTableDefinition {
802 base: data.cast().into(),
803 current_elements: *size,
804 }
805 }
806 Table::Static(StaticTable::Cont(StaticContTable { data, size })) => VMTableDefinition {
807 base: data.cast().into(),
808 current_elements: *size,
809 },
810 Table::Dynamic(DynamicTable::Func(DynamicFuncTable { elements, .. })) => {
811 VMTableDefinition {
812 base: NonNull::new(elements.as_mut_ptr()).unwrap().cast().into(),
813 current_elements: elements.len(),
814 }
815 }
816 Table::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => {
817 VMTableDefinition {
818 base: NonNull::new(elements.as_mut_ptr()).unwrap().cast().into(),
819 current_elements: elements.len(),
820 }
821 }
822 Table::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => {
823 VMTableDefinition {
824 base: NonNull::new(elements.as_mut_ptr()).unwrap().cast().into(),
825 current_elements: elements.len(),
826 }
827 }
828 }
829 }
830
831 fn funcrefs(&self) -> (&[MaybeTaggedFuncRef], bool) {
832 assert_eq!(self.element_type(), TableElementType::Func);
833 match self {
834 Self::Dynamic(DynamicTable::Func(DynamicFuncTable {
835 elements,
836 lazy_init,
837 ..
838 })) => (
839 unsafe { slice::from_raw_parts(elements.as_ptr().cast(), elements.len()) },
840 *lazy_init,
841 ),
842 Self::Static(StaticTable::Func(StaticFuncTable {
843 data,
844 size,
845 lazy_init,
846 })) => (
847 unsafe { slice::from_raw_parts(data.as_ptr().cast(), *size) },
848 *lazy_init,
849 ),
850 _ => unreachable!(),
851 }
852 }
853
854 fn funcrefs_mut(&mut self) -> (&mut [MaybeTaggedFuncRef], bool) {
855 assert_eq!(self.element_type(), TableElementType::Func);
856 match self {
857 Self::Dynamic(DynamicTable::Func(DynamicFuncTable {
858 elements,
859 lazy_init,
860 ..
861 })) => (
862 unsafe { slice::from_raw_parts_mut(elements.as_mut_ptr().cast(), elements.len()) },
863 *lazy_init,
864 ),
865 Self::Static(StaticTable::Func(StaticFuncTable {
866 data,
867 size,
868 lazy_init,
869 })) => (
870 unsafe { slice::from_raw_parts_mut(data.as_ptr().cast(), *size) },
871 *lazy_init,
872 ),
873 _ => unreachable!(),
874 }
875 }
876
877 fn gc_refs(&self) -> &[Option<VMGcRef>] {
878 assert_eq!(self.element_type(), TableElementType::GcRef);
879 match self {
880 Self::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => elements,
881 Self::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => unsafe {
882 &data.as_non_null().as_ref()[..*size]
883 },
884 _ => unreachable!(),
885 }
886 }
887
888 fn contrefs(&self) -> &[Option<VMContObj>] {
889 assert_eq!(self.element_type(), TableElementType::Cont);
890 match self {
891 Self::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => unsafe {
892 slice::from_raw_parts(elements.as_ptr().cast(), elements.len())
893 },
894 Self::Static(StaticTable::Cont(StaticContTable { data, size })) => unsafe {
895 slice::from_raw_parts(data.as_ptr().cast(), *size)
896 },
897 _ => unreachable!(),
898 }
899 }
900
901 fn contrefs_mut(&mut self) -> &mut [Option<VMContObj>] {
902 assert_eq!(self.element_type(), TableElementType::Cont);
903 match self {
904 Self::Dynamic(DynamicTable::Cont(DynamicContTable { elements, .. })) => unsafe {
905 slice::from_raw_parts_mut(elements.as_mut_ptr().cast(), elements.len())
906 },
907 Self::Static(StaticTable::Cont(StaticContTable { data, size })) => unsafe {
908 slice::from_raw_parts_mut(data.as_ptr().cast(), *size)
909 },
910 _ => unreachable!(),
911 }
912 }
913
914 pub fn gc_refs_mut(&mut self) -> &mut [Option<VMGcRef>] {
918 assert_eq!(self.element_type(), TableElementType::GcRef);
919 match self {
920 Self::Dynamic(DynamicTable::GcRef(DynamicGcRefTable { elements, .. })) => elements,
921 Self::Static(StaticTable::GcRef(StaticGcRefTable { data, size })) => unsafe {
922 &mut data.as_non_null().as_mut()[..*size]
923 },
924 _ => unreachable!(),
925 }
926 }
927
928 pub fn manually_memset_zeros(&mut self) {
934 match self.element_type() {
935 TableElementType::Func => {
936 let (funcrefs, _lazy_init) = self.funcrefs_mut();
937 funcrefs.fill(MaybeTaggedFuncRef(None));
938 }
939 TableElementType::GcRef => {
940 for r in self.gc_refs_mut() {
944 *r = None;
945 }
946 }
947 TableElementType::Cont => {
948 self.contrefs_mut().fill(None);
949 }
950 }
951 }
952
953 pub fn debug_assert_all_zero(&self) {
954 match self.element_type() {
955 TableElementType::Func => {
956 let (funcrefs, _lazy_init) = self.funcrefs();
957 debug_assert!(funcrefs.iter().all(|f| f.0.is_none()));
958 }
959 TableElementType::GcRef => {
960 debug_assert!(self.gc_refs().iter().all(|r| r.is_none()));
961 }
962 TableElementType::Cont => {
963 debug_assert!(self.contrefs().iter().all(|c| c.is_none()));
964 }
965 }
966 }
967}
968
969impl Default for Table {
971 fn default() -> Self {
972 Self::from(StaticFuncTable {
973 data: SendSyncPtr::new(NonNull::from(&mut [])),
974 size: 0,
975 lazy_init: false,
976 })
977 }
978}