about summary refs log tree commit diff
path: root/tvix/eval/src/observer.rs
diff options
context:
space:
mode:
Diffstat (limited to 'tvix/eval/src/observer.rs')
-rw-r--r--tvix/eval/src/observer.rs66
1 files changed, 64 insertions, 2 deletions
diff --git a/tvix/eval/src/observer.rs b/tvix/eval/src/observer.rs
index bf05295ac356..5aeb344ee954 100644
--- a/tvix/eval/src/observer.rs
+++ b/tvix/eval/src/observer.rs
@@ -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();
+    }
+}