1
0

Fix register-setting bug

This commit is contained in:
Jeff 2025-01-01 21:53:54 -05:00
parent 10c66b3f95
commit 56becbfacb
9 changed files with 104 additions and 56 deletions

View File

@ -1,18 +1,19 @@
use std::io::{self, stdout, Read}; use std::{
use std::time::{Duration, Instant}; fs::read_to_string,
use std::{fs::read_to_string, path::PathBuf}; io::{self, stdout, Read},
path::PathBuf,
use clap::builder::StyledStr; time::{Duration, Instant},
use clap::error::ErrorKind; };
use clap::{
builder::{styling::AnsiColor, Styles}, use clap::{
crate_authors, crate_description, crate_version, ColorChoice, Parser, Subcommand, ValueHint, builder::{styling::AnsiColor, StyledStr, Styles},
crate_authors, crate_description, crate_version,
error::ErrorKind,
Args, ColorChoice, Error, Parser, Subcommand, ValueHint,
}; };
use clap::{Args, Error};
use color_print::cstr; use color_print::cstr;
use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm}; use dust_lang::{CompileError, Compiler, DustError, DustString, Lexer, Span, Token, Vm};
use tracing::subscriber::set_global_default; use tracing::{subscriber::set_global_default, Level};
use tracing::Level;
use tracing_subscriber::FmtSubscriber; use tracing_subscriber::FmtSubscriber;
const CLI_HELP_TEMPLATE: &str = cstr!( const CLI_HELP_TEMPLATE: &str = cstr!(
@ -214,6 +215,7 @@ fn main() {
let subscriber = FmtSubscriber::builder() let subscriber = FmtSubscriber::builder()
.with_max_level(log_level) .with_max_level(log_level)
.with_thread_names(true) .with_thread_names(true)
.with_file(false)
.finish(); .finish();
set_global_default(subscriber).expect("Failed to set tracing subscriber"); set_global_default(subscriber).expect("Failed to set tracing subscriber");

View File

@ -197,7 +197,7 @@ impl<'src> Compiler<'src> {
/// [`CompileError`] if any are found. After calling this function, check its return value for /// [`CompileError`] if any are found. After calling this function, check its return value for
/// an error, then call [`Compiler::finish`] to get the compiled chunk. /// an error, then call [`Compiler::finish`] to get the compiled chunk.
pub fn compile(&mut self) -> Result<(), CompileError> { pub fn compile(&mut self) -> Result<(), CompileError> {
let span = span!(Level::INFO, "Compiling"); let span = span!(Level::INFO, "Compile");
let _enter = span.enter(); let _enter = span.enter();
info!( info!(

View File

@ -1,10 +1,25 @@
use crate::{Instruction, Operation}; use crate::{Instruction, Operation};
use super::InstructionData;
pub struct GetLocal { pub struct GetLocal {
pub destination: u8, pub destination: u8,
pub local_index: u8, pub local_index: u8,
} }
impl From<InstructionData> for GetLocal {
fn from(data: InstructionData) -> Self {
let InstructionData {
a_field, b_field, ..
} = data;
GetLocal {
destination: a_field,
local_index: b_field,
}
}
}
impl From<&Instruction> for GetLocal { impl From<&Instruction> for GetLocal {
fn from(instruction: &Instruction) -> Self { fn from(instruction: &Instruction) -> Self {
let destination = instruction.a_field(); let destination = instruction.a_field();

View File

@ -26,6 +26,10 @@ impl CallStack {
self.calls.is_empty() self.calls.is_empty()
} }
pub fn len(&self) -> usize {
self.calls.len()
}
pub fn push(&mut self, call: FunctionCall) { pub fn push(&mut self, call: FunctionCall) {
self.calls.push(call); self.calls.push(call);
} }

View File

@ -41,7 +41,7 @@ impl Vm {
} }
pub fn run(mut self) -> Option<Value> { pub fn run(mut self) -> Option<Value> {
let span = span!(Level::INFO, "Running"); let span = span!(Level::INFO, "Run");
let _enter = span.enter(); let _enter = span.enter();
if self.threads.len() == 1 { if self.threads.len() == 1 {

View File

@ -7,6 +7,7 @@ use crate::{DustString, Function, FunctionType, Local, Span, Value};
use super::{run_action::RunAction, Pointer, Register}; use super::{run_action::RunAction, Pointer, Register};
#[derive(Debug)]
pub struct Record { pub struct Record {
pub ip: usize, pub ip: usize,
pub actions: SmallVec<[RunAction; 32]>, pub actions: SmallVec<[RunAction; 32]>,
@ -113,6 +114,12 @@ impl Record {
self.stack[to_register] = register; self.stack[to_register] = register;
} }
pub fn reserve_registers(&mut self, count: usize) {
for _ in 0..count {
self.stack.push(Register::Empty);
}
}
pub fn open_register(&self, register_index: u8) -> &Value { pub fn open_register(&self, register_index: u8) -> &Value {
trace!("Open register R{register_index}"); trace!("Open register R{register_index}");
@ -151,7 +158,7 @@ impl Record {
} }
} }
pub fn replace_register_or_clone_constant( pub fn empty_register_or_clone_constant(
&mut self, &mut self,
register_index: u8, register_index: u8,
new_register: Register, new_register: Register,
@ -175,6 +182,24 @@ impl Record {
} }
} }
pub fn clone_register_value_or_constant(&self, register_index: u8) -> Value {
assert!(
(register_index as usize) < self.stack.len(),
"VM Error: Register index out of bounds"
);
let register = &self.stack[register_index as usize];
match register {
Register::Value(value) => value.clone(),
Register::Pointer(pointer) => match pointer {
Pointer::Stack(register_index) => self.open_register(*register_index).clone(),
Pointer::Constant(constant_index) => self.get_constant(*constant_index).clone(),
},
Register::Empty => panic!("VM Error: Register {register_index} is empty"),
}
}
/// DRY helper to get a value from an Argument /// DRY helper to get a value from an Argument
pub fn get_argument(&self, index: u8, is_constant: bool) -> &Value { pub fn get_argument(&self, index: u8, is_constant: bool) -> &Value {
if is_constant { if is_constant {

View File

@ -2,7 +2,8 @@ use tracing::trace;
use crate::{ use crate::{
instruction::{ instruction::{
Call, CallNative, Close, LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Point, Call, CallNative, Close, GetLocal, LoadBoolean, LoadConstant, LoadFunction, LoadList,
LoadSelf, Point,
}, },
vm::VmError, vm::VmError,
AbstractList, ConcreteValue, Instruction, InstructionData, Type, Value, AbstractList, ConcreteValue, Instruction, InstructionData, Type, Value,
@ -194,15 +195,14 @@ pub fn load_self(instruction_data: InstructionData, record: &mut Record) -> Thre
} }
pub fn get_local(instruction_data: InstructionData, record: &mut Record) -> ThreadSignal { pub fn get_local(instruction_data: InstructionData, record: &mut Record) -> ThreadSignal {
let InstructionData { let GetLocal {
a_field: a, destination,
b_field: b, local_index,
.. } = instruction_data.into();
} = instruction_data; let local_register_index = record.get_local_register(local_index);
let local_register_index = record.get_local_register(b);
let register = Register::Pointer(Pointer::Stack(local_register_index)); let register = Register::Pointer(Pointer::Stack(local_register_index));
record.set_register(a, register); record.set_register(destination, register);
ThreadSignal::Continue ThreadSignal::Continue
} }

View File

@ -1,4 +1,4 @@
use tracing::{info, trace}; use tracing::{info, span, trace, Level};
use crate::{ use crate::{
vm::{FunctionCall, Register}, vm::{FunctionCall, Register},
@ -26,6 +26,12 @@ impl Thread {
} }
pub fn run(&mut self) -> Option<Value> { pub fn run(&mut self) -> Option<Value> {
let mut current_call = FunctionCall {
name: None,
record_index: 0,
return_register: 0,
ip: 0,
};
let mut active = &mut self.records[0]; let mut active = &mut self.records[0];
info!( info!(
@ -59,6 +65,8 @@ impl Thread {
let action = active.actions[active.ip]; let action = active.actions[active.ip];
let signal = (action.logic)(action.data, active); let signal = (action.logic)(action.data, active);
trace!("Thread Signal: {:?}", signal);
active.ip += 1; active.ip += 1;
match signal { match signal {
@ -73,8 +81,7 @@ impl Thread {
let mut arguments = Vec::with_capacity(argument_count as usize); let mut arguments = Vec::with_capacity(argument_count as usize);
for register_index in first_argument_register..return_register { for register_index in first_argument_register..return_register {
let value = active let value = active.clone_register_value_or_constant(register_index);
.replace_register_or_clone_constant(register_index, Register::Empty);
arguments.push(value); arguments.push(value);
} }
@ -89,20 +96,21 @@ impl Thread {
active.ip = 0; active.ip = 0;
} }
self.call_stack.push(current_call);
active.reserve_registers(arguments.len());
current_call = FunctionCall {
name: active.name().cloned(),
record_index: active.index(),
return_register,
ip: active.ip,
};
active = &mut self.records[record_index]; active = &mut self.records[record_index];
for (index, argument) in arguments.into_iter().enumerate() { for (index, argument) in arguments.into_iter().enumerate() {
active.set_register(index as u8, Register::Value(argument)); active.set_register(index as u8, Register::Value(argument));
} }
let function_call = FunctionCall {
name: active.name().cloned(),
record_index: active.index(),
return_register,
ip: 0,
};
self.call_stack.push(function_call);
} }
ThreadSignal::LoadFunction { ThreadSignal::LoadFunction {
from_record_index, from_record_index,
@ -121,47 +129,41 @@ impl Thread {
active.set_register(to_register_index, register); active.set_register(to_register_index, register);
} }
ThreadSignal::Return(should_return_value) => { ThreadSignal::Return(should_return_value) => {
let returning_call = match self.call_stack.pop() { trace!("{:#?}", self.call_stack);
Some(function_call) => function_call,
None => { if self.call_stack.is_empty() {
if should_return_value { return None;
return active.last_assigned_register().map(|register| { }
active.replace_register_or_clone_constant(
register, let outer_call = self.call_stack.pop().unwrap();
Register::Empty, let record_index = outer_call.record_index as usize;
)
});
} else {
return None;
}
}
};
let outer_call = self.call_stack.last();
let record_index = outer_call.map_or(0, |call| call.record_index as usize);
if should_return_value { if should_return_value {
let return_register = active let return_register = active
.last_assigned_register() .last_assigned_register()
.unwrap_or_else(|| panic!("Expected return value")); .unwrap_or_else(|| panic!("Expected return value"));
let return_value = active let return_value = active
.replace_register_or_clone_constant(return_register, Register::Empty); .empty_register_or_clone_constant(return_register, Register::Empty);
active = &mut self.records[record_index]; active = &mut self.records[record_index];
active.reserve_registers((current_call.return_register + 1) as usize);
active.set_register( active.set_register(
returning_call.return_register, current_call.return_register,
Register::Value(return_value), Register::Value(return_value),
); );
} else { } else {
active = &mut self.records[record_index]; active = &mut self.records[record_index];
active.ip = record_index;
} }
current_call = outer_call;
} }
} }
} }
} }
} }
#[derive(Debug)]
pub enum ThreadSignal { pub enum ThreadSignal {
Continue, Continue,
Call { Call {

View File

@ -5,4 +5,4 @@ fn fib (n: int) -> int {
fib(n - 1) + fib(n - 2) fib(n - 1) + fib(n - 2)
} }
write_line(fib(0)) write_line(fib(2))