From ec5033a32fdebc69cd918e43be49e9ac3f5caccb Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 14 Dec 2024 08:49:02 -0500 Subject: [PATCH] Continue VM optimizations --- dust-lang/src/chunk/disassembler.rs | 6 +- dust-lang/src/chunk/mod.rs | 10 +- dust-lang/src/compiler/mod.rs | 23 +-- dust-lang/src/lib.rs | 4 +- dust-lang/src/native_function/assertion.rs | 4 +- dust-lang/src/native_function/io.rs | 11 +- dust-lang/src/native_function/mod.rs | 4 +- dust-lang/src/native_function/string.rs | 4 +- dust-lang/src/value/abstract_value.rs | 22 ++- dust-lang/src/value/concrete_value.rs | 6 +- dust-lang/src/value/mod.rs | 102 +++++-------- dust-lang/src/vm/mod.rs | 61 ++++---- dust-lang/src/vm/runners.rs | 157 +++++++++------------ 13 files changed, 175 insertions(+), 239 deletions(-) diff --git a/dust-lang/src/chunk/disassembler.rs b/dust-lang/src/chunk/disassembler.rs index 3a73c62..c5edceb 100644 --- a/dust-lang/src/chunk/disassembler.rs +++ b/dust-lang/src/chunk/disassembler.rs @@ -46,7 +46,7 @@ use std::{ use colored::{ColoredString, Colorize}; -use crate::{value::ConcreteValue, Chunk, Local}; +use crate::{value::ConcreteValue, Chunk, Local, Value}; const INSTRUCTION_COLUMNS: [(&str, usize); 4] = [("i", 5), ("POSITION", 12), ("OPERATION", 17), ("INFO", 24)]; @@ -336,7 +336,7 @@ impl<'a, W: Write> Disassembler<'a, W> { self.write_centered_with_border(CONSTANT_BORDERS[1])?; for (index, value) in self.chunk.constants().iter().enumerate() { - let is_function = matches!(value, ConcreteValue::Function(_)); + let is_function = matches!(value, Value::Concrete(ConcreteValue::Function(_))); let type_display = value.r#type().to_string(); let value_display = if is_function { "Function displayed below".to_string() @@ -353,7 +353,7 @@ impl<'a, W: Write> Disassembler<'a, W> { self.write_centered_with_border(&constant_display)?; - if let ConcreteValue::Function(chunk) = value { + if let Value::Concrete(ConcreteValue::Function(chunk)) = value { let function_disassembler = chunk .disassembler(self.writer) .style(self.style) diff --git a/dust-lang/src/chunk/mod.rs b/dust-lang/src/chunk/mod.rs index 8590176..919d6bd 100644 --- a/dust-lang/src/chunk/mod.rs +++ b/dust-lang/src/chunk/mod.rs @@ -17,7 +17,7 @@ use std::io::Write; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; -use crate::{ConcreteValue, DustString, FunctionType, Instruction, Span}; +use crate::{ConcreteValue, DustString, FunctionType, Instruction, Span, Value}; /// In-memory representation of a Dust program or function. /// @@ -28,7 +28,7 @@ pub struct Chunk { r#type: FunctionType, instructions: SmallVec<[(Instruction, Span); 32]>, - constants: SmallVec<[ConcreteValue; 16]>, + constants: SmallVec<[Value; 16]>, locals: SmallVec<[Local; 8]>, stack_size: usize, @@ -39,7 +39,7 @@ impl Chunk { name: Option, r#type: FunctionType, instructions: SmallVec<[(Instruction, Span); 32]>, - constants: SmallVec<[ConcreteValue; 16]>, + constants: SmallVec<[Value; 16]>, locals: SmallVec<[Local; 8]>, stack_size: usize, ) -> Self { @@ -57,7 +57,7 @@ impl Chunk { name: Option, r#type: FunctionType, instructions: impl Into>, - constants: impl Into>, + constants: impl Into>, locals: impl Into>, ) -> Self { Self { @@ -82,7 +82,7 @@ impl Chunk { self.instructions.is_empty() } - pub fn constants(&self) -> &SmallVec<[ConcreteValue; 16]> { + pub fn constants(&self) -> &SmallVec<[Value; 16]> { &self.constants } diff --git a/dust-lang/src/compiler/mod.rs b/dust-lang/src/compiler/mod.rs index e249fb2..6062e6d 100644 --- a/dust-lang/src/compiler/mod.rs +++ b/dust-lang/src/compiler/mod.rs @@ -24,7 +24,7 @@ use crate::{ Not, Return, SetLocal, Test, }, Argument, Chunk, ConcreteValue, DustError, DustString, FunctionType, Instruction, Lexer, Local, - NativeFunction, Operation, Scope, Span, Token, TokenKind, Type, + NativeFunction, Operation, Scope, Span, Token, TokenKind, Type, Value, }; /// Compiles the input and returns a chunk. @@ -58,7 +58,7 @@ pub fn compile(source: &str) -> Result { pub struct Compiler<'src> { self_name: Option, instructions: SmallVec<[(Instruction, Type, Span); 32]>, - constants: SmallVec<[ConcreteValue; 16]>, + constants: SmallVec<[Value; 16]>, locals: SmallVec<[(Local, Type); 8]>, stack_size: usize, @@ -203,11 +203,12 @@ impl<'src> Compiler<'src> { .rev() .find_map(|(index, (local, _))| { let constant = self.constants.get(local.identifier_index as usize)?; - let identifier = if let ConcreteValue::String(identifier) = constant { - identifier - } else { - return None; - }; + let identifier = + if let Value::Concrete(ConcreteValue::String(identifier)) = constant { + identifier + } else { + return None; + }; if identifier == identifier_text { Some(index as u8) @@ -231,7 +232,7 @@ impl<'src> Compiler<'src> { ) -> (u8, u8) { log::info!("Declaring local {identifier}"); - let identifier = ConcreteValue::string(identifier); + let identifier = Value::Concrete(ConcreteValue::string(identifier)); let identifier_index = self.push_or_get_constant(identifier); let local_index = self.locals.len() as u8; @@ -253,7 +254,7 @@ impl<'src> Compiler<'src> { }) } - fn push_or_get_constant(&mut self, value: ConcreteValue) -> u8 { + fn push_or_get_constant(&mut self, value: Value) -> u8 { if let Some(index) = self .constants .iter() @@ -405,7 +406,7 @@ impl<'src> Compiler<'src> { position: Span, ) -> Result<(), CompileError> { let r#type = constant.r#type(); - let constant_index = self.push_or_get_constant(constant); + let constant_index = self.push_or_get_constant(Value::Concrete(constant)); let destination = self.next_register(); let load_constant = Instruction::load_constant(destination, constant_index, false); @@ -1618,7 +1619,7 @@ impl<'src> Compiler<'src> { let function_end = function_compiler.previous_position.1; let chunk = function_compiler.finish(None, value_parameters.clone()); - let function = ConcreteValue::function(chunk); + let function = Value::Concrete(ConcreteValue::function(chunk)); let constant_index = self.push_or_get_constant(function); let destination = self.next_register(); let function_type = FunctionType { diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index 0c7f7cc..f965f05 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -47,9 +47,7 @@ pub use crate::lexer::{lex, LexError, Lexer}; pub use crate::native_function::{NativeFunction, NativeFunctionError}; pub use crate::r#type::{EnumType, FunctionType, StructType, Type, TypeConflict}; pub use crate::token::{Token, TokenKind, TokenOwned}; -pub use crate::value::{ - AbstractValue, ConcreteValue, DustString, RangeValue, Value, ValueError, ValueRef, -}; +pub use crate::value::{AbstractValue, ConcreteValue, DustString, RangeValue, Value, ValueError}; pub use crate::vm::{run, Vm, VmError}; use std::fmt::Display; diff --git a/dust-lang/src/native_function/assertion.rs b/dust-lang/src/native_function/assertion.rs index 7fe89d0..8e9e3e2 100644 --- a/dust-lang/src/native_function/assertion.rs +++ b/dust-lang/src/native_function/assertion.rs @@ -3,11 +3,11 @@ use std::panic; use annotate_snippets::{Level, Renderer, Snippet}; use smallvec::SmallVec; -use crate::{DustString, NativeFunctionError, Value, ValueRef, Vm}; +use crate::{DustString, NativeFunctionError, Value, Vm}; pub fn panic( vm: &Vm, - arguments: SmallVec<[ValueRef; 4]>, + arguments: SmallVec<[&Value; 4]>, ) -> Result, NativeFunctionError> { let mut message: Option = None; diff --git a/dust-lang/src/native_function/io.rs b/dust-lang/src/native_function/io.rs index f163b0d..c2c16ee 100644 --- a/dust-lang/src/native_function/io.rs +++ b/dust-lang/src/native_function/io.rs @@ -2,12 +2,9 @@ use std::io::{stdin, stdout, Write}; use smallvec::SmallVec; -use crate::{ConcreteValue, NativeFunctionError, Value, ValueRef, Vm}; +use crate::{ConcreteValue, NativeFunctionError, Value, Vm}; -pub fn read_line( - vm: &Vm, - _: SmallVec<[ValueRef; 4]>, -) -> Result, NativeFunctionError> { +pub fn read_line(vm: &Vm, _: SmallVec<[&Value; 4]>) -> Result, NativeFunctionError> { let mut buffer = String::new(); match stdin().read_line(&mut buffer) { @@ -27,7 +24,7 @@ pub fn read_line( pub fn write( vm: &Vm, - arguments: SmallVec<[ValueRef; 4]>, + arguments: SmallVec<[&Value; 4]>, ) -> Result, NativeFunctionError> { let mut stdout = stdout(); @@ -50,7 +47,7 @@ pub fn write( pub fn write_line( vm: &Vm, - arguments: SmallVec<[ValueRef; 4]>, + arguments: SmallVec<[&Value; 4]>, ) -> Result, NativeFunctionError> { let mut stdout = stdout(); diff --git a/dust-lang/src/native_function/mod.rs b/dust-lang/src/native_function/mod.rs index 30cd8cb..c1b50d4 100644 --- a/dust-lang/src/native_function/mod.rs +++ b/dust-lang/src/native_function/mod.rs @@ -15,7 +15,7 @@ use std::{ use serde::{Deserialize, Serialize}; use smallvec::{smallvec, SmallVec}; -use crate::{AnnotatedError, FunctionType, Span, Type, Value, ValueRef, Vm, VmError}; +use crate::{AnnotatedError, FunctionType, Span, Type, Value, Vm, VmError}; macro_rules! define_native_function { ($(($name:ident, $bytes:literal, $str:expr, $type:expr, $function:expr)),*) => { @@ -33,7 +33,7 @@ macro_rules! define_native_function { pub fn call<'a>( &self, vm: &Vm<'a>, - arguments: SmallVec<[ValueRef<'a>; 4]>, + arguments: SmallVec<[&Value; 4]>, ) -> Result, NativeFunctionError> { match self { $( diff --git a/dust-lang/src/native_function/string.rs b/dust-lang/src/native_function/string.rs index 03caf7e..8857025 100644 --- a/dust-lang/src/native_function/string.rs +++ b/dust-lang/src/native_function/string.rs @@ -1,10 +1,10 @@ use smallvec::SmallVec; -use crate::{ConcreteValue, NativeFunctionError, Value, ValueRef, Vm}; +use crate::{ConcreteValue, NativeFunctionError, Value, Vm}; pub fn to_string( vm: &Vm, - arguments: SmallVec<[ValueRef; 4]>, + arguments: SmallVec<[&Value; 4]>, ) -> Result, NativeFunctionError> { if arguments.len() != 1 { return Err(NativeFunctionError::ExpectedArgumentCount { diff --git a/dust-lang/src/value/abstract_value.rs b/dust-lang/src/value/abstract_value.rs index 0407fb5..8e7de63 100644 --- a/dust-lang/src/value/abstract_value.rs +++ b/dust-lang/src/value/abstract_value.rs @@ -1,11 +1,14 @@ use std::fmt::{self, Display, Formatter}; -use crate::{vm::Pointer, ConcreteValue, DustString, Value, ValueRef, Vm, VmError}; +use crate::{vm::Pointer, ConcreteValue, DustString, Type, Value, Vm, VmError}; #[derive(Debug, PartialEq, PartialOrd)] pub enum AbstractValue { FunctionSelf, - List { item_pointers: Vec }, + List { + item_type: Type, + item_pointers: Vec, + }, } impl AbstractValue { @@ -13,10 +16,6 @@ impl AbstractValue { Value::Abstract(self) } - pub fn to_value_ref(&self) -> ValueRef { - ValueRef::Abstract(self) - } - pub fn to_concrete_owned(&self, vm: &Vm) -> ConcreteValue { match self { AbstractValue::FunctionSelf => ConcreteValue::function(vm.chunk().clone()), @@ -26,7 +25,7 @@ impl AbstractValue { for pointer in item_pointers { let item_option = vm.follow_pointer_allow_empty(*pointer); let item = match item_option { - Some(value_ref) => value_ref.into_concrete_owned(vm), + Some(value) => value.clone().into_concrete_owned(vm), None => continue, }; @@ -65,6 +64,13 @@ impl AbstractValue { Ok(display) } + + pub fn r#type(&self) -> Type { + match self { + AbstractValue::FunctionSelf => Type::SelfChunk, + AbstractValue::List { item_type, .. } => Type::List(Box::new(item_type.clone())), + } + } } impl Clone for AbstractValue { @@ -74,8 +80,10 @@ impl Clone for AbstractValue { match self { AbstractValue::FunctionSelf => AbstractValue::FunctionSelf, AbstractValue::List { + item_type: r#type, item_pointers: items, } => AbstractValue::List { + item_type: r#type.clone(), item_pointers: items.clone(), }, } diff --git a/dust-lang/src/value/concrete_value.rs b/dust-lang/src/value/concrete_value.rs index 13dd2ca..e0f6491 100644 --- a/dust-lang/src/value/concrete_value.rs +++ b/dust-lang/src/value/concrete_value.rs @@ -3,7 +3,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; use smartstring::{LazyCompact, SmartString}; -use crate::{Chunk, Type, Value, ValueError, ValueRef}; +use crate::{Chunk, Type, Value, ValueError}; use super::RangeValue; @@ -27,10 +27,6 @@ impl ConcreteValue { Value::Concrete(self) } - pub fn to_value_ref(&self) -> ValueRef { - ValueRef::Concrete(self) - } - pub fn function(chunk: Chunk) -> Self { ConcreteValue::Function(Box::new(chunk)) } diff --git a/dust-lang/src/value/mod.rs b/dust-lang/src/value/mod.rs index a6f0761..d8105ae 100644 --- a/dust-lang/src/value/mod.rs +++ b/dust-lang/src/value/mod.rs @@ -6,25 +6,20 @@ mod range_value; pub use abstract_value::AbstractValue; pub use concrete_value::{ConcreteValue, DustString}; pub use range_value::RangeValue; +use serde::{Deserialize, Serialize}; use std::fmt::{self, Debug, Display, Formatter}; -use crate::{Vm, VmError}; +use crate::{Type, Vm, VmError}; -#[derive(Clone, Debug, PartialEq, PartialOrd)] +#[derive(Clone, Debug, PartialEq, PartialOrd, Serialize, Deserialize)] pub enum Value { + #[serde(skip)] Abstract(AbstractValue), Concrete(ConcreteValue), } impl Value { - pub fn to_ref(&self) -> ValueRef { - match self { - Value::Abstract(abstract_value) => ValueRef::Abstract(abstract_value), - Value::Concrete(concrete_value) => ValueRef::Concrete(concrete_value), - } - } - pub fn into_concrete_owned(self, vm: &Vm) -> ConcreteValue { match self { Value::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), @@ -39,58 +34,24 @@ impl Value { None } } -} -impl Display for Value { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + pub fn r#type(&self) -> Type { match self { - Value::Abstract(abstract_value) => write!(f, "{}", abstract_value), - Value::Concrete(concrete_value) => write!(f, "{}", concrete_value), - } - } -} - -#[derive(Clone, Copy, Debug, PartialEq, PartialOrd)] -pub enum ValueRef<'a> { - Abstract(&'a AbstractValue), - Concrete(&'a ConcreteValue), -} - -impl ValueRef<'_> { - pub fn to_owned(&self) -> Value { - match self { - ValueRef::Abstract(abstract_value) => Value::Abstract((*abstract_value).clone()), - ValueRef::Concrete(concrete_value) => Value::Concrete((*concrete_value).clone()), + Value::Abstract(abstract_value) => abstract_value.r#type(), + Value::Concrete(concrete_value) => concrete_value.r#type(), } } - pub fn into_concrete_owned(self, vm: &Vm) -> ConcreteValue { - match self { - ValueRef::Abstract(abstract_value) => abstract_value.to_concrete_owned(vm), - ValueRef::Concrete(concrete_value) => concrete_value.clone(), - } - } - - pub fn display(&self, vm: &Vm) -> Result { - match self { - ValueRef::Abstract(abstract_value) => abstract_value.to_dust_string(vm), - ValueRef::Concrete(concrete_value) => Ok(concrete_value.to_dust_string()), - } - } - - #[inline(always)] - pub fn add(&self, other: ValueRef) -> Result { + pub fn add(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { - left.add(right).map(Value::Concrete) - } + (Value::Concrete(left), Value::Concrete(right)) => left.add(right).map(Value::Concrete), _ => Err(ValueError::CannotAdd(self.to_owned(), other.to_owned())), } } - pub fn subtract(&self, other: ValueRef) -> Result { + pub fn subtract(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + (Value::Concrete(left), Value::Concrete(right)) => { left.subtract(right).map(Value::Concrete) } _ => Err(ValueError::CannotSubtract( @@ -100,9 +61,9 @@ impl ValueRef<'_> { } } - pub fn multiply(&self, other: ValueRef) -> Result { + pub fn multiply(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + (Value::Concrete(left), Value::Concrete(right)) => { left.multiply(right).map(Value::Concrete) } _ => Err(ValueError::CannotMultiply( @@ -112,18 +73,18 @@ impl ValueRef<'_> { } } - pub fn divide(&self, other: ValueRef) -> Result { + pub fn divide(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + (Value::Concrete(left), Value::Concrete(right)) => { left.divide(right).map(Value::Concrete) } _ => Err(ValueError::CannotDivide(self.to_owned(), other.to_owned())), } } - pub fn modulo(&self, other: ValueRef) -> Result { + pub fn modulo(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + (Value::Concrete(left), Value::Concrete(right)) => { left.modulo(right).map(Value::Concrete) } _ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())), @@ -132,51 +93,58 @@ impl ValueRef<'_> { pub fn negate(&self) -> Result { match self { - ValueRef::Concrete(concrete_value) => concrete_value.negate().map(Value::Concrete), + Value::Concrete(concrete_value) => concrete_value.negate().map(Value::Concrete), _ => Err(ValueError::CannotNegate(self.to_owned())), } } pub fn not(&self) -> Result { match self { - ValueRef::Concrete(concrete_value) => concrete_value.not().map(Value::Concrete), + Value::Concrete(concrete_value) => concrete_value.not().map(Value::Concrete), _ => Err(ValueError::CannotNot(self.to_owned())), } } - pub fn equal(&self, other: ValueRef) -> Result { + pub fn equal(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + (Value::Concrete(left), Value::Concrete(right)) => { left.equal(right).map(Value::Concrete) } _ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())), } } - pub fn less(&self, other: ValueRef) -> Result { + pub fn less(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + (Value::Concrete(left), Value::Concrete(right)) => { left.less_than(right).map(Value::Concrete) } _ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())), } } - pub fn less_equal(&self, other: ValueRef) -> Result { + pub fn less_equal(&self, other: &Value) -> Result { match (self, other) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => { + (Value::Concrete(left), Value::Concrete(right)) => { left.less_than_or_equal(right).map(Value::Concrete) } _ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())), } } + + pub fn display(&self, vm: &Vm) -> Result { + match self { + Value::Abstract(abstract_value) => abstract_value.to_dust_string(vm), + Value::Concrete(concrete_value) => Ok(concrete_value.to_dust_string()), + } + } } -impl Display for ValueRef<'_> { +impl Display for Value { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { - ValueRef::Abstract(abstract_value) => write!(f, "{}", abstract_value), - ValueRef::Concrete(concrete_value) => write!(f, "{}", concrete_value), + Value::Abstract(abstract_value) => write!(f, "{}", abstract_value), + Value::Concrete(concrete_value) => write!(f, "{}", concrete_value), } } } diff --git a/dust-lang/src/vm/mod.rs b/dust-lang/src/vm/mod.rs index 896bc32..d6035d4 100644 --- a/dust-lang/src/vm/mod.rs +++ b/dust-lang/src/vm/mod.rs @@ -4,6 +4,7 @@ mod runners; use std::{ fmt::{self, Display, Formatter}, io, iter, + rc::Rc, }; use runners::Runner; @@ -11,10 +12,10 @@ use smallvec::SmallVec; use crate::{ compile, instruction::*, AbstractValue, AnnotatedError, Chunk, ConcreteValue, DustError, - NativeFunctionError, Span, Value, ValueError, ValueRef, + NativeFunctionError, Span, Value, ValueError, }; -pub fn run(source: &str) -> Result, DustError> { +pub fn run(source: &str) -> Result, DustError> { let chunk = compile(source)?; let vm = Vm::new(source, &chunk, None, None); @@ -35,7 +36,7 @@ pub struct Vm<'a> { ip: usize, last_assigned_register: Option, source: &'a str, - return_value: Option, + return_value: Option, } impl<'a> Vm<'a> { @@ -85,26 +86,31 @@ impl<'a> Vm<'a> { position } - pub fn run(mut self) -> Option { + pub fn run(mut self) -> Option { while self.ip < self.runners.len() && self.return_value.is_none() { - let runner = self.runners[self.ip]; - - runner.run(&mut self); + self.execute_next_runner(); } self.return_value } - pub(crate) fn follow_pointer(&self, pointer: Pointer) -> ValueRef { + pub fn execute_next_runner(&mut self) { + assert!( + self.ip < self.runners.len(), + "Runtime Error: IP out of bounds" + ); + + let runner = self.runners[self.ip]; + + runner.run(self); + } + + pub(crate) fn follow_pointer(&self, pointer: Pointer) -> &Value { log::trace!("Follow pointer {pointer}"); match pointer { Pointer::Stack(register_index) => self.open_register(register_index), - Pointer::Constant(constant_index) => { - let constant = self.get_constant(constant_index); - - ValueRef::Concrete(constant) - } + Pointer::Constant(constant_index) => self.get_constant(constant_index), Pointer::ParentStack(register_index) => { assert!(self.parent.is_some(), "Vm Error: Expected parent"); @@ -113,15 +119,12 @@ impl<'a> Vm<'a> { Pointer::ParentConstant(constant_index) => { assert!(self.parent.is_some(), "Vm Error: Expected parent"); - self.parent - .unwrap() - .get_constant(constant_index) - .to_value_ref() + self.parent.unwrap().get_constant(constant_index) } } } - pub(crate) fn follow_pointer_allow_empty(&self, pointer: Pointer) -> Option { + pub(crate) fn follow_pointer_allow_empty(&self, pointer: Pointer) -> Option<&Value> { log::trace!("Follow pointer {pointer}"); match pointer { @@ -129,7 +132,7 @@ impl<'a> Vm<'a> { Pointer::Constant(constant_index) => { let constant = self.get_constant(constant_index); - Some(ValueRef::Concrete(constant)) + Some(constant) } Pointer::ParentStack(register_index) => { assert!(self.parent.is_some(), "Vm Error: Expected parent"); @@ -141,18 +144,14 @@ impl<'a> Vm<'a> { Pointer::ParentConstant(constant_index) => { assert!(self.parent.is_some(), "Vm Error: Expected parent"); - let constant = self - .parent - .unwrap() - .get_constant(constant_index) - .to_value_ref(); + let constant = self.parent.unwrap().get_constant(constant_index); Some(constant) } } } - fn open_register(&self, register_index: u8) -> ValueRef { + fn open_register(&self, register_index: u8) -> &Value { log::trace!("Open register R{register_index}"); let register_index = register_index as usize; @@ -165,13 +164,13 @@ impl<'a> Vm<'a> { let register = &self.stack[register_index]; match register { - Register::Value(value) => value.to_ref(), + Register::Value(value) => value, Register::Pointer(pointer) => self.follow_pointer(*pointer), Register::Empty => panic!("VM Error: Register {register_index} is empty"), } } - fn open_register_allow_empty(&self, register_index: u8) -> Option { + fn open_register_allow_empty(&self, register_index: u8) -> Option<&Value> { log::trace!("Open register R{register_index}"); let register_index = register_index as usize; @@ -184,7 +183,7 @@ impl<'a> Vm<'a> { let register = &self.stack[register_index]; match register { - Register::Value(value) => Some(value.to_ref()), + Register::Value(value) => Some(value), Register::Pointer(pointer) => Some(self.follow_pointer(*pointer)), Register::Empty => None, } @@ -209,9 +208,9 @@ impl<'a> Vm<'a> { } /// DRY helper to get a value from an Argument - fn get_argument(&self, index: u8, is_constant: bool) -> ValueRef { + fn get_argument(&self, index: u8, is_constant: bool) -> &Value { if is_constant { - self.get_constant(index).to_value_ref() + self.get_constant(index) } else { self.open_register(index) } @@ -229,7 +228,7 @@ impl<'a> Vm<'a> { self.stack[to_register] = register; } - fn get_constant(&self, constant_index: u8) -> &ConcreteValue { + fn get_constant(&self, constant_index: u8) -> &Value { let constant_index = constant_index as usize; let constants = self.chunk.constants(); diff --git a/dust-lang/src/vm/runners.rs b/dust-lang/src/vm/runners.rs index 9fb33ac..9eb8c9a 100644 --- a/dust-lang/src/vm/runners.rs +++ b/dust-lang/src/vm/runners.rs @@ -1,6 +1,8 @@ +use std::{borrow::BorrowMut, cell::RefCell, rc::Rc}; + use smallvec::SmallVec; -use crate::{AbstractValue, ConcreteValue, NativeFunction, Value, ValueRef}; +use crate::{AbstractValue, ConcreteValue, NativeFunction, Type, Value}; use super::{Instruction, InstructionData, Pointer, Register, Vm}; @@ -56,8 +58,7 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 24] = [ r#return, ]; -#[allow(clippy::needless_lifetimes)] -pub fn r#move<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { +pub fn r#move(vm: &mut Vm, instruction_data: InstructionData) { let InstructionData { b, c, .. } = instruction_data; let from_register_has_value = vm .stack @@ -71,9 +72,7 @@ pub fn r#move<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -93,9 +92,7 @@ pub fn close<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -112,9 +109,7 @@ pub fn load_boolean<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionDat vm.ip += 1; } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -130,20 +125,29 @@ pub fn load_constant<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionDa vm.ip += 1; } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] pub fn load_list<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { let InstructionData { a, b, .. } = instruction_data; - let mut item_pointers = Vec::new(); + let mut item_pointers = Vec::with_capacity((a - b) as usize); let stack = vm.stack.as_slice(); + let mut item_type = Type::Any; for register_index in b..a { - if let Register::Empty = stack[register_index as usize] { - continue; + match &stack[register_index as usize] { + 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 = vm.follow_pointer(*pointer).r#type(); + } + } } let pointer = Pointer::Stack(register_index); @@ -151,16 +155,18 @@ pub fn load_list<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) item_pointers.push(pointer); } - let list_value = AbstractValue::List { item_pointers }.to_value(); + let list_value = AbstractValue::List { + item_type, + item_pointers, + } + .to_value(); let register = Register::Value(list_value); vm.set_register(a, register); vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -172,9 +178,7 @@ pub fn load_self<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -187,9 +191,7 @@ pub fn get_local<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -202,9 +204,7 @@ pub fn set_local<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -220,7 +220,7 @@ pub fn add<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { let left = vm.get_argument(b, b_is_constant); let right = vm.get_argument(c, c_is_constant); let sum = match (left, right) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) { + (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { ConcreteValue::Integer(left + right).to_value() } @@ -234,9 +234,7 @@ pub fn add<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -252,7 +250,7 @@ pub fn subtract<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { let left = vm.get_argument(b, b_is_constant); let right = vm.get_argument(c, c_is_constant); let difference = match (left, right) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) { + (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { ConcreteValue::Integer(left - right).to_value() } @@ -266,9 +264,7 @@ pub fn subtract<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -284,7 +280,7 @@ pub fn multiply<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { let left = vm.get_argument(b, b_is_constant); let right = vm.get_argument(c, c_is_constant); let product = match (left, right) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) { + (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { ConcreteValue::Integer(left * right).to_value() } @@ -298,9 +294,7 @@ pub fn multiply<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -316,7 +310,7 @@ pub fn divide<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { let left = vm.get_argument(b, b_is_constant); let right = vm.get_argument(c, c_is_constant); let quotient = match (left, right) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) { + (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { ConcreteValue::Integer(left / right).to_value() } @@ -330,9 +324,7 @@ pub fn divide<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -348,7 +340,7 @@ pub fn modulo<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { let left = vm.get_argument(b, b_is_constant); let right = vm.get_argument(c, c_is_constant); let remainder = match (left, right) { - (ValueRef::Concrete(left), ValueRef::Concrete(right)) => match (left, right) { + (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { ConcreteValue::Integer(left % right).to_value() } @@ -362,9 +354,7 @@ pub fn modulo<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -376,7 +366,7 @@ pub fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { .. } = instruction_data; let value = vm.get_argument(b, b_is_constant); - let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value { + let boolean = if let Value::Concrete(ConcreteValue::Boolean(boolean)) = value { *boolean } else { panic!( @@ -392,9 +382,7 @@ pub fn test<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -407,7 +395,7 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { .. } = instruction_data; let value = vm.get_argument(b, b_is_constant); - let boolean = if let ValueRef::Concrete(ConcreteValue::Boolean(boolean)) = value { + let boolean = if let Value::Concrete(ConcreteValue::Boolean(boolean)) = value { *boolean } else { panic!( @@ -432,9 +420,7 @@ pub fn test_set<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -457,13 +443,10 @@ pub fn equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } -#[allow(clippy::needless_lifetimes)] -pub fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { +pub fn less(vm: &mut Vm, instruction_data: InstructionData) { let InstructionData { b, c, @@ -482,9 +465,7 @@ pub fn less<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -507,9 +488,7 @@ pub fn less_equal<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) vm.ip += 1; } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -522,12 +501,12 @@ pub fn negate<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { } = instruction_data; let argument = vm.get_argument(b, b_is_constant); let negated = match argument { - ValueRef::Concrete(value) => match value { + Value::Concrete(value) => match value { ConcreteValue::Float(float) => ConcreteValue::Float(-float), ConcreteValue::Integer(integer) => ConcreteValue::Integer(-integer), _ => panic!("Value Error: Cannot negate value"), }, - ValueRef::Abstract(_) => panic!("VM Error: Cannot negate value"), + Value::Abstract(_) => panic!("VM Error: Cannot negate value"), }; let register = Register::Value(Value::Concrete(negated)); @@ -535,9 +514,7 @@ pub fn negate<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -550,7 +527,7 @@ pub fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { } = instruction_data; let argument = vm.get_argument(b, b_is_constant); let not = match argument { - ValueRef::Concrete(ConcreteValue::Boolean(boolean)) => ConcreteValue::Boolean(!boolean), + Value::Concrete(ConcreteValue::Boolean(boolean)) => ConcreteValue::Boolean(!boolean), _ => panic!("VM Error: Expected boolean value for NOT operation"), }; let register = Register::Value(Value::Concrete(not)); @@ -559,9 +536,7 @@ pub fn not<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -576,9 +551,7 @@ pub fn jump<'c>(vm: &mut Vm<'c>, instruction_data: InstructionData) { vm.ip -= offset } - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -591,9 +564,9 @@ pub fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { .. } = instruction_data; let function = vm.get_argument(b, b_is_constant); - let mut function_vm = if let ValueRef::Concrete(ConcreteValue::Function(chunk)) = function { + let mut function_vm = if let Value::Concrete(ConcreteValue::Function(chunk)) = function { Vm::new(vm.source, chunk, Some(vm), None) - } else if let ValueRef::Abstract(AbstractValue::FunctionSelf) = function { + } else if let Value::Abstract(AbstractValue::FunctionSelf) = function { Vm::new(vm.source, vm.chunk, Some(vm), Some(vm.runners.clone())) } else { panic!("VM Error: Expected function") @@ -620,16 +593,14 @@ pub fn call<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { let return_value = function_vm.run(); if let Some(concrete_value) = return_value { - let register = Register::Value(concrete_value.to_value()); + let register = Register::Value(concrete_value); vm.set_register(a, register); } vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -637,12 +608,12 @@ pub fn call_native<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData let InstructionData { a, b, c, .. } = instruction_data; let first_argument_index = (a - c) as usize; let argument_range = first_argument_index..a as usize; - let mut arguments: SmallVec<[ValueRef; 4]> = SmallVec::new(); + let mut arguments: SmallVec<[&Value; 4]> = SmallVec::new(); for register_index in argument_range { let register = &vm.stack[register_index]; let value = match register { - Register::Value(value) => value.to_ref(), + Register::Value(value) => value, Register::Pointer(pointer) => { let value_option = vm.follow_pointer_allow_empty(*pointer); @@ -668,9 +639,7 @@ pub fn call_native<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData vm.ip += 1; - let next = vm.runners[vm.ip]; - - next.run(vm); + vm.execute_next_runner(); } #[allow(clippy::needless_lifetimes)] @@ -682,7 +651,7 @@ pub fn r#return<'b, 'c>(vm: &'b mut Vm<'c>, instruction_data: InstructionData) { } if let Some(register_index) = &vm.last_assigned_register { - let return_value = vm.open_register(*register_index).into_concrete_owned(vm); + let return_value = vm.open_register(*register_index).clone(); vm.return_value = Some(return_value); } else {