Compare commits

..

No commits in common. "6db6dc372579d06cff39d8c2a5df824eb37838fd" and "32ddedc066167b5299fd1c994559f226ff7a4d40" have entirely different histories.

4 changed files with 77 additions and 94 deletions

View File

@ -5,7 +5,6 @@ use crate::{
string_interner::Interner, string_interner::Interner,
value::{ value::{
BogusClosure, BogusClosure,
Table,
Value, Value,
}, },
}; };
@ -60,7 +59,6 @@ pub struct State {
current_instructions: Rc <[u32]>, current_instructions: Rc <[u32]>,
pub upvalues: Vec <Value>, pub upvalues: Vec <Value>,
pub si: Interner, pub si: Interner,
tables: Vec <crate::value::Table>,
} }
fn lw_io_write (l: &mut State, num_args: usize) -> usize { fn lw_io_write (l: &mut State, num_args: usize) -> usize {
@ -116,7 +114,7 @@ fn lw_table_concat (l: &mut State, num_args: usize) -> usize {
assert_eq! (num_args, 2); assert_eq! (num_args, 2);
let s = { let s = {
let t = &l.tables [l.reg (0).as_table ().unwrap ()]; let t = l.reg (0).as_table ().unwrap ().borrow ();
let joiner = l.reg (1).as_str ().unwrap (); let joiner = l.reg (1).as_str ().unwrap ();
let mut s = String::new (); let mut s = String::new ();
@ -137,9 +135,9 @@ fn lw_table_concat (l: &mut State, num_args: usize) -> usize {
fn lw_table_pack (l: &mut State, num_args: usize) -> usize { fn lw_table_pack (l: &mut State, num_args: usize) -> usize {
let mut v = vec! []; let mut v = vec! [];
for i in 0..num_args { for i in 0..num_args {
v.push ((Value::from (i + 1), l.reg (u8::try_from (i).unwrap ()).clone ())); v.push (l.reg (u8::try_from (i).unwrap ()).clone ());
} }
*l.reg_mut (0) = l.intern_table (Table::from_iter (v)); *l.reg_mut (0) = Value::from_iter (v.into_iter ());
1 1
} }
@ -199,17 +197,17 @@ impl State {
current_instructions, current_instructions,
upvalues, upvalues,
si: Default::default (), si: Default::default (),
tables: Default::default (),
} }
} }
pub fn new_with_args <I: Iterator <Item = String>> (chunk: Chunk, si: Interner, args: I) -> Self { 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_instructions = match chunk.blocks.get (0) { let current_instructions = match chunk.blocks.get (0) {
Some (x) => Rc::clone (&x.instructions), Some (x) => Rc::clone (&x.instructions),
None => Rc::from ([]), None => Rc::from ([]),
}; };
let mut that = Self { Self {
// TODO: Stack is actually supposed to grow to a limit of // TODO: Stack is actually supposed to grow to a limit of
// idk 10,000. I thought it was fixed at 256. // idk 10,000. I thought it was fixed at 256.
registers: vec! [Value::Nil; 256], registers: vec! [Value::Nil; 256],
@ -219,13 +217,9 @@ impl State {
debug_print: false, debug_print: false,
chunk, chunk,
current_instructions, current_instructions,
upvalues: Default::default (), upvalues,
si, si,
tables: Default::default (), }
};
that.upvalues = that.upvalues_from_args (args);
that
} }
pub fn at_breakpoint (&self, bp: &Breakpoint) -> bool { pub fn at_breakpoint (&self, bp: &Breakpoint) -> bool {
@ -233,46 +227,40 @@ impl State {
frame.block_idx == bp.block_idx && frame.program_counter == bp.program_counter frame.block_idx == bp.block_idx && frame.program_counter == bp.program_counter
} }
fn intern_table (&mut self, table: Table) -> Value { pub fn upvalues_from_args <I: Iterator <Item = String>> (si: &mut Interner, args: I) -> Vec <Value>
let t = self.tables.len ();
self.tables.push (table);
Value::Table (t)
}
pub fn upvalues_from_args <I: Iterator <Item = String>> (&mut self, args: I) -> Vec <Value>
{ {
let arg: Vec <_> = args.map (|s| self.si.intern (&s)).enumerate ().collect (); let arg = args.map (|s| si.intern (&s)).enumerate ();
let arg = self.intern_table (Table::from_iter (arg.into_iter ().map (|(i, v)| (Value::from (i), Value::String (v))))); let arg = Value::from_iter (arg.map (|(i, v)| (Value::from (i), Value::String (v))));
let io: Vec <_> = [ let io: Vec <_> = [
("write", Value::RsFunc (lw_io_write)), ("write", Value::RsFunc (lw_io_write)),
].into_iter ().map (|(k, v)| (Value::String (self.si.intern (k)), v)).collect (); ].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
let math: Vec <_> = [ let math: Vec <_> = [
("sqrt", Value::RsFunc (lw_sqrt)), ("sqrt", Value::RsFunc (lw_sqrt)),
].into_iter ().map (|(k, v)| (Value::String (self.si.intern (k)), v)).collect (); ].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
let string: Vec <_> = [ let string: Vec <_> = [
("format", Value::RsFunc (lw_string_format)), ("format", Value::RsFunc (lw_string_format)),
].into_iter ().map (|(k, v)| (Value::String (self.si.intern (k)), v)).collect (); ].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
let table: Vec <_> = [ let table: Vec <_> = [
("concat", Value::RsFunc (lw_table_concat)), ("concat", Value::RsFunc (lw_table_concat)),
("pack", Value::RsFunc (lw_table_pack)), ("pack", Value::RsFunc (lw_table_pack)),
].into_iter ().map (|(k, v)| (Value::String (self.si.intern (k)), v)).collect (); ].into_iter ().map (|(k, v)| (si.intern (k), v)).collect ();
let env: Vec <_> = [ let env = [
("arg", arg), ("arg", arg),
("io", self.intern_table (Table::from_iter (io))), ("io", Value::from_iter (io.into_iter ())),
("math", self.intern_table (Table::from_iter (math))), ("math", Value::from_iter (math.into_iter ())),
("print", Value::RsFunc (lw_print)), ("print", Value::RsFunc (lw_print)),
("string", self.intern_table (Table::from_iter (string))), ("string", Value::from_iter (string.into_iter ())),
("table", self.intern_table (Table::from_iter (table))), ("table", Value::from_iter (table.into_iter ())),
("tonumber", Value::RsFunc (lw_tonumber)), ("tonumber", Value::RsFunc (lw_tonumber)),
].into_iter ().map (|(k, v)| (Value::String (self.si.intern (k)), v)).collect (); ].into_iter ().map (|(k, v)| (si.intern (k), v));
vec! [ vec! [
self.intern_table (Table::from_iter (env)), Value::from_iter (env.into_iter ()),
] ]
} }
@ -425,7 +413,7 @@ impl State {
let val = match &self.registers [self.stack_top.register_offset + usize::from (b)] { let val = match &self.registers [self.stack_top.register_offset + usize::from (b)] {
Value::Nil => panic! ("R[B] must not be nil"), Value::Nil => panic! ("R[B] must not be nil"),
Value::Table (t) => self.tables [*t].get_str (*key).clone (), Value::Table (t) => t.borrow ().get_str (*key).clone (),
_ => panic! ("R[B] must be a table"), _ => panic! ("R[B] must be a table"),
}; };
@ -434,13 +422,13 @@ impl State {
fn op_get_table (&mut self, a: u8, b: u8, c: u8) { fn op_get_table (&mut self, a: u8, b: u8, c: u8) {
let t = match self.reg (b) { let t = match self.reg (b) {
Value::Table (t) => *t, Value::Table (t) => t,
_ => panic! ("R[B] must be a table"), _ => panic! ("R[B] must be a table"),
}; };
let key = self.reg (c); let key = self.reg (c);
let val = self.tables [t].get (key.clone ()).clone (); let val = t.borrow ().get (key.clone ()).clone ();
*self.reg_mut (a) = val; *self.reg_mut (a) = val;
} }
@ -494,9 +482,8 @@ impl State {
self.reg_mut (c) self.reg_mut (c)
}.clone (); }.clone ();
let t = self.reg (a).as_table () let mut dst = self.reg (a).as_table ()
.expect ("SetField only works on tables"); .expect ("SetField only works on tables").borrow_mut ();
let dst = &mut self.tables [t];
dst.insert_str (key, value); dst.insert_str (key, value);
} }
@ -679,7 +666,7 @@ impl State {
self.upvalues.get (b).unwrap ().clone () self.upvalues.get (b).unwrap ().clone ()
}; };
let table = &self.tables [value.as_table ().expect ("GetTabUp only works on tables")]; let table = value.as_table ().expect ("GetTabUp only works on tables").borrow ();
let key = match self.constants ().get (c).unwrap () { let key = match self.constants ().get (c).unwrap () {
Value::String (s) => *s, Value::String (s) => *s,
@ -692,7 +679,7 @@ impl State {
let key = i64::try_from (i.c ()).unwrap (); let key = i64::try_from (i.c ()).unwrap ();
let value = { let value = {
let table = &self.tables [self.reg (i.b ()).as_table ().expect ("GetI only works on tables")]; let table = self.reg (i.b ()).as_table ().expect ("GetI only works on tables").borrow ();
table.get_int (key).clone () table.get_int (key).clone ()
}; };
@ -726,7 +713,7 @@ impl State {
Value::Nil => Err (make_step_error ("attempt to get length of a nil value"))?, Value::Nil => Err (make_step_error ("attempt to get length of a nil value"))?,
Value::RsFunc (_) => Err (make_step_error ("attempt to get length of a function value"))?, Value::RsFunc (_) => Err (make_step_error ("attempt to get length of a function value"))?,
Value::String (s) => self.si.get (*s).len ().into (), Value::String (s) => self.si.get (*s).len ().into (),
Value::Table (t) => self.tables [*t].length ().into (), Value::Table (t) => t.borrow ().length ().into (),
}; };
*self.reg_mut (i.a ()) = len; *self.reg_mut (i.a ()) = len;
@ -797,9 +784,7 @@ impl State {
*self.reg_mut (i.a ()) = x; *self.reg_mut (i.a ()) = x;
}, },
0x13 => { 0x13 => {
let t = self.tables.len (); *self.reg_mut (i.a ()) = Value::Table (Default::default ());
self.tables.push (Default::default ());
*self.reg_mut (i.a ()) = Value::Table (t);
}, },
0x33 => { 0x33 => {
*self.reg_mut (i.a ()) = Value::Boolean (! self.reg (i.b ()).is_truthy()); *self.reg_mut (i.a ()) = Value::Boolean (! self.reg (i.b ()).is_truthy());
@ -894,14 +879,13 @@ impl State {
} }
.clone (); .clone ();
let t = self.reg_mut (i.a ()).as_table ().expect ("SetI only works on tables"); let mut dst = self.reg_mut (i.a ()).as_table ().expect ("SetI only works on tables").borrow_mut ();
let dst = &mut self.tables [t];
dst.insert_int (i64::from (i.b ()), value); dst.insert_int (i64::from (i.b ()), value);
}, },
0x4e => { 0x4e => {
let a = i.a (); let a = i.a ();
let b = i.b () as usize; let b = i.b ();
if b == 0 { if b == 0 {
panic! ("SetList with b == 0 not implemented"); panic! ("SetList with b == 0 not implemented");
@ -910,12 +894,11 @@ impl State {
panic! ("SetList with k = true not implemented"); panic! ("SetList with k = true not implemented");
} }
let t = self.reg (a).as_table ().expect ("SetList only works on tables"); let mut dst = self.reg (a).as_table ().expect ("SetList only works on tables").borrow_mut ();
let dst = &mut self.tables [t];
for j in 1..=b { for j in 1..=b {
let src = self.registers [self.stack_top.register_offset + a as usize + j].clone (); let src = self.reg (a + j);
dst.insert_int (i64::try_from (i.c () as usize + j).unwrap (), src); dst.insert_int (i64::from (i.c () + j), src.clone ());
} }
}, },
0x0f => { 0x0f => {
@ -932,8 +915,8 @@ impl State {
.clone (); .clone ();
let key = self.constants ().get (b).unwrap ().as_str ().expect ("SetTabUp K[B] must be a string"); let key = self.constants ().get (b).unwrap ().as_str ().expect ("SetTabUp K[B] must be a string");
let t = self.upvalues.get_mut (a).unwrap ().as_table ().unwrap (); let table = self.upvalues.get_mut (a).unwrap ().as_table ().unwrap ();
self.tables [t].insert_str (key, value); table.borrow_mut ().insert_str (key, value);
}, },
0x23 => { 0x23 => {
if self.op_sub (i.a (), i.b (), i.c ()) { if self.op_sub (i.a (), i.b (), i.c ()) {

View File

@ -30,7 +30,7 @@ fn calculate_hash<T: Hash>(t: &T) -> u64 {
/// and returns the output /// and returns the output
fn run_chunk (vm: &mut State, args: &[&str], chunk: Chunk) -> Vec <Value> { fn run_chunk (vm: &mut State, args: &[&str], chunk: Chunk) -> Vec <Value> {
vm.upvalues = vm.upvalues_from_args(args.into_iter ().map (|s| s.to_string ())); vm.upvalues = State::upvalues_from_args(&mut vm.si, args.into_iter ().map (|s| s.to_string ()));
vm.set_chunk (chunk); vm.set_chunk (chunk);
vm.execute ().unwrap () vm.execute ().unwrap ()
} }

View File

@ -33,7 +33,7 @@ pub enum Value {
Integer (i64), Integer (i64),
RsFunc (fn (&mut crate::state::State, usize) -> usize), RsFunc (fn (&mut crate::state::State, usize) -> usize),
String (InternedString), String (InternedString),
Table (usize), Table (Rc <RefCell <Table>>),
// These are all bogus, I haven't figured out how to implement // These are all bogus, I haven't figured out how to implement
// closures yet // closures yet
@ -53,7 +53,7 @@ impl fmt::Debug for Value {
Value::Integer (x) => write! (f, "{}", x), Value::Integer (x) => write! (f, "{}", x),
Value::RsFunc (x) => write! (f, "function: {:?}", x), Value::RsFunc (x) => write! (f, "function: {:?}", x),
Value::String (s) => write! (f, "unimplemented Debug",), Value::String (s) => write! (f, "unimplemented Debug",),
Value::Table (t) => write! (f, "table"), Value::Table (t) => write! (f, "{:?}", t.borrow ()),
Value::BogusClosure (x) => write! (f, "{:?}", x.borrow ()), Value::BogusClosure (x) => write! (f, "{:?}", x.borrow ()),
} }
@ -76,7 +76,7 @@ impl fmt::Display for Value {
Value::Integer (x) => write! (f, "{}", x), Value::Integer (x) => write! (f, "{}", x),
Value::RsFunc (x) => write! (f, "function: {:?}", x), Value::RsFunc (x) => write! (f, "function: {:?}", x),
Value::String (s) => write! (f, "unimplemented Display"), Value::String (s) => write! (f, "unimplemented Display"),
Value::Table (t) => write! (f, "table"), Value::Table (t) => write! (f, "table: {:?}", std::rc::Rc::as_ptr (t)),
Value::BogusClosure (x) => write! (f, "BogusClosure: {:?}", std::rc::Rc::as_ptr (x)), Value::BogusClosure (x) => write! (f, "BogusClosure: {:?}", std::rc::Rc::as_ptr (x)),
} }
@ -125,6 +125,31 @@ impl From <InternedString> for Value {
} }
} }
impl From <Table> for Value {
fn from (x: Table) -> Self {
Self::Table (Rc::new (RefCell::new (x)))
}
}
impl FromIterator <(Value, Value)> for Value {
fn from_iter <I: IntoIterator <Item=(Value, Value)>> (i: I) -> Self {
let table = Table::from_iter (i);
Self::from (table)
}
}
impl FromIterator <(InternedString, Value)> for Value {
fn from_iter <I: IntoIterator <Item=(InternedString, Value)>> (i: I) -> Self {
Self::from_iter (i.into_iter ().map (|(s, v)| (Value::String (s), v)))
}
}
impl FromIterator <Value> for Value {
fn from_iter <I: IntoIterator <Item=Value>> (i: I) -> Self {
Self::from_iter ((1..).zip (i.into_iter ()).map (|(i, v)| (Value::from (i), v)))
}
}
impl Eq for Value {} impl Eq for Value {}
impl std::hash::Hash for Value { impl std::hash::Hash for Value {
@ -135,31 +160,14 @@ impl std::hash::Hash for Value {
match self { match self {
// TODO: Weaken to a Lua error // TODO: Weaken to a Lua error
Self::Nil => panic! ("can't hash a nil value"), Self::Nil => panic! ("can't hash a nil value"),
Self::Boolean (x) => { Self::Boolean (x) => x.hash (state),
[0x01].hash (state); Self::Float (x) => x.to_ne_bytes ().hash (state),
x.hash (state) Self::Integer (x) => x.hash (state),
},
Self::Float (x) => { Self::RsFunc (x) => x.hash (state),
[0x02].hash (state);
x.to_ne_bytes ().hash (state)
},
Self::Integer (x) => {
[0x03].hash (state);
x.hash (state)
},
Self::RsFunc (x) => {
[0x04].hash (state);
x.hash (state)
},
// TODO: Implement string interning so we don't hash the whole string here // TODO: Implement string interning so we don't hash the whole string here
Self::String (x) => { Self::String (x) => x.hash (state),
[0x05].hash (state); Self::Table (x) => Rc::as_ptr (&x).hash (state),
x.hash (state)
},
Self::Table (x) => {
[0x06].hash (state);
x.hash (state)
},
Self::BogusClosure (_) => panic! ("can't hash Bogus values"), Self::BogusClosure (_) => panic! ("can't hash Bogus values"),
} }
@ -207,9 +215,9 @@ impl Value {
} }
} }
pub fn as_table (&self) -> Option <usize> { pub fn as_table (&self) -> Option <&Rc <RefCell <Table>>> {
match self { match self {
Self::Table (t) => Some (*t), Self::Table (t) => Some (t),
_ => None, _ => None,
} }
} }

View File

@ -49,21 +49,13 @@ Did absolutely nothing. I couldn't outsmart LLVM.
## Remove RefCell ## Remove RefCell
Result: Worked well. Dropped from about 3,700 to 3,200 samples. The code got even uglier. (upcoming)
Plan:
I think the `borrow` and `borrow_mut` calls slow down OP_GETFIELD and OP_SETFIELD. I can remove them if I store all the tables in State directly, replacing `Rc <RefCell <Table>>` with my own ref counting. This might I think the `borrow` and `borrow_mut` calls slow down OP_GETFIELD and OP_SETFIELD. I can remove them if I store all the tables in State directly, replacing `Rc <RefCell <Table>>` with my own ref counting. This might
remove a layer of indirection, too. remove a layer of indirection, too.
It's a big change, but I'd need _something_ like this for adding a GC anyway, and sometimes big changes have paid off. It's a big change, but I'd need _something_ like this for adding a GC anyway, and sometimes big changes have paid off.
## Cache constants
Result: Regressed from 3200 to 3600. Not sure why.
Plan: OP_GETFIELD hits the constants a lot. I thought caching it and not dereferencing the chunk and block constantly might help.
## Iterating over instruction list ## Iterating over instruction list
(upcoming) (upcoming)