mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-28 14:24:45 +00:00
wasm_interp: remove CallStack, create Frame, & share value storage for stack and locals
This allows us to do calls without moving arguments from one place to another
This commit is contained in:
parent
8b8e385cde
commit
caedb9060b
7 changed files with 487 additions and 570 deletions
181
crates/wasm_interp/src/frame.rs
Normal file
181
crates/wasm_interp/src/frame.rs
Normal file
|
@ -0,0 +1,181 @@
|
|||
use roc_wasm_module::{parse::Parse, Value, ValueType, WasmModule};
|
||||
use std::fmt;
|
||||
use std::iter::repeat;
|
||||
|
||||
use crate::value_stack::ValueStack;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Frame {
|
||||
/// The function this frame belongs to
|
||||
pub fn_index: usize,
|
||||
/// Address in the code section where this frame returns to
|
||||
pub return_addr: usize,
|
||||
/// Number of block scopes when this frame returns
|
||||
pub return_block_depth: usize,
|
||||
/// Offset in the ValueStack where the locals begin
|
||||
pub locals_start: usize,
|
||||
/// Number of locals in the frame
|
||||
pub locals_count: usize,
|
||||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn new() -> Self {
|
||||
Frame {
|
||||
fn_index: 0,
|
||||
return_addr: 0,
|
||||
return_block_depth: 0,
|
||||
locals_start: 0,
|
||||
locals_count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enter(
|
||||
fn_index: usize,
|
||||
return_addr: usize,
|
||||
return_block_depth: usize,
|
||||
arg_type_bytes: &[u8],
|
||||
code_bytes: &[u8],
|
||||
value_stack: &mut ValueStack<'_>,
|
||||
pc: &mut usize,
|
||||
) -> Self {
|
||||
let n_args = arg_type_bytes.len();
|
||||
let locals_start = value_stack.depth() - n_args;
|
||||
|
||||
// Parse local variable declarations in the function header. They're grouped by type.
|
||||
let local_group_count = u32::parse((), code_bytes, pc).unwrap();
|
||||
for _ in 0..local_group_count {
|
||||
let (group_size, ty) = <(u32, ValueType)>::parse((), code_bytes, pc).unwrap();
|
||||
let n = group_size as usize;
|
||||
let zero = match ty {
|
||||
ValueType::I32 => Value::I32(0),
|
||||
ValueType::I64 => Value::I64(0),
|
||||
ValueType::F32 => Value::F32(0.0),
|
||||
ValueType::F64 => Value::F64(0.0),
|
||||
};
|
||||
value_stack.extend(repeat(zero).take(n));
|
||||
}
|
||||
|
||||
let locals_count = value_stack.depth() - locals_start;
|
||||
|
||||
Frame {
|
||||
fn_index,
|
||||
return_addr,
|
||||
return_block_depth,
|
||||
locals_start,
|
||||
locals_count,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_local(&self, values: &ValueStack<'_>, index: u32) -> Value {
|
||||
debug_assert!((index as usize) < self.locals_count);
|
||||
*values.get(self.locals_start + index as usize).unwrap()
|
||||
}
|
||||
|
||||
pub fn set_local(&self, values: &mut ValueStack<'_>, index: u32, value: Value) {
|
||||
debug_assert!((index as usize) < self.locals_count);
|
||||
values.set(self.locals_start + index as usize, value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn write_stack_trace(
|
||||
_current_frame: &Frame,
|
||||
_previous_frames: &[Frame],
|
||||
_module: &WasmModule<'_>,
|
||||
value_stack: &ValueStack<'_>,
|
||||
_pc: usize,
|
||||
_buffer: &mut String,
|
||||
) -> fmt::Result {
|
||||
let _ = value_stack.iter();
|
||||
|
||||
// let divider = "-------------------";
|
||||
// writeln!(buffer, "{}", divider)?;
|
||||
|
||||
// let mut value_stack_iter = value_stack.iter();
|
||||
|
||||
// for frame in 0..self.frame_offsets.len() {
|
||||
// let next_frame = frame + 1;
|
||||
// let op_offset = if next_frame < self.frame_offsets.len() {
|
||||
// // return address of next frame = next op in this frame
|
||||
// let next_op = self.return_addrs_and_block_depths[next_frame].0 as usize;
|
||||
// // Call address is more intuitive than the return address when debugging. Search backward for it.
|
||||
// // Skip last byte of function index to avoid a false match with CALL/CALLINDIRECT.
|
||||
// // The more significant bytes won't match because of LEB-128 encoding.
|
||||
// let mut call_op = next_op - 2;
|
||||
// loop {
|
||||
// let byte = module.code.bytes[call_op];
|
||||
// if byte == OpCode::CALL as u8 || byte == OpCode::CALLINDIRECT as u8 {
|
||||
// break;
|
||||
// } else {
|
||||
// call_op -= 1;
|
||||
// }
|
||||
// }
|
||||
// call_op
|
||||
// } else {
|
||||
// pc
|
||||
// };
|
||||
|
||||
// let fn_index = pc_to_fn_index(op_offset, module);
|
||||
// let address = op_offset + module.code.section_offset as usize;
|
||||
// writeln!(buffer, "function {}", fn_index)?;
|
||||
// writeln!(buffer, " address {:06x}", address)?; // format matches wasm-objdump, for easy search
|
||||
|
||||
// write!(buffer, " args ")?;
|
||||
// let arg_count = {
|
||||
// let n_import_fns = module.import.imports.len();
|
||||
// let signature_index = if fn_index < n_import_fns {
|
||||
// match module.import.imports[fn_index].description {
|
||||
// ImportDesc::Func { signature_index } => signature_index,
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
// } else {
|
||||
// module.function.signatures[fn_index - n_import_fns]
|
||||
// };
|
||||
// module.types.look_up_arg_type_bytes(signature_index).len()
|
||||
// };
|
||||
// let args_and_locals_count = {
|
||||
// let frame_offset = self.frame_offsets[frame] as usize;
|
||||
// let next_frame_offset = if frame == self.frame_offsets.len() - 1 {
|
||||
// self.locals.len()
|
||||
// } else {
|
||||
// self.frame_offsets[frame + 1] as usize
|
||||
// };
|
||||
// next_frame_offset - frame_offset
|
||||
// };
|
||||
// for index in 0..args_and_locals_count {
|
||||
// let value = self.get_local_help(frame, index as u32);
|
||||
// if index != 0 {
|
||||
// write!(buffer, ", ")?;
|
||||
// }
|
||||
// if index == arg_count {
|
||||
// write!(buffer, "\n locals ")?;
|
||||
// }
|
||||
// write!(buffer, "{}: {:?}", index, value)?;
|
||||
// }
|
||||
// write!(buffer, "\n stack [")?;
|
||||
|
||||
// let frame_value_count = {
|
||||
// let value_stack_base = self.value_stack_bases[frame];
|
||||
// let next_value_stack_base = if frame == self.frame_offsets.len() - 1 {
|
||||
// value_stack.depth() as u32
|
||||
// } else {
|
||||
// self.value_stack_bases[frame + 1]
|
||||
// };
|
||||
// next_value_stack_base - value_stack_base
|
||||
// };
|
||||
// for i in 0..frame_value_count {
|
||||
// if i != 0 {
|
||||
// write!(buffer, ", ")?;
|
||||
// }
|
||||
// if let Some(value) = value_stack_iter.next() {
|
||||
// write!(buffer, "{:?}", value)?;
|
||||
// }
|
||||
// }
|
||||
|
||||
// writeln!(buffer, "]")?;
|
||||
// writeln!(buffer, "{}", divider)?;
|
||||
// }
|
||||
|
||||
// Ok(())
|
||||
|
||||
todo!()
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue