1
0

Add more optimizations to the VM

This commit is contained in:
Jeff 2024-12-04 05:10:53 -05:00
parent ab551fb883
commit 193653ff22
3 changed files with 89 additions and 83 deletions

View File

@ -66,6 +66,7 @@ impl ConcreteValue {
} }
} }
#[inline(always)]
pub fn add(&self, other: &Self) -> Result<ConcreteValue, ValueError> { pub fn add(&self, other: &Self) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*; use ConcreteValue::*;
@ -240,6 +241,7 @@ impl ConcreteValue {
Ok(equal) Ok(equal)
} }
#[inline(always)]
pub fn less_than(&self, other: &ConcreteValue) -> Result<ConcreteValue, ValueError> { pub fn less_than(&self, other: &ConcreteValue) -> Result<ConcreteValue, ValueError> {
use ConcreteValue::*; use ConcreteValue::*;

View File

@ -32,17 +32,11 @@ impl Value {
} }
} }
pub fn display(&self, vm: &Vm) -> Result<String, VmError> { pub fn as_boolean(&self) -> Option<&bool> {
match self { if let Value::Concrete(ConcreteValue::Boolean(value)) = self {
Value::Abstract(abstract_value) => abstract_value.display(vm), Some(value)
Value::Concrete(concrete_value) => Ok(concrete_value.to_string()), } else {
} None
}
pub fn add_assign(&mut self, other: ValueRef) -> Result<(), ValueError> {
match (self, other) {
(Value::Concrete(left), ValueRef::Concrete(right)) => left.add_assign(right),
(left, right) => Err(ValueError::CannotAdd(left.clone(), right.to_owned())),
} }
} }
} }
@ -84,6 +78,7 @@ impl ValueRef<'_> {
} }
} }
#[inline(always)]
pub fn add(&self, other: ValueRef) -> Result<Value, ValueError> { pub fn add(&self, other: ValueRef) -> Result<Value, ValueError> {
match (self, other) { match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => { (ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
@ -158,6 +153,7 @@ impl ValueRef<'_> {
} }
} }
#[inline(always)]
pub fn less_than(&self, other: ValueRef) -> Result<Value, ValueError> { pub fn less_than(&self, other: ValueRef) -> Result<Value, ValueError> {
match (self, other) { match (self, other) {
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => { (ValueRef::Concrete(left), ValueRef::Concrete(right)) => {

View File

@ -57,7 +57,9 @@ impl<'a> Vm<'a> {
} }
pub fn run(&mut self) -> Result<Option<ConcreteValue>, VmError> { pub fn run(&mut self) -> Result<Option<ConcreteValue>, VmError> {
while let Ok(instruction) = self.read() { loop {
let instruction = self.read();
log::info!( log::info!(
"{} | {} | {} | {}", "{} | {} | {} | {}",
self.ip - 1, self.ip - 1,
@ -195,10 +197,11 @@ impl<'a> Vm<'a> {
let register_index = self.get_destination(destination)?; let register_index = self.get_destination(destination)?;
let left = self.get_argument(left)?; let left = self.get_argument(left)?;
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let sum = left.add(right).map_err(|error| VmError::Value { let sum_result = left.add(right);
error,
position: self.current_position, assert!(sum_result.is_ok(), "VM Error: {}", sum_result.unwrap_err());
})?;
let sum = sum_result.unwrap();
self.set_register(register_index, Register::Value(sum))?; self.set_register(register_index, Register::Value(sum))?;
} }
@ -351,21 +354,27 @@ impl<'a> Vm<'a> {
let Less { value, left, right } = Less::from(&instruction); let Less { value, left, right } = Less::from(&instruction);
let left = self.get_argument(left)?; let left = self.get_argument(left)?;
let right = self.get_argument(right)?; let right = self.get_argument(right)?;
let less_result = left.less_than(right).map_err(|error| VmError::Value { let less_result = left.less_than(right);
error,
position: self.current_position,
})?;
let is_less_than =
if let Value::Concrete(ConcreteValue::Boolean(boolean)) = less_result {
boolean
} else {
return Err(VmError::ExpectedBoolean {
found: less_result,
position: self.current_position,
});
};
if is_less_than == value { assert!(
less_result.is_ok(),
"VM Error: {}\nPosition: {}",
less_result.unwrap_err(),
self.current_position
);
let less_than_value = less_result.unwrap();
let less_than_boolean = less_than_value.as_boolean();
assert!(
less_than_boolean.is_some(),
"VM Error: Expected a boolean\nPosition: {}",
self.current_position
);
let is_less_than = less_than_boolean.unwrap();
if is_less_than == &value {
self.jump(1, true); self.jump(1, true);
} }
} }
@ -512,15 +521,13 @@ impl<'a> Vm<'a> {
} }
} }
} }
Ok(None)
} }
pub(crate) fn follow_pointer(&self, pointer: Pointer) -> Result<ValueRef, VmError> { pub(crate) fn follow_pointer(&self, pointer: Pointer) -> Result<ValueRef, VmError> {
match pointer { match pointer {
Pointer::Stack(register_index) => self.open_register(register_index), Pointer::Stack(register_index) => self.open_register(register_index),
Pointer::Constant(constant_index) => { Pointer::Constant(constant_index) => {
let constant = self.get_constant(constant_index)?; let constant = self.get_constant(constant_index);
Ok(ValueRef::Concrete(constant)) Ok(ValueRef::Concrete(constant))
} }
@ -541,7 +548,7 @@ impl<'a> Vm<'a> {
.ok_or_else(|| VmError::ExpectedParent { .ok_or_else(|| VmError::ExpectedParent {
position: self.current_position, position: self.current_position,
})?; })?;
let constant = parent.get_constant(constant_index)?; let constant = parent.get_constant(constant_index);
Ok(ValueRef::Concrete(constant)) Ok(ValueRef::Concrete(constant))
} }
@ -550,13 +557,13 @@ impl<'a> Vm<'a> {
fn open_register(&self, register_index: u16) -> Result<ValueRef, VmError> { fn open_register(&self, register_index: u16) -> Result<ValueRef, VmError> {
let register_index = register_index as usize; let register_index = register_index as usize;
let register =
self.stack assert!(
.get(register_index) register_index < self.stack.len(),
.ok_or_else(|| VmError::RegisterIndexOutOfBounds { "VM Error: Register index out of bounds"
index: register_index, );
position: self.current_position,
})?; let register = &self.stack[register_index];
log::trace!("Open R{register_index} to {register}"); log::trace!("Open R{register_index} to {register}");
@ -615,15 +622,7 @@ impl<'a> Vm<'a> {
fn get_destination(&self, destination: Destination) -> Result<u16, VmError> { fn get_destination(&self, destination: Destination) -> Result<u16, VmError> {
let index = match destination { let index = match destination {
Destination::Register(register_index) => register_index, Destination::Register(register_index) => register_index,
Destination::Local(local_index) => self Destination::Local(local_index) => self.get_local_register(local_index)?,
.local_definitions
.get(local_index as usize)
.copied()
.flatten()
.ok_or_else(|| VmError::UndefinedLocal {
local_index,
position: self.current_position,
})?,
}; };
Ok(index) Ok(index)
@ -633,10 +632,14 @@ impl<'a> Vm<'a> {
fn get_argument(&self, argument: Argument) -> Result<ValueRef, VmError> { fn get_argument(&self, argument: Argument) -> Result<ValueRef, VmError> {
let value_ref = match argument { let value_ref = match argument {
Argument::Constant(constant_index) => { Argument::Constant(constant_index) => {
ValueRef::Concrete(self.get_constant(constant_index)?) ValueRef::Concrete(self.get_constant(constant_index))
} }
Argument::Register(register_index) => self.open_register(register_index)?, Argument::Register(register_index) => self.open_register(register_index)?,
Argument::Local(local_index) => self.get_local(local_index)?, Argument::Local(local_index) => {
let register_index = self.get_local_register(local_index)?;
self.open_register(register_index)?
}
}; };
Ok(value_ref) Ok(value_ref)
@ -648,51 +651,56 @@ impl<'a> Vm<'a> {
let to_register = to_register as usize; let to_register = to_register as usize;
assert!(self.stack.len() > to_register); // Compiler hint to avoid bounds check assert!(
self.stack.len() > to_register,
"VM Error: Register index out of bounds"
);
self.stack[to_register] = register; self.stack[to_register] = register;
Ok(()) Ok(())
} }
fn get_constant(&self, constant_index: u16) -> Result<&ConcreteValue, VmError> { #[inline(always)]
self.chunk fn get_constant(&self, constant_index: u16) -> &ConcreteValue {
.constants() let constant_index = constant_index as usize;
.get(constant_index as usize) let constants = self.chunk.constants();
.ok_or_else(|| VmError::ConstantIndexOutOfBounds {
index: constant_index as usize, assert!(
position: self.current_position, constant_index < constants.len(),
}) "VM Error: Constant index out of bounds"
);
&constants[constant_index]
} }
fn get_local(&self, local_index: u16) -> Result<ValueRef, VmError> { #[inline(always)]
let register_index = self fn get_local_register(&self, local_index: u16) -> Result<u16, VmError> {
.local_definitions let local_index = local_index as usize;
.get(local_index as usize)
.ok_or_else(|| VmError::UndefinedLocal {
local_index,
position: self.current_position,
})?
.ok_or_else(|| VmError::UndefinedLocal {
local_index,
position: self.current_position,
})?;
self.open_register(register_index) assert!(
local_index < self.local_definitions.len(),
"VM Error: Local index out of bounds"
);
self.local_definitions[local_index].ok_or_else(|| VmError::UndefinedLocal {
local_index: local_index as u16,
position: self.current_position,
})
} }
fn read(&mut self) -> Result<Instruction, VmError> { #[inline(always)]
let (instruction, position) = self.chunk.instructions().get(self.ip).ok_or_else(|| { fn read(&mut self) -> Instruction {
VmError::InstructionIndexOutOfBounds { let instructions = self.chunk.instructions();
index: self.ip,
position: self.current_position, assert!(self.ip < instructions.len(), "VM Error: IP out of bounds");
}
})?; let (instruction, position) = instructions[self.ip];
self.ip += 1; self.ip += 1;
self.current_position = *position; self.current_position = position;
Ok(*instruction) instruction
} }
} }