📈 performance: caching the current block helps, barely
parent
52df317326
commit
b35dc346e8
|
@ -1,4 +1,7 @@
|
||||||
use std::io::Read;
|
use std::{
|
||||||
|
io::Read,
|
||||||
|
rc::Rc,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::Instruction as Inst,
|
instruction::Instruction as Inst,
|
||||||
|
@ -243,7 +246,7 @@ fn parse_i64 <R: Read> (rdr: &mut R) -> Option <i64> {
|
||||||
// code, but I don't like recursion in general, and I don't know
|
// code, but I don't like recursion in general, and I don't know
|
||||||
// why PUC wrote it that way.
|
// why PUC wrote it that way.
|
||||||
|
|
||||||
pub fn parse_block <R: Read> (rdr: &mut R, si: &mut Interner, blocks: &mut Vec <Block>)
|
pub fn parse_block <R: Read> (rdr: &mut R, si: &mut Interner, blocks: &mut Vec <Rc <Block>>)
|
||||||
-> Option <()>
|
-> Option <()>
|
||||||
{
|
{
|
||||||
// Ignore things I haven't implemented yet
|
// Ignore things I haven't implemented yet
|
||||||
|
@ -306,7 +309,7 @@ pub fn parse_block <R: Read> (rdr: &mut R, si: &mut Interner, blocks: &mut Vec <
|
||||||
constants,
|
constants,
|
||||||
instructions,
|
instructions,
|
||||||
upvalues,
|
upvalues,
|
||||||
});
|
}.into ());
|
||||||
|
|
||||||
// Recursion
|
// Recursion
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
instruction::Instruction,
|
instruction::Instruction,
|
||||||
string_interner::Interner,
|
string_interner::Interner,
|
||||||
|
@ -23,7 +25,7 @@ pub struct Block {
|
||||||
|
|
||||||
#[derive (Clone, Debug, Default)]
|
#[derive (Clone, Debug, Default)]
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
pub blocks: Vec <Block>,
|
pub blocks: Vec <Rc <Block>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive (Clone, Copy, Debug, Default)]
|
#[derive (Clone, Copy, Debug, Default)]
|
||||||
|
@ -54,6 +56,7 @@ pub struct State {
|
||||||
|
|
||||||
pub debug_print: bool,
|
pub debug_print: bool,
|
||||||
chunk: Chunk,
|
chunk: Chunk,
|
||||||
|
current_block: Rc <Block>,
|
||||||
pub upvalues: Vec <Value>,
|
pub upvalues: Vec <Value>,
|
||||||
pub si: Interner,
|
pub si: Interner,
|
||||||
}
|
}
|
||||||
|
@ -180,22 +183,7 @@ pub enum StepError {
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
pub fn new (chunk: Chunk, upvalues: Vec <Value>) -> Self {
|
pub fn new (chunk: Chunk, upvalues: Vec <Value>) -> Self {
|
||||||
Self {
|
let current_block = Rc::clone (&chunk.blocks [0]);
|
||||||
// TODO: Stack is actually supposed to grow to a limit of
|
|
||||||
// idk 10,000. I thought it was fixed at 256.
|
|
||||||
registers: vec! [Value::Nil; 256],
|
|
||||||
top: 0,
|
|
||||||
stack: vec! [],
|
|
||||||
stack_top: Default::default (),
|
|
||||||
debug_print: false,
|
|
||||||
chunk,
|
|
||||||
upvalues,
|
|
||||||
si: Default::default (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_args <I: Iterator <Item = String>> (chunk: Chunk, mut si: Interner, args: I) -> Self {
|
|
||||||
let upvalues = Self::upvalues_from_args (&mut si, args);
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
// TODO: Stack is actually supposed to grow to a limit of
|
// TODO: Stack is actually supposed to grow to a limit of
|
||||||
|
@ -206,6 +194,26 @@ impl State {
|
||||||
stack_top: Default::default (),
|
stack_top: Default::default (),
|
||||||
debug_print: false,
|
debug_print: false,
|
||||||
chunk,
|
chunk,
|
||||||
|
current_block,
|
||||||
|
upvalues,
|
||||||
|
si: Default::default (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_with_args <I: Iterator <Item = String>> (chunk: Chunk, mut si: Interner, args: I) -> Self {
|
||||||
|
let upvalues = Self::upvalues_from_args (&mut si, args);
|
||||||
|
let current_block = Rc::clone (&chunk.blocks [0]);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
// TODO: Stack is actually supposed to grow to a limit of
|
||||||
|
// idk 10,000. I thought it was fixed at 256.
|
||||||
|
registers: vec! [Value::Nil; 256],
|
||||||
|
top: 0,
|
||||||
|
stack: vec! [],
|
||||||
|
stack_top: Default::default (),
|
||||||
|
debug_print: false,
|
||||||
|
chunk,
|
||||||
|
current_block,
|
||||||
upvalues,
|
upvalues,
|
||||||
si,
|
si,
|
||||||
}
|
}
|
||||||
|
@ -321,11 +329,11 @@ impl State {
|
||||||
let target_block = idx;
|
let target_block = idx;
|
||||||
|
|
||||||
self.stack.push (self.stack_top);
|
self.stack.push (self.stack_top);
|
||||||
self.stack_top = StackFrame {
|
self.set_stack_top (StackFrame {
|
||||||
program_counter: 0,
|
program_counter: 0,
|
||||||
block_idx: target_block,
|
block_idx: target_block,
|
||||||
register_offset: self.stack_top.register_offset + a as usize + 1,
|
register_offset: self.stack_top.register_offset + a as usize + 1,
|
||||||
};
|
});
|
||||||
|
|
||||||
// Skip the PC increment at the bottom of the loop
|
// Skip the PC increment at the bottom of the loop
|
||||||
return true;
|
return true;
|
||||||
|
@ -354,7 +362,8 @@ impl State {
|
||||||
let num_results = x (self, num_args);
|
let num_results = x (self, num_args);
|
||||||
|
|
||||||
let popped_frame = self.stack_top;
|
let popped_frame = self.stack_top;
|
||||||
self.stack_top = self.stack.pop ().unwrap ();
|
let x = self.stack.pop ().unwrap ();
|
||||||
|
self.set_stack_top (x);
|
||||||
self.stack_top.register_offset = old_offset;
|
self.stack_top.register_offset = old_offset;
|
||||||
let offset = old_offset + usize::from (a);
|
let offset = old_offset + usize::from (a);
|
||||||
|
|
||||||
|
@ -391,7 +400,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_get_field (&mut self, a: u8, b: u8, c: u8) {
|
fn op_get_field (&mut self, a: u8, b: u8, c: u8) {
|
||||||
let block = self.chunk.blocks.get (self.stack_top.block_idx).unwrap ();
|
let block = &self.current_block;
|
||||||
let constants = &block.constants;
|
let constants = &block.constants;
|
||||||
|
|
||||||
let key = match &constants [usize::from (c)] {
|
let key = match &constants [usize::from (c)] {
|
||||||
|
@ -449,8 +458,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_set_field (&mut self, a: u8, b: u8, c: u8, k: bool) {
|
fn op_set_field (&mut self, a: u8, b: u8, c: u8, k: bool) {
|
||||||
let frame = &self.stack_top;
|
let block = &self.current_block;
|
||||||
let block = self.chunk.blocks.get (frame.block_idx).unwrap ();
|
|
||||||
let constants = &block.constants;
|
let constants = &block.constants;
|
||||||
|
|
||||||
let b = usize::try_from (b).unwrap ();
|
let b = usize::try_from (b).unwrap ();
|
||||||
|
@ -489,12 +497,21 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn constants (&self) -> &[Value] {
|
fn constants (&self) -> &[Value] {
|
||||||
&self.chunk.blocks.get (self.stack_top.block_idx).unwrap ().constants
|
&self.current_block.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode (&self) -> Instruction {
|
fn set_block_idx (&mut self, block_idx: usize) {
|
||||||
let block = self.chunk.blocks.get (self.stack_top.block_idx).unwrap ();
|
self.stack_top.block_idx = block_idx;
|
||||||
match block.instructions.get (self.stack_top.program_counter) {
|
self.current_block = Rc::clone (&self.chunk.blocks [block_idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_stack_top (&mut self, frame: StackFrame) {
|
||||||
|
self.stack_top = frame;
|
||||||
|
self.current_block = Rc::clone (&self.chunk.blocks [frame.block_idx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fetch (&self) -> Instruction {
|
||||||
|
match self.current_block.instructions.get (self.stack_top.program_counter) {
|
||||||
Some (x) => *x,
|
Some (x) => *x,
|
||||||
None => {
|
None => {
|
||||||
dbg! (&self.stack, &self.stack_top);
|
dbg! (&self.stack, &self.stack_top);
|
||||||
|
@ -509,7 +526,7 @@ impl State {
|
||||||
|
|
||||||
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
||||||
{
|
{
|
||||||
let instruction = self.decode ();
|
let instruction = self.fetch ();
|
||||||
|
|
||||||
let make_step_error = |msg| {
|
let make_step_error = |msg| {
|
||||||
self.make_step_error (msg, &instruction)
|
self.make_step_error (msg, &instruction)
|
||||||
|
@ -798,7 +815,7 @@ impl State {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some (new_frame) = self.stack.pop () {
|
if let Some (new_frame) = self.stack.pop () {
|
||||||
self.stack_top = new_frame;
|
self.set_stack_top (new_frame);
|
||||||
|
|
||||||
// Shift our output registers down so the caller
|
// Shift our output registers down so the caller
|
||||||
// can grab them
|
// can grab them
|
||||||
|
@ -821,7 +838,8 @@ impl State {
|
||||||
},
|
},
|
||||||
Instruction::Return0 => {
|
Instruction::Return0 => {
|
||||||
let popped_frame = self.stack_top;
|
let popped_frame = self.stack_top;
|
||||||
self.stack_top = self.stack.pop ().unwrap ();
|
let x = self.stack.pop ().unwrap ();
|
||||||
|
self.set_stack_top (x);
|
||||||
self.top = popped_frame.register_offset - 1 + 0;
|
self.top = popped_frame.register_offset - 1 + 0;
|
||||||
},
|
},
|
||||||
Instruction::Return1 (a) => {
|
Instruction::Return1 (a) => {
|
||||||
|
@ -830,7 +848,8 @@ impl State {
|
||||||
|
|
||||||
self.registers [popped_frame.register_offset - 1] = self.register_window ()[a].clone ();
|
self.registers [popped_frame.register_offset - 1] = self.register_window ()[a].clone ();
|
||||||
|
|
||||||
self.stack_top = self.stack.pop ().unwrap ();
|
let x = self.stack.pop ().unwrap ();
|
||||||
|
self.set_stack_top (x);
|
||||||
|
|
||||||
// Shift output register down
|
// Shift output register down
|
||||||
let offset = popped_frame.register_offset;
|
let offset = popped_frame.register_offset;
|
||||||
|
@ -917,9 +936,11 @@ impl State {
|
||||||
|
|
||||||
// Jump into the other function
|
// Jump into the other function
|
||||||
|
|
||||||
self.stack_top.program_counter = 0;
|
self.set_stack_top (StackFrame {
|
||||||
self.stack_top.block_idx = closure.idx;
|
block_idx: closure.idx,
|
||||||
self.stack_top.program_counter = 0;
|
program_counter: 0,
|
||||||
|
register_offset: self.stack_top.register_offset,
|
||||||
|
});
|
||||||
|
|
||||||
// Skip the PC increment
|
// Skip the PC increment
|
||||||
return Ok (None);
|
return Ok (None);
|
||||||
|
@ -954,7 +975,7 @@ impl State {
|
||||||
let popped_frame = self.stack_top;
|
let popped_frame = self.stack_top;
|
||||||
|
|
||||||
if let Some (new_frame) = self.stack.pop () {
|
if let Some (new_frame) = self.stack.pop () {
|
||||||
self.stack_top = new_frame;
|
self.set_stack_top (new_frame);
|
||||||
|
|
||||||
// Set up top for the next call
|
// Set up top for the next call
|
||||||
if c == 0 {
|
if c == 0 {
|
||||||
|
@ -1025,7 +1046,7 @@ impl State {
|
||||||
|
|
||||||
pub fn set_chunk (&mut self, chunk: Chunk) {
|
pub fn set_chunk (&mut self, chunk: Chunk) {
|
||||||
self.stack = vec! [];
|
self.stack = vec! [];
|
||||||
self.stack_top = Default::default ();
|
self.set_stack_top (Default::default ());
|
||||||
self.chunk = chunk;
|
self.chunk = chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue