diff --git a/dust-lang/src/instruction/mod.rs b/dust-lang/src/instruction/mod.rs index b3a4907..e670a86 100644 --- a/dust-lang/src/instruction/mod.rs +++ b/dust-lang/src/instruction/mod.rs @@ -366,6 +366,10 @@ impl Instruction { } } + pub fn no_op() -> Instruction { + Instruction(Operation::NO_OP.0 as u64) + } + pub fn point(destination: u16, to: Operand) -> Instruction { Instruction::from(Point { destination, to }) } diff --git a/dust-lang/src/instruction/operation.rs b/dust-lang/src/instruction/operation.rs index b4a22fd..6299971 100644 --- a/dust-lang/src/instruction/operation.rs +++ b/dust-lang/src/instruction/operation.rs @@ -9,49 +9,52 @@ use serde::{Deserialize, Serialize}; pub struct Operation(pub u8); impl Operation { + pub const NO_OP: Operation = Operation(0); + // Stack manipulation - pub const POINT: Operation = Operation(0); - pub const CLOSE: Operation = Operation(1); + pub const POINT: Operation = Operation(1); + pub const CLOSE: Operation = Operation(2); // Loaders - pub const LOAD_ENCODED: Operation = Operation(2); - pub const LOAD_CONSTANT: Operation = Operation(3); - pub const LOAD_FUNCTION: Operation = Operation(4); - pub const LOAD_LIST: Operation = Operation(5); - pub const LOAD_SELF: Operation = Operation(6); + pub const LOAD_ENCODED: Operation = Operation(3); + pub const LOAD_CONSTANT: Operation = Operation(4); + pub const LOAD_FUNCTION: Operation = Operation(5); + pub const LOAD_LIST: Operation = Operation(6); + pub const LOAD_SELF: Operation = Operation(7); // Arithmetic - 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); + pub const ADD: Operation = Operation(8); + pub const SUBTRACT: Operation = Operation(9); + pub const MULTIPLY: Operation = Operation(10); + pub const DIVIDE: Operation = Operation(11); + pub const MODULO: Operation = Operation(12); // Comparison - pub const EQUAL: Operation = Operation(12); - pub const LESS: Operation = Operation(13); - pub const LESS_EQUAL: Operation = Operation(14); + pub const EQUAL: Operation = Operation(13); + pub const LESS: Operation = Operation(14); + pub const LESS_EQUAL: Operation = Operation(15); // Unary operations - pub const NEGATE: Operation = Operation(15); - pub const NOT: Operation = Operation(16); + pub const NEGATE: Operation = Operation(16); + pub const NOT: Operation = Operation(17); // Logical operations - pub const TEST: Operation = Operation(17); - pub const TEST_SET: Operation = Operation(18); + pub const TEST: Operation = Operation(18); + pub const TEST_SET: Operation = Operation(19); // Function calls - pub const CALL: Operation = Operation(19); - pub const CALL_NATIVE: Operation = Operation(20); + pub const CALL: Operation = Operation(20); + pub const CALL_NATIVE: Operation = Operation(21); // Control flow - pub const JUMP: Operation = Operation(21); - pub const RETURN: Operation = Operation(22); + pub const JUMP: Operation = Operation(22); + pub const RETURN: Operation = Operation(23); } impl Operation { pub fn name(&self) -> &'static str { match *self { + Self::NO_OP => "NO_OP", Self::POINT => "POINT", Self::CLOSE => "CLOSE", Self::LOAD_ENCODED => "LOAD_ENCODED", diff --git a/dust-lang/src/value/abstract_list.rs b/dust-lang/src/value/abstract_list.rs index 14be0f1..39122b2 100644 --- a/dust-lang/src/value/abstract_list.rs +++ b/dust-lang/src/value/abstract_list.rs @@ -43,6 +43,15 @@ impl AbstractList { } } +impl Default for AbstractList { + fn default() -> Self { + Self { + item_type: TypeCode::NONE, + item_pointers: Vec::new(), + } + } +} + impl Display for AbstractList { fn fmt(&self, f: &mut Formatter) -> fmt::Result { write!(f, "[")?; diff --git a/dust-lang/src/value/function.rs b/dust-lang/src/value/function.rs index f331dcf..08f9089 100644 --- a/dust-lang/src/value/function.rs +++ b/dust-lang/src/value/function.rs @@ -11,6 +11,16 @@ pub struct Function { pub prototype_index: u16, } +impl Default for Function { + fn default() -> Self { + Self { + name: None, + r#type: FunctionType::default(), + prototype_index: 0, + } + } +} + impl Display for Function { fn fmt(&self, f: &mut Formatter) -> fmt::Result { let mut type_string = self.r#type.to_string(); diff --git a/dust-lang/src/vm/action/add.rs b/dust-lang/src/vm/action/add.rs new file mode 100644 index 0000000..ce0de5a --- /dev/null +++ b/dust-lang/src/vm/action/add.rs @@ -0,0 +1,259 @@ +use tracing::trace; + +use crate::{ + DustString, + instruction::{InstructionFields, TypeCode}, + vm::{Register, Thread, call_frame::PointerCache}, +}; + +pub fn add( + _: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + pointer_cache: &mut PointerCache, +) { + let destination = instruction.a_field as usize; + let left = instruction.b_field as usize; + let left_is_constant = instruction.b_is_constant; + let left_type = instruction.b_type; + let right = instruction.c_field as usize; + let right_is_constant = instruction.c_is_constant; + let right_type = instruction.c_type; + + match (left_type, right_type) { + (TypeCode::INTEGER, TypeCode::INTEGER) => add_integers(instruction, thread, pointer_cache), + (TypeCode::BYTE, TypeCode::BYTE) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_byte().unwrap() + } else { + unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() } + } + } else { + thread.get_byte_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_byte().unwrap() + } else { + unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() } + } + } else { + thread.get_byte_register(right) + }; + let sum = left_value + right_value; + let register = Register::Value(sum); + + thread.set_byte_register(destination, register); + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_float().unwrap() + } else { + unsafe { thread.get_constant(left).as_float().unwrap_unchecked() } + } + } else { + thread.get_float_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_float().unwrap() + } else { + unsafe { thread.get_constant(right).as_float().unwrap_unchecked() } + } + } else { + thread.get_float_register(right) + }; + let sum = left_value + right_value; + let register = Register::Value(sum); + + thread.set_float_register(destination, register); + } + (TypeCode::STRING, TypeCode::STRING) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_string().unwrap().clone() + } else { + unsafe { + thread + .get_constant(left) + .as_string() + .unwrap_unchecked() + .clone() + } + } + } else { + thread.get_string_register(left).clone() + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_string().unwrap().clone() + } else { + unsafe { + thread + .get_constant(right) + .as_string() + .unwrap_unchecked() + .clone() + } + } + } else { + thread.get_string_register(right).clone() + }; + let concatenated = left_value + &right_value; + let register = Register::Value(concatenated); + + thread.set_string_register(destination, register); + } + (TypeCode::CHARACTER, TypeCode::CHARACTER) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_character().unwrap() + } else { + unsafe { thread.get_constant(left).as_character().unwrap_unchecked() } + } + } else { + thread.get_character_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_character().unwrap() + } else { + unsafe { thread.get_constant(right).as_character().unwrap_unchecked() } + } + } else { + thread.get_character_register(right) + }; + let mut sum = DustString::new(); + + sum.push(*left_value); + sum.push(*right_value); + + let register = Register::Value(sum); + + thread.set_string_register(destination, register); + } + (TypeCode::STRING, TypeCode::CHARACTER) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_string().unwrap().clone() + } else { + unsafe { + thread + .get_constant(left) + .as_string() + .unwrap_unchecked() + .clone() + } + } + } else { + thread.get_string_register(left).clone() + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_character().unwrap() + } else { + unsafe { thread.get_constant(right).as_character().unwrap_unchecked() } + } + } else { + thread.get_character_register(right) + }; + let mut sum = left_value.clone(); + + sum.push(*right_value); + + let register = Register::Value(sum); + + thread.set_string_register(destination, register); + } + (TypeCode::CHARACTER, TypeCode::STRING) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_character().unwrap() + } else { + unsafe { thread.get_constant(left).as_character().unwrap_unchecked() } + } + } else { + thread.get_character_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_string().unwrap() + } else { + unsafe { thread.get_constant(right).as_string().unwrap_unchecked() } + } + } else { + thread.get_string_register(right) + }; + let mut sum = right_value.clone(); + + sum.insert(0, *left_value); + + let register = Register::Value(sum); + + thread.set_string_register(destination, register); + } + _ => unreachable!(), + } +} + +pub fn add_integers( + instruction: InstructionFields, + thread: &mut Thread, + pointer_cache: &mut PointerCache, +) { + let destination = instruction.a_field as usize; + let left = instruction.b_field as usize; + let left_is_constant = instruction.b_is_constant; + let right = instruction.c_field as usize; + let right_is_constant = instruction.c_is_constant; + + if pointer_cache.integer_mut.is_null() { + trace!("ADD: Run and cache pointers"); + + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_integer().unwrap() + } else { + unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() } + } + } else { + thread.get_integer_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_integer().unwrap() + } else { + unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() } + } + } else { + thread.get_integer_register(right) + }; + let sum = left_value.saturating_add(*right_value); + + pointer_cache.integer_left = left_value; + pointer_cache.integer_right = right_value; + pointer_cache.integer_mut = thread.get_integer_register_mut_allow_empty(destination); + + thread.set_integer_register(destination, Register::Value(sum)); + } else { + trace!("ADD: Use cached pointers"); + + add_integer_pointers( + pointer_cache.integer_mut, + pointer_cache.integer_left, + pointer_cache.integer_right, + ); + }; +} + +pub fn add_integer_pointers(destination: *mut i64, left: *const i64, right: *const i64) { + assert!(destination.is_aligned()); + assert!(left.is_aligned()); + assert!(right.is_aligned()); + + unsafe { + *destination = (*left).saturating_add(*right); + } +} diff --git a/dust-lang/src/vm/action/jump.rs b/dust-lang/src/vm/action/jump.rs new file mode 100644 index 0000000..db25e26 --- /dev/null +++ b/dust-lang/src/vm/action/jump.rs @@ -0,0 +1,28 @@ +use tracing::trace; + +use crate::{ + instruction::InstructionFields, + vm::{Thread, call_frame::PointerCache}, +}; + +pub fn jump( + ip: &mut usize, + instruction: InstructionFields, + _: &mut Thread, + _pointer_cache: &mut PointerCache, +) { + let offset = instruction.b_field as usize; + let is_positive = instruction.c_field != 0; + + if is_positive { + trace!("JUMP +{}", offset); + } else { + trace!("JUMP -{}", offset); + } + + if is_positive { + *ip += offset; + } else { + *ip -= offset + 1; + } +} diff --git a/dust-lang/src/vm/action/less.rs b/dust-lang/src/vm/action/less.rs new file mode 100644 index 0000000..5c9e6ad --- /dev/null +++ b/dust-lang/src/vm/action/less.rs @@ -0,0 +1,232 @@ +use tracing::trace; + +use crate::{ + instruction::{InstructionFields, TypeCode}, + vm::{Thread, call_frame::PointerCache}, +}; + +pub fn less( + ip: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + pointer_cache: &mut PointerCache, +) { + let comparator = instruction.d_field; + let left = instruction.b_field as usize; + let left_type = instruction.b_type; + let left_is_constant = instruction.b_is_constant; + let right = instruction.c_field as usize; + let right_type = instruction.c_type; + let right_is_constant = instruction.c_is_constant; + + match (left_type, right_type) { + (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_boolean().unwrap() + } else { + unsafe { thread.get_constant(left).as_boolean().unwrap_unchecked() } + } + } else { + thread.get_boolean_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_boolean().unwrap() + } else { + unsafe { thread.get_constant(right).as_boolean().unwrap_unchecked() } + } + } else { + thread.get_boolean_register(right) + }; + let result = left_value < right_value; + + if result == comparator { + *ip += 1; + } + } + (TypeCode::BYTE, TypeCode::BYTE) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_byte().unwrap() + } else { + unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() } + } + } else { + thread.get_byte_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_byte().unwrap() + } else { + unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() } + } + } else { + thread.get_byte_register(right) + }; + let result = left_value < right_value; + + if result == comparator { + *ip += 1; + } + } + (TypeCode::CHARACTER, TypeCode::CHARACTER) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_character().unwrap() + } else { + unsafe { thread.get_constant(left).as_character().unwrap_unchecked() } + } + } else { + thread.get_character_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_character().unwrap() + } else { + unsafe { thread.get_constant(right).as_character().unwrap_unchecked() } + } + } else { + thread.get_character_register(right) + }; + let result = left_value < right_value; + + if result == comparator { + *ip += 1; + } + } + (TypeCode::FLOAT, TypeCode::FLOAT) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_float().unwrap() + } else { + unsafe { thread.get_constant(left).as_float().unwrap_unchecked() } + } + } else { + thread.get_float_register(left) + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_float().unwrap() + } else { + unsafe { thread.get_constant(right).as_float().unwrap_unchecked() } + } + } else { + thread.get_float_register(right) + }; + let result = left_value < right_value; + + if result == comparator { + *ip += 1; + } + } + (TypeCode::INTEGER, TypeCode::INTEGER) => { + less_integers(ip, instruction, thread, pointer_cache) + } + (TypeCode::STRING, TypeCode::STRING) => { + let left_value = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_string().unwrap().clone() + } else { + unsafe { + thread + .get_constant(left) + .as_string() + .unwrap_unchecked() + .clone() + } + } + } else { + thread.get_string_register(left).clone() + }; + let right_value = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_string().unwrap().clone() + } else { + unsafe { + thread + .get_constant(right) + .as_string() + .unwrap_unchecked() + .clone() + } + } + } else { + thread.get_string_register(right).clone() + }; + let result = left_value < right_value; + + if result == comparator { + *ip += 1; + } + } + _ => unreachable!(), + } +} + +pub fn less_integers( + ip: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + pointer_cache: &mut PointerCache, +) { + if pointer_cache.integer_left.is_null() { + trace!("LESS: Run and cache pointers"); + + let left = instruction.b_field as usize; + let left_is_constant = instruction.b_is_constant; + let right = instruction.c_field as usize; + let right_is_constant = instruction.c_is_constant; + let left_pointer = if left_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(left).as_integer().unwrap() + } else { + unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() } + } + } else { + thread.get_integer_register(left) + } as *const i64; + let right_pointer = if right_is_constant { + if cfg!(debug_assertions) { + thread.get_constant(right).as_integer().unwrap() + } else { + unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() } + } + } else { + thread.get_integer_register(right) + } as *const i64; + + pointer_cache.integer_left = left_pointer; + pointer_cache.integer_right = right_pointer; + + less_integer_pointers(ip, left_pointer, right_pointer, instruction.d_field); + } else { + trace!("LESS: Use cached pointers"); + + less_integer_pointers( + ip, + pointer_cache.integer_left, + pointer_cache.integer_right, + instruction.d_field, + ); + }; +} + +pub fn less_integer_pointers( + ip: *mut usize, + left: *const i64, + right: *const i64, + comparator: bool, +) { + assert!(ip.is_aligned()); + assert!(left.is_aligned()); + assert!(right.is_aligned()); + + unsafe { + let is_less_than = *left < *right; + + if is_less_than == comparator { + *ip += 1; + } + } +} diff --git a/dust-lang/src/vm/action.rs b/dust-lang/src/vm/action/mod.rs similarity index 62% rename from dust-lang/src/vm/action.rs rename to dust-lang/src/vm/action/mod.rs index 7e95650..e23bc54 100644 --- a/dust-lang/src/vm/action.rs +++ b/dust-lang/src/vm/action/mod.rs @@ -1,52 +1,63 @@ -use std::{ - arch::asm, - fmt::{self, Display, Formatter}, -}; +mod add; +mod jump; +mod less; + +use add::{add, add_integer_pointers}; +use jump::jump; +use less::{less, less_integer_pointers}; + +use tracing::trace; + +use std::fmt::{self, Display, Formatter}; use crate::{ - AbstractList, ConcreteValue, DustString, Instruction, Operation, Value, - instruction::{InstructionFields, Jump, TypeCode}, + AbstractList, ConcreteValue, Operation, Value, + instruction::{InstructionFields, TypeCode}, + vm::call_frame::PointerCache, }; -use super::{Pointer, Register, call_frame::PointerCache, thread::Thread}; +use super::{Pointer, Register, thread::Thread}; -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct ActionSequence { pub actions: Vec, } impl ActionSequence { #[allow(clippy::while_let_on_iterator)] - pub fn new(instructions: &[Instruction]) -> Self { - let mut instructions = instructions.iter().rev(); + pub fn new(instructions: T) -> Self + where + T: ExactSizeIterator + DoubleEndedIterator + Clone, + { let mut actions = Vec::with_capacity(instructions.len()); + let mut instructions_reversed = instructions.rev(); + let mut in_loop = false; - while let Some(instruction) = instructions.next() { - if instruction.operation() == Operation::JUMP { - let Jump { - offset: backward_offset, - is_positive, - } = Jump::from(instruction); + while let Some(instruction) = instructions_reversed.next() { + if instruction.operation == Operation::JUMP { + let backward_offset = instruction.b_field as usize; + let is_positive = instruction.c_field != 0; if !is_positive { + let mut loop_instructions = Vec::new(); let mut previous = instruction; - actions.push(Action::optimized(instruction)); + in_loop = true; - while let Some(instruction) = instructions.next() { - actions.push(Action::optimized(instruction)); + loop_instructions.push(instruction); - if matches!( - instruction.operation(), - Operation::EQUAL | Operation::LESS | Operation::LESS_EQUAL - ) && previous.operation() == Operation::JUMP + while let Some(instruction) = instructions_reversed.next() { + loop_instructions.push(instruction); + + if instruction.operation == Operation::LESS + && previous.operation == Operation::JUMP { - let Jump { - offset: forward_offset, - is_positive, - } = Jump::from(previous); + let forward_offset = previous.b_field as usize; + let is_positive = previous.c_field != 0; if is_positive && forward_offset == backward_offset - 1 { + in_loop = false; + break; } } @@ -54,11 +65,21 @@ impl ActionSequence { previous = instruction; } + loop_instructions.reverse(); + + let loop_action = Action::optimized_loop(loop_instructions); + + actions.push(loop_action); + continue; } } - let action = Action::unoptimized(instruction); + let action = if in_loop { + Action::optimized_inline(instruction) + } else { + Action::unoptimized(instruction) + }; actions.push(action); } @@ -71,6 +92,58 @@ impl ActionSequence { pub fn len(&self) -> usize { self.actions.len() } + + pub fn run(&self, thread: &mut Thread) { + let mut pointer_caches = vec![PointerCache::new(); self.actions.len()]; + let mut local_ip = 0; + + while local_ip < self.actions.len() { + assert!(local_ip < self.actions.len()); + assert!(local_ip < pointer_caches.len()); + + let action = &self.actions[local_ip]; + let cache = &mut pointer_caches[local_ip]; + local_ip += 1; + + trace!("Run {action}"); + + if let Some(loop_actions) = &action.loop_actions { + loop_actions.run(thread); + } else if action.optimize_inline { + match action.instruction.operation { + Operation::ADD => { + if cache.integer_mut.is_null() { + add(&mut local_ip, action.instruction, thread, cache); + } else { + add_integer_pointers( + cache.integer_mut, + cache.integer_left, + cache.integer_right, + ); + } + } + Operation::LESS => { + if cache.integer_left.is_null() { + less(&mut local_ip, action.instruction, thread, cache); + } else { + less_integer_pointers( + &mut local_ip, + cache.integer_left, + cache.integer_right, + action.instruction.d_field, + ); + } + } + Operation::JUMP => jump(&mut local_ip, action.instruction, thread, cache), + _ => { + (action.logic)(&mut local_ip, action.instruction, thread, cache); + } + } + } else { + (action.logic)(&mut local_ip, action.instruction, thread, cache); + } + } + } } impl Display for ActionSequence { @@ -78,7 +151,7 @@ impl Display for ActionSequence { write!(f, "[")?; for (index, action) in self.actions.iter().enumerate() { - write!(f, "{}", action.name)?; + write!(f, "{action}")?; if index < self.actions.len() - 1 { write!(f, ", ")?; @@ -89,40 +162,44 @@ impl Display for ActionSequence { } } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Debug)] pub struct Action { - pub name: &'static str, pub logic: ActionLogic, pub instruction: InstructionFields, + pub optimize_inline: bool, + pub loop_actions: Option, } impl Action { - fn optimized(instruction: &Instruction) -> Self { - let instruction = InstructionFields::from(instruction); - let (name, logic): (&'static str, ActionLogic) = match ( - instruction.operation, - instruction.b_type, - instruction.c_type, - ) { - (Operation::ADD, TypeCode::INTEGER, TypeCode::INTEGER) => { - ("ADD_INTEGERS", add_integers_optimized) - } - (Operation::LESS, TypeCode::INTEGER, TypeCode::INTEGER) => { - ("LESS_INTEGERS", less_integers_optimized) - } - (Operation::JUMP, _, _) => ("JUMP", jump), - _ => todo!(), - }; + fn optimized_loop(instructions: Vec) -> Self { + let mut loop_actions = Vec::with_capacity(instructions.len()); + + for instruction in instructions { + let action = Action::optimized_inline(instruction); + + loop_actions.push(action); + } Action { - name, - logic, - instruction, + logic: no_op, + instruction: InstructionFields::default(), + optimize_inline: false, + loop_actions: Some(ActionSequence { + actions: loop_actions, + }), } } - fn unoptimized(instruction: &Instruction) -> Self { - let instruction = InstructionFields::from(instruction); + fn optimized_inline(instruction: InstructionFields) -> Self { + Action { + logic: no_op, + optimize_inline: true, + instruction, + loop_actions: None, + } + } + + fn unoptimized(instruction: InstructionFields) -> Self { let logic = match instruction.operation { Operation::POINT => point, Operation::CLOSE => close, @@ -141,21 +218,35 @@ impl Action { Operation::LESS_EQUAL => less_equal, Operation::TEST => test, Operation::TEST_SET => test_set, + Operation::JUMP => jump, Operation::RETURN => r#return, _ => todo!(), }; Action { - name: instruction.operation.name(), logic, instruction, + optimize_inline: false, + loop_actions: None, } } } -pub type ActionLogic = fn(InstructionFields, &mut Thread); +impl Display for Action { + fn fmt(&self, f: &mut Formatter) -> fmt::Result { + if let Some(action_sequence) = &self.loop_actions { + write!(f, "LOOP: {action_sequence}") + } else { + write!(f, "{}", self.instruction.operation) + } + } +} -pub fn point(instruction: InstructionFields, thread: &mut Thread) { +pub type ActionLogic = fn(&mut usize, InstructionFields, &mut Thread, &mut PointerCache); + +fn no_op(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {} + +fn point(_: &mut usize, instruction: InstructionFields, thread: &mut Thread, _: &mut PointerCache) { let destination = instruction.a_field as usize; let to = instruction.b_field as usize; let to_is_constant = instruction.b_is_constant; @@ -262,7 +353,7 @@ pub fn point(instruction: InstructionFields, thread: &mut Thread) { } } -pub fn close(instruction: InstructionFields, thread: &mut Thread) { +fn close(_: &mut usize, instruction: InstructionFields, thread: &mut Thread, _: &mut PointerCache) { let from = instruction.b_field as usize; let to = instruction.c_field as usize; let r#type = instruction.b_type; @@ -307,7 +398,12 @@ pub fn close(instruction: InstructionFields, thread: &mut Thread) { } } -pub fn load_encoded(instruction: InstructionFields, thread: &mut Thread) { +fn load_encoded( + ip: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let destination = instruction.a_field; let value = instruction.b_field; let value_type = instruction.b_type; @@ -328,11 +424,16 @@ pub fn load_encoded(instruction: InstructionFields, thread: &mut Thread) { } if jump_next { - thread.current_frame_mut().ip += 1; + *ip += 1; } } -pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) { +fn load_constant( + ip: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let destination = instruction.a_field as usize; let constant_index = instruction.b_field as usize; let constant_type = instruction.b_type; @@ -366,11 +467,16 @@ pub fn load_constant(instruction: InstructionFields, thread: &mut Thread) { } if jump_next { - thread.current_frame_mut().ip += 1; + *ip += 1; } } -pub fn load_list(instruction: InstructionFields, thread: &mut Thread) { +fn load_list( + ip: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let destination = instruction.a_field; let start_register = instruction.b_field; let item_type = instruction.b_type; @@ -462,283 +568,24 @@ pub fn load_list(instruction: InstructionFields, thread: &mut Thread) { thread.set_list_register(destination as usize, register); if jump_next { - thread.current_frame_mut().ip += 1; + *ip += 1; } } -pub fn load_function(_: InstructionFields, _: &mut Thread) { +fn load_function(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) { todo!() } -pub fn load_self(_: InstructionFields, _: &mut Thread) { +fn load_self(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) { todo!() } -pub fn add(instruction: InstructionFields, thread: &mut Thread) { - let destination = instruction.a_field as usize; - let left = instruction.b_field as usize; - let left_is_constant = instruction.b_is_constant; - let left_type = instruction.b_type; - let right = instruction.c_field as usize; - let right_is_constant = instruction.c_is_constant; - let right_type = instruction.c_type; - - match (left_type, right_type) { - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_integer().unwrap() - } else { - unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_integer().unwrap() - } else { - unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(right) - }; - let sum = left_value + right_value; - let register = Register::Value(sum); - - thread.set_integer_register(destination, register); - } - (TypeCode::BYTE, TypeCode::BYTE) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_byte().unwrap() - } else { - unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() } - } - } else { - thread.get_byte_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_byte().unwrap() - } else { - unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() } - } - } else { - thread.get_byte_register(right) - }; - let sum = left_value + right_value; - let register = Register::Value(sum); - - thread.set_byte_register(destination, register); - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_float().unwrap() - } else { - unsafe { thread.get_constant(left).as_float().unwrap_unchecked() } - } - } else { - thread.get_float_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_float().unwrap() - } else { - unsafe { thread.get_constant(right).as_float().unwrap_unchecked() } - } - } else { - thread.get_float_register(right) - }; - let sum = left_value + right_value; - let register = Register::Value(sum); - - thread.set_float_register(destination, register); - } - (TypeCode::STRING, TypeCode::STRING) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_string().unwrap().clone() - } else { - unsafe { - thread - .get_constant(left) - .as_string() - .unwrap_unchecked() - .clone() - } - } - } else { - thread.get_string_register(left).clone() - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_string().unwrap().clone() - } else { - unsafe { - thread - .get_constant(right) - .as_string() - .unwrap_unchecked() - .clone() - } - } - } else { - thread.get_string_register(right).clone() - }; - let concatenated = left_value + &right_value; - let register = Register::Value(concatenated); - - thread.set_string_register(destination, register); - } - (TypeCode::CHARACTER, TypeCode::CHARACTER) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_character().unwrap() - } else { - unsafe { thread.get_constant(left).as_character().unwrap_unchecked() } - } - } else { - thread.get_character_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_character().unwrap() - } else { - unsafe { thread.get_constant(right).as_character().unwrap_unchecked() } - } - } else { - thread.get_character_register(right) - }; - let mut sum = DustString::new(); - - sum.push(*left_value); - sum.push(*right_value); - - let register = Register::Value(sum); - - thread.set_string_register(destination, register); - } - (TypeCode::STRING, TypeCode::CHARACTER) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_string().unwrap().clone() - } else { - unsafe { - thread - .get_constant(left) - .as_string() - .unwrap_unchecked() - .clone() - } - } - } else { - thread.get_string_register(left).clone() - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_character().unwrap() - } else { - unsafe { thread.get_constant(right).as_character().unwrap_unchecked() } - } - } else { - thread.get_character_register(right) - }; - let mut sum = left_value.clone(); - - sum.push(*right_value); - - let register = Register::Value(sum); - - thread.set_string_register(destination, register); - } - (TypeCode::CHARACTER, TypeCode::STRING) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_character().unwrap() - } else { - unsafe { thread.get_constant(left).as_character().unwrap_unchecked() } - } - } else { - thread.get_character_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_string().unwrap() - } else { - unsafe { thread.get_constant(right).as_string().unwrap_unchecked() } - } - } else { - thread.get_string_register(right) - }; - let mut sum = right_value.clone(); - - sum.insert(0, *left_value); - - let register = Register::Value(sum); - - thread.set_string_register(destination, register); - } - _ => unreachable!(), - } -} - -fn add_integers_optimized(instruction: InstructionFields, thread: &mut Thread) { - let current_frame = thread.current_frame_mut(); - let pointer_cache = current_frame.pointer_caches[current_frame.ip]; - - if let PointerCache::Integers { left, right } = pointer_cache { - let destination = instruction.a_field as usize; - let destination_pointer = thread.get_integer_register_mut(destination) as *mut i64; - - unsafe { - asm!( - "add {}, {}", - inout(reg) *left => *destination_pointer, - in(reg) *right, - ) - } - } else if let PointerCache::Empty = pointer_cache { - let left = instruction.b_field as usize; - let right = instruction.c_field as usize; - let left_is_constant = instruction.b_is_constant; - let right_is_constant = instruction.c_is_constant; - - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_integer().unwrap() - } else { - unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_integer().unwrap() - } else { - unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(right) - }; - let cache = PointerCache::Integers { - left: left_value, - right: right_value, - }; - let destination = instruction.a_field as usize; - let sum = left_value.saturating_add(*right_value); - let register = Register::Value(sum); - - thread.set_integer_register(destination, register); - thread.set_current_pointer_cache(cache); - } else { - unreachable!() - } -} - -pub fn subtract(instruction: InstructionFields, thread: &mut Thread) { +fn subtract( + _: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let destination = instruction.a_field as usize; let left = instruction.b_field as usize; let left_type = instruction.b_type; @@ -824,7 +671,12 @@ pub fn subtract(instruction: InstructionFields, thread: &mut Thread) { } } -pub fn multiply(instruction: InstructionFields, thread: &mut Thread) { +fn multiply( + _: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let destination = instruction.a_field as usize; let left = instruction.b_field as usize; let left_type = instruction.b_type; @@ -910,7 +762,12 @@ pub fn multiply(instruction: InstructionFields, thread: &mut Thread) { } } -pub fn divide(instruction: InstructionFields, thread: &mut Thread) { +fn divide( + _: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let destination = instruction.a_field as usize; let left = instruction.b_field as usize; let left_type = instruction.b_type; @@ -996,7 +853,12 @@ pub fn divide(instruction: InstructionFields, thread: &mut Thread) { } } -pub fn modulo(instruction: InstructionFields, thread: &mut Thread) { +fn modulo( + _: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let destination = instruction.a_field as usize; let left = instruction.b_field as usize; let left_type = instruction.b_type; @@ -1082,21 +944,26 @@ pub fn modulo(instruction: InstructionFields, thread: &mut Thread) { } } -pub fn test(instruction: InstructionFields, thread: &mut Thread) { +fn test(ip: &mut usize, instruction: InstructionFields, thread: &mut Thread, _: &mut PointerCache) { let operand_register = instruction.b_field as usize; let test_value = instruction.c_field != 0; let operand_boolean = thread.get_boolean_register(operand_register); if *operand_boolean == test_value { - thread.current_frame_mut().ip += 1; + *ip += 1; } } -pub fn test_set(_: InstructionFields, _: &mut Thread) { +fn test_set(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) { todo!() } -pub fn equal(instruction: InstructionFields, thread: &mut Thread) { +fn equal( + ip: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let comparator = instruction.d_field; let left = instruction.b_field as usize; let left_type = instruction.b_type; @@ -1128,7 +995,7 @@ pub fn equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value == right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::BYTE, TypeCode::BYTE) => { @@ -1153,7 +1020,7 @@ pub fn equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value == right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::CHARACTER, TypeCode::CHARACTER) => { @@ -1178,7 +1045,7 @@ pub fn equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value == right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::FLOAT, TypeCode::FLOAT) => { @@ -1203,7 +1070,7 @@ pub fn equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value == right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::INTEGER, TypeCode::INTEGER) => { @@ -1228,7 +1095,7 @@ pub fn equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value == right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::STRING, TypeCode::STRING) => { @@ -1265,241 +1132,19 @@ pub fn equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value == right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } _ => unreachable!(), } } -pub fn less(instruction: InstructionFields, thread: &mut Thread) { - let comparator = instruction.d_field; - let left = instruction.b_field as usize; - let left_type = instruction.b_type; - let left_is_constant = instruction.b_is_constant; - let right = instruction.c_field as usize; - let right_type = instruction.c_type; - let right_is_constant = instruction.c_is_constant; - - match (left_type, right_type) { - (TypeCode::BOOLEAN, TypeCode::BOOLEAN) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_boolean().unwrap() - } else { - unsafe { thread.get_constant(left).as_boolean().unwrap_unchecked() } - } - } else { - thread.get_boolean_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_boolean().unwrap() - } else { - unsafe { thread.get_constant(right).as_boolean().unwrap_unchecked() } - } - } else { - thread.get_boolean_register(right) - }; - let result = left_value < right_value; - - if result == comparator { - thread.current_frame_mut().ip += 1; - } - } - (TypeCode::BYTE, TypeCode::BYTE) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_byte().unwrap() - } else { - unsafe { thread.get_constant(left).as_byte().unwrap_unchecked() } - } - } else { - thread.get_byte_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_byte().unwrap() - } else { - unsafe { thread.get_constant(right).as_byte().unwrap_unchecked() } - } - } else { - thread.get_byte_register(right) - }; - let result = left_value < right_value; - - if result == comparator { - thread.current_frame_mut().ip += 1; - } - } - (TypeCode::CHARACTER, TypeCode::CHARACTER) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_character().unwrap() - } else { - unsafe { thread.get_constant(left).as_character().unwrap_unchecked() } - } - } else { - thread.get_character_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_character().unwrap() - } else { - unsafe { thread.get_constant(right).as_character().unwrap_unchecked() } - } - } else { - thread.get_character_register(right) - }; - let result = left_value < right_value; - - if result == comparator { - thread.current_frame_mut().ip += 1; - } - } - (TypeCode::FLOAT, TypeCode::FLOAT) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_float().unwrap() - } else { - unsafe { thread.get_constant(left).as_float().unwrap_unchecked() } - } - } else { - thread.get_float_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_float().unwrap() - } else { - unsafe { thread.get_constant(right).as_float().unwrap_unchecked() } - } - } else { - thread.get_float_register(right) - }; - let result = left_value < right_value; - - if result == comparator { - thread.current_frame_mut().ip += 1; - } - } - (TypeCode::INTEGER, TypeCode::INTEGER) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_integer().unwrap() - } else { - unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_integer().unwrap() - } else { - unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(right) - }; - let result = left_value < right_value; - - if result == comparator { - thread.current_frame_mut().ip += 1; - } - } - (TypeCode::STRING, TypeCode::STRING) => { - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_string().unwrap().clone() - } else { - unsafe { - thread - .get_constant(left) - .as_string() - .unwrap_unchecked() - .clone() - } - } - } else { - thread.get_string_register(left).clone() - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_string().unwrap().clone() - } else { - unsafe { - thread - .get_constant(right) - .as_string() - .unwrap_unchecked() - .clone() - } - } - } else { - thread.get_string_register(right).clone() - }; - let result = left_value < right_value; - - if result == comparator { - thread.current_frame_mut().ip += 1; - } - } - _ => unreachable!(), - } -} - -fn less_integers_optimized(instruction: InstructionFields, thread: &mut Thread) { - let current_frame = thread.current_frame_mut(); - let pointer_cache = current_frame.pointer_caches[current_frame.ip]; - - let is_less = if let PointerCache::Integers { left, right } = pointer_cache { - let left_value = unsafe { *left }; - let right_value = unsafe { *right }; - - left_value < right_value - } else if let PointerCache::Empty = pointer_cache { - let left = instruction.b_field as usize; - let right = instruction.c_field as usize; - let left_is_constant = instruction.b_is_constant; - let right_is_constant = instruction.c_is_constant; - - let left_value = if left_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(left).as_integer().unwrap() - } else { - unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(left) - }; - let right_value = if right_is_constant { - if cfg!(debug_assertions) { - thread.get_constant(right).as_integer().unwrap() - } else { - unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() } - } - } else { - thread.get_integer_register(right) - }; - let cache = PointerCache::Integers { - left: left_value, - right: right_value, - }; - let is_less = left_value < right_value; - - thread.set_current_pointer_cache(cache); - - is_less - } else { - unreachable!() - }; - - if is_less { - thread.current_frame_mut().ip += 1; - } -} - -pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) { +fn less_equal( + ip: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let comparator = instruction.d_field; let left = instruction.b_field as usize; let left_type = instruction.b_type; @@ -1531,7 +1176,7 @@ pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value <= right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::BYTE, TypeCode::BYTE) => { @@ -1556,7 +1201,7 @@ pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value <= right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::CHARACTER, TypeCode::CHARACTER) => { @@ -1581,7 +1226,7 @@ pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value <= right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::FLOAT, TypeCode::FLOAT) => { @@ -1606,7 +1251,7 @@ pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value <= right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::INTEGER, TypeCode::INTEGER) => { @@ -1631,7 +1276,7 @@ pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value <= right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } (TypeCode::STRING, TypeCode::STRING) => { @@ -1668,41 +1313,35 @@ pub fn less_equal(instruction: InstructionFields, thread: &mut Thread) { let result = left_value <= right_value; if result == comparator { - thread.current_frame_mut().ip += 1; + *ip += 1; } } _ => unreachable!(), } } -pub fn negate(_: InstructionFields, _: &mut Thread) { +fn negate(_: InstructionFields, _: &mut Thread, _: &mut PointerCache) { todo!() } -pub fn not(_: InstructionFields, _: &mut Thread) { +fn not(_: InstructionFields, _: &mut Thread, _: &mut PointerCache) { todo!() } -pub fn jump(instruction: InstructionFields, thread: &mut Thread) { - let offset = instruction.b_field as usize; - let is_positive = instruction.c_field != 0; - - if is_positive { - thread.current_frame_mut().ip += offset; - } else { - thread.current_frame_mut().ip -= offset + 1; - } -} - -pub fn call(_: InstructionFields, _: &mut Thread) { +fn call(_: InstructionFields, _: &mut Thread, _: &mut PointerCache) { todo!() } -pub fn call_native(_: InstructionFields, _: &mut Thread) { +fn call_native(_: InstructionFields, _: &mut Thread, _: &mut PointerCache) { todo!() } -pub fn r#return(instruction: InstructionFields, thread: &mut Thread) { +fn r#return( + _: &mut usize, + instruction: InstructionFields, + thread: &mut Thread, + _: &mut PointerCache, +) { let should_return_value = instruction.b_field != 0; let return_register = instruction.c_field as usize; let return_type = instruction.b_type; @@ -1711,27 +1350,27 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) { match return_type { TypeCode::BOOLEAN => { let return_value = *thread.get_boolean_register(return_register); - thread.return_value = Some(Some(Value::boolean(return_value))); + thread.return_value = Some(Value::boolean(return_value)); } TypeCode::BYTE => { let return_value = *thread.get_byte_register(return_register); - thread.return_value = Some(Some(Value::byte(return_value))); + thread.return_value = Some(Value::byte(return_value)); } TypeCode::CHARACTER => { let return_value = *thread.get_character_register(return_register); - thread.return_value = Some(Some(Value::character(return_value))); + thread.return_value = Some(Value::character(return_value)); } TypeCode::FLOAT => { let return_value = *thread.get_float_register(return_register); - thread.return_value = Some(Some(Value::float(return_value))); + thread.return_value = Some(Value::float(return_value)); } TypeCode::INTEGER => { let return_value = *thread.get_integer_register(return_register); - thread.return_value = Some(Some(Value::integer(return_value))); + thread.return_value = Some(Value::integer(return_value)); } TypeCode::STRING => { let return_value = thread.get_string_register(return_register).clone(); - thread.return_value = Some(Some(Value::string(return_value))); + thread.return_value = Some(Value::string(return_value)); } TypeCode::LIST => { let abstract_list = thread.get_list_register(return_register).clone(); @@ -1743,14 +1382,12 @@ pub fn r#return(instruction: InstructionFields, thread: &mut Thread) { items.push(value); } - thread.return_value = Some(Some(Value::Concrete(ConcreteValue::List { + thread.return_value = Some(Value::Concrete(ConcreteValue::List { items, item_type: abstract_list.item_type, - }))); + })); } _ => unreachable!(), } - } else { - thread.return_value = Some(None); } } diff --git a/dust-lang/src/vm/call_frame.rs b/dust-lang/src/vm/call_frame.rs index 4249257..750f30b 100644 --- a/dust-lang/src/vm/call_frame.rs +++ b/dust-lang/src/vm/call_frame.rs @@ -1,37 +1,30 @@ use std::{ fmt::{self, Debug, Display, Formatter}, - sync::Arc, + ptr, + rc::Rc, }; use smallvec::{SmallVec, smallvec}; use crate::{AbstractList, Chunk, DustString, Function}; -use super::action::ActionSequence; - #[derive(Debug)] pub struct CallFrame { - pub chunk: Arc, + pub chunk: Rc, pub ip: usize, pub return_register: u16, pub registers: RegisterTable, - pub action_sequence: ActionSequence, - pub pointer_caches: Vec, } impl CallFrame { - pub fn new(chunk: Arc, return_register: u16) -> Self { + pub fn new(chunk: Rc, return_register: u16) -> Self { let registers = RegisterTable::new(); - let action_sequence = ActionSequence::new(&chunk.instructions); - let optimization_data = vec![PointerCache::default(); chunk.instructions.len()]; Self { chunk, ip: 0, return_register, registers, - action_sequence, - pointer_caches: optimization_data, } } } @@ -65,14 +58,14 @@ pub struct RegisterTable { impl RegisterTable { pub fn new() -> Self { Self { - booleans: smallvec![Register::Empty; 64], - bytes: smallvec![Register::Empty; 64], - characters: smallvec![Register::Empty; 64], - floats: smallvec![Register::Empty; 64], - integers: smallvec![Register::Empty; 64], - strings: smallvec![Register::Empty; 64], - lists: smallvec![Register::Empty; 64], - functions: smallvec![Register::Empty; 64], + booleans: smallvec![Register::default(); 64], + bytes: smallvec![Register::default(); 64], + characters: smallvec![Register::default(); 64], + floats: smallvec![Register::default(); 64], + integers: smallvec![Register::default(); 64], + strings: smallvec![Register::default(); 64], + lists: smallvec![Register::default(); 64], + functions: smallvec![Register::default(); 64], } } } @@ -84,27 +77,31 @@ impl Default for RegisterTable { } #[derive(Clone, Copy, Debug, PartialEq)] -pub enum Register { - Empty, +pub enum Register { Value(T), Closed(T), Pointer(Pointer), } -impl Register { +impl Register { pub fn contained_value_mut(&mut self) -> Option<&mut T> { match self { Self::Value(value) => Some(value), Self::Closed(value) => Some(value), - _ => None, + Self::Pointer(_) => None, } } } -impl Display for Register { +impl Default for Register { + fn default() -> Self { + Self::Value(T::default()) + } +} + +impl Display for Register { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match self { - Self::Empty => write!(f, "empty"), Self::Closed(value) => write!(f, "Closed({value})"), Self::Value(value) => write!(f, "Value({value})"), Self::Pointer(pointer) => write!(f, "Pointer({pointer:?})"), @@ -147,12 +144,25 @@ impl Display for Pointer { } } -#[derive(Debug, Clone, Copy, Default)] -pub enum PointerCache { - #[default] - Empty, - Integers { - left: *const i64, - right: *const i64, - }, +#[derive(Debug, Clone, Copy)] +pub struct PointerCache { + pub integer_mut: *mut i64, + pub integer_left: *const i64, + pub integer_right: *const i64, +} + +impl PointerCache { + pub fn new() -> Self { + Self { + integer_mut: ptr::null_mut(), + integer_left: ptr::null(), + integer_right: ptr::null(), + } + } +} + +impl Default for PointerCache { + fn default() -> Self { + Self::new() + } } diff --git a/dust-lang/src/vm/mod.rs b/dust-lang/src/vm/mod.rs index a88f3b6..a17da0a 100644 --- a/dust-lang/src/vm/mod.rs +++ b/dust-lang/src/vm/mod.rs @@ -3,7 +3,7 @@ mod action; mod call_frame; mod thread; -use std::{sync::Arc, thread::Builder}; +use std::{rc::Rc, thread::Builder}; pub use action::Action; pub use call_frame::{CallFrame, Pointer, Register, RegisterTable}; @@ -40,14 +40,14 @@ impl Vm { .map(|name| name.to_string()) .unwrap_or_else(|| "anonymous".to_string()); let (tx, rx) = bounded(1); - let main_chunk = Arc::new(self.main_chunk); Builder::new() .name(thread_name) .spawn(move || { + let main_chunk = Rc::new(self.main_chunk); let main_thread = Thread::new(main_chunk); - let value_option = main_thread.run(); - let _ = tx.send(value_option); + let return_value = main_thread.run(); + let _ = tx.send(return_value); }) .unwrap() .join() diff --git a/dust-lang/src/vm/thread.rs b/dust-lang/src/vm/thread.rs index e316221..0ab1872 100644 --- a/dust-lang/src/vm/thread.rs +++ b/dust-lang/src/vm/thread.rs @@ -1,22 +1,26 @@ -use std::{sync::Arc, thread::JoinHandle}; +use std::{rc::Rc, thread::JoinHandle}; use tracing::{info, trace}; -use crate::{AbstractList, Chunk, ConcreteValue, DustString, Span, Value, vm::CallFrame}; +use crate::{ + AbstractList, Chunk, ConcreteValue, DustString, Span, Value, + instruction::InstructionFields, + vm::{CallFrame, action::ActionSequence}, +}; -use super::call_frame::{Pointer, PointerCache, Register}; +use super::call_frame::{Pointer, Register}; pub struct Thread { - chunk: Arc, + chunk: Rc, call_stack: Vec, - pub return_value: Option>, + pub return_value: Option, _spawned_threads: Vec>, } impl Thread { - pub fn new(chunk: Arc) -> Self { + pub fn new(chunk: Rc) -> Self { let mut call_stack = Vec::with_capacity(chunk.prototypes.len() + 1); - let main_call = CallFrame::new(Arc::clone(&chunk), 0); + let main_call = CallFrame::new(Rc::clone(&chunk), 0); call_stack.push(main_call); @@ -36,28 +40,15 @@ impl Thread { .clone() .unwrap_or_else(|| DustString::from("anonymous")) ); - trace!("Thread actions: {}", self.current_frame().action_sequence); - loop { - if let Some(return_value_option) = self.return_value { - return return_value_option; - } + let actions = + ActionSequence::new(self.chunk.instructions.iter().map(InstructionFields::from)); - let current_frame = self.current_frame_mut(); - let ip = { - let ip = current_frame.ip; - current_frame.ip += 1; + trace!("Thread actions: {}", actions); - ip - }; - let current_action = if cfg!(debug_assertions) { - current_frame.action_sequence.actions.get_mut(ip).unwrap() - } else { - unsafe { current_frame.action_sequence.actions.get_unchecked_mut(ip) } - }; + actions.run(&mut self); - (current_action.logic)(current_action.instruction, &mut self); - } + self.return_value } pub fn current_position(&self) -> Span { @@ -82,29 +73,6 @@ impl Thread { } } - pub fn set_current_pointer_cache(&mut self, new_cache: PointerCache) { - let ip = self.current_frame().ip; - - let old_cache = if cfg!(debug_assertions) { - self.call_stack - .last_mut() - .unwrap() - .pointer_caches - .get_mut(ip - 1) - .unwrap() - } else { - unsafe { - self.call_stack - .last_mut() - .unwrap_unchecked() - .pointer_caches - .get_unchecked_mut(ip - 1) - } - }; - - *old_cache = new_cache; - } - pub fn get_value_from_pointer(&self, pointer: &Pointer) -> ConcreteValue { match pointer { Pointer::RegisterBoolean(register_index) => { @@ -204,7 +172,6 @@ impl Thread { Register::Value(value) => value, Register::Closed(value) => value, Register::Pointer(pointer) => self.get_pointer_to_boolean(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), } } @@ -299,7 +266,6 @@ impl Thread { Register::Value(value) => value, Register::Closed(value) => value, Register::Pointer(pointer) => self.get_pointer_to_byte(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), } } @@ -394,7 +360,6 @@ impl Thread { Register::Value(value) => value, Register::Closed(value) => value, Register::Pointer(pointer) => self.get_pointer_to_character(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), } } @@ -494,7 +459,6 @@ impl Thread { Register::Value(value) => value, Register::Closed(value) => value, Register::Pointer(pointer) => self.get_pointer_to_float(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), } } @@ -592,11 +556,10 @@ impl Thread { Register::Value(value) => value, Register::Closed(value) => value, Register::Pointer(pointer) => self.get_pointer_to_integer(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), } } - pub fn get_integer_register_mut(&mut self, register_index: usize) -> &mut i64 { + pub fn get_integer_register_mut_allow_empty(&mut self, register_index: usize) -> &mut i64 { if cfg!(debug_assertions) { self.call_stack .last_mut() @@ -715,7 +678,6 @@ impl Thread { Register::Value(value) => value, Register::Closed(value) => value, Register::Pointer(pointer) => self.get_pointer_to_string(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), } } @@ -782,7 +744,7 @@ impl Thread { pub fn close_string_register(&mut self, register_index: usize) { let current_frame = self.current_frame_mut(); - current_frame.registers.strings.push(Register::Empty); + current_frame.registers.strings.push(Register::default()); let old_register = current_frame.registers.strings.swap_remove(register_index); @@ -822,7 +784,6 @@ impl Thread { Register::Value(value) => value, Register::Closed(value) => value, Register::Pointer(pointer) => self.get_pointer_to_list(pointer), - Register::Empty => panic!("Attempted to get value from empty register"), } } @@ -886,7 +847,7 @@ impl Thread { pub fn close_list_register(&mut self, register_index: usize) { let current_frame = self.current_frame_mut(); - current_frame.registers.lists.push(Register::Empty); + current_frame.registers.lists.push(Register::default()); let old_register = current_frame.registers.lists.swap_remove(register_index);