From c03ec528b76a4ac31dddac4ef96407e256aaedb7 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 8 Jan 2025 21:04:08 -0500 Subject: [PATCH] Optimize and refine VM thread and record --- Cargo.lock | 7 - dust-lang/Cargo.toml | 1 - dust-lang/src/lib.rs | 2 + dust-lang/src/native_function/io.rs | 18 +- dust-lang/src/native_function/string.rs | 6 +- dust-lang/src/vm/mod.rs | 4 +- dust-lang/src/vm/record.rs | 52 ++--- dust-lang/src/vm/run_action.rs | 245 ++++++++++++++---------- dust-lang/src/vm/thread.rs | 38 ++-- 9 files changed, 203 insertions(+), 170 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8f82233..eecbb0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -342,7 +342,6 @@ dependencies = [ "smallvec", "smartstring", "tracing", - "typed-arena", ] [[package]] @@ -947,12 +946,6 @@ dependencies = [ "tracing-log", ] -[[package]] -name = "typed-arena" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" - [[package]] name = "unicode-ident" version = "1.0.13" diff --git a/dust-lang/Cargo.toml b/dust-lang/Cargo.toml index 1de72f1..28c86ac 100644 --- a/dust-lang/Cargo.toml +++ b/dust-lang/Cargo.toml @@ -22,7 +22,6 @@ smartstring = { version = "1.0.1", features = [ "serde", ], default-features = false } tracing = "0.1.41" -typed-arena = "2.0.2" [dev-dependencies] criterion = { version = "0.3.4", features = ["html_reports"] } diff --git a/dust-lang/src/lib.rs b/dust-lang/src/lib.rs index f1e8dbd..14c00a9 100644 --- a/dust-lang/src/lib.rs +++ b/dust-lang/src/lib.rs @@ -28,6 +28,8 @@ //! println!("{}", report); //! ``` +#![feature(array_repeat)] + pub mod chunk; pub mod compiler; pub mod dust_error; diff --git a/dust-lang/src/native_function/io.rs b/dust-lang/src/native_function/io.rs index 1ca207f..126cf51 100644 --- a/dust-lang/src/native_function/io.rs +++ b/dust-lang/src/native_function/io.rs @@ -1,7 +1,7 @@ use std::io::{self, stdin, stdout, Write}; use std::ops::Range; -use crate::vm::{Register, ThreadSignal}; +use crate::vm::{get_next_action, Register, ThreadSignal}; use crate::{vm::Record, ConcreteValue, NativeFunctionError, Value}; pub fn read_line( @@ -30,7 +30,9 @@ pub fn read_line( } } - Ok(ThreadSignal::Continue) + let next_action = get_next_action(record); + + Ok(ThreadSignal::Continue(next_action)) } pub fn write( @@ -41,7 +43,7 @@ pub fn write( let mut stdout = stdout(); for register_index in argument_range { - if let Some(value) = record.open_register_allow_empty(register_index) { + if let Some(value) = record.open_register_allow_empty_unchecked(register_index) { let string = value.display(record); stdout @@ -58,7 +60,9 @@ pub fn write( position: record.current_position(), })?; - Ok(ThreadSignal::Continue) + let next_action = get_next_action(record); + + Ok(ThreadSignal::Continue(next_action)) } pub fn write_line( @@ -73,7 +77,7 @@ pub fn write_line( let mut stdout = stdout().lock(); for register_index in argument_range { - if let Some(value) = record.open_register_allow_empty(register_index) { + if let Some(value) = record.open_register_allow_empty_unchecked(register_index) { let string = value.display(record); stdout.write(string.as_bytes()).map_err(map_err)?; @@ -83,5 +87,7 @@ pub fn write_line( stdout.flush().map_err(map_err)?; - Ok(ThreadSignal::Continue) + let next_action = get_next_action(record); + + Ok(ThreadSignal::Continue(next_action)) } diff --git a/dust-lang/src/native_function/string.rs b/dust-lang/src/native_function/string.rs index 2d48ce7..38f2b70 100644 --- a/dust-lang/src/native_function/string.rs +++ b/dust-lang/src/native_function/string.rs @@ -1,7 +1,7 @@ use std::ops::Range; use crate::{ - vm::{Record, Register, ThreadSignal}, + vm::{get_next_action, Record, Register, ThreadSignal}, ConcreteValue, NativeFunctionError, Value, }; @@ -17,5 +17,7 @@ pub fn to_string( record.set_register(destination, register); - Ok(ThreadSignal::Continue) + let next_action = get_next_action(record); + + Ok(ThreadSignal::Continue(next_action)) } diff --git a/dust-lang/src/vm/mod.rs b/dust-lang/src/vm/mod.rs index dc52e98..e32ff1d 100644 --- a/dust-lang/src/vm/mod.rs +++ b/dust-lang/src/vm/mod.rs @@ -13,9 +13,11 @@ use std::{ pub use error::VmError; pub use record::Record; -pub use run_action::RecordAction; +pub(crate) use run_action::get_next_action; +pub use run_action::RunAction; pub use stack::{FunctionCall, Stack}; pub use thread::{Thread, ThreadSignal}; + use tracing::{span, Level}; use crate::{compile, Chunk, DustError, DustString, Value}; diff --git a/dust-lang/src/vm/record.rs b/dust-lang/src/vm/record.rs index 8c709a7..1a3fa33 100644 --- a/dust-lang/src/vm/record.rs +++ b/dust-lang/src/vm/record.rs @@ -14,7 +14,6 @@ pub struct Record<'a> { } impl<'a> Record<'a> { - #[allow(clippy::too_many_arguments)] pub fn new(chunk: &'a Chunk) -> Self { Self { ip: 0, @@ -44,7 +43,7 @@ impl<'a> Record<'a> { match pointer { Pointer::Stack(register_index) => self.open_register_unchecked(register_index), - Pointer::Constant(constant_index) => self.get_constant(constant_index), + Pointer::Constant(constant_index) => self.get_constant_unchecked(constant_index), } } @@ -90,17 +89,10 @@ impl<'a> Record<'a> { } } - pub fn open_register_allow_empty(&self, register_index: u8) -> Option<&Value> { + pub fn open_register_allow_empty_unchecked(&self, register_index: u8) -> Option<&Value> { trace!("Open register R{register_index}"); - let register_index = register_index as usize; - - assert!( - register_index < self.registers.len(), - "VM Error: Register index out of bounds" - ); - - let register = &self.registers[register_index]; + let register = self.get_register_unchecked(register_index); match register { Register::Value(value) => { @@ -117,7 +109,7 @@ impl<'a> Record<'a> { } } - pub fn empty_register_or_clone_constant(&mut self, register_index: u8) -> Value { + pub fn empty_register_or_clone_constant_unchecked(&mut self, register_index: u8) -> Value { let register_index = register_index as usize; assert!( @@ -131,21 +123,18 @@ impl<'a> Record<'a> { Register::Value(value) => value, Register::Pointer(pointer) => match pointer { Pointer::Stack(register_index) => { - self.empty_register_or_clone_constant(register_index) + self.empty_register_or_clone_constant_unchecked(register_index) + } + Pointer::Constant(constant_index) => { + self.get_constant_unchecked(constant_index).clone() } - Pointer::Constant(constant_index) => self.get_constant(constant_index).clone(), }, Register::Empty => panic!("VM Error: Register {register_index} is empty"), } } - pub fn clone_register_value_or_constant(&self, register_index: u8) -> Value { - assert!( - (register_index as usize) < self.registers.len(), - "VM Error: Register index out of bounds" - ); - - let register = &self.registers[register_index as usize]; + pub fn clone_register_value_or_constant_unchecked(&self, register_index: u8) -> Value { + let register = self.get_register_unchecked(register_index); match register { Register::Value(value) => value.clone(), @@ -153,29 +142,30 @@ impl<'a> Record<'a> { Pointer::Stack(register_index) => { self.open_register_unchecked(*register_index).clone() } - Pointer::Constant(constant_index) => self.get_constant(*constant_index).clone(), + Pointer::Constant(constant_index) => { + self.get_constant_unchecked(*constant_index).clone() + } }, Register::Empty => panic!("VM Error: Register {register_index} is empty"), } } /// DRY helper to get a value from an Argument - pub fn get_argument(&self, argument: Argument) -> &Value { + pub fn get_argument_unchecked(&self, argument: Argument) -> &Value { match argument { - Argument::Constant(constant_index) => self.get_constant(constant_index), + Argument::Constant(constant_index) => self.get_constant_unchecked(constant_index), Argument::Register(register_index) => self.open_register_unchecked(register_index), } } - pub fn get_constant(&self, constant_index: u8) -> &Value { + pub fn get_constant_unchecked(&self, constant_index: u8) -> &Value { let constant_index = constant_index as usize; - assert!( - constant_index < self.chunk.constants.len(), - "VM Error: Constant index out of bounds" - ); - - &self.chunk.constants[constant_index] + if cfg!(debug_assertions) { + &self.chunk.constants[constant_index] + } else { + unsafe { self.chunk.constants.get_unchecked(constant_index) } + } } pub fn get_local_register(&self, local_index: u8) -> u8 { diff --git a/dust-lang/src/vm/run_action.rs b/dust-lang/src/vm/run_action.rs index f520c23..29eca8b 100644 --- a/dust-lang/src/vm/run_action.rs +++ b/dust-lang/src/vm/run_action.rs @@ -10,24 +10,24 @@ use crate::{ AbstractList, Argument, ConcreteValue, DustString, Instruction, Type, Value, }; -use super::{thread::ThreadData, Pointer, Record, Register}; +use super::{thread::ThreadData, Pointer, Record, Register, ThreadSignal}; #[derive(Clone, Copy, Debug, PartialEq)] -pub struct RecordAction { +pub struct RunAction { pub logic: RunnerLogic, pub instruction: Instruction, } -impl From for RecordAction { +impl From for RunAction { fn from(instruction: Instruction) -> Self { let operation = instruction.operation(); let logic = RUNNER_LOGIC_TABLE[operation.0 as usize]; - RecordAction { logic, instruction } + RunAction { logic, instruction } } } -pub type RunnerLogic = fn(Instruction, &mut ThreadData) -> Option; +pub type RunnerLogic = fn(Instruction, &mut ThreadData) -> ThreadSignal; pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 25] = [ point, @@ -57,7 +57,15 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 25] = [ r#return, ]; -pub fn point(instruction: Instruction, data: &mut ThreadData) -> Option { +pub(crate) fn get_next_action(record: &Record) -> RunAction { + let instruction = record.chunk.instructions[record.ip]; + let operation = instruction.operation(); + let logic = RUNNER_LOGIC_TABLE[operation.0 as usize]; + + RunAction { logic, instruction } +} + +pub fn point(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Point { from, to } = instruction.into(); let from_register = record.get_register_unchecked(from); @@ -71,30 +79,27 @@ pub fn point(instruction: Instruction, data: &mut ThreadData) -> Option { record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn close(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn close(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Close { from, to } = instruction.into(); - assert!(from < to, "Runtime Error: Malformed instruction"); - for register_index in from..to { - assert!( - (register_index as usize) < record.stack_size(), - "Runtime Error: Register index out of bounds" - ); - record.set_register(register_index, Register::Empty); } record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn load_boolean(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn load_boolean(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let LoadBoolean { destination, @@ -112,10 +117,12 @@ pub fn load_boolean(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn load_constant(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let LoadConstant { destination, @@ -134,10 +141,12 @@ pub fn load_constant(instruction: Instruction, data: &mut ThreadData) -> Option< record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn load_list(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn load_list(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let LoadList { destination, @@ -176,10 +185,12 @@ pub fn load_list(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn load_function(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let LoadFunction { destination, @@ -193,10 +204,12 @@ pub fn load_function(instruction: Instruction, data: &mut ThreadData) -> Option< record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn load_self(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn load_self(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let LoadSelf { destination } = instruction.into(); let function = record.as_function(); @@ -206,10 +219,12 @@ pub fn load_self(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn get_local(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let GetLocal { destination, @@ -222,10 +237,12 @@ pub fn get_local(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn set_local(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let SetLocal { register_index, @@ -238,18 +255,20 @@ pub fn set_local(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn add(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Add { destination, left, right, } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let sum = left.add(right); let register = Register::Value(sum); @@ -257,18 +276,20 @@ pub fn add(instruction: Instruction, data: &mut ThreadData) -> Option { record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn subtract(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn subtract(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Subtract { destination, left, right, } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let difference = left.subtract(right); let register = Register::Value(difference); @@ -276,18 +297,20 @@ pub fn subtract(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn multiply(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Multiply { destination, left, right, } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let product = match (left, right) { (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { @@ -303,18 +326,20 @@ pub fn multiply(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn divide(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Divide { destination, left, right, } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let quotient = match (left, right) { (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { @@ -330,18 +355,20 @@ pub fn divide(instruction: Instruction, data: &mut ThreadData) -> Option record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn modulo(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn modulo(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Modulo { destination, left, right, } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let remainder = match (left, right) { (Value::Concrete(left), Value::Concrete(right)) => match (left, right) { (ConcreteValue::Integer(left), ConcreteValue::Integer(right)) => { @@ -357,10 +384,12 @@ pub fn modulo(instruction: Instruction, data: &mut ThreadData) -> Option record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn test(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn test(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Test { operand_register, @@ -379,17 +408,19 @@ pub fn test(instruction: Instruction, data: &mut ThreadData) -> Option { record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn test_set(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn test_set(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let TestSet { destination, argument, test_value, } = instruction.into(); - let value = record.get_argument(argument); + let value = record.get_argument_unchecked(argument); let boolean = if let Value::Concrete(ConcreteValue::Boolean(boolean)) = value { *boolean } else { @@ -410,14 +441,16 @@ pub fn test_set(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn equal(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Equal { value, left, right } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let is_equal = left.equals(right); if is_equal == value { @@ -426,14 +459,16 @@ pub fn equal(instruction: Instruction, data: &mut ThreadData) -> Option { record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn less(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn less(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Less { value, left, right } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let is_less = left < right; if is_less == value { @@ -442,14 +477,16 @@ pub fn less(instruction: Instruction, data: &mut ThreadData) -> Option { record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn less_equal(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn less_equal(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let LessEqual { value, left, right } = instruction.into(); - let left = record.get_argument(left); - let right = record.get_argument(right); + let left = record.get_argument_unchecked(left); + let right = record.get_argument_unchecked(right); let is_less_or_equal = left <= right; if is_less_or_equal == value { @@ -458,16 +495,18 @@ pub fn less_equal(instruction: Instruction, data: &mut ThreadData) -> Option Option { +pub fn negate(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Negate { destination, argument, } = instruction.into(); - let argument = record.get_argument(argument); + let argument = record.get_argument_unchecked(argument); let negated = argument.negate(); let register = Register::Value(negated); @@ -475,16 +514,18 @@ pub fn negate(instruction: Instruction, data: &mut ThreadData) -> Option record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn not(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn not(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Not { destination, argument, } = instruction.into(); - let argument = record.get_argument(argument); + let argument = record.get_argument_unchecked(argument); let not = match argument { Value::Concrete(ConcreteValue::Boolean(boolean)) => ConcreteValue::Boolean(!boolean), _ => panic!("VM Error: Expected boolean value for NOT operation"), @@ -495,10 +536,12 @@ pub fn not(instruction: Instruction, data: &mut ThreadData) -> Option { record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn jump(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn jump(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let Jump { offset, @@ -514,11 +557,13 @@ pub fn jump(instruction: Instruction, data: &mut ThreadData) -> Option { record.ip += 1; - None + let next_action = get_next_action(record); + + ThreadSignal::Continue(next_action) } -pub fn call(instruction: Instruction, data: &mut ThreadData) -> Option { - let record = data.records.last_mut_unchecked(); +pub fn call(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { + let mut current_record = data.records.pop_unchecked(); let Call { destination: return_register, function_register, @@ -526,25 +571,25 @@ pub fn call(instruction: Instruction, data: &mut ThreadData) -> Option { is_recursive, } = instruction.into(); - let function = record + let function = current_record .open_register_unchecked(function_register) .as_function() .unwrap(); let first_argument_register = return_register - argument_count; let prototype = if is_recursive { - record.chunk + current_record.chunk } else { - &record.chunk.prototypes[function.prototype_index as usize] + ¤t_record.chunk.prototypes[function.prototype_index as usize] }; let mut next_record = Record::new(prototype); let next_call = FunctionCall { name: next_record.name().cloned(), return_register, - ip: record.ip, + ip: current_record.ip, }; for (argument_index, register_index) in (first_argument_register..return_register).enumerate() { - let argument = record.clone_register_value_or_constant(register_index); + let argument = current_record.clone_register_value_or_constant_unchecked(register_index); trace!( "Passing argument \"{argument}\" to {}", @@ -557,15 +602,18 @@ pub fn call(instruction: Instruction, data: &mut ThreadData) -> Option { next_record.set_register(argument_index as u8, Register::Value(argument)); } - record.ip += 1; + let next_action = get_next_action(&next_record); + + current_record.ip += 1; data.call_stack.push(next_call); + data.records.push(current_record); data.records.push(next_record); - None + ThreadSignal::Continue(next_action) } -pub fn call_native(instruction: Instruction, data: &mut ThreadData) -> Option { +pub fn call_native(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { let record = data.records.last_mut_unchecked(); let CallNative { destination, @@ -581,34 +629,31 @@ pub fn call_native(instruction: Instruction, data: &mut ThreadData) -> Option Option { - let record = data.records.last_mut_unchecked(); +pub fn r#return(instruction: Instruction, data: &mut ThreadData) -> ThreadSignal { + trace!("Returning with call stack:\n{}", data.call_stack); + let Return { should_return_value, return_register, } = instruction.into(); - - trace!("Returning with call stack:\n{}", data.call_stack); + let current_call = data.call_stack.pop_unchecked(); + let mut current_record = data.records.pop_unchecked(); let return_value = if should_return_value { - Some(record.empty_register_or_clone_constant(return_register)) + Some(current_record.empty_register_or_clone_constant_unchecked(return_register)) } else { None }; - let current_call = data.call_stack.pop_unchecked(); - let _current_record = data.records.pop_unchecked(); let destination = current_call.return_register; if data.call_stack.is_empty() { - return if should_return_value { - return_value - } else { - None - }; + return ThreadSignal::End(return_value); } let outer_record = data.records.last_mut_unchecked(); @@ -617,7 +662,9 @@ pub fn r#return(instruction: Instruction, data: &mut ThreadData) -> Option { + next_action = action; + } + ThreadSignal::End(value_option) => { + info!("Thread ended"); - return value_option; + return value_option; + } } } } @@ -64,20 +68,8 @@ pub struct ThreadData<'a> { #[derive(Debug)] pub enum ThreadSignal { - Continue, - Call { - function_register: u8, - return_register: u8, - argument_count: u8, - }, - Return { - should_return_value: bool, - return_register: u8, - }, - LoadFunction { - prototype_index: u8, - destination: u8, - }, + Continue(RunAction), + End(Option), } impl Display for ThreadSignal {