use crate::translate::Load;
use core::fmt;
use cranelift_codegen::{
cursor::FuncCursor,
ir::{self, InstBuilder as _},
};
use wasmtime_environ::{
BuiltinFunctionIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex,
GetPtrSize, GlobalIndex, MemoryIndex, ModuleInternedTypeIndex, OwnedMemoryIndex, PtrSize as _,
RuntimeDataIndex, StaticModuleIndex, TableIndex, TagIndex, VMOffsets,
component::{
ComponentBuiltinFunctionIndex, LoweredIndex, ResourceIndex, RuntimeCallbackIndex,
RuntimeComponentInstanceIndex, RuntimeMemoryIndex, RuntimePostReturnIndex,
VMComponentOffsets,
},
};
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
enum VmType {
VMContext,
VMStoreContext,
VMMemoryDefinition,
VMTableDefinition,
VMComponentContext,
VMDrcHeapData,
VMCopyingHeapData,
VMNullHeapData,
VMDeferredThread,
VMContRef,
ContinuationStackMemory,
VMFunctionImport,
VMMemoryImport,
VMTableImport,
VMTagImport,
VMGlobalImport,
VMFuncRef,
TypeIdsArray,
EpochCounter,
BuiltinFunctionsArray,
ComponentBuiltinFunctionsArray,
HostValRaw,
}
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
enum AliasRegionKey {
Vm {
ty: VmType,
offset: u32,
},
PublicMemory,
DefinedMemory {
module: StaticModuleIndex,
index: DefinedMemoryIndex,
},
PublicTable,
DefinedTable {
module: StaticModuleIndex,
index: DefinedTableIndex,
},
PublicGlobal,
DefinedGlobal {
module: StaticModuleIndex,
index: DefinedGlobalIndex,
},
GcHeap,
Stack {
slot: ir::StackSlot,
},
UnsafeIntrinsicMemory,
ElementSegment,
DataSegment,
}
impl AliasRegionKey {
const KIND_BITS: u32 = 6;
const KIND_OFFSET: u32 = 32 - Self::KIND_BITS;
const KIND_MASK: u32 = ((1 << Self::KIND_BITS) - 1) << Self::KIND_OFFSET;
const OFFSET_MASK: u32 = !Self::KIND_MASK;
const MODULE_BITS: u32 = 8;
const MODULE_OFFSET: u32 = Self::KIND_OFFSET - Self::MODULE_BITS;
const MODULE_MASK: u32 = ((1 << Self::MODULE_BITS) - 1) << Self::MODULE_OFFSET;
const INDEX_MASK: u32 = !Self::KIND_MASK & !Self::MODULE_MASK;
const fn new_kind(kind: u32) -> u32 {
assert!(kind < (1 << Self::KIND_BITS));
kind << Self::KIND_OFFSET
}
const VM_CONTEXT_KIND: u32 = Self::new_kind(0b000000);
const VM_STORE_CONTEXT_KIND: u32 = Self::new_kind(0b000001);
const IMPORTED_MEMORY_KIND: u32 = Self::new_kind(0b000010);
const DEFINED_MEMORY_KIND: u32 = Self::new_kind(0b000011);
const IMPORTED_TABLE_KIND: u32 = Self::new_kind(0b000100);
const DEFINED_TABLE_KIND: u32 = Self::new_kind(0b000101);
const IMPORTED_GLOBAL_KIND: u32 = Self::new_kind(0b000110);
const DEFINED_GLOBAL_KIND: u32 = Self::new_kind(0b000111);
const GC_HEAP_KIND: u32 = Self::new_kind(0b001000);
const VM_MEMORY_DEFINITION_KIND: u32 = Self::new_kind(0b001001);
const VM_TABLE_DEFINITION_KIND: u32 = Self::new_kind(0b001010);
const VM_COMPONENT_CONTEXT_KIND: u32 = Self::new_kind(0b001011);
const VM_DRC_HEAP_DATA_KIND: u32 = Self::new_kind(0b001100);
const VM_COPYING_HEAP_DATA_KIND: u32 = Self::new_kind(0b001101);
const VM_NULL_HEAP_DATA_KIND: u32 = Self::new_kind(0b001110);
const VM_DEFERRED_THREAD_KIND: u32 = Self::new_kind(0b001111);
const VM_CONTREF_KIND: u32 = Self::new_kind(0b010000);
const CONTINUATION_STACK_MEMORY_KIND: u32 = Self::new_kind(0b010001);
const VM_FUNCTION_IMPORT_KIND: u32 = Self::new_kind(0b010010);
const VM_MEMORY_IMPORT_KIND: u32 = Self::new_kind(0b010011);
const VM_TABLE_IMPORT_KIND: u32 = Self::new_kind(0b010100);
const VM_TAG_IMPORT_KIND: u32 = Self::new_kind(0b010101);
const VM_GLOBAL_IMPORT_KIND: u32 = Self::new_kind(0b010110);
const STACK_KIND: u32 = Self::new_kind(0b010111);
const VM_FUNC_REF_KIND: u32 = Self::new_kind(0b011000);
const TYPE_IDS_ARRAY_KIND: u32 = Self::new_kind(0b011001);
const EPOCH_COUNTER_KIND: u32 = Self::new_kind(0b011010);
const BUILTIN_FUNCTIONS_KIND: u32 = Self::new_kind(0b011011);
const COMPONENT_BUILTIN_FUNCTIONS_KIND: u32 = Self::new_kind(0b011100);
const UNSAFE_INTRINSIC_MEMORY_KIND: u32 = Self::new_kind(0b011101);
const HOST_VAL_RAW_KIND: u32 = Self::new_kind(0b011110);
const ELEMENT_SEGMENT_KIND: u32 = Self::new_kind(0b011111);
const DATA_SEGMENT_KIND: u32 = Self::new_kind(0b100000);
pub(crate) fn into_raw(self) -> u32 {
match self {
AliasRegionKey::Vm { ty, offset } => {
debug_assert_eq!(offset & Self::KIND_MASK, 0);
let kind = match ty {
VmType::VMContext => Self::VM_CONTEXT_KIND,
VmType::VMStoreContext => Self::VM_STORE_CONTEXT_KIND,
VmType::VMMemoryDefinition => Self::VM_MEMORY_DEFINITION_KIND,
VmType::VMTableDefinition => Self::VM_TABLE_DEFINITION_KIND,
VmType::VMComponentContext => Self::VM_COMPONENT_CONTEXT_KIND,
VmType::VMDrcHeapData => Self::VM_DRC_HEAP_DATA_KIND,
VmType::VMCopyingHeapData => Self::VM_COPYING_HEAP_DATA_KIND,
VmType::VMNullHeapData => Self::VM_NULL_HEAP_DATA_KIND,
VmType::VMDeferredThread => Self::VM_DEFERRED_THREAD_KIND,
VmType::VMContRef => Self::VM_CONTREF_KIND,
VmType::ContinuationStackMemory => Self::CONTINUATION_STACK_MEMORY_KIND,
VmType::VMFunctionImport => Self::VM_FUNCTION_IMPORT_KIND,
VmType::VMMemoryImport => Self::VM_MEMORY_IMPORT_KIND,
VmType::VMTableImport => Self::VM_TABLE_IMPORT_KIND,
VmType::VMTagImport => Self::VM_TAG_IMPORT_KIND,
VmType::VMGlobalImport => Self::VM_GLOBAL_IMPORT_KIND,
VmType::VMFuncRef => Self::VM_FUNC_REF_KIND,
VmType::TypeIdsArray => Self::TYPE_IDS_ARRAY_KIND,
VmType::EpochCounter => Self::EPOCH_COUNTER_KIND,
VmType::BuiltinFunctionsArray => Self::BUILTIN_FUNCTIONS_KIND,
VmType::ComponentBuiltinFunctionsArray => {
Self::COMPONENT_BUILTIN_FUNCTIONS_KIND
}
VmType::HostValRaw => Self::HOST_VAL_RAW_KIND,
};
kind | (offset & Self::OFFSET_MASK)
}
AliasRegionKey::PublicMemory => Self::IMPORTED_MEMORY_KIND,
AliasRegionKey::DefinedMemory { module, index } => {
debug_assert_eq!(
module.as_u32() & !(Self::MODULE_MASK >> Self::MODULE_OFFSET),
0
);
debug_assert_eq!(index.as_u32() & !Self::INDEX_MASK, 0);
Self::DEFINED_MEMORY_KIND
| (module.as_u32() << Self::MODULE_OFFSET)
| index.as_u32()
}
AliasRegionKey::PublicTable => Self::IMPORTED_TABLE_KIND,
AliasRegionKey::DefinedTable { module, index } => {
debug_assert_eq!(
module.as_u32() & !(Self::MODULE_MASK >> Self::MODULE_OFFSET),
0
);
debug_assert_eq!(index.as_u32() & !Self::INDEX_MASK, 0);
Self::DEFINED_TABLE_KIND | (module.as_u32() << Self::MODULE_OFFSET) | index.as_u32()
}
AliasRegionKey::PublicGlobal => Self::IMPORTED_GLOBAL_KIND,
AliasRegionKey::DefinedGlobal { module, index } => {
debug_assert_eq!(
module.as_u32() & !(Self::MODULE_MASK >> Self::MODULE_OFFSET),
0
);
debug_assert_eq!(index.as_u32() & !Self::INDEX_MASK, 0);
Self::DEFINED_GLOBAL_KIND
| (module.as_u32() << Self::MODULE_OFFSET)
| index.as_u32()
}
AliasRegionKey::GcHeap => Self::GC_HEAP_KIND,
AliasRegionKey::Stack { slot } => {
debug_assert_eq!(slot.as_u32() & Self::KIND_MASK, 0);
Self::STACK_KIND | (slot.as_u32() & Self::OFFSET_MASK)
}
AliasRegionKey::UnsafeIntrinsicMemory => Self::UNSAFE_INTRINSIC_MEMORY_KIND,
AliasRegionKey::ElementSegment => Self::ELEMENT_SEGMENT_KIND,
AliasRegionKey::DataSegment => Self::DATA_SEGMENT_KIND,
}
}
}
impl fmt::Debug for AliasRegionKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
AliasRegionKey::Vm { ty, offset } => write!(f, "{ty:?}+{offset:#x}"),
AliasRegionKey::PublicMemory => write!(f, "PublicMemory"),
AliasRegionKey::DefinedMemory { module, index } => {
write!(f, "DefinedMemory({module:?}, {index:?})")
}
AliasRegionKey::PublicTable => write!(f, "PublicTable"),
AliasRegionKey::DefinedTable { module, index } => {
write!(f, "DefinedTable({module:?}, {index:?})")
}
AliasRegionKey::PublicGlobal => write!(f, "PublicGlobal"),
AliasRegionKey::DefinedGlobal { module, index } => {
write!(f, "DefinedGlobal({module:?}, {index:?})")
}
AliasRegionKey::GcHeap => write!(f, "GcHeap"),
AliasRegionKey::Stack { slot } => write!(f, "Stack({slot:?})"),
AliasRegionKey::UnsafeIntrinsicMemory => write!(f, "UnsafeIntrinsicMemory"),
AliasRegionKey::ElementSegment => write!(f, "ElementSegment"),
AliasRegionKey::DataSegment => write!(f, "DataSegment"),
}
}
}
impl From<AliasRegionKey> for ir::AliasRegionData {
fn from(key: AliasRegionKey) -> ir::AliasRegionData {
ir::AliasRegionData {
user_id: key.into_raw(),
description: format!("{key:?}").into(),
}
}
}
pub struct AliasRegions<Offsets> {
pointer_type: ir::Type,
offsets: Offsets,
cache: std::collections::HashMap<AliasRegionKey, ir::AliasRegion>,
}
impl<Offsets> AliasRegions<Offsets> {
pub fn stack_map_region(
regions: &mut ir::AliasRegionSet,
_ty: ir::Type,
slot: ir::StackSlot,
_offset: u32,
) -> Option<ir::AliasRegion> {
let key = AliasRegionKey::Stack { slot };
let id = key.into_raw();
if let Some(region) = regions.get(id) {
Some(region)
} else {
Some(regions.insert(key.into()))
}
}
pub fn stack_slot_region(
&mut self,
func: &mut ir::Function,
slot: ir::StackSlot,
) -> ir::AliasRegion {
self.region(func, AliasRegionKey::Stack { slot })
}
fn region(&mut self, func: &mut ir::Function, key: AliasRegionKey) -> ir::AliasRegion {
*self
.cache
.entry(key)
.or_insert_with(|| func.dfg.alias_regions.insert(key.into()))
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn new(offsets: Offsets) -> Self {
Self {
pointer_type: ir::Type::int_with_byte_size(offsets.get_ptr_size().size().into())
.unwrap(),
offsets,
cache: std::collections::HashMap::default(),
}
}
pub fn gc_heap_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(func, AliasRegionKey::GcHeap)
}
pub fn public_memory_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(func, AliasRegionKey::PublicMemory)
}
pub fn defined_memory_region(
&mut self,
func: &mut ir::Function,
module: StaticModuleIndex,
index: DefinedMemoryIndex,
) -> ir::AliasRegion {
self.region(func, AliasRegionKey::DefinedMemory { module, index })
}
pub fn public_table_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(func, AliasRegionKey::PublicTable)
}
pub fn defined_table_region(
&mut self,
func: &mut ir::Function,
module: StaticModuleIndex,
index: DefinedTableIndex,
) -> ir::AliasRegion {
self.region(func, AliasRegionKey::DefinedTable { module, index })
}
pub fn public_global_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(func, AliasRegionKey::PublicGlobal)
}
pub fn defined_global_region(
&mut self,
func: &mut ir::Function,
module: StaticModuleIndex,
index: DefinedGlobalIndex,
) -> ir::AliasRegion {
self.region(func, AliasRegionKey::DefinedGlobal { module, index })
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
fn vmctx_region(&mut self, func: &mut ir::Function, offset: u32) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMContext,
offset,
},
)
}
fn vmctx_load(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
base_flags: ir::MemFlagsData,
vmctx: ir::Value,
offset: u32,
) -> ir::Value {
let region = self.vmctx_region(cursor.func, offset);
cursor.ins().load(
ty,
base_flags.with_alias_region(Some(region)),
vmctx,
i32::try_from(offset).unwrap(),
)
}
fn vmctx_store(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
vmctx: ir::Value,
offset: u32,
val: ir::Value,
) {
let region = self.vmctx_region(cursor.func, offset);
cursor.ins().store(
base_flags.with_alias_region(Some(region)),
val,
vmctx,
i32::try_from(offset).unwrap(),
);
}
pub fn vmctx_magic(&mut self, cursor: &mut FuncCursor<'_>, vmctx: ir::Value) -> ir::Value {
self.vmctx_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.get_ptr_size().vmctx_magic().into(),
)
}
pub fn vmctx_store_context(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
) -> ir::Value {
self.vmctx_store_context_load(cursor.func)
.emit(cursor, vmctx)
}
pub fn vmctx_store_context_load(&mut self, func: &mut ir::Function) -> Load {
let offset = u32::from(self.offsets.get_ptr_size().vmctx_store_context());
let region = self.vmctx_region(func, offset);
Load {
offset,
flags: ir::MemFlagsData::trusted()
.with_readonly()
.with_can_move()
.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmctx_epoch_ptr(&mut self, cursor: &mut FuncCursor<'_>, vmctx: ir::Value) -> ir::Value {
self.vmctx_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.get_ptr_size().vmctx_epoch_ptr().into(),
)
}
pub fn vmctx_shared_type_ids_array(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
) -> ir::Value {
self.vmctx_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.get_ptr_size().vmctx_type_ids_array().into(),
)
}
pub fn vmctx_gc_heap_data(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
) -> ir::Value {
self.vmctx_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.get_ptr_size().vmctx_gc_heap_data().into(),
)
}
pub fn vmctx_builtin_functions(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
) -> ir::Value {
self.vmctx_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets
.get_ptr_size()
.vmcontext_builtin_functions()
.into(),
)
}
}
impl AliasRegions<VMOffsets<u8>> {
fn vmimport_load(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
base_flags: ir::MemFlagsData,
vmctx: ir::Value,
vmctx_offset: u32,
field_offset: u32,
vm_type: VmType,
) -> ir::Value {
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: vm_type,
offset: field_offset,
},
);
cursor.ins().load(
ty,
base_flags.with_alias_region(Some(region)),
vmctx,
i32::try_from(vmctx_offset).unwrap(),
)
}
pub fn vmctx_vmtag_import_vmctx(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
tag: TagIndex,
) -> ir::Value {
self.vmimport_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.vmctx_vmtag_import_vmctx(tag),
self.offsets.vmtag_import_vmctx().into(),
VmType::VMTagImport,
)
}
pub fn vmctx_vmtag_import_index(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
tag: TagIndex,
) -> ir::Value {
self.vmimport_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.vmctx_vmtag_import_index(tag),
self.offsets.vmtag_import_index().into(),
VmType::VMTagImport,
)
}
pub fn vmctx_vmtag_import_from(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
tag: TagIndex,
) -> ir::Value {
self.vmimport_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.vmctx_vmtag_import_from(tag),
self.offsets.vmtag_import_from().into(),
VmType::VMTagImport,
)
}
pub fn vmctx_vmfunction_import_vmctx(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
func: FuncIndex,
) -> ir::Value {
self.vmimport_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.vmctx_vmfunction_import_vmctx(func),
self.offsets.vmfunction_import_vmctx().into(),
VmType::VMFunctionImport,
)
}
pub fn vmctx_vmfunction_import_wasm_call(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
func: FuncIndex,
) -> ir::Value {
self.vmimport_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
self.offsets.vmctx_vmfunction_import_wasm_call(func),
self.offsets.vmfunction_import_wasm_call().into(),
VmType::VMFunctionImport,
)
}
pub fn vmctx_vmmemory_import_vmctx(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
memory: MemoryIndex,
) -> ir::Value {
let mem_offset = self.offsets.vmctx_vmmemory_import(memory);
let mem_vmctx_offset = mem_offset + u32::from(self.offsets.vmmemory_import_vmctx());
self.vmimport_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
mem_vmctx_offset,
self.offsets.vmmemory_import_vmctx().into(),
VmType::VMMemoryImport,
)
}
pub fn vmctx_vmmemory_import_index(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
memory: MemoryIndex,
) -> ir::Value {
let mem_offset = self.offsets.vmctx_vmmemory_import(memory);
let mem_index_offset = mem_offset + u32::from(self.offsets.vmmemory_import_index());
self.vmimport_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
mem_index_offset,
self.offsets.vmmemory_import_index().into(),
VmType::VMMemoryImport,
)
}
pub fn vmctx_vmmemory_import_from(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
memory: MemoryIndex,
) -> ir::Value {
self.vmctx_vmmemory_import_from_load(cursor.func, memory)
.emit(cursor, vmctx)
}
pub fn vmctx_vmmemory_import_from_load(
&mut self,
func: &mut ir::Function,
memory: MemoryIndex,
) -> Load {
let mem_offset = self.offsets.vmctx_vmmemory_import(memory);
let offset = mem_offset + u32::from(self.offsets.vmmemory_import_from());
let region = self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMMemoryImport,
offset: self.offsets.vmmemory_import_from().into(),
},
);
Load {
offset,
flags: ir::MemFlagsData::trusted()
.with_readonly()
.with_can_move()
.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmctx_vmtable_import_vmctx(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
table: TableIndex,
) -> ir::Value {
let table_offset = self.offsets.vmctx_vmtable_import(table);
let table_vmctx_offset = table_offset + u32::from(self.offsets.vmtable_import_vmctx());
self.vmimport_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
table_vmctx_offset,
self.offsets.vmtable_import_vmctx().into(),
VmType::VMTableImport,
)
}
pub fn vmctx_vmtable_import_index(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
table: TableIndex,
) -> ir::Value {
let table_offset = self.offsets.vmctx_vmtable_import(table);
let table_index_offset = table_offset + u32::from(self.offsets.vmtable_import_index());
self.vmimport_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
table_index_offset,
self.offsets.vmtable_import_index().into(),
VmType::VMTableImport,
)
}
pub fn vmctx_vmtable_from_load(&mut self, func: &mut ir::Function, table: TableIndex) -> Load {
let offset = self.offsets.vmctx_vmtable_from(table);
let region = self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMTableImport,
offset: self.offsets.vmtable_import_from().into(),
},
);
Load {
offset,
flags: ir::MemFlagsData::trusted()
.with_readonly()
.with_can_move()
.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmctx_vmglobal_import_from(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
global: GlobalIndex,
) -> ir::Value {
let from_offset = self.offsets.vmctx_vmglobal_import_from(global);
self.vmimport_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmctx,
from_offset,
self.offsets.vmglobal_import_from().into(),
VmType::VMGlobalImport,
)
}
pub fn vmctx_vmmemory_pointer(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
memory: DefinedMemoryIndex,
) -> ir::Value {
self.vmctx_vmmemory_pointer_load(cursor.func, memory)
.emit(cursor, vmctx)
}
pub fn vmctx_vmmemory_pointer_load(
&mut self,
func: &mut ir::Function,
memory: DefinedMemoryIndex,
) -> Load {
let offset = self.offsets.vmctx_vmmemory_pointer(memory);
let region = self.vmctx_region(func, offset);
Load {
offset,
flags: ir::MemFlagsData::trusted()
.with_readonly()
.with_can_move()
.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmctx_runtime_data_base(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
runtime_data: RuntimeDataIndex,
) -> ir::Value {
self.vmctx_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.vmctx_runtime_data_base(runtime_data),
)
}
pub fn vmctx_runtime_data_length(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
runtime_data: RuntimeDataIndex,
) -> ir::Value {
self.vmctx_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.vmctx_runtime_data_length(runtime_data),
)
}
pub fn store_vmctx_runtime_data_length(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
runtime_data: RuntimeDataIndex,
new_length: ir::Value,
) {
self.vmctx_store(
cursor,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.vmctx_runtime_data_length(runtime_data),
new_length,
)
}
pub fn vmctx_vmmemory_definition_base_load(
&mut self,
func: &mut ir::Function,
memory: OwnedMemoryIndex,
base_flags: ir::MemFlagsData,
) -> Load {
let field = self.offsets.ptr.vmmemory_definition_base();
let region = self.vmmemory_definition_region(func, field.into());
Load {
offset: self.offsets.vmctx_vmmemory_definition_base(memory),
flags: base_flags.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmctx_vmmemory_definition_base(
&mut self,
cursor: &mut FuncCursor<'_>,
memory: OwnedMemoryIndex,
base_flags: ir::MemFlagsData,
vmctx: ir::Value,
) -> ir::Value {
self.vmctx_vmmemory_definition_base_load(cursor.func, memory, base_flags)
.emit(cursor, vmctx)
}
pub fn vmctx_vmmemory_definition_current_length_load(
&mut self,
func: &mut ir::Function,
memory: OwnedMemoryIndex,
) -> Load {
let field = self.offsets.ptr.vmmemory_definition_current_length();
let region = self.vmmemory_definition_region(func, field.into());
Load {
offset: self
.offsets
.vmctx_vmmemory_definition_current_length(memory),
flags: ir::MemFlagsData::trusted().with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmctx_vmmemory_definition_current_length(
&mut self,
cursor: &mut FuncCursor<'_>,
memory: OwnedMemoryIndex,
vmctx: ir::Value,
) -> ir::Value {
self.vmctx_vmmemory_definition_current_length_load(cursor.func, memory)
.emit(cursor, vmctx)
}
fn vmtable_definition_region(
&mut self,
func: &mut ir::Function,
offset: u32,
) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMTableDefinition,
offset,
},
)
}
pub fn vmctx_vmtable_definition_base_load(
&mut self,
func: &mut ir::Function,
table: DefinedTableIndex,
base_flags: ir::MemFlagsData,
) -> Load {
let field = self.offsets.vmtable_definition_base();
let region = self.vmtable_definition_region(func, field.into());
Load {
offset: self.offsets.vmctx_vmtable_definition_base(table),
flags: base_flags.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmctx_vmtable_definition_current_elements_load(
&mut self,
func: &mut ir::Function,
table: DefinedTableIndex,
ty: ir::Type,
) -> Load {
let field = self.offsets.vmtable_definition_current_elements();
let region = self.vmtable_definition_region(func, field.into());
Load {
offset: self
.offsets
.vmctx_vmtable_definition_current_elements(table),
flags: ir::MemFlagsData::trusted().with_alias_region(Some(region)),
ty,
}
}
pub fn vmtable_definition_base_load(
&mut self,
func: &mut ir::Function,
base_flags: ir::MemFlagsData,
) -> Load {
let offset = self.offsets.vmtable_definition_base().into();
let region = self.vmtable_definition_region(func, offset);
Load {
offset,
flags: base_flags.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmtable_definition_current_elements_load(
&mut self,
func: &mut ir::Function,
ty: ir::Type,
) -> Load {
let offset = self.offsets.vmtable_definition_current_elements().into();
let region = self.vmtable_definition_region(func, offset);
Load {
offset,
flags: ir::MemFlagsData::trusted().with_alias_region(Some(region)),
ty,
}
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
fn vmstore_context_region(&mut self, func: &mut ir::Function, offset: u32) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMStoreContext,
offset,
},
)
}
fn vmstore_context_load(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
base_flags: ir::MemFlagsData,
vmstore_ctx: ir::Value,
offset: u32,
) -> ir::Value {
let region = self.vmstore_context_region(cursor.func, offset);
cursor.ins().load(
ty,
base_flags.with_alias_region(Some(region)),
vmstore_ctx,
i32::try_from(offset).unwrap(),
)
}
fn vmstore_context_store(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
vmstore_ctx: ir::Value,
offset: u32,
val: ir::Value,
) {
let region = self.vmstore_context_region(cursor.func, offset);
cursor.ins().store(
base_flags.with_alias_region(Some(region)),
val,
vmstore_ctx,
i32::try_from(offset).unwrap(),
);
}
pub fn vmstore_context_store_data(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly().with_can_move(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_store_data()
.into(),
)
}
pub fn vmstore_context_execution_version(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_load(
cursor,
ir::types::I64,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_execution_version()
.into(),
)
}
pub fn store_vmstore_context_execution_version(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
new_version: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_execution_version()
.into(),
new_version,
)
}
pub fn vmstore_context_fuel_consumed(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_load(
cursor,
ir::types::I64,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_fuel_consumed()
.into(),
)
}
pub fn store_vmstore_context_fuel_consumed(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
fuel_consumed: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_fuel_consumed()
.into(),
fuel_consumed,
)
}
pub fn vmstore_context_epoch_deadline(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_load(
cursor,
ir::types::I64,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_epoch_deadline()
.into(),
)
}
pub fn vmstore_context_stack_limit_load(&mut self, func: &mut ir::Function) -> Load {
let offset = self
.offsets
.get_ptr_size()
.vmstore_context_stack_limit()
.into();
let region = self.vmstore_context_region(func, offset);
Load {
offset,
flags: ir::MemFlagsData::trusted().with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmstore_context_stack_limit(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_stack_limit_load(cursor.func)
.emit(cursor, vmstore_ctx)
}
pub fn store_vmstore_context_stack_limit(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
stack_limit: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_stack_limit()
.into(),
stack_limit,
)
}
pub fn vmstore_context_current_thread(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_current_thread()
.into(),
)
}
pub fn store_vmstore_context_current_thread(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
new_thread: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_current_thread()
.into(),
new_thread,
)
}
pub fn vmstore_context_gc_heap_base_load(
&mut self,
func: &mut ir::Function,
base_flags: ir::MemFlagsData,
) -> Load {
let offset = self
.offsets
.get_ptr_size()
.vmstore_context_gc_heap_base()
.into();
let region = self.vmstore_context_region(func, offset);
Load {
offset,
flags: base_flags.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmstore_context_gc_heap_base(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_gc_heap_base_load(cursor.func, base_flags)
.emit(cursor, vmstore_ctx)
}
pub fn vmstore_context_gc_heap_current_length_load(&mut self, func: &mut ir::Function) -> Load {
let offset = self
.offsets
.get_ptr_size()
.vmstore_context_gc_heap_current_length()
.into();
let region = self.vmstore_context_region(func, offset);
Load {
offset,
flags: ir::MemFlagsData::trusted().with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmstore_context_gc_heap_current_length(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_gc_heap_current_length_load(cursor.func)
.emit(cursor, vmstore_ctx)
}
pub fn vmstore_context_last_wasm_entry_fp(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
) -> ir::Value {
self.vmstore_context_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_last_wasm_entry_fp()
.into(),
)
}
pub fn store_vmstore_context_last_wasm_entry_fp(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
fp: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_last_wasm_entry_fp()
.into(),
fp,
)
}
pub fn store_vmstore_context_last_wasm_entry_sp(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
sp: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_last_wasm_entry_sp()
.into(),
sp,
)
}
pub fn store_vmstore_context_last_wasm_entry_trap_handler(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
trap_handler: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_last_wasm_entry_trap_handler()
.into(),
trap_handler,
)
}
pub fn store_vmstore_context_last_wasm_exit_trampoline_fp(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
fp: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_last_wasm_exit_trampoline_fp()
.into(),
fp,
)
}
pub fn store_vmstore_context_last_wasm_exit_pc(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
pc: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_last_wasm_exit_pc()
.into(),
pc,
)
}
pub fn vmstore_context_stack_chain_region(
&mut self,
func: &mut ir::Function,
) -> ir::AliasRegion {
let offset = self.offsets.get_ptr_size().vmstore_context_stack_chain();
self.vmstore_context_region(func, offset.into())
}
pub fn vmstore_context_component_context_slot(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
vmstore_ctx: ir::Value,
slot: u8,
) -> ir::Value {
self.vmstore_context_load(
cursor,
ty,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_component_context_slot(slot)
.into(),
)
}
pub fn store_vmstore_context_component_context_slot(
&mut self,
cursor: &mut FuncCursor<'_>,
vmstore_ctx: ir::Value,
slot: u8,
val: ir::Value,
) {
self.vmstore_context_store(
cursor,
ir::MemFlagsData::trusted(),
vmstore_ctx,
self.offsets
.get_ptr_size()
.vmstore_context_component_context_slot(slot)
.into(),
val,
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
fn vmdeferred_thread_region(
&mut self,
func: &mut ir::Function,
offset: u32,
) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMDeferredThread,
offset,
},
)
}
fn vmdeferred_thread_load(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
base_flags: ir::MemFlagsData,
vmdeferred_thread_ptr: ir::Value,
offset: u32,
) -> ir::Value {
let region = self.vmdeferred_thread_region(cursor.func, offset);
cursor.ins().load(
ty,
base_flags.with_alias_region(Some(region)),
vmdeferred_thread_ptr,
i32::try_from(offset).unwrap(),
)
}
fn vmdeferred_thread_store(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
vmdeferred_thread_ptr: ir::Value,
offset: u32,
val: ir::Value,
) {
let region = self.vmdeferred_thread_region(cursor.func, offset);
cursor.ins().store(
base_flags.with_alias_region(Some(region)),
val,
vmdeferred_thread_ptr,
i32::try_from(offset).unwrap(),
);
}
pub fn vmdeferred_thread_parent(
&mut self,
cursor: &mut FuncCursor<'_>,
vmdeferred_thread_ptr: ir::Value,
) -> ir::Value {
self.vmdeferred_thread_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmdeferred_thread_ptr,
self.offsets
.get_ptr_size()
.vmdeferred_thread_parent()
.into(),
)
}
pub fn store_vmdeferred_thread_parent(
&mut self,
cursor: &mut FuncCursor<'_>,
vmdeferred_thread_ptr: ir::Value,
parent: ir::Value,
) {
self.vmdeferred_thread_store(
cursor,
ir::MemFlagsData::trusted(),
vmdeferred_thread_ptr,
self.offsets
.get_ptr_size()
.vmdeferred_thread_parent()
.into(),
parent,
)
}
pub fn store_vmdeferred_thread_caller_instance(
&mut self,
cursor: &mut FuncCursor<'_>,
vmdeferred_thread_ptr: ir::Value,
caller_instance: ir::Value,
) {
self.vmdeferred_thread_store(
cursor,
ir::MemFlagsData::trusted(),
vmdeferred_thread_ptr,
self.offsets
.get_ptr_size()
.vmdeferred_thread_caller_instance()
.into(),
caller_instance,
)
}
pub fn store_vmdeferred_thread_callee_async(
&mut self,
cursor: &mut FuncCursor<'_>,
vmdeferred_thread_ptr: ir::Value,
callee_async: ir::Value,
) {
self.vmdeferred_thread_store(
cursor,
ir::MemFlagsData::trusted(),
vmdeferred_thread_ptr,
self.offsets
.get_ptr_size()
.vmdeferred_thread_callee_async()
.into(),
callee_async,
)
}
pub fn store_vmdeferred_thread_callee_instance(
&mut self,
cursor: &mut FuncCursor<'_>,
vmdeferred_thread_ptr: ir::Value,
callee_instance: ir::Value,
) {
self.vmdeferred_thread_store(
cursor,
ir::MemFlagsData::trusted(),
vmdeferred_thread_ptr,
self.offsets
.get_ptr_size()
.vmdeferred_thread_callee_instance()
.into(),
callee_instance,
)
}
pub fn vmdeferred_thread_saved_context(
&mut self,
cursor: &mut FuncCursor<'_>,
vmdeferred_thread_ptr: ir::Value,
i: u8,
) -> ir::Value {
self.vmdeferred_thread_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted(),
vmdeferred_thread_ptr,
self.offsets
.get_ptr_size()
.vmdeferred_thread_saved_context(i)
.into(),
)
}
pub fn store_vmdeferred_thread_saved_context(
&mut self,
cursor: &mut FuncCursor<'_>,
vmdeferred_thread_ptr: ir::Value,
i: u8,
val: ir::Value,
) {
self.vmdeferred_thread_store(
cursor,
ir::MemFlagsData::trusted(),
vmdeferred_thread_ptr,
self.offsets
.get_ptr_size()
.vmdeferred_thread_saved_context(i)
.into(),
val,
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
fn vmmemory_definition_region(
&mut self,
func: &mut ir::Function,
offset: u32,
) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMMemoryDefinition,
offset,
},
)
}
pub fn vmmemory_definition_base_load(
&mut self,
func: &mut ir::Function,
base_flags: ir::MemFlagsData,
) -> Load {
let offset = self
.offsets
.get_ptr_size()
.vmmemory_definition_base()
.into();
let region = self.vmmemory_definition_region(func, offset);
Load {
offset,
flags: base_flags.with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmmemory_definition_current_length_load(&mut self, func: &mut ir::Function) -> Load {
let offset = self
.offsets
.get_ptr_size()
.vmmemory_definition_current_length()
.into();
let region = self.vmmemory_definition_region(func, offset);
Load {
offset,
flags: ir::MemFlagsData::trusted().with_alias_region(Some(region)),
ty: self.pointer_type,
}
}
pub fn vmmemory_definition_base(
&mut self,
cursor: &mut FuncCursor<'_>,
vmmemory_definition: ir::Value,
) -> ir::Value {
self.vmmemory_definition_base_load(cursor.func, ir::MemFlagsData::trusted())
.emit(cursor, vmmemory_definition)
}
pub fn vmmemory_definition_current_length(
&mut self,
cursor: &mut FuncCursor<'_>,
vmmemory_definition: ir::Value,
) -> ir::Value {
self.vmmemory_definition_current_length_load(cursor.func)
.emit(cursor, vmmemory_definition)
}
pub fn vmmemory_definition_current_length_atomic(
&mut self,
cursor: &mut FuncCursor<'_>,
vmmemory_definition: ir::Value,
) -> ir::Value {
let offset = self
.offsets
.get_ptr_size()
.vmmemory_definition_current_length();
let region = self.vmmemory_definition_region(cursor.func, offset.into());
let offset = cursor.ins().iconst(self.pointer_type, i64::from(offset));
let ptr = cursor.ins().iadd(vmmemory_definition, offset);
cursor.ins().atomic_load(
self.pointer_type,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
ptr,
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
fn vmfuncref_region(&mut self, func: &mut ir::Function, offset: u32) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMFuncRef,
offset,
},
)
}
pub fn vmfuncref_type_index(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
funcref: ir::Value,
) -> ir::Value {
let offset = self.offsets.get_ptr_size().vm_func_ref_type_index();
let region = self.vmfuncref_region(cursor.func, offset.into());
let ty = ir::Type::int_with_byte_size(
self.offsets
.get_ptr_size()
.size_of_vmshared_type_index()
.into(),
)
.unwrap();
cursor.ins().load(
ty,
base_flags.with_alias_region(Some(region)),
funcref,
i32::from(offset),
)
}
pub fn vmfuncref_wasm_call(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
funcref: ir::Value,
) -> ir::Value {
let offset = self.offsets.get_ptr_size().vm_func_ref_wasm_call();
let region = self.vmfuncref_region(cursor.func, offset.into());
cursor.ins().load(
self.pointer_type,
base_flags.with_alias_region(Some(region)),
funcref,
i32::from(offset),
)
}
pub fn vmfuncref_vmctx(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
funcref: ir::Value,
) -> ir::Value {
let offset = self.offsets.get_ptr_size().vm_func_ref_vmctx();
let region = self.vmfuncref_region(cursor.func, offset.into());
cursor.ins().load(
self.pointer_type,
base_flags.with_alias_region(Some(region)),
funcref,
i32::from(offset),
)
}
pub fn vmarray_call_host_func_context_array_call(
&mut self,
cursor: &mut FuncCursor<'_>,
host_func_ctx: ir::Value,
) -> ir::Value {
let func_ref = self
.offsets
.get_ptr_size()
.vmarray_call_host_func_context_func_ref();
let field = self.offsets.get_ptr_size().vm_func_ref_array_call();
let region = self.vmfuncref_region(cursor.func, field.into());
cursor.ins().load(
self.pointer_type,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
host_func_ctx,
i32::from(func_ref) + i32::from(field),
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn type_ids_array_element(
&mut self,
cursor: &mut FuncCursor<'_>,
array: ir::Value,
ty: ModuleInternedTypeIndex,
) -> ir::Value {
let load_ty = ir::Type::int_with_byte_size(
self.offsets
.get_ptr_size()
.size_of_vmshared_type_index()
.into(),
)
.unwrap();
let offset = ty.as_u32().checked_mul(load_ty.bytes()).unwrap();
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: VmType::TypeIdsArray,
offset,
},
);
cursor.ins().load(
load_ty,
ir::MemFlagsData::trusted()
.with_readonly()
.with_can_move()
.with_alias_region(Some(region)),
array,
i32::try_from(offset).unwrap(),
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn epoch_counter(
&mut self,
cursor: &mut FuncCursor<'_>,
epoch_ptr: ir::Value,
) -> ir::Value {
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: VmType::EpochCounter,
offset: 0,
},
);
cursor.ins().load(
ir::types::I64,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
epoch_ptr,
0,
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn builtin_functions_array_element(
&mut self,
cursor: &mut FuncCursor<'_>,
array: ir::Value,
builtin: BuiltinFunctionIndex,
) -> ir::Value {
let offset = builtin
.index()
.checked_mul(self.pointer_type.bytes())
.unwrap();
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: VmType::BuiltinFunctionsArray,
offset,
},
);
cursor.ins().load(
self.pointer_type,
ir::MemFlagsData::trusted()
.with_readonly()
.with_can_move()
.with_alias_region(Some(region)),
array,
i32::try_from(offset).unwrap(),
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn component_builtin_functions_array_element(
&mut self,
cursor: &mut FuncCursor<'_>,
array: ir::Value,
builtin: ComponentBuiltinFunctionIndex,
) -> ir::Value {
let offset = builtin
.index()
.checked_mul(self.pointer_type.bytes())
.unwrap();
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: VmType::ComponentBuiltinFunctionsArray,
offset,
},
);
cursor.ins().load(
self.pointer_type,
ir::MemFlagsData::trusted()
.with_readonly()
.with_can_move()
.with_alias_region(Some(region)),
array,
i32::try_from(offset).unwrap(),
)
}
pub fn host_val_raw_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::HostValRaw,
offset: 0,
},
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn element_segment_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(func, AliasRegionKey::ElementSegment)
}
pub fn data_segment_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(func, AliasRegionKey::DataSegment)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn unsafe_intrinsic_load(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
base_flags: ir::MemFlagsData,
addr: ir::Value,
) -> ir::Value {
let region = self.region(cursor.func, AliasRegionKey::UnsafeIntrinsicMemory);
cursor
.ins()
.load(ty, base_flags.with_alias_region(Some(region)), addr, 0)
}
pub fn unsafe_intrinsic_store(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
val: ir::Value,
addr: ir::Value,
) {
let region = self.region(cursor.func, AliasRegionKey::UnsafeIntrinsicMemory);
cursor
.ins()
.store(base_flags.with_alias_region(Some(region)), val, addr, 0);
}
}
impl AliasRegions<VMComponentOffsets<u8>> {
fn vmcomponent_region(&mut self, func: &mut ir::Function, offset: u32) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMComponentContext,
offset,
},
)
}
fn vmcomponent_load(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
base_flags: ir::MemFlagsData,
vmctx: ir::Value,
offset: u32,
) -> ir::Value {
let region = self.vmcomponent_region(cursor.func, offset);
cursor.ins().load(
ty,
base_flags.with_alias_region(Some(region)),
vmctx,
i32::try_from(offset).unwrap(),
)
}
fn vmcomponent_store(
&mut self,
cursor: &mut FuncCursor<'_>,
base_flags: ir::MemFlagsData,
vmctx: ir::Value,
offset: u32,
val: ir::Value,
) {
let region = self.vmcomponent_region(cursor.func, offset);
cursor.ins().store(
base_flags.with_alias_region(Some(region)),
val,
vmctx,
i32::try_from(offset).unwrap(),
);
}
pub fn vmcomponent_lowering_data(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
index: LoweredIndex,
) -> ir::Value {
self.vmcomponent_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.lowering_data(index),
)
}
pub fn vmcomponent_lowering_callee(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
index: LoweredIndex,
) -> ir::Value {
self.vmcomponent_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.lowering_callee(index),
)
}
pub fn vmcomponent_task_may_block(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
) -> ir::Value {
self.vmcomponent_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted().with_readonly(),
vmctx,
self.offsets.task_may_block(),
)
}
pub fn store_vmcomponent_task_may_block(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
val: ir::Value,
) {
self.vmcomponent_store(
cursor,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.task_may_block(),
val,
)
}
pub fn vmcomponent_resource_destructor(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
index: ResourceIndex,
) -> ir::Value {
self.vmcomponent_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly(),
vmctx,
self.offsets.resource_destructor(index),
)
}
pub fn vmcomponent_runtime_memory(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
index: RuntimeMemoryIndex,
) -> ir::Value {
self.vmcomponent_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.runtime_memory(index),
)
}
pub fn vmcomponent_runtime_callback(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
index: RuntimeCallbackIndex,
) -> ir::Value {
self.vmcomponent_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.runtime_callback(index),
)
}
pub fn vmcomponent_runtime_post_return(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
index: RuntimePostReturnIndex,
) -> ir::Value {
self.vmcomponent_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.runtime_post_return(index),
)
}
pub fn vmcomponent_builtins(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
) -> ir::Value {
self.vmcomponent_load(
cursor,
self.pointer_type,
ir::MemFlagsData::trusted().with_readonly(),
vmctx,
self.offsets.builtins(),
)
}
pub fn vmcomponent_instance_may_leave(
&mut self,
cursor: &mut FuncCursor<'_>,
vmctx: ir::Value,
instance: RuntimeComponentInstanceIndex,
) -> ir::Value {
self.vmcomponent_load(
cursor,
ir::types::I32,
ir::MemFlagsData::trusted(),
vmctx,
self.offsets.may_leave(instance),
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn vmcomponent_context_generic_load(
&mut self,
cursor: &mut FuncCursor<'_>,
ty: ir::Type,
base_flags: ir::MemFlagsData,
vmctx: ir::Value,
offset: u32,
) -> ir::Value {
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: VmType::VMComponentContext,
offset,
},
);
cursor.ins().load(
ty,
base_flags.with_alias_region(Some(region)),
vmctx,
i32::try_from(offset).unwrap(),
)
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
fn vmdrc_heap_data_region(&mut self, func: &mut ir::Function, offset: u32) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMDrcHeapData,
offset,
},
)
}
pub fn vmdrc_heap_data_over_approximated_stack_roots(
&mut self,
cursor: &mut FuncCursor<'_>,
drc_heap_data: ir::Value,
) -> ir::Value {
let offset = self
.offsets
.get_ptr_size()
.vmdrc_heap_data_over_approximated_stack_roots();
let region = self.vmdrc_heap_data_region(cursor.func, offset.into());
cursor.ins().load(
ir::types::I32,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
drc_heap_data,
i32::from(offset),
)
}
pub fn store_vmdrc_heap_data_over_approximated_stack_roots(
&mut self,
cursor: &mut FuncCursor<'_>,
drc_heap_data: ir::Value,
val: ir::Value,
) {
let offset = self
.offsets
.get_ptr_size()
.vmdrc_heap_data_over_approximated_stack_roots();
let region = self.vmdrc_heap_data_region(cursor.func, offset.into());
cursor.ins().store(
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
val,
drc_heap_data,
i32::from(offset),
);
}
pub fn vmdrc_heap_data_current_over_approximated_stack_roots_len(
&mut self,
cursor: &mut FuncCursor<'_>,
drc_heap_data: ir::Value,
) -> ir::Value {
let offset = self
.offsets
.get_ptr_size()
.vmdrc_heap_data_current_over_approximated_stack_roots_len();
let region = self.vmdrc_heap_data_region(cursor.func, offset.into());
cursor.ins().load(
ir::types::I32,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
drc_heap_data,
i32::from(offset),
)
}
pub fn store_vmdrc_heap_data_current_over_approximated_stack_roots_len(
&mut self,
cursor: &mut FuncCursor<'_>,
drc_heap_data: ir::Value,
len: ir::Value,
) {
let offset = self
.offsets
.get_ptr_size()
.vmdrc_heap_data_current_over_approximated_stack_roots_len();
let region = self.vmdrc_heap_data_region(cursor.func, offset.into());
cursor.ins().store(
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
len,
drc_heap_data,
i32::from(offset),
);
}
pub fn vmdrc_heap_data_over_approximated_stack_roots_len_after_last_gc(
&mut self,
cursor: &mut FuncCursor<'_>,
drc_heap_data: ir::Value,
) -> ir::Value {
let offset = self
.offsets
.get_ptr_size()
.vmdrc_heap_data_over_approximated_stack_roots_len_after_last_gc();
let region = self.vmdrc_heap_data_region(cursor.func, offset.into());
cursor.ins().load(
ir::types::I32,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
drc_heap_data,
i32::from(offset),
)
}
fn vmcopying_heap_data_region(
&mut self,
func: &mut ir::Function,
offset: u32,
) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMCopyingHeapData,
offset,
},
)
}
pub fn vmcopying_heap_data_bump_ptr(
&mut self,
cursor: &mut FuncCursor<'_>,
copying_heap_data: ir::Value,
) -> ir::Value {
let offset = self.offsets.get_ptr_size().vmcopying_heap_data_bump_ptr();
let region = self.vmcopying_heap_data_region(cursor.func, offset.into());
cursor.ins().load(
ir::types::I32,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
copying_heap_data,
i32::from(offset),
)
}
pub fn store_vmcopying_heap_data_bump_ptr(
&mut self,
cursor: &mut FuncCursor<'_>,
copying_heap_data: ir::Value,
val: ir::Value,
) {
let offset = self.offsets.get_ptr_size().vmcopying_heap_data_bump_ptr();
let region = self.vmcopying_heap_data_region(cursor.func, offset.into());
cursor.ins().store(
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
val,
copying_heap_data,
i32::from(offset),
);
}
pub fn vmcopying_heap_data_active_space_end(
&mut self,
cursor: &mut FuncCursor<'_>,
copying_heap_data: ir::Value,
) -> ir::Value {
let offset = self
.offsets
.get_ptr_size()
.vmcopying_heap_data_active_space_end();
let region = self.vmcopying_heap_data_region(cursor.func, offset.into());
cursor.ins().load(
ir::types::I32,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
copying_heap_data,
i32::from(offset),
)
}
pub fn vmnull_heap_data_bump_finger(
&mut self,
cursor: &mut FuncCursor<'_>,
null_collector_heap_data: ir::Value,
) -> ir::Value {
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: VmType::VMNullHeapData,
offset: 0,
},
);
cursor.ins().load(
ir::types::I32,
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
null_collector_heap_data,
0,
)
}
pub fn store_vmnull_heap_data_bump_finger(
&mut self,
cursor: &mut FuncCursor<'_>,
null_collector_heap_data: ir::Value,
val: ir::Value,
) {
let region = self.region(
cursor.func,
AliasRegionKey::Vm {
ty: VmType::VMNullHeapData,
offset: 0,
},
);
cursor.ins().store(
ir::MemFlagsData::trusted().with_alias_region(Some(region)),
val,
null_collector_heap_data,
0,
);
}
}
impl<Offsets> AliasRegions<Offsets>
where
Offsets: GetPtrSize,
{
pub fn vmcontref_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::VMContRef,
offset: 0,
},
)
}
pub fn continuation_stack_memory_region(&mut self, func: &mut ir::Function) -> ir::AliasRegion {
self.region(
func,
AliasRegionKey::Vm {
ty: VmType::ContinuationStackMemory,
offset: 0,
},
)
}
}
pub(crate) fn debug_assert_all_mem_insts_have_alias_regions(func: &ir::Function) {
if cfg!(debug_assertions) {
for block in func.layout.blocks() {
for inst in func.layout.block_insts(block) {
let opcode = func.dfg.insts[inst].opcode();
if !opcode.can_load() && !opcode.can_store() {
continue;
}
if let Some(flags) = func.dfg.insts[inst].memflags() {
debug_assert!(
func.dfg.mem_flags[flags].alias_region().is_some(),
"CLIF memory instruction emitted without an alias region: {}",
func.dfg.display_inst(inst),
);
}
}
}
}
}