From 130746bc856f5c2eb5672cceb0e1304ee2c95b1e Mon Sep 17 00:00:00 2001 From: johannst Date: Wed, 28 Feb 2024 18:32:44 +0000 Subject: deploy: 7cc72737a0140f5f71e9d83d4f87503eb4c7604f --- src/add/add.rs.html | 13 ++-- src/fib/fib.rs.html | 9 ++- src/juicebox_asm/asm.rs.html | 7 +- src/juicebox_asm/imm.rs.html | 3 +- src/juicebox_asm/insn.rs.html | 31 +++++++- src/juicebox_asm/insn/add.rs.html | 3 +- src/juicebox_asm/insn/call.rs.html | 3 +- src/juicebox_asm/insn/cmp.rs.html | 3 +- src/juicebox_asm/insn/dec.rs.html | 3 +- src/juicebox_asm/insn/jmp.rs.html | 3 +- src/juicebox_asm/insn/jnz.rs.html | 3 +- src/juicebox_asm/insn/jz.rs.html | 3 +- src/juicebox_asm/insn/mov.rs.html | 3 +- src/juicebox_asm/insn/nop.rs.html | 3 +- src/juicebox_asm/insn/pop.rs.html | 30 +++++++ src/juicebox_asm/insn/push.rs.html | 30 +++++++ src/juicebox_asm/insn/ret.rs.html | 3 +- src/juicebox_asm/insn/test.rs.html | 3 +- src/juicebox_asm/label.rs.html | 3 +- src/juicebox_asm/lib.rs.html | 7 +- src/juicebox_asm/reg.rs.html | 5 +- src/juicebox_asm/rt.rs.html | 155 ++++++++++++++++++++++++++++++++----- src/tiny_vm/tiny_vm.rs.html | 103 +++++++++++++----------- 23 files changed, 334 insertions(+), 95 deletions(-) create mode 100644 src/juicebox_asm/insn/pop.rs.html create mode 100644 src/juicebox_asm/insn/push.rs.html (limited to 'src') diff --git a/src/add/add.rs.html b/src/add/add.rs.html index dc8c566..5e602fb 100644 --- a/src/add/add.rs.html +++ b/src/add/add.rs.html @@ -1,4 +1,5 @@ -add.rs - source
1
+add.rs - source
+    
1
 2
 3
 4
@@ -41,14 +42,14 @@
 //! Jit compile a function at runtime (generate native host code) which calls a function defined in
 //! the example based on the SystemV abi to demonstrate the [`juicebox_asm`] crate.
 
-#[cfg(not(any(target_arch = "x86_64", target_os = "linux")))]
-compile_error!("Only supported on x86_64 with SystemV abi");
+#[cfg(not(any(target_arch = "x86_64", target_os = "linux")))]
+compile_error!("Only supported on x86_64 with SystemV abi");
 
 use juicebox_asm::insn::*;
 use juicebox_asm::Runtime;
 use juicebox_asm::{Asm, Imm64, Reg64::*};
 
-extern "C" fn add(a: u32, b: u32) -> u32 {
+extern "C" fn add(a: u32, b: u32) -> u32 {
     a + b
 }
 
@@ -66,10 +67,10 @@
     asm.ret();
 
     let code = asm.into_code();
-    std::fs::write("jit.asm", &code).unwrap();
+    std::fs::write("jit.asm", &code).unwrap();
 
     let mut rt = Runtime::new();
-    let add42 = unsafe { rt.add_code::<extern "C" fn(u32) -> u32>(code) };
+    let add42 = unsafe { rt.add_code::<extern "C" fn(u32) -> u32>(code) };
 
     let res = add42(5);
     assert_eq!(res, 47);
diff --git a/src/fib/fib.rs.html b/src/fib/fib.rs.html
index f7b4aa6..7c8db91 100644
--- a/src/fib/fib.rs.html
+++ b/src/fib/fib.rs.html
@@ -1,4 +1,5 @@
-fib.rs - source
1
+fib.rs - source
+    
1
 2
 3
 4
@@ -144,15 +145,15 @@
     // Write out JIT code for visualization.
     // Disassemble for example with `ndisasm -b 64 jit.asm`.
     let code = asm.into_code();
-    std::fs::write("jit.asm", &code).unwrap();
+    std::fs::write("jit.asm", &code).unwrap();
 
     // Move code into executable page and get function pointer to it.
     let mut rt = Runtime::new();
-    let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(code) };
+    let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(code) };
 
     for n in 0..15 {
         let fib_jit = fib(n);
-        println!("fib({}) = {}", n, fib_jit);
+        println!("fib({}) = {}", n, fib_jit);
         assert_eq!(fib_jit, fib_rs(n));
     }
 }
