📈 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::{
|
||||
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
|
||||
// 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 <()>
|
||||
{
|
||||
// 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,
|
||||
instructions,
|
||||
upvalues,
|
||||
});
|
||||
}.into ());
|
||||
|
||||
// Recursion
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
use std::rc::Rc;
|
||||
|
||||
use crate::{
|
||||
instruction::Instruction,
|
||||
string_interner::Interner,
|
||||
|
@ -23,7 +25,7 @@ pub struct Block {
|
|||
|
||||
#[derive (Clone, Debug, Default)]
|
||||
pub struct Chunk {
|
||||
pub blocks: Vec <Block>,
|
||||
pub blocks: Vec <Rc <Block>>,
|
||||
}
|
||||
|
||||
#[derive (Clone, Copy, Debug, Default)]
|
||||
|
@ -54,6 +56,7 @@ pub struct State {
|
|||
|
||||
pub debug_print: bool,
|
||||
chunk: Chunk,
|
||||
current_block: Rc <Block>,
|
||||
pub upvalues: Vec <Value>,
|
||||
pub si: Interner,
|
||||
}
|
||||
|
@ -180,6 +183,8 @@ pub enum StepError {
|
|||
|
||||
impl State {
|
||||
pub fn new (chunk: Chunk, upvalues: Vec <Value>) -> Self {
|
||||
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.
|
||||
|
@ -189,6 +194,7 @@ impl State {
|
|||
stack_top: Default::default (),
|
||||
debug_print: false,
|
||||
chunk,
|
||||
current_block,
|
||||
upvalues,
|
||||
si: Default::default (),
|
||||
}
|
||||
|
@ -196,6 +202,7 @@ impl State {
|
|||
|
||||
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
|
||||
|
@ -206,6 +213,7 @@ impl State {
|
|||
stack_top: Default::default (),
|
||||
debug_print: false,
|
||||
chunk,
|
||||
current_block,
|
||||
upvalues,
|
||||
si,
|
||||
}
|
||||
|
@ -321,11 +329,11 @@ impl State {
|
|||
let target_block = idx;
|
||||
|
||||
self.stack.push (self.stack_top);
|
||||
self.stack_top = StackFrame {
|
||||
self.set_stack_top (StackFrame {
|
||||
program_counter: 0,
|
||||
block_idx: target_block,
|
||||
register_offset: self.stack_top.register_offset + a as usize + 1,
|
||||
};
|
||||
});
|
||||
|
||||
// Skip the PC increment at the bottom of the loop
|
||||
return true;
|
||||
|
@ -354,7 +362,8 @@ impl State {
|
|||
let num_results = x (self, num_args);
|
||||
|
||||
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;
|
||||
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) {
|
||||
let block = self.chunk.blocks.get (self.stack_top.block_idx).unwrap ();
|
||||
let block = &self.current_block;
|
||||
let constants = &block.constants;
|
||||
|
||||
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) {
|
||||
let frame = &self.stack_top;
|
||||
let block = self.chunk.blocks.get (frame.block_idx).unwrap ();
|
||||
let block = &self.current_block;
|
||||
let constants = &block.constants;
|
||||
|
||||
let b = usize::try_from (b).unwrap ();
|
||||
|
@ -489,12 +497,21 @@ impl State {
|
|||
}
|
||||
|
||||
fn constants (&self) -> &[Value] {
|
||||
&self.chunk.blocks.get (self.stack_top.block_idx).unwrap ().constants
|
||||
&self.current_block.constants
|
||||
}
|
||||
|
||||
fn decode (&self) -> Instruction {
|
||||
let block = self.chunk.blocks.get (self.stack_top.block_idx).unwrap ();
|
||||
match block.instructions.get (self.stack_top.program_counter) {
|
||||
fn set_block_idx (&mut self, block_idx: usize) {
|
||||
self.stack_top.block_idx = block_idx;
|
||||
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,
|
||||
None => {
|
||||
dbg! (&self.stack, &self.stack_top);
|
||||
|
@ -509,7 +526,7 @@ impl State {
|
|||
|
||||
pub fn step (&mut self) -> Result <Option <StepOutput>, StepError>
|
||||
{
|
||||
let instruction = self.decode ();
|
||||
let instruction = self.fetch ();
|
||||
|
||||
let make_step_error = |msg| {
|
||||
self.make_step_error (msg, &instruction)
|
||||
|
@ -798,7 +815,7 @@ impl State {
|
|||
}
|
||||
|
||||
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
|
||||
// can grab them
|
||||
|
@ -821,7 +838,8 @@ impl State {
|
|||
},
|
||||
Instruction::Return0 => {
|
||||
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;
|
||||
},
|
||||
Instruction::Return1 (a) => {
|
||||
|
@ -830,7 +848,8 @@ impl State {
|
|||
|
||||
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
|
||||
let offset = popped_frame.register_offset;
|
||||
|
@ -917,9 +936,11 @@ impl State {
|
|||
|
||||
// Jump into the other function
|
||||
|
||||
self.stack_top.program_counter = 0;
|
||||
self.stack_top.block_idx = closure.idx;
|
||||
self.stack_top.program_counter = 0;
|
||||
self.set_stack_top (StackFrame {
|
||||
block_idx: closure.idx,
|
||||
program_counter: 0,
|
||||
register_offset: self.stack_top.register_offset,
|
||||
});
|
||||
|
||||
// Skip the PC increment
|
||||
return Ok (None);
|
||||
|
@ -954,7 +975,7 @@ impl State {
|
|||
let popped_frame = self.stack_top;
|
||||
|
||||
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
|
||||
if c == 0 {
|
||||
|
@ -1025,7 +1046,7 @@ impl State {
|
|||
|
||||
pub fn set_chunk (&mut self, chunk: Chunk) {
|
||||
self.stack = vec! [];
|
||||
self.stack_top = Default::default ();
|
||||
self.set_stack_top (Default::default ());
|
||||
self.chunk = chunk;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue