about summary refs log tree commit diff
path: root/tvix/eval/src/observer.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-09-04T13·56+0300
committertazjin <tazjin@tvl.su>2022-09-09T21·10+0000
commit8ee4d6d5db44d93c0fff67db87dcb4ae9f885351 (patch)
tree070d533eb3f1c775011695dc25a96c55aad05a8c /tvix/eval/src/observer.rs
parent7ae45342df28c7f3feb50334aee535a1d36e2bec (diff)
feat(tvix/eval): implement DisassemblingObserver for compiler r/4775
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
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();
+    }
+}