diff --git a/src/juicebox_asm/asm.rs.html b/src/juicebox_asm/asm.rs.html
index fd5f0d5..e58260d 100644
--- a/src/juicebox_asm/asm.rs.html
+++ b/src/juicebox_asm/asm.rs.html
@@ -1,4 +1,5 @@
-asm.rs - source
1
+asm.rs - source
+    
1
 2
 3
 4
@@ -418,14 +419,14 @@
     fn resolve(&mut self, label: &mut Label) {
         if let Some(loc) = label.location() {
             // For now we only support disp32 as label location.
-            let loc = i32::try_from(loc).expect("Label location did not fit into i32.");
+            let loc = i32::try_from(loc).expect("Label location did not fit into i32.");
 
             // Resolve any pending relocations for the label.
             for off in label.offsets_mut().drain() {
                 // Displacement is relative to the next instruction following the jump.
                 // We record the offset to patch at the first byte of the disp32 therefore we need
                 // to account for that in the disp computation.
-                let disp32 = loc - i32::try_from(off).expect("Label offset did not fit into i32") - 4 /* account for the disp32 */;
+                let disp32 = loc - i32::try_from(off).expect("Label offset did not fit into i32") - 4 /* account for the disp32 */;
 
                 // Patch the relocation with the disp32.
                 self.emit_at(off, &disp32.to_ne_bytes());
diff --git a/src/juicebox_asm/imm.rs.html b/src/juicebox_asm/imm.rs.html
index e0b6592..306b800 100644
--- a/src/juicebox_asm/imm.rs.html
+++ b/src/juicebox_asm/imm.rs.html
@@ -1,4 +1,5 @@
-imm.rs - source
1
+imm.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn.rs.html b/src/juicebox_asm/insn.rs.html
index a367feb..7198773 100644
--- a/src/juicebox_asm/insn.rs.html
+++ b/src/juicebox_asm/insn.rs.html
@@ -1,4 +1,5 @@
-insn.rs - source
1
+insn.rs - source
+    
1
 2
 3
 4
@@ -71,6 +72,20 @@
 71
 72
 73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
 
//! Trait definitions of various instructions.
 
 mod add;
@@ -82,6 +97,8 @@
 mod jz;
 mod mov;
 mod nop;
+mod pop;
+mod push;
 mod ret;
 mod test;
 
@@ -136,6 +153,18 @@
     fn mov(&mut self, op1: T, op2: U);
 }
 
+/// Trait for [`push`](https://www.felixcloutier.com/x86/push) instruction kinds.
+pub trait Push<T> {
+    /// Emit a push instruction.
+    fn push(&mut self, op1: T);
+}
+
+/// Trait for [`pop`](https://www.felixcloutier.com/x86/pop) instruction kinds.
+pub trait Pop<T> {
+    /// Emit a pop instruction.
+    fn pop(&mut self, op1: T);
+}
+
 /// Trait for [`test`](https://www.felixcloutier.com/x86/test) instruction kinds.
 pub trait Test<T, U> {
     /// Emit a logical compare instruction.
diff --git a/src/juicebox_asm/insn/add.rs.html b/src/juicebox_asm/insn/add.rs.html
index d7d8c39..a6ac132 100644
--- a/src/juicebox_asm/insn/add.rs.html
+++ b/src/juicebox_asm/insn/add.rs.html
@@ -1,4 +1,5 @@
-add.rs - source
1
+add.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/call.rs.html b/src/juicebox_asm/insn/call.rs.html
index e88996d..3a70194 100644
--- a/src/juicebox_asm/insn/call.rs.html
+++ b/src/juicebox_asm/insn/call.rs.html
@@ -1,4 +1,5 @@
-call.rs - source
1
+call.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/cmp.rs.html b/src/juicebox_asm/insn/cmp.rs.html
index 4e28818..c8bcee2 100644
--- a/src/juicebox_asm/insn/cmp.rs.html
+++ b/src/juicebox_asm/insn/cmp.rs.html
@@ -1,4 +1,5 @@
-cmp.rs - source
1
+cmp.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/dec.rs.html b/src/juicebox_asm/insn/dec.rs.html
index 5a10063..1eed3b2 100644
--- a/src/juicebox_asm/insn/dec.rs.html
+++ b/src/juicebox_asm/insn/dec.rs.html
@@ -1,4 +1,5 @@
-dec.rs - source
1
+dec.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/jmp.rs.html b/src/juicebox_asm/insn/jmp.rs.html
index e0167e3..88f3066 100644
--- a/src/juicebox_asm/insn/jmp.rs.html
+++ b/src/juicebox_asm/insn/jmp.rs.html
@@ -1,4 +1,5 @@
-jmp.rs - source
1
+jmp.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/jnz.rs.html b/src/juicebox_asm/insn/jnz.rs.html
index be0062d..40ae96c 100644
--- a/src/juicebox_asm/insn/jnz.rs.html
+++ b/src/juicebox_asm/insn/jnz.rs.html
@@ -1,4 +1,5 @@
-jnz.rs - source
1
+jnz.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/jz.rs.html b/src/juicebox_asm/insn/jz.rs.html
index e4197af..9a44a21 100644
--- a/src/juicebox_asm/insn/jz.rs.html
+++ b/src/juicebox_asm/insn/jz.rs.html
@@ -1,4 +1,5 @@
-jz.rs - source
1
+jz.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/mov.rs.html b/src/juicebox_asm/insn/mov.rs.html
index 1e672a1..6d6e6e7 100644
--- a/src/juicebox_asm/insn/mov.rs.html
+++ b/src/juicebox_asm/insn/mov.rs.html
@@ -1,4 +1,5 @@
-mov.rs - source
1
+mov.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/nop.rs.html b/src/juicebox_asm/insn/nop.rs.html
index c3c264b..34afd35 100644
--- a/src/juicebox_asm/insn/nop.rs.html
+++ b/src/juicebox_asm/insn/nop.rs.html
@@ -1,4 +1,5 @@
-nop.rs - source
1
+nop.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/pop.rs.html b/src/juicebox_asm/insn/pop.rs.html
new file mode 100644
index 0000000..0852511
--- /dev/null
+++ b/src/juicebox_asm/insn/pop.rs.html
@@ -0,0 +1,30 @@
+pop.rs - source
+    
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+
use super::Pop;
+use crate::{Asm, Reg16, Reg64};
+
+impl Pop<Reg64> for Asm {
+    fn pop(&mut self, op1: Reg64) {
+        self.encode_r(0x8f, 0x0, op1);
+    }
+}
+
+impl Pop<Reg16> for Asm {
+    fn pop(&mut self, op1: Reg16) {
+        self.encode_r(0x8f, 0x0, op1);
+    }
+}
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/push.rs.html b/src/juicebox_asm/insn/push.rs.html new file mode 100644 index 0000000..e947e8b --- /dev/null +++ b/src/juicebox_asm/insn/push.rs.html @@ -0,0 +1,30 @@ +push.rs - source +
1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+
use super::Push;
+use crate::{Asm, Reg16, Reg64};
+
+impl Push<Reg64> for Asm {
+    fn push(&mut self, op1: Reg64) {
+        self.encode_r(0xff, 0x6, op1);
+    }
+}
+
+impl Push<Reg16> for Asm {
+    fn push(&mut self, op1: Reg16) {
+        self.encode_r(0xff, 0x6, op1);
+    }
+}
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/ret.rs.html b/src/juicebox_asm/insn/ret.rs.html index 26e3a47..bc88856 100644 --- a/src/juicebox_asm/insn/ret.rs.html +++ b/src/juicebox_asm/insn/ret.rs.html @@ -1,4 +1,5 @@ -ret.rs - source
1
+ret.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/insn/test.rs.html b/src/juicebox_asm/insn/test.rs.html
index 0f1d8da..6a0372d 100644
--- a/src/juicebox_asm/insn/test.rs.html
+++ b/src/juicebox_asm/insn/test.rs.html
@@ -1,4 +1,5 @@
-test.rs - source
1
+test.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/label.rs.html b/src/juicebox_asm/label.rs.html
index 29d236e..d986d64 100644
--- a/src/juicebox_asm/label.rs.html
+++ b/src/juicebox_asm/label.rs.html
@@ -1,4 +1,5 @@
-label.rs - source
1
+label.rs - source
+    
1
 2
 3
 4
diff --git a/src/juicebox_asm/lib.rs.html b/src/juicebox_asm/lib.rs.html
index 7d1bc0c..d7d33f1 100644
--- a/src/juicebox_asm/lib.rs.html
+++ b/src/juicebox_asm/lib.rs.html
@@ -1,4 +1,5 @@
-lib.rs - source
1
+lib.rs - source
+    
1
 2
 3
 4
@@ -170,11 +171,11 @@
 //!
 //!     // Move code into executable page and get function pointer to it.
 //!     let mut rt = Runtime::new();
-//!     let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(&asm.into_code()) };
+//!     let fib = unsafe { rt.add_code::<extern "C" fn(u64) -> u64>(&asm.into_code()) };
 //!
 //!     for n in 0..15 {
 //!         let fib_jit = fib(n);
-//!         println!("fib({}) = {}", n, fib_jit);
+//!         println!("fib({}) = {}", n, fib_jit);
 //!         assert_eq!(fib_jit, fib_rs(n));
 //!     }
 //! }
diff --git a/src/juicebox_asm/reg.rs.html b/src/juicebox_asm/reg.rs.html
index fe4b50c..f0612f6 100644
--- a/src/juicebox_asm/reg.rs.html
+++ b/src/juicebox_asm/reg.rs.html
@@ -1,4 +1,5 @@
-reg.rs - source
1
+reg.rs - source
+    
1
 2
 3
 4
@@ -353,7 +354,7 @@
 
         #[cfg(test)]
         impl $name {
-            fn iter() -> impl Iterator<Item = &'static $name> {
+            fn iter() -> impl Iterator<Item = &'static $name> {
                 use $name::*;
                 [$( $reg, )+].iter()
             }
diff --git a/src/juicebox_asm/rt.rs.html b/src/juicebox_asm/rt.rs.html
index efc55d3..d58d3e7 100644
--- a/src/juicebox_asm/rt.rs.html
+++ b/src/juicebox_asm/rt.rs.html
@@ -1,4 +1,5 @@
-rt.rs - source
1
+rt.rs - source
+    
1
 2
 3
 4
@@ -200,21 +201,125 @@
 200
 201
 202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
 
//! Simple `mmap`ed runtime.
 //!
 //! This runtime supports adding code to executable pages and turn the added code into user
 //! specified function pointer.
 
-use nix::sys::mman::{mmap, mprotect, munmap, MapFlags, ProtFlags};
+#[cfg(not(target_os = "linux"))]
+compile_error!("This runtime is only supported on linux");
 
-#[cfg(not(target_os = "linux"))]
-compile_error!("This runtime is only supported on linux");
+use nix::sys::mman::{mmap, mprotect, munmap, MapFlags, ProtFlags};
+
+mod perf {
+    use std::fs;
+    use std::io::Write;
+
+    /// Provide support for the simple [perf jit interface][perf-jit].
+    ///
+    /// This allows a simple (static) jit runtime to generate meta data describing the generated
+    /// functions, which is used during post-processing by `perf report` to symbolize addresses
+    /// captured while executing jitted code.
+    ///
+    /// By the nature of this format, this can not be used for dynamic jit runtimes, which reuses
+    /// memory which previously contained jitted code.
+    ///
+    /// [perf-jit]: https://elixir.bootlin.com/linux/v6.6.6/source/tools/perf/Documentation/jit-interface.txt
+    pub(super) struct PerfMap {
+        file: std::fs::File,
+    }
+
+    impl PerfMap {
+        /// Create an empty perf map file.
+        pub(super) fn new() -> Self {
+            let name = format!("/tmp/perf-{}.map", nix::unistd::getpid());
+            let file = fs::OpenOptions::new()
+                .truncate(true)
+                .create(true)
+                .write(true)
+                .open(&name)
+                .unwrap_or_else(|_| panic!("Failed to open perf map file {}", &name));
+
+            PerfMap { file }
+        }
+
+        /// Add an entry to the perf map file.
+        pub(super) fn add_entry(&mut self, start: usize, len: usize) {
+            // Each line has the following format, fields separated with spaces:
+            //   START SIZE NAME
+            //
+            // START and SIZE are hex numbers without 0x.
+            // NAME is the rest of the line, so it could contain special characters.
+            writeln!(self.file, "{:x} {:x} jitfn_{:x}", start, len, start)
+                .expect("Failed to write PerfMap entry");
+        }
+    }
+}
 
 /// A simple `mmap`ed runtime with executable pages.
 pub struct Runtime {
     buf: *mut u8,
     len: usize,
     idx: usize,
+    perf: Option<perf::PerfMap>,
 }
 
 impl Runtime {
@@ -225,7 +330,7 @@
     /// Panics if the `mmap` call fails.
     pub fn new() -> Runtime {
         // Allocate a single page.
-        let len = core::num::NonZeroUsize::new(4096).expect("Value is non zero");
+        let len = core::num::NonZeroUsize::new(4096).expect("Value is non zero");
         let buf = unsafe {
             mmap(
                 None,
@@ -235,16 +340,23 @@
                 0, /* fd */
                 0, /* off */
             )
-            .expect("Failed to mmap runtime code page") as *mut u8
+            .expect("Failed to mmap runtime code page") as *mut u8
         };
 
         Runtime {
             buf,
             len: len.get(),
             idx: 0,
+            perf: None,
         }
     }
 
+    pub fn with_profile() -> Runtime {
+        let mut rt = Runtime::new();
+        rt.perf = Some(perf::PerfMap::new());
+        rt
+    }
+
     /// Add the block of `code` to the runtime and a get function pointer of type `F`.
     ///
     /// # Panics
@@ -262,21 +374,21 @@
     /// let mut rt = juicebox_asm::Runtime::new();
     ///
     /// let code = [ 0x90 /* nop */, 0xc3 /* ret */ ];
-    /// let nop = unsafe { rt.add_code::<extern "C" fn()>(&code) };
+    /// let nop = unsafe { rt.add_code::<extern "C" fn()>(&code) };
     ///
     /// nop();
     /// ```
     pub unsafe fn add_code<F>(&mut self, code: impl AsRef<[u8]>) -> F {
         // Get pointer to start of next free byte.
-        assert!(self.idx < self.len, "Runtime code page full");
+        assert!(self.idx < self.len, "Runtime code page full");
         let fn_start = self.buf.add(self.idx);
 
         // Copy over code.
         let code = code.as_ref();
-        assert!(!code.is_empty(), "Adding empty code not supported");
+        assert!(!code.is_empty(), "Adding empty code not supported");
         assert!(
             code.len() <= (self.len - self.idx),
-            "Code does not fit on the runtime code page"
+            "Code does not fit on the runtime code page"
         );
         self.unprotect();
         unsafe { std::ptr::copy_nonoverlapping(code.as_ptr(), fn_start, code.len()) };
@@ -285,6 +397,11 @@
         // Increment index to next free byte.
         self.idx += code.len();
 
+        // Add perf map entry.
+        if let Some(map) = &mut self.perf {
+            map.add_entry(fn_start as usize, code.len());
+        }
+
         // Return function to newly added code.
         unsafe { Self::as_fn::<F>(fn_start) }
     }
@@ -304,7 +421,7 @@
     pub fn dump(&self) {
         assert!(self.idx <= self.len);
         let code = unsafe { core::slice::from_raw_parts(self.buf, self.idx) };
-        std::fs::write("jit.asm", code).expect("Failed to write file");
+        std::fs::write("jit.asm", code).expect("Failed to write file");
     }
 
     /// Reinterpret the block of code pointed to by `fn_start` as `F`.
@@ -326,7 +443,7 @@
                 self.len,
                 ProtFlags::PROT_READ | ProtFlags::PROT_EXEC,
             )
-            .expect("Failed to RX mprotect runtime code page");
+            .expect("Failed to RX mprotect runtime code page");
         }
     }
 
@@ -339,7 +456,7 @@
         unsafe {
             // Add write permissions to code page.
             mprotect(self.buf.cast(), self.len, ProtFlags::PROT_WRITE)
-                .expect("Failed to W mprotect runtime code page");
+                .expect("Failed to W mprotect runtime code page");
         }
     }
 }
@@ -349,7 +466,7 @@
     /// [`Runtime::add_code`].
     fn drop(&mut self) {
         unsafe {
-            munmap(self.buf.cast(), self.len).expect("Failed to munmap runtime");
+            munmap(self.buf.cast(), self.len).expect("Failed to munmap runtime");
         }
     }
 }
@@ -363,7 +480,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4096];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -373,7 +490,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4097];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -383,12 +500,12 @@
         let mut rt = Runtime::new();
         let code = [0u8; 4096];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
 
         let code = [0u8; 1];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 
@@ -398,7 +515,7 @@
         let mut rt = Runtime::new();
         let code = [0u8; 0];
         unsafe {
-            rt.add_code::<extern "C" fn()>(code);
+            rt.add_code::<extern "C" fn()>(code);
         }
     }
 }
diff --git a/src/tiny_vm/tiny_vm.rs.html b/src/tiny_vm/tiny_vm.rs.html
index d36abd1..938bc61 100644
--- a/src/tiny_vm/tiny_vm.rs.html
+++ b/src/tiny_vm/tiny_vm.rs.html
@@ -1,4 +1,5 @@
-tiny_vm.rs - source
1
+tiny_vm.rs - source
+    
1
 2
 3
 4
@@ -696,12 +697,19 @@
 696
 697
 698
+699
+700
+701
+702
+703
+704
+705
 
//! TinyVm example.
 //!
-//! This example introduces as simple 16 bit virtual machine the [`TinyVm`]. The VM consits of
-//! three registers defined in [`TinyReg`], a separate _data_ and _insutrction_ memory and a small
+//! This example introduces a simple 16 bit virtual machine the [`TinyVm`]. The VM consists of
+//! three registers defined in [`TinyReg`], a separate _data_ and _instruction_ memory and a small
 //! set of instructions [`TinyInsn`], sufficient to implement a guest program to compute the
-//! fiibonacci sequence.
+//! Fibonacci sequence.
 //!
 //! The `TinyVm` implements a simple _just-in-time (JIT)_ compiler to demonstrate the
 //! [`juicebox_asm`] crate. Additionally, it implements a reference _interpreter_.
@@ -801,7 +809,7 @@
 ///                    End of basic block, executed N instructions,
 ///                    must re-enter at `pc = R`.
 /// ```
-type JitFn = extern "C" fn(*mut u16, *mut u8) -> JitRet;
+type JitFn = extern "C" fn(*mut u16, *mut u8) -> JitRet;
 
 /// The `TinyVm` virtual machine state.
 pub struct TinyVm {
@@ -842,7 +850,9 @@
             // -- JIT state.
             jit_cache,
             rt: Runtime::new(),
-        }
+            // Confifigure the runtime to generates perf meta data.
+            //rt: Runtime::with_profile(),
+        }
     }
 
     /// Read guest register.
