From e041851581743757b9b6a7fb2844229e1735d3b4 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Sat, 13 Aug 2022 22:14:53 +0300 Subject: feat(tvix/eval): implement chunk disassembler output This makes for a much nicer view of an execution if `--feature disassembler` is set, for example: tvix-repl> let value = [ 1 2 { a = 1; } ]; in value ++ [ 1 ] === compiled bytecode (11 operations) === 02 OpConstant(1) 02 OpConstant(2) 02 OpConstant("a") 02 OpConstant(1) 02 OpAttrs(1) 02 OpList(3) 02 OpGetLocal(0) 02 OpConstant(1) 02 OpList(1) 02 OpConcat 02 OpCloseScope(1) === runtime trace === 0001 OpConstant(ConstantIdx(0)) [ 1 ] 0002 OpConstant(ConstantIdx(1)) [ 1 2 ] 0003 OpConstant(ConstantIdx(2)) [ 1 2 "a" ] 0004 OpConstant(ConstantIdx(3)) [ 1 2 "a" 1 ] 0005 OpAttrs(1) [ 1 2 { a = 1; } ] 0006 OpList(3) [ [ 1 2 { a = 1; } ] ] 0007 OpGetLocal(0) [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } ] ] 0008 OpConstant(ConstantIdx(4)) [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } ] 1 ] 0009 OpList(1) [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } ] [ 1 ] ] 0010 OpConcat [ [ 1 2 { a = 1; } ] [ 1 2 { a = 1; } 1 ] ] 0011 OpCloseScope(1) [ [ 1 2 { a = 1; } 1 ] ] => [ 1 2 { a = 1; } 1 ] :: list Change-Id: If79c7fd1f0f18255ddb3763c1ba585fda8041b1b Reviewed-on: https://cl.tvl.fyi/c/depot/+/6195 Tested-by: BuildkiteCI Reviewed-by: sterni --- tvix/eval/src/chunk.rs | 2 +- tvix/eval/src/disassembler.rs | 31 +++++++++++++++++++++++++++++++ tvix/eval/src/eval.rs | 4 +++- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/tvix/eval/src/chunk.rs b/tvix/eval/src/chunk.rs index e0b584fb1f98..03071b3008de 100644 --- a/tvix/eval/src/chunk.rs +++ b/tvix/eval/src/chunk.rs @@ -4,7 +4,7 @@ use crate::value::Value; #[derive(Debug, Default)] pub struct Chunk { pub code: Vec, - constants: Vec, + pub constants: Vec, } impl Chunk { diff --git a/tvix/eval/src/disassembler.rs b/tvix/eval/src/disassembler.rs index 98a6dac9afc4..e5f6df525ad4 100644 --- a/tvix/eval/src/disassembler.rs +++ b/tvix/eval/src/disassembler.rs @@ -4,6 +4,7 @@ use std::io::{Stderr, Write}; use tabwriter::TabWriter; +use crate::chunk::Chunk; use crate::opcode::OpCode; use crate::value::Value; @@ -35,3 +36,33 @@ impl Drop for Tracer { self.0.flush().ok(); } } + +fn disassemble_op(tw: &mut TabWriter, chunk: &Chunk, offset: usize) { + let code_width = format!("{}", chunk.code.len()).len(); + write!(tw, "{:0width$}\t ", width = code_width).ok(); + + match chunk.code[offset] { + OpCode::OpConstant(idx) => write!(tw, "OpConstant({})\n", chunk.constant(idx)).ok(), + + op => write!(tw, "{:?}\n", op).ok(), + }; +} + +/// Disassemble a chunk of code, printing out the operations in a +/// reasonable, human-readable format. +pub fn disassemble_chunk(chunk: &Chunk) { + let mut tw = TabWriter::new(std::io::stderr()); + + write!( + &mut tw, + "=== compiled bytecode ({} operations) ===\n", + chunk.code.len() + ) + .ok(); + + for (idx, _) in chunk.code.iter().enumerate() { + disassemble_op(&mut tw, chunk, idx); + } + + tw.flush().ok(); +} diff --git a/tvix/eval/src/eval.rs b/tvix/eval/src/eval.rs index 903708f108b3..456f2575cab7 100644 --- a/tvix/eval/src/eval.rs +++ b/tvix/eval/src/eval.rs @@ -17,7 +17,9 @@ pub fn interpret(code: &str, location: Option) -> EvalResult { } let result = crate::compiler::compile(ast, location)?; - println!("code: {:?}", result.chunk); + + #[cfg(feature = "disassembler")] + crate::disassembler::disassemble_chunk(&result.chunk); for warning in result.warnings { eprintln!( -- cgit 1.4.1