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)]
pub struct Frame<'a> {
/// 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
/// index into the Vec, meaning some slots may be unused.
registers: Entries,
@@ -100,6 +100,11 @@ impl<'a> Frame<'a> {
pub fn entries_mut(&mut self) -> &mut [Option<DataValue>] {
&mut self.registers
}
/// Accessor for the [`Function`] of this frame.
pub fn function(&self) -> &'a Function {
self.function
}
}
#[cfg(test)]

View File

@@ -93,7 +93,7 @@ impl<'a> Interpreter<'a> {
/// instructions, which may continue in other blocks, until the function returns.
fn block(&mut self, block: Block) -> Result<ControlFlow<'a, DataValue>, InterpreterError> {
trace!("Block: {}", block);
let function = self.state.current_frame_mut().function;
let function = self.state.current_frame_mut().function();
let layout = &function.layout;
let mut maybe_inst = layout.first_inst(block);
while let Some(inst) = maybe_inst {
@@ -257,10 +257,10 @@ impl<'a> InterpreterState<'a> {
impl<'a> State<'a, DataValue> for InterpreterState<'a> {
fn get_function(&self, func_ref: FuncRef) -> Option<&'a Function> {
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 {
self.current_frame().function
self.current_frame().function()
}
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) {
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
@@ -282,11 +282,11 @@ impl<'a> State<'a, DataValue> for InterpreterState<'a> {
if let Some(frame) = self.frame_stack.pop() {
// Shorten the stack after exiting the frame
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
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 {
self.pinned_reg.clone()
}
@@ -1054,18 +1036,18 @@ mod tests {
ss0 = explicit_slot 69
ss1 = explicit_slot 69
ss2 = explicit_slot 69
block0:
v0 = f32const -0x1.434342p-60
v1 = stack_addr.i64 ss2+24
store notrap aligned v0, v1
return v0
}
function %u1() -> f32 system_v {
sig0 = () -> f32 system_v
fn0 = colocated %u2 sig0
block0:
v57 = call fn0()
return v57

View File

@@ -92,9 +92,6 @@ pub trait State<'a, V> {
/// in intermediate global values.
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
fn get_pinned_reg(&self) -> V;
/// Sets a value for the pinned reg
@@ -231,10 +228,6 @@ where
unimplemented!()
}
fn validate_address(&self, _addr: &Address) -> Result<(), MemoryError> {
unimplemented!()
}
fn get_pinned_reg(&self) -> V {
unimplemented!()
}

View File

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