Add new benchmarks; Experiment with VM optimizations
This commit is contained in:
parent
4145499e0c
commit
720f006d8c
29
dust-lang/benches/addictive_division.rs
Normal file
29
dust-lang/benches/addictive_division.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
use dust_lang::run;
|
||||||
|
|
||||||
|
const SOURCE: &str = r"
|
||||||
|
let mut i = 1.7976931348623157e308
|
||||||
|
|
||||||
|
while i > 1.0 {
|
||||||
|
i /= 1.00014196662;
|
||||||
|
}
|
||||||
|
";
|
||||||
|
|
||||||
|
fn addictive_division(source: &str) {
|
||||||
|
run(source).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn criterion_benchmark(c: &mut Criterion) {
|
||||||
|
let mut group = c.benchmark_group("addictive_division");
|
||||||
|
|
||||||
|
group.measurement_time(Duration::from_secs(15));
|
||||||
|
group.bench_function("addictive_division", |b| {
|
||||||
|
b.iter(|| addictive_division(black_box(SOURCE)))
|
||||||
|
});
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, criterion_benchmark);
|
||||||
|
criterion_main!(benches);
|
29
dust-lang/benches/addictive_multiplication.rs
Normal file
29
dust-lang/benches/addictive_multiplication.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
use dust_lang::run;
|
||||||
|
|
||||||
|
const SOURCE: &str = r"
|
||||||
|
let mut i = 1.0
|
||||||
|
|
||||||
|
while i < 1.7976931348623157e308 {
|
||||||
|
i *= 1.00014196662
|
||||||
|
}
|
||||||
|
";
|
||||||
|
|
||||||
|
fn addictive_multiplication(source: &str) {
|
||||||
|
run(source).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn criterion_benchmark(c: &mut Criterion) {
|
||||||
|
let mut group = c.benchmark_group("addictive_multiplication");
|
||||||
|
|
||||||
|
group.measurement_time(Duration::from_secs(15));
|
||||||
|
group.bench_function("addictive_multiplication", |b| {
|
||||||
|
b.iter(|| addictive_multiplication(black_box(SOURCE)))
|
||||||
|
});
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, criterion_benchmark);
|
||||||
|
criterion_main!(benches);
|
29
dust-lang/benches/addictive_subtraction.rs
Normal file
29
dust-lang/benches/addictive_subtraction.rs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||||
|
use dust_lang::run;
|
||||||
|
|
||||||
|
const SOURCE: &str = r"
|
||||||
|
let mut i = 5_000_000
|
||||||
|
|
||||||
|
while i > 0 {
|
||||||
|
i -= 1
|
||||||
|
}
|
||||||
|
";
|
||||||
|
|
||||||
|
fn addictive_subtraction(source: &str) {
|
||||||
|
run(source).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn criterion_benchmark(c: &mut Criterion) {
|
||||||
|
let mut group = c.benchmark_group("addictive_subtraction");
|
||||||
|
|
||||||
|
group.measurement_time(Duration::from_secs(15));
|
||||||
|
group.bench_function("addictive_subtraction", |b| {
|
||||||
|
b.iter(|| addictive_subtraction(black_box(SOURCE)))
|
||||||
|
});
|
||||||
|
group.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
criterion_group!(benches, criterion_benchmark);
|
||||||
|
criterion_main!(benches);
|
@ -1,259 +1,39 @@
|
|||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
DustString,
|
|
||||||
instruction::{InstructionFields, TypeCode},
|
instruction::{InstructionFields, TypeCode},
|
||||||
vm::{Register, Thread, call_frame::PointerCache},
|
vm::{call_frame::PointerCache, Register, Thread},
|
||||||
|
DustString,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn add(
|
pub fn add_integers(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
_: &mut usize,
|
trace!("ADD: Run and cache pointers");
|
||||||
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 destination = instruction.a_field as usize;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_is_constant = instruction.b_is_constant;
|
let left_is_constant = instruction.b_is_constant;
|
||||||
let right = instruction.c_field as usize;
|
let right = instruction.c_field as usize;
|
||||||
let right_is_constant = instruction.c_is_constant;
|
let right_is_constant = instruction.c_is_constant;
|
||||||
|
|
||||||
if pointer_cache.integer_mut.is_null() {
|
let left_value = if left_is_constant {
|
||||||
trace!("ADD: Run and cache pointers");
|
if cfg!(debug_assertions) {
|
||||||
|
thread.get_constant(left).as_integer().unwrap()
|
||||||
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 {
|
} else {
|
||||||
thread.get_integer_register(left)
|
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
|
||||||
};
|
}
|
||||||
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 {
|
} else {
|
||||||
trace!("ADD: Use cached pointers");
|
thread.get_integer_register(left)
|
||||||
|
|
||||||
add_integer_pointers(
|
|
||||||
pointer_cache.integer_mut,
|
|
||||||
pointer_cache.integer_left,
|
|
||||||
pointer_cache.integer_right,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
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);
|
||||||
|
|
||||||
pub fn add_integer_pointers(destination: *mut i64, left: *const i64, right: *const i64) {
|
thread.set_integer_register(destination, Register::Value(sum));
|
||||||
assert!(destination.is_aligned());
|
|
||||||
assert!(left.is_aligned());
|
|
||||||
assert!(right.is_aligned());
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
*destination = (*left).saturating_add(*right);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -2,15 +2,10 @@ use tracing::trace;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::InstructionFields,
|
instruction::InstructionFields,
|
||||||
vm::{Thread, call_frame::PointerCache},
|
vm::{call_frame::PointerCache, Thread},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn jump(
|
pub fn jump(ip: &mut usize, instruction: &InstructionFields, _: &mut Thread) {
|
||||||
ip: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
_: &mut Thread,
|
|
||||||
_pointer_cache: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let offset = instruction.b_field as usize;
|
let offset = instruction.b_field as usize;
|
||||||
let is_positive = instruction.c_field != 0;
|
let is_positive = instruction.c_field != 0;
|
||||||
|
|
||||||
|
@ -2,231 +2,38 @@ use tracing::trace;
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::{InstructionFields, TypeCode},
|
instruction::{InstructionFields, TypeCode},
|
||||||
vm::{Thread, call_frame::PointerCache},
|
vm::{call_frame::PointerCache, Thread},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn less(
|
pub fn less_integers(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
ip: &mut usize,
|
trace!("LESS unoptimized");
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
pointer_cache: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let comparator = instruction.d_field;
|
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_type = instruction.b_type;
|
|
||||||
let left_is_constant = instruction.b_is_constant;
|
let left_is_constant = instruction.b_is_constant;
|
||||||
let right = instruction.c_field as usize;
|
let right = instruction.c_field as usize;
|
||||||
let right_type = instruction.c_type;
|
|
||||||
let right_is_constant = instruction.c_is_constant;
|
let right_is_constant = instruction.c_is_constant;
|
||||||
|
let left_value = if left_is_constant {
|
||||||
match (left_type, right_type) {
|
if cfg!(debug_assertions) {
|
||||||
(TypeCode::BOOLEAN, TypeCode::BOOLEAN) => {
|
thread.get_constant(left).as_integer().unwrap()
|
||||||
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 {
|
} else {
|
||||||
thread.get_integer_register(left)
|
unsafe { thread.get_constant(left).as_integer().unwrap_unchecked() }
|
||||||
} 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 {
|
} else {
|
||||||
trace!("LESS: Use cached pointers");
|
thread.get_integer_register(left)
|
||||||
|
|
||||||
less_integer_pointers(
|
|
||||||
ip,
|
|
||||||
pointer_cache.integer_left,
|
|
||||||
pointer_cache.integer_right,
|
|
||||||
instruction.d_field,
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
}
|
let right_value = if right_is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
pub fn less_integer_pointers(
|
thread.get_constant(right).as_integer().unwrap()
|
||||||
ip: *mut usize,
|
} else {
|
||||||
left: *const i64,
|
unsafe { thread.get_constant(right).as_integer().unwrap_unchecked() }
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
thread.get_integer_register(right)
|
||||||
|
};
|
||||||
|
let is_less_than = left_value < right_value;
|
||||||
|
let comparator = instruction.d_field;
|
||||||
|
|
||||||
|
if is_less_than == comparator {
|
||||||
|
*ip += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,36 +2,35 @@ mod add;
|
|||||||
mod jump;
|
mod jump;
|
||||||
mod less;
|
mod less;
|
||||||
|
|
||||||
use add::{add, add_integer_pointers};
|
use add::add_integers;
|
||||||
use jump::jump;
|
use jump::jump;
|
||||||
use less::{less, less_integer_pointers};
|
use less::less_integers;
|
||||||
|
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::{
|
||||||
|
fmt::{self, Display, Formatter},
|
||||||
use crate::{
|
ptr,
|
||||||
AbstractList, ConcreteValue, Operation, Value,
|
|
||||||
instruction::{InstructionFields, TypeCode},
|
|
||||||
vm::call_frame::PointerCache,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Pointer, Register, thread::Thread};
|
use crate::{
|
||||||
|
instruction::{InstructionFields, TypeCode},
|
||||||
|
vm::call_frame::PointerCache,
|
||||||
|
AbstractList, ConcreteValue, Operation, Value,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::{thread::Thread, Pointer, Register};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ActionSequence {
|
pub struct ActionSequence {
|
||||||
pub actions: Vec<Action>,
|
pub actions: Vec<(Action, InstructionFields)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ActionSequence {
|
impl ActionSequence {
|
||||||
#[allow(clippy::while_let_on_iterator)]
|
#[allow(clippy::while_let_on_iterator)]
|
||||||
pub fn new<T>(instructions: T) -> Self
|
pub fn new(instructions: Vec<InstructionFields>) -> Self {
|
||||||
where
|
|
||||||
T: ExactSizeIterator<Item = InstructionFields> + DoubleEndedIterator + Clone,
|
|
||||||
{
|
|
||||||
let mut actions = Vec::with_capacity(instructions.len());
|
let mut actions = Vec::with_capacity(instructions.len());
|
||||||
let mut instructions_reversed = instructions.rev();
|
let mut instructions_reversed = instructions.into_iter().rev();
|
||||||
let mut in_loop = false;
|
|
||||||
|
|
||||||
while let Some(instruction) = instructions_reversed.next() {
|
while let Some(instruction) = instructions_reversed.next() {
|
||||||
if instruction.operation == Operation::JUMP {
|
if instruction.operation == Operation::JUMP {
|
||||||
@ -39,49 +38,33 @@ impl ActionSequence {
|
|||||||
let is_positive = instruction.c_field != 0;
|
let is_positive = instruction.c_field != 0;
|
||||||
|
|
||||||
if !is_positive {
|
if !is_positive {
|
||||||
let mut loop_instructions = Vec::new();
|
let mut loop_actions = Vec::with_capacity(backward_offset + 1);
|
||||||
let mut previous = instruction;
|
let jump_action = Action::optimized(&instruction);
|
||||||
|
|
||||||
in_loop = true;
|
loop_actions.push((jump_action, instruction));
|
||||||
|
|
||||||
loop_instructions.push(instruction);
|
for _ in 0..backward_offset {
|
||||||
|
let instruction = instructions_reversed.next().unwrap();
|
||||||
|
let action = Action::optimized(&instruction);
|
||||||
|
|
||||||
while let Some(instruction) = instructions_reversed.next() {
|
loop_actions.push((action, instruction));
|
||||||
loop_instructions.push(instruction);
|
|
||||||
|
|
||||||
if instruction.operation == Operation::LESS
|
|
||||||
&& previous.operation == Operation::JUMP
|
|
||||||
{
|
|
||||||
let forward_offset = previous.b_field as usize;
|
|
||||||
let is_positive = previous.c_field != 0;
|
|
||||||
|
|
||||||
if is_positive && forward_offset == backward_offset - 1 {
|
|
||||||
in_loop = false;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
previous = instruction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_instructions.reverse();
|
loop_actions.reverse();
|
||||||
|
|
||||||
let loop_action = Action::optimized_loop(loop_instructions);
|
let r#loop = Action::r#loop(ActionSequence {
|
||||||
|
actions: loop_actions,
|
||||||
|
});
|
||||||
|
|
||||||
actions.push(loop_action);
|
actions.push((r#loop, instruction));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = if in_loop {
|
let action = Action::unoptimized(instruction);
|
||||||
Action::optimized_inline(instruction)
|
|
||||||
} else {
|
|
||||||
Action::unoptimized(instruction)
|
|
||||||
};
|
|
||||||
|
|
||||||
actions.push(action);
|
actions.push((action, instruction));
|
||||||
}
|
}
|
||||||
|
|
||||||
actions.reverse();
|
actions.reverse();
|
||||||
@ -93,54 +76,101 @@ impl ActionSequence {
|
|||||||
self.actions.len()
|
self.actions.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self, thread: &mut Thread) {
|
pub fn run(&mut self, thread: &mut Thread) {
|
||||||
let mut pointer_caches = vec![PointerCache::new(); self.actions.len()];
|
|
||||||
let mut local_ip = 0;
|
let mut local_ip = 0;
|
||||||
|
|
||||||
while local_ip < self.actions.len() {
|
while local_ip < self.actions.len() {
|
||||||
assert!(local_ip < self.actions.len());
|
let (action, instruction) = &mut self.actions[local_ip];
|
||||||
assert!(local_ip < pointer_caches.len());
|
|
||||||
|
|
||||||
let action = &self.actions[local_ip];
|
|
||||||
let cache = &mut pointer_caches[local_ip];
|
|
||||||
local_ip += 1;
|
local_ip += 1;
|
||||||
|
|
||||||
trace!("Run {action}");
|
trace!("Run {action}");
|
||||||
|
|
||||||
if let Some(loop_actions) = &action.loop_actions {
|
match action {
|
||||||
loop_actions.run(thread);
|
Action::Unoptimized { logic, instruction } => {
|
||||||
} else if action.optimize_inline {
|
logic(&mut local_ip, &*instruction, thread);
|
||||||
match action.instruction.operation {
|
}
|
||||||
Operation::ADD => {
|
Action::Loop { actions } => {
|
||||||
if cache.integer_mut.is_null() {
|
actions.run(thread);
|
||||||
add(&mut local_ip, action.instruction, thread, cache);
|
}
|
||||||
} else {
|
Action::OptimizedAddIntegers {
|
||||||
add_integer_pointers(
|
destination_pointer,
|
||||||
cache.integer_mut,
|
left_pointer,
|
||||||
cache.integer_left,
|
right_pointer,
|
||||||
cache.integer_right,
|
} => {
|
||||||
);
|
let left = if left_pointer.is_null() || !left_pointer.is_aligned() {
|
||||||
|
let left_index = instruction.b_field as usize;
|
||||||
|
let left_is_constant = instruction.b_is_constant;
|
||||||
|
let left_value = thread.get_integer(left_index, left_is_constant);
|
||||||
|
|
||||||
|
*left_pointer = left_value;
|
||||||
|
|
||||||
|
left_value
|
||||||
|
} else {
|
||||||
|
unsafe { &ptr::read(*left_pointer) }
|
||||||
|
};
|
||||||
|
let right = if right_pointer.is_null() || !right_pointer.is_aligned() {
|
||||||
|
let right_index = instruction.c_field as usize;
|
||||||
|
let right_is_constant = instruction.c_is_constant;
|
||||||
|
let right_value = thread.get_integer(right_index, right_is_constant);
|
||||||
|
|
||||||
|
*right_pointer = right_value;
|
||||||
|
|
||||||
|
right_value
|
||||||
|
} else {
|
||||||
|
unsafe { &ptr::read(*right_pointer) }
|
||||||
|
};
|
||||||
|
let sum = left.saturating_add(*right);
|
||||||
|
|
||||||
|
if destination_pointer.is_null() || !destination_pointer.is_aligned() {
|
||||||
|
let destination = instruction.a_field as usize;
|
||||||
|
let register = Register::Value(sum);
|
||||||
|
|
||||||
|
thread.set_integer_register(destination, register);
|
||||||
|
} else {
|
||||||
|
unsafe {
|
||||||
|
**destination_pointer = sum;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operation::LESS => {
|
|
||||||
if cache.integer_left.is_null() {
|
|
||||||
less(&mut local_ip, action.instruction, thread, cache);
|
|
||||||
} else {
|
|
||||||
less_integer_pointers(
|
|
||||||
&mut local_ip,
|
|
||||||
cache.integer_left,
|
|
||||||
cache.integer_right,
|
|
||||||
action.instruction.d_field,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Operation::JUMP => jump(&mut local_ip, action.instruction, thread, cache),
|
|
||||||
_ => {
|
|
||||||
(action.logic)(&mut local_ip, action.instruction, thread, cache);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
Action::OptimizedLessIntegers {
|
||||||
(action.logic)(&mut local_ip, action.instruction, thread, cache);
|
left_pointer,
|
||||||
|
right_pointer,
|
||||||
|
} => {
|
||||||
|
let left = if left_pointer.is_null() || !left_pointer.is_aligned() {
|
||||||
|
let left_index = instruction.b_field as usize;
|
||||||
|
let left_is_constant = instruction.b_is_constant;
|
||||||
|
let left_value = thread.get_integer(left_index, left_is_constant);
|
||||||
|
|
||||||
|
*left_pointer = left_value;
|
||||||
|
|
||||||
|
left_value
|
||||||
|
} else {
|
||||||
|
unsafe { &ptr::read(*left_pointer) }
|
||||||
|
};
|
||||||
|
let right = if right_pointer.is_null() || !right_pointer.is_aligned() {
|
||||||
|
let right_index = instruction.c_field as usize;
|
||||||
|
let right_is_constant = instruction.c_is_constant;
|
||||||
|
let right_value = thread.get_integer(right_index, right_is_constant);
|
||||||
|
|
||||||
|
*right_pointer = right_value;
|
||||||
|
|
||||||
|
right_value
|
||||||
|
} else {
|
||||||
|
unsafe { &ptr::read(*right_pointer) }
|
||||||
|
};
|
||||||
|
let is_less_than = left < right;
|
||||||
|
let comparator = instruction.d_field;
|
||||||
|
|
||||||
|
if is_less_than == comparator {
|
||||||
|
local_ip += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Action::OptimizedJumpForward { offset } => {
|
||||||
|
local_ip += *offset;
|
||||||
|
}
|
||||||
|
Action::OptimizedJumpBackward { offset } => {
|
||||||
|
local_ip -= *offset + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -150,12 +180,12 @@ impl Display for ActionSequence {
|
|||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
write!(f, "[")?;
|
write!(f, "[")?;
|
||||||
|
|
||||||
for (index, action) in self.actions.iter().enumerate() {
|
for (index, (action, _)) in self.actions.iter().enumerate() {
|
||||||
write!(f, "{action}")?;
|
if index > 0 {
|
||||||
|
|
||||||
if index < self.actions.len() - 1 {
|
|
||||||
write!(f, ", ")?;
|
write!(f, ", ")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
write!(f, "{action}")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "]")
|
write!(f, "]")
|
||||||
@ -163,43 +193,33 @@ impl Display for ActionSequence {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Action {
|
pub enum Action {
|
||||||
pub logic: ActionLogic,
|
Unoptimized {
|
||||||
pub instruction: InstructionFields,
|
logic: ActionLogic,
|
||||||
pub optimize_inline: bool,
|
instruction: InstructionFields,
|
||||||
pub loop_actions: Option<ActionSequence>,
|
},
|
||||||
|
Loop {
|
||||||
|
actions: ActionSequence,
|
||||||
|
},
|
||||||
|
OptimizedAddIntegers {
|
||||||
|
destination_pointer: *mut i64,
|
||||||
|
left_pointer: *const i64,
|
||||||
|
right_pointer: *const i64,
|
||||||
|
},
|
||||||
|
OptimizedLessIntegers {
|
||||||
|
left_pointer: *const i64,
|
||||||
|
right_pointer: *const i64,
|
||||||
|
},
|
||||||
|
OptimizedJumpForward {
|
||||||
|
offset: usize,
|
||||||
|
},
|
||||||
|
OptimizedJumpBackward {
|
||||||
|
offset: usize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Action {
|
impl Action {
|
||||||
fn optimized_loop(instructions: Vec<InstructionFields>) -> Self {
|
pub fn unoptimized(instruction: InstructionFields) -> Self {
|
||||||
let mut loop_actions = Vec::with_capacity(instructions.len());
|
|
||||||
|
|
||||||
for instruction in instructions {
|
|
||||||
let action = Action::optimized_inline(instruction);
|
|
||||||
|
|
||||||
loop_actions.push(action);
|
|
||||||
}
|
|
||||||
|
|
||||||
Action {
|
|
||||||
logic: no_op,
|
|
||||||
instruction: InstructionFields::default(),
|
|
||||||
optimize_inline: false,
|
|
||||||
loop_actions: Some(ActionSequence {
|
|
||||||
actions: loop_actions,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn optimized_inline(instruction: InstructionFields) -> Self {
|
|
||||||
Action {
|
|
||||||
logic: no_op,
|
|
||||||
optimize_inline: true,
|
|
||||||
instruction,
|
|
||||||
loop_actions: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unoptimized(instruction: InstructionFields) -> Self {
|
|
||||||
let logic = match instruction.operation {
|
let logic = match instruction.operation {
|
||||||
Operation::POINT => point,
|
Operation::POINT => point,
|
||||||
Operation::CLOSE => close,
|
Operation::CLOSE => close,
|
||||||
@ -208,7 +228,10 @@ impl Action {
|
|||||||
Operation::LOAD_LIST => load_list,
|
Operation::LOAD_LIST => load_list,
|
||||||
Operation::LOAD_FUNCTION => load_function,
|
Operation::LOAD_FUNCTION => load_function,
|
||||||
Operation::LOAD_SELF => load_self,
|
Operation::LOAD_SELF => load_self,
|
||||||
Operation::ADD => add,
|
Operation::ADD => match (instruction.b_type, instruction.c_type) {
|
||||||
|
(TypeCode::INTEGER, TypeCode::INTEGER) => add_integers,
|
||||||
|
_ => todo!(),
|
||||||
|
},
|
||||||
Operation::SUBTRACT => subtract,
|
Operation::SUBTRACT => subtract,
|
||||||
Operation::MULTIPLY => multiply,
|
Operation::MULTIPLY => multiply,
|
||||||
Operation::DIVIDE => divide,
|
Operation::DIVIDE => divide,
|
||||||
@ -216,7 +239,10 @@ impl Action {
|
|||||||
Operation::NEGATE => negate,
|
Operation::NEGATE => negate,
|
||||||
Operation::NOT => not,
|
Operation::NOT => not,
|
||||||
Operation::EQUAL => equal,
|
Operation::EQUAL => equal,
|
||||||
Operation::LESS => less,
|
Operation::LESS => match (instruction.b_type, instruction.c_type) {
|
||||||
|
(TypeCode::INTEGER, TypeCode::INTEGER) => less_integers,
|
||||||
|
_ => todo!(),
|
||||||
|
},
|
||||||
Operation::LESS_EQUAL => less_equal,
|
Operation::LESS_EQUAL => less_equal,
|
||||||
Operation::TEST => test,
|
Operation::TEST => test,
|
||||||
Operation::TEST_SET => test_set,
|
Operation::TEST_SET => test_set,
|
||||||
@ -227,30 +253,75 @@ impl Action {
|
|||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Action {
|
Action::Unoptimized { logic, instruction }
|
||||||
logic,
|
}
|
||||||
instruction,
|
|
||||||
optimize_inline: false,
|
pub fn optimized(instruction: &InstructionFields) -> Self {
|
||||||
loop_actions: None,
|
match instruction.operation {
|
||||||
|
Operation::ADD => match (instruction.b_type, instruction.c_type) {
|
||||||
|
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedAddIntegers {
|
||||||
|
destination_pointer: std::ptr::null_mut(),
|
||||||
|
left_pointer: std::ptr::null(),
|
||||||
|
right_pointer: std::ptr::null(),
|
||||||
|
},
|
||||||
|
_ => todo!(),
|
||||||
|
},
|
||||||
|
Operation::LESS => match (instruction.b_type, instruction.c_type) {
|
||||||
|
(TypeCode::INTEGER, TypeCode::INTEGER) => Action::OptimizedLessIntegers {
|
||||||
|
left_pointer: std::ptr::null(),
|
||||||
|
right_pointer: std::ptr::null(),
|
||||||
|
},
|
||||||
|
_ => todo!(),
|
||||||
|
},
|
||||||
|
Operation::JUMP => {
|
||||||
|
let offset = instruction.b_field as usize;
|
||||||
|
let is_positive = instruction.c_field != 0;
|
||||||
|
|
||||||
|
if is_positive {
|
||||||
|
Action::OptimizedJumpForward { offset }
|
||||||
|
} else {
|
||||||
|
Action::OptimizedJumpBackward { offset }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn r#loop(actions: ActionSequence) -> Self {
|
||||||
|
Action::Loop { actions }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Action {
|
impl Display for Action {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
if let Some(action_sequence) = &self.loop_actions {
|
match self {
|
||||||
write!(f, "LOOP: {action_sequence}")
|
Action::Unoptimized { instruction, .. } => {
|
||||||
} else {
|
write!(f, "{}", instruction.operation)
|
||||||
write!(f, "{}", self.instruction.operation)
|
}
|
||||||
|
Action::Loop { actions } => {
|
||||||
|
write!(f, "LOOP: {actions}")
|
||||||
|
}
|
||||||
|
Action::OptimizedAddIntegers { .. } => {
|
||||||
|
write!(f, "ADD integers optimized")
|
||||||
|
}
|
||||||
|
Action::OptimizedLessIntegers { .. } => {
|
||||||
|
write!(f, "LESS integers optimized")
|
||||||
|
}
|
||||||
|
Action::OptimizedJumpForward { offset } => {
|
||||||
|
write!(f, "JUMP +{offset}")
|
||||||
|
}
|
||||||
|
Action::OptimizedJumpBackward { offset } => {
|
||||||
|
write!(f, "JUMP -{offset}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ActionLogic = fn(&mut usize, InstructionFields, &mut Thread, &mut PointerCache);
|
pub type ActionLogic = fn(&mut usize, &InstructionFields, &mut Thread);
|
||||||
|
|
||||||
fn no_op(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {}
|
fn no_op(_: &mut usize, _: &InstructionFields, _: &mut Thread) {}
|
||||||
|
|
||||||
fn point(_: &mut usize, instruction: InstructionFields, thread: &mut Thread, _: &mut PointerCache) {
|
fn point(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
let destination = instruction.a_field as usize;
|
let destination = instruction.a_field as usize;
|
||||||
let to = instruction.b_field as usize;
|
let to = instruction.b_field as usize;
|
||||||
let to_is_constant = instruction.b_is_constant;
|
let to_is_constant = instruction.b_is_constant;
|
||||||
@ -357,7 +428,7 @@ fn point(_: &mut usize, instruction: InstructionFields, thread: &mut Thread, _:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close(_: &mut usize, instruction: InstructionFields, thread: &mut Thread, _: &mut PointerCache) {
|
fn close(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
let from = instruction.b_field as usize;
|
let from = instruction.b_field as usize;
|
||||||
let to = instruction.c_field as usize;
|
let to = instruction.c_field as usize;
|
||||||
let r#type = instruction.b_type;
|
let r#type = instruction.b_type;
|
||||||
@ -402,12 +473,7 @@ fn close(_: &mut usize, instruction: InstructionFields, thread: &mut Thread, _:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_encoded(
|
fn load_encoded(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
ip: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let destination = instruction.a_field;
|
let destination = instruction.a_field;
|
||||||
let value = instruction.b_field;
|
let value = instruction.b_field;
|
||||||
let value_type = instruction.b_type;
|
let value_type = instruction.b_type;
|
||||||
@ -432,12 +498,7 @@ fn load_encoded(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_constant(
|
fn load_constant(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
ip: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let destination = instruction.a_field as usize;
|
let destination = instruction.a_field as usize;
|
||||||
let constant_index = instruction.b_field as usize;
|
let constant_index = instruction.b_field as usize;
|
||||||
let constant_type = instruction.b_type;
|
let constant_type = instruction.b_type;
|
||||||
@ -475,12 +536,7 @@ fn load_constant(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_list(
|
fn load_list(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
ip: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let destination = instruction.a_field;
|
let destination = instruction.a_field;
|
||||||
let start_register = instruction.b_field;
|
let start_register = instruction.b_field;
|
||||||
let item_type = instruction.b_type;
|
let item_type = instruction.b_type;
|
||||||
@ -576,20 +632,15 @@ fn load_list(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_function(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {
|
fn load_function(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_self(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {
|
fn load_self(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn subtract(
|
fn subtract(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
_: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let destination = instruction.a_field as usize;
|
let destination = instruction.a_field as usize;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_type = instruction.b_type;
|
let left_type = instruction.b_type;
|
||||||
@ -675,12 +726,7 @@ fn subtract(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn multiply(
|
fn multiply(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
_: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let destination = instruction.a_field as usize;
|
let destination = instruction.a_field as usize;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_type = instruction.b_type;
|
let left_type = instruction.b_type;
|
||||||
@ -766,12 +812,7 @@ fn multiply(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn divide(
|
fn divide(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
_: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let destination = instruction.a_field as usize;
|
let destination = instruction.a_field as usize;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_type = instruction.b_type;
|
let left_type = instruction.b_type;
|
||||||
@ -857,12 +898,7 @@ fn divide(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modulo(
|
fn modulo(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
_: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let destination = instruction.a_field as usize;
|
let destination = instruction.a_field as usize;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_type = instruction.b_type;
|
let left_type = instruction.b_type;
|
||||||
@ -948,7 +984,7 @@ fn modulo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test(ip: &mut usize, instruction: InstructionFields, thread: &mut Thread, _: &mut PointerCache) {
|
fn test(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
let operand_register = instruction.b_field as usize;
|
let operand_register = instruction.b_field as usize;
|
||||||
let test_value = instruction.c_field != 0;
|
let test_value = instruction.c_field != 0;
|
||||||
let operand_boolean = thread.get_boolean_register(operand_register);
|
let operand_boolean = thread.get_boolean_register(operand_register);
|
||||||
@ -958,16 +994,11 @@ fn test(ip: &mut usize, instruction: InstructionFields, thread: &mut Thread, _:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_set(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {
|
fn test_set(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn equal(
|
fn equal(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
ip: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let comparator = instruction.d_field;
|
let comparator = instruction.d_field;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_type = instruction.b_type;
|
let left_type = instruction.b_type;
|
||||||
@ -1143,12 +1174,7 @@ fn equal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn less_equal(
|
fn less_equal(ip: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
ip: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let comparator = instruction.d_field;
|
let comparator = instruction.d_field;
|
||||||
let left = instruction.b_field as usize;
|
let left = instruction.b_field as usize;
|
||||||
let left_type = instruction.b_type;
|
let left_type = instruction.b_type;
|
||||||
@ -1324,28 +1350,23 @@ fn less_equal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn negate(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {
|
fn negate(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn not(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {
|
fn not(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {
|
fn call(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call_native(_: &mut usize, _: InstructionFields, _: &mut Thread, _: &mut PointerCache) {
|
fn call_native(_: &mut usize, _: &InstructionFields, _: &mut Thread) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn r#return(
|
fn r#return(_: &mut usize, instruction: &InstructionFields, thread: &mut Thread) {
|
||||||
_: &mut usize,
|
|
||||||
instruction: InstructionFields,
|
|
||||||
thread: &mut Thread,
|
|
||||||
_: &mut PointerCache,
|
|
||||||
) {
|
|
||||||
let should_return_value = instruction.b_field != 0;
|
let should_return_value = instruction.b_field != 0;
|
||||||
let return_register = instruction.c_field as usize;
|
let return_register = instruction.c_field as usize;
|
||||||
let return_type = instruction.b_type;
|
let return_type = instruction.b_type;
|
||||||
|
@ -3,9 +3,9 @@ use std::{rc::Rc, thread::JoinHandle};
|
|||||||
use tracing::{info, trace};
|
use tracing::{info, trace};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
AbstractList, Chunk, ConcreteValue, DustString, Span, Value,
|
|
||||||
instruction::InstructionFields,
|
instruction::InstructionFields,
|
||||||
vm::{CallFrame, action::ActionSequence},
|
vm::{action::ActionSequence, Action, CallFrame},
|
||||||
|
AbstractList, Chunk, ConcreteValue, DustString, Span, Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::call_frame::{Pointer, Register};
|
use super::call_frame::{Pointer, Register};
|
||||||
@ -41,8 +41,13 @@ impl Thread {
|
|||||||
.unwrap_or_else(|| DustString::from("anonymous"))
|
.unwrap_or_else(|| DustString::from("anonymous"))
|
||||||
);
|
);
|
||||||
|
|
||||||
let actions =
|
let mut actions = ActionSequence::new(
|
||||||
ActionSequence::new(self.chunk.instructions.iter().map(InstructionFields::from));
|
self.chunk
|
||||||
|
.instructions
|
||||||
|
.iter()
|
||||||
|
.map(InstructionFields::from)
|
||||||
|
.collect(),
|
||||||
|
);
|
||||||
|
|
||||||
trace!("Thread actions: {}", actions);
|
trace!("Thread actions: {}", actions);
|
||||||
|
|
||||||
@ -532,6 +537,18 @@ impl Thread {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_integer(&self, index: usize, is_constant: bool) -> &i64 {
|
||||||
|
if is_constant {
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
self.get_constant(index).as_integer().unwrap()
|
||||||
|
} else {
|
||||||
|
unsafe { self.get_constant(index).as_integer().unwrap_unchecked() }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.get_integer_register(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_integer_register(&self, register_index: usize) -> &i64 {
|
pub fn get_integer_register(&self, register_index: usize) -> &i64 {
|
||||||
let register = if cfg!(debug_assertions) {
|
let register = if cfg!(debug_assertions) {
|
||||||
self.call_stack
|
self.call_stack
|
||||||
|
Loading…
x
Reference in New Issue
Block a user