1
0

New VM optimizations; Pass all tests

This commit is contained in:
Jeff 2025-02-12 17:00:27 -05:00
parent 69ef1b3b06
commit 8940f37654
11 changed files with 873 additions and 720 deletions

View File

@ -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 })
}

View File

@ -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",

View File

@ -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, "[")?;

View File

@ -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();

View 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);
}
}

View 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;
}
}

View 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

View File

@ -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()
}
}

View File

@ -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()

View File

@ -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);