cranelift_interpreter/
state.rs

1//! Cranelift instructions modify the state of the machine; the [State] trait describes these
2//! ways this can happen.
3use crate::address::{Address, AddressSize};
4use crate::frame::Frame;
5use crate::interpreter::LibCallHandler;
6use cranelift_codegen::data_value::DataValue;
7use cranelift_codegen::ir::{
8    types, ExternalName, FuncRef, Function, GlobalValue, LibCall, MemFlags, Signature, StackSlot,
9    Type, Value,
10};
11use cranelift_codegen::isa::CallConv;
12use smallvec::SmallVec;
13use thiserror::Error;
14
15/// This trait manages the state necessary to interpret a single Cranelift instruction--it describes
16/// all of the ways a Cranelift interpreter can interact with its virtual state. This makes it
17/// possible to use the [Interpreter](crate::interpreter::Interpreter) in a range of situations:
18/// - when interpretation needs to happen in a way isolated from the host a state which keeps a
19///   stack and bound checks memory accesses can be used, like
20///   [InterpreterState](crate::interpreter::InterpreterState).
21/// - when interpretation needs to have access to the host a state which allows direct access to the
22///   host memory and native functions can be used.
23pub trait State<'a> {
24    /// Retrieve a reference to a [Function].
25    fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function>;
26    /// Retrieve a reference to the currently executing [Function].
27    fn get_current_function(&self) -> &'a Function;
28    /// Retrieve the handler callback for a [LibCall]
29    fn get_libcall_handler(&self) -> LibCallHandler;
30
31    /// Record that an interpreter has called into a new [Function].
32    fn push_frame(&mut self, function: &'a Function);
33    /// Record that an interpreter has returned from a called [Function].
34    fn pop_frame(&mut self);
35
36    fn current_frame_mut(&mut self) -> &mut Frame<'a>;
37    fn current_frame(&self) -> &Frame<'a>;
38
39    /// Collect a list of values `V` by their [value references](cranelift_codegen::ir::Value).
40    fn collect_values(&self, names: &[Value]) -> SmallVec<[DataValue; 1]> {
41        let frame = self.current_frame();
42        names.into_iter().map(|n| frame.get(*n).clone()).collect()
43    }
44
45    /// Computes the stack address for this stack slot, including an offset.
46    fn stack_address(
47        &self,
48        size: AddressSize,
49        slot: StackSlot,
50        offset: u64,
51    ) -> Result<Address, MemoryError>;
52    /// Retrieve a value `V` from memory at the given `address`, checking if it belongs either to the
53    /// stack or to one of the heaps; the number of bytes loaded corresponds to the specified [Type].
54    fn checked_load(
55        &self,
56        address: Address,
57        ty: Type,
58        mem_flags: MemFlags,
59    ) -> Result<DataValue, MemoryError>;
60    /// Store a value `V` into memory at the given `address`, checking if it belongs either to the
61    /// stack or to one of the heaps; the number of bytes stored corresponds to the specified [Type].
62    fn checked_store(
63        &mut self,
64        address: Address,
65        v: DataValue,
66        mem_flags: MemFlags,
67    ) -> Result<(), MemoryError>;
68
69    /// Compute the address of a function given its name.
70    fn function_address(
71        &self,
72        size: AddressSize,
73        name: &ExternalName,
74    ) -> Result<Address, MemoryError>;
75
76    /// Retrieve a reference to a [Function] given its address.
77    fn get_function_from_address(&self, address: Address) -> Option<InterpreterFunctionRef<'a>>;
78
79    /// Given a global value, compute the final value for that global value, applying all operations
80    /// in intermediate global values.
81    fn resolve_global_value(&self, gv: GlobalValue) -> Result<DataValue, MemoryError>;
82
83    /// Retrieves the current pinned reg value
84    fn get_pinned_reg(&self) -> DataValue;
85    /// Sets a value for the pinned reg
86    fn set_pinned_reg(&mut self, v: DataValue);
87}
88
89pub enum InterpreterFunctionRef<'a> {
90    Function(&'a Function),
91    LibCall(LibCall),
92}
93
94impl<'a> InterpreterFunctionRef<'a> {
95    pub fn signature(&self) -> Signature {
96        match self {
97            InterpreterFunctionRef::Function(f) => f.stencil.signature.clone(),
98            // CallConv here is sort of irrelevant, since we don't use it for anything
99            // FIXME handle non-64bit systems
100            InterpreterFunctionRef::LibCall(lc) => lc.signature(CallConv::SystemV, types::I64),
101        }
102    }
103}
104
105impl<'a> From<&'a Function> for InterpreterFunctionRef<'a> {
106    fn from(f: &'a Function) -> Self {
107        InterpreterFunctionRef::Function(f)
108    }
109}
110
111impl From<LibCall> for InterpreterFunctionRef<'_> {
112    fn from(lc: LibCall) -> Self {
113        InterpreterFunctionRef::LibCall(lc)
114    }
115}
116
117#[derive(Error, Debug)]
118pub enum MemoryError {
119    #[error("Invalid DataValue passed as an address: {0}")]
120    InvalidAddress(DataValue),
121    #[error("Invalid type for address: {0}")]
122    InvalidAddressType(Type),
123    #[error("Requested an the entry {entry} but only {max} entries are allowed")]
124    InvalidEntry { entry: u64, max: u64 },
125    #[error("Requested an offset of {offset} but max was {max}")]
126    InvalidOffset { offset: u64, max: u64 },
127    #[error("Load of {load_size} bytes is larger than available size at address {addr:?}")]
128    OutOfBoundsLoad {
129        addr: Address,
130        load_size: usize,
131        mem_flags: MemFlags,
132    },
133    #[error("Store of {store_size} bytes is larger than available size at address {addr:?}")]
134    OutOfBoundsStore {
135        addr: Address,
136        store_size: usize,
137        mem_flags: MemFlags,
138    },
139    #[error("Load of {load_size} bytes is misaligned at address {addr:?}")]
140    MisalignedLoad { addr: Address, load_size: usize },
141    #[error("Store of {store_size} bytes is misaligned at address {addr:?}")]
142    MisalignedStore { addr: Address, store_size: usize },
143}