Path: blob/main/cranelift/interpreter/src/address.rs
1692 views
//! Virtual Addressing Scheme for the Interpreter1//!2//! The interpreter uses virtual memory addresses for its memory operations. These addresses3//! are obtained by the various `_addr` instructions (e.g. `stack_addr`) and can be either 32 or 644//! bits.5//!6//! Addresses are composed of 3 fields: "region", "entry" and offset.7//!8//! "region" refers to the type of memory that this address points to.9//! "entry" refers to which instance of this memory the address points to (e.g table1 would be10//! "entry" 1 of a `Table` region address).11//! The last field is the "offset", which refers to the offset within the entry.12//!13//! The address has the "region" field as the 2 most significant bits. The following bits14//! are the "entry" field, the amount of "entry" bits depends on the size of the address and15//! the "region" of the address. The remaining bits belong to the "offset" field16//!17//! An example address could be a 32 bit address, in the `function` region, which has 1 "entry" bit18//! this address would have 32 - 1 - 2 = 29 offset bits.19//!20//! The only exception to this is the "stack" region, where, because we only have a single "stack"21//! we have 0 "entry" bits, and thus is all offset.22//!23//! | address size | address kind | region value (2 bits) | entry bits (#) | offset bits (#) |24//! |--------------|--------------|-----------------------|----------------|-----------------|25//! | 32 | Stack | 0b00 | 0 | 30 |26//! | 32 | Function | 0b01 | 1 | 29 |27//! | 32 | Table | 0b10 | 5 | 25 |28//! | 32 | GlobalValue | 0b11 | 6 | 24 |29//! | 64 | Stack | 0b00 | 0 | 62 |30//! | 64 | Function | 0b01 | 1 | 61 |31//! | 64 | Table | 0b10 | 10 | 52 |32//! | 64 | GlobalValue | 0b11 | 12 | 50 |3334use crate::state::MemoryError;35use cranelift_codegen::data_value::DataValue;36use cranelift_codegen::ir::{Type, types};3738#[derive(Debug, Copy, Clone, PartialEq)]39pub enum AddressSize {40_32,41_64,42}4344impl AddressSize {45pub fn bits(&self) -> u64 {46match self {47AddressSize::_64 => 64,48AddressSize::_32 => 32,49}50}51}5253impl TryFrom<Type> for AddressSize {54type Error = MemoryError;5556fn try_from(ty: Type) -> Result<Self, Self::Error> {57match ty {58types::I64 => Ok(AddressSize::_64),59types::I32 => Ok(AddressSize::_32),60_ => Err(MemoryError::InvalidAddressType(ty)),61}62}63}6465/// Virtual Address region66#[derive(Debug, Copy, Clone, PartialEq)]67pub enum AddressRegion {68Stack,69Function,70Table,71GlobalValue,72}7374impl AddressRegion {75pub fn decode(bits: u64) -> Self {76assert!(bits < 4);77match bits {780 => AddressRegion::Stack,791 => AddressRegion::Function,802 => AddressRegion::Table,813 => AddressRegion::GlobalValue,82_ => unreachable!(),83}84}8586pub fn encode(self) -> u64 {87match self {88AddressRegion::Stack => 0,89AddressRegion::Function => 1,90AddressRegion::Table => 2,91AddressRegion::GlobalValue => 3,92}93}94}9596#[derive(Debug, Clone, PartialEq)]97pub struct Address {98pub size: AddressSize,99pub region: AddressRegion,100pub entry: u64,101pub offset: u64,102}103104impl Address {105pub fn from_parts(106size: AddressSize,107region: AddressRegion,108entry: u64,109offset: u64,110) -> Result<Self, MemoryError> {111let entry_bits = Address::entry_bits(size, region);112let offset_bits = Address::offset_bits(size, region);113114let max_entries = (1 << entry_bits) - 1;115let max_offset = (1 << offset_bits) - 1;116117if entry > max_entries {118return Err(MemoryError::InvalidEntry {119entry,120max: max_entries,121});122}123124if offset > max_offset {125return Err(MemoryError::InvalidOffset {126offset,127max: max_offset,128});129}130131Ok(Address {132size,133region,134entry,135offset,136})137}138139fn entry_bits(size: AddressSize, region: AddressRegion) -> u64 {140match (size, region) {141// We only have one stack, so the whole address is offset142(_, AddressRegion::Stack) => 0,143144// We have two function "entries", one for libcalls, and145// another for user functions.146(_, AddressRegion::Function) => 1,147148(AddressSize::_32, AddressRegion::Table) => 5,149(AddressSize::_32, AddressRegion::GlobalValue) => 6,150151(AddressSize::_64, AddressRegion::Table) => 10,152(AddressSize::_64, AddressRegion::GlobalValue) => 12,153}154}155156fn offset_bits(size: AddressSize, region: AddressRegion) -> u64 {157let region_bits = 2;158let entry_bits = Address::entry_bits(size, region);159size.bits() - entry_bits - region_bits160}161}162163impl TryFrom<Address> for DataValue {164type Error = MemoryError;165166fn try_from(addr: Address) -> Result<Self, Self::Error> {167let entry_bits = Address::entry_bits(addr.size, addr.region);168let offset_bits = Address::offset_bits(addr.size, addr.region);169170let entry = addr.entry << offset_bits;171let region = addr.region.encode() << (entry_bits + offset_bits);172173let value = region | entry | addr.offset;174Ok(match addr.size {175AddressSize::_32 => DataValue::I32(value as u32 as i32),176AddressSize::_64 => DataValue::I64(value as i64),177})178}179}180181impl TryFrom<DataValue> for Address {182type Error = MemoryError;183184fn try_from(value: DataValue) -> Result<Self, Self::Error> {185let addr = match value {186DataValue::I32(v) => v as u32 as u64,187DataValue::I64(v) => v as u64,188_ => {189return Err(MemoryError::InvalidAddress(value));190}191};192193let size = match value {194DataValue::I32(_) => AddressSize::_32,195DataValue::I64(_) => AddressSize::_64,196_ => unreachable!(),197};198199let region = AddressRegion::decode(addr >> (size.bits() - 2));200201let entry_bits = Address::entry_bits(size, region);202let offset_bits = Address::offset_bits(size, region);203204let entry = (addr >> offset_bits) & ((1 << entry_bits) - 1);205let offset = addr & ((1 << offset_bits) - 1);206207Address::from_parts(size, region, entry, offset)208}209}210211impl TryFrom<u64> for Address {212type Error = MemoryError;213214fn try_from(value: u64) -> Result<Self, Self::Error> {215let dv = if value > u32::MAX as u64 {216DataValue::I64(value as i64)217} else {218DataValue::I32(value as i32)219};220221Address::try_from(dv)222}223}224225#[derive(Debug, Clone, PartialEq)]226pub enum AddressFunctionEntry {227UserFunction = 0,228LibCall,229}230231impl From<u64> for AddressFunctionEntry {232fn from(bits: u64) -> Self {233match bits {2340 => AddressFunctionEntry::UserFunction,2351 => AddressFunctionEntry::LibCall,236_ => unreachable!(),237}238}239}240241#[cfg(test)]242mod tests {243use super::*;244245#[test]246fn address_region_roundtrip_encode_decode() {247let all_regions = [248AddressRegion::Stack,249AddressRegion::Function,250AddressRegion::Table,251AddressRegion::GlobalValue,252];253254for region in all_regions {255assert_eq!(AddressRegion::decode(region.encode()), region);256}257}258259#[test]260fn address_roundtrip() {261let test_addresses = [262(AddressSize::_32, AddressRegion::Stack, 0, 0),263(AddressSize::_32, AddressRegion::Stack, 0, 1),264(AddressSize::_32, AddressRegion::Stack, 0, 1024),265(AddressSize::_32, AddressRegion::Stack, 0, 0x3FFF_FFFF),266(AddressSize::_32, AddressRegion::Function, 0, 0),267(AddressSize::_32, AddressRegion::Function, 1, 1),268(AddressSize::_32, AddressRegion::Function, 0, 1024),269(AddressSize::_32, AddressRegion::Function, 1, 0x0FFF_FFFF),270(AddressSize::_32, AddressRegion::Table, 0, 0),271(AddressSize::_32, AddressRegion::Table, 1, 1),272(AddressSize::_32, AddressRegion::Table, 31, 0x1FF_FFFF),273(AddressSize::_32, AddressRegion::GlobalValue, 0, 0),274(AddressSize::_32, AddressRegion::GlobalValue, 1, 1),275(AddressSize::_32, AddressRegion::GlobalValue, 63, 0xFF_FFFF),276(AddressSize::_64, AddressRegion::Stack, 0, 0),277(AddressSize::_64, AddressRegion::Stack, 0, 1),278(279AddressSize::_64,280AddressRegion::Stack,2810,2820x3FFFFFFF_FFFFFFFF,283),284(AddressSize::_64, AddressRegion::Function, 0, 0),285(AddressSize::_64, AddressRegion::Function, 1, 1),286(AddressSize::_64, AddressRegion::Function, 0, 1024),287(AddressSize::_64, AddressRegion::Function, 1, 0x0FFF_FFFF),288(AddressSize::_64, AddressRegion::Table, 0, 0),289(AddressSize::_64, AddressRegion::Table, 1, 1),290(AddressSize::_64, AddressRegion::Table, 31, 0x1FF_FFFF),291(AddressSize::_64, AddressRegion::GlobalValue, 0, 0),292(AddressSize::_64, AddressRegion::GlobalValue, 1, 1),293(AddressSize::_64, AddressRegion::GlobalValue, 63, 0xFF_FFFF),294];295296for (size, region, entry, offset) in test_addresses {297let original = Address {298size,299region,300entry,301offset,302};303304let dv: DataValue = original.clone().try_into().unwrap();305let addr = dv.try_into().unwrap();306307assert_eq!(original, addr);308}309}310}311312313