New VM optimizations; Pass all tests
This commit is contained in:
parent
69ef1b3b06
commit
8940f37654
@ -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 })
|
||||
}
|
||||
|
@ -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",
|
||||
|
@ -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, "[")?;
|
||||
|
@ -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();
|
||||
|
259
dust-lang/src/vm/action/add.rs
Normal file
259
dust-lang/src/vm/action/add.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
28
dust-lang/src/vm/action/jump.rs
Normal file
28
dust-lang/src/vm/action/jump.rs
Normal file
@ -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;
|
||||
}
|
||||
}
|
232
dust-lang/src/vm/action/less.rs
Normal file
232
dust-lang/src/vm/action/less.rs
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -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<Chunk>,
|
||||
pub chunk: Rc<Chunk>,
|
||||
pub ip: usize,
|
||||
pub return_register: u16,
|
||||
pub registers: RegisterTable,
|
||||
pub action_sequence: ActionSequence,
|
||||
pub pointer_caches: Vec<PointerCache>,
|
||||
}
|
||||
|
||||
impl CallFrame {
|
||||
pub fn new(chunk: Arc<Chunk>, return_register: u16) -> Self {
|
||||
pub fn new(chunk: Rc<Chunk>, 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<T> {
|
||||
Empty,
|
||||
pub enum Register<T: Default> {
|
||||
Value(T),
|
||||
Closed(T),
|
||||
Pointer(Pointer),
|
||||
}
|
||||
|
||||
impl<T> Register<T> {
|
||||
impl<T: Default> Register<T> {
|
||||
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<T: Display> Display for Register<T> {
|
||||
impl<T: Default> Default for Register<T> {
|
||||
fn default() -> Self {
|
||||
Self::Value(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Default + Display> Display for Register<T> {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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>,
|
||||
chunk: Rc<Chunk>,
|
||||
call_stack: Vec<CallFrame>,
|
||||
pub return_value: Option<Option<Value>>,
|
||||
pub return_value: Option<Value>,
|
||||
_spawned_threads: Vec<JoinHandle<()>>,
|
||||
}
|
||||
|
||||
impl Thread {
|
||||
pub fn new(chunk: Arc<Chunk>) -> Self {
|
||||
pub fn new(chunk: Rc<Chunk>) -> 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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user