Attempt alternative to total register overhaul
This commit is contained in:
parent
3fcbde59e5
commit
c1fe54ccd5
@ -56,14 +56,11 @@ impl Display for Add {
|
||||
let Add {
|
||||
destination,
|
||||
left,
|
||||
left_type,
|
||||
left_type: _,
|
||||
right,
|
||||
right_type,
|
||||
right_type: _,
|
||||
} = self;
|
||||
|
||||
write!(
|
||||
f,
|
||||
"R{destination} = {left}({left_type}) + {right}({right_type})",
|
||||
)
|
||||
write!(f, "R{destination} = {left} + {right}",)
|
||||
}
|
||||
}
|
||||
|
@ -56,15 +56,12 @@ impl Display for Less {
|
||||
let Less {
|
||||
comparator,
|
||||
left,
|
||||
left_type,
|
||||
left_type: _,
|
||||
right,
|
||||
right_type,
|
||||
right_type: _,
|
||||
} = self;
|
||||
let operator = if *comparator { "<" } else { "≥" };
|
||||
|
||||
write!(
|
||||
f,
|
||||
"if {left_type}({left}) {operator} {right_type}({right}) {{ JUMP +1 }}"
|
||||
)
|
||||
write!(f, "if {left} {operator} {right} {{ JUMP +1 }}")
|
||||
}
|
||||
}
|
||||
|
@ -56,15 +56,12 @@ impl Display for LessEqual {
|
||||
let LessEqual {
|
||||
comparator,
|
||||
left,
|
||||
left_type,
|
||||
left_type: _,
|
||||
right,
|
||||
right_type,
|
||||
right_type: _,
|
||||
} = self;
|
||||
let operator = if *comparator { "≤" } else { ">" };
|
||||
|
||||
write!(
|
||||
f,
|
||||
"if {left_type}({left}) {operator} {right_type}({right}) {{ JUMP +1 }}"
|
||||
)
|
||||
write!(f, "if {left} {operator} {right} {{ JUMP +1 }}")
|
||||
}
|
||||
}
|
||||
|
@ -154,6 +154,7 @@ pub use type_code::TypeCode;
|
||||
|
||||
use crate::NativeFunction;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct InstructionBuilder {
|
||||
pub operation: Operation,
|
||||
pub a_field: u16,
|
||||
@ -182,6 +183,22 @@ impl InstructionBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Instruction> for InstructionBuilder {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
InstructionBuilder {
|
||||
operation: instruction.operation(),
|
||||
a_field: instruction.a_field(),
|
||||
b_field: instruction.b_field(),
|
||||
c_field: instruction.c_field(),
|
||||
d_field: instruction.d_field(),
|
||||
b_is_constant: instruction.b_is_constant(),
|
||||
c_is_constant: instruction.c_is_constant(),
|
||||
b_type: instruction.b_type(),
|
||||
c_type: instruction.c_type(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for InstructionBuilder {
|
||||
fn default() -> Self {
|
||||
InstructionBuilder {
|
||||
|
@ -3,31 +3,50 @@ use tracing::trace;
|
||||
use crate::{
|
||||
AbstractList, ConcreteValue, Instruction, Operand, Type, Value,
|
||||
instruction::{
|
||||
Add, Call, CallNative, Close, Divide, Equal, GetLocal, Jump, Less, LessEqual, LoadBoolean,
|
||||
LoadConstant, LoadFunction, LoadList, LoadSelf, Modulo, Multiply, Negate, Not, Point,
|
||||
Return, SetLocal, Subtract, Test, TestSet, TypeCode,
|
||||
Add, Call, CallNative, Close, Divide, Equal, GetLocal, InstructionBuilder, Jump, Less,
|
||||
LessEqual, LoadBoolean, LoadConstant, LoadFunction, LoadList, LoadSelf, Modulo, Multiply,
|
||||
Negate, Not, Point, Return, SetLocal, Subtract, Test, TestSet, TypeCode,
|
||||
},
|
||||
vm::FunctionCall,
|
||||
vm::CallFrame,
|
||||
};
|
||||
|
||||
use super::{Pointer, Register, thread::ThreadData};
|
||||
use super::{Pointer, Register, thread::Thread};
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct RunAction {
|
||||
pub logic: RunnerLogic,
|
||||
pub instruction: Instruction,
|
||||
pub struct ActionSequence {
|
||||
pub actions: Vec<Action>,
|
||||
}
|
||||
|
||||
impl From<Instruction> for RunAction {
|
||||
fn from(instruction: Instruction) -> Self {
|
||||
let operation = instruction.operation();
|
||||
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
||||
impl ActionSequence {
|
||||
pub fn new(instructions: &[Instruction]) -> Self {
|
||||
let mut actions = Vec::with_capacity(instructions.len());
|
||||
|
||||
RunAction { logic, instruction }
|
||||
for instruction in instructions {
|
||||
let action = Action::from(*instruction);
|
||||
|
||||
actions.push(action);
|
||||
}
|
||||
|
||||
ActionSequence { actions }
|
||||
}
|
||||
}
|
||||
|
||||
pub type RunnerLogic = fn(Instruction, &mut ThreadData) -> bool;
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Action {
|
||||
pub logic: RunnerLogic,
|
||||
pub instruction: InstructionBuilder,
|
||||
}
|
||||
|
||||
impl From<&Instruction> for Action {
|
||||
fn from(instruction: &Instruction) -> Self {
|
||||
let operation = instruction.operation();
|
||||
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
||||
let instruction = InstructionBuilder::from(instruction);
|
||||
|
||||
Action { logic, instruction }
|
||||
}
|
||||
}
|
||||
|
||||
pub type RunnerLogic = fn(InstructionBuilder, &mut Thread) -> bool;
|
||||
|
||||
pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 25] = [
|
||||
point,
|
||||
@ -57,18 +76,7 @@ pub const RUNNER_LOGIC_TABLE: [RunnerLogic; 25] = [
|
||||
r#return,
|
||||
];
|
||||
|
||||
pub(crate) fn get_next_action(data: &mut ThreadData) -> RunAction {
|
||||
let current_call = data.call_stack.last_mut_unchecked();
|
||||
let instruction = current_call.chunk.instructions[current_call.ip];
|
||||
let operation = instruction.operation();
|
||||
let logic = RUNNER_LOGIC_TABLE[operation.0 as usize];
|
||||
|
||||
current_call.ip += 1;
|
||||
|
||||
RunAction { logic, instruction }
|
||||
}
|
||||
|
||||
pub fn point(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn point(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Point { from, to } = instruction.into();
|
||||
let from_register = data.get_register_unchecked(from);
|
||||
let from_register_is_empty = matches!(from_register, Register::Empty);
|
||||
@ -84,7 +92,7 @@ pub fn point(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn close(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn close(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Close { from, to } = instruction.into();
|
||||
|
||||
for register_index in from..to {
|
||||
@ -96,7 +104,7 @@ pub fn close(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn load_boolean(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn load_boolean(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let LoadBoolean {
|
||||
destination,
|
||||
value,
|
||||
@ -118,7 +126,7 @@ pub fn load_boolean(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn load_constant(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn load_constant(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let LoadConstant {
|
||||
destination,
|
||||
constant_index,
|
||||
@ -141,7 +149,7 @@ pub fn load_constant(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn load_list(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn load_list(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let LoadList {
|
||||
destination,
|
||||
start_register,
|
||||
@ -183,7 +191,7 @@ pub fn load_list(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn load_function(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn load_function(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let LoadFunction {
|
||||
destination,
|
||||
prototype_index,
|
||||
@ -202,7 +210,7 @@ pub fn load_function(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn load_self(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn load_self(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let LoadSelf {
|
||||
destination,
|
||||
jump_next,
|
||||
@ -219,7 +227,7 @@ pub fn load_self(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn get_local(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn get_local(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let GetLocal {
|
||||
destination,
|
||||
local_index,
|
||||
@ -234,7 +242,7 @@ pub fn get_local(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn set_local(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn set_local(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let SetLocal {
|
||||
register_index,
|
||||
local_index,
|
||||
@ -249,7 +257,7 @@ pub fn set_local(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn add(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn add(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Add {
|
||||
destination,
|
||||
left,
|
||||
@ -297,7 +305,7 @@ pub fn add(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn subtract(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn subtract(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Subtract {
|
||||
destination,
|
||||
left,
|
||||
@ -345,7 +353,7 @@ pub fn subtract(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn multiply(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn multiply(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Multiply {
|
||||
destination,
|
||||
left,
|
||||
@ -393,7 +401,7 @@ pub fn multiply(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn divide(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn divide(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Divide {
|
||||
destination,
|
||||
left,
|
||||
@ -441,7 +449,7 @@ pub fn divide(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn modulo(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn modulo(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Modulo {
|
||||
destination,
|
||||
left,
|
||||
@ -475,7 +483,7 @@ pub fn modulo(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn test(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn test(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Test {
|
||||
operand_register,
|
||||
test_value,
|
||||
@ -498,7 +506,7 @@ pub fn test(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn test_set(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn test_set(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let TestSet {
|
||||
destination,
|
||||
argument,
|
||||
@ -527,7 +535,7 @@ pub fn test_set(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn equal(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn equal(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Equal {
|
||||
comparator,
|
||||
left,
|
||||
@ -606,7 +614,7 @@ pub fn equal(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn less(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn less(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Less {
|
||||
comparator,
|
||||
left,
|
||||
@ -657,7 +665,7 @@ pub fn less(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn less_equal(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn less_equal(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let LessEqual {
|
||||
comparator,
|
||||
left,
|
||||
@ -708,7 +716,7 @@ pub fn less_equal(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn negate(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn negate(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Negate {
|
||||
destination,
|
||||
argument,
|
||||
@ -725,7 +733,7 @@ pub fn negate(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn not(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn not(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Not {
|
||||
destination,
|
||||
argument,
|
||||
@ -744,7 +752,7 @@ pub fn not(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn jump(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn jump(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Jump {
|
||||
offset,
|
||||
is_positive,
|
||||
@ -763,7 +771,7 @@ pub fn jump(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn call(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn call(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let Call {
|
||||
destination: return_register,
|
||||
function_register,
|
||||
@ -782,7 +790,7 @@ pub fn call(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
|
||||
current_call.chunk.prototypes[function.prototype_index as usize].clone()
|
||||
};
|
||||
let mut next_call = FunctionCall::new(prototype, return_register);
|
||||
let mut next_call = CallFrame::new(prototype, return_register);
|
||||
let mut argument_index = 0;
|
||||
|
||||
for register_index in first_argument_register..return_register {
|
||||
@ -804,7 +812,7 @@ pub fn call(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn call_native(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn call_native(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
let CallNative {
|
||||
destination,
|
||||
function,
|
||||
@ -816,7 +824,7 @@ pub fn call_native(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
function.call(data, destination, argument_range)
|
||||
}
|
||||
|
||||
pub fn r#return(instruction: Instruction, data: &mut ThreadData) -> bool {
|
||||
pub fn r#return(instruction: InstructionBuilder, data: &mut Thread) -> bool {
|
||||
trace!("Returning with call stack:\n{}", data.call_stack);
|
||||
|
||||
let Return {
|
@ -8,14 +8,14 @@ use crate::{Chunk, DustString};
|
||||
use super::Register;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FunctionCall {
|
||||
pub struct CallFrame {
|
||||
pub chunk: Arc<Chunk>,
|
||||
pub ip: usize,
|
||||
pub return_register: u16,
|
||||
pub registers: Vec<Register>,
|
||||
}
|
||||
|
||||
impl FunctionCall {
|
||||
impl CallFrame {
|
||||
pub fn new(chunk: Arc<Chunk>, return_register: u16) -> Self {
|
||||
let register_count = chunk.register_count;
|
||||
|
||||
@ -28,7 +28,7 @@ impl FunctionCall {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for FunctionCall {
|
||||
impl Display for CallFrame {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
@ -1,7 +1,6 @@
|
||||
//! Virtual machine and errors
|
||||
mod function_call;
|
||||
mod run_action;
|
||||
mod stack;
|
||||
mod action;
|
||||
mod call_frame;
|
||||
mod thread;
|
||||
|
||||
use std::{
|
||||
@ -10,11 +9,10 @@ use std::{
|
||||
thread::Builder,
|
||||
};
|
||||
|
||||
pub use function_call::FunctionCall;
|
||||
pub use run_action::RunAction;
|
||||
pub(crate) use run_action::get_next_action;
|
||||
pub use stack::Stack;
|
||||
pub use thread::{Thread, ThreadData};
|
||||
pub use action::Action;
|
||||
pub(crate) use action::get_next_action;
|
||||
pub use call_frame::CallFrame;
|
||||
pub use thread::Thread;
|
||||
|
||||
use crossbeam_channel::bounded;
|
||||
use tracing::{Level, span};
|
||||
@ -46,12 +44,13 @@ impl Vm {
|
||||
.as_ref()
|
||||
.map(|name| name.to_string())
|
||||
.unwrap_or_else(|| "anonymous".to_string());
|
||||
let mut main_thread = Thread::new(Arc::new(self.main_chunk));
|
||||
let (tx, rx) = bounded(1);
|
||||
let main_chunk = Arc::new(self.main_chunk);
|
||||
|
||||
Builder::new()
|
||||
.name(thread_name)
|
||||
.spawn(move || {
|
||||
let main_thread = Thread::new(main_chunk);
|
||||
let value_option = main_thread.run();
|
||||
let _ = tx.send(value_option);
|
||||
})
|
||||
|
@ -1,137 +0,0 @@
|
||||
use std::{
|
||||
fmt::{self, Debug, Display, Formatter},
|
||||
ops::{Index, IndexMut, Range},
|
||||
};
|
||||
|
||||
use super::FunctionCall;
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Stack<T> {
|
||||
items: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T> Stack<T> {
|
||||
pub fn new() -> Self {
|
||||
Stack {
|
||||
items: Vec::with_capacity(1),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_capacity(capacity: usize) -> Self {
|
||||
Stack {
|
||||
items: Vec::with_capacity(capacity),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.items.is_empty()
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.items.len()
|
||||
}
|
||||
|
||||
pub fn get_unchecked(&self, index: usize) -> &T {
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(index < self.len(), "Stack underflow");
|
||||
|
||||
&self.items[index]
|
||||
} else {
|
||||
unsafe { self.items.get_unchecked(index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_unchecked_mut(&mut self, index: usize) -> &mut T {
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(index < self.len(), "Stack underflow");
|
||||
|
||||
&mut self.items[index]
|
||||
} else {
|
||||
unsafe { self.items.get_unchecked_mut(index) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn push(&mut self, item: T) {
|
||||
self.items.push(item);
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Option<T> {
|
||||
self.items.pop()
|
||||
}
|
||||
|
||||
pub fn last(&self) -> Option<&T> {
|
||||
self.items.last()
|
||||
}
|
||||
|
||||
pub fn last_mut(&mut self) -> Option<&mut T> {
|
||||
self.items.last_mut()
|
||||
}
|
||||
|
||||
pub fn pop_unchecked(&mut self) -> T {
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(!self.is_empty(), "Stack underflow");
|
||||
|
||||
self.items.pop().unwrap()
|
||||
} else {
|
||||
unsafe { self.items.pop().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_unchecked(&self) -> &T {
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(!self.is_empty(), "Stack underflow");
|
||||
|
||||
self.items.last().unwrap()
|
||||
} else {
|
||||
unsafe { self.items.last().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_mut_unchecked(&mut self) -> &mut T {
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(!self.is_empty(), "Stack underflow");
|
||||
|
||||
self.items.last_mut().unwrap()
|
||||
} else {
|
||||
unsafe { self.items.last_mut().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Default for Stack<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Index<Range<usize>> for Stack<T> {
|
||||
type Output = [T];
|
||||
|
||||
fn index(&self, index: Range<usize>) -> &Self::Output {
|
||||
&self.items[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IndexMut<Range<usize>> for Stack<T> {
|
||||
fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
|
||||
&mut self.items[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Debug> Debug for Stack<T> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{:?}", self.items)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Stack<FunctionCall> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
writeln!(f, "----- DUST CALL STACK -----")?;
|
||||
|
||||
for (index, function_call) in self.items.iter().enumerate().rev() {
|
||||
writeln!(f, "{index:02} | {function_call}")?;
|
||||
}
|
||||
|
||||
write!(f, "---------------------------")
|
||||
}
|
||||
}
|
@ -2,20 +2,36 @@ use std::{mem::replace, sync::Arc, thread::JoinHandle};
|
||||
|
||||
use tracing::{info, trace};
|
||||
|
||||
use crate::{Chunk, DustString, Operand, Span, Value, vm::FunctionCall};
|
||||
use crate::{
|
||||
Chunk, DustString, Operand, Span, Value,
|
||||
vm::{CallFrame, action::ActionSequence},
|
||||
};
|
||||
|
||||
use super::{Pointer, Register, RunAction, Stack};
|
||||
use super::{Pointer, Register};
|
||||
|
||||
pub struct Thread {
|
||||
chunk: Arc<Chunk>,
|
||||
call_stack: Vec<CallFrame>,
|
||||
return_value_index: Option<Option<usize>>,
|
||||
spawned_threads: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
pub fn new(chunk: Arc<Chunk>) -> Self {
|
||||
Thread { chunk }
|
||||
let mut call_stack = Vec::with_capacity(chunk.prototypes.len() + 1);
|
||||
let main_call = CallFrame::new(Arc::clone(&chunk), 0);
|
||||
|
||||
call_stack.push(main_call);
|
||||
|
||||
Thread {
|
||||
chunk,
|
||||
call_stack,
|
||||
return_value_index: None,
|
||||
spawned_threads: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Option<Value> {
|
||||
pub fn run(mut self) -> Option<Value> {
|
||||
info!(
|
||||
"Starting thread with {}",
|
||||
self.chunk
|
||||
@ -24,64 +40,59 @@ impl Thread {
|
||||
.unwrap_or_else(|| DustString::from("anonymous"))
|
||||
);
|
||||
|
||||
let mut call_stack = Stack::with_capacity(self.chunk.prototypes.len() + 1);
|
||||
let mut main_call = FunctionCall::new(self.chunk.clone(), 0);
|
||||
main_call.ip = 1; // The first action is already known
|
||||
|
||||
call_stack.push(main_call);
|
||||
|
||||
let first_action = RunAction::from(*self.chunk.instructions.first().unwrap());
|
||||
let mut thread_data = ThreadData {
|
||||
call_stack,
|
||||
next_action: first_action,
|
||||
return_value_index: None,
|
||||
spawned_threads: Vec::new(),
|
||||
};
|
||||
let main_call = self.current_frame();
|
||||
let action_sequence = ActionSequence::new(&main_call.chunk.instructions);
|
||||
|
||||
loop {
|
||||
trace!("Instruction: {}", thread_data.next_action.instruction);
|
||||
let current_frame = self.current_frame_mut();
|
||||
let ip = {
|
||||
let ip = current_frame.ip;
|
||||
current_frame.ip += 1;
|
||||
|
||||
let should_end = (thread_data.next_action.logic)(
|
||||
thread_data.next_action.instruction,
|
||||
&mut thread_data,
|
||||
);
|
||||
ip
|
||||
};
|
||||
let current_action = if cfg!(debug_assertions) {
|
||||
action_sequence.actions.get(ip).unwrap()
|
||||
} else {
|
||||
unsafe { action_sequence.actions.get_unchecked(ip) }
|
||||
};
|
||||
|
||||
if should_end {
|
||||
let value_option = if let Some(register_index) = thread_data.return_value_index {
|
||||
let value =
|
||||
thread_data.empty_register_or_clone_constant_unchecked(register_index);
|
||||
trace!("Operation: {}", current_action.instruction.operation);
|
||||
|
||||
Some(value)
|
||||
(current_action.logic)(current_action.instruction, &mut self);
|
||||
|
||||
if let Some(return_index_option) = self.return_value_index {
|
||||
if let Some(return_index) = return_index_option {
|
||||
let return_value = self.open_register_unchecked(return_index as u16).clone();
|
||||
|
||||
return Some(return_value);
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
thread_data
|
||||
.spawned_threads
|
||||
.into_iter()
|
||||
.for_each(|join_handle| {
|
||||
let _ = join_handle.join();
|
||||
});
|
||||
|
||||
return value_option;
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ThreadData {
|
||||
pub call_stack: Stack<FunctionCall>,
|
||||
pub next_action: RunAction,
|
||||
pub return_value_index: Option<u16>,
|
||||
pub spawned_threads: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl ThreadData {
|
||||
pub fn current_position(&self) -> Span {
|
||||
let current_call = self.call_stack.last_unchecked();
|
||||
let current_frame = self.current_frame();
|
||||
|
||||
current_call.chunk.positions[current_call.ip]
|
||||
current_frame.chunk.positions[current_frame.ip]
|
||||
}
|
||||
|
||||
pub fn current_frame(&self) -> &CallFrame {
|
||||
if cfg!(debug_assertions) {
|
||||
self.call_stack.last().unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.last().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn current_frame_mut(&mut self) -> &mut CallFrame {
|
||||
if cfg!(debug_assertions) {
|
||||
self.call_stack.last_mut().unwrap()
|
||||
} else {
|
||||
unsafe { self.call_stack.last_mut().unwrap_unchecked() }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn follow_pointer_unchecked(&self, pointer: Pointer) -> &Value {
|
||||
|
Loading…
x
Reference in New Issue
Block a user