refactor(tvix/eval): use call frame for top-level lambda

This wires up most of the machinery for executing different call
frames inside of the VM and stuffs the top-level lambda which the
compiler outputs in there, as well.

Change-Id: Ib6201b3e3be1af96a4d195f6eb147f452860ffc3
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6242
Tested-by: BuildkiteCI
Reviewed-by: grfn <grfn@gws.fyi>
This commit is contained in:
Vincent Ambo 2022-08-23 23:09:03 +03:00 committed by tazjin
parent 0b37b3f2a9
commit a060c8f467

View file

@ -21,8 +21,6 @@ struct CallFrame {
pub struct VM { pub struct VM {
frames: Vec<CallFrame>, frames: Vec<CallFrame>,
ip: usize,
chunk: Chunk,
stack: Vec<Value>, stack: Vec<Value>,
// Stack indices of attribute sets from which variables should be // Stack indices of attribute sets from which variables should be
@ -83,9 +81,22 @@ macro_rules! cmp_op {
} }
impl VM { impl VM {
fn frame(&self) -> &CallFrame {
&self.frames[self.frames.len() - 1]
}
fn chunk(&self) -> &Chunk {
&self.frame().lambda.chunk
}
fn frame_mut(&mut self) -> &mut CallFrame {
let idx = self.frames.len() - 1;
&mut self.frames[idx]
}
fn inc_ip(&mut self) -> OpCode { fn inc_ip(&mut self) -> OpCode {
let op = self.chunk.code[self.ip]; let op = self.chunk().code[self.frame().ip];
self.ip += 1; self.frame_mut().ip += 1;
op op
} }
@ -109,7 +120,7 @@ impl VM {
let op = self.inc_ip(); let op = self.inc_ip();
match op { match op {
OpCode::OpConstant(idx) => { OpCode::OpConstant(idx) => {
let c = self.chunk.constant(idx).clone(); let c = self.chunk().constant(idx).clone();
self.push(c); self.push(c);
} }
@ -235,25 +246,25 @@ impl VM {
OpCode::OpInterpolate(count) => self.run_interpolate(count)?, OpCode::OpInterpolate(count) => self.run_interpolate(count)?,
OpCode::OpJump(offset) => { OpCode::OpJump(offset) => {
self.ip += offset; self.frame_mut().ip += offset;
} }
OpCode::OpJumpIfTrue(offset) => { OpCode::OpJumpIfTrue(offset) => {
if self.peek(0).as_bool()? { if self.peek(0).as_bool()? {
self.ip += offset; self.frame_mut().ip += offset;
} }
} }
OpCode::OpJumpIfFalse(offset) => { OpCode::OpJumpIfFalse(offset) => {
if !self.peek(0).as_bool()? { if !self.peek(0).as_bool()? {
self.ip += offset; self.frame_mut().ip += offset;
} }
} }
OpCode::OpJumpIfNotFound(offset) => { OpCode::OpJumpIfNotFound(offset) => {
if matches!(self.peek(0), Value::NotFound) { if matches!(self.peek(0), Value::NotFound) {
self.pop(); self.pop();
self.ip += offset; self.frame_mut().ip += offset;
} }
} }
@ -324,10 +335,10 @@ impl VM {
#[cfg(feature = "disassembler")] #[cfg(feature = "disassembler")]
{ {
tracer.trace(&op, self.ip, &self.stack); tracer.trace(&op, self.frame().ip, &self.stack);
} }
if self.ip == self.chunk.code.len() { if self.frame().ip == self.chunk().code.len() {
return Ok(self.pop()); return Ok(self.pop());
} }
} }
@ -373,10 +384,14 @@ impl VM {
} }
pub fn run_lambda(lambda: Lambda) -> EvalResult<Value> { pub fn run_lambda(lambda: Lambda) -> EvalResult<Value> {
let mut vm = VM { let frame = CallFrame {
frames: vec![], lambda,
chunk: Rc::<Chunk>::try_unwrap(lambda.chunk).unwrap(),
ip: 0, ip: 0,
stack_offset: 0,
};
let mut vm = VM {
frames: vec![frame],
stack: vec![], stack: vec![],
with_stack: vec![], with_stack: vec![],
}; };