@@ -874,11 +884,11 @@
 
     /// Dump the VM state to stdout.
     pub fn dump(&self) {
-        println!("-- TinyVm state --");
-        println!("  ICNT: {}", self.icnt);
-        println!("  PC  : {:02x}", self.pc - 1);
+        println!("-- TinyVm state --");
+        println!("  ICNT: {}", self.icnt);
+        println!("  PC  : {:02x}", self.pc - 1);
         println!(
-            "  A:{:04x} B:{:04x} C:{:04x}",
+            "  A:{:04x} B:{:04x} C:{:04x}",
             self.read_reg(TinyReg::A),
             self.read_reg(TinyReg::B),
             self.read_reg(TinyReg::C),
@@ -887,16 +897,16 @@
 
     /// Run in interpreter mode until the next [`TinyInsn::Halt`] instruction is hit.
     pub fn interp(&mut self) {
-        'outer: loop {
+        'outer: loop {
             let insn = self.imem[self.pc];
-            //println!("[0x{:02x}] {:?}", self.pc, insn);
+            //println!("[0x{:02x}] {:?}", self.pc, insn);
 
             self.pc = self.pc.wrapping_add(1);
             self.icnt += 1;
 
             match insn {
                 TinyInsn::Halt => {
-                    break 'outer;
+                    break 'outer;
                 }
                 TinyInsn::LoadImm(a, imm) => {
                     self.write_reg(a, imm);
@@ -932,34 +942,39 @@
     /// Run in JIT mode until the next [`TinyInsn::Halt`] instruction is hit. Translate guest
     /// _basic blocks_ on demand.
     pub fn jit(&mut self) {
-        'outer: loop {
-            if let Some(bb_fn) = self.jit_cache[self.pc] {
-                match bb_fn(self.regs.as_mut_ptr(), self.dmem.as_mut_ptr()) {
-                    JitRet(0, insn) => {
-                        self.pc += insn as usize;
-                        self.icnt += insn as usize;
-                        break 'outer;
-                    }
-                    JitRet(insn, reenter_pc) => {
-                        self.pc = reenter_pc as usize;
-                        self.icnt += insn as usize;
-                    }
-                }
+        'outer: loop {
+            let bb_fn = if let Some(bb_fn) = self.jit_cache[self.pc] {
+                bb_fn
             } else {
                 let bb_fn = self.translate_next_bb();
                 self.jit_cache[self.pc] = Some(bb_fn);
-                //println!("[0x{:02x}] translated bb at {:p}", self.pc, bb_fn);
-            }
+                //println!("[0x{:02x}] translated bb at {:p}", self.pc, bb_fn);
+                bb_fn
+            };
+
+            match bb_fn(self.regs.as_mut_ptr(), self.dmem.as_mut_ptr()) {
+                // HALT instruction hit.
+                JitRet(0, insn) => {
+                    self.pc += insn as usize;
+                    self.icnt += insn as usize;
+                    break 'outer;
+                }
+                // End of basic block, re-enter.
+                JitRet(insn, reenter_pc) => {
+                    self.pc = reenter_pc as usize;
+                    self.icnt += insn as usize;
+                }
+            }
         }
     }
 
-    #[cfg(all(any(target_arch = "x86_64", target_os = "linux")))]
+    #[cfg(all(any(target_arch = "x86_64", target_os = "linux")))]
     /// Translate the bb at the current pc and return a JitFn pointer to it.
     fn translate_next_bb(&mut self) -> JitFn {
         let mut bb = Asm::new();
         let mut pc = self.pc;
 
-        'outer: loop {
+        'outer: loop {
             let insn = self.imem[pc];
 
             pc = pc.wrapping_add(1);
@@ -976,7 +991,7 @@
 
             // Generate memory operand into regs for guest register.
             let reg_op = |r: TinyReg| {
-                MemOp::IndirectDisp(Reg64::rdi, (r.idx() * 2).try_into().expect("only 3 regs"))
+                MemOp::IndirectDisp(Reg64::rdi, (r.idx() * 2).try_into().expect("only 3 regs"))
             };
 
             // Generate memory operand into dmem for guest phys address.
@@ -992,7 +1007,7 @@
                     bb.mov(Reg64::rax, Imm64::from(0));
                     bb.mov(Reg64::rdx, Imm64::from(bb_icnt()));
                     bb.ret();
-                    break 'outer;
+                    break 'outer;
                 }
                 TinyInsn::LoadImm(a, imm) => {
                     bb.mov(reg_op(a), Imm16::from(imm));
@@ -1016,7 +1031,7 @@
                     bb.mov(Reg64::rax, Imm64::from(bb_icnt()));
                     bb.mov(Reg64::rdx, Imm64::from(reenter_pc(disp)));
                     bb.ret();
-                    break 'outer;
+                    break 'outer;
                 }
                 TinyInsn::BranchZero(a, disp) => {
                     bb.cmp(reg_op(a), Imm16::from(0u16));
@@ -1029,7 +1044,7 @@
                     bb.mov(Reg64::rdx, Imm64::from(reenter_pc(pc)));
                     bb.bind(&mut skip_next_pc);
                     bb.ret();
-                    break 'outer;
+                    break 'outer;
                 }
             }
         }
@@ -1053,7 +1068,7 @@
     pub fn bind(self, prog: &mut Vec<TinyInsn>) {
         let plen = prog.len();
         let insn = prog.get_mut(self.pc).expect(&format!(
-            "Trying to apply Fixup, but Fixup is out of range pc={} prog.len={}",
+            "Trying to apply Fixup, but Fixup is out of range pc={} prog.len={}",
             self.pc, plen
         ));
 
@@ -1062,7 +1077,7 @@
                 *disp = plen;
             }
             _ => {
-                unimplemented!("Trying to fixup non-branch instruction '{:?}'", *insn);
+                unimplemented!("Trying to fixup non-branch instruction '{:?}'", *insn);
             }
         }
     }
@@ -1190,24 +1205,24 @@
 
 fn main() {
     let use_jit = match std::env::args().nth(1) {
-        Some(a) if a == "-h" || a == "--help" => {
-            println!("Usage: tiny_vm [mode]");
-            println!("");
-            println!("Options:");
-            println!("    mode    if mode is 'jit' then run in jit mode, else in interpreter mode");
+        Some(a) if a == "-h" || a == "--help" => {
+            println!("Usage: tiny_vm [mode]");
+            println!("");
+            println!("Options:");
+            println!("    mode    if mode is 'jit' then run in jit mode, else in interpreter mode");
             std::process::exit(0);
         }
-        Some(a) if a == "jit" => true,
+        Some(a) if a == "jit" => true,
         _ => false,
     };
 
     let mut vm = TinyVm::new(make_tinyvm_fib(42));
 
     if use_jit {
-        println!("Run in jit mode..");
+        println!("Run in jit mode..");
         vm.jit();
     } else {
-        println!("Run in interpreter mode..");
+        println!("Run in interpreter mode..");
         vm.interp();
     }
     vm.dump();
-- 
cgit v1.2.3