Various cranelift interpreter improvements (#6176)

* Remove the validate_address State trait method

It isn't used anywhere

* Expose the inner Function of a Frame

This is necessary to create your own interpreter that reuses most of
cranelift-interpreter. For example to use a different State
implementation.

* Support the symbol_value and tls_value instructions in the interpreter
This commit is contained in:
bjorn3
2023-04-07 17:22:13 +02:00
committed by GitHub
parent e1777710b1
commit bada17beab
4 changed files with 16 additions and 38 deletions

View File

@@ -12,7 +12,7 @@ pub(crate) type Entries = Vec<Option<DataValue>>;
#[derive(Debug)] #[derive(Debug)]
pub struct Frame<'a> { pub struct Frame<'a> {
/// The currently executing function. /// The currently executing function.
pub(crate) function: &'a Function, function: &'a Function,
/// The current mapping of SSA value-references to their actual values. For efficiency, each SSA value is used as an /// The current mapping of SSA value-references to their actual values. For efficiency, each SSA value is used as an
/// index into the Vec, meaning some slots may be unused. /// index into the Vec, meaning some slots may be unused.
registers: Entries, registers: Entries,
@@ -100,6 +100,11 @@ impl<'a> Frame<'a> {
pub fn entries_mut(&mut self) -> &mut [Option<DataValue>] { pub fn entries_mut(&mut self) -> &mut [Option<DataValue>] {
&mut self.registers &mut self.registers
} }
/// Accessor for the [`Function`] of this frame.
pub fn function(&self) -> &'a Function {
self.function
}
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -93,7 +93,7 @@ impl<'a> Interpreter<'a> {
/// instructions, which may continue in other blocks, until the function returns. /// instructions, which may continue in other blocks, until the function returns.
fn block(&mut self, block: Block) -> Result<ControlFlow<'a, DataValue>, InterpreterError> { fn block(&mut self, block: Block) -> Result<ControlFlow<'a, DataValue>, InterpreterError> {
trace!("Block: {}", block); trace!("Block: {}", block);
let function = self.state.current_frame_mut().function; let function = self.state.current_frame_mut().function();
let layout = &function.layout; let layout = &function.layout;
let mut maybe_inst = layout.first_inst(block); let mut maybe_inst = layout.first_inst(block);
while let Some(inst) = maybe_inst { while let Some(inst) = maybe_inst {
@@ -257,10 +257,10 @@ impl<'a> InterpreterState<'a> {
impl<'a> State<'a, DataValue> for InterpreterState<'a> { impl<'a> State<'a, DataValue> for InterpreterState<'a> {
fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function> { fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function> {
self.functions self.functions
.get_from_func_ref(func_ref, self.frame_stack.last().unwrap().function) .get_from_func_ref(func_ref, self.frame_stack.last().unwrap().function())
} }
fn get_current_function(&self) -> &'a Function { fn get_current_function(&self) -> &'a Function {
self.current_frame().function self.current_frame().function()
} }
fn get_libcall_handler(&self) -> LibCallHandler<DataValue> { fn get_libcall_handler(&self) -> LibCallHandler<DataValue> {
@@ -269,7 +269,7 @@ impl<'a> State<'a, DataValue> for InterpreterState<'a> {
fn push_frame(&mut self, function: &'a Function) { fn push_frame(&mut self, function: &'a Function) {
if let Some(frame) = self.frame_stack.iter().last() { if let Some(frame) = self.frame_stack.iter().last() {
self.frame_offset += frame.function.fixed_stack_size() as usize; self.frame_offset += frame.function().fixed_stack_size() as usize;
} }
// Grow the stack by the space necessary for this frame // Grow the stack by the space necessary for this frame
@@ -282,11 +282,11 @@ impl<'a> State<'a, DataValue> for InterpreterState<'a> {
if let Some(frame) = self.frame_stack.pop() { if let Some(frame) = self.frame_stack.pop() {
// Shorten the stack after exiting the frame // Shorten the stack after exiting the frame
self.stack self.stack
.truncate(self.stack.len() - frame.function.fixed_stack_size() as usize); .truncate(self.stack.len() - frame.function().fixed_stack_size() as usize);
// Reset frame_offset to the start of this function // Reset frame_offset to the start of this function
if let Some(frame) = self.frame_stack.iter().last() { if let Some(frame) = self.frame_stack.iter().last() {
self.frame_offset -= frame.function.fixed_stack_size() as usize; self.frame_offset -= frame.function().fixed_stack_size() as usize;
} }
} }
} }
@@ -550,24 +550,6 @@ impl<'a> State<'a, DataValue> for InterpreterState<'a> {
} }
} }
fn validate_address(&self, addr: &Address) -> Result<(), MemoryError> {
match addr.region {
AddressRegion::Stack => {
let stack_len = self.stack.len() as u64;
if addr.offset > stack_len {
return Err(MemoryError::InvalidEntry {
entry: addr.entry,
max: self.stack.len() as u64,
});
}
}
_ => unimplemented!(),
};
Ok(())
}
fn get_pinned_reg(&self) -> DataValue { fn get_pinned_reg(&self) -> DataValue {
self.pinned_reg.clone() self.pinned_reg.clone()
} }

View File

@@ -92,9 +92,6 @@ pub trait State<'a, V> {
/// in intermediate global values. /// in intermediate global values.
fn resolve_global_value(&self, gv: GlobalValue) -> Result<V, MemoryError>; fn resolve_global_value(&self, gv: GlobalValue) -> Result<V, MemoryError>;
/// Checks if an address is valid and within a known region of memory
fn validate_address(&self, address: &Address) -> Result<(), MemoryError>;
/// Retrieves the current pinned reg value /// Retrieves the current pinned reg value
fn get_pinned_reg(&self) -> V; fn get_pinned_reg(&self) -> V;
/// Sets a value for the pinned reg /// Sets a value for the pinned reg
@@ -231,10 +228,6 @@ where
unimplemented!() unimplemented!()
} }
fn validate_address(&self, _addr: &Address) -> Result<(), MemoryError> {
unimplemented!()
}
fn get_pinned_reg(&self) -> V { fn get_pinned_reg(&self) -> V {
unimplemented!() unimplemented!()
} }

View File

@@ -563,15 +563,13 @@ where
Opcode::DynamicStackAddr => unimplemented!("DynamicStackSlot"), Opcode::DynamicStackAddr => unimplemented!("DynamicStackSlot"),
Opcode::DynamicStackLoad => unimplemented!("DynamicStackLoad"), Opcode::DynamicStackLoad => unimplemented!("DynamicStackLoad"),
Opcode::DynamicStackStore => unimplemented!("DynamicStackStore"), Opcode::DynamicStackStore => unimplemented!("DynamicStackStore"),
Opcode::GlobalValue => { Opcode::GlobalValue | Opcode::SymbolValue | Opcode::TlsValue => {
if let InstructionData::UnaryGlobalValue { global_value, .. } = inst { if let InstructionData::UnaryGlobalValue { global_value, .. } = inst {
assign_or_memtrap(state.resolve_global_value(global_value)) assign_or_memtrap(state.resolve_global_value(global_value))
} else { } else {
unreachable!() unreachable!()
} }
} }
Opcode::SymbolValue => unimplemented!("SymbolValue"),
Opcode::TlsValue => unimplemented!("TlsValue"),
Opcode::GetPinnedReg => assign(state.get_pinned_reg()), Opcode::GetPinnedReg => assign(state.get_pinned_reg()),
Opcode::SetPinnedReg => { Opcode::SetPinnedReg => {
let arg0 = arg(0)?; let arg0 = arg(0)?;