feat(tvix/eval): implement DisassemblingObserver for compiler

This type implements an observer that is called whenever the compiler
emits a chunk (after the toplevel, thunks, or lambdas) and prints the
output of the disassembler to its internal writer.

This replaces half of the uses of the `disassembler` feature, which
has been removed from the Cargo configuration.

Note that at this commit runtime tracing is not yet implemented as an
observer.

Change-Id: I7894ca1ba445761aba4ad51d98e4a7b6445f1aea
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6449
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2022-09-04 16:56:20 +03:00 committed by tazjin
parent 7ae45342df
commit 8ee4d6d5db
7 changed files with 111 additions and 98 deletions

View file

@ -4,9 +4,15 @@
//! This can be used to gain insights from compilation, to trace the
//! runtime, and so on.
use crate::value::Lambda;
use codemap::CodeMap;
use std::io::Write;
use std::rc::Rc;
use tabwriter::TabWriter;
use crate::chunk::Chunk;
use crate::disassembler::disassemble_op;
use crate::opcode::CodeIdx;
use crate::value::Lambda;
/// Implemented by types that wish to observe internal happenings of
/// Tvix.
@ -34,3 +40,59 @@ pub trait Observer {
pub struct NoOpObserver {}
impl Observer for NoOpObserver {}
/// An observer that prints disassembled chunk information to its
/// internal writer whenwever the compiler emits a toplevel function,
/// closure or thunk.
pub struct DisassemblingObserver<W: Write> {
codemap: Rc<CodeMap>,
writer: TabWriter<W>,
}
impl<W: Write> DisassemblingObserver<W> {
pub fn new(codemap: Rc<CodeMap>, writer: W) -> Self {
Self {
codemap,
writer: TabWriter::new(writer),
}
}
fn lambda_header(&mut self, kind: &str, lambda: &Rc<Lambda>) {
let _ = writeln!(
&mut self.writer,
"=== compiled {} @ {:p} ({} ops) ===",
kind,
lambda,
lambda.chunk.code.len()
);
}
fn disassemble_chunk(&mut self, chunk: &Chunk) {
// calculate width of the widest address in the chunk
let width = format!("{:#x}", chunk.code.len() - 1).len();
for (idx, _) in chunk.code.iter().enumerate() {
disassemble_op(&mut self.writer, &self.codemap, chunk, width, CodeIdx(idx));
}
}
}
impl<W: Write> Observer for DisassemblingObserver<W> {
fn observe_compiled_toplevel(&mut self, lambda: &Rc<Lambda>) {
self.lambda_header("toplevel", lambda);
self.disassemble_chunk(&lambda.chunk);
let _ = self.writer.flush();
}
fn observe_compiled_lambda(&mut self, lambda: &Rc<Lambda>) {
self.lambda_header("lambda", lambda);
self.disassemble_chunk(&lambda.chunk);
let _ = self.writer.flush();
}
fn observe_compiled_thunk(&mut self, lambda: &Rc<Lambda>) {
self.lambda_header("thunk", lambda);
self.disassemble_chunk(&lambda.chunk);
let _ = self.writer.flush();
}
}