Add more optimizations to the VM
This commit is contained in:
parent
ab551fb883
commit
193653ff22
@ -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::*;
|
||||||
|
|
||||||
|
@ -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)) => {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user