1use crate::{
10 DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, FuncIndex,
11 FuncRefIndex, GlobalIndex, MemoryIndex, Module, ModuleInternedTypeIndex, OwnedMemoryIndex,
12 RuntimeDataIndex, TableIndex, TagIndex,
13};
14
15pub const NUM_COMPONENT_CONTEXT_SLOTS: usize = 2;
18
19#[cfg(target_pointer_width = "32")]
20fn cast_to_u32(sz: usize) -> u32 {
21 u32::try_from(sz).unwrap()
22}
23#[cfg(target_pointer_width = "64")]
24fn cast_to_u32(sz: usize) -> u32 {
25 u32::try_from(sz).expect("overflow in cast from usize to u32")
26}
27
28#[inline]
30fn align(offset: u32, width: u32) -> u32 {
31 (offset + (width - 1)) / width * width
32}
33
34macro_rules! define_vm_type_offsets {
38 (@size ($p:expr) UnsafeCell < $inner:tt >) => { define_vm_type_offsets!(@size ($p) $inner) };
41
42 (@size ($p:expr) VmPtr < $g:ty >) => { u32::from($p) };
48 (@size ($p:expr) Option < VmPtr < $g:ty >>) => { u32::from($p) };
49 (@size ($p:expr) AtomicUsize) => { u32::from($p) };
50 (@size ($p:expr) usize) => { u32::from($p) };
51 (@size ($p:expr) i64) => { 8u32 };
52 (@size ($p:expr) u64) => { 8u32 };
53 (@size ($p:expr) u32) => { 4u32 };
54 (@size ($p:expr) NonZeroU32) => { 4u32 };
57 (@size ($p:expr) Option < VMGcRef >) => { 4u32 };
58 (@size ($p:expr) [u32; $n:expr]) => { 4u32 * u32::try_from($n).unwrap() };
59 (@size ($p:expr) VMSharedTypeIndex) => { u32::from(($p).size_of_vmshared_type_index()) };
60 (@size ($p:expr) DefinedTableIndex) => { 4u32 };
61 (@size ($p:expr) DefinedMemoryIndex) => { 4u32 };
62 (@size ($p:expr) DefinedTagIndex) => { 4u32 };
63 (@size ($p:expr) VMGlobalKind) => { 8u32 };
64 (@size ($p:expr) Range < *mut u8 >) => { 2u32 * u32::from($p) };
66 (@size ($p:expr) VMMemoryDefinition) => { u32::from(($p).vm_memory_definition().size()) };
69 (@size ($p:expr) VMLazyThread) => { u32::from(($p).vm_lazy_thread().size()) };
70 (@size ($p:expr) VMStackLimits) => { u32::from(($p).vm_stack_limits().size()) };
71 (@size ($p:expr) VMHostArray) => { u32::from(($p).vm_host_array().size()) };
72 (@size ($p:expr) VMPayloads) => { u32::from(($p).vm_payloads().size()) };
73 (@size ($p:expr) VMAsanStackSupport) => {
74 u32::from(($p).vm_asan_stack_support().size())
75 };
76 (@size ($p:expr) VMCommonStackInformation) => {
77 u32::from(($p).vm_common_stack_information().size())
78 };
79 (@size ($p:expr) VMGcHeader) => { u32::from(($p).vm_gc_header().size()) };
80 (@size ($p:expr) VMStackChain) => { u32::from(($p).size_of_vmstack_chain()) };
83 (@size ($p:expr) VMStackState) => { 4u32 };
84 (@size ($p:expr) VMContinuationStack) => { 3u32 * u32::from($p) };
88 (@size ($p:expr) PhantomPinned) => { 0u32 };
89
90 (@align ($p:expr) UnsafeCell < $inner:tt >) => { define_vm_type_offsets!(@align ($p) $inner) };
92
93 (@align ($p:expr) VmPtr < $g:ty >) => { u32::from($p) };
101 (@align ($p:expr) Option < VmPtr < $g:ty >>) => { u32::from($p) };
102 (@align ($p:expr) AtomicUsize) => { u32::from($p) };
103 (@align ($p:expr) usize) => { u32::from($p) };
104 (@align ($p:expr) i64) => { 8u32 };
105 (@align ($p:expr) u64) => { 8u32 };
106 (@align ($p:expr) u32) => { 4u32 };
107 (@align ($p:expr) NonZeroU32) => { 4u32 };
108 (@align ($p:expr) Option < VMGcRef >) => { 4u32 };
109 (@align ($p:expr) [u32; $n:expr]) => { 4u32 };
110 (@align ($p:expr) VMSharedTypeIndex) => { u32::from(($p).align_of_vmshared_type_index()) };
111 (@align ($p:expr) DefinedTableIndex) => { 4u32 };
112 (@align ($p:expr) DefinedMemoryIndex) => { 4u32 };
113 (@align ($p:expr) DefinedTagIndex) => { 4u32 };
114 (@align ($p:expr) VMGlobalKind) => { 4u32 };
115 (@align ($p:expr) Range < *mut u8 >) => { u32::from($p) };
116 (@align ($p:expr) VMMemoryDefinition) => { u32::from(($p).vm_memory_definition().align()) };
117 (@align ($p:expr) VMLazyThread) => { u32::from(($p).vm_lazy_thread().align()) };
118 (@align ($p:expr) VMStackLimits) => { u32::from(($p).vm_stack_limits().align()) };
119 (@align ($p:expr) VMHostArray) => { u32::from(($p).vm_host_array().align()) };
120 (@align ($p:expr) VMPayloads) => { u32::from(($p).vm_payloads().align()) };
121 (@align ($p:expr) VMAsanStackSupport) => {
122 u32::from(($p).vm_asan_stack_support().align())
123 };
124 (@align ($p:expr) VMCommonStackInformation) => {
125 u32::from(($p).vm_common_stack_information().align())
126 };
127 (@align ($p:expr) VMGcHeader) => { u32::from(($p).vm_gc_header().align()) };
128 (@align ($p:expr) VMStackChain) => { u32::from($p) };
129 (@align ($p:expr) VMStackState) => { 4u32 };
130 (@align ($p:expr) VMContinuationStack) => { u32::from($p) };
131 (@align ($p:expr) PhantomPinned) => { 1u32 };
132
133 (@repr_align C) => { 1u32 };
135 (@repr_align transparent) => { 1u32 };
136 (@repr_align C, align($n:literal)) => {{ let align: u32 = $n; align }};
137
138 (@fields $Name:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )) => {};
148 (@fields $Name:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )
149 [ $fname:ident : $($fty:tt)* ]
150 $($rest:tt)*
151 ) => {
152 #[doc = concat!(
153 "The offset of the `", stringify!($fname),
154 "` field of `", stringify!($Name), "`."
155 )]
156 #[inline]
157 pub fn $fname(&self) -> u8 {
158 let $p = self.0.size();
159 let $o: u32 = 0;
160 $($prefix)*
161 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
162 let _ = $p;
163 u8::try_from($o).unwrap()
164 }
165 define_vm_type_offsets!(@fields $Name ($p, $o)
166 prefix(
167 $($prefix)*
168 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
169 let $o = $o + define_vm_type_offsets!(@size ($p) $($fty)*);
170 )
171 $($rest)*
172 );
173 };
174
175 (@impl $Name:ident [$($repr:tt)*] { $( [ $fname:ident : $($fty:tt)* ] )* }) => {
185 impl<P: PtrSize> $Name<P> {
186 define_vm_type_offsets!(@fields $Name (p, o) prefix()
187 $( [ $fname : $($fty)* ] )*
188 );
189
190 #[doc = concat!("The alignment of the `", stringify!($Name), "` type.")]
191 #[inline]
192 pub fn align(&self) -> u8 {
193 let p = self.0.size();
194 let a: u32 = define_vm_type_offsets!(@repr_align $($repr)*);
195 $(
196 let a = core::cmp::max(
197 a,
198 define_vm_type_offsets!(@align (p) $($fty)*),
199 );
200 )*
201 let _ = p;
202 u8::try_from(a).unwrap()
203 }
204
205 #[doc = concat!("The size of the `", stringify!($Name), "` type.")]
206 #[inline]
207 pub fn size(&self) -> u8 {
208 let p = self.0.size();
209 let o: u32 = 0;
210 $(
211 let o = align(o, define_vm_type_offsets!(@align (p) $($fty)*));
212 let o = o + define_vm_type_offsets!(@size (p) $($fty)*);
213 )*
214 let o = align(o, u32::from(self.align()));
215 let _ = p;
216 u8::try_from(o).unwrap()
217 }
218 }
219 };
220 (@impl $Name:ident $repr:tt { $($groups:tt)* }
225 $(#[$($attr:tt)*])* $fvis:vis $fname:ident : $($rest:tt)*
226 ) => {
227 define_vm_type_offsets!(@impl_ty $Name $repr { $($groups)* } $fname [] $($rest)*);
228 };
229 (@impl_ty $Name:ident $repr:tt { $($groups:tt)* } $fname:ident [ $($fty:tt)* ] , $($rest:tt)*) => {
232 define_vm_type_offsets!(@impl $Name $repr { $($groups)* [ $fname : $($fty)* ] } $($rest)*);
233 };
234 (@impl_ty $Name:ident $repr:tt { $($groups:tt)* } $fname:ident [ $($fty:tt)* ] $tok:tt $($rest:tt)*) => {
235 define_vm_type_offsets!(@impl_ty $Name $repr { $($groups)* } $fname [ $($fty)* $tok ] $($rest)*);
236 };
237
238 ( $(
240 $(#[doc = $sdoc:literal])*
241 $(#[cfg($($scfg:tt)*)])?
242 $(#[derive($($d:ident),*)])?
243 #[repr($($repr:tt)*)]
244 #[snake_name = $snake:ident]
245 $svis:vis struct $Name:ident {
246 $($body:tt)*
247 }
248 )* ) => {
249 $(
250 #[doc = concat!("Offsets of fields within the `", stringify!($Name), "` type.")]
251 pub struct $Name<P: PtrSize>(pub P);
252
253 define_vm_type_offsets!(@impl $Name [$($repr)*] {} $($body)*);
254 )*
255 };
256}
257
258#[allow(
262 unused_macro_rules,
263 reason = "only `VMComponentContext` has a `#[ptr_size_offset]` prefix in its \
264 `dynamic` section, so those arms go unused for `VMContext`"
265)]
266macro_rules! define_vmctx_static_offsets {
267 (@chain $p:ident [ $($prev:tt)* ] [] [ $($dyn:tt)* ]) => {
271 #[inline]
275 pub fn end_of_static_fields(&self) -> u8 {
276 let $p = self.0.size();
277 let _ = $p;
278 u8::try_from($($prev)*).unwrap()
279 }
280
281 define_vmctx_static_offsets!(@dyn_chain $p [ $($prev)* ] [ $($dyn)* ]);
282 };
283 (@chain $p:ident [ $($prev:tt)* ] [ align { $al:tt } $($rest:tt)* ] $dyn:tt) => {
284 define_vmctx_static_offsets!(
285 @chain $p
286 [ crate::vmctxtypes::align_up($($prev)*, vmctx_align_value!(($p) $al)) ]
287 [ $($rest)* ]
288 $dyn
289 );
290 };
291 (@chain $p:ident [ $($prev:tt)* ] [
292 field { $(# $fattr:tt)* $fname:ident : $($fty:tt)* } $($rest:tt)*
293 ] $dyn:tt) => {
294 #[doc = concat!("The offset of the `", stringify!($fname), "` field.")]
295 #[inline]
296 pub fn $fname(&self) -> u8 {
297 let $p = self.0.size();
298 let _ = $p;
299 u8::try_from($($prev)*).unwrap()
300 }
301 define_vmctx_static_offsets!(
302 @chain $p
303 [ $($prev)* + vmctx_field_size!(($p) $($fty)*) ]
304 [ $($rest)* ]
305 $dyn
306 );
307 };
308
309 (@dyn_chain $p:ident [ $($prev:tt)* ] [ align { $al:tt } $($rest:tt)* ]) => {
312 define_vmctx_static_offsets!(
313 @dyn_chain $p
314 [ crate::vmctxtypes::align_up($($prev)*, vmctx_align_value!(($p) $al)) ]
315 [ $($rest)* ]
316 );
317 };
318 (@dyn_chain $p:ident [ $($prev:tt)* ] [
319 field { #[ptr_size_offset] $(# $fattr:tt)* $fname:ident : $($fty:tt)* } $($rest:tt)*
320 ]) => {
321 #[doc = concat!("The offset of the `", stringify!($fname), "` field.")]
322 #[inline]
323 pub fn $fname(&self) -> u32 {
324 let $p = self.0.size();
325 let _ = $p;
326 $($prev)*
327 }
328 define_vmctx_static_offsets!(
329 @dyn_chain $p
330 [ $($prev)* + vmctx_field_size!(($p) $($fty)*) ]
331 [ $($rest)* ]
332 );
333 };
334 (@dyn_chain $p:ident [ $($prev:tt)* ] [
335 array {
336 #[ptr_size_offset] $(# $fattr:tt)*
337 $fname:ident [ $count:ident ; $Index:ident ] : $($fty:tt)*
338 } $($rest:tt)*
339 ]) => {
340 #[doc = concat!(
344 "The offset of the `index`th element of the `", stringify!($fname),
345 "` array.\n\nThis is not bounds checked: the array's length is a \
346 property of the particular module or component being compiled, which \
347 is exactly what this wrapper does not know."
348 )]
349 #[inline]
350 pub fn $fname(&self, index: impl crate::VmctxArrayIndex) -> u32 {
351 let $p = self.0.size();
352 let _ = $p;
353 let index = index.vmctx_array_index();
354 ($($prev)*) + vmctx_field_size!(($p) $($fty)*) * index
355 }
356 };
360 (@dyn_chain $p:ident [ $($prev:tt)* ] [ $($rest:tt)* ]) => {};
362
363 ( $(
364 {
365 $Name:ident $snake:ident
366 static { $($stat:tt)* }
367 dynamic { $($dyn:tt)* }
368 }
369 )* ) => {
370 $(
371 #[doc = concat!("Offsets of the statically-positioned fields within the `",
372 stringify!($Name), "` type.")]
373 pub struct $Name<P: PtrSize>(pub P);
374
375 impl<P: PtrSize> $Name<P> {
376 define_vmctx_static_offsets!(@chain ptr [ 0u32 ] [ $($stat)* ] [ $($dyn)* ]);
377 }
378 )*
379 };
380}
381
382pub mod offsets {
389 use super::{NUM_COMPONENT_CONTEXT_SLOTS, PtrSize, align};
390
391 for_each_vm_type!(define_vm_type_offsets);
392 for_each_vmctx_type!(define_vmctx_static_offsets);
393}
394
395impl<P: PtrSize> offsets::VMStoreContext<P> {
398 pub fn gc_heap_base(&self) -> u8 {
400 let offset = self.gc_heap() + self.0.vm_memory_definition().base();
401 debug_assert!(offset < self.last_wasm_exit_trampoline_fp());
402 offset
403 }
404
405 pub fn gc_heap_current_length(&self) -> u8 {
408 let offset = self.gc_heap() + self.0.vm_memory_definition().current_length();
409 debug_assert!(offset < self.last_wasm_exit_trampoline_fp());
410 offset
411 }
412}
413
414macro_rules! define_ptr_size_vm_type_accessors {
417 ( $(
418 $(#[doc = $sdoc:literal])*
419 $(#[cfg($($scfg:tt)*)])?
420 $(#[derive($($d:ident),*)])?
421 #[repr($($repr:tt)*)]
422 #[snake_name = $snake:ident]
423 $svis:vis struct $Name:ident {
424 $($body:tt)*
425 }
426 )* ) => {
427 $(
428 #[doc = concat!("Get the [`offsets::", stringify!($Name), "`] offsets for this pointer size.")]
429 #[inline]
430 fn $snake(&self) -> offsets::$Name<&Self> {
431 offsets::$Name(self)
432 }
433 )*
434 };
435}
436
437macro_rules! define_ptr_size_vmctx_type_accessors {
440 ( $(
441 {
442 $Name:ident $snake:ident
443 static { $($stat:tt)* }
444 dynamic { $($dyn:tt)* }
445 }
446 )* ) => {
447 $(
448 #[doc = concat!("Get the [`offsets::", stringify!($Name),
449 "`] offsets for this pointer size.")]
450 #[inline]
451 fn $snake(&self) -> offsets::$Name<&Self> {
452 offsets::$Name(self)
453 }
454 )*
455 };
456}
457
458#[derive(Debug, Clone, Copy)]
461pub struct VMOffsets<P> {
462 pub ptr: P,
464 pub num_imported_functions: u32,
466 pub num_imported_tables: u32,
468 pub num_imported_memories: u32,
470 pub num_imported_globals: u32,
472 pub num_imported_tags: u32,
474 pub num_defined_tables: u32,
476 pub num_defined_memories: u32,
478 pub num_owned_memories: u32,
480 pub num_defined_globals: u32,
482 pub num_defined_tags: u32,
484 pub num_escaped_funcs: u32,
487 pub num_runtime_data: u32,
489 pub has_startup_func: bool,
491
492 imported_memories: u32,
494 memories: u32,
495 owned_memories: u32,
496 imported_functions: u32,
497 imported_tables: u32,
498 imported_globals: u32,
499 imported_tags: u32,
500 tables: u32,
501 globals: u32,
502 tags: u32,
503 func_refs: u32,
504 startup_func_ref: u32,
505 runtime_data_bases: u32,
506 runtime_data_lengths: u32,
507 size: u32,
508}
509
510pub trait PtrSize {
512 fn size(&self) -> u8;
514
515 for_each_vm_type!(define_ptr_size_vm_type_accessors);
518
519 for_each_vmctx_type!(define_ptr_size_vmctx_type_accessors);
522
523 #[inline]
525 fn size_of_vmshared_type_index(&self) -> u8 {
526 4
527 }
528
529 #[inline]
531 fn align_of_vmshared_type_index(&self) -> u8 {
532 4
533 }
534
535 #[inline]
537 fn maximum_value_size(&self) -> u8 {
538 16
539 }
540
541 #[inline]
543 fn size_of_vmmemory_pointer(&self) -> u8 {
544 self.size()
545 }
546
547 fn vmarray_call_host_func_context_func_ref(&self) -> u8 {
551 u8::try_from(align(
552 u32::try_from(core::mem::size_of::<u32>()).unwrap(),
553 u32::from(self.size()),
554 ))
555 .unwrap()
556 }
557
558 fn size_of_vmstack_chain(&self) -> u8 {
560 2 * self.size()
561 }
562
563 fn vmcontobj_contref(&self) -> u8 {
567 0
568 }
569
570 fn vmcontobj_revision(&self) -> u8 {
572 self.size()
573 }
574
575 fn size_of_vmcontobj(&self) -> u8 {
577 u8::try_from(align(
578 u32::from(self.vmcontobj_revision())
579 + u32::try_from(core::mem::size_of::<usize>()).unwrap(),
580 u32::from(self.size()),
581 ))
582 .unwrap()
583 }
584}
585
586pub trait GetPtrSize {
588 type Ptr: PtrSize;
590
591 fn get_ptr_size(&self) -> &Self::Ptr;
593}
594
595impl<P> GetPtrSize for P
596where
597 P: PtrSize,
598{
599 type Ptr = Self;
600
601 #[inline]
602 fn get_ptr_size(&self) -> &Self::Ptr {
603 self
604 }
605}
606
607#[derive(Clone, Copy)]
609pub struct HostPtr;
610
611impl PtrSize for HostPtr {
612 #[inline]
613 fn size(&self) -> u8 {
614 core::mem::size_of::<usize>() as u8
615 }
616}
617
618impl PtrSize for u8 {
619 #[inline]
620 fn size(&self) -> u8 {
621 *self
622 }
623}
624
625impl<P> PtrSize for &'_ P
626where
627 P: PtrSize + ?Sized,
628{
629 #[inline]
630 fn size(&self) -> u8 {
631 (**self).size()
632 }
633}
634
635#[derive(Debug, Clone, Copy)]
637pub struct VMOffsetsFields<P> {
638 pub ptr: P,
640 pub num_imported_functions: u32,
642 pub num_imported_tables: u32,
644 pub num_imported_memories: u32,
646 pub num_imported_globals: u32,
648 pub num_imported_tags: u32,
650 pub num_defined_tables: u32,
652 pub num_defined_memories: u32,
654 pub num_owned_memories: u32,
656 pub num_defined_globals: u32,
658 pub num_defined_tags: u32,
660 pub num_escaped_funcs: u32,
663 pub num_runtime_data: u32,
665 pub has_startup_func: bool,
667}
668
669impl<P: PtrSize> VMOffsets<P> {
670 pub fn new(ptr: P, module: &Module) -> Self {
672 let num_owned_memories = module
673 .memories
674 .iter()
675 .skip(module.num_imported_memories)
676 .filter(|p| !p.1.shared)
677 .count()
678 .try_into()
679 .unwrap();
680 VMOffsets::from(VMOffsetsFields {
681 ptr,
682 num_imported_functions: cast_to_u32(module.num_imported_funcs),
683 num_imported_tables: cast_to_u32(module.num_imported_tables),
684 num_imported_memories: cast_to_u32(module.num_imported_memories),
685 num_imported_globals: cast_to_u32(module.num_imported_globals),
686 num_imported_tags: cast_to_u32(module.num_imported_tags),
687 num_defined_tables: cast_to_u32(module.num_defined_tables()),
688 num_defined_memories: cast_to_u32(module.num_defined_memories()),
689 num_owned_memories,
690 num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),
691 num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),
692 num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),
693 num_runtime_data: cast_to_u32(module.runtime_data.len()),
694 has_startup_func: !module.startup.is_none(),
695 })
696 }
697
698 #[inline]
700 pub fn pointer_size(&self) -> u8 {
701 self.ptr.size()
702 }
703
704 pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {
709 macro_rules! calculate_sizes {
710 ($($name:ident: $desc:tt,)*) => {{
711 let VMOffsets {
712 ptr: _,
715 num_imported_functions: _,
716 num_imported_tables: _,
717 num_imported_memories: _,
718 num_imported_globals: _,
719 num_imported_tags: _,
720 num_defined_tables: _,
721 num_defined_globals: _,
722 num_defined_memories: _,
723 num_defined_tags: _,
724 num_owned_memories: _,
725 num_escaped_funcs: _,
726 num_runtime_data: _,
727 has_startup_func: _,
728
729 size,
731
732 $($name,)*
735 } = *self;
736
737 let mut last = size;
741 $(
742 assert!($name <= last);
743 let tmp = $name;
744 let $name = last - $name;
745 last = tmp;
746 )*
747 assert_ne!(last, 0);
748 IntoIterator::into_iter([
749 $(($desc, $name),)*
750 ("static vmctx data", last),
751 ])
752 }};
753 }
754
755 calculate_sizes! {
756 runtime_data_lengths: "runtime data lengths",
757 runtime_data_bases: "runtime data base pointers",
758 startup_func_ref: "startup funcref",
759 func_refs: "module functions",
760 tags: "defined tags",
761 globals: "defined globals",
762 tables: "defined tables",
763 imported_tags: "imported tags",
764 imported_globals: "imported globals",
765 imported_tables: "imported tables",
766 imported_functions: "imported functions",
767 owned_memories: "owned memories",
768 memories: "defined memories",
769 imported_memories: "imported memories",
770 }
771 }
772}
773
774impl<P: PtrSize> GetPtrSize for VMOffsets<P> {
775 type Ptr = P;
776
777 #[inline]
778 fn get_ptr_size(&self) -> &Self::Ptr {
779 &self.ptr
780 }
781}
782
783impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {
784 fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {
785 let mut ret = Self {
786 ptr: fields.ptr,
787 num_imported_functions: fields.num_imported_functions,
788 num_imported_tables: fields.num_imported_tables,
789 num_imported_memories: fields.num_imported_memories,
790 num_imported_globals: fields.num_imported_globals,
791 num_imported_tags: fields.num_imported_tags,
792 num_defined_tables: fields.num_defined_tables,
793 num_defined_memories: fields.num_defined_memories,
794 num_owned_memories: fields.num_owned_memories,
795 num_defined_globals: fields.num_defined_globals,
796 num_defined_tags: fields.num_defined_tags,
797 num_escaped_funcs: fields.num_escaped_funcs,
798 num_runtime_data: fields.num_runtime_data,
799 has_startup_func: fields.has_startup_func,
800 imported_memories: 0,
801 memories: 0,
802 owned_memories: 0,
803 imported_functions: 0,
804 imported_tables: 0,
805 imported_globals: 0,
806 imported_tags: 0,
807 tables: 0,
808 globals: 0,
809 tags: 0,
810 func_refs: 0,
811 startup_func_ref: 0,
812 runtime_data_bases: 0,
813 runtime_data_lengths: 0,
814 size: 0,
815 };
816 ret.compute_field_offsets();
817 ret
818 }
819}
820
821impl<P: PtrSize> VMOffsets<P> {
823 pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
825 1 * self.pointer_size()
826 }
827}
828
829impl<P: PtrSize> VMOffsets<P> {
831 #[inline]
833 pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {
834 self.pointer_size()
835 }
836}
837
838impl<P: PtrSize> VMOffsets<P> {
840 #[inline]
842 pub fn size_of_vmshared_type_index(&self) -> u8 {
843 self.ptr.size_of_vmshared_type_index()
844 }
845}
846
847impl_vmctx_array_index! {
848 MemoryIndex,
849 DefinedMemoryIndex,
850 OwnedMemoryIndex,
851 FuncIndex,
852 TableIndex,
853 DefinedTableIndex,
854 GlobalIndex,
855 DefinedGlobalIndex,
856 TagIndex,
857 DefinedTagIndex,
858 FuncRefIndex,
859 RuntimeDataIndex,
860 ModuleInternedTypeIndex,
861}
862
863macro_rules! define_vmoffsets_dynamic_offsets {
866 (@one VMContext $snake:ident { $($dyn:tt)* }) => {
867 impl<P: PtrSize> VMOffsets<P> {
869 define_vmctx_dynamic_offsets!(@accessors (self) [ $($dyn)* ]);
870 define_vmctx_dynamic_offsets!(@compute_fn (self, next) $snake [ $($dyn)* ]);
871
872 #[inline]
874 pub fn size_of_vmctx(&self) -> u32 {
875 self.size
876 }
877 }
878 };
879 (@one $other:ident $snake:ident { $($dyn:tt)* }) => {};
880
881 ( $(
882 {
883 $Name:ident $snake:ident
884 static { $($stat:tt)* }
885 dynamic { $($dyn:tt)* }
886 }
887 )* ) => {
888 $( define_vmoffsets_dynamic_offsets!(@one $Name $snake { $($dyn)* }); )*
889 };
890}
891for_each_vmctx_type!(define_vmoffsets_dynamic_offsets);
892
893pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");
897
898pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");
903
904#[cfg(test)]
905mod tests {
906 use crate::vmoffsets::{VMOffsets, VMOffsetsFields, align};
907
908 #[test]
909 fn alignment() {
910 fn is_aligned(x: u32) -> bool {
911 x % 16 == 0
912 }
913 assert!(is_aligned(align(0, 16)));
914 assert!(is_aligned(align(32, 16)));
915 assert!(is_aligned(align(33, 16)));
916 assert!(is_aligned(align(31, 16)));
917 }
918
919 #[test]
920 fn pointer_fields_aligned_after_tags() {
921 for ptr in [4u8, 8] {
922 for num_defined_tags in 0..4 {
923 let offsets = VMOffsets::from(VMOffsetsFields {
924 ptr,
925 num_imported_functions: 0,
926 num_imported_tables: 0,
927 num_imported_memories: 0,
928 num_imported_globals: 0,
929 num_imported_tags: 0,
930 num_defined_tables: 0,
931 num_defined_memories: 0,
932 num_owned_memories: 0,
933 num_defined_globals: 0,
934 num_defined_tags,
935 num_escaped_funcs: 1,
936 num_runtime_data: 1,
937 has_startup_func: true,
938 });
939 let ptr = u32::from(ptr);
940 assert_eq!(offsets.func_refs % ptr, 0);
941 assert_eq!(offsets.startup_func_ref % ptr, 0);
942 assert_eq!(offsets.runtime_data_bases % ptr, 0);
943 }
944 }
945 }
946}
947
948pub const VM_LAZY_THREAD_FORCED: u64 = 1;