Path: blob/main/crates/environ/src/vmoffsets.rs
3076 views
//! Offsets and sizes of various structs in `wasmtime::runtime::vm::*` that are1//! accessed directly by compiled Wasm code.23// Currently the `VMContext` allocation by field looks like this:4//5// struct VMContext {6// // Fixed-width data comes first so the calculation of the offset of7// // these fields is a compile-time constant when using `HostPtr`.8// magic: u32,9// _padding: u32, // (On 64-bit systems)10// vm_store_context: *const VMStoreContext,11// builtin_functions: *mut VMBuiltinFunctionsArray,12// epoch_ptr: *mut AtomicU64,13// gc_heap_data: *mut T, // Collector-specific pointer14// type_ids: *const VMSharedTypeIndex,15//16// // Variable-width fields come after the fixed-width fields above. Place17// // memory-related items first as they're some of the most frequently18// // accessed items and minimizing their offset in this structure can19// // shrink the size of load/store instruction offset immediates on20// // platforms like x64 and Pulley (e.g. fit in an 8-bit offset instead21// // of needing a 32-bit offset)22// imported_memories: [VMMemoryImport; module.num_imported_memories],23// memories: [*mut VMMemoryDefinition; module.num_defined_memories],24// owned_memories: [VMMemoryDefinition; module.num_owned_memories],25// imported_functions: [VMFunctionImport; module.num_imported_functions],26// imported_tables: [VMTableImport; module.num_imported_tables],27// imported_globals: [VMGlobalImport; module.num_imported_globals],28// imported_tags: [VMTagImport; module.num_imported_tags],29// tables: [VMTableDefinition; module.num_defined_tables],30// globals: [VMGlobalDefinition; module.num_defined_globals],31// tags: [VMTagDefinition; module.num_defined_tags],32// func_refs: [VMFuncRef; module.num_escaped_funcs],33// }3435use crate::{36DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, DefinedTagIndex, FuncIndex,37FuncRefIndex, GlobalIndex, MemoryIndex, Module, OwnedMemoryIndex, TableIndex, TagIndex,38};39use cranelift_entity::packed_option::ReservedValue;4041#[cfg(target_pointer_width = "32")]42fn cast_to_u32(sz: usize) -> u32 {43u32::try_from(sz).unwrap()44}45#[cfg(target_pointer_width = "64")]46fn cast_to_u32(sz: usize) -> u32 {47u32::try_from(sz).expect("overflow in cast from usize to u32")48}4950/// Align an offset used in this module to a specific byte-width by rounding up51#[inline]52fn align(offset: u32, width: u32) -> u32 {53(offset + (width - 1)) / width * width54}5556/// This class computes offsets to fields within `VMContext` and other57/// related structs that JIT code accesses directly.58#[derive(Debug, Clone, Copy)]59pub struct VMOffsets<P> {60/// The size in bytes of a pointer on the target.61pub ptr: P,62/// The number of imported functions in the module.63pub num_imported_functions: u32,64/// The number of imported tables in the module.65pub num_imported_tables: u32,66/// The number of imported memories in the module.67pub num_imported_memories: u32,68/// The number of imported globals in the module.69pub num_imported_globals: u32,70/// The number of imported tags in the module.71pub num_imported_tags: u32,72/// The number of defined tables in the module.73pub num_defined_tables: u32,74/// The number of defined memories in the module.75pub num_defined_memories: u32,76/// The number of memories owned by the module instance.77pub num_owned_memories: u32,78/// The number of defined globals in the module.79pub num_defined_globals: u32,80/// The number of defined tags in the module.81pub num_defined_tags: u32,82/// The number of escaped functions in the module, the size of the func_refs83/// array.84pub num_escaped_funcs: u32,8586// precalculated offsets of various member fields87imported_functions: u32,88imported_tables: u32,89imported_memories: u32,90imported_globals: u32,91imported_tags: u32,92defined_tables: u32,93defined_memories: u32,94owned_memories: u32,95defined_globals: u32,96defined_tags: u32,97defined_func_refs: u32,98size: u32,99}100101/// Trait used for the `ptr` representation of the field of `VMOffsets`102pub trait PtrSize {103/// Returns the pointer size, in bytes, for the target.104fn size(&self) -> u8;105106/// The offset of the `VMContext::store_context` field107fn vmcontext_store_context(&self) -> u8 {108u8::try_from(align(109u32::try_from(core::mem::size_of::<u32>()).unwrap(),110u32::from(self.size()),111))112.unwrap()113}114115/// The offset of the `VMContext::builtin_functions` field116fn vmcontext_builtin_functions(&self) -> u8 {117self.vmcontext_store_context() + self.size()118}119120/// The offset of the `array_call` field.121#[inline]122fn vm_func_ref_array_call(&self) -> u8 {1230 * self.size()124}125126/// The offset of the `wasm_call` field.127#[inline]128fn vm_func_ref_wasm_call(&self) -> u8 {1291 * self.size()130}131132/// The offset of the `type_index` field.133#[inline]134fn vm_func_ref_type_index(&self) -> u8 {1352 * self.size()136}137138/// The offset of the `vmctx` field.139#[inline]140fn vm_func_ref_vmctx(&self) -> u8 {1413 * self.size()142}143144/// Return the size of `VMFuncRef`.145#[inline]146fn size_of_vm_func_ref(&self) -> u8 {1474 * self.size()148}149150/// Return the size of `VMGlobalDefinition`; this is the size of the largest value type (i.e. a151/// V128).152#[inline]153fn size_of_vmglobal_definition(&self) -> u8 {15416155}156157/// Return the size of `VMTagDefinition`.158#[inline]159fn size_of_vmtag_definition(&self) -> u8 {1604161}162163/// This is the size of the largest value type (i.e. a V128).164#[inline]165fn maximum_value_size(&self) -> u8 {166self.size_of_vmglobal_definition()167}168169// Offsets within `VMStoreContext`170171/// Return the offset of the `fuel_consumed` field of `VMStoreContext`172#[inline]173fn vmstore_context_fuel_consumed(&self) -> u8 {1740175}176177/// Return the offset of the `epoch_deadline` field of `VMStoreContext`178#[inline]179fn vmstore_context_epoch_deadline(&self) -> u8 {180self.vmstore_context_fuel_consumed() + 8181}182183/// Return the offset of the `stack_limit` field of `VMStoreContext`184#[inline]185fn vmstore_context_stack_limit(&self) -> u8 {186self.vmstore_context_epoch_deadline() + 8187}188189/// Return the offset of the `gc_heap` field of `VMStoreContext`.190#[inline]191fn vmstore_context_gc_heap(&self) -> u8 {192self.vmstore_context_stack_limit() + self.size()193}194195/// Return the offset of the `gc_heap.base` field within a `VMStoreContext`.196fn vmstore_context_gc_heap_base(&self) -> u8 {197let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_base();198debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());199offset200}201202/// Return the offset of the `gc_heap.current_length` field within a `VMStoreContext`.203fn vmstore_context_gc_heap_current_length(&self) -> u8 {204let offset = self.vmstore_context_gc_heap() + self.vmmemory_definition_current_length();205debug_assert!(offset < self.vmstore_context_last_wasm_exit_trampoline_fp());206offset207}208209/// Return the offset of the `last_wasm_exit_trampoline_fp` field210/// of `VMStoreContext`.211fn vmstore_context_last_wasm_exit_trampoline_fp(&self) -> u8 {212self.vmstore_context_gc_heap() + self.size_of_vmmemory_definition()213}214215/// Return the offset of the `last_wasm_exit_pc` field of `VMStoreContext`.216fn vmstore_context_last_wasm_exit_pc(&self) -> u8 {217self.vmstore_context_last_wasm_exit_trampoline_fp() + self.size()218}219220/// Return the offset of the `last_wasm_entry_sp` field of `VMStoreContext`.221fn vmstore_context_last_wasm_entry_sp(&self) -> u8 {222self.vmstore_context_last_wasm_exit_pc() + self.size()223}224225/// Return the offset of the `last_wasm_entry_fp` field of `VMStoreContext`.226fn vmstore_context_last_wasm_entry_fp(&self) -> u8 {227self.vmstore_context_last_wasm_entry_sp() + self.size()228}229230/// Return the offset of the `last_wasm_entry_trap_handler` field of `VMStoreContext`.231fn vmstore_context_last_wasm_entry_trap_handler(&self) -> u8 {232self.vmstore_context_last_wasm_entry_fp() + self.size()233}234235/// Return the offset of the `stack_chain` field of `VMStoreContext`.236fn vmstore_context_stack_chain(&self) -> u8 {237self.vmstore_context_last_wasm_entry_trap_handler() + self.size()238}239240/// Return the offset of the `stack_chain` field of `VMStoreContext`.241fn vmstore_context_store_data(&self) -> u8 {242self.vmstore_context_stack_chain() + self.size_of_vmstack_chain()243}244245// Offsets within `VMMemoryDefinition`246247/// The offset of the `base` field.248#[inline]249fn vmmemory_definition_base(&self) -> u8 {2500 * self.size()251}252253/// The offset of the `current_length` field.254#[inline]255fn vmmemory_definition_current_length(&self) -> u8 {2561 * self.size()257}258259/// Return the size of `VMMemoryDefinition`.260#[inline]261fn size_of_vmmemory_definition(&self) -> u8 {2622 * self.size()263}264265/// Return the size of `*mut VMMemoryDefinition`.266#[inline]267fn size_of_vmmemory_pointer(&self) -> u8 {268self.size()269}270271// Offsets within `VMArrayCallHostFuncContext`.272273/// Return the offset of `VMArrayCallHostFuncContext::func_ref`.274fn vmarray_call_host_func_context_func_ref(&self) -> u8 {275u8::try_from(align(276u32::try_from(core::mem::size_of::<u32>()).unwrap(),277u32::from(self.size()),278))279.unwrap()280}281282/// Return the size of `VMStackChain`.283fn size_of_vmstack_chain(&self) -> u8 {2842 * self.size()285}286287// Offsets within `VMStackLimits`288289/// Return the offset of `VMStackLimits::stack_limit`.290fn vmstack_limits_stack_limit(&self) -> u8 {2910292}293294/// Return the offset of `VMStackLimits::last_wasm_entry_fp`.295fn vmstack_limits_last_wasm_entry_fp(&self) -> u8 {296self.size()297}298299// Offsets within `VMHostArray`300301/// Return the offset of `VMHostArray::length`.302fn vmhostarray_length(&self) -> u8 {3030304}305306/// Return the offset of `VMHostArray::capacity`.307fn vmhostarray_capacity(&self) -> u8 {3084309}310311/// Return the offset of `VMHostArray::data`.312fn vmhostarray_data(&self) -> u8 {3138314}315316/// Return the size of `VMHostArray`.317fn size_of_vmhostarray(&self) -> u8 {3188 + self.size()319}320321// Offsets within `VMCommonStackInformation`322323/// Return the offset of `VMCommonStackInformation::limits`.324fn vmcommon_stack_information_limits(&self) -> u8 {3250 * self.size()326}327328/// Return the offset of `VMCommonStackInformation::state`.329fn vmcommon_stack_information_state(&self) -> u8 {3302 * self.size()331}332333/// Return the offset of `VMCommonStackInformation::handlers`.334fn vmcommon_stack_information_handlers(&self) -> u8 {335u8::try_from(align(336self.vmcommon_stack_information_state() as u32 + 4,337u32::from(self.size()),338))339.unwrap()340}341342/// Return the offset of `VMCommonStackInformation::first_switch_handler_index`.343fn vmcommon_stack_information_first_switch_handler_index(&self) -> u8 {344self.vmcommon_stack_information_handlers() + self.size_of_vmhostarray()345}346347/// Return the size of `VMCommonStackInformation`.348fn size_of_vmcommon_stack_information(&self) -> u8 {349u8::try_from(align(350self.vmcommon_stack_information_first_switch_handler_index() as u32 + 4,351u32::from(self.size()),352))353.unwrap()354}355356// Offsets within `VMContObj`357358/// Return the offset of `VMContObj::contref`359fn vmcontobj_contref(&self) -> u8 {3600361}362363/// Return the offset of `VMContObj::revision`364fn vmcontobj_revision(&self) -> u8 {365self.size()366}367368/// Return the size of `VMContObj`.369fn size_of_vmcontobj(&self) -> u8 {370u8::try_from(align(371u32::from(self.vmcontobj_revision())372+ u32::try_from(core::mem::size_of::<usize>()).unwrap(),373u32::from(self.size()),374))375.unwrap()376}377378// Offsets within `VMContRef`379380/// Return the offset of `VMContRef::common_stack_information`.381fn vmcontref_common_stack_information(&self) -> u8 {3820 * self.size()383}384385/// Return the offset of `VMContRef::parent_chain`.386fn vmcontref_parent_chain(&self) -> u8 {387u8::try_from(align(388(self.vmcontref_common_stack_information() + self.size_of_vmcommon_stack_information())389as u32,390u32::from(self.size()),391))392.unwrap()393}394395/// Return the offset of `VMContRef::last_ancestor`.396fn vmcontref_last_ancestor(&self) -> u8 {397self.vmcontref_parent_chain() + 2 * self.size()398}399400/// Return the offset of `VMContRef::revision`.401fn vmcontref_revision(&self) -> u8 {402self.vmcontref_last_ancestor() + self.size()403}404405/// Return the offset of `VMContRef::stack`.406fn vmcontref_stack(&self) -> u8 {407self.vmcontref_revision() + self.size()408}409410/// Return the offset of `VMContRef::args`.411fn vmcontref_args(&self) -> u8 {412self.vmcontref_stack() + 3 * self.size()413}414415/// Return the offset of `VMContRef::values`.416fn vmcontref_values(&self) -> u8 {417self.vmcontref_args() + self.size_of_vmhostarray()418}419420/// Return the offset to the `magic` value in this `VMContext`.421#[inline]422fn vmctx_magic(&self) -> u8 {423// This is required by the implementation of `VMContext::instance` and424// `VMContext::instance_mut`. If this value changes then those locations425// need to be updated.4260427}428429/// Return the offset to the `VMStoreContext` structure430#[inline]431fn vmctx_store_context(&self) -> u8 {432self.vmctx_magic() + self.size()433}434435/// Return the offset to the `VMBuiltinFunctionsArray` structure436#[inline]437fn vmctx_builtin_functions(&self) -> u8 {438self.vmctx_store_context() + self.size()439}440441/// Return the offset to the `*const AtomicU64` epoch-counter442/// pointer.443#[inline]444fn vmctx_epoch_ptr(&self) -> u8 {445self.vmctx_builtin_functions() + self.size()446}447448/// Return the offset to the `*mut T` collector-specific data.449///450/// This is a pointer that different collectors can use however they see451/// fit.452#[inline]453fn vmctx_gc_heap_data(&self) -> u8 {454self.vmctx_epoch_ptr() + self.size()455}456457/// The offset of the `type_ids` array pointer.458#[inline]459fn vmctx_type_ids_array(&self) -> u8 {460self.vmctx_gc_heap_data() + self.size()461}462463/// The end of statically known offsets in `VMContext`.464///465/// Data after this is dynamically sized.466#[inline]467fn vmctx_dynamic_data_start(&self) -> u8 {468self.vmctx_type_ids_array() + self.size()469}470}471472/// Type representing the size of a pointer for the current compilation host473#[derive(Clone, Copy)]474pub struct HostPtr;475476impl PtrSize for HostPtr {477#[inline]478fn size(&self) -> u8 {479core::mem::size_of::<usize>() as u8480}481}482483impl PtrSize for u8 {484#[inline]485fn size(&self) -> u8 {486*self487}488}489490/// Used to construct a `VMOffsets`491#[derive(Debug, Clone, Copy)]492pub struct VMOffsetsFields<P> {493/// The size in bytes of a pointer on the target.494pub ptr: P,495/// The number of imported functions in the module.496pub num_imported_functions: u32,497/// The number of imported tables in the module.498pub num_imported_tables: u32,499/// The number of imported memories in the module.500pub num_imported_memories: u32,501/// The number of imported globals in the module.502pub num_imported_globals: u32,503/// The number of imported tags in the module.504pub num_imported_tags: u32,505/// The number of defined tables in the module.506pub num_defined_tables: u32,507/// The number of defined memories in the module.508pub num_defined_memories: u32,509/// The number of memories owned by the module instance.510pub num_owned_memories: u32,511/// The number of defined globals in the module.512pub num_defined_globals: u32,513/// The number of defined tags in the module.514pub num_defined_tags: u32,515/// The number of escaped functions in the module, the size of the function516/// references array.517pub num_escaped_funcs: u32,518}519520impl<P: PtrSize> VMOffsets<P> {521/// Return a new `VMOffsets` instance, for a given pointer size.522pub fn new(ptr: P, module: &Module) -> Self {523let num_owned_memories = module524.memories525.iter()526.skip(module.num_imported_memories)527.filter(|p| !p.1.shared)528.count()529.try_into()530.unwrap();531VMOffsets::from(VMOffsetsFields {532ptr,533num_imported_functions: cast_to_u32(module.num_imported_funcs),534num_imported_tables: cast_to_u32(module.num_imported_tables),535num_imported_memories: cast_to_u32(module.num_imported_memories),536num_imported_globals: cast_to_u32(module.num_imported_globals),537num_imported_tags: cast_to_u32(module.num_imported_tags),538num_defined_tables: cast_to_u32(module.num_defined_tables()),539num_defined_memories: cast_to_u32(module.num_defined_memories()),540num_owned_memories,541num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),542num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),543num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),544})545}546547/// Returns the size, in bytes, of the target548#[inline]549pub fn pointer_size(&self) -> u8 {550self.ptr.size()551}552553/// Returns an iterator which provides a human readable description and a554/// byte size. The iterator returned will iterate over the bytes allocated555/// to the entire `VMOffsets` structure to explain where each byte size is556/// coming from.557pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {558macro_rules! calculate_sizes {559($($name:ident: $desc:tt,)*) => {{560let VMOffsets {561// These fields are metadata not talking about specific562// offsets of specific fields.563ptr: _,564num_imported_functions: _,565num_imported_tables: _,566num_imported_memories: _,567num_imported_globals: _,568num_imported_tags: _,569num_defined_tables: _,570num_defined_globals: _,571num_defined_memories: _,572num_defined_tags: _,573num_owned_memories: _,574num_escaped_funcs: _,575576// used as the initial size below577size,578579// exhaustively match the rest of the fields with input from580// the macro581$($name,)*582} = *self;583584// calculate the size of each field by relying on the inputs to585// the macro being in reverse order and determining the size of586// the field as the offset from the field to the last field.587let mut last = size;588$(589assert!($name <= last);590let tmp = $name;591let $name = last - $name;592last = tmp;593)*594assert_ne!(last, 0);595IntoIterator::into_iter([596$(($desc, $name),)*597("static vmctx data", last),598])599}};600}601602calculate_sizes! {603defined_func_refs: "module functions",604defined_tags: "defined tags",605defined_globals: "defined globals",606defined_tables: "defined tables",607imported_tags: "imported tags",608imported_globals: "imported globals",609imported_tables: "imported tables",610imported_functions: "imported functions",611owned_memories: "owned memories",612defined_memories: "defined memories",613imported_memories: "imported memories",614}615}616}617618impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {619fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {620let mut ret = Self {621ptr: fields.ptr,622num_imported_functions: fields.num_imported_functions,623num_imported_tables: fields.num_imported_tables,624num_imported_memories: fields.num_imported_memories,625num_imported_globals: fields.num_imported_globals,626num_imported_tags: fields.num_imported_tags,627num_defined_tables: fields.num_defined_tables,628num_defined_memories: fields.num_defined_memories,629num_owned_memories: fields.num_owned_memories,630num_defined_globals: fields.num_defined_globals,631num_defined_tags: fields.num_defined_tags,632num_escaped_funcs: fields.num_escaped_funcs,633imported_functions: 0,634imported_tables: 0,635imported_memories: 0,636imported_globals: 0,637imported_tags: 0,638defined_tables: 0,639defined_memories: 0,640owned_memories: 0,641defined_globals: 0,642defined_tags: 0,643defined_func_refs: 0,644size: 0,645};646647// Convenience functions for checked addition and multiplication.648// As side effect this reduces binary size by using only a single649// `#[track_caller]` location for each function instead of one for650// each individual invocation.651#[inline]652fn cadd(count: u32, size: u32) -> u32 {653count.checked_add(size).unwrap()654}655656#[inline]657fn cmul(count: u32, size: u8) -> u32 {658count.checked_mul(u32::from(size)).unwrap()659}660661let mut next_field_offset = u32::from(ret.ptr.vmctx_dynamic_data_start());662663macro_rules! fields {664(size($field:ident) = $size:expr, $($rest:tt)*) => {665ret.$field = next_field_offset;666next_field_offset = cadd(next_field_offset, u32::from($size));667fields!($($rest)*);668};669(align($align:expr), $($rest:tt)*) => {670next_field_offset = align(next_field_offset, $align);671fields!($($rest)*);672};673() => {};674}675676fields! {677size(imported_memories)678= cmul(ret.num_imported_memories, ret.size_of_vmmemory_import()),679size(defined_memories)680= cmul(ret.num_defined_memories, ret.ptr.size_of_vmmemory_pointer()),681size(owned_memories)682= cmul(ret.num_owned_memories, ret.ptr.size_of_vmmemory_definition()),683size(imported_functions)684= cmul(ret.num_imported_functions, ret.size_of_vmfunction_import()),685size(imported_tables)686= cmul(ret.num_imported_tables, ret.size_of_vmtable_import()),687size(imported_globals)688= cmul(ret.num_imported_globals, ret.size_of_vmglobal_import()),689size(imported_tags)690= cmul(ret.num_imported_tags, ret.size_of_vmtag_import()),691size(defined_tables)692= cmul(ret.num_defined_tables, ret.size_of_vmtable_definition()),693align(16),694size(defined_globals)695= cmul(ret.num_defined_globals, ret.ptr.size_of_vmglobal_definition()),696size(defined_tags)697= cmul(ret.num_defined_tags, ret.ptr.size_of_vmtag_definition()),698size(defined_func_refs) = cmul(699ret.num_escaped_funcs,700ret.ptr.size_of_vm_func_ref(),701),702}703704ret.size = next_field_offset;705706return ret;707}708}709710impl<P: PtrSize> VMOffsets<P> {711/// The offset of the `wasm_call` field.712#[inline]713pub fn vmfunction_import_wasm_call(&self) -> u8 {7140 * self.pointer_size()715}716717/// The offset of the `array_call` field.718#[inline]719pub fn vmfunction_import_array_call(&self) -> u8 {7201 * self.pointer_size()721}722723/// The offset of the `vmctx` field.724#[inline]725pub fn vmfunction_import_vmctx(&self) -> u8 {7262 * self.pointer_size()727}728729/// Return the size of `VMFunctionImport`.730#[inline]731pub fn size_of_vmfunction_import(&self) -> u8 {7323 * self.pointer_size()733}734}735736/// Offsets for `*const VMFunctionBody`.737impl<P: PtrSize> VMOffsets<P> {738/// The size of the `current_elements` field.739pub fn size_of_vmfunction_body_ptr(&self) -> u8 {7401 * self.pointer_size()741}742}743744/// Offsets for `VMTableImport`.745impl<P: PtrSize> VMOffsets<P> {746/// The offset of the `from` field.747#[inline]748pub fn vmtable_import_from(&self) -> u8 {7490 * self.pointer_size()750}751752/// The offset of the `vmctx` field.753#[inline]754pub fn vmtable_import_vmctx(&self) -> u8 {7551 * self.pointer_size()756}757758/// The offset of the `index` field.759#[inline]760pub fn vmtable_import_index(&self) -> u8 {7612 * self.pointer_size()762}763764/// Return the size of `VMTableImport`.765#[inline]766pub fn size_of_vmtable_import(&self) -> u8 {7673 * self.pointer_size()768}769}770771/// Offsets for `VMTableDefinition`.772impl<P: PtrSize> VMOffsets<P> {773/// The offset of the `base` field.774#[inline]775pub fn vmtable_definition_base(&self) -> u8 {7760 * self.pointer_size()777}778779/// The offset of the `current_elements` field.780pub fn vmtable_definition_current_elements(&self) -> u8 {7811 * self.pointer_size()782}783784/// The size of the `current_elements` field.785#[inline]786pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {787self.pointer_size()788}789790/// Return the size of `VMTableDefinition`.791#[inline]792pub fn size_of_vmtable_definition(&self) -> u8 {7932 * self.pointer_size()794}795}796797/// Offsets for `VMMemoryImport`.798impl<P: PtrSize> VMOffsets<P> {799/// The offset of the `from` field.800#[inline]801pub fn vmmemory_import_from(&self) -> u8 {8020 * self.pointer_size()803}804805/// The offset of the `vmctx` field.806#[inline]807pub fn vmmemory_import_vmctx(&self) -> u8 {8081 * self.pointer_size()809}810811/// The offset of the `index` field.812#[inline]813pub fn vmmemory_import_index(&self) -> u8 {8142 * self.pointer_size()815}816817/// Return the size of `VMMemoryImport`.818#[inline]819pub fn size_of_vmmemory_import(&self) -> u8 {8203 * self.pointer_size()821}822}823824/// Offsets for `VMGlobalImport`.825impl<P: PtrSize> VMOffsets<P> {826/// The offset of the `from` field.827#[inline]828pub fn vmglobal_import_from(&self) -> u8 {8290 * self.pointer_size()830}831832/// Return the size of `VMGlobalImport`.833#[inline]834pub fn size_of_vmglobal_import(&self) -> u8 {835// `VMGlobalImport` has two pointers plus 8 bytes for `VMGlobalKind`8362 * self.pointer_size() + 8837}838}839840/// Offsets for `VMSharedTypeIndex`.841impl<P: PtrSize> VMOffsets<P> {842/// Return the size of `VMSharedTypeIndex`.843#[inline]844pub fn size_of_vmshared_type_index(&self) -> u8 {8454846}847}848849/// Offsets for `VMTagImport`.850impl<P: PtrSize> VMOffsets<P> {851/// The offset of the `from` field.852#[inline]853pub fn vmtag_import_from(&self) -> u8 {8540 * self.pointer_size()855}856857/// The offset of the `vmctx` field.858#[inline]859pub fn vmtag_import_vmctx(&self) -> u8 {8601 * self.pointer_size()861}862863/// The offset of the `index` field.864#[inline]865pub fn vmtag_import_index(&self) -> u8 {8662 * self.pointer_size()867}868869/// Return the size of `VMTagImport`.870#[inline]871pub fn size_of_vmtag_import(&self) -> u8 {8723 * self.pointer_size()873}874}875876/// Offsets for `VMContext`.877impl<P: PtrSize> VMOffsets<P> {878/// The offset of the `tables` array.879#[inline]880pub fn vmctx_imported_functions_begin(&self) -> u32 {881self.imported_functions882}883884/// The offset of the `tables` array.885#[inline]886pub fn vmctx_imported_tables_begin(&self) -> u32 {887self.imported_tables888}889890/// The offset of the `memories` array.891#[inline]892pub fn vmctx_imported_memories_begin(&self) -> u32 {893self.imported_memories894}895896/// The offset of the `globals` array.897#[inline]898pub fn vmctx_imported_globals_begin(&self) -> u32 {899self.imported_globals900}901902/// The offset of the `tags` array.903#[inline]904pub fn vmctx_imported_tags_begin(&self) -> u32 {905self.imported_tags906}907908/// The offset of the `tables` array.909#[inline]910pub fn vmctx_tables_begin(&self) -> u32 {911self.defined_tables912}913914/// The offset of the `memories` array.915#[inline]916pub fn vmctx_memories_begin(&self) -> u32 {917self.defined_memories918}919920/// The offset of the `owned_memories` array.921#[inline]922pub fn vmctx_owned_memories_begin(&self) -> u32 {923self.owned_memories924}925926/// The offset of the `globals` array.927#[inline]928pub fn vmctx_globals_begin(&self) -> u32 {929self.defined_globals930}931932/// The offset of the `tags` array.933#[inline]934pub fn vmctx_tags_begin(&self) -> u32 {935self.defined_tags936}937938/// The offset of the `func_refs` array.939#[inline]940pub fn vmctx_func_refs_begin(&self) -> u32 {941self.defined_func_refs942}943944/// Return the size of the `VMContext` allocation.945#[inline]946pub fn size_of_vmctx(&self) -> u32 {947self.size948}949950/// Return the offset to `VMFunctionImport` index `index`.951#[inline]952pub fn vmctx_vmfunction_import(&self, index: FuncIndex) -> u32 {953assert!(index.as_u32() < self.num_imported_functions);954self.vmctx_imported_functions_begin()955+ index.as_u32() * u32::from(self.size_of_vmfunction_import())956}957958/// Return the offset to `VMTable` index `index`.959#[inline]960pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {961assert!(index.as_u32() < self.num_imported_tables);962self.vmctx_imported_tables_begin()963+ index.as_u32() * u32::from(self.size_of_vmtable_import())964}965966/// Return the offset to `VMMemoryImport` index `index`.967#[inline]968pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {969assert!(index.as_u32() < self.num_imported_memories);970self.vmctx_imported_memories_begin()971+ index.as_u32() * u32::from(self.size_of_vmmemory_import())972}973974/// Return the offset to `VMGlobalImport` index `index`.975#[inline]976pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {977assert!(index.as_u32() < self.num_imported_globals);978self.vmctx_imported_globals_begin()979+ index.as_u32() * u32::from(self.size_of_vmglobal_import())980}981982/// Return the offset to `VMTagImport` index `index`.983#[inline]984pub fn vmctx_vmtag_import(&self, index: TagIndex) -> u32 {985assert!(index.as_u32() < self.num_imported_tags);986self.vmctx_imported_tags_begin() + index.as_u32() * u32::from(self.size_of_vmtag_import())987}988989/// Return the offset to `VMTableDefinition` index `index`.990#[inline]991pub fn vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32 {992assert!(index.as_u32() < self.num_defined_tables);993self.vmctx_tables_begin() + index.as_u32() * u32::from(self.size_of_vmtable_definition())994}995996/// Return the offset to the `*mut VMMemoryDefinition` at index `index`.997#[inline]998pub fn vmctx_vmmemory_pointer(&self, index: DefinedMemoryIndex) -> u32 {999assert!(index.as_u32() < self.num_defined_memories);1000self.vmctx_memories_begin()1001+ index.as_u32() * u32::from(self.ptr.size_of_vmmemory_pointer())1002}10031004/// Return the offset to the owned `VMMemoryDefinition` at index `index`.1005#[inline]1006pub fn vmctx_vmmemory_definition(&self, index: OwnedMemoryIndex) -> u32 {1007assert!(index.as_u32() < self.num_owned_memories);1008self.vmctx_owned_memories_begin()1009+ index.as_u32() * u32::from(self.ptr.size_of_vmmemory_definition())1010}10111012/// Return the offset to the `VMGlobalDefinition` index `index`.1013#[inline]1014pub fn vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32 {1015assert!(index.as_u32() < self.num_defined_globals);1016self.vmctx_globals_begin()1017+ index.as_u32() * u32::from(self.ptr.size_of_vmglobal_definition())1018}10191020/// Return the offset to the `VMTagDefinition` index `index`.1021#[inline]1022pub fn vmctx_vmtag_definition(&self, index: DefinedTagIndex) -> u32 {1023assert!(index.as_u32() < self.num_defined_tags);1024self.vmctx_tags_begin() + index.as_u32() * u32::from(self.ptr.size_of_vmtag_definition())1025}10261027/// Return the offset to the `VMFuncRef` for the given function1028/// index (either imported or defined).1029#[inline]1030pub fn vmctx_func_ref(&self, index: FuncRefIndex) -> u32 {1031assert!(!index.is_reserved_value());1032assert!(index.as_u32() < self.num_escaped_funcs);1033self.vmctx_func_refs_begin() + index.as_u32() * u32::from(self.ptr.size_of_vm_func_ref())1034}10351036/// Return the offset to the `wasm_call` field in `*const VMFunctionBody` index `index`.1037#[inline]1038pub fn vmctx_vmfunction_import_wasm_call(&self, index: FuncIndex) -> u32 {1039self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_wasm_call())1040}10411042/// Return the offset to the `array_call` field in `*const VMFunctionBody` index `index`.1043#[inline]1044pub fn vmctx_vmfunction_import_array_call(&self, index: FuncIndex) -> u32 {1045self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_array_call())1046}10471048/// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.1049#[inline]1050pub fn vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32 {1051self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())1052}10531054/// Return the offset to the `from` field in the imported `VMTable` at index1055/// `index`.1056#[inline]1057pub fn vmctx_vmtable_from(&self, index: TableIndex) -> u32 {1058self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_from())1059}10601061/// Return the offset to the `base` field in `VMTableDefinition` index `index`.1062#[inline]1063pub fn vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32 {1064self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())1065}10661067/// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`.1068#[inline]1069pub fn vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32 {1070self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())1071}10721073/// Return the offset to the `from` field in `VMMemoryImport` index `index`.1074#[inline]1075pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {1076self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_from())1077}10781079/// Return the offset to the `base` field in `VMMemoryDefinition` index `index`.1080#[inline]1081pub fn vmctx_vmmemory_definition_base(&self, index: OwnedMemoryIndex) -> u32 {1082self.vmctx_vmmemory_definition(index) + u32::from(self.ptr.vmmemory_definition_base())1083}10841085/// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`.1086#[inline]1087pub fn vmctx_vmmemory_definition_current_length(&self, index: OwnedMemoryIndex) -> u32 {1088self.vmctx_vmmemory_definition(index)1089+ u32::from(self.ptr.vmmemory_definition_current_length())1090}10911092/// Return the offset to the `from` field in `VMGlobalImport` index `index`.1093#[inline]1094pub fn vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32 {1095self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_from())1096}10971098/// Return the offset to the `from` field in `VMTagImport` index `index`.1099#[inline]1100pub fn vmctx_vmtag_import_from(&self, index: TagIndex) -> u32 {1101self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_from())1102}11031104/// Return the offset to the `vmctx` field in `VMTagImport` index `index`.1105#[inline]1106pub fn vmctx_vmtag_import_vmctx(&self, index: TagIndex) -> u32 {1107self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_vmctx())1108}11091110/// Return the offset to the `index` field in `VMTagImport` index `index`.1111#[inline]1112pub fn vmctx_vmtag_import_index(&self, index: TagIndex) -> u32 {1113self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_index())1114}1115}11161117/// Offsets for `VMGcHeader`.1118impl<P: PtrSize> VMOffsets<P> {1119/// Return the offset for the `VMGcHeader::kind` field.1120#[inline]1121pub fn vm_gc_header_kind(&self) -> u32 {112201123}11241125/// Return the offset for the `VMGcHeader`'s reserved bits.1126#[inline]1127pub fn vm_gc_header_reserved_bits(&self) -> u32 {1128// NB: The reserved bits are the unused `VMGcKind` bits.1129self.vm_gc_header_kind()1130}11311132/// Return the offset for the `VMGcHeader::ty` field.1133#[inline]1134pub fn vm_gc_header_ty(&self) -> u32 {1135self.vm_gc_header_kind() + 41136}1137}11381139/// Offsets for `VMDrcHeader`.1140///1141/// Should only be used when the DRC collector is enabled.1142impl<P: PtrSize> VMOffsets<P> {1143/// Return the offset for `VMDrcHeader::ref_count`.1144#[inline]1145pub fn vm_drc_header_ref_count(&self) -> u32 {114681147}11481149/// Return the offset for `VMDrcHeader::next_over_approximated_stack_root`.1150#[inline]1151pub fn vm_drc_header_next_over_approximated_stack_root(&self) -> u32 {1152self.vm_drc_header_ref_count() + 81153}1154}11551156/// Magic value for core Wasm VM contexts.1157///1158/// This is stored at the start of all `VMContext` structures.1159pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");11601161/// Equivalent of `VMCONTEXT_MAGIC` except for array-call host functions.1162///1163/// This is stored at the start of all `VMArrayCallHostFuncContext` structures1164/// and double-checked on `VMArrayCallHostFuncContext::from_opaque`.1165pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");11661167#[cfg(test)]1168mod tests {1169use crate::vmoffsets::align;11701171#[test]1172fn alignment() {1173fn is_aligned(x: u32) -> bool {1174x % 16 == 01175}1176assert!(is_aligned(align(0, 16)));1177assert!(is_aligned(align(32, 16)));1178assert!(is_aligned(align(33, 16)));1179assert!(is_aligned(align(31, 16)));1180}1181}118211831184