Fix incorrect offset calculation in label jumps/branches

This commit is contained in:
2026-05-08 16:19:59 +03:00
parent 0b242e5384
commit 55e38af0ed
4 changed files with 88 additions and 11 deletions
+24
View File
@@ -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
View File
@@ -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));
}
}
-1
View File
@@ -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
View File
@@ -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 {