From 371a061b1c5a63959cc502f1b24d55a0eae7fb08 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 3 Feb 2025 17:49:38 -0500 Subject: [PATCH] Consolidate local operations to point operations --- Cargo.lock | 4 + dust-lang/Cargo.toml | 1 + dust-lang/src/compiler/mod.rs | 34 +- dust-lang/src/instruction/get_local.rs | 49 -- dust-lang/src/instruction/mod.rs | 36 +- dust-lang/src/instruction/negate.rs | 2 +- dust-lang/src/instruction/not.rs | 2 +- dust-lang/src/instruction/operation.rs | 39 +- dust-lang/src/instruction/point.rs | 21 +- dust-lang/src/instruction/set_local.rs | 49 -- dust-lang/src/instruction/test_set.rs | 2 +- dust-lang/src/native_function/assert.rs | 10 +- dust-lang/src/native_function/io.rs | 37 +- dust-lang/src/native_function/mod.rs | 12 +- dust-lang/src/native_function/random.rs | 26 +- dust-lang/src/native_function/string.rs | 17 +- dust-lang/src/native_function/thread.rs | 56 +- dust-lang/src/value/abstract_list.rs | 8 +- dust-lang/src/value/mod.rs | 4 +- dust-lang/src/vm/action.rs | 803 ++---------------------- dust-lang/src/vm/call_frame.rs | 13 +- dust-lang/src/vm/mod.rs | 11 +- dust-lang/src/vm/thread.rs | 228 ++----- 23 files changed, 218 insertions(+), 1246 deletions(-) delete mode 100644 dust-lang/src/instruction/get_local.rs delete mode 100644 dust-lang/src/instruction/set_local.rs diff --git a/Cargo.lock b/Cargo.lock index f62c495..b599be5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -349,6 +349,7 @@ dependencies = [ "rand", "serde", "serde_json", + "smallvec", "smartstring", "tracing", ] @@ -805,6 +806,9 @@ name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +dependencies = [ + "serde", +] [[package]] name = "smartstring" diff --git a/dust-lang/Cargo.toml b/dust-lang/Cargo.toml index 96fedb5..a1f819b 100644 --- a/dust-lang/Cargo.toml +++ b/dust-lang/Cargo.toml @@ -22,6 +22,7 @@ smartstring = { version = "1.0.1", features = [ ], default-features = false } tracing = "0.1.41" crossbeam-channel = "0.5.14" +smallvec = { version = "1.13.2", features = ["serde", "const_generics"] } [dev-dependencies] criterion = { version = "0.3.4", features = ["html_reports"] } diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index 8df9d3a..4fc2dd5 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -35,7 +35,7 @@ use optimize::control_flow_register_consolidation; use crate::{ Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local, NativeFunction, Operand, Operation, Scope, Span, Token, TokenKind, Type, Value, - instruction::{CallNative, Close, GetLocal, Jump, LoadList, Return, SetLocal, TypeCode}, + instruction::{CallNative, Close, Jump, LoadList, Point, Return, TypeCode}, }; /// Compiles the input and returns a chunk. @@ -697,12 +697,7 @@ impl<'src> Compiler<'src> { ) -> Result<(Operand, bool), CompileError> { let (argument, push_back) = match instruction.operation() { Operation::LOAD_CONSTANT => (Operand::Constant(instruction.b_field()), false), - Operation::GET_LOCAL => { - let local_index = instruction.b_field(); - let (local, _) = self.get_local(local_index)?; - - (Operand::Register(local.register_index), false) - } + Operation::POINT => (Operand::Register(instruction.a_field()), false), Operation::LOAD_BOOLEAN | Operation::LOAD_LIST | Operation::LOAD_SELF @@ -749,11 +744,11 @@ impl<'src> Compiler<'src> { position: self.previous_position, })?; let (left, push_back_left) = self.handle_binary_argument(&left_instruction)?; - let left_is_mutable_local = if let Operation::GET_LOCAL = left_instruction.operation() { - let GetLocal { local_index, .. } = GetLocal::from(left_instruction); + let left_is_mutable_local = if left_instruction.operation() == Operation::POINT { + let Point { to, .. } = Point::from(left_instruction); self.locals - .get(local_index as usize) + .get(to.index() as usize) .map(|(local, _)| local.is_mutable) .unwrap_or(false) } else { @@ -1008,8 +1003,9 @@ impl<'src> Compiler<'src> { found: self.previous_token.to_owned(), position: self.previous_position, })?; - let operand_register = if last_instruction.operation() == Operation::GET_LOCAL { - let (local, _) = self.get_local(last_instruction.b_field())?; + let operand_register = if last_instruction.operation() == Operation::POINT { + let Point { to, .. } = Point::from(last_instruction); + let (local, _) = self.get_local(to.index())?; local.register_index } else if last_instruction.yields_value() { @@ -1138,24 +1134,18 @@ impl<'src> Compiler<'src> { math_instruction.set_a_field(local_register_index); } else { let register = self.next_register() - 1; - let set_local = Instruction::from(SetLocal { - register_index: register, - local_index, - }); + let point = Instruction::point(local_register_index, Operand::Register(register)); - self.emit_instruction(set_local, Type::None, start_position); + self.emit_instruction(point, r#type, start_position); } return Ok(()); } let destination = self.next_register(); - let get_local = Instruction::from(GetLocal { - destination, - local_index, - }); + let point = Instruction::point(destination, Operand::Register(local_register_index)); - self.emit_instruction(get_local, r#type, self.previous_position); + self.emit_instruction(point, r#type, self.previous_position); Ok(()) } diff --git a/dust-lang/src/instruction/get_local.rs b/dust-lang/src/instruction/get_local.rs deleted file mode 100644 index 8aba567..0000000 --- a/dust-lang/src/instruction/get_local.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use crate::{Instruction, Operation}; - -use super::InstructionBuilder; - -pub struct GetLocal { - pub destination: u16, - pub local_index: u16, -} - -impl From for GetLocal { - fn from(instruction: Instruction) -> Self { - let destination = instruction.a_field(); - let local_index = instruction.b_field(); - - GetLocal { - destination, - local_index, - } - } -} - -impl From for Instruction { - fn from(get_local: GetLocal) -> Self { - let operation = Operation::GET_LOCAL; - let a_field = get_local.destination; - let b_field = get_local.local_index; - - InstructionBuilder { - operation, - a_field, - b_field, - ..Default::default() - } - .build() - } -} - -impl Display for GetLocal { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let GetLocal { - destination, - local_index, - } = self; - - write!(f, "R{destination} = L{local_index}") - } -} diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index 99c3f68..8fbfe46 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -99,7 +99,6 @@ mod call_native; mod close; mod divide; mod equal; -mod get_local; mod jump; mod less; mod less_equal; @@ -115,7 +114,6 @@ mod not; mod operation; mod point; mod r#return; -mod set_local; mod subtract; mod test; mod test_set; @@ -127,7 +125,6 @@ pub use call_native::CallNative; pub use close::Close; pub use divide::Divide; pub use equal::Equal; -pub use get_local::GetLocal; pub use jump::Jump; pub use less::Less; pub use less_equal::LessEqual; @@ -143,7 +140,6 @@ pub use not::Not; pub use operation::Operation; pub use point::Point; pub use r#return::Return; -pub use set_local::SetLocal; pub use subtract::Subtract; pub use test::Test; pub use test_set::TestSet; @@ -276,8 +272,8 @@ impl Instruction { self.0 = (bits as u64) << 63; } - pub fn point(from: u16, to: u16) -> Instruction { - Instruction::from(Point { from, to }) + pub fn point(destination: u16, to: Operand) -> Instruction { + Instruction::from(Point { destination, to }) } pub fn close(from: u16, to: u16) -> Instruction { @@ -323,20 +319,6 @@ impl Instruction { }) } - pub fn get_local(destination: u16, local_index: u16) -> Instruction { - Instruction::from(GetLocal { - destination, - local_index, - }) - } - - pub fn set_local(register: u16, local_index: u16) -> Instruction { - Instruction::from(SetLocal { - local_index, - register_index: register, - }) - } - pub fn add( destination: u16, left: Operand, @@ -546,10 +528,10 @@ impl Instruction { pub fn as_argument(&self) -> Option { match self.operation() { Operation::LOAD_CONSTANT => Some(Operand::Constant(self.b_field())), - Operation::LOAD_BOOLEAN + Operation::POINT + | Operation::LOAD_BOOLEAN | Operation::LOAD_LIST | Operation::LOAD_SELF - | Operation::GET_LOCAL | Operation::ADD | Operation::SUBTRACT | Operation::MULTIPLY @@ -574,7 +556,7 @@ impl Instruction { } } - pub fn b_as_argument(&self) -> Operand { + pub fn b_as_operand(&self) -> Operand { if self.b_is_constant() { Operand::Constant(self.b_field()) } else { @@ -605,7 +587,6 @@ impl Instruction { | Operation::LOAD_FUNCTION | Operation::LOAD_LIST | Operation::LOAD_SELF - | Operation::GET_LOCAL | Operation::ADD | Operation::SUBTRACT | Operation::MULTIPLY @@ -619,9 +600,7 @@ impl Instruction { function.returns_value() } - Operation::CLOSE - | Operation::SET_LOCAL - | Operation::EQUAL + Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL | Operation::TEST @@ -637,14 +616,11 @@ impl Instruction { match operation { Operation::POINT => Point::from(*self).to_string(), - Operation::CLOSE => Close::from(*self).to_string(), Operation::LOAD_BOOLEAN => LoadBoolean::from(*self).to_string(), Operation::LOAD_CONSTANT => LoadConstant::from(*self).to_string(), Operation::LOAD_FUNCTION => LoadFunction::from(*self).to_string(), Operation::LOAD_LIST => LoadList::from(*self).to_string(), Operation::LOAD_SELF => LoadSelf::from(*self).to_string(), - Operation::GET_LOCAL => GetLocal::from(*self).to_string(), - Operation::SET_LOCAL => SetLocal::from(*self).to_string(), Operation::ADD => Add::from(*self).to_string(), Operation::SUBTRACT => Subtract::from(*self).to_string(), Operation::MULTIPLY => Multiply::from(*self).to_string(), diff --git a/dust-lang/src/instruction/negate.rs b/dust-lang/src/instruction/negate.rs index e2a4aa4..17739b2 100644 --- a/dust-lang/src/instruction/negate.rs +++ b/dust-lang/src/instruction/negate.rs @@ -11,7 +11,7 @@ pub struct Negate { impl From for Negate { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); - let argument = instruction.b_as_argument(); + let argument = instruction.b_as_operand(); let argument_type = instruction.b_type(); Negate { diff --git a/dust-lang/src/instruction/not.rs b/dust-lang/src/instruction/not.rs index 51a06db..c74b822 100644 --- a/dust-lang/src/instruction/not.rs +++ b/dust-lang/src/instruction/not.rs @@ -12,7 +12,7 @@ pub struct Not { impl From for Not { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); - let argument = instruction.b_as_argument(); + let argument = instruction.b_as_operand(); Not { destination, diff --git a/dust-lang/src/instruction/operation.rs b/dust-lang/src/instruction/operation.rs index 5617f9c..5cbdaf6 100644 --- a/dust-lang/src/instruction/operation.rs +++ b/dust-lang/src/instruction/operation.rs @@ -20,51 +20,44 @@ impl Operation { pub const LOAD_LIST: Operation = Operation(5); pub const LOAD_SELF: Operation = Operation(6); - // Locals - pub const GET_LOCAL: Operation = Operation(7); - pub const SET_LOCAL: Operation = Operation(8); - // Arithmetic - pub const ADD: Operation = Operation(9); - pub const SUBTRACT: Operation = Operation(10); - pub const MULTIPLY: Operation = Operation(11); - pub const DIVIDE: Operation = Operation(12); - pub const MODULO: Operation = Operation(13); + pub const ADD: Operation = Operation(7); + pub const SUBTRACT: Operation = Operation(8); + pub const MULTIPLY: Operation = Operation(9); + pub const DIVIDE: Operation = Operation(10); + pub const MODULO: Operation = Operation(11); // Comparison - pub const EQUAL: Operation = Operation(14); - pub const LESS: Operation = Operation(15); - pub const LESS_EQUAL: Operation = Operation(16); + pub const EQUAL: Operation = Operation(12); + pub const LESS: Operation = Operation(13); + pub const LESS_EQUAL: Operation = Operation(14); // Unary operations - pub const NEGATE: Operation = Operation(17); - pub const NOT: Operation = Operation(18); + pub const NEGATE: Operation = Operation(15); + pub const NOT: Operation = Operation(16); // Logical operations - pub const TEST: Operation = Operation(19); - pub const TEST_SET: Operation = Operation(20); + pub const TEST: Operation = Operation(17); + pub const TEST_SET: Operation = Operation(18); // Function calls - pub const CALL: Operation = Operation(21); - pub const CALL_NATIVE: Operation = Operation(22); + pub const CALL: Operation = Operation(19); + pub const CALL_NATIVE: Operation = Operation(20); // Control flow - pub const JUMP: Operation = Operation(23); - pub const RETURN: Operation = Operation(24); + pub const JUMP: Operation = Operation(21); + pub const RETURN: Operation = Operation(22); } impl Operation { pub fn name(&self) -> &'static str { match *self { Self::POINT => "POINT", - Self::CLOSE => "CLOSE", Self::LOAD_BOOLEAN => "LOAD_BOOLEAN", Self::LOAD_CONSTANT => "LOAD_CONSTANT", Self::LOAD_FUNCTION => "LOAD_FUNCTION", Self::LOAD_LIST => "LOAD_LIST", Self::LOAD_SELF => "LOAD_SELF", - Self::GET_LOCAL => "GET_LOCAL", - Self::SET_LOCAL => "SET_LOCAL", Self::ADD => "ADD", Self::SUBTRACT => "SUBTRACT", Self::MULTIPLY => "MULTIPLY", diff --git a/dust-lang/src/instruction/point.rs b/dust-lang/src/instruction/point.rs index eb6e459..4ba8914 100644 --- a/dust-lang/src/instruction/point.rs +++ b/dust-lang/src/instruction/point.rs @@ -2,18 +2,18 @@ use std::fmt::{self, Display, Formatter}; use crate::{Instruction, Operation}; -use super::InstructionBuilder; +use super::{InstructionBuilder, Operand}; pub struct Point { - pub from: u16, - pub to: u16, + pub destination: u16, + pub to: Operand, } impl From for Point { fn from(instruction: Instruction) -> Self { Point { - from: instruction.b_field(), - to: instruction.c_field(), + destination: instruction.a_field(), + to: instruction.b_as_operand(), } } } @@ -21,13 +21,14 @@ impl From for Point { impl From for Instruction { fn from(r#move: Point) -> Self { let operation = Operation::POINT; - let b_field = r#move.from; - let c_field = r#move.to; + let a_field = r#move.destination; + let (b_field, b_is_constant) = r#move.to.as_index_and_constant_flag(); InstructionBuilder { operation, + a_field, b_field, - c_field, + b_is_constant, ..Default::default() } .build() @@ -36,8 +37,8 @@ impl From for Instruction { impl Display for Point { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let Point { from, to } = self; + let Point { destination, to } = self; - write!(f, "{from} -> {to}") + write!(f, "R{destination} -> {to}") } } diff --git a/dust-lang/src/instruction/set_local.rs b/dust-lang/src/instruction/set_local.rs deleted file mode 100644 index 57b48a2..0000000 --- a/dust-lang/src/instruction/set_local.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::fmt::{self, Display, Formatter}; - -use crate::{Instruction, Operation}; - -use super::InstructionBuilder; - -pub struct SetLocal { - pub register_index: u16, - pub local_index: u16, -} - -impl From for SetLocal { - fn from(instruction: Instruction) -> Self { - let register_index = instruction.b_field(); - let local_index = instruction.c_field(); - - SetLocal { - register_index, - local_index, - } - } -} - -impl From for Instruction { - fn from(set_local: SetLocal) -> Self { - let operation = Operation::SET_LOCAL; - let b_field = set_local.register_index; - let c_field = set_local.local_index; - - InstructionBuilder { - operation, - b_field, - c_field, - ..Default::default() - } - .build() - } -} - -impl Display for SetLocal { - fn fmt(&self, f: &mut Formatter) -> fmt::Result { - let SetLocal { - register_index, - local_index, - } = self; - - write!(f, "L{local_index} = R{register_index}") - } -} diff --git a/dust-lang/src/instruction/test_set.rs b/dust-lang/src/instruction/test_set.rs index c946767..55b1b0e 100644 --- a/dust-lang/src/instruction/test_set.rs +++ b/dust-lang/src/instruction/test_set.rs @@ -13,7 +13,7 @@ pub struct TestSet { impl From for TestSet { fn from(instruction: Instruction) -> Self { let destination = instruction.a_field(); - let argument = instruction.b_as_argument(); + let argument = instruction.b_as_operand(); let test_value = instruction.c_field() != 0; TestSet { diff --git a/dust-lang/src/native_function/assert.rs b/dust-lang/src/native_function/assert.rs index 3cd7045..a006f27 100644 --- a/dust-lang/src/native_function/assert.rs +++ b/dust-lang/src/native_function/assert.rs @@ -1,17 +1,13 @@ use std::{ops::Range, panic}; -use crate::vm::ThreadData; +use crate::vm::Thread; -pub fn panic(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { +pub fn panic(data: &mut Thread, _: usize, argument_range: Range) { let position = data.current_position(); let mut message = format!("Dust panic at {position}!"); for register_index in argument_range { - let value_option = data.open_register_allow_empty_unchecked(register_index); - let value = match value_option { - Some(value) => value, - None => continue, - }; + let value = data.get_register(register_index); let string = value.display(data); message.push_str(&string); diff --git a/dust-lang/src/native_function/io.rs b/dust-lang/src/native_function/io.rs index 89bf2b7..402ebfc 100644 --- a/dust-lang/src/native_function/io.rs +++ b/dust-lang/src/native_function/io.rs @@ -3,10 +3,10 @@ use std::ops::Range; use crate::{ ConcreteValue, Value, - vm::{Register, ThreadData, get_next_action}, + vm::{Register, Thread}, }; -pub fn read_line(data: &mut ThreadData, destination: u16, _argument_range: Range) -> bool { +pub fn read_line(data: &mut Thread, destination: usize, _argument_range: Range) { let mut buffer = String::new(); if stdin().read_line(&mut buffer).is_ok() { @@ -14,45 +14,32 @@ pub fn read_line(data: &mut ThreadData, destination: u16, _argument_range: Range buffer.truncate(length.saturating_sub(1)); - let register = Register::Value(Value::Concrete(ConcreteValue::string(buffer))); + let new_register = Register::Value(Value::Concrete(ConcreteValue::string(buffer))); + let old_register = data.get_register_mut(destination); - data.set_register(destination, register); + *old_register = new_register; } - - data.next_action = get_next_action(data); - - false } -pub fn write(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { +pub fn write(data: &mut Thread, _: usize, argument_range: Range) { let mut stdout = stdout(); for register_index in argument_range { - if let Some(value) = data.open_register_allow_empty_unchecked(register_index) { - let string = value.display(data); - let _ = stdout.write(string.as_bytes()); - } + let value = data.get_register(register_index); + let _ = stdout.write(value.to_string().as_bytes()); } let _ = stdout.flush(); - data.next_action = get_next_action(data); - - false } -pub fn write_line(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { +pub fn write_line(data: &mut Thread, _: usize, argument_range: Range) { let mut stdout = stdout().lock(); for register_index in argument_range { - if let Some(value) = data.open_register_allow_empty_unchecked(register_index) { - let string = value.display(data); - let _ = stdout.write(string.as_bytes()); - let _ = stdout.write(b"\n"); - } + let value = data.get_register(register_index); + let _ = stdout.write(value.to_string().as_bytes()); } + let _ = stdout.write(b"\n"); let _ = stdout.flush(); - data.next_action = get_next_action(data); - - false } diff --git a/dust-lang/src/native_function/mod.rs b/dust-lang/src/native_function/mod.rs index 1926143..136539f 100644 --- a/dust-lang/src/native_function/mod.rs +++ b/dust-lang/src/native_function/mod.rs @@ -17,7 +17,7 @@ use std::{ use serde::{Deserialize, Serialize}; -use crate::{AnnotatedError, FunctionType, Span, Type, vm::ThreadData}; +use crate::{AnnotatedError, FunctionType, Span, Type, vm::Thread}; macro_rules! define_native_function { ($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => { @@ -34,13 +34,13 @@ macro_rules! define_native_function { impl NativeFunction { pub fn call( &self, - data: &mut ThreadData, - destination: u16, - argument_range: Range, - ) -> bool { + thread: &mut Thread, + destination: usize, + argument_range: Range, + ) { match self { $( - NativeFunction::$name => $function(data, destination, argument_range), + NativeFunction::$name => $function(thread, destination, argument_range), )* } } diff --git a/dust-lang/src/native_function/random.rs b/dust-lang/src/native_function/random.rs index 1eae46a..71d112c 100644 --- a/dust-lang/src/native_function/random.rs +++ b/dust-lang/src/native_function/random.rs @@ -4,10 +4,10 @@ use rand::Rng; use crate::{ Value, - vm::{Register, ThreadData, get_next_action}, + vm::{Register, Thread}, }; -pub fn random_int(data: &mut ThreadData, destination: u16, argument_range: Range) -> bool { +pub fn random_int(data: &mut Thread, destination: usize, argument_range: Range) { let mut argument_range_iter = argument_range.into_iter(); let (min, max) = { let mut min = None; @@ -16,25 +16,21 @@ pub fn random_int(data: &mut ThreadData, destination: u16, argument_range: Range let register_index = argument_range_iter .next() .unwrap_or_else(|| panic!("No argument was passed to \"random_int\"")); - let value_option = data.open_register_allow_empty_unchecked(register_index); + let argument = data.get_register(register_index); - if let Some(argument) = value_option { - if let Some(integer) = argument.as_integer() { - if min.is_none() { - min = Some(integer); - } else { - break (min, integer); - } + if let Some(integer) = argument.as_integer() { + if min.is_none() { + min = Some(integer); + } else { + break (min, integer); } } } }; let random_integer = rand::thread_rng().gen_range(min.unwrap()..max); + let new_register = Register::Value(Value::integer(random_integer)); + let old_register = data.get_register_mut(destination); - data.set_register(destination, Register::Value(Value::integer(random_integer))); - - data.next_action = get_next_action(data); - - false + *old_register = new_register; } diff --git a/dust-lang/src/native_function/string.rs b/dust-lang/src/native_function/string.rs index 9e3546c..1363cfc 100644 --- a/dust-lang/src/native_function/string.rs +++ b/dust-lang/src/native_function/string.rs @@ -2,17 +2,14 @@ use std::ops::Range; use crate::{ ConcreteValue, Value, - vm::{Register, ThreadData, get_next_action}, + vm::{Register, Thread}, }; -pub fn to_string(data: &mut ThreadData, destination: u16, argument_range: Range) -> bool { - let argument_value = data.open_register_unchecked(argument_range.start); - let argument_string = argument_value.display(data); - let register = Register::Value(Value::Concrete(ConcreteValue::string(argument_string))); +pub fn to_string(thread: &mut Thread, destination: usize, argument_range: Range) { + let argument_value = thread.get_register(argument_range.start); + let argument_string = argument_value.display(thread); + let new_register = Register::Value(Value::Concrete(ConcreteValue::string(argument_string))); + let old_register = thread.get_register_mut(destination); - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false + *old_register = new_register; } diff --git a/dust-lang/src/native_function/thread.rs b/dust-lang/src/native_function/thread.rs index 4b0cf85..b108031 100644 --- a/dust-lang/src/native_function/thread.rs +++ b/dust-lang/src/native_function/thread.rs @@ -5,60 +5,12 @@ use std::{ use tracing::{Level, info, span}; -use crate::{ - DustString, - vm::{Thread, ThreadData, get_next_action}, -}; +use crate::{DustString, vm::Thread}; -fn start_thread(data: &mut ThreadData, argument_range: Range) -> JoinHandle<()> { - let mut argument_range_iter = argument_range.into_iter(); - let function_argument = { - loop { - let register_index = argument_range_iter - .next() - .unwrap_or_else(|| panic!("No argument was passed to \"spawn\"")); - let value_option = data.open_register_allow_empty_unchecked(register_index); - - if let Some(argument) = value_option { - break argument; - } - } - }; - let function = function_argument.as_function().unwrap(); - let prototype_index = function.prototype_index as usize; - let current_call = data.call_stack.last_unchecked(); - let prototype = current_call.chunk.prototypes[prototype_index].clone(); - - info!( - "Spawning thread for \"{}\"", - function - .name - .as_ref() - .cloned() - .unwrap_or_else(|| DustString::from("anonymous")) - ); - - let thread_name = prototype - .name - .as_ref() - .map(|name| name.to_string()) - .unwrap_or_else(|| "anonymous".to_string()); - let mut thread = Thread::new(prototype); - - Builder::new() - .name(thread_name) - .spawn(move || { - let span = span!(Level::INFO, "Spawned thread"); - let _enter = span.enter(); - - thread.run(); - }) - .expect("Critical VM Error: Failed to spawn thread") +fn start_thread(thread: &mut Thread, argument_range: Range) -> JoinHandle<()> { + todo!(); } -pub fn spawn(data: &mut ThreadData, _: u16, argument_range: Range) -> bool { +pub fn spawn(data: &mut Thread, _: usize, argument_range: Range) { let _ = start_thread(data, argument_range); - data.next_action = get_next_action(data); - - false } diff --git a/dust-lang/src/value/abstract_list.rs b/dust-lang/src/value/abstract_list.rs index f678d77..7b7ded6 100644 --- a/dust-lang/src/value/abstract_list.rs +++ b/dust-lang/src/value/abstract_list.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display, Formatter}; -use crate::{vm::ThreadData, Pointer, Type}; +use crate::{Pointer, Type, vm::Thread}; use super::DustString; @@ -11,17 +11,17 @@ pub struct AbstractList { } impl AbstractList { - pub fn display(&self, data: &ThreadData) -> DustString { + pub fn display(&self, thread: &Thread) -> DustString { let mut display = DustString::new(); display.push('['); - for (i, item) in self.item_pointers.iter().enumerate() { + for (i, pointer) in self.item_pointers.iter().enumerate() { if i > 0 { display.push_str(", "); } - let item_display = data.follow_pointer_unchecked(*item).display(data); + let item_display = thread.get_pointer_value(pointer).to_string(); display.push_str(&item_display); } diff --git a/dust-lang/src/value/mod.rs b/dust-lang/src/value/mod.rs index b9b7d91..7e5b9a8 100644 --- a/dust-lang/src/value/mod.rs +++ b/dust-lang/src/value/mod.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use std::fmt::{self, Debug, Display, Formatter}; -use crate::{Type, vm::ThreadData}; +use crate::{Type, vm::Thread}; #[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] pub enum Value { @@ -219,7 +219,7 @@ impl Value { } } - pub fn display(&self, data: &ThreadData) -> DustString { + pub fn display(&self, data: &Thread) -> DustString { match self { Value::AbstractList(list) => list.display(data), Value::Concrete(concrete_value) => concrete_value.display(), diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action.rs index 8225425..fd01a93 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action.rs @@ -3,15 +3,16 @@ use tracing::trace; use crate::{ AbstractList, ConcreteValue, Instruction, Operand, Type, Value, instruction::{ - Add, Call, CallNative, Close, Divide, Equal, GetLocal, InstructionBuilder, Jump, Less, - LessEqual, LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Modulo, Multiply, - Negate, Not, Point, Return, SetLocal, Subtract, Test, TestSet, TypeCode, + Add, Call, CallNative, Divide, Equal, InstructionBuilder, Jump, Less, LessEqual, + LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Modulo, Multiply, Negate, Not, + Return, Subtract, Test, TestSet, TypeCode, }, vm::CallFrame, }; use super::{Pointer, Register, thread::Thread}; +#[derive(Debug)] pub struct ActionSequence { pub actions: Vec, } @@ -21,7 +22,7 @@ impl ActionSequence { let mut actions = Vec::with_capacity(instructions.len()); for instruction in instructions { - let action = Action::from(*instruction); + let action = Action::from(instruction); actions.push(action); } @@ -46,18 +47,15 @@ impl From<&Instruction> for Action { } } -pub type RunnerLogic = fn(InstructionBuilder, &mut Thread) -> bool; +pub type RunnerLogic = fn(InstructionBuilder, &mut Thread); -pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 25] = [ +pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 22] = [ point, - close, load_boolean, load_constant, load_function, load_list, load_self, - get_local, - set_local, add, subtract, multiply, @@ -76,782 +74,66 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 25] = [ r#return, ]; -pub fn point(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Point { from, to } = instruction.into(); - let from_register = data.get_register_unchecked(from); - let from_register_is_empty = matches!(from_register, Register::Empty); - - if !from_register_is_empty { - let register = Register::Pointer(Pointer::Register(to)); - - data.set_register(from, register); - } - - data.next_action = get_next_action(data); - - false -} - -pub fn close(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Close { from, to } = instruction.into(); - - for register_index in from..to { - data.set_register(register_index, Register::Empty); - } - - data.next_action = get_next_action(data); - - false -} - -pub fn load_boolean(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let LoadBoolean { - destination, - value, - jump_next, - } = instruction.into(); - let boolean = Value::Concrete(ConcreteValue::Boolean(value)); - let register = Register::Value(boolean); - - data.set_register(destination, register); - - if jump_next { - let current_call = data.call_stack.last_mut_unchecked(); - - current_call.ip += 1; - } - - data.next_action = get_next_action(data); - - false -} - -pub fn load_constant(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let LoadConstant { - destination, - constant_index, - jump_next, - } = instruction.into(); - let register = Register::Pointer(Pointer::Constant(constant_index)); - - trace!("Load constant {constant_index} into R{destination}"); - - data.set_register(destination, register); - - if jump_next { - let current_call = data.call_stack.last_mut_unchecked(); - - current_call.ip += 1; - } - - data.next_action = get_next_action(data); - - false -} - -pub fn load_list(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let LoadList { - destination, - start_register, - jump_next, - } = instruction.into(); - let mut item_pointers = Vec::with_capacity((destination - start_register) as usize); - let mut item_type = Type::Any; - - for register_index in start_register..destination { - match data.get_register_unchecked(register_index) { - Register::Empty => continue, - Register::Value(value) => { - if item_type == Type::Any { - item_type = value.r#type(); - } - } - Register::Pointer(pointer) => { - if item_type == Type::Any { - item_type = data.follow_pointer_unchecked(*pointer).r#type(); - } - } - } - - let pointer = Pointer::Register(register_index); - - item_pointers.push(pointer); - } - - let list_value = Value::AbstractList(AbstractList { - item_type, - item_pointers, - }); - let register = Register::Value(list_value); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn load_function(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let LoadFunction { - destination, - prototype_index, - jump_next, - } = instruction.into(); - let prototype_index = prototype_index as usize; - let current_call = data.call_stack.last_mut_unchecked(); - let prototype = ¤t_call.chunk.prototypes[prototype_index]; - let function = prototype.as_function(); - let register = Register::Value(Value::Function(function)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn load_self(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let LoadSelf { - destination, - jump_next, - } = instruction.into(); - let current_call = data.call_stack.last_mut_unchecked(); - let prototype = ¤t_call.chunk; - let function = prototype.as_function(); - let register = Register::Value(Value::Function(function)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn get_local(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let GetLocal { - destination, - local_index, - } = instruction.into(); - let local_register_index = data.get_local_register(local_index); - let register = Register::Pointer(Pointer::Register(local_register_index)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn set_local(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let SetLocal { - register_index, - local_index, - } = instruction.into(); - let local_register_index = data.get_local_register(local_index); - let register = Register::Pointer(Pointer::Register(register_index)); - - data.set_register(local_register_index, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn add(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Add { - destination, - left, - left_type, - right, - right_type, - } = instruction.into(); - let sum = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; - - ConcreteValue::Integer(left + right) - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_float() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_float() - .unwrap_unchecked() - }; - - ConcreteValue::Float(left + right) - } - _ => panic!("VM Error: Cannot add values"), - }; - let register = Register::Value(Value::Concrete(sum)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn subtract(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Subtract { - destination, - left, - left_type, - right, - right_type, - } = instruction.into(); - let difference = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; - - ConcreteValue::Integer(left - right) - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_float() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_float() - .unwrap_unchecked() - }; - - ConcreteValue::Float(left - right) - } - _ => panic!("VM Error: Cannot subtract values"), - }; - let register = Register::Value(Value::Concrete(difference)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn multiply(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Multiply { - destination, - left, - left_type, - right, - right_type, - } = instruction.into(); - let product = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; - - ConcreteValue::Integer(left * right) - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_float() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_float() - .unwrap_unchecked() - }; - - ConcreteValue::Float(left * right) - } - _ => panic!("VM Error: Cannot multiply values"), - }; - let register = Register::Value(Value::Concrete(product)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn divide(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Divide { - destination, - left, - left_type, - right, - right_type, - } = instruction.into(); - let quotient = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; - - ConcreteValue::Integer(left / right) - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_float() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_float() - .unwrap_unchecked() - }; - - ConcreteValue::Float(left / right) - } - _ => panic!("VM Error: Cannot divide values"), - }; - let register = Register::Value(Value::Concrete(quotient)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn modulo(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Modulo { - destination, - left, - left_type, - right, - right_type, - } = instruction.into(); - let remainder = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; - - ConcreteValue::Integer(left % right) - } - _ => panic!("VM Error: Cannot modulo values"), - }; - let register = Register::Value(Value::Concrete(remainder)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn test(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Test { - operand_register, - test_value, - } = instruction.into(); - let value = data.open_register_unchecked(operand_register); - let boolean = if let Value::Concrete(ConcreteValue::Boolean(boolean)) = value { - *boolean +pub fn point(instruction: InstructionBuilder, thread: &mut Thread) { + let destination = instruction.a_field as usize; + let to = instruction.b_field as usize; + let to_is_constant = instruction.b_is_constant; + let pointer = if to_is_constant { + Pointer::Constant(to) } else { - panic!("VM Error: Expected boolean value for TEST operation",); + Pointer::Register(to) }; + let new_register = Register::Pointer(pointer); + let old_register = thread.get_register_mut(destination); - if boolean == test_value { - let current_call = data.call_stack.last_mut_unchecked(); - - current_call.ip += 1; - } - - data.next_action = get_next_action(data); - - false + *old_register = new_register; } -pub fn test_set(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let TestSet { - destination, - argument, - test_value, - } = instruction.into(); - let value = data.get_argument_unchecked(argument); - let boolean = if let Value::Concrete(ConcreteValue::Boolean(boolean)) = value { - *boolean - } else { - panic!("VM Error: Expected boolean value for TEST_SET operation",); - }; +pub fn load_boolean(instruction: InstructionBuilder, thread: &mut Thread) {} - if boolean == test_value { - } else { - let pointer = match argument { - Operand::Constant(constant_index) => Pointer::Constant(constant_index), - Operand::Register(register_index) => Pointer::Register(register_index), - }; - let register = Register::Pointer(pointer); +pub fn load_constant(instruction: InstructionBuilder, thread: &mut Thread) {} - data.set_register(destination, register); - } +pub fn load_list(instruction: InstructionBuilder, thread: &mut Thread) {} - data.next_action = get_next_action(data); +pub fn load_function(instruction: InstructionBuilder, thread: &mut Thread) {} - false -} +pub fn load_self(instruction: InstructionBuilder, thread: &mut Thread) {} -pub fn equal(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Equal { - comparator, - left, - left_type, - right, - right_type, - } = instruction.into(); - let is_equal = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; +pub fn get_local(instruction: InstructionBuilder, thread: &mut Thread) {} - left == right - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_float() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_float() - .unwrap_unchecked() - }; +pub fn set_local(instruction: InstructionBuilder, thread: &mut Thread) {} - left == right - } - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_boolean() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_boolean() - .unwrap_unchecked() - }; +pub fn add(instruction: InstructionBuilder, thread: &mut Thread) {} - left == right - } - (TypeCode::STRING, TypeCode::STRING) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_string() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_string() - .unwrap_unchecked() - }; +pub fn subtract(instruction: InstructionBuilder, thread: &mut Thread) {} - left == right - } - _ => panic!("VM Error: Cannot compare values"), - }; +pub fn multiply(instruction: InstructionBuilder, thread: &mut Thread) {} - if is_equal == comparator { - let current_call = data.call_stack.last_mut_unchecked(); +pub fn divide(instruction: InstructionBuilder, thread: &mut Thread) {} - current_call.ip += 1; - } +pub fn modulo(instruction: InstructionBuilder, thread: &mut Thread) {} - data.next_action = get_next_action(data); +pub fn test(instruction: InstructionBuilder, thread: &mut Thread) {} - false -} +pub fn test_set(instruction: InstructionBuilder, thread: &mut Thread) {} -pub fn less(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Less { - comparator, - left, - left_type, - right, - right_type, - } = instruction.into(); - let is_less = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; +pub fn equal(instruction: InstructionBuilder, thread: &mut Thread) {} - left < right - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_float() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_float() - .unwrap_unchecked() - }; +pub fn less(instruction: InstructionBuilder, thread: &mut Thread) {} - left < right - } - _ => panic!("VM Error: Cannot compare values"), - }; +pub fn less_equal(instruction: InstructionBuilder, thread: &mut Thread) {} - if is_less == comparator { - let current_call = data.call_stack.last_mut_unchecked(); +pub fn negate(instruction: InstructionBuilder, thread: &mut Thread) {} - current_call.ip += 1; - } +pub fn not(instruction: InstructionBuilder, thread: &mut Thread) {} - data.next_action = get_next_action(data); +pub fn jump(instruction: InstructionBuilder, thread: &mut Thread) {} - false -} +pub fn call(instruction: InstructionBuilder, thread: &mut Thread) {} -pub fn less_equal(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let LessEqual { - comparator, - left, - left_type, - right, - right_type, - } = instruction.into(); - let is_less_or_equal = match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_integer() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_integer() - .unwrap_unchecked() - }; +pub fn call_native(instruction: InstructionBuilder, thread: &mut Thread) {} - left <= right - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left = unsafe { - data.get_argument_unchecked(left) - .as_float() - .unwrap_unchecked() - }; - let right = unsafe { - data.get_argument_unchecked(right) - .as_float() - .unwrap_unchecked() - }; - - left <= right - } - _ => panic!("VM Error: Cannot compare values"), - }; - - if is_less_or_equal == comparator { - let current_call = data.call_stack.last_mut_unchecked(); - - current_call.ip += 1; - } - - data.next_action = get_next_action(data); - - false -} - -pub fn negate(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Negate { - destination, - argument, - argument_type, - } = instruction.into(); - let argument = data.get_argument_unchecked(argument); - let negated = argument.negate(); - let register = Register::Value(negated); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn not(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Not { - destination, - argument, - } = instruction.into(); - let argument = data.get_argument_unchecked(argument); - let not = match argument { - Value::Concrete(ConcreteValue::Boolean(boolean)) => ConcreteValue::Boolean(!boolean), - _ => panic!("VM Error: Expected boolean value for NOT operation"), - }; - let register = Register::Value(Value::Concrete(not)); - - data.set_register(destination, register); - - data.next_action = get_next_action(data); - - false -} - -pub fn jump(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Jump { - offset, - is_positive, - } = instruction.into(); - let offset = offset as usize; - let current_call = data.call_stack.last_mut_unchecked(); - - if is_positive { - current_call.ip += offset; - } else { - current_call.ip -= offset + 1; - } - - data.next_action = get_next_action(data); - - false -} - -pub fn call(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let Call { - destination: return_register, - function_register, - argument_count, - is_recursive, - } = instruction.into(); - let current_call = data.call_stack.last_unchecked(); - let first_argument_register = return_register - argument_count; - let prototype = if is_recursive { - current_call.chunk.clone() - } else { - let function = data - .open_register_unchecked(function_register) - .as_function() - .unwrap(); - - current_call.chunk.prototypes[function.prototype_index as usize].clone() - }; - let mut next_call = CallFrame::new(prototype, return_register); - let mut argument_index = 0; - - for register_index in first_argument_register..return_register { - let value_option = data.open_register_allow_empty_unchecked(register_index); - let argument = if let Some(value) = value_option { - value.clone() - } else { - continue; - }; - - next_call.registers[argument_index] = Register::Value(argument); - argument_index += 1; - } - - data.call_stack.push(next_call); - - data.next_action = get_next_action(data); - - false -} - -pub fn call_native(instruction: InstructionBuilder, data: &mut Thread) -> bool { - let CallNative { - destination, - function, - argument_count, - } = instruction.into(); - let first_argument_index = destination - argument_count; - let argument_range = first_argument_index..destination; - - function.call(data, destination, argument_range) -} - -pub fn r#return(instruction: InstructionBuilder, data: &mut Thread) -> bool { - trace!("Returning with call stack:\n{}", data.call_stack); - - let Return { - should_return_value, - return_register, - } = instruction.into(); - let (destination, return_value) = if data.call_stack.len() == 1 { - if should_return_value { - data.return_value_index = Some(return_register); - }; - - return true; - } else { - let return_value = data.empty_register_or_clone_constant_unchecked(return_register); - let destination = data.call_stack.pop_unchecked().return_register; - - (destination, return_value) - }; - - if should_return_value { - data.set_register(destination, Register::Value(return_value)); - } - - data.next_action = get_next_action(data); - - false -} +pub fn r#return(instruction: InstructionBuilder, thread: &mut Thread) {} #[cfg(test)] mod tests { @@ -860,15 +142,12 @@ mod tests { use super::*; - const ALL_OPERATIONS: [(Operation, RunnerLogic); 24] = [ + const ALL_OPERATIONS: [(Operation, RunnerLogic); 21] = [ (Operation::POINT, point), - (Operation::CLOSE, close), (Operation::LOAD_BOOLEAN, load_boolean), (Operation::LOAD_CONSTANT, load_constant), (Operation::LOAD_LIST, load_list), (Operation::LOAD_SELF, load_self), - (Operation::GET_LOCAL, get_local), - (Operation::SET_LOCAL, set_local), (Operation::ADD, add), (Operation::SUBTRACT, subtract), (Operation::MULTIPLY, multiply), diff --git a/dust-lang/src/vm/call_frame.rs b/dust-lang/src/vm/call_frame.rs index 9495200..13cf626 100644 --- a/dust-lang/src/vm/call_frame.rs +++ b/dust-lang/src/vm/call_frame.rs @@ -3,27 +3,32 @@ use std::{ sync::Arc, }; +use smallvec::{SmallVec, smallvec}; + use crate::{Chunk, DustString}; -use super::Register; +use super::{Register, action::ActionSequence}; #[derive(Debug)] pub struct CallFrame { pub chunk: Arc, pub ip: usize, pub return_register: u16, - pub registers: Vec, + pub registers: SmallVec<[Register; 64]>, + pub action_sequence: ActionSequence, } impl CallFrame { pub fn new(chunk: Arc, return_register: u16) -> Self { - let register_count = chunk.register_count; + let registers = smallvec![Register::Empty; chunk.register_count]; + let action_sequence = ActionSequence::new(&chunk.instructions); Self { chunk, ip: 0, return_register, - registers: vec![Register::Empty; register_count], + registers, + action_sequence, } } } diff --git a/dust-lang/src/vm/mod.rs b/dust-lang/src/vm/mod.rs index aa9fae3..8631d27 100644 --- a/dust-lang/src/vm/mod.rs +++ b/dust-lang/src/vm/mod.rs @@ -10,7 +10,6 @@ use std::{ }; pub use action::Action; -pub(crate) use action::get_next_action; pub use call_frame::CallFrame; pub use thread::Thread; @@ -73,17 +72,17 @@ impl Display for Register { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { Self::Empty => write!(f, "empty"), - Self::Value(value) => write!(f, "{}", value), - Self::Pointer(pointer) => write!(f, "{}", pointer), + Self::Value(value) => write!(f, "{value}"), + Self::Pointer(pointer) => write!(f, "{pointer}"), } } } #[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)] pub enum Pointer { - Register(u16), - Constant(u16), - Stack(usize, u16), + Register(usize), + Constant(usize), + Stack(usize, usize), } impl Display for Pointer { diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index 3dad090..fe2b493 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -1,11 +1,8 @@ -use std::{mem::replace, sync::Arc, thread::JoinHandle}; +use std::{sync::Arc, thread::JoinHandle}; use tracing::{info, trace}; -use crate::{ - Chunk, DustString, Operand, Span, Value, - vm::{CallFrame, action::ActionSequence}, -}; +use crate::{Chunk, DustString, Span, Value, vm::CallFrame}; use super::{Pointer, Register}; @@ -40,9 +37,6 @@ impl Thread { .unwrap_or_else(|| DustString::from("anonymous")) ); - let main_call = self.current_frame(); - let action_sequence = ActionSequence::new(&main_call.chunk.instructions); - loop { let current_frame = self.current_frame_mut(); let ip = { @@ -52,18 +46,21 @@ impl Thread { ip }; let current_action = if cfg!(debug_assertions) { - action_sequence.actions.get(ip).unwrap() + current_frame.action_sequence.actions.get(ip).unwrap() } else { - unsafe { action_sequence.actions.get_unchecked(ip) } + unsafe { current_frame.action_sequence.actions.get_unchecked(ip) } }; - trace!("Operation: {}", current_action.instruction.operation); + trace!( + "Instruction operation: {}", + current_action.instruction.operation + ); (current_action.logic)(current_action.instruction, &mut self); if let Some(return_index_option) = self.return_value_index { if let Some(return_index) = return_index_option { - let return_value = self.open_register_unchecked(return_index as u16).clone(); + let return_value = self.get_register(return_index).clone(); return Some(return_value); } else { @@ -95,187 +92,84 @@ impl Thread { } } - pub(crate) fn follow_pointer_unchecked(&self, pointer: Pointer) -> &Value { - trace!("Follow {pointer}"); - - match pointer { - Pointer::Register(register_index) => self.open_register_unchecked(register_index), - Pointer::Constant(constant_index) => self.get_constant_unchecked(constant_index), - Pointer::Stack(stack_index, register_index) => unsafe { - let register = self - .call_stack - .get_unchecked(stack_index) - .registers - .get_unchecked(register_index as usize); - - match register { - Register::Value(value) => value, - Register::Pointer(pointer) => self.follow_pointer_unchecked(*pointer), - Register::Empty => panic!("VM Error: Register {register_index} is empty"), - } - }, - } - } - - pub fn get_register_unchecked(&self, register_index: u16) -> &Register { + pub fn get_register(&self, register_index: usize) -> &Value { trace!("Get R{register_index}"); - let register_index = register_index as usize; - - if cfg!(debug_assertions) { - &self.call_stack.last_unchecked().registers[register_index] - } else { - unsafe { - self.call_stack - .last_unchecked() - .registers - .get_unchecked(register_index) - } - } - } - - pub fn set_register(&mut self, to_register: u16, register: Register) { - let to_register = to_register as usize; - - self.call_stack.last_mut_unchecked().registers[to_register] = register; - } - - pub fn open_register_unchecked(&self, register_index: u16) -> &Value { - let register_index = register_index as usize; - let register = if cfg!(debug_assertions) { - &self.call_stack.last_unchecked().registers[register_index] + self.call_stack + .last() + .unwrap() + .registers + .get(register_index) + .unwrap() } else { unsafe { self.call_stack - .last_unchecked() + .last() + .unwrap_unchecked() .registers .get_unchecked(register_index) } }; - trace!("Open R{register_index} to {register}"); - match register { Register::Value(value) => value, - Register::Pointer(pointer) => self.follow_pointer_unchecked(*pointer), - Register::Empty => panic!("VM Error: Register {register_index} is empty"), + Register::Pointer(pointer) => self.get_pointer_value(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), } } - pub fn open_register_allow_empty_unchecked(&self, register_index: u16) -> Option<&Value> { - trace!("Open R{register_index}"); - - let register = self.get_register_unchecked(register_index); - - trace!("Open R{register_index} to {register}"); - - match register { - Register::Value(value) => Some(value), - Register::Pointer(pointer) => Some(self.follow_pointer_unchecked(*pointer)), - Register::Empty => None, - } - } - - pub fn empty_register_or_clone_constant_unchecked(&mut self, register_index: u16) -> Value { - let register_index = register_index as usize; - let old_register = replace( - &mut self.call_stack.last_mut_unchecked().registers[register_index], - Register::Empty, - ); - - match old_register { - Register::Value(value) => value, - Register::Pointer(pointer) => match pointer { - Pointer::Register(register_index) => { - self.empty_register_or_clone_constant_unchecked(register_index) - } - Pointer::Constant(constant_index) => { - self.get_constant_unchecked(constant_index).clone() - } - Pointer::Stack(stack_index, register_index) => { - let call = self.call_stack.get_unchecked_mut(stack_index); - - let old_register = replace( - &mut call.registers[register_index as usize], - Register::Empty, - ); - - match old_register { - Register::Value(value) => value, - Register::Pointer(pointer) => { - self.follow_pointer_unchecked(pointer).clone() - } - Register::Empty => panic!("VM Error: Register {register_index} is empty"), - } - } - }, - Register::Empty => panic!("VM Error: Register {register_index} is empty"), - } - } - - pub fn clone_register_value_or_constant_unchecked(&self, register_index: u16) -> Value { - let register = self.get_register_unchecked(register_index); - - match register { - Register::Value(value) => value.clone(), - Register::Pointer(pointer) => match pointer { - Pointer::Register(register_index) => { - self.open_register_unchecked(*register_index).clone() - } - Pointer::Constant(constant_index) => { - self.get_constant_unchecked(*constant_index).clone() - } - Pointer::Stack(stack_index, register_index) => { - let call = self.call_stack.get_unchecked(*stack_index); - let register = &call.registers[*register_index as usize]; - - match register { - Register::Value(value) => value.clone(), - Register::Pointer(pointer) => { - self.follow_pointer_unchecked(*pointer).clone() - } - Register::Empty => panic!("VM Error: Register {register_index} is empty"), - } - } - }, - Register::Empty => panic!("VM Error: Register {register_index} is empty"), - } - } - - /// DRY helper to get a value from an Argument - pub fn get_argument_unchecked(&self, argument: Operand) -> &Value { - match argument { - Operand::Constant(constant_index) => self.get_constant_unchecked(constant_index), - Operand::Register(register_index) => self.open_register_unchecked(register_index), - } - } - - pub fn get_constant_unchecked(&self, constant_index: u16) -> &Value { - let constant_index = constant_index as usize; + pub fn get_register_mut(&mut self, register_index: usize) -> &mut Register { + trace!("Get R{register_index}"); if cfg!(debug_assertions) { - &self.call_stack.last().unwrap().chunk.constants[constant_index] + self.call_stack + .last_mut() + .unwrap() + .registers + .get_mut(register_index) + .unwrap() } else { unsafe { self.call_stack - .last_unchecked() - .chunk - .constants - .get_unchecked(constant_index) + .last_mut() + .unwrap_unchecked() + .registers + .get_unchecked_mut(register_index) } } } - pub fn get_local_register(&self, local_index: u16) -> u16 { - let local_index = local_index as usize; - let chunk = &self.call_stack.last_unchecked().chunk; + pub fn get_constant(&self, constant_index: usize) -> &Value { + if cfg!(debug_assertions) { + self.chunk.constants.get(constant_index).unwrap() + } else { + unsafe { self.chunk.constants.get_unchecked(constant_index) } + } + } - assert!( - local_index < chunk.locals.len(), - "VM Error: Local index out of bounds" - ); + pub fn get_pointer_value(&self, pointer: &Pointer) -> &Value { + match pointer { + Pointer::Register(register_index) => self.get_register(*register_index), + Pointer::Constant(constant_index) => self.get_constant(*constant_index), + Pointer::Stack(call_index, register_index) => { + let call_frame = if cfg!(debug_assertions) { + self.call_stack.get(*call_index).unwrap() + } else { + unsafe { self.call_stack.get_unchecked(*call_index) } + }; + let register = if cfg!(debug_assertions) { + call_frame.registers.get(*register_index).unwrap() + } else { + unsafe { call_frame.registers.get_unchecked(*register_index) } + }; - chunk.locals[local_index].register_index + match register { + Register::Value(value) => value, + Register::Pointer(pointer) => self.get_pointer_value(pointer), + Register::Empty => panic!("Attempted to get value from empty register"), + } + } + } } }