Path: blob/main/crates/environ/src/vmoffsets.rs
1691 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_fp` field of `VMStoreContext`.221fn vmstore_context_last_wasm_entry_fp(&self) -> u8 {222self.vmstore_context_last_wasm_exit_pc() + self.size()223}224225/// Return the offset of the `stack_chain` field of `VMStoreContext`.226fn vmstore_context_stack_chain(&self) -> u8 {227self.vmstore_context_last_wasm_entry_fp() + self.size()228}229230// Offsets within `VMMemoryDefinition`231232/// The offset of the `base` field.233#[inline]234fn vmmemory_definition_base(&self) -> u8 {2350 * self.size()236}237238/// The offset of the `current_length` field.239#[inline]240fn vmmemory_definition_current_length(&self) -> u8 {2411 * self.size()242}243244/// Return the size of `VMMemoryDefinition`.245#[inline]246fn size_of_vmmemory_definition(&self) -> u8 {2472 * self.size()248}249250/// Return the size of `*mut VMMemoryDefinition`.251#[inline]252fn size_of_vmmemory_pointer(&self) -> u8 {253self.size()254}255256// Offsets within `VMArrayCallHostFuncContext`.257258/// Return the offset of `VMArrayCallHostFuncContext::func_ref`.259fn vmarray_call_host_func_context_func_ref(&self) -> u8 {260u8::try_from(align(261u32::try_from(core::mem::size_of::<u32>()).unwrap(),262u32::from(self.size()),263))264.unwrap()265}266267/// Return the size of `VMStackChain`.268fn size_of_vmstack_chain(&self) -> u8 {2692 * self.size()270}271272// Offsets within `VMStackLimits`273274/// Return the offset of `VMStackLimits::stack_limit`.275fn vmstack_limits_stack_limit(&self) -> u8 {2760277}278279/// Return the offset of `VMStackLimits::last_wasm_entry_fp`.280fn vmstack_limits_last_wasm_entry_fp(&self) -> u8 {281self.size()282}283284// Offsets within `VMHostArray`285286/// Return the offset of `VMHostArray::length`.287fn vmhostarray_length(&self) -> u8 {2880289}290291/// Return the offset of `VMHostArray::capacity`.292fn vmhostarray_capacity(&self) -> u8 {2934294}295296/// Return the offset of `VMHostArray::data`.297fn vmhostarray_data(&self) -> u8 {2988299}300301/// Return the size of `VMHostArray`.302fn size_of_vmhostarray(&self) -> u8 {3038 + self.size()304}305306// Offsets within `VMCommonStackInformation`307308/// Return the offset of `VMCommonStackInformation::limits`.309fn vmcommon_stack_information_limits(&self) -> u8 {3100 * self.size()311}312313/// Return the offset of `VMCommonStackInformation::state`.314fn vmcommon_stack_information_state(&self) -> u8 {3152 * self.size()316}317318/// Return the offset of `VMCommonStackInformation::handlers`.319fn vmcommon_stack_information_handlers(&self) -> u8 {320u8::try_from(align(321self.vmcommon_stack_information_state() as u32 + 4,322u32::from(self.size()),323))324.unwrap()325}326327/// Return the offset of `VMCommonStackInformation::first_switch_handler_index`.328fn vmcommon_stack_information_first_switch_handler_index(&self) -> u8 {329self.vmcommon_stack_information_handlers() + self.size_of_vmhostarray()330}331332/// Return the size of `VMCommonStackInformation`.333fn size_of_vmcommon_stack_information(&self) -> u8 {334u8::try_from(align(335self.vmcommon_stack_information_first_switch_handler_index() as u32 + 4,336u32::from(self.size()),337))338.unwrap()339}340341// Offsets within `VMContObj`342343/// Return the offset of `VMContObj::contref`344fn vmcontobj_contref(&self) -> u8 {3450346}347348/// Return the offset of `VMContObj::revision`349fn vmcontobj_revision(&self) -> u8 {350self.size()351}352353/// Return the size of `VMContObj`.354fn size_of_vmcontobj(&self) -> u8 {355u8::try_from(align(356u32::from(self.vmcontobj_revision())357+ u32::try_from(core::mem::size_of::<usize>()).unwrap(),358u32::from(self.size()),359))360.unwrap()361}362363// Offsets within `VMContRef`364365/// Return the offset of `VMContRef::common_stack_information`.366fn vmcontref_common_stack_information(&self) -> u8 {3670 * self.size()368}369370/// Return the offset of `VMContRef::parent_chain`.371fn vmcontref_parent_chain(&self) -> u8 {372u8::try_from(align(373(self.vmcontref_common_stack_information() + self.size_of_vmcommon_stack_information())374as u32,375u32::from(self.size()),376))377.unwrap()378}379380/// Return the offset of `VMContRef::last_ancestor`.381fn vmcontref_last_ancestor(&self) -> u8 {382self.vmcontref_parent_chain() + 2 * self.size()383}384385/// Return the offset of `VMContRef::revision`.386fn vmcontref_revision(&self) -> u8 {387self.vmcontref_last_ancestor() + self.size()388}389390/// Return the offset of `VMContRef::stack`.391fn vmcontref_stack(&self) -> u8 {392self.vmcontref_revision() + self.size()393}394395/// Return the offset of `VMContRef::args`.396fn vmcontref_args(&self) -> u8 {397self.vmcontref_stack() + 3 * self.size()398}399400/// Return the offset of `VMContRef::values`.401fn vmcontref_values(&self) -> u8 {402self.vmcontref_args() + self.size_of_vmhostarray()403}404405/// Return the offset to the `magic` value in this `VMContext`.406#[inline]407fn vmctx_magic(&self) -> u8 {408// This is required by the implementation of `VMContext::instance` and409// `VMContext::instance_mut`. If this value changes then those locations410// need to be updated.4110412}413414/// Return the offset to the `VMStoreContext` structure415#[inline]416fn vmctx_store_context(&self) -> u8 {417self.vmctx_magic() + self.size()418}419420/// Return the offset to the `VMBuiltinFunctionsArray` structure421#[inline]422fn vmctx_builtin_functions(&self) -> u8 {423self.vmctx_store_context() + self.size()424}425426/// Return the offset to the `*const AtomicU64` epoch-counter427/// pointer.428#[inline]429fn vmctx_epoch_ptr(&self) -> u8 {430self.vmctx_builtin_functions() + self.size()431}432433/// Return the offset to the `*mut T` collector-specific data.434///435/// This is a pointer that different collectors can use however they see436/// fit.437#[inline]438fn vmctx_gc_heap_data(&self) -> u8 {439self.vmctx_epoch_ptr() + self.size()440}441442/// The offset of the `type_ids` array pointer.443#[inline]444fn vmctx_type_ids_array(&self) -> u8 {445self.vmctx_gc_heap_data() + self.size()446}447448/// The end of statically known offsets in `VMContext`.449///450/// Data after this is dynamically sized.451#[inline]452fn vmctx_dynamic_data_start(&self) -> u8 {453self.vmctx_type_ids_array() + self.size()454}455}456457/// Type representing the size of a pointer for the current compilation host458#[derive(Clone, Copy)]459pub struct HostPtr;460461impl PtrSize for HostPtr {462#[inline]463fn size(&self) -> u8 {464core::mem::size_of::<usize>() as u8465}466}467468impl PtrSize for u8 {469#[inline]470fn size(&self) -> u8 {471*self472}473}474475/// Used to construct a `VMOffsets`476#[derive(Debug, Clone, Copy)]477pub struct VMOffsetsFields<P> {478/// The size in bytes of a pointer on the target.479pub ptr: P,480/// The number of imported functions in the module.481pub num_imported_functions: u32,482/// The number of imported tables in the module.483pub num_imported_tables: u32,484/// The number of imported memories in the module.485pub num_imported_memories: u32,486/// The number of imported globals in the module.487pub num_imported_globals: u32,488/// The number of imported tags in the module.489pub num_imported_tags: u32,490/// The number of defined tables in the module.491pub num_defined_tables: u32,492/// The number of defined memories in the module.493pub num_defined_memories: u32,494/// The number of memories owned by the module instance.495pub num_owned_memories: u32,496/// The number of defined globals in the module.497pub num_defined_globals: u32,498/// The number of defined tags in the module.499pub num_defined_tags: u32,500/// The number of escaped functions in the module, the size of the function501/// references array.502pub num_escaped_funcs: u32,503}504505impl<P: PtrSize> VMOffsets<P> {506/// Return a new `VMOffsets` instance, for a given pointer size.507pub fn new(ptr: P, module: &Module) -> Self {508let num_owned_memories = module509.memories510.iter()511.skip(module.num_imported_memories)512.filter(|p| !p.1.shared)513.count()514.try_into()515.unwrap();516VMOffsets::from(VMOffsetsFields {517ptr,518num_imported_functions: cast_to_u32(module.num_imported_funcs),519num_imported_tables: cast_to_u32(module.num_imported_tables),520num_imported_memories: cast_to_u32(module.num_imported_memories),521num_imported_globals: cast_to_u32(module.num_imported_globals),522num_imported_tags: cast_to_u32(module.num_imported_tags),523num_defined_tables: cast_to_u32(module.num_defined_tables()),524num_defined_memories: cast_to_u32(module.num_defined_memories()),525num_owned_memories,526num_defined_globals: cast_to_u32(module.globals.len() - module.num_imported_globals),527num_defined_tags: cast_to_u32(module.tags.len() - module.num_imported_tags),528num_escaped_funcs: cast_to_u32(module.num_escaped_funcs),529})530}531532/// Returns the size, in bytes, of the target533#[inline]534pub fn pointer_size(&self) -> u8 {535self.ptr.size()536}537538/// Returns an iterator which provides a human readable description and a539/// byte size. The iterator returned will iterate over the bytes allocated540/// to the entire `VMOffsets` structure to explain where each byte size is541/// coming from.542pub fn region_sizes(&self) -> impl Iterator<Item = (&str, u32)> {543macro_rules! calculate_sizes {544($($name:ident: $desc:tt,)*) => {{545let VMOffsets {546// These fields are metadata not talking about specific547// offsets of specific fields.548ptr: _,549num_imported_functions: _,550num_imported_tables: _,551num_imported_memories: _,552num_imported_globals: _,553num_imported_tags: _,554num_defined_tables: _,555num_defined_globals: _,556num_defined_memories: _,557num_defined_tags: _,558num_owned_memories: _,559num_escaped_funcs: _,560561// used as the initial size below562size,563564// exhaustively match the rest of the fields with input from565// the macro566$($name,)*567} = *self;568569// calculate the size of each field by relying on the inputs to570// the macro being in reverse order and determining the size of571// the field as the offset from the field to the last field.572let mut last = size;573$(574assert!($name <= last);575let tmp = $name;576let $name = last - $name;577last = tmp;578)*579assert_ne!(last, 0);580IntoIterator::into_iter([581$(($desc, $name),)*582("static vmctx data", last),583])584}};585}586587calculate_sizes! {588defined_func_refs: "module functions",589defined_tags: "defined tags",590defined_globals: "defined globals",591defined_tables: "defined tables",592imported_tags: "imported tags",593imported_globals: "imported globals",594imported_tables: "imported tables",595imported_functions: "imported functions",596owned_memories: "owned memories",597defined_memories: "defined memories",598imported_memories: "imported memories",599}600}601}602603impl<P: PtrSize> From<VMOffsetsFields<P>> for VMOffsets<P> {604fn from(fields: VMOffsetsFields<P>) -> VMOffsets<P> {605let mut ret = Self {606ptr: fields.ptr,607num_imported_functions: fields.num_imported_functions,608num_imported_tables: fields.num_imported_tables,609num_imported_memories: fields.num_imported_memories,610num_imported_globals: fields.num_imported_globals,611num_imported_tags: fields.num_imported_tags,612num_defined_tables: fields.num_defined_tables,613num_defined_memories: fields.num_defined_memories,614num_owned_memories: fields.num_owned_memories,615num_defined_globals: fields.num_defined_globals,616num_defined_tags: fields.num_defined_tags,617num_escaped_funcs: fields.num_escaped_funcs,618imported_functions: 0,619imported_tables: 0,620imported_memories: 0,621imported_globals: 0,622imported_tags: 0,623defined_tables: 0,624defined_memories: 0,625owned_memories: 0,626defined_globals: 0,627defined_tags: 0,628defined_func_refs: 0,629size: 0,630};631632// Convenience functions for checked addition and multiplication.633// As side effect this reduces binary size by using only a single634// `#[track_caller]` location for each function instead of one for635// each individual invocation.636#[inline]637fn cadd(count: u32, size: u32) -> u32 {638count.checked_add(size).unwrap()639}640641#[inline]642fn cmul(count: u32, size: u8) -> u32 {643count.checked_mul(u32::from(size)).unwrap()644}645646let mut next_field_offset = u32::from(ret.ptr.vmctx_dynamic_data_start());647648macro_rules! fields {649(size($field:ident) = $size:expr, $($rest:tt)*) => {650ret.$field = next_field_offset;651next_field_offset = cadd(next_field_offset, u32::from($size));652fields!($($rest)*);653};654(align($align:expr), $($rest:tt)*) => {655next_field_offset = align(next_field_offset, $align);656fields!($($rest)*);657};658() => {};659}660661fields! {662size(imported_memories)663= cmul(ret.num_imported_memories, ret.size_of_vmmemory_import()),664size(defined_memories)665= cmul(ret.num_defined_memories, ret.ptr.size_of_vmmemory_pointer()),666size(owned_memories)667= cmul(ret.num_owned_memories, ret.ptr.size_of_vmmemory_definition()),668size(imported_functions)669= cmul(ret.num_imported_functions, ret.size_of_vmfunction_import()),670size(imported_tables)671= cmul(ret.num_imported_tables, ret.size_of_vmtable_import()),672size(imported_globals)673= cmul(ret.num_imported_globals, ret.size_of_vmglobal_import()),674size(imported_tags)675= cmul(ret.num_imported_tags, ret.size_of_vmtag_import()),676size(defined_tables)677= cmul(ret.num_defined_tables, ret.size_of_vmtable_definition()),678align(16),679size(defined_globals)680= cmul(ret.num_defined_globals, ret.ptr.size_of_vmglobal_definition()),681size(defined_tags)682= cmul(ret.num_defined_tags, ret.ptr.size_of_vmtag_definition()),683size(defined_func_refs) = cmul(684ret.num_escaped_funcs,685ret.ptr.size_of_vm_func_ref(),686),687}688689ret.size = next_field_offset;690691return ret;692}693}694695impl<P: PtrSize> VMOffsets<P> {696/// The offset of the `wasm_call` field.697#[inline]698pub fn vmfunction_import_wasm_call(&self) -> u8 {6990 * self.pointer_size()700}701702/// The offset of the `array_call` field.703#[inline]704pub fn vmfunction_import_array_call(&self) -> u8 {7051 * self.pointer_size()706}707708/// The offset of the `vmctx` field.709#[inline]710pub fn vmfunction_import_vmctx(&self) -> u8 {7112 * self.pointer_size()712}713714/// Return the size of `VMFunctionImport`.715#[inline]716pub fn size_of_vmfunction_import(&self) -> u8 {7173 * self.pointer_size()718}719}720721/// Offsets for `*const VMFunctionBody`.722impl<P: PtrSize> VMOffsets<P> {723/// The size of the `current_elements` field.724pub fn size_of_vmfunction_body_ptr(&self) -> u8 {7251 * self.pointer_size()726}727}728729/// Offsets for `VMTableImport`.730impl<P: PtrSize> VMOffsets<P> {731/// The offset of the `from` field.732#[inline]733pub fn vmtable_import_from(&self) -> u8 {7340 * self.pointer_size()735}736737/// The offset of the `vmctx` field.738#[inline]739pub fn vmtable_import_vmctx(&self) -> u8 {7401 * self.pointer_size()741}742743/// The offset of the `index` field.744#[inline]745pub fn vmtable_import_index(&self) -> u8 {7462 * self.pointer_size()747}748749/// Return the size of `VMTableImport`.750#[inline]751pub fn size_of_vmtable_import(&self) -> u8 {7523 * self.pointer_size()753}754}755756/// Offsets for `VMTableDefinition`.757impl<P: PtrSize> VMOffsets<P> {758/// The offset of the `base` field.759#[inline]760pub fn vmtable_definition_base(&self) -> u8 {7610 * self.pointer_size()762}763764/// The offset of the `current_elements` field.765pub fn vmtable_definition_current_elements(&self) -> u8 {7661 * self.pointer_size()767}768769/// The size of the `current_elements` field.770#[inline]771pub fn size_of_vmtable_definition_current_elements(&self) -> u8 {772self.pointer_size()773}774775/// Return the size of `VMTableDefinition`.776#[inline]777pub fn size_of_vmtable_definition(&self) -> u8 {7782 * self.pointer_size()779}780}781782/// Offsets for `VMMemoryImport`.783impl<P: PtrSize> VMOffsets<P> {784/// The offset of the `from` field.785#[inline]786pub fn vmmemory_import_from(&self) -> u8 {7870 * self.pointer_size()788}789790/// The offset of the `vmctx` field.791#[inline]792pub fn vmmemory_import_vmctx(&self) -> u8 {7931 * self.pointer_size()794}795796/// The offset of the `index` field.797#[inline]798pub fn vmmemory_import_index(&self) -> u8 {7992 * self.pointer_size()800}801802/// Return the size of `VMMemoryImport`.803#[inline]804pub fn size_of_vmmemory_import(&self) -> u8 {8053 * self.pointer_size()806}807}808809/// Offsets for `VMGlobalImport`.810impl<P: PtrSize> VMOffsets<P> {811/// The offset of the `from` field.812#[inline]813pub fn vmglobal_import_from(&self) -> u8 {8140 * self.pointer_size()815}816817/// Return the size of `VMGlobalImport`.818#[inline]819pub fn size_of_vmglobal_import(&self) -> u8 {820// `VMGlobalImport` has two pointers plus 8 bytes for `VMGlobalKind`8212 * self.pointer_size() + 8822}823}824825/// Offsets for `VMSharedTypeIndex`.826impl<P: PtrSize> VMOffsets<P> {827/// Return the size of `VMSharedTypeIndex`.828#[inline]829pub fn size_of_vmshared_type_index(&self) -> u8 {8304831}832}833834/// Offsets for `VMTagImport`.835impl<P: PtrSize> VMOffsets<P> {836/// The offset of the `from` field.837#[inline]838pub fn vmtag_import_from(&self) -> u8 {8390 * self.pointer_size()840}841842/// The offset of the `vmctx` field.843#[inline]844pub fn vmtag_import_vmctx(&self) -> u8 {8451 * self.pointer_size()846}847848/// The offset of the `index` field.849#[inline]850pub fn vmtag_import_index(&self) -> u8 {8512 * self.pointer_size()852}853854/// Return the size of `VMTagImport`.855#[inline]856pub fn size_of_vmtag_import(&self) -> u8 {8573 * self.pointer_size()858}859}860861/// Offsets for `VMContext`.862impl<P: PtrSize> VMOffsets<P> {863/// The offset of the `tables` array.864#[inline]865pub fn vmctx_imported_functions_begin(&self) -> u32 {866self.imported_functions867}868869/// The offset of the `tables` array.870#[inline]871pub fn vmctx_imported_tables_begin(&self) -> u32 {872self.imported_tables873}874875/// The offset of the `memories` array.876#[inline]877pub fn vmctx_imported_memories_begin(&self) -> u32 {878self.imported_memories879}880881/// The offset of the `globals` array.882#[inline]883pub fn vmctx_imported_globals_begin(&self) -> u32 {884self.imported_globals885}886887/// The offset of the `tags` array.888#[inline]889pub fn vmctx_imported_tags_begin(&self) -> u32 {890self.imported_tags891}892893/// The offset of the `tables` array.894#[inline]895pub fn vmctx_tables_begin(&self) -> u32 {896self.defined_tables897}898899/// The offset of the `memories` array.900#[inline]901pub fn vmctx_memories_begin(&self) -> u32 {902self.defined_memories903}904905/// The offset of the `owned_memories` array.906#[inline]907pub fn vmctx_owned_memories_begin(&self) -> u32 {908self.owned_memories909}910911/// The offset of the `globals` array.912#[inline]913pub fn vmctx_globals_begin(&self) -> u32 {914self.defined_globals915}916917/// The offset of the `tags` array.918#[inline]919pub fn vmctx_tags_begin(&self) -> u32 {920self.defined_tags921}922923/// The offset of the `func_refs` array.924#[inline]925pub fn vmctx_func_refs_begin(&self) -> u32 {926self.defined_func_refs927}928929/// Return the size of the `VMContext` allocation.930#[inline]931pub fn size_of_vmctx(&self) -> u32 {932self.size933}934935/// Return the offset to `VMFunctionImport` index `index`.936#[inline]937pub fn vmctx_vmfunction_import(&self, index: FuncIndex) -> u32 {938assert!(index.as_u32() < self.num_imported_functions);939self.vmctx_imported_functions_begin()940+ index.as_u32() * u32::from(self.size_of_vmfunction_import())941}942943/// Return the offset to `VMTable` index `index`.944#[inline]945pub fn vmctx_vmtable_import(&self, index: TableIndex) -> u32 {946assert!(index.as_u32() < self.num_imported_tables);947self.vmctx_imported_tables_begin()948+ index.as_u32() * u32::from(self.size_of_vmtable_import())949}950951/// Return the offset to `VMMemoryImport` index `index`.952#[inline]953pub fn vmctx_vmmemory_import(&self, index: MemoryIndex) -> u32 {954assert!(index.as_u32() < self.num_imported_memories);955self.vmctx_imported_memories_begin()956+ index.as_u32() * u32::from(self.size_of_vmmemory_import())957}958959/// Return the offset to `VMGlobalImport` index `index`.960#[inline]961pub fn vmctx_vmglobal_import(&self, index: GlobalIndex) -> u32 {962assert!(index.as_u32() < self.num_imported_globals);963self.vmctx_imported_globals_begin()964+ index.as_u32() * u32::from(self.size_of_vmglobal_import())965}966967/// Return the offset to `VMTagImport` index `index`.968#[inline]969pub fn vmctx_vmtag_import(&self, index: TagIndex) -> u32 {970assert!(index.as_u32() < self.num_imported_tags);971self.vmctx_imported_tags_begin() + index.as_u32() * u32::from(self.size_of_vmtag_import())972}973974/// Return the offset to `VMTableDefinition` index `index`.975#[inline]976pub fn vmctx_vmtable_definition(&self, index: DefinedTableIndex) -> u32 {977assert!(index.as_u32() < self.num_defined_tables);978self.vmctx_tables_begin() + index.as_u32() * u32::from(self.size_of_vmtable_definition())979}980981/// Return the offset to the `*mut VMMemoryDefinition` at index `index`.982#[inline]983pub fn vmctx_vmmemory_pointer(&self, index: DefinedMemoryIndex) -> u32 {984assert!(index.as_u32() < self.num_defined_memories);985self.vmctx_memories_begin()986+ index.as_u32() * u32::from(self.ptr.size_of_vmmemory_pointer())987}988989/// Return the offset to the owned `VMMemoryDefinition` at index `index`.990#[inline]991pub fn vmctx_vmmemory_definition(&self, index: OwnedMemoryIndex) -> u32 {992assert!(index.as_u32() < self.num_owned_memories);993self.vmctx_owned_memories_begin()994+ index.as_u32() * u32::from(self.ptr.size_of_vmmemory_definition())995}996997/// Return the offset to the `VMGlobalDefinition` index `index`.998#[inline]999pub fn vmctx_vmglobal_definition(&self, index: DefinedGlobalIndex) -> u32 {1000assert!(index.as_u32() < self.num_defined_globals);1001self.vmctx_globals_begin()1002+ index.as_u32() * u32::from(self.ptr.size_of_vmglobal_definition())1003}10041005/// Return the offset to the `VMTagDefinition` index `index`.1006#[inline]1007pub fn vmctx_vmtag_definition(&self, index: DefinedTagIndex) -> u32 {1008assert!(index.as_u32() < self.num_defined_tags);1009self.vmctx_tags_begin() + index.as_u32() * u32::from(self.ptr.size_of_vmtag_definition())1010}10111012/// Return the offset to the `VMFuncRef` for the given function1013/// index (either imported or defined).1014#[inline]1015pub fn vmctx_func_ref(&self, index: FuncRefIndex) -> u32 {1016assert!(!index.is_reserved_value());1017assert!(index.as_u32() < self.num_escaped_funcs);1018self.vmctx_func_refs_begin() + index.as_u32() * u32::from(self.ptr.size_of_vm_func_ref())1019}10201021/// Return the offset to the `wasm_call` field in `*const VMFunctionBody` index `index`.1022#[inline]1023pub fn vmctx_vmfunction_import_wasm_call(&self, index: FuncIndex) -> u32 {1024self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_wasm_call())1025}10261027/// Return the offset to the `array_call` field in `*const VMFunctionBody` index `index`.1028#[inline]1029pub fn vmctx_vmfunction_import_array_call(&self, index: FuncIndex) -> u32 {1030self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_array_call())1031}10321033/// Return the offset to the `vmctx` field in `*const VMFunctionBody` index `index`.1034#[inline]1035pub fn vmctx_vmfunction_import_vmctx(&self, index: FuncIndex) -> u32 {1036self.vmctx_vmfunction_import(index) + u32::from(self.vmfunction_import_vmctx())1037}10381039/// Return the offset to the `from` field in the imported `VMTable` at index1040/// `index`.1041#[inline]1042pub fn vmctx_vmtable_from(&self, index: TableIndex) -> u32 {1043self.vmctx_vmtable_import(index) + u32::from(self.vmtable_import_from())1044}10451046/// Return the offset to the `base` field in `VMTableDefinition` index `index`.1047#[inline]1048pub fn vmctx_vmtable_definition_base(&self, index: DefinedTableIndex) -> u32 {1049self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_base())1050}10511052/// Return the offset to the `current_elements` field in `VMTableDefinition` index `index`.1053#[inline]1054pub fn vmctx_vmtable_definition_current_elements(&self, index: DefinedTableIndex) -> u32 {1055self.vmctx_vmtable_definition(index) + u32::from(self.vmtable_definition_current_elements())1056}10571058/// Return the offset to the `from` field in `VMMemoryImport` index `index`.1059#[inline]1060pub fn vmctx_vmmemory_import_from(&self, index: MemoryIndex) -> u32 {1061self.vmctx_vmmemory_import(index) + u32::from(self.vmmemory_import_from())1062}10631064/// Return the offset to the `base` field in `VMMemoryDefinition` index `index`.1065#[inline]1066pub fn vmctx_vmmemory_definition_base(&self, index: OwnedMemoryIndex) -> u32 {1067self.vmctx_vmmemory_definition(index) + u32::from(self.ptr.vmmemory_definition_base())1068}10691070/// Return the offset to the `current_length` field in `VMMemoryDefinition` index `index`.1071#[inline]1072pub fn vmctx_vmmemory_definition_current_length(&self, index: OwnedMemoryIndex) -> u32 {1073self.vmctx_vmmemory_definition(index)1074+ u32::from(self.ptr.vmmemory_definition_current_length())1075}10761077/// Return the offset to the `from` field in `VMGlobalImport` index `index`.1078#[inline]1079pub fn vmctx_vmglobal_import_from(&self, index: GlobalIndex) -> u32 {1080self.vmctx_vmglobal_import(index) + u32::from(self.vmglobal_import_from())1081}10821083/// Return the offset to the `from` field in `VMTagImport` index `index`.1084#[inline]1085pub fn vmctx_vmtag_import_from(&self, index: TagIndex) -> u32 {1086self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_from())1087}10881089/// Return the offset to the `vmctx` field in `VMTagImport` index `index`.1090#[inline]1091pub fn vmctx_vmtag_import_vmctx(&self, index: TagIndex) -> u32 {1092self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_vmctx())1093}10941095/// Return the offset to the `index` field in `VMTagImport` index `index`.1096#[inline]1097pub fn vmctx_vmtag_import_index(&self, index: TagIndex) -> u32 {1098self.vmctx_vmtag_import(index) + u32::from(self.vmtag_import_index())1099}1100}11011102/// Offsets for `VMGcHeader`.1103impl<P: PtrSize> VMOffsets<P> {1104/// Return the offset for the `VMGcHeader::kind` field.1105#[inline]1106pub fn vm_gc_header_kind(&self) -> u32 {110701108}11091110/// Return the offset for the `VMGcHeader`'s reserved bits.1111#[inline]1112pub fn vm_gc_header_reserved_bits(&self) -> u32 {1113// NB: The reserved bits are the unused `VMGcKind` bits.1114self.vm_gc_header_kind()1115}11161117/// Return the offset for the `VMGcHeader::ty` field.1118#[inline]1119pub fn vm_gc_header_ty(&self) -> u32 {1120self.vm_gc_header_kind() + 41121}1122}11231124/// Offsets for `VMDrcHeader`.1125///1126/// Should only be used when the DRC collector is enabled.1127impl<P: PtrSize> VMOffsets<P> {1128/// Return the offset for `VMDrcHeader::ref_count`.1129#[inline]1130pub fn vm_drc_header_ref_count(&self) -> u32 {113181132}11331134/// Return the offset for `VMDrcHeader::next_over_approximated_stack_root`.1135#[inline]1136pub fn vm_drc_header_next_over_approximated_stack_root(&self) -> u32 {1137self.vm_drc_header_ref_count() + 81138}1139}11401141/// Magic value for core Wasm VM contexts.1142///1143/// This is stored at the start of all `VMContext` structures.1144pub const VMCONTEXT_MAGIC: u32 = u32::from_le_bytes(*b"core");11451146/// Equivalent of `VMCONTEXT_MAGIC` except for array-call host functions.1147///1148/// This is stored at the start of all `VMArrayCallHostFuncContext` structures1149/// and double-checked on `VMArrayCallHostFuncContext::from_opaque`.1150pub const VM_ARRAY_CALL_HOST_FUNC_MAGIC: u32 = u32::from_le_bytes(*b"ACHF");11511152#[cfg(test)]1153mod tests {1154use crate::vmoffsets::align;11551156#[test]1157fn alignment() {1158fn is_aligned(x: u32) -> bool {1159x % 16 == 01160}1161assert!(is_aligned(align(0, 16)));1162assert!(is_aligned(align(32, 16)));1163assert!(is_aligned(align(33, 16)));1164assert!(is_aligned(align(31, 16)));1165}1166}116711681169