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
19pub const LAZY_LENDERS_CAPACITY: usize = 8;
25
26#[cfg(target_pointer_width = "32")]
27fn cast_to_u32(sz: usize) -> u32 {
28 u32::try_from(sz).unwrap()
29}
30#[cfg(target_pointer_width = "64")]
31fn cast_to_u32(sz: usize) -> u32 {
32 u32::try_from(sz).expect("overflow in cast from usize to u32")
33}
34
35#[inline]
37fn align(offset: u32, width: u32) -> u32 {
38 (offset + (width - 1)) / width * width
39}
40
41#[allow(
49 unused_macro_rules,
50 reason = "the enum arms go unused whenever no `VM*` type is an enum, and \
51 the type classifiers are written for all field types rather than \
52 only those some type happens to use"
53)]
54macro_rules! define_vm_type_offsets {
55 (@size ($p:expr) UnsafeCell < $inner:tt >) => { define_vm_type_offsets!(@size ($p) $inner) };
58
59 (@size ($p:expr) VmPtr < $g:ty >) => { u32::from($p) };
65 (@size ($p:expr) VmPtr < VmPtr < $g:ty >>) => { u32::from($p) };
66 (@size ($p:expr) Option < VmPtr < $g:ty >>) => { u32::from($p) };
67 (@size ($p:expr) AtomicUsize) => { u32::from($p) };
68 (@size ($p:expr) usize) => { u32::from($p) };
69 (@size ($p:expr) i64) => { 8u32 };
70 (@size ($p:expr) u64) => { 8u32 };
71 (@size ($p:expr) u32) => { 4u32 };
72 (@size ($p:expr) u16) => { 2u32 };
73 (@size ($p:expr) u8) => { 1u32 };
74 (@size ($p:expr) NonZeroU32) => { 4u32 };
77 (@size ($p:expr) Option < VMGcRef >) => { 4u32 };
78 (@size ($p:expr) [u32; $n:expr]) => { 4u32 * u32::try_from($n).unwrap() };
79 (@size ($p:expr) VMSharedTypeIndex) => { u32::from(($p).size_of_vmshared_type_index()) };
80 (@size ($p:expr) DefinedTableIndex) => { 4u32 };
81 (@size ($p:expr) DefinedMemoryIndex) => { 4u32 };
82 (@size ($p:expr) DefinedTagIndex) => { 4u32 };
83 (@size ($p:expr) VMGlobalKind) => { 8u32 };
84 (@size ($p:expr) Range < *mut u8 >) => { 2u32 * u32::from($p) };
86 (@size ($p:expr) VMMemoryDefinition) => { u32::from(($p).vm_memory_definition().size()) };
89 (@size ($p:expr) VMLazyThread) => { u32::from(($p).vm_lazy_thread().size()) };
90 (@size ($p:expr) VMStackLimits) => { u32::from(($p).vm_stack_limits().size()) };
91 (@size ($p:expr) VMHostArray) => { u32::from(($p).vm_host_array().size()) };
92 (@size ($p:expr) VMPayloads) => { u32::from(($p).vm_payloads().size()) };
93 (@size ($p:expr) VMAsanStackSupport) => {
94 u32::from(($p).vm_asan_stack_support().size())
95 };
96 (@size ($p:expr) VMCommonStackInformation) => {
97 u32::from(($p).vm_common_stack_information().size())
98 };
99 (@size ($p:expr) VMGcHeader) => { u32::from(($p).vm_gc_header().size()) };
100 (@size ($p:expr) VMTypedResource) => { u32::from(($p).vm_typed_resource().size()) };
101 (@size ($p:expr) VMScope) => { u32::from(($p).vm_scope().size()) };
102 (@size ($p:expr) VMTransmitLocalState) => {
103 u32::from(($p).vm_transmit_local_state().size())
104 };
105 (@size ($p:expr) VMStackChain) => { u32::from(($p).size_of_vmstack_chain()) };
108 (@size ($p:expr) VMStackState) => { 4u32 };
109 (@size ($p:expr) VMContinuationStack) => { 3u32 * u32::from($p) };
113 (@size ($p:expr) PhantomPinned) => { 0u32 };
114
115 (@align ($p:expr) UnsafeCell < $inner:tt >) => { define_vm_type_offsets!(@align ($p) $inner) };
117
118 (@align ($p:expr) VmPtr < $g:ty >) => { u32::from($p) };
126 (@align ($p:expr) VmPtr < VmPtr < $g:ty >>) => { u32::from($p) };
127 (@align ($p:expr) Option < VmPtr < $g:ty >>) => { u32::from($p) };
128 (@align ($p:expr) AtomicUsize) => { u32::from($p) };
129 (@align ($p:expr) usize) => { u32::from($p) };
130 (@align ($p:expr) i64) => { 8u32 };
131 (@align ($p:expr) u64) => { 8u32 };
132 (@align ($p:expr) u32) => { 4u32 };
133 (@align ($p:expr) u16) => { 2u32 };
134 (@align ($p:expr) u8) => { 1u32 };
135 (@align ($p:expr) NonZeroU32) => { 4u32 };
136 (@align ($p:expr) Option < VMGcRef >) => { 4u32 };
137 (@align ($p:expr) [u32; $n:expr]) => { 4u32 };
138 (@align ($p:expr) VMSharedTypeIndex) => { u32::from(($p).align_of_vmshared_type_index()) };
139 (@align ($p:expr) DefinedTableIndex) => { 4u32 };
140 (@align ($p:expr) DefinedMemoryIndex) => { 4u32 };
141 (@align ($p:expr) DefinedTagIndex) => { 4u32 };
142 (@align ($p:expr) VMGlobalKind) => { 4u32 };
143 (@align ($p:expr) Range < *mut u8 >) => { u32::from($p) };
144 (@align ($p:expr) VMMemoryDefinition) => { u32::from(($p).vm_memory_definition().align()) };
145 (@align ($p:expr) VMLazyThread) => { u32::from(($p).vm_lazy_thread().align()) };
146 (@align ($p:expr) VMStackLimits) => { u32::from(($p).vm_stack_limits().align()) };
147 (@align ($p:expr) VMHostArray) => { u32::from(($p).vm_host_array().align()) };
148 (@align ($p:expr) VMPayloads) => { u32::from(($p).vm_payloads().align()) };
149 (@align ($p:expr) VMAsanStackSupport) => {
150 u32::from(($p).vm_asan_stack_support().align())
151 };
152 (@align ($p:expr) VMCommonStackInformation) => {
153 u32::from(($p).vm_common_stack_information().align())
154 };
155 (@align ($p:expr) VMGcHeader) => { u32::from(($p).vm_gc_header().align()) };
156 (@align ($p:expr) VMTypedResource) => { u32::from(($p).vm_typed_resource().align()) };
157 (@align ($p:expr) VMScope) => { u32::from(($p).vm_scope().align()) };
158 (@align ($p:expr) VMTransmitLocalState) => {
159 u32::from(($p).vm_transmit_local_state().align())
160 };
161 (@align ($p:expr) VMStackChain) => { u32::from($p) };
162 (@align ($p:expr) VMStackState) => { 4u32 };
163 (@align ($p:expr) VMContinuationStack) => { u32::from($p) };
164 (@align ($p:expr) PhantomPinned) => { 1u32 };
165
166 (@repr_align C) => { 1u32 };
168 (@repr_align transparent) => { 1u32 };
169 (@repr_align C, align($n:literal)) => {{ let align: u32 = $n; align }};
170
171 (@tag_size u8) => { 1u32 };
174 (@tag_size u16) => { 2u32 };
175 (@tag_size u32) => { 4u32 };
176 (@tag_size u64) => { 8u32 };
177
178 (@fields $Name:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )) => {};
188 (@fields $Name:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )
189 [ $fname:ident : $($fty:tt)* ]
190 $($rest:tt)*
191 ) => {
192 #[doc = concat!(
193 "The offset of the `", stringify!($fname),
194 "` field of `", stringify!($Name), "`."
195 )]
196 #[inline]
197 pub fn $fname(&self) -> u8 {
198 let $p = self.0.size();
199 let $o: u32 = 0;
200 $($prefix)*
201 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
202 let _ = $p;
203 u8::try_from($o).unwrap()
204 }
205 define_vm_type_offsets!(@fields $Name ($p, $o)
206 prefix(
207 $($prefix)*
208 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
209 let $o = $o + define_vm_type_offsets!(@size ($p) $($fty)*);
210 )
211 $($rest)*
212 );
213 };
214
215 (@impl $Name:ident [$($repr:tt)*] { $( [ $fname:ident : $($fty:tt)* ] )* }) => {
225 impl<P: PtrSize> $Name<P> {
226 define_vm_type_offsets!(@fields $Name (p, o) prefix()
227 $( [ $fname : $($fty)* ] )*
228 );
229
230 #[doc = concat!("The alignment of the `", stringify!($Name), "` type.")]
231 #[inline]
232 pub fn align(&self) -> u8 {
233 let p = self.0.size();
234 let a: u32 = define_vm_type_offsets!(@repr_align $($repr)*);
235 $(
236 let a = core::cmp::max(
237 a,
238 define_vm_type_offsets!(@align (p) $($fty)*),
239 );
240 )*
241 let _ = p;
242 u8::try_from(a).unwrap()
243 }
244
245 #[doc = concat!("The size of the `", stringify!($Name), "` type.")]
246 #[inline]
247 pub fn size(&self) -> u8 {
248 let p = self.0.size();
249 let o: u32 = 0;
250 $(
251 let o = align(o, define_vm_type_offsets!(@align (p) $($fty)*));
252 let o = o + define_vm_type_offsets!(@size (p) $($fty)*);
253 )*
254 let o = align(o, u32::from(self.align()));
255 let _ = p;
256 u8::try_from(o).unwrap()
257 }
258 }
259 };
260 (@impl $Name:ident $repr:tt { $($groups:tt)* }
265 $(#[$($attr:tt)*])* $fvis:vis $fname:ident : $($rest:tt)*
266 ) => {
267 define_vm_type_offsets!(@impl_ty $Name $repr { $($groups)* } $fname [] $($rest)*);
268 };
269 (@impl_ty $Name:ident $repr:tt { $($groups:tt)* } $fname:ident [ $($fty:tt)* ] , $($rest:tt)*) => {
272 define_vm_type_offsets!(@impl $Name $repr { $($groups)* [ $fname : $($fty)* ] } $($rest)*);
273 };
274 (@impl_ty $Name:ident $repr:tt { $($groups:tt)* } $fname:ident [ $($fty:tt)* ] $tok:tt $($rest:tt)*) => {
275 define_vm_type_offsets!(@impl_ty $Name $repr { $($groups)* } $fname [ $($fty)* $tok ] $($rest)*);
276 };
277
278 (@def struct $Name:ident $snake:ident $repr:tt { $($body:tt)* }) => {
280 define_vm_type_offsets!(@impl $Name $repr {} $($body)*);
281 };
282 (@def enum $Name:ident $snake:ident [ C, $tag:ident ] { $($body:tt)* }) => {
284 define_vm_type_offsets!(@enum_variants $Name $snake $tag {} $($body)*);
285 };
286
287 (@enum_variants $Name:ident $snake:ident $tag:ident { $($vs:tt)* }) => {
291 define_vm_type_offsets!(@enum_emit $Name $snake $tag { $($vs)* });
292 };
293 (@enum_variants $Name:ident $snake:ident $tag:ident { $($vs:tt)* }
294 $(#[doc = $vdoc:literal])*
295 #[snake_name = $vsnake:ident]
296 $(#[$vattr:meta])*
297 $Variant:ident { $($vbody:tt)* } = $disc:literal ,
298 $($rest:tt)*
299 ) => {
300 define_vm_type_offsets!(
301 @enum_fields $Name $snake $tag { $($vs)* }
302 $vsnake $Variant $disc {}
303 [ $($vbody)* ] [ $($rest)* ]
304 );
305 };
306
307 (@enum_fields $Name:ident $snake:ident $tag:ident { $($vs:tt)* }
310 $vsnake:ident $Variant:ident $disc:literal { $($g:tt)* }
311 [] [ $($rest:tt)* ]
312 ) => {
313 define_vm_type_offsets!(
314 @enum_variants $Name $snake $tag
315 { $($vs)* { $vsnake $Variant $disc { $($g)* } } }
316 $($rest)*
317 );
318 };
319 (@enum_fields $Name:ident $snake:ident $tag:ident { $($vs:tt)* }
320 $vsnake:ident $Variant:ident $disc:literal { $($g:tt)* }
321 [ $(#[$($fattr:tt)*])* $fname:ident : $($vrest:tt)* ] $rest:tt
322 ) => {
323 define_vm_type_offsets!(
324 @enum_field_ty $Name $snake $tag { $($vs)* }
325 $vsnake $Variant $disc { $($g)* }
326 $fname [] [ $($vrest)* ] $rest
327 );
328 };
329 (@enum_field_ty $Name:ident $snake:ident $tag:ident { $($vs:tt)* }
330 $vsnake:ident $Variant:ident $disc:literal { $($g:tt)* }
331 $fname:ident [ $($fty:tt)* ] [ , $($vrest:tt)* ] $rest:tt
332 ) => {
333 define_vm_type_offsets!(
334 @enum_fields $Name $snake $tag { $($vs)* }
335 $vsnake $Variant $disc { $($g)* [ $fname : $($fty)* ] }
336 [ $($vrest)* ] $rest
337 );
338 };
339 (@enum_field_ty $Name:ident $snake:ident $tag:ident { $($vs:tt)* }
340 $vsnake:ident $Variant:ident $disc:literal { $($g:tt)* }
341 $fname:ident [ $($fty:tt)* ] [ $tok:tt $($vrest:tt)* ] $rest:tt
342 ) => {
343 define_vm_type_offsets!(
344 @enum_field_ty $Name $snake $tag { $($vs)* }
345 $vsnake $Variant $disc { $($g)* }
346 $fname [ $($fty)* $tok ] [ $($vrest)* ] $rest
347 );
348 };
349
350 (@enum_emit $Name:ident $snake:ident $tag:ident {
357 $(
358 { $vsnake:ident $Variant:ident $disc:literal {
359 $( [ $fname:ident : $($fty:tt)* ] )*
360 } }
361 )*
362 }) => {
363 impl<P: PtrSize> $Name<P> {
364 #[doc = concat!(
365 "The offset of the `", stringify!($tag), "` tag of `",
366 stringify!($Name), "`."
367 )]
368 #[inline]
369 pub fn tag(&self) -> u8 {
370 0
371 }
372
373 #[doc = concat!(
374 "The size, in bytes, of the `", stringify!($tag), "` tag of `",
375 stringify!($Name), "`."
376 )]
377 #[inline]
378 pub fn tag_size(&self) -> u8 {
379 u8::try_from(define_vm_type_offsets!(@tag_size $tag)).unwrap()
380 }
381
382 #[doc = concat!(
383 "The offset at which every variant of `", stringify!($Name),
384 "` lays out its fields."
385 )]
386 #[inline]
387 pub fn payload(&self) -> u8 {
388 let tag_size = u32::from(self.tag_size());
389 u8::try_from(align(tag_size, u32::from(self.align()))).unwrap()
390 }
391
392 #[doc = concat!("The alignment of the `", stringify!($Name), "` type.")]
393 #[inline]
394 pub fn align(&self) -> u8 {
395 let p = self.0.size();
396 let a: u32 = define_vm_type_offsets!(@tag_size $tag);
398 $($(
399 let a = core::cmp::max(
400 a,
401 define_vm_type_offsets!(@align (p) $($fty)*),
402 );
403 )*)*
404 let _ = p;
405 u8::try_from(a).unwrap()
406 }
407
408 #[doc = concat!("The size of the `", stringify!($Name), "` type.")]
409 #[inline]
410 pub fn size(&self) -> u8 {
411 let p = self.0.size();
412 let payload = u32::from(self.payload());
413 let s: u32 = payload;
414 $(
415 let o: u32 = payload;
416 $(
417 let o = align(o, define_vm_type_offsets!(@align (p) $($fty)*));
418 let o = o + define_vm_type_offsets!(@size (p) $($fty)*);
419 )*
420 let s = core::cmp::max(s, o);
421 )*
422 let s = align(s, u32::from(self.align()));
423 let _ = p;
424 u8::try_from(s).unwrap()
425 }
426
427 $(
428 #[doc = concat!(
429 "Get the offsets of the `", stringify!($Variant),
430 "` variant's fields."
431 )]
432 #[inline]
433 pub fn $vsnake(&self) -> $snake::$Variant<&P> {
434 $snake::$Variant($Name(&self.0))
435 }
436 )*
437 }
438
439 #[doc = concat!(
440 "Offsets of the fields of each variant of the `", stringify!($Name),
441 "` enum."
442 )]
443 pub mod $snake {
444 use super::{$Name, PtrSize, align};
445
446 $(
447 #[doc = concat!(
448 "Offsets of fields within the `", stringify!($Name), "::",
449 stringify!($Variant), "` variant."
450 )]
451 pub struct $Variant<P: PtrSize>(pub $Name<P>);
452
453 impl<P: PtrSize> $Variant<P> {
454 #[doc = concat!(
455 "The value of the `u32` tag that identifies the `",
456 stringify!($Variant), "` variant."
457 )]
458 #[inline]
459 pub fn tag_value(&self) -> u32 {
460 $disc
461 }
462
463 define_vm_type_offsets!(@vfields $Name $Variant (p, o) prefix()
464 $( [ $fname : $($fty)* ] )*
465 );
466 }
467 )*
468 }
469 };
470
471 (@vfields $Name:ident $Variant:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )) => {};
474 (@vfields $Name:ident $Variant:ident ($p:ident, $o:ident) prefix( $($prefix:tt)* )
475 [ $fname:ident : $($fty:tt)* ]
476 $($rest:tt)*
477 ) => {
478 #[doc = concat!(
479 "The offset of the `", stringify!($fname),
480 "` field of `", stringify!($Name), "::", stringify!($Variant), "`."
481 )]
482 #[inline]
483 pub fn $fname(&self) -> u8 {
484 let $p = (self.0).0.size();
485 let $o: u32 = u32::from(self.0.payload());
486 $($prefix)*
487 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
488 let _ = $p;
489 u8::try_from($o).unwrap()
490 }
491 define_vm_type_offsets!(@vfields $Name $Variant ($p, $o)
492 prefix(
493 $($prefix)*
494 let $o = align($o, define_vm_type_offsets!(@align ($p) $($fty)*));
495 let $o = $o + define_vm_type_offsets!(@size ($p) $($fty)*);
496 )
497 $($rest)*
498 );
499 };
500
501 ( $(
504 $(#[doc = $sdoc:literal])*
505 $(#[cfg($($scfg:tt)*)])?
506 $(#[derive($($d:ident),*)])?
507 #[repr($($repr:tt)*)]
508 #[snake_name = $snake:ident]
509 $svis:vis $kind:ident $Name:ident {
510 $($body:tt)*
511 }
512 )* ) => {
513 $(
514 #[doc = concat!("Offsets of fields within the `", stringify!($Name), "` type.")]
515 pub struct $Name<P: PtrSize>(pub P);
516
517 define_vm_type_offsets!(@def $kind $Name $snake [$($repr)*] { $($body)* });
518 )*
519 };
520}
521
522#[allow(
526 unused_macro_rules,
527 reason = "only `VMComponentContext` has a `#[ptr_size_offset]` prefix in its \
528 `dynamic` section, so those arms go unused for `VMContext`"
529)]
530macro_rules! define_vmctx_static_offsets {
531 (@chain $p:ident [ $($prev:tt)* ] [] [ $($dyn:tt)* ]) => {
535 #[inline]
539 pub fn end_of_static_fields(&self) -> u8 {
540 let $p = self.0.size();
541 let _ = $p;
542 u8::try_from($($prev)*).unwrap()
543 }
544
545 define_vmctx_static_offsets!(@dyn_chain $p [ $($prev)* ] [ $($dyn)* ]);
546 };
547 (@chain $p:ident [ $($prev:tt)* ] [ align { $al:tt } $($rest:tt)* ] $dyn:tt) => {
548 define_vmctx_static_offsets!(
549 @chain $p
550 [ crate::vmctxtypes::align_up($($prev)*, vmctx_align_value!(($p) $al)) ]
551 [ $($rest)* ]
552 $dyn
553 );
554 };
555 (@chain $p:ident [ $($prev:tt)* ] [
556 field { $(# $fattr:tt)* $fname:ident : $($fty:tt)* } $($rest:tt)*
557 ] $dyn:tt) => {
558 #[doc = concat!("The offset of the `", stringify!($fname), "` field.")]
559 #[inline]
560 pub fn $fname(&self) -> u8 {
561 let $p = self.0.size();
562 let _ = $p;
563 u8::try_from($($prev)*).unwrap()
564 }
565 define_vmctx_static_offsets!(
566 @chain $p
567 [ $($prev)* + vmctx_field_size!(($p) $($fty)*) ]
568 [ $($rest)* ]
569 $dyn
570 );
571 };
572
573 (@dyn_chain $p:ident [ $($prev:tt)* ] [ align { $al:tt } $($rest:tt)* ]) => {
576 define_vmctx_static_offsets!(
577 @dyn_chain $p
578 [ crate::vmctxtypes::align_up($($prev)*, vmctx_align_value!(($p) $al)) ]
579 [ $($rest)* ]
580 );
581 };
582 (@dyn_chain $p:ident [ $($prev:tt)* ] [
583 field { #[ptr_size_offset] $(# $fattr:tt)* $fname:ident : $($fty:tt)* } $($rest:tt)*
584 ]) => {
585 #[doc = concat!("The offset of the `", stringify!($fname), "` field.")]
586 #[inline]
587 pub fn $fname(&self) -> u32 {
588 let $p = self.0.size();
589 let _ = $p;
590 $($prev)*
591 }
592 define_vmctx_static_offsets!(
593 @dyn_chain $p
594 [ $($prev)* + vmctx_field_size!(($p) $($fty)*) ]
595 [ $($rest)* ]
596 );
597 };
598 (@dyn_chain $p:ident [ $($prev:tt)* ] [
599 array {
600 #[ptr_size_offset] $(# $fattr:tt)*
601 $fname:ident [ $count:ident ; $Index:ident ] : $($fty:tt)*
602 } $($rest:tt)*
603 ]) => {
604 #[doc = concat!(
608 "The offset of the `index`th element of the `", stringify!($fname),
609 "` array.\n\nThis is not bounds checked: the array's length is a \
610 property of the particular module or component being compiled, which \
611 is exactly what this wrapper does not know."
612 )]
613 #[inline]
614 pub fn $fname(&self, index: impl crate::VmctxArrayIndex) -> u32 {
615 let $p = self.0.size();
616 let _ = $p;
617 let index = index.vmctx_array_index();
618 ($($prev)*) + vmctx_field_size!(($p) $($fty)*) * index
619 }
620 };
624 (@dyn_chain $p:ident [ $($prev:tt)* ] [ $($rest:tt)* ]) => {};
626
627 ( $(
628 {
629 $Name:ident $snake:ident
630 static { $($stat:tt)* }
631 dynamic { $($dyn:tt)* }
632 }
633 )* ) => {
634 $(
635 #[doc = concat!("Offsets of the statically-positioned fields within the `",
636 stringify!($Name), "` type.")]
637 pub struct $Name<P: PtrSize>(pub P);
638
639 impl<P: PtrSize> $Name<P> {
640 define_vmctx_static_offsets!(@chain ptr [ 0u32 ] [ $($stat)* ] [ $($dyn)* ]);
641 }
642 )*
643 };
644}
645
646pub mod offsets {
653 use super::{NUM_COMPONENT_CONTEXT_SLOTS, PtrSize, align};
654
655 for_each_vm_type!(define_vm_type_offsets);
656 for_each_vmctx_type!(define_vmctx_static_offsets);
657}
658
659impl<P: PtrSize> offsets::VMStoreContext<P> {
662 pub fn gc_heap_base(&self) -> u8 {
664 let offset = self.gc_heap() + self.0.vm_memory_definition().base();
665 debug_assert!(offset < self.last_wasm_exit_trampoline_fp());
666 offset
667 }
668
669 pub fn gc_heap_current_length(&self) -> u8 {
672 let offset = self.gc_heap() + self.0.vm_memory_definition().current_length();
673 debug_assert!(offset < self.last_wasm_exit_trampoline_fp());
674 offset
675 }
676}
677
678macro_rules! define_ptr_size_vm_type_accessors {
681 ( $(
682 $(#[doc = $sdoc:literal])*
683 $(#[cfg($($scfg:tt)*)])?
684 $(#[derive($($d:ident),*)])?
685 #[repr($($repr:tt)*)]
686 #[snake_name = $snake:ident]
687 $svis:vis $kind:ident $Name:ident {
688 $($body:tt)*
689 }
690 )* ) => {
691 $(
692 #[doc = concat!("Get the [`offsets::", stringify!($Name), "`] offsets for this pointer size.")]
693 #[inline]
694 fn $snake(&self) -> offsets::$Name<&Self> {
695 offsets::$Name(self)
696 }
697 )*
698 };
699}
700
701macro_rules! define_ptr_size_vmctx_type_accessors {
704 ( $(
705 {
706 $Name:ident $snake:ident
707 static { $($stat:tt)* }
708 dynamic { $($dyn:tt)* }
709 }
710 )* ) => {
711 $(
712 #[doc = concat!("Get the [`offsets::", stringify!($Name),
713 "`] offsets for this pointer size.")]
714 #[inline]
715 fn $snake(&self) -> offsets::$Name<&Self> {
716 offsets::$Name(self)
717 }
718 )*
719 };
720}
721
722#[derive(Debug, Clone, Copy)]
725pub struct VMOffsets<P> {
726 pub ptr: P,
728 pub num_imported_functions: u32,
730 pub num_imported_tables: u32,
732 pub num_imported_memories: u32,
734 pub num_imported_globals: u32,
736 pub num_imported_tags: u32,
738 pub num_defined_tables: u32,
740 pub num_defined_memories: u32,
742 pub num_owned_memories: u32,
744 pub num_shadow_memories: u32,
748 pub num_defined_globals: u32,
750 pub num_defined_tags: u32,
752 pub num_escaped_funcs: u32,
755 pub num_runtime_data: u32,
757 pub has_startup_func: bool,
759
760 imported_memories: u32,
762 memories: u32,
763 owned_memories: u32,
764 shadow_memories: u32,
765 imported_functions: u32,
766 imported_tables: u32,
767 imported_globals: u32,
768 imported_tags: u32,
769 tables: u32,
770 globals: u32,
771 tags: u32,
772 func_refs: u32,
773 startup_func_ref: u32,
774 runtime_data_bases: u32,
775 runtime_data_lengths: u32,
776 size: u32,
777}
778
779pub trait PtrSize {
781 fn size(&self) -> u8;
783
784 for_each_vm_type!(define_ptr_size_vm_type_accessors);
787
788 for_each_vmctx_type!(define_ptr_size_vmctx_type_accessors);
791
792 #[inline]
794 fn size_of_vmshared_type_index(&self) -> u8 {
795 4
796 }
797
798 #[inline]
800 fn align_of_vmshared_type_index(&self) -> u8 {
801 4
802 }
803
804 #[inline]
806 fn maximum_value_size(&self) -> u8 {
807 16
808 }
809
810 #[inline]
812 fn size_of_vmmemory_pointer(&self) -> u8 {
813 self.size()
814 }
815
816 fn vmarray_call_host_func_context_func_ref(&self) -> u8 {
820 u8::try_from(align(
821 u32::try_from(core::mem::size_of::<u32>()).unwrap(),
822 u32::from(self.size()),
823 ))
824 .unwrap()
825 }
826
827 fn size_of_vmstack_chain(&self) -> u8 {
829 2 * self.size()
830 }
831
832 fn vmcontobj_contref(&self) -> u8 {
836 0
837 }
838
839 fn vmcontobj_revision(&self) -> u8 {
841 self.size()
842 }
843
844 fn size_of_vmcontobj(&self) -> u8 {
846 u8::try_from(align(
847 u32::from(self.vmcontobj_revision())
848 + u32::try_from(core::mem::size_of::<usize>()).unwrap(),
849 u32::from(self.size()),
850 ))
851 .unwrap()
852 }
853}
854
855pub trait GetPtrSize {
857 type Ptr: PtrSize;
859
860 fn get_ptr_size(&self) -> &Self::Ptr;
862}
863
864impl<P> GetPtrSize for P
865where
866 P: PtrSize,
867{
868 type Ptr = Self;
869
870 #[inline]
871 fn get_ptr_size(&self) -> &Self::Ptr {
872 self
873 }
874}
875
876#[derive(Clone, Copy)]
878pub struct HostPtr;
879
880impl PtrSize for HostPtr {
881 #[inline]
882 fn size(&self) -> u8 {
883 core::mem::size_of::<usize>() as u8
884 }
885}
886
887impl PtrSize for u8 {
888 #[inline]
889 fn size(&self) -> u8 {
890 *self
891 }
892}
893
894impl<P> PtrSize for &'_ P
895where
896 P: PtrSize + ?Sized,
897{
898 #[inline]
899 fn size(&self) -> u8 {
900 (**self).size()
901 }
902}
903
904#[derive(Debug, Clone, Copy)]
906pub struct VMOffsetsFields<P> {
907 pub ptr: P,
909 pub num_imported_functions: u32,
911 pub num_imported_tables: u32,
913 pub num_imported_memories: u32,
915 pub num_imported_globals: u32,
917 pub num_imported_tags: u32,
919 pub num_defined_tables: u32,
921 pub num_defined_memories: u32,
923 pub num_owned_memories: u32,
925 pub num_shadow_memories: u32,
929 pub num_defined_globals: u32,
931 pub num_defined_tags: u32,
933 pub num_escaped_funcs: u32,
936 pub num_runtime_data: u32,
938 pub has_startup_func: bool,
940}
941
942impl<P: PtrSize> VMOffsets<P> {
943 pub fn new(ptr: P, module: &Module) -> Self {
945 let num_owned_memories = module
946 .memories
947 .iter()
948 .skip(module.num_imported_memories)
949 .filter(|p| !p.1.shared)
950 .count()
951 .try_into()
952 .unwrap();
953 VMOffsets::from(VMOffsetsFields {
954 ptr,
955 num_imported_functions: cast_to_u32(module.num_imported_funcs),
956 num_imported_tables: cast_to_u32(module.num_imported_tables),
957 num_imported_memories: cast_to_u32(module.num_imported_memories),
958 num_imported_globals: cast_to_u32(module.num_imported_globals),
959 num_imported_tags: cast_to_u32(module.num_imported_tags),
960 num_defined_tables: cast_to_u32(module.num_defined_tables()),
961 num_defined_memories: cast_to_u32(module.num_defined_memories()),
962 num_owned_memories,
963 num_shadow_memories: if module.has_shadow_memories {
964 cast_to_u32(module.memories.len())
965 } else {
966 0
967 },
968 num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),
969 num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),
970 num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),
971 num_runtime_data: cast_to_u32(module.runtime_data.len()),
972 has_startup_func: !module.startup.is_none(),
973 })
974 }
975
976 #[inline]
978 pub fn pointer_size(&self) -> u8 {
979 self.ptr.size()
980 }
981
982 pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {
987 macro_rules! calculate_sizes {
988 ($($name:ident: $desc:tt,)*) => {{
989 let VMOffsets {
990 ptr: _,
993 num_imported_functions: _,
994 num_imported_tables: _,
995 num_imported_memories: _,
996 num_imported_globals: _,
997 num_imported_tags: _,
998 num_defined_tables: _,
999 num_defined_globals: _,
1000 num_defined_memories: _,
1001 num_defined_tags: _,
1002 num_owned_memories: _,
1003 num_shadow_memories: _,
1004 num_escaped_funcs: _,
1005 num_runtime_data: _,
1006 has_startup_func: _,
1007
1008 size,
1010
1011 $($name,)*
1014 } = *self;
1015
1016 let mut last = size;
1020 $(
1021 assert!($name <= last);
1022 let tmp = $name;
1023 let $name = last - $name;
1024 last = tmp;
1025 )*
1026 assert_ne!(last, 0);
1027 IntoIterator::into_iter([
1028 $(($desc, $name),)*
1029 ("static vmctx data", last),
1030 ])
1031 }};
1032 }
1033
1034 calculate_sizes! {
1035 runtime_data_lengths: "runtime data lengths",
1036 runtime_data_bases: "runtime data base pointers",
1037 startup_func_ref: "startup funcref",
1038 func_refs: "module functions",
1039 tags: "defined tags",
1040 globals: "defined globals",
1041 tables: "defined tables",
1042 imported_tags: "imported tags",
1043 imported_globals: "imported globals",
1044 imported_tables: "imported tables",
1045 imported_functions: "imported functions",
1046 shadow_memories: "shadow memories",
1047 owned_memories: "owned memories",
1048 memories: "defined memories",
1049 imported_memories: "imported memories",
1050 }
1051 }
1052}
1053
1054impl<P: PtrSize> GetPtrSize for VMOffsets<P> {
1055 type Ptr = P;
1056
1057 #[inline]
1058 fn get_ptr_size(&self) -> &Self::Ptr {
1059 &self.ptr
1060 }
1061}
1062
1063impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {
1064 fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {
1065 let mut ret = Self {
1066 ptr: fields.ptr,
1067 num_imported_functions: fields.num_imported_functions,
1068 num_imported_tables: fields.num_imported_tables,
1069 num_imported_memories: fields.num_imported_memories,
1070 num_imported_globals: fields.num_imported_globals,
1071 num_imported_tags: fields.num_imported_tags,
1072 num_defined_tables: fields.num_defined_tables,
1073 num_defined_memories: fields.num_defined_memories,
1074 num_owned_memories: fields.num_owned_memories,
1075 num_shadow_memories: fields.num_shadow_memories,
1076 num_defined_globals: fields.num_defined_globals,
1077 num_defined_tags: fields.num_defined_tags,
1078 num_escaped_funcs: fields.num_escaped_funcs,
1079 num_runtime_data: fields.num_runtime_data,
1080 has_startup_func: fields.has_startup_func,
1081 imported_memories: 0,
1082 memories: 0,
1083 owned_memories: 0,
1084 shadow_memories: 0,
1085 imported_functions: 0,
1086 imported_tables: 0,
1087 imported_globals: 0,
1088 imported_tags: 0,
1089 tables: 0,
1090 globals: 0,
1091 tags: 0,
1092 func_refs: 0,
1093 startup_func_ref: 0,
1094 runtime_data_bases: 0,
1095 runtime_data_lengths: 0,
1096 size: 0,
1097 };
1098 ret.compute_field_offsets();
1099 ret
1100 }
1101}
1102
1103impl<P: PtrSize> VMOffsets<P> {
1105 pub fn size_of_vmfunction_body_ptr(&self) -> u8 {
1107 1 * self.pointer_size()
1108 }
1109}
1110
1111impl<P: PtrSize> VMOffsets<P> {
1113 #[inline]
1115 pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {
1116 self.pointer_size()
1117 }
1118}
1119
1120impl<P: PtrSize> VMOffsets<P> {
1122 #[inline]
1124 pub fn size_of_vmshared_type_index(&self) -> u8 {
1125 self.ptr.size_of_vmshared_type_index()
1126 }
1127}
1128
1129impl_vmctx_array_index! {
1130 MemoryIndex,
1131 DefinedMemoryIndex,
1132 OwnedMemoryIndex,
1133 FuncIndex,
1134 TableIndex,
1135 DefinedTableIndex,
1136 GlobalIndex,
1137 DefinedGlobalIndex,
1138 TagIndex,
1139 DefinedTagIndex,
1140 FuncRefIndex,
1141 RuntimeDataIndex,
1142 ModuleInternedTypeIndex,
1143}
1144
1145macro_rules! define_vmoffsets_dynamic_offsets {
1148 (@one VMContext $snake:ident { $($dyn:tt)* }) => {
1149 impl<P: PtrSize> VMOffsets<P> {
1151 define_vmctx_dynamic_offsets!(@accessors (self) [ $($dyn)* ]);
1152 define_vmctx_dynamic_offsets!(@compute_fn (self, next) $snake [ $($dyn)* ]);
1153
1154 #[inline]
1156 pub fn size_of_vmctx(&self) -> u32 {
1157 self.size
1158 }
1159 }
1160 };
1161 (@one $other:ident $snake:ident { $($dyn:tt)* }) => {};
1162
1163 ( $(
1164 {
1165 $Name:ident $snake:ident
1166 static { $($stat:tt)* }
1167 dynamic { $($dyn:tt)* }
1168 }
1169 )* ) => {
1170 $( define_vmoffsets_dynamic_offsets!(@one $Name $snake { $($dyn)* }); )*
1171 };
1172}
1173for_each_vmctx_type!(define_vmoffsets_dynamic_offsets);
1174
1175pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");
1179
1180pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");
1185
1186#[cfg(test)]
1187mod tests {
1188 use crate::vmoffsets::{VMOffsets, VMOffsetsFields, align};
1189
1190 #[test]
1191 fn alignment() {
1192 fn is_aligned(x: u32) -> bool {
1193 x % 16 == 0
1194 }
1195 assert!(is_aligned(align(0, 16)));
1196 assert!(is_aligned(align(32, 16)));
1197 assert!(is_aligned(align(33, 16)));
1198 assert!(is_aligned(align(31, 16)));
1199 }
1200
1201 #[test]
1202 fn pointer_fields_aligned_after_tags() {
1203 for ptr in [4u8, 8] {
1204 for num_defined_tags in 0..4 {
1205 let offsets = VMOffsets::from(VMOffsetsFields {
1206 ptr,
1207 num_imported_functions: 0,
1208 num_imported_tables: 0,
1209 num_imported_memories: 0,
1210 num_imported_globals: 0,
1211 num_imported_tags: 0,
1212 num_defined_tables: 0,
1213 num_defined_memories: 0,
1214 num_owned_memories: 0,
1215 num_shadow_memories: 0,
1216 num_defined_globals: 0,
1217 num_defined_tags,
1218 num_escaped_funcs: 1,
1219 num_runtime_data: 1,
1220 has_startup_func: true,
1221 });
1222 let ptr = u32::from(ptr);
1223 assert_eq!(offsets.func_refs % ptr, 0);
1224 assert_eq!(offsets.startup_func_ref % ptr, 0);
1225 assert_eq!(offsets.runtime_data_bases % ptr, 0);
1226 }
1227 }
1228 }
1229}
1230
1231pub const VM_LAZY_THREAD_FORCED: u64 = 1;