use crate::GetPtrSize;
use crate::PtrSize;
use crate::component::*;
pub const VMCOMPONENT_MAGIC: u32 = u32::from_le_bytes(*b"comp");
#[derive(Debug, Clone, Copy)]
pub struct VMComponentOffsets<P> {
pub ptr: P,
pub num_lowerings: u32,
pub num_runtime_memories: u32,
pub num_runtime_tables: u32,
pub num_runtime_reallocs: u32,
pub num_runtime_callbacks: u32,
pub num_runtime_post_returns: u32,
pub num_runtime_component_instances: u32,
pub num_trampolines: u32,
pub num_unsafe_intrinsics: u32,
pub num_resources: u32,
may_leave: u32,
trampoline_func_refs: u32,
intrinsic_func_refs: u32,
lowerings: u32,
memories: u32,
tables: u32,
reallocs: u32,
callbacks: u32,
post_returns: u32,
resource_destructors: u32,
size: u32,
}
impl<P: PtrSize> GetPtrSize for VMComponentOffsets<P> {
type Ptr = P;
#[inline]
fn get_ptr_size(&self) -> &Self::Ptr {
&self.ptr
}
}
impl_vmctx_array_index! {
RuntimeComponentInstanceIndex,
TrampolineIndex,
LoweredIndex,
RuntimeMemoryIndex,
RuntimeTableIndex,
RuntimeReallocIndex,
RuntimeCallbackIndex,
RuntimePostReturnIndex,
ResourceIndex,
}
impl crate::VmctxArrayIndex for UnsafeIntrinsic {
#[inline]
fn vmctx_array_index(self) -> u32 {
self.index()
}
}
macro_rules! define_vmcomponent_offsets_dynamic_offsets {
(@one VMComponentContext $snake:ident { $($dyn:tt)* }) => {
impl<P: PtrSize> VMComponentOffsets<P> {
define_vmctx_dynamic_offsets!(@accessors (self) [ $($dyn)* ]);
define_vmctx_dynamic_offsets!(@compute_fn (self, next) $snake [ $($dyn)* ]);
#[inline]
pub fn size_of_vmctx(&self) -> u32 {
self.size
}
}
};
(@one $other:ident $snake:ident { $($dyn:tt)* }) => {};
( $(
{
$Name:ident $snake:ident
static { $($stat:tt)* }
dynamic { $($dyn:tt)* }
}
)* ) => {
$( define_vmcomponent_offsets_dynamic_offsets!(@one $Name $snake { $($dyn)* }); )*
};
}
for_each_vmctx_type!(define_vmcomponent_offsets_dynamic_offsets);
impl<P: PtrSize> VMComponentOffsets<P> {
pub fn new(ptr: P, component: &Component) -> Self {
assert_eq!(ptr.vmcomponent().magic(), 0);
let mut ret = Self {
ptr,
num_lowerings: component.num_lowerings,
num_runtime_memories: component.num_runtime_memories,
num_runtime_tables: component.num_runtime_tables,
num_runtime_reallocs: component.num_runtime_reallocs,
num_runtime_callbacks: component.num_runtime_callbacks,
num_runtime_post_returns: component.num_runtime_post_returns,
num_runtime_component_instances: component.num_runtime_component_instances,
num_trampolines: component.trampolines.len().try_into().unwrap(),
num_unsafe_intrinsics: if let Some(i) = component
.unsafe_intrinsics
.iter()
.rposition(|x| x.is_some())
{
u32::try_from(i + 1).unwrap()
} else {
0
},
num_resources: component.num_resources,
may_leave: 0,
trampoline_func_refs: 0,
intrinsic_func_refs: 0,
lowerings: 0,
memories: 0,
tables: 0,
reallocs: 0,
callbacks: 0,
post_returns: 0,
resource_destructors: 0,
size: 0,
};
ret.compute_field_offsets();
debug_assert!(
(0..ret.num_runtime_component_instances)
.map(RuntimeComponentInstanceIndex::from_u32)
.all(|i| ret.may_leave().at(i) == ret.ptr.vmcomponent().may_leave(i))
);
ret
}
#[inline]
pub fn pointer_size(&self) -> u8 {
self.ptr.size()
}
#[inline]
pub fn lowering_callee(&self, index: LoweredIndex) -> u32 {
self.lowerings().at(index) + self.lowering_callee_offset()
}
#[inline]
pub fn lowering_data(&self, index: LoweredIndex) -> u32 {
self.lowerings().at(index) + self.lowering_data_offset()
}
#[inline]
pub fn lowering_size(&self) -> u8 {
2 * self.ptr.size()
}
#[inline]
pub fn lowering_callee_offset(&self) -> u32 {
0
}
#[inline]
pub fn lowering_data_offset(&self) -> u32 {
u32::from(self.ptr.size())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flag_offsets_match_layout() {
for ptr in [4u8, 8] {
for num_runtime_component_instances in 0..8 {
let component = Component {
num_runtime_component_instances,
..Default::default()
};
let offsets = VMComponentOffsets::new(ptr, &component);
for i in 0..num_runtime_component_instances {
let index = RuntimeComponentInstanceIndex::from_u32(i);
assert_eq!(
offsets.may_leave().at(index),
ptr.vmcomponent().may_leave(index)
);
}
}
}
}
}