Fix incorrect offset calculation in label jumps/branches
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
;; vi:ft=lisp:sw=2:ts=2
|
||||
|
||||
(defun factorial (x)
|
||||
(if (= x 0)
|
||||
1
|
||||
(* (factorial (- x 1)) x)
|
||||
)
|
||||
)
|
||||
|
||||
(print 1 "\t" (factorial 1))
|
||||
(print 2 "\t" (factorial 2))
|
||||
(print 3 "\t" (factorial 3))
|
||||
(print 4 "\t" (factorial 4))
|
||||
(print 5 "\t" (factorial 5))
|
||||
(print 6 "\t" (factorial 6))
|
||||
(print 7 "\t" (factorial 7))
|
||||
(print 8 "\t" (factorial 8))
|
||||
(print 9 "\t" (factorial 9))
|
||||
(print 10 "\t" (factorial 10))
|
||||
(print 11 "\t" (factorial 11))
|
||||
(print 12 "\t" (factorial 12))
|
||||
(print 13 "\t" (factorial 13))
|
||||
(print 14 "\t" (factorial 14))
|
||||
(print 15 "\t" (factorial 15))
|
||||
+11
-3
@@ -138,9 +138,11 @@ impl FunctionBlock {
|
||||
|
||||
pub fn resolve_labels(self) -> CompiledFunction {
|
||||
let mut instructions = vec![];
|
||||
for emitted in self.instructions {
|
||||
// eprintln!("RESOLVE LABELS");
|
||||
for (function_offset, emitted) in self.instructions.into_iter().enumerate() {
|
||||
match emitted {
|
||||
Emitted::Instruction(instruction) => {
|
||||
// eprintln!("{function_offset}: {instruction:?}");
|
||||
instructions.push(instruction);
|
||||
}
|
||||
Emitted::Branch(label) => {
|
||||
@@ -148,7 +150,11 @@ impl FunctionBlock {
|
||||
if address == usize::MAX {
|
||||
todo!()
|
||||
}
|
||||
let offset = U::new(address as u32).unwrap();
|
||||
let diff = address.checked_signed_diff(function_offset).expect("TODO");
|
||||
// eprintln!(
|
||||
// "{function_offset}: branch to label {label} (@ {address}) -> {diff:+}"
|
||||
// );
|
||||
let offset = U::from_signed(diff as i64).expect("TODO");
|
||||
instructions.push(Instruction::Branch(offset));
|
||||
}
|
||||
Emitted::Jump(label) => {
|
||||
@@ -156,7 +162,9 @@ impl FunctionBlock {
|
||||
if address == usize::MAX {
|
||||
todo!()
|
||||
}
|
||||
let offset = U::new(address as u32).unwrap();
|
||||
let diff = address.checked_signed_diff(function_offset).expect("TODO");
|
||||
// eprintln!("{function_offset}: jump to label {label} (@ {address}) -> {diff:+}");
|
||||
let offset = U::from_signed(diff as i64).expect("TODO");
|
||||
instructions.push(Instruction::Jump(offset));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,6 @@ impl Expression {
|
||||
}
|
||||
|
||||
fn parse_inner(value: &Value) -> Rc<Self> {
|
||||
eprintln!("{}: parse_inner({value})", core::panic::Location::caller());
|
||||
match value {
|
||||
Value::Nil => Rc::new(Self::Nil),
|
||||
Value::Boolean(value) => Rc::new(Self::BooleanLiteral(*value)),
|
||||
|
||||
+53
-7
@@ -31,6 +31,7 @@ pub struct Machine {
|
||||
pub ip: Option<InstructionPointer>,
|
||||
value_stack: Stack<Value>,
|
||||
pub call_stack: Stack<CallFrame>,
|
||||
pub trace_instructions: bool,
|
||||
// Top-level locals
|
||||
locals: HashMap<u32, Value>,
|
||||
}
|
||||
@@ -49,6 +50,8 @@ impl Default for Machine {
|
||||
value_stack: Stack::new(1024),
|
||||
call_stack: Stack::new(32),
|
||||
locals: HashMap::new(),
|
||||
|
||||
trace_instructions: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,7 +222,7 @@ impl Machine {
|
||||
self.execute_builtin_native(environment, function, count)
|
||||
}
|
||||
|
||||
fn execute_branch(&mut self, offset: usize) -> Result<bool, MachineError> {
|
||||
fn execute_branch(&mut self, offset: isize) -> Result<bool, MachineError> {
|
||||
let value = self.pop()?;
|
||||
let do_branch = !bool::try_from_value(&value).unwrap_or_default();
|
||||
if do_branch {
|
||||
@@ -228,11 +231,11 @@ impl Machine {
|
||||
Ok(!do_branch)
|
||||
}
|
||||
|
||||
fn execute_jump(&mut self, offset: usize) -> Result<(), MachineError> {
|
||||
fn execute_jump(&mut self, offset: isize) -> Result<(), MachineError> {
|
||||
let ip = self.ip.clone().unwrap();
|
||||
self.ip = Some(InstructionPointer {
|
||||
module: ip.module,
|
||||
address: offset,
|
||||
address: ip.address.wrapping_add_signed(offset),
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
@@ -330,11 +333,54 @@ impl Machine {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn trace_instruction(&self, ip: &InstructionPointer) {
|
||||
let code = ip.module.instruction(ip.address);
|
||||
let Some(code) = code else {
|
||||
eprintln!("{ip}: <undefined>");
|
||||
return;
|
||||
};
|
||||
eprint!("{ip}: {code:08x} ");
|
||||
if let Ok(instruction) = Instruction::try_from(code) {
|
||||
eprint!("{instruction:?}");
|
||||
match instruction {
|
||||
Instruction::PushConstant(index) => {
|
||||
if let Some(constant) = ip.module.constant(index) {
|
||||
eprint!(" [-> {constant}]");
|
||||
} else {
|
||||
eprint!(" [-> <undefined>]");
|
||||
}
|
||||
}
|
||||
Instruction::PushArgument(index) => {
|
||||
if let Some(argument) = self
|
||||
.call_stack
|
||||
.current()
|
||||
.and_then(|frame| frame.arguments.get(usize::from(index)))
|
||||
{
|
||||
eprint!(" [-> {argument}]");
|
||||
} else {
|
||||
eprint!(" [-> <undefined>]")
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
} else {
|
||||
eprint!("<undefined>");
|
||||
}
|
||||
eprintln!();
|
||||
}
|
||||
|
||||
pub fn execute_next(
|
||||
&mut self,
|
||||
environment: &mut Environment,
|
||||
) -> Result<ExecutionEvent, MachineError> {
|
||||
let ip = self.ip.clone().unwrap();
|
||||
let ip = self
|
||||
.ip
|
||||
.clone()
|
||||
.ok_or_else(|| self.error_at_ip(MachineErrorKind::UndefinedInstructionPointer))?;
|
||||
|
||||
if self.trace_instructions {
|
||||
self.trace_instruction(&ip);
|
||||
}
|
||||
let instruction = ip.module.instruction(ip.address).ok_or_else(|| {
|
||||
self.error_at_ip(MachineErrorKind::InstructionOutOfBounds(ip.clone()))
|
||||
})?;
|
||||
@@ -362,7 +408,7 @@ impl Machine {
|
||||
self.pop()?;
|
||||
}
|
||||
Instruction::ExportMacro(index) => {
|
||||
self.execute_export_macro(environment, index.into())?;
|
||||
self.execute_export_macro(environment, index)?;
|
||||
}
|
||||
Instruction::GetGlobal => {
|
||||
self.execute_get_global(environment)?;
|
||||
@@ -388,11 +434,11 @@ impl Machine {
|
||||
self.execute_math(environment, math, count.into())?;
|
||||
}
|
||||
Instruction::Branch(offset) => {
|
||||
advance = self.execute_branch(offset.into())?;
|
||||
advance = self.execute_branch(offset.sign_extend_i64() as isize)?;
|
||||
}
|
||||
Instruction::Jump(offset) => {
|
||||
advance = false;
|
||||
self.execute_jump(offset.into())?;
|
||||
self.execute_jump(offset.sign_extend_i64() as isize)?;
|
||||
}
|
||||
}
|
||||
if advance {
|
||||
|
||||
Reference in New Issue
Block a user