#[macro_export]
macro_rules! for_each_vmctx_type {
($mac:ident) => {
$mac! {
{
VMContext vmctx
static {
field { #[readonly] #[can_move] magic: u32 }
align { ptr }
field { #[readonly] #[can_move] store_context: VmPtr<VMStoreContext> }
field {
#[readonly]
#[can_move]
#[pointee(
#[readonly]
#[can_move]
BuiltinFunctionsArray as builtin_functions_array[BuiltinFunctionIndex]:
unsafe extern "C" fn
)]
builtin_functions: VmPtr<VMBuiltinFunctionsArray>
}
field {
#[pointee(EpochCounter as epoch_counter: AtomicU64)]
epoch_ptr: VmPtr<AtomicU64>
}
field { #[readonly] #[can_move] gc_heap_data: VmPtr<u8> }
field {
#[readonly]
#[can_move]
#[pointee(
#[readonly]
#[can_move]
TypeIdsArray as type_ids_array[ModuleInternedTypeIndex]:
VMSharedTypeIndex
)]
type_ids: VmPtr<VMSharedTypeIndex>
}
}
dynamic {
array {
#[aggregate]
imported_memories[num_imported_memories; MemoryIndex]: VMMemoryImport
}
array {
#[readonly]
#[can_move]
memories[num_defined_memories; DefinedMemoryIndex]: VmPtr<VMMemoryDefinition>
}
array {
#[aggregate]
owned_memories[num_owned_memories; OwnedMemoryIndex]: VMMemoryDefinition
}
array {
#[aggregate]
imported_functions[num_imported_functions; FuncIndex]: VMFunctionImport
}
array {
#[aggregate]
imported_tables[num_imported_tables; TableIndex]: VMTableImport
}
array {
#[aggregate]
imported_globals[num_imported_globals; GlobalIndex]: VMGlobalImport
}
array {
#[aggregate]
imported_tags[num_imported_tags; TagIndex]: VMTagImport
}
array {
#[aggregate]
tables[num_defined_tables; DefinedTableIndex]: VMTableDefinition
}
align { 16 }
array {
#[aggregate]
globals[num_defined_globals; DefinedGlobalIndex]: VMGlobalDefinition
}
array {
#[aggregate]
tags[num_defined_tags; DefinedTagIndex]: VMTagDefinition
}
array {
#[aggregate]
func_refs[num_escaped_funcs; FuncRefIndex]: VMFuncRef
}
optional {
#[aggregate]
startup_func_ref[if has_startup_func]: VMFuncRef
}
array {
runtime_data_bases[num_runtime_data; RuntimeDataIndex]: VmPtr<u8>
}
array {
runtime_data_lengths[num_runtime_data; RuntimeDataIndex]: u32
}
}
}
{
VMComponentContext vmcomponent
static {
field { #[readonly] #[can_move] magic: u32 }
align { ptr }
field {
#[readonly]
#[pointee(
#[readonly]
#[can_move]
ComponentBuiltinFunctionsArray as builtins_array[ComponentBuiltinFunctionIndex]:
unsafe extern "C" fn
)]
builtins: VmPtr<VMComponentBuiltins>
}
field { #[readonly] #[can_move] store_context: VmPtr<VMStoreContext> }
}
dynamic {
align { 16 }
array {
#[ptr_size_offset]
#[access_as = u32]
may_leave[num_runtime_component_instances; RuntimeComponentInstanceIndex]: VMGlobalDefinition
}
align { ptr }
array {
#[aggregate]
trampoline_func_refs[num_trampolines; TrampolineIndex]: VMFuncRef
}
array {
#[aggregate]
intrinsic_func_refs[num_unsafe_intrinsics; UnsafeIntrinsic]: VMFuncRef
}
array {
#[aggregate]
lowerings[num_lowerings; LoweredIndex]: VMLowering
}
array {
memories
[num_runtime_memories; RuntimeMemoryIndex]: VmPtr<VMMemoryDefinition>
}
array {
#[aggregate]
tables[num_runtime_tables; RuntimeTableIndex]: VMTableImport
}
array {
reallocs[num_runtime_reallocs; RuntimeReallocIndex]: VmPtr<VMFuncRef>
}
array {
callbacks[num_runtime_callbacks; RuntimeCallbackIndex]: VmPtr<VMFuncRef>
}
array {
post_returns[num_runtime_post_returns; RuntimePostReturnIndex]: VmPtr<VMFuncRef>
}
array {
#[readonly]
resource_destructors[num_resources; ResourceIndex]: VmPtr<VMFuncRef>
}
}
}
}
};
}
#[inline]
pub(crate) fn align_up(offset: u32, align: u32) -> u32 {
debug_assert!(align.is_power_of_two());
(offset + (align - 1)) & !(align - 1)
}
#[inline]
pub(crate) fn cadd(a: u32, b: u32) -> u32 {
a.checked_add(b).unwrap()
}
#[inline]
pub(crate) fn cmul(count: u32, size: u32) -> u32 {
count.checked_mul(size).unwrap()
}
#[allow(
unused_macro_rules,
reason = "some element types only appear in `VMComponentContext`, and so are \
unused when the `component-model` feature is disabled"
)]
macro_rules! vmctx_field_size {
(($p:expr) u32) => {
4u32
};
(($p:expr) VmPtr < $g:ident >) => {
u32::from($p)
};
(($p:expr) VMLowering) => {
2u32 * u32::from($p)
};
(($p:expr) $Name:ident) => {
u32::from(crate::vmoffsets::offsets::$Name($p).size())
};
}
macro_rules! vmctx_align_value {
(($p:expr) ptr) => {
u32::from($p)
};
(($p:expr) $n:literal) => {
$n
};
}
#[allow(
unused_macro_rules,
reason = "single dynamically-positioned fields only appear in \
`VMComponentContext`, and so are unused when the `component-model` \
feature is disabled"
)]
macro_rules! define_vmctx_dynamic_offsets {
(@accessors ($s:ident) [ $($kind:ident $entry:tt)* ]) => {
$( define_vmctx_dynamic_offsets!(@accessor ($s) $kind $entry); )*
};
(@accessor ($s:ident) align { $al:tt }) => {};
(@accessor ($s:ident) field { $(# $fattr:tt)* $fname:ident : $($fty:tt)* }) => {
#[doc = concat!("The offset of the `", stringify!($fname), "` field.")]
#[inline]
pub fn $fname(&$s) -> u32 {
$s.$fname
}
};
(@accessor ($s:ident) array {
$(# $fattr:tt)* $fname:ident [ $count:ident ; $Index:ident ] : $($fty:tt)*
}) => {
#[doc = concat!("The offsets of the `", stringify!($fname), "` array.")]
#[inline]
pub fn $fname(&$s) -> $crate::ArrayOffsets<$Index> {
$crate::ArrayOffsets::new(
$s.$fname,
vmctx_field_size!(($s.ptr.size()) $($fty)*),
$s.$count,
)
}
};
(@accessor ($s:ident) optional {
$(# $fattr:tt)* $fname:ident [ if $flag:ident ] : $($fty:tt)*
}) => {
#[doc = concat!(
"The offset of the `", stringify!($fname), "` field.\n\n",
"Panics if `", stringify!($flag), "` is false, in which case this \
field is not present at all."
)]
#[inline]
pub fn $fname(&$s) -> u32 {
assert!($s.$flag);
$s.$fname
}
};
(@compute_fn ($s:ident, $next:ident) $snake:ident [ $($kind:ident $entry:tt)* ]) => {
fn compute_field_offsets(&mut $s) {
let mut $next = u32::from($s.ptr.$snake().end_of_static_fields());
$( define_vmctx_dynamic_offsets!(@compute ($s, $next) $kind $entry); )*
$s.size = $next;
}
};
(@compute ($s:ident, $next:ident) align { $al:tt }) => {
$next = crate::vmctxtypes::align_up($next, vmctx_align_value!(($s.ptr.size()) $al));
};
(@compute ($s:ident, $next:ident) field {
$(# $fattr:tt)* $fname:ident : $($fty:tt)*
}) => {
$s.$fname = $next;
$next = crate::vmctxtypes::cadd($next, vmctx_field_size!(($s.ptr.size()) $($fty)*));
};
(@compute ($s:ident, $next:ident) array {
$(# $fattr:tt)* $fname:ident [ $count:ident ; $Index:ident ] : $($fty:tt)*
}) => {
$s.$fname = $next;
$next = crate::vmctxtypes::cadd(
$next,
crate::vmctxtypes::cmul($s.$count, vmctx_field_size!(($s.ptr.size()) $($fty)*)),
);
};
(@compute ($s:ident, $next:ident) optional {
$(# $fattr:tt)* $fname:ident [ if $flag:ident ] : $($fty:tt)*
}) => {
$s.$fname = $next;
$next = crate::vmctxtypes::cadd(
$next,
if $s.$flag {
vmctx_field_size!(($s.ptr.size()) $($fty)*)
} else {
0
},
);
};
}
#[derive(Debug, Clone, Copy)]
pub struct ArrayOffsets<I> {
begin: u32,
stride: u32,
count: u32,
_index: core::marker::PhantomData<I>,
}
impl<I> ArrayOffsets<I> {
#[inline]
pub fn new(begin: u32, stride: u32, count: u32) -> Self {
ArrayOffsets {
begin,
stride,
count,
_index: core::marker::PhantomData,
}
}
#[inline]
pub fn begin(&self) -> u32 {
self.begin
}
#[inline]
pub fn stride(&self) -> u32 {
self.stride
}
#[inline]
pub fn count(&self) -> u32 {
self.count
}
}
impl<I: VmctxArrayIndex> ArrayOffsets<I> {
#[inline]
pub fn at(&self, index: I) -> u32 {
let index = index.vmctx_array_index();
assert!(index < self.count);
self.begin + index * self.stride
}
}
pub trait VmctxArrayIndex: Copy {
fn vmctx_array_index(self) -> u32;
}
macro_rules! impl_vmctx_array_index {
($($ty:ty),* $(,)?) => {
$(
impl $crate::VmctxArrayIndex for $ty {
#[inline]
fn vmctx_array_index(self) -> u32 {
self.as_u32()
}
}
)*
};
}