1use crate::{
40 DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, FuncIndex,
41 FuncRefIndex, GlobalIndex, MemoryIndex, Module, OwnedMemoryIndex, RuntimeDataIndex, TableIndex,
42 TagIndex,
43};
44use cranelift_entity::packed_option::ReservedValue;
45
46pub const NUM_COMPONENT_CONTEXT_SLOTS: usize = 2;
49
50#[cfg(target_pointer_width = "32")]
51fn cast_to_u32(sz: usize) -> u32 {
52 u32::try_from(sz).unwrap()
53}
54#[cfg(target_pointer_width = "64")]
55fn cast_to_u32(sz: usize) -> u32 {
56 u32::try_from(sz).expect("overflow in cast from usize to u32")
57}
58
59#[inline]
61fn align(offset: u32, width: u32) -> u32 {
62 (offset + (width - 1)) / width * width
63}
64
65macro_rules! define_vm_type_offsets {
69 (@size ($p:expr) UnsafeCell < $inner:tt >) => { define_vm_type_offsets!(@size ($p) $inner) };
72
73 (@size ($p:expr) VmPtr < $g:ty >) => { u32::from($p) };
79 (@size ($p:expr) Option < VmPtr < $g:ty >>) => { u32::from($p) };
80 (@size ($p:expr) AtomicUsize) => { u32::from($p) };
81 (@size ($p:expr) usize) => { u32::from($p) };
82 (@size ($p:expr) i64) => { 8u32 };
83 (@size ($p:expr) u64) => { 8u32 };
84 (@size ($p:expr) u32) => { 4u32 };
85 (@size ($p:expr) [u8; 16]) => { 16u32 };
86 (@size ($p:expr) [u32; $n:expr]) => { 4u32 * u32::try_from($n).unwrap() };
87 (@size ($p:expr) VMSharedTypeIndex) => { u32::from(($p).size_of_vmshared_type_index()) };
88 (@size ($p:expr) DefinedTableIndex) => { 4u32 };
89 (@size ($p:expr) DefinedMemoryIndex) => { 4u32 };
90 (@size ($p:expr) DefinedTagIndex) => { 4u32 };
91 (@size ($p:expr) VMGlobalKind) => { 8u32 };
92 (@size ($p:expr) Range < *mut u8 >) => { 2u32 * u32::from($p) };
94 (@size ($p:expr) VMMemoryDefinition) => { u32::from(($p).vm_memory_definition().size()) };
97 (@size ($p:expr) VMLazyThread) => { u32::from(($p).vm_lazy_thread().size()) };
98 (@size ($p:expr) VMStackChain) => { u32::from(($p).size_of_vmstack_chain()) };
101
102 (@align ($p:expr) UnsafeCell < $inner:tt >) => { define_vm_type_offsets!(@align ($p) $inner) };
104
105 (@align ($p:expr) VmPtr < $g:ty >) => { u32::from($p) };
113 (@align ($p:expr) Option < VmPtr < $g:ty >>) => { u32::from($p) };
114 (@align ($p:expr) AtomicUsize) => { u32::from($p) };
115 (@align ($p:expr) usize) => { u32::from($p) };
116 (@align ($p:expr) i64) => { 8u32 };
117 (@align ($p:expr) u64) => { 8u32 };
118 (@align ($p:expr) u32) => { 4u32 };
119 (@align ($p:expr) [u8; 16]) => { 16u32 };
120 (@align ($p:expr) [u32; $n:expr]) => { 4u32 };
121 (@align ($p:expr) VMSharedTypeIndex) => { u32::from(($p).align_of_vmshared_type_index()) };
122 (@align ($p:expr) DefinedTableIndex) => { 4u32 };
123 (@align ($p:expr) DefinedMemoryIndex) => { 4u32 };
124 (@align ($p:expr) DefinedTagIndex) => { 4u32 };
125 (@align ($p:expr) VMGlobalKind) => { 4u32 };
126 (@align ($p:expr) Range < *mut u8 >) => { u32::from($p) };
127 (@align ($p:expr) VMMemoryDefinition) => { u32::from(($p).vm_memory_definition().align()) };
128 (@align ($p:expr) VMLazyThread) => { u32::from(($p).vm_lazy_thread().align()) };
129 (@align ($p:expr) VMStackChain) => { u32::from($p) };
130
131 (@repr_align C) => { 1u32 };
133 (@repr_align transparent) => { 1u32 };
134 (@repr_align C, align($n:literal)) => {{ let align: u32 = $n; align }};
135
136 (@fields $Name:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )) => {};
146 (@fields $Name:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )
147 [ $fname:ident : $($fty:tt)* ]
148 $($rest:tt)*
149 ) => {
150 #[doc = concat!(
151 "The offset of the `", stringify!($fname),
152 "` field of `", stringify!($Name), "`."
153 )]
154 #[inline]
155 pub fn $fname(&self) -> u8 {
156 let $p = self.0.size();
157 let $o: u32 = 0;
158 $($prefix)*
159 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
160 let _ = $p;
161 u8::try_from($o).unwrap()
162 }
163 define_vm_type_offsets!(@fields $Name ($p, $o)
164 prefix(
165 $($prefix)*
166 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
167 let $o = $o + define_vm_type_offsets!(@size ($p) $($fty)*);
168 )
169 $($rest)*
170 );
171 };
172
173 (@impl $Name:ident [$($repr:tt)*] { $( [ $fname:ident : $($fty:tt)* ] )* }) => {
183 impl<P: PtrSize> $Name<P> {
184 define_vm_type_offsets!(@fields $Name (p, o) prefix()
185 $( [ $fname : $($fty)* ] )*
186 );
187
188 #[doc = concat!("The alignment of the `", stringify!($Name), "` type.")]
189 #[inline]
190 pub fn align(&self) -> u8 {
191 let p = self.0.size();
192 let a: u32 = define_vm_type_offsets!(@repr_align $($repr)*);
193 $(
194 let a = core::cmp::max(
195 a,
196 define_vm_type_offsets!(@align (p) $($fty)*),
197 );
198 )*
199 let _ = p;
200 u8::try_from(a).unwrap()
201 }
202
203 #[doc = concat!("The size of the `", stringify!($Name), "` type.")]
204 #[inline]
205 pub fn size(&self) -> u8 {
206 let p = self.0.size();
207 let o: u32 = 0;
208 $(
209 let o = align(o, define_vm_type_offsets!(@align (p) $($fty)*));
210 let o = o + define_vm_type_offsets!(@size (p) $($fty)*);
211 )*
212 let o = align(o, u32::from(self.align()));
213 let _ = p;
214 u8::try_from(o).unwrap()
215 }
216 }
217 };
218 (@impl $Name:ident $repr:tt { $($groups:tt)* }
223 $(#[$($attr:tt)*])* $fvis:vis $fname:ident : $($rest:tt)*
224 ) => {
225 define_vm_type_offsets!(@impl_ty $Name $repr { $($groups)* } $fname [] $($rest)*);
226 };
227 (@impl_ty $Name:ident $repr:tt { $($groups:tt)* } $fname:ident [ $($fty:tt)* ] , $($rest:tt)*) => {
230 define_vm_type_offsets!(@impl $Name $repr { $($groups)* [ $fname : $($fty)* ] } $($rest)*);
231 };
232 (@impl_ty $Name:ident $repr:tt { $($groups:tt)* } $fname:ident [ $($fty:tt)* ] $tok:tt $($rest:tt)*) => {
233 define_vm_type_offsets!(@impl_ty $Name $repr { $($groups)* } $fname [ $($fty)* $tok ] $($rest)*);
234 };
235
236 ( $(
238 $(#[doc = $sdoc:literal])*
239 $(#[derive($($d:ident),*)])?
240 #[repr($($repr:tt)*)]
241 #[snake_name = $snake:ident]
242 $svis:vis struct $Name:ident {
243 $($body:tt)*
244 }
245 )* ) => {
246 pub mod offsets {
253 use super::{align, PtrSize, NUM_COMPONENT_CONTEXT_SLOTS};
254
255 $(
256 #[doc = concat!("Offsets of fields within the `", stringify!($Name), "` type.")]
257 pub struct $Name<P: PtrSize>(pub P);
258
259 define_vm_type_offsets!(@impl $Name [$($repr)*] {} $($body)*);
260 )*
261 }
262 };
263}
264for_each_vm_type!(define_vm_type_offsets);
265
266const COMPONENT_CONTEXT_SLOT_SIZE: u8 = 4;
270
271impl<P: PtrSize> offsets::VMStoreContext<P> {
274 pub fn gc_heap_base(&self) -> u8 {
276 let offset = self.gc_heap() + self.0.vm_memory_definition().base();
277 debug_assert!(offset < self.last_wasm_exit_trampoline_fp());
278 offset
279 }
280
281 pub fn gc_heap_current_length(&self) -> u8 {
284 let offset = self.gc_heap() + self.0.vm_memory_definition().current_length();
285 debug_assert!(offset < self.last_wasm_exit_trampoline_fp());
286 offset
287 }
288
289 pub fn component_context_slot(&self, i: u8) -> u8 {
291 assert!(usize::from(i) < NUM_COMPONENT_CONTEXT_SLOTS);
292 self.component_context() + i * COMPONENT_CONTEXT_SLOT_SIZE
293 }
294}
295
296impl<P: PtrSize> offsets::VMDeferredThread<P> {
299 pub fn saved_context_slot(&self, i: u8) -> u8 {
301 assert!(usize::from(i) < NUM_COMPONENT_CONTEXT_SLOTS);
302 self.saved_context() + i * COMPONENT_CONTEXT_SLOT_SIZE
303 }
304}
305
306macro_rules! define_ptr_size_vm_type_accessors {
310 ( $(
311 $(#[doc = $sdoc:literal])*
312 $(#[derive($($d:ident),*)])?
313 #[repr($($repr:tt)*)]
314 #[snake_name = $snake:ident]
315 $svis:vis struct $Name:ident {
316 $($body:tt)*
319 }
320 )* ) => {
321 $(
322 #[doc = concat!("Get the [`offsets::", stringify!($Name), "`] offsets for this pointer size.")]
323 #[inline]
324 fn $snake(&self) -> offsets::$Name<&Self> {
325 offsets::$Name(self)
326 }
327 )*
328 };
329}
330
331#[derive(Debug, Clone, Copy)]
334pub struct VMOffsets<P> {
335 pub ptr: P,
337 pub num_imported_functions: u32,
339 pub num_imported_tables: u32,
341 pub num_imported_memories: u32,
343 pub num_imported_globals: u32,
345 pub num_imported_tags: u32,
347 pub num_defined_tables: u32,
349 pub num_defined_memories: u32,
351 pub num_owned_memories: u32,
353 pub num_defined_globals: u32,
355 pub num_defined_tags: u32,
357 pub num_escaped_funcs: u32,
360 pub num_runtime_data: u32,
362 pub has_startup_func: bool,
364
365 imported_functions: u32,
367 imported_tables: u32,
368 imported_memories: u32,
369 imported_globals: u32,
370 imported_tags: u32,
371 defined_tables: u32,
372 defined_memories: u32,
373 owned_memories: u32,
374 defined_globals: u32,
375 defined_tags: u32,
376 defined_func_refs: u32,
377 startup_func_ref: u32,
378 runtime_data_bases: u32,
379 runtime_data_lengths: u32,
380 size: u32,
381}
382
383pub trait PtrSize {
385 fn size(&self) -> u8;
387
388 for_each_vm_type!(define_ptr_size_vm_type_accessors);
392
393 fn vmcontext_store_context(&self) -> u8 {
395 u8::try_from(align(
396 u32::try_from(core::mem::size_of::<u32>()).unwrap(),
397 u32::from(self.size()),
398 ))
399 .unwrap()
400 }
401
402 fn vmcontext_builtin_functions(&self) -> u8 {
404 self.vmcontext_store_context() + self.size()
405 }
406
407 #[inline]
409 fn size_of_vmshared_type_index(&self) -> u8 {
410 4
411 }
412
413 #[inline]
415 fn align_of_vmshared_type_index(&self) -> u8 {
416 4
417 }
418
419 #[inline]
421 fn maximum_value_size(&self) -> u8 {
422 self.vm_global_definition().size()
423 }
424
425 #[inline]
427 fn size_of_vmmemory_pointer(&self) -> u8 {
428 self.size()
429 }
430
431 fn vmarray_call_host_func_context_func_ref(&self) -> u8 {
435 u8::try_from(align(
436 u32::try_from(core::mem::size_of::<u32>()).unwrap(),
437 u32::from(self.size()),
438 ))
439 .unwrap()
440 }
441
442 fn size_of_vmstack_chain(&self) -> u8 {
444 2 * self.size()
445 }
446
447 fn vmstack_limits_stack_limit(&self) -> u8 {
451 0
452 }
453
454 fn vmstack_limits_last_wasm_entry_fp(&self) -> u8 {
456 self.size()
457 }
458
459 fn vmstack_limits_last_wasm_entry_sp(&self) -> u8 {
461 self.vmstack_limits_last_wasm_entry_fp() + self.size()
462 }
463
464 fn vmstack_limits_last_wasm_entry_trap_handler(&self) -> u8 {
466 self.vmstack_limits_last_wasm_entry_sp() + self.size()
467 }
468
469 fn vmhostarray_length(&self) -> u8 {
473 0
474 }
475
476 fn vmhostarray_capacity(&self) -> u8 {
478 4
479 }
480
481 fn vmhostarray_data(&self) -> u8 {
483 8
484 }
485
486 fn size_of_vmhostarray(&self) -> u8 {
488 8 + self.size()
489 }
490
491 fn vmcommon_stack_information_limits(&self) -> u8 {
495 0 * self.size()
496 }
497
498 fn vmcommon_stack_information_state(&self) -> u8 {
500 4 * self.size()
501 }
502
503 fn vmcommon_stack_information_handlers(&self) -> u8 {
505 u8::try_from(align(
506 self.vmcommon_stack_information_state() as u32 + 4,
507 u32::from(self.size()),
508 ))
509 .unwrap()
510 }
511
512 fn vmcommon_stack_information_first_switch_handler_index(&self) -> u8 {
514 self.vmcommon_stack_information_handlers() + self.size_of_vmhostarray()
515 }
516
517 fn size_of_vmcommon_stack_information(&self) -> u8 {
519 u8::try_from(align(
520 self.vmcommon_stack_information_first_switch_handler_index() as u32 + 4,
521 u32::from(self.size()),
522 ))
523 .unwrap()
524 }
525
526 fn vmcontobj_contref(&self) -> u8 {
530 0
531 }
532
533 fn vmcontobj_revision(&self) -> u8 {
535 self.size()
536 }
537
538 fn size_of_vmcontobj(&self) -> u8 {
540 u8::try_from(align(
541 u32::from(self.vmcontobj_revision())
542 + u32::try_from(core::mem::size_of::<usize>()).unwrap(),
543 u32::from(self.size()),
544 ))
545 .unwrap()
546 }
547
548 fn vmcontref_common_stack_information(&self) -> u8 {
552 0 * self.size()
553 }
554
555 fn vmcontref_parent_chain(&self) -> u8 {
557 u8::try_from(align(
558 (self.vmcontref_common_stack_information() + self.size_of_vmcommon_stack_information())
559 as u32,
560 u32::from(self.size()),
561 ))
562 .unwrap()
563 }
564
565 fn vmcontref_last_ancestor(&self) -> u8 {
567 self.vmcontref_parent_chain() + 2 * self.size()
568 }
569
570 fn vmcontref_revision(&self) -> u8 {
572 self.vmcontref_last_ancestor() + self.size()
573 }
574
575 fn vmcontref_stack(&self) -> u8 {
577 self.vmcontref_revision() + self.size()
578 }
579
580 fn vmcontref_args(&self) -> u8 {
582 self.vmcontref_stack() + 3 * self.size()
583 }
584
585 fn vmcontref_values(&self) -> u8 {
587 self.vmcontref_args() + self.size_of_vmhostarray()
588 }
589
590 #[inline]
592 fn vmctx_magic(&self) -> u8 {
593 0
597 }
598
599 #[inline]
601 fn vmctx_store_context(&self) -> u8 {
602 self.vmctx_magic() + self.size()
603 }
604
605 #[inline]
607 fn vmctx_builtin_functions(&self) -> u8 {
608 self.vmctx_store_context() + self.size()
609 }
610
611 #[inline]
614 fn vmctx_epoch_ptr(&self) -> u8 {
615 self.vmctx_builtin_functions() + self.size()
616 }
617
618 #[inline]
623 fn vmctx_gc_heap_data(&self) -> u8 {
624 self.vmctx_epoch_ptr() + self.size()
625 }
626
627 #[inline]
630 fn vmdrc_heap_data_over_approximated_stack_roots(&self) -> u8 {
631 0
632 }
633
634 #[inline]
637 fn vmdrc_heap_data_current_over_approximated_stack_roots_len(&self) -> u8 {
638 4
639 }
640
641 #[inline]
645 fn vmdrc_heap_data_over_approximated_stack_roots_len_after_last_gc(&self) -> u8 {
646 8
647 }
648
649 #[inline]
651 fn size_of_vmdrc_heap_data(&self) -> u8 {
652 12
653 }
654
655 #[inline]
657 fn align_of_vmdrc_heap_data(&self) -> u8 {
658 4
659 }
660
661 #[inline]
663 fn vmcopying_heap_data_bump_ptr(&self) -> u8 {
664 0
665 }
666
667 #[inline]
670 fn vmcopying_heap_data_active_space_end(&self) -> u8 {
671 4
672 }
673
674 #[inline]
676 fn size_of_vmcopying_heap_data(&self) -> u8 {
677 8
678 }
679
680 #[inline]
682 fn align_of_vmcopying_heap_data(&self) -> u8 {
683 4
684 }
685
686 #[inline]
688 fn vmctx_type_ids_array(&self) -> u8 {
689 self.vmctx_gc_heap_data() + self.size()
690 }
691
692 #[inline]
696 fn vmctx_dynamic_data_start(&self) -> u8 {
697 self.vmctx_type_ids_array() + self.size()
698 }
699}
700
701pub trait GetPtrSize {
703 type Ptr: PtrSize;
705
706 fn get_ptr_size(&self) -> &Self::Ptr;
708}
709
710impl<P> GetPtrSize for P
711where
712 P: PtrSize,
713{
714 type Ptr = Self;
715
716 #[inline]
717 fn get_ptr_size(&self) -> &Self::Ptr {
718 self
719 }
720}
721
722#[derive(Clone, Copy)]
724pub struct HostPtr;
725
726impl PtrSize for HostPtr {
727 #[inline]
728 fn size(&self) -> u8 {
729 core::mem::size_of::<usize>() as u8
730 }
731}
732
733impl PtrSize for u8 {
734 #[inline]
735 fn size(&self) -> u8 {
736 *self
737 }
738}
739
740impl<P> PtrSize for &'_ P
741where
742 P: PtrSize + ?Sized,
743{
744 #[inline]
745 fn size(&self) -> u8 {
746 (**self).size()
747 }
748}
749
750#[derive(Debug, Clone, Copy)]
752pub struct VMOffsetsFields<P> {
753 pub ptr: P,
755 pub num_imported_functions: u32,
757 pub num_imported_tables: u32,
759 pub num_imported_memories: u32,
761 pub num_imported_globals: u32,
763 pub num_imported_tags: u32,
765 pub num_defined_tables: u32,
767 pub num_defined_memories: u32,
769 pub num_owned_memories: u32,
771 pub num_defined_globals: u32,
773 pub num_defined_tags: u32,
775 pub num_escaped_funcs: u32,
778 pub num_runtime_data: u32,
780 pub has_startup_func: bool,
782}
783
784impl<P: PtrSize> VMOffsets<P> {
785 pub fn new(ptr: P, module: &Module) -> Self {
787 let num_owned_memories = module
788 .memories
789 .iter()
790 .skip(module.num_imported_memories)
791 .filter(|p| !p.1.shared)
792 .count()
793 .try_into()
794 .unwrap();
795 VMOffsets::from(VMOffsetsFields {
796 ptr,
797 num_imported_functions: cast_to_u32(module.num_imported_funcs),
798 num_imported_tables: cast_to_u32(module.num_imported_tables),
799 num_imported_memories: cast_to_u32(module.num_imported_memories),
800 num_imported_globals: cast_to_u32(module.num_imported_globals),
801 num_imported_tags: cast_to_u32(module.num_imported_tags),
802 num_defined_tables: cast_to_u32(module.num_defined_tables()),
803 num_defined_memories: cast_to_u32(module.num_defined_memories()),
804 num_owned_memories,
805 num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),
806 num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),
807 num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),
808 num_runtime_data: cast_to_u32(module.runtime_data.len()),
809 has_startup_func: !module.startup.is_none(),
810 })
811 }
812
813 #[inline]
815 pub fn pointer_size(&self) -> u8 {
816 self.ptr.size()
817 }
818
819 pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {
824 macro_rules! calculate_sizes {
825 ($($name:ident: $desc:tt,)*) => {{
826 let VMOffsets {
827 ptr: _,
830 num_imported_functions: _,
831 num_imported_tables: _,
832 num_imported_memories: _,
833 num_imported_globals: _,
834 num_imported_tags: _,
835 num_defined_tables: _,
836 num_defined_globals: _,
837 num_defined_memories: _,
838 num_defined_tags: _,
839 num_owned_memories: _,
840 num_escaped_funcs: _,
841 num_runtime_data: _,
842 has_startup_func: _,
843
844 size,
846
847 $($name,)*
850 } = *self;
851
852 let mut last = size;
856 $(
857 assert!($name <= last);
858 let tmp = $name;
859 let $name = last - $name;
860 last = tmp;
861 )*
862 assert_ne!(last, 0);
863 IntoIterator::into_iter([
864 $(($desc, $name),)*
865 ("static vmctx data", last),
866 ])
867 }};
868 }
869
870 calculate_sizes! {
871 runtime_data_lengths: "runtime data lengths",
872 runtime_data_bases: "runtime data base pointers",
873 startup_func_ref: "startup funcref",
874 defined_func_refs: "module functions",
875 defined_tags: "defined tags",
876 defined_globals: "defined globals",
877 defined_tables: "defined tables",
878 imported_tags: "imported tags",
879 imported_globals: "imported globals",
880 imported_tables: "imported tables",
881 imported_functions: "imported functions",
882 owned_memories: "owned memories",
883 defined_memories: "defined memories",
884 imported_memories: "imported memories",
885 }
886 }
887}
888
889impl<P: PtrSize> GetPtrSize for VMOffsets<P> {
890 type Ptr = P;
891
892 #[inline]
893 fn get_ptr_size(&self) -> &Self::Ptr {
894 &self.ptr
895 }
896}
897
898impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {
899 fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {
900 let mut ret = Self {
901 ptr: fields.ptr,
902 num_imported_functions: fields.num_imported_functions,
903 num_imported_tables: fields.num_imported_tables,
904 num_imported_memories: fields.num_imported_memories,
905 num_imported_globals: fields.num_imported_globals,
906 num_imported_tags: fields.num_imported_tags,
907 num_defined_tables: fields.num_defined_tables,
908 num_defined_memories: fields.num_defined_memories,
909 num_owned_memories: fields.num_owned_memories,
910 num_defined_globals: fields.num_defined_globals,
911 num_defined_tags: fields.num_defined_tags,
912 num_escaped_funcs: fields.num_escaped_funcs,
913 num_runtime_data: fields.num_runtime_data,
914 has_startup_func: fields.has_startup_func,
915 imported_functions: 0,
916 imported_tables: 0,
917 imported_memories: 0,
918 imported_globals: 0,
919 imported_tags: 0,
920 defined_tables: 0,
921 defined_memories: 0,
922 owned_memories: 0,
923 defined_globals: 0,
924 defined_tags: 0,
925 defined_func_refs: 0,
926 startup_func_ref: 0,
927 runtime_data_bases: 0,
928 runtime_data_lengths: 0,
929 size: 0,
930 };
931
932 #[inline]
937 fn cadd(count: u32, size: u32) -> u32 {
938 count.checked_add(size).unwrap()
939 }
940
941 #[inline]
942 fn cmul(count: u32, size: u8) -> u32 {
943 count.checked_mul(u32::from(size)).unwrap()
944 }
945
946 let mut next_field_offset = u32::from(ret.ptr.vmctx_dynamic_data_start());
947
948 macro_rules! fields {
949 (size($field:ident) = $size:expr, $($rest:tt)*) => {
950 ret.$field = next_field_offset;
951 next_field_offset = cadd(next_field_offset, u32::from($size));
952 fields!($($rest)*);
953 };
954 (align($align:expr), $($rest:tt)*) => {
955 next_field_offset = align(next_field_offset, $align);
956 fields!($($rest)*);
957 };
958 () => {};
959 }
960
961 fields! {
962 size(imported_memories)
963 = cmul(ret.num_imported_memories, ret.ptr.vm_memory_import().size()),
964 size(defined_memories)
965 = cmul(ret.num_defined_memories, ret.ptr.size_of_vmmemory_pointer()),
966 size(owned_memories)
967 = cmul(ret.num_owned_memories, ret.ptr.vm_memory_definition().size()),
968 size(imported_functions)
969 = cmul(ret.num_imported_functions, ret.ptr.vm_function_import().size()),
970 size(imported_tables)
971 = cmul(ret.num_imported_tables, ret.ptr.vm_table_import().size()),
972 size(imported_globals)
973 = cmul(ret.num_imported_globals, ret.ptr.vm_global_import().size()),
974 size(imported_tags)
975 = cmul(ret.num_imported_tags, ret.ptr.vm_tag_import().size()),
976 size(defined_tables)
977 = cmul(ret.num_defined_tables, ret.ptr.vm_table_definition().size()),
978 align(16),
979 size(defined_globals)
980 = cmul(ret.num_defined_globals, ret.ptr.vm_global_definition().size()),
981 size(defined_tags)
982 = cmul(ret.num_defined_tags, ret.ptr.vm_tag_definition().size()),
983 size(defined_func_refs) = cmul(
984 ret.num_escaped_funcs,
985 ret.ptr.vm_func_ref().size(),
986 ),
987 size(startup_func_ref) = if ret.has_startup_func {
988 ret.ptr.vm_func_ref().size()
989 } else {
990 0
991 },
992 size(runtime_data_bases) = cmul(ret.num_runtime_data, ret.ptr.size()),
993 size(runtime_data_lengths) = cmul(ret.num_runtime_data, 4),
994 }
995
996 ret.size = next_field_offset;
997
998 return ret;
999 }
1000}
1001
1002impl<P: PtrSize> VMOffsets<P> {
1004 pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
1006 1 * self.pointer_size()
1007 }
1008}
1009
1010impl<P: PtrSize> VMOffsets<P> {
1012 #[inline]
1014 pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {
1015 self.pointer_size()
1016 }
1017}
1018
1019impl<P: PtrSize> VMOffsets<P> {
1021 #[inline]
1023 pub fn size_of_vmshared_type_index(&self) -> u8 {
1024 self.ptr.size_of_vmshared_type_index()
1025 }
1026}
1027
1028impl<P: PtrSize> VMOffsets<P> {
1030 #[inline]
1032 pub fn vmctx_imported_functions_begin(&self) -> u32 {
1033 self.imported_functions
1034 }
1035
1036 #[inline]
1038 pub fn vmctx_imported_tables_begin(&self) -> u32 {
1039 self.imported_tables
1040 }
1041
1042 #[inline]
1044 pub fn vmctx_imported_memories_begin(&self) -> u32 {
1045 self.imported_memories
1046 }
1047
1048 #[inline]
1050 pub fn vmctx_imported_globals_begin(&self) -> u32 {
1051 self.imported_globals
1052 }
1053
1054 #[inline]
1056 pub fn vmctx_imported_tags_begin(&self) -> u32 {
1057 self.imported_tags
1058 }
1059
1060 #[inline]
1062 pub fn vmctx_tables_begin(&self) -> u32 {
1063 self.defined_tables
1064 }
1065
1066 #[inline]
1068 pub fn vmctx_memories_begin(&self) -> u32 {
1069 self.defined_memories
1070 }
1071
1072 #[inline]
1074 pub fn vmctx_owned_memories_begin(&self) -> u32 {
1075 self.owned_memories
1076 }
1077
1078 #[inline]
1080 pub fn vmctx_globals_begin(&self) -> u32 {
1081 self.defined_globals
1082 }
1083
1084 #[inline]
1086 pub fn vmctx_tags_begin(&self) -> u32 {
1087 self.defined_tags
1088 }
1089
1090 #[inline]
1092 pub fn vmctx_func_refs_begin(&self) -> u32 {
1093 self.defined_func_refs
1094 }
1095
1096 #[inline]
1098 pub fn vmctx_runtime_data_bases_begin(&self) -> u32 {
1099 self.runtime_data_bases
1100 }
1101
1102 #[inline]
1104 pub fn vmctx_runtime_data_lengths_begin(&self) -> u32 {
1105 self.runtime_data_lengths
1106 }
1107
1108 #[inline]
1110 pub fn size_of_vmctx(&self) -> u32 {
1111 self.size
1112 }
1113
1114 #[inline]
1116 pub fn vmctx_vmfunction_import(&self, index: FuncIndex) -> u32 {
1117 assert!(index.as_u32() < self.num_imported_functions);
1118 self.vmctx_imported_functions_begin()
1119 + index.as_u32() * u32::from(self.ptr.vm_function_import().size())
1120 }
1121
1122 #[inline]
1124 pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {
1125 assert!(index.as_u32() < self.num_imported_tables);
1126 self.vmctx_imported_tables_begin()
1127 + index.as_u32() * u32::from(self.ptr.vm_table_import().size())
1128 }
1129
1130 #[inline]
1132 pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {
1133 assert!(index.as_u32() < self.num_imported_memories);
1134 self.vmctx_imported_memories_begin()
1135 + index.as_u32() * u32::from(self.ptr.vm_memory_import().size())
1136 }
1137
1138 #[inline]
1140 pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {
1141 assert!(index.as_u32() < self.num_imported_globals);
1142 self.vmctx_imported_globals_begin()
1143 + index.as_u32() * u32::from(self.ptr.vm_global_import().size())
1144 }
1145
1146 #[inline]
1148 pub fn vmctx_vmtag_import(&self, index: TagIndex) -> u32 {
1149 assert!(index.as_u32() < self.num_imported_tags);
1150 self.vmctx_imported_tags_begin()
1151 + index.as_u32() * u32::from(self.ptr.vm_tag_import().size())
1152 }
1153
1154 #[inline]
1156 pub fn vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32 {
1157 assert!(index.as_u32() < self.num_defined_tables);
1158 self.vmctx_tables_begin()
1159 + index.as_u32() * u32::from(self.ptr.vm_table_definition().size())
1160 }
1161
1162 #[inline]
1164 pub fn vmctx_vmmemory_pointer(&self, index: DefinedMemoryIndex) -> u32 {
1165 assert!(index.as_u32() < self.num_defined_memories);
1166 self.vmctx_memories_begin()
1167 + index.as_u32() * u32::from(self.ptr.size_of_vmmemory_pointer())
1168 }
1169
1170 #[inline]
1172 pub fn vmctx_vmmemory_definition(&self, index: OwnedMemoryIndex) -> u32 {
1173 assert!(index.as_u32() < self.num_owned_memories);
1174 self.vmctx_owned_memories_begin()
1175 + index.as_u32() * u32::from(self.ptr.vm_memory_definition().size())
1176 }
1177
1178 #[inline]
1180 pub fn vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32 {
1181 assert!(index.as_u32() < self.num_defined_globals);
1182 self.vmctx_globals_begin()
1183 + index.as_u32() * u32::from(self.ptr.vm_global_definition().size())
1184 }
1185
1186 #[inline]
1188 pub fn vmctx_vmtag_definition(&self, index: DefinedTagIndex) -> u32 {
1189 assert!(index.as_u32() < self.num_defined_tags);
1190 self.vmctx_tags_begin() + index.as_u32() * u32::from(self.ptr.vm_tag_definition().size())
1191 }
1192
1193 #[inline]
1196 pub fn vmctx_func_ref(&self, index: FuncRefIndex) -> u32 {
1197 assert!(!index.is_reserved_value());
1198 assert!(index.as_u32() < self.num_escaped_funcs);
1199 self.vmctx_func_refs_begin() + index.as_u32() * u32::from(self.ptr.vm_func_ref().size())
1200 }
1201
1202 #[inline]
1206 pub fn vmctx_startup_func_ref(&self) -> u32 {
1207 assert!(self.has_startup_func);
1208 self.startup_func_ref
1209 }
1210
1211 #[inline]
1213 pub fn vmctx_runtime_data_base(&self, index: RuntimeDataIndex) -> u32 {
1214 assert!(!index.is_reserved_value());
1215 assert!(index.as_u32() < self.num_runtime_data);
1216 self.vmctx_runtime_data_bases_begin() + index.as_u32() * u32::from(self.ptr.size())
1217 }
1218
1219 #[inline]
1221 pub fn vmctx_runtime_data_length(&self, index: RuntimeDataIndex) -> u32 {
1222 assert!(!index.is_reserved_value());
1223 assert!(index.as_u32() < self.num_runtime_data);
1224 self.vmctx_runtime_data_lengths_begin() + index.as_u32() * 4
1225 }
1226
1227 #[inline]
1229 pub fn vmctx_vmfunction_import_wasm_call(&self, index: FuncIndex) -> u32 {
1230 self.vmctx_vmfunction_import(index) + u32::from(self.ptr.vm_function_import().wasm_call())
1231 }
1232
1233 #[inline]
1235 pub fn vmctx_vmfunction_import_array_call(&self, index: FuncIndex) -> u32 {
1236 self.vmctx_vmfunction_import(index) + u32::from(self.ptr.vm_function_import().array_call())
1237 }
1238
1239 #[inline]
1241 pub fn vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32 {
1242 self.vmctx_vmfunction_import(index) + u32::from(self.ptr.vm_function_import().vmctx())
1243 }
1244
1245 #[inline]
1248 pub fn vmctx_vmtable_from(&self, index: TableIndex) -> u32 {
1249 self.vmctx_vmtable_import(index) + u32::from(self.ptr.vm_table_import().from())
1250 }
1251
1252 #[inline]
1254 pub fn vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32 {
1255 self.vmctx_vmtable_definition(index) + u32::from(self.ptr.vm_table_definition().base())
1256 }
1257
1258 #[inline]
1260 pub fn vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32 {
1261 self.vmctx_vmtable_definition(index)
1262 + u32::from(self.ptr.vm_table_definition().current_elements())
1263 }
1264
1265 #[inline]
1267 pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {
1268 self.vmctx_vmmemory_import(index) + u32::from(self.ptr.vm_memory_import().from())
1269 }
1270
1271 #[inline]
1273 pub fn vmctx_vmmemory_definition_base(&self, index: OwnedMemoryIndex) -> u32 {
1274 self.vmctx_vmmemory_definition(index) + u32::from(self.ptr.vm_memory_definition().base())
1275 }
1276
1277 #[inline]
1279 pub fn vmctx_vmmemory_definition_current_length(&self, index: OwnedMemoryIndex) -> u32 {
1280 self.vmctx_vmmemory_definition(index)
1281 + u32::from(self.ptr.vm_memory_definition().current_length())
1282 }
1283
1284 #[inline]
1286 pub fn vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32 {
1287 self.vmctx_vmglobal_import(index) + u32::from(self.ptr.vm_global_import().from())
1288 }
1289
1290 #[inline]
1292 pub fn vmctx_vmtag_import_from(&self, index: TagIndex) -> u32 {
1293 self.vmctx_vmtag_import(index) + u32::from(self.ptr.vm_tag_import().from())
1294 }
1295
1296 #[inline]
1298 pub fn vmctx_vmtag_import_vmctx(&self, index: TagIndex) -> u32 {
1299 self.vmctx_vmtag_import(index) + u32::from(self.ptr.vm_tag_import().vmctx())
1300 }
1301
1302 #[inline]
1304 pub fn vmctx_vmtag_import_index(&self, index: TagIndex) -> u32 {
1305 self.vmctx_vmtag_import(index) + u32::from(self.ptr.vm_tag_import().index())
1306 }
1307}
1308
1309impl<P: PtrSize> VMOffsets<P> {
1311 #[inline]
1313 pub fn vm_gc_header_kind(&self) -> u32 {
1314 0
1315 }
1316
1317 #[inline]
1319 pub fn vm_gc_header_reserved_bits(&self) -> u32 {
1320 self.vm_gc_header_kind()
1322 }
1323
1324 #[inline]
1326 pub fn vm_gc_header_ty(&self) -> u32 {
1327 self.vm_gc_header_kind() + 4
1328 }
1329}
1330
1331impl<P: PtrSize> VMOffsets<P> {
1335 #[inline]
1337 pub fn vm_drc_header_ref_count(&self) -> u32 {
1338 8
1339 }
1340
1341 #[inline]
1343 pub fn vm_drc_header_next_over_approximated_stack_root(&self) -> u32 {
1344 self.vm_drc_header_ref_count() + 8
1345 }
1346}
1347
1348pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");
1352
1353pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");
1358
1359#[cfg(test)]
1360mod tests {
1361 use crate::vmoffsets::align;
1362
1363 #[test]
1364 fn alignment() {
1365 fn is_aligned(x: u32) -> bool {
1366 x % 16 == 0
1367 }
1368 assert!(is_aligned(align(0, 16)));
1369 assert!(is_aligned(align(32, 16)));
1370 assert!(is_aligned(align(33, 16)));
1371 assert!(is_aligned(align(31, 16)));
1372 }
1373}
1374
1375pub const VM_LAZY_THREAD_FORCED: u64 = 1;