Optimize VM
This commit is contained in:
parent
9ae923febd
commit
cd4fa6bef5
@ -199,7 +199,7 @@ fn main() {
|
|||||||
let chunk = compiler.finish(None, None);
|
let chunk = compiler.finish(None, None);
|
||||||
let compile_end = start_time.elapsed();
|
let compile_end = start_time.elapsed();
|
||||||
|
|
||||||
let vm = Vm::new(&source, &chunk, None);
|
let vm = Vm::new(&source, &chunk, None, None);
|
||||||
let return_value = vm.run();
|
let return_value = vm.run();
|
||||||
let run_end = start_time.elapsed();
|
let run_end = start_time.elapsed();
|
||||||
|
|
||||||
|
@ -153,7 +153,6 @@ impl ValueRef<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
pub fn less(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn less(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
|
@ -3,10 +3,10 @@ mod runners;
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{self, Display, Formatter},
|
fmt::{self, Display, Formatter},
|
||||||
io,
|
io, iter,
|
||||||
};
|
};
|
||||||
|
|
||||||
use runners::{Runner, RUNNERS};
|
use runners::Runner;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -16,7 +16,7 @@ use crate::{
|
|||||||
|
|
||||||
pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
|
pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
|
||||||
let chunk = compile(source)?;
|
let chunk = compile(source)?;
|
||||||
let vm = Vm::new(source, &chunk, None);
|
let vm = Vm::new(source, &chunk, None, None);
|
||||||
|
|
||||||
Ok(vm.run())
|
Ok(vm.run())
|
||||||
}
|
}
|
||||||
@ -28,6 +28,7 @@ pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
|
|||||||
pub struct Vm<'a> {
|
pub struct Vm<'a> {
|
||||||
stack: Vec<Register>,
|
stack: Vec<Register>,
|
||||||
|
|
||||||
|
runners: Vec<Runner>,
|
||||||
chunk: &'a Chunk,
|
chunk: &'a Chunk,
|
||||||
parent: Option<&'a Vm<'a>>,
|
parent: Option<&'a Vm<'a>>,
|
||||||
|
|
||||||
@ -38,11 +39,28 @@ pub struct Vm<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Vm<'a> {
|
impl<'a> Vm<'a> {
|
||||||
pub fn new(source: &'a str, chunk: &'a Chunk, parent: Option<&'a Vm<'a>>) -> Self {
|
pub fn new(
|
||||||
|
source: &'a str,
|
||||||
|
chunk: &'a Chunk,
|
||||||
|
parent: Option<&'a Vm<'a>>,
|
||||||
|
runners: Option<Vec<Runner>>,
|
||||||
|
) -> Self {
|
||||||
let stack = vec![Register::Empty; chunk.stack_size()];
|
let stack = vec![Register::Empty; chunk.stack_size()];
|
||||||
|
let runners = runners.unwrap_or_else(|| {
|
||||||
|
let mut runners = Vec::with_capacity(chunk.instructions().len());
|
||||||
|
|
||||||
|
for (instruction, _) in chunk.instructions() {
|
||||||
|
let runner = Runner::new(*instruction);
|
||||||
|
|
||||||
|
runners.push(runner);
|
||||||
|
}
|
||||||
|
|
||||||
|
runners
|
||||||
|
});
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
chunk,
|
chunk,
|
||||||
|
runners,
|
||||||
stack,
|
stack,
|
||||||
parent,
|
parent,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
@ -68,27 +86,13 @@ impl<'a> Vm<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(mut self) -> Option<ConcreteValue> {
|
pub fn run(mut self) -> Option<ConcreteValue> {
|
||||||
let runners = self
|
while self.ip < self.runners.len() && self.return_value.is_none() {
|
||||||
.chunk
|
let runner = self.runners[self.ip];
|
||||||
.instructions()
|
|
||||||
.iter()
|
|
||||||
.map(|(instruction, _)| {
|
|
||||||
let (operation, data) = instruction.decode();
|
|
||||||
let runner = RUNNERS[operation.0 as usize];
|
|
||||||
|
|
||||||
(runner, data)
|
runner.run(&mut self);
|
||||||
})
|
|
||||||
.collect::<Vec<(Runner, InstructionData)>>();
|
|
||||||
|
|
||||||
while self.ip < runners.len() && self.return_value.is_none() {
|
|
||||||
let (runner, data) = runners[self.ip];
|
|
||||||
|
|
||||||
self.ip += 1;
|
|
||||||
|
|
||||||
runner(&mut self, data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.return_value.take()
|
self.return_value
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn follow_pointer(&self, pointer: Pointer) -> ValueRef {
|
pub(crate) fn follow_pointer(&self, pointer: Pointer) -> ValueRef {
|
||||||
@ -179,8 +183,6 @@ impl<'a> Vm<'a> {
|
|||||||
|
|
||||||
let register = &self.stack[register_index];
|
let register = &self.stack[register_index];
|
||||||
|
|
||||||
log::trace!("Open R{register_index} to {register}");
|
|
||||||
|
|
||||||
match register {
|
match register {
|
||||||
Register::Value(value) => Some(value.to_ref()),
|
Register::Value(value) => Some(value.to_ref()),
|
||||||
Register::Pointer(pointer) => Some(self.follow_pointer(*pointer)),
|
Register::Pointer(pointer) => Some(self.follow_pointer(*pointer)),
|
||||||
@ -218,19 +220,18 @@ impl<'a> Vm<'a> {
|
|||||||
fn set_register(&mut self, to_register: u8, register: Register) {
|
fn set_register(&mut self, to_register: u8, register: Register) {
|
||||||
self.last_assigned_register = Some(to_register);
|
self.last_assigned_register = Some(to_register);
|
||||||
let to_register = to_register as usize;
|
let to_register = to_register as usize;
|
||||||
let stack = self.stack.as_mut_slice();
|
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
to_register < stack.len(),
|
to_register < self.stack.len(),
|
||||||
"VM Error: Register index out of bounds"
|
"VM Error: Register index out of bounds"
|
||||||
);
|
);
|
||||||
|
|
||||||
stack[to_register] = register;
|
self.stack[to_register] = register;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_constant(&self, constant_index: u8) -> &ConcreteValue {
|
fn get_constant(&self, constant_index: u8) -> &ConcreteValue {
|
||||||
let constant_index = constant_index as usize;
|
let constant_index = constant_index as usize;
|
||||||
let constants = self.chunk.constants().as_slice();
|
let constants = self.chunk.constants();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
constant_index < constants.len(),
|
constant_index < constants.len(),
|
||||||
@ -242,7 +243,7 @@ impl<'a> Vm<'a> {
|
|||||||
|
|
||||||
fn get_local_register(&self, local_index: u8) -> u8 {
|
fn get_local_register(&self, local_index: u8) -> u8 {
|
||||||
let local_index = local_index as usize;
|
let local_index = local_index as usize;
|
||||||
let locals = self.chunk.locals().as_slice();
|
let locals = self.chunk.locals();
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
local_index < locals.len(),
|
local_index < locals.len(),
|
||||||
@ -419,9 +420,11 @@ impl AnnotatedError for VmError {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use runners::{RunnerLogic, RUNNER_LOGIC_TABLE};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
const ALL_OPERATIONS: [(Operation, Runner); 24] = [
|
const ALL_OPERATIONS: [(Operation, RunnerLogic); 24] = [
|
||||||
(Operation::MOVE, runners::r#move),
|
(Operation::MOVE, runners::r#move),
|
||||||
(Operation::CLOSE, runners::close),
|
(Operation::CLOSE, runners::close),
|
||||||
(Operation::LOAD_BOOLEAN, runners::load_boolean),
|
(Operation::LOAD_BOOLEAN, runners::load_boolean),
|
||||||
@ -451,7 +454,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn operations_map_to_the_correct_runner() {
|
fn operations_map_to_the_correct_runner() {
|
||||||
for (operation, expected_runner) in ALL_OPERATIONS {
|
for (operation, expected_runner) in ALL_OPERATIONS {
|
||||||
let actual_runner = RUNNERS[operation.0 as usize];
|
let actual_runner = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expected_runner, actual_runner,
|
expected_runner, actual_runner,
|
||||||
|
@ -2,11 +2,34 @@ use smallvec::SmallVec;
|
|||||||
|
|
||||||
use crate::{AbstractValue, ConcreteValue, NativeFunction, Value, ValueRef};
|
use crate::{AbstractValue, ConcreteValue, NativeFunction, Value, ValueRef};
|
||||||
|
|
||||||
use super::{InstructionData, Pointer, Register, Vm};
|
use super::{Instruction, InstructionData, Pointer, Register, Vm};
|
||||||
|
|
||||||
pub type Runner = fn(&mut Vm, InstructionData);
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
pub struct Runner {
|
||||||
|
logic: RunnerLogic,
|
||||||
|
data: InstructionData,
|
||||||
|
}
|
||||||
|
|
||||||
pub const RUNNERS: [Runner; 24] = [
|
impl Runner {
|
||||||
|
pub fn new(instruction: Instruction) -> Self {
|
||||||
|
let (operation, data) = instruction.decode();
|
||||||
|
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
||||||
|
|
||||||
|
Self { logic, data }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_parts(logic: RunnerLogic, data: InstructionData) -> Self {
|
||||||
|
Self { logic, data }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(&self, vm: &mut Vm) {
|
||||||
|
(self.logic)(vm, self.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type RunnerLogic = fn(&mut Vm, InstructionData);
|
||||||
|
|
||||||
|
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 24] = [
|
||||||
r#move,
|
r#move,
|
||||||
close,
|
close,
|
||||||
load_boolean,
|
load_boolean,
|
||||||
@ -45,6 +68,12 @@ pub fn r#move<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
if from_register_has_value {
|
if from_register_has_value {
|
||||||
vm.set_register(c, register);
|
vm.set_register(c, register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -61,6 +90,12 @@ pub fn close<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
|
|
||||||
vm.stack[register_index as usize] = Register::Empty;
|
vm.stack[register_index as usize] = Register::Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -72,8 +107,14 @@ pub fn load_boolean<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionDat
|
|||||||
vm.set_register(a, register);
|
vm.set_register(a, register);
|
||||||
|
|
||||||
if c != 0 {
|
if c != 0 {
|
||||||
vm.jump_instructions(1, true);
|
vm.ip += 2;
|
||||||
|
} else {
|
||||||
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -84,8 +125,14 @@ pub fn load_constant<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionDa
|
|||||||
vm.set_register(a, register);
|
vm.set_register(a, register);
|
||||||
|
|
||||||
if c != 0 {
|
if c != 0 {
|
||||||
vm.jump_instructions(1, true);
|
vm.ip += 2;
|
||||||
|
} else {
|
||||||
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -107,7 +154,13 @@ pub fn load_list<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
|
|||||||
let list_value = AbstractValue::List { item_pointers }.to_value();
|
let list_value = AbstractValue::List { item_pointers }.to_value();
|
||||||
let register = Register::Value(list_value);
|
let register = Register::Value(list_value);
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -115,7 +168,13 @@ pub fn load_self<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
|
|||||||
let InstructionData { a, .. } = instruction_data;
|
let InstructionData { a, .. } = instruction_data;
|
||||||
let register = Register::Value(AbstractValue::FunctionSelf.to_value());
|
let register = Register::Value(AbstractValue::FunctionSelf.to_value());
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -124,7 +183,13 @@ pub fn get_local<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
|
|||||||
let local_register_index = vm.get_local_register(b);
|
let local_register_index = vm.get_local_register(b);
|
||||||
let register = Register::Pointer(Pointer::Stack(local_register_index));
|
let register = Register::Pointer(Pointer::Stack(local_register_index));
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -133,7 +198,13 @@ pub fn set_local<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
|
|||||||
let local_register_index = vm.get_local_register(c);
|
let local_register_index = vm.get_local_register(c);
|
||||||
let register = Register::Pointer(Pointer::Stack(b));
|
let register = Register::Pointer(Pointer::Stack(b));
|
||||||
|
|
||||||
vm.set_register(local_register_index, register)
|
vm.set_register(local_register_index, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -159,7 +230,13 @@ pub fn add<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
};
|
};
|
||||||
let register = Register::Value(sum);
|
let register = Register::Value(sum);
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -185,7 +262,13 @@ pub fn subtract<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
};
|
};
|
||||||
let register = Register::Value(difference);
|
let register = Register::Value(difference);
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -211,7 +294,13 @@ pub fn multiply<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
};
|
};
|
||||||
let register = Register::Value(product);
|
let register = Register::Value(product);
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -237,7 +326,13 @@ pub fn divide<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
};
|
};
|
||||||
let register = Register::Value(quotient);
|
let register = Register::Value(quotient);
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -263,7 +358,13 @@ pub fn modulo<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
};
|
};
|
||||||
let register = Register::Value(remainder);
|
let register = Register::Value(remainder);
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -286,8 +387,14 @@ pub fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
let test_value = c != 0;
|
let test_value = c != 0;
|
||||||
|
|
||||||
if boolean == test_value {
|
if boolean == test_value {
|
||||||
vm.jump_instructions(1, true);
|
vm.ip += 2;
|
||||||
|
} else {
|
||||||
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -311,7 +418,7 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
let test_value = c != 0;
|
let test_value = c != 0;
|
||||||
|
|
||||||
if boolean == test_value {
|
if boolean == test_value {
|
||||||
vm.jump_instructions(1, true);
|
vm.ip += 2;
|
||||||
} else {
|
} else {
|
||||||
let pointer = if b_is_constant {
|
let pointer = if b_is_constant {
|
||||||
Pointer::Constant(b)
|
Pointer::Constant(b)
|
||||||
@ -321,7 +428,13 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
let register = Register::Pointer(pointer);
|
let register = Register::Pointer(pointer);
|
||||||
|
|
||||||
vm.set_register(a, register);
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -339,8 +452,14 @@ pub fn equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
let is_equal = left == right;
|
let is_equal = left == right;
|
||||||
|
|
||||||
if is_equal == d {
|
if is_equal == d {
|
||||||
vm.jump_instructions(1, true);
|
vm.ip += 2;
|
||||||
|
} else {
|
||||||
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -358,8 +477,14 @@ pub fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
let is_less = left < right;
|
let is_less = left < right;
|
||||||
|
|
||||||
if is_less == d {
|
if is_less == d {
|
||||||
vm.jump_instructions(1, true);
|
vm.ip += 2;
|
||||||
|
} else {
|
||||||
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -377,8 +502,14 @@ pub fn less_equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData)
|
|||||||
let is_less_or_equal = left <= right;
|
let is_less_or_equal = left <= right;
|
||||||
|
|
||||||
if is_less_or_equal == d {
|
if is_less_or_equal == d {
|
||||||
vm.jump_instructions(1, true);
|
vm.ip += 2;
|
||||||
|
} else {
|
||||||
|
vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -400,7 +531,13 @@ pub fn negate<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
};
|
};
|
||||||
let register = Register::Value(Value::Concrete(negated));
|
let register = Register::Value(Value::Concrete(negated));
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -418,15 +555,30 @@ pub fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
};
|
};
|
||||||
let register = Register::Value(Value::Concrete(not));
|
let register = Register::Value(Value::Concrete(not));
|
||||||
|
|
||||||
vm.set_register(a, register)
|
vm.set_register(a, register);
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
pub fn jump<'c>(vm: &mut Vm<'c>, instruction_data: InstructionData) {
|
pub fn jump<'c>(vm: &mut Vm<'c>, instruction_data: InstructionData) {
|
||||||
let InstructionData { b, c, .. } = instruction_data;
|
let InstructionData { b, c, .. } = instruction_data;
|
||||||
|
let offset = b as usize;
|
||||||
let is_positive = c != 0;
|
let is_positive = c != 0;
|
||||||
|
|
||||||
vm.jump_instructions(b as usize, is_positive);
|
if is_positive {
|
||||||
|
vm.ip += offset + 1
|
||||||
|
} else {
|
||||||
|
vm.ip -= offset
|
||||||
|
}
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -439,14 +591,13 @@ pub fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
..
|
..
|
||||||
} = instruction_data;
|
} = instruction_data;
|
||||||
let function = vm.get_argument(b, b_is_constant);
|
let function = vm.get_argument(b, b_is_constant);
|
||||||
let chunk = if let ValueRef::Concrete(ConcreteValue::Function(chunk)) = function {
|
let mut function_vm = if let ValueRef::Concrete(ConcreteValue::Function(chunk)) = function {
|
||||||
chunk
|
Vm::new(vm.source, chunk, Some(vm), None)
|
||||||
} else if let ValueRef::Abstract(AbstractValue::FunctionSelf) = function {
|
} else if let ValueRef::Abstract(AbstractValue::FunctionSelf) = function {
|
||||||
vm.chunk
|
Vm::new(vm.source, vm.chunk, Some(vm), Some(vm.runners.clone()))
|
||||||
} else {
|
} else {
|
||||||
panic!("VM Error: Expected function")
|
panic!("VM Error: Expected function")
|
||||||
};
|
};
|
||||||
let mut function_vm = Vm::new(vm.source, chunk, Some(vm));
|
|
||||||
let first_argument_index = a - c;
|
let first_argument_index = a - c;
|
||||||
let mut argument_index = 0;
|
let mut argument_index = 0;
|
||||||
|
|
||||||
@ -473,6 +624,12 @@ pub fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
|
|
||||||
vm.set_register(a, register);
|
vm.set_register(a, register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -508,6 +665,12 @@ pub fn call_native<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData
|
|||||||
|
|
||||||
vm.set_register(a, register);
|
vm.set_register(a, register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vm.ip += 1;
|
||||||
|
|
||||||
|
let next = vm.runners[vm.ip];
|
||||||
|
|
||||||
|
next.run(vm);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::needless_lifetimes)]
|
#[allow(clippy::needless_lifetimes)]
|
||||||
@ -515,7 +678,7 @@ pub fn r#return<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) {
|
|||||||
let should_return_value = instruction_data.b != 0;
|
let should_return_value = instruction_data.b != 0;
|
||||||
|
|
||||||
if !should_return_value {
|
if !should_return_value {
|
||||||
return;
|
return vm.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(register_index) = &vm.last_assigned_register {
|
if let Some(register_index) = &vm.last_assigned_register {
|
||||||
|
Loading…
Reference in New Issue
Block a user