From 5289cbf5331dfd0d0c2242a7e7c8030aa4032c7e Mon Sep 17 00:00:00 2001 From: johannst Date: Sat, 7 Dec 2024 01:01:45 +0000 Subject: deploy: 9c3c3fd923d894d2351eb22129ea693eb98fa8ff --- src/add/add.rs.html | 7 +- src/bf_vm/bf_vm.rs.html | 585 +++++++++++++++++++++++++++++++++++ src/fib/fib.rs.html | 7 +- src/juicebox_asm/asm.rs.html | 281 +++++++++++++++-- src/juicebox_asm/imm.rs.html | 9 +- src/juicebox_asm/insn.rs.html | 33 +- src/juicebox_asm/insn/add.rs.html | 29 +- src/juicebox_asm/insn/call.rs.html | 7 +- src/juicebox_asm/insn/cmovnz.rs.html | 7 +- src/juicebox_asm/insn/cmovz.rs.html | 7 +- src/juicebox_asm/insn/cmp.rs.html | 19 +- src/juicebox_asm/insn/dec.rs.html | 55 +++- src/juicebox_asm/insn/inc.rs.html | 77 +++++ src/juicebox_asm/insn/jmp.rs.html | 7 +- src/juicebox_asm/insn/jnz.rs.html | 7 +- src/juicebox_asm/insn/jz.rs.html | 7 +- src/juicebox_asm/insn/mov.rs.html | 7 +- src/juicebox_asm/insn/nop.rs.html | 7 +- src/juicebox_asm/insn/pop.rs.html | 7 +- src/juicebox_asm/insn/push.rs.html | 7 +- src/juicebox_asm/insn/ret.rs.html | 7 +- src/juicebox_asm/insn/test.rs.html | 7 +- src/juicebox_asm/insn/xor.rs.html | 17 + src/juicebox_asm/label.rs.html | 7 +- src/juicebox_asm/lib.rs.html | 119 ++++++- src/juicebox_asm/reg.rs.html | 11 +- src/juicebox_asm/rt.rs.html | 7 +- src/tiny_vm/tiny_vm.rs.html | 7 +- 28 files changed, 1231 insertions(+), 123 deletions(-) create mode 100644 src/bf_vm/bf_vm.rs.html create mode 100644 src/juicebox_asm/insn/inc.rs.html create mode 100644 src/juicebox_asm/insn/xor.rs.html (limited to 'src') diff --git a/src/add/add.rs.html b/src/add/add.rs.html index 5e602fb..38058ec 100644 --- a/src/add/add.rs.html +++ b/src/add/add.rs.html @@ -1,5 +1,5 @@ -add.rs - source -
1
+add.rs - source

add/
add.rs

+1
 2
 3
 4
@@ -36,8 +36,7 @@
 35
 36
 37
-38
-
//! Add example.
+38
//! Add example.
 //!
 //! 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.
diff --git a/src/bf_vm/bf_vm.rs.html b/src/bf_vm/bf_vm.rs.html
new file mode 100644
index 0000000..a62b04e
--- /dev/null
+++ b/src/bf_vm/bf_vm.rs.html
@@ -0,0 +1,585 @@
+bf_vm.rs - source

bf_vm/
bf_vm.rs

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+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
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
//! Brainfuck VM.
+//!
+//! This example implements a simple
+//! [brainfuck][https://en.wikipedia.org/wiki/Brainfuck] interpreter
+//! [`BrainfuckInterp`] and a jit compiler [`BrainfuckJit`].
+//!
+//! Brainfuck is an esoteric programming languge existing of 8 commands.
+//! - `>` increment data pointer.
+//! - `<` decrement data pointer.
+//! - `+` increment data at current data pointer.
+//! - `-` decrement data at current data pointer.
+//! - `.` output data at current data pointer.
+//! - `,` read input and store at current data pointer.
+//! - `[` jump behind matching ']' if data at data pointer is zero.
+//! - `]` jump behind matching '[' if data at data pointer is non-zero.
+
+use std::collections::HashMap;
+use std::io::Write;
+
+use juicebox_asm::insn::*;
+use juicebox_asm::Runtime;
+use juicebox_asm::{Asm, Imm64, Imm8, Label, MemOp, MemOp8, Reg64, Reg8};
+
+struct BrainfuckInterp {
+    pc: usize,
+    imem: Vec<char>,
+    dptr: usize,
+    dmem: [u8; 256],
+    branches: HashMap<usize, usize>,
+}
+
+impl BrainfuckInterp {
+    fn new(prog: &str) -> Result<Self, String> {
+        // Do a first pass over the bf program to filter whitespace and detect invalid tokens.
+        // Additionally validate all conditional branches, and compute their branch target.
+        let (imem, branches) = {
+            // Instruction memory holding the final bf program.
+            let mut imem = Vec::new();
+            // Helper to track index of open brackets.
+            let mut lhs_brackets = Vec::new();
+            // Mapping from branch instruction to branch target.
+            let mut branches = HashMap::new();
+
+            for (idx, token) in prog.chars().filter(|c| !c.is_whitespace()).enumerate() {
+                match token {
+                    '<' | '>' | '+' | '-' | '.' | ',' => { /* ignore valid bf tokens */ }
+                    '[' => lhs_brackets.push(idx),
+                    ']' => {
+                        if let Some(lhs) = lhs_brackets.pop() {
+                            branches.insert(lhs, idx);
+                            branches.insert(idx, lhs);
+                        } else {
+                            return Err(format!("encountered un-balanced brackets, found ']' at index {idx} without matching '['"));
+                        }
+                    }
+                    _ => return Err(format!("invalid bf token '{token}'")),
+                }
+                imem.push(token)
+            }
+
+            if !lhs_brackets.is_empty() {
+                return Err(String::from(
+                    "encountered un-balanced brackets, left-over '[' after parsing bf program",
+                ));
+            }
+
+            (imem, branches)
+        };
+
+        Ok(BrainfuckInterp {
+            pc: 0,
+            imem,
+            dptr: 0,
+            dmem: [0; 256],
+            branches,
+        })
+    }
+}
+
+fn run_interp(prog: &str) {
+    let mut vm = BrainfuckInterp::new(prog).unwrap();
+
+    loop {
+        let insn = match vm.imem.get(vm.pc) {
+            Some(insn) => insn,
+            None => break, // End of bf program.
+        };
+
+        let putchar = |val: u8| {
+            std::io::stdout()
+                .write(&[val])
+                .expect("Failed to write to stdout!");
+        };
+
+        match insn {
+            '>' => {
+                vm.dptr += 1;
+                assert!(vm.dptr < vm.dmem.len());
+            }
+            '<' => {
+                assert!(vm.dptr > 0);
+                vm.dptr -= 1;
+            }
+            '+' => {
+                vm.dmem[vm.dptr] += 1;
+            }
+            '-' => {
+                vm.dmem[vm.dptr] -= 1;
+            }
+            '.' => {
+                putchar(vm.dmem[vm.dptr]);
+            }
+            ',' => {
+                unimplemented!("getchar");
+            }
+            '[' => {
+                if vm.dmem[vm.dptr] == 0 {
+                    vm.pc = *vm.branches.get(&vm.pc).unwrap();
+                }
+            }
+            ']' => {
+                if vm.dmem[vm.dptr] != 0 {
+                    vm.pc = *vm.branches.get(&vm.pc).unwrap();
+                }
+            }
+            _ => unreachable!(),
+        }
+
+        vm.pc += 1;
+    }
+}
+
+// -- BRAINFUCK JIT --------------------------------------------------------------
+
+#[cfg(not(any(target_arch = "x86_64", target_os = "linux")))]
+compile_error!("Only supported on x86_64 with SystemV abi");
+
+struct BrainfuckJit {
+    imem: Vec<char>,
+    dmem: [u8; 256],
+}
+
+impl BrainfuckJit {
+    fn new(prog: &str) -> Result<Self, String> {
+        // Do a first pass over the bf program to filter whitespace and detect invalid tokens.
+        let imem = prog
+            .chars()
+            .filter(|c| !c.is_whitespace())
+            .map(|c| match c {
+                '<' | '>' | '+' | '-' | '.' | ',' | '[' | ']' => Ok(c),
+                _ => Err(format!("invalid bf token '{c}'")),
+            })
+            .collect::<Result<Vec<char>, String>>()?;
+
+        Ok(BrainfuckJit {
+            imem,
+            dmem: [0; 256],
+        })
+    }
+}
+
+extern "C" fn putchar(c: u8) {
+    std::io::stdout()
+        .write(&[c])
+        .expect("Failed to write to stdout!");
+}
+
+fn run_jit(prog: &str) {
+    let mut vm = BrainfuckJit::new(prog).unwrap();
+
+    // Use callee saved registers to hold vm state, such that we don't
+    // need to save any state before calling out to putchar.
+    let dmem_base = Reg64::rbx;
+    let dmem_idx = Reg64::r12;
+
+    let mut asm = Asm::new();
+    // Move data memory pointer (argument on jit entry) into correct
+    // register.
+    asm.mov(dmem_base, Reg64::rdi);
+    // Clear data memory index.
+    asm.xor(dmem_idx, dmem_idx);
+
+    // A stack of label pairs, used to link up forward and backward
+    // jumps for a given '[]' pair.
+    let mut label_stack = Vec::new();
+
+    // Generate code for each instruction in the bf program.
+    for insn in vm.imem {
+        match insn {
+            '>' => {
+                // TODO: generate runtime bounds check.
+                asm.inc(dmem_idx);
+            }
+            '<' => {
+                // TODO: generate runtime bounds check.
+                asm.dec(dmem_idx);
+            }
+            '+' => {
+                asm.inc(MemOp8::from(MemOp::IndirectBaseIndex(dmem_base, dmem_idx)));
+            }
+            '-' => {
+                asm.dec(MemOp8::from(MemOp::IndirectBaseIndex(dmem_base, dmem_idx)));
+            }
+            '.' => {
+                // Load data memory from active cell into di register,
+                // which is the first argument register according to
+                // the SystemV abi, then call into putchar. Since we
+                // stored all out vm state in callee saved registers
+                // we don't need to save any registers before the
+                // call.
+                asm.mov(Reg8::dil, MemOp::IndirectBaseIndex(dmem_base, dmem_idx));
+                asm.mov(Reg64::rax, Imm64::from(putchar as usize));
+                asm.call(Reg64::rax);
+            }
+            ',' => {
+                unimplemented!("getchar");
+            }
+            '[' => {
+                // Create new label pair.
+                label_stack.push((Label::new(), Label::new()));
+                // UNWRAP: We just pushed a new entry on the stack.
+                let label_pair = label_stack.last_mut().unwrap();
+
+                // Goto label_pair.0 if data memory at active cell is 0.
+                //   if vm.dmem[vm.dptr] == 0 goto label_pair.0
+                asm.cmp(
+                    MemOp::IndirectBaseIndex(dmem_base, dmem_idx),
+                    Imm8::from(0u8),
+                );
+                asm.jz(&mut label_pair.0);
+
+                // Bind label_pair.1 after the jump instruction, which
+                // will be the branch target for the matching ']'.
+                asm.bind(&mut label_pair.1);
+            }
+            ']' => {
+                let mut label_pair = label_stack
+                    .pop()
+                    .expect("encountered un-balanced brackets, found ']' without matching '['");
+
+                // Goto label_pair.1 if data memory at active cell is
+                // not 0.
+                //   if vm.dmem[vm.dptr] != 0 goto label_pair.1
+                asm.cmp(
+                    MemOp::IndirectBaseIndex(dmem_base, dmem_idx),
+                    Imm8::from(0u8),
+                );
+                asm.jnz(&mut label_pair.1);
+
+                // Bind label_pair.0 after the jump instruction, which
+                // is the branch target for the matching '['.
+                asm.bind(&mut label_pair.0);
+            }
+            _ => unreachable!(),
+        }
+    }
+
+    // Return from bf program.
+    asm.ret();
+
+    if !label_stack.is_empty() {
+        panic!("encountered un-balanced brackets, left-over '[' after jitting bf program")
+    }
+
+    // Execute jitted bf program.
+    let mut rt = Runtime::new();
+    let bf_entry = unsafe { rt.add_code::<extern "C" fn(*mut u8)>(asm.into_code()) };
+    bf_entry(&mut vm.dmem as *mut u8);
+}
+
+fn main() {
+    // https://en.wikipedia.org/wiki/Brainfuck#Adding_two_values
+    //let inp = "++>+++++ [<+>-] ++++++++[<++++++>-]<.";
+    //println!("add-print-7 (wikipedia.org) - interp");
+    //run_interp(inp);
+    //println!("add-print-7 (wikipedia.org) - jit");
+    //run_jit(inp);
+
+    // https://en.wikipedia.org/wiki/Brainfuck#Hello_World!
+    let inp = "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.";
+    println!("hello-world (wikipedia.org) - interp");
+    run_interp(inp);
+    println!("hello-world (wikipedia.org) - jit");
+    run_jit(inp);
+
+    // https://programmingwiki.de/Brainfuck
+    let inp = ">+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.+++++++..+++.[-]>++++++++[<++++>-] <.>+++++++++++[<++++++++>-]<-.--------.+++.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++.";
+    println!("hello-world (programmingwiki.de) - interp");
+    run_interp(inp);
+    println!("hello-world (programmingwiki.de) - jit");
+    run_jit(inp);
+}
+
\ No newline at end of file diff --git a/src/fib/fib.rs.html b/src/fib/fib.rs.html index 7c8db91..0b7a4bf 100644 --- a/src/fib/fib.rs.html +++ b/src/fib/fib.rs.html @@ -1,5 +1,5 @@ -fib.rs - source -
1
+fib.rs - source

fib/
fib.rs

+1
 2
 3
 4
@@ -77,8 +77,7 @@
 76
 77
 78
-79
-
//! Fibonacci example.
+79
//! Fibonacci example.
 //!
 //! Jit compile a function at runtime (generate native host code) to compute the fibonacci sequence
 //! to demonstrate the [`juicebox_asm`] crate.
diff --git a/src/juicebox_asm/asm.rs.html b/src/juicebox_asm/asm.rs.html
index 4418397..3f24ae2 100644
--- a/src/juicebox_asm/asm.rs.html
+++ b/src/juicebox_asm/asm.rs.html
@@ -1,5 +1,5 @@
-asm.rs - source
-    
1
+asm.rs - source

juicebox_asm/
asm.rs

+1
 2
 3
 4
@@ -344,7 +344,120 @@
 343
 344
 345
-
//! The `x64` jit assembler.
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
//! The `x64` jit assembler.
 
 use crate::*;
 use imm::Imm;
@@ -364,6 +477,11 @@
     ((mod_ & 0b11) << 6) | ((reg & 0b111) << 3) | (rm & 0b111)
 }
 
+/// Encode the `SIB` byte.
+const fn sib(scale: u8, index: u8, base: u8) -> u8 {
+    ((scale & 0b11) << 6) | ((index & 0b111) << 3) | (base & 0b111)
+}
+
 /// `x64` jit assembler.
 pub struct Asm {
     buf: Vec<u8>,
@@ -495,6 +613,52 @@
         self.emit(&[opc, modrm]);
     }
 
+    /// Encode a memory operand instruction.
+    pub(crate) fn encode_m<T: MemOpSized>(&mut self, opc: u8, opc_ext: u8, op1: T)
+    where
+        Self: EncodeM<T>,
+    {
+        let op1 = op1.mem_op();
+
+        // M operand encoding.
+        //   op1 -> modrm.rm
+        let (mode, rm) = match op1 {
+            MemOp::Indirect(..) => {
+                assert!(!op1.base().need_sib() && !op1.base().is_pc_rel());
+                (0b00, op1.base().idx())
+            }
+            MemOp::IndirectDisp(..) => {
+                assert!(!op1.base().need_sib());
+                (0b10, op1.base().idx())
+            }
+            MemOp::IndirectBaseIndex(..) => {
+                assert!(!op1.base().is_pc_rel());
+                // Using rsp as index register is interpreted as just base w/o offset.
+                //   https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2
+                // Disallow this case, as guard for the user.
+                assert!(!matches!(op1.index(), Reg64::rsp));
+                (0b00, 0b100)
+            }
+        };
+
+        let modrm = modrm(
+            mode,    /* mode */
+            opc_ext, /* reg */
+            rm,      /* rm */
+        );
+
+        let prefix = <Self as EncodeM<T>>::legacy_prefix();
+        let rex = <Self as EncodeM<T>>::rex(&op1);
+
+        self.emit_optional(&[prefix, rex]);
+        self.emit(&[opc, modrm]);
+        match op1 {
+            MemOp::Indirect(..) => {}
+            MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()),
+            MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]),
+        }
+    }
+
     /// Encode a memory-immediate instruction.
     pub(crate) fn encode_mi<T: Imm>(&mut self, opc: u8, opc_ext: u8, op1: MemOp, op2: T)
     where
@@ -503,21 +667,29 @@
         // MI operand encoding.
         //   op1 -> modrm.rm
         //   op2 -> imm
-        let mode = match op1 {
+        let (mode, rm) = match op1 {
             MemOp::Indirect(..) => {
                 assert!(!op1.base().need_sib() && !op1.base().is_pc_rel());
-                0b00
-            }
+                (0b00, op1.base().idx())
+            }
             MemOp::IndirectDisp(..) => {
                 assert!(!op1.base().need_sib());
-                0b10
-            }
+                (0b10, op1.base().idx())
+            }
+            MemOp::IndirectBaseIndex(..) => {
+                assert!(!op1.base().is_pc_rel());
+                // Using rsp as index register is interpreted as just base w/o offset.
+                //   https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2
+                // Disallow this case, as guard for the user.
+                assert!(!matches!(op1.index(), Reg64::rsp));
+                (0b00, 0b100)
+            }
         };
 
         let modrm = modrm(
-            mode,             /* mode */
-            opc_ext,          /* reg */
-            op1.base().idx(), /* rm */
+            mode,    /* mode */
+            opc_ext, /* reg */
+            rm,      /* rm */
         );
 
         let prefix = <Self as EncodeMI<T>>::legacy_prefix();
@@ -525,8 +697,10 @@
 
         self.emit_optional(&[prefix, rex]);
         self.emit(&[opc, modrm]);
-        if let MemOp::IndirectDisp(_, disp) = op1 {
-            self.emit(&disp.to_ne_bytes());
+        match op1 {
+            MemOp::Indirect(..) => {}
+            MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()),
+            MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]),
         }
         self.emit(op2.bytes());
     }
@@ -539,29 +713,40 @@
         // MR operand encoding.
         //   op1 -> modrm.rm
         //   op2 -> modrm.reg
-        let mode = match op1 {
+        let (mode, rm) = match op1 {
             MemOp::Indirect(..) => {
                 assert!(!op1.base().need_sib() && !op1.base().is_pc_rel());
-                0b00
-            }
+                (0b00, op1.base().idx())
+            }
             MemOp::IndirectDisp(..) => {
                 assert!(!op1.base().need_sib());
-                0b10
-            }
+                (0b10, op1.base().idx())
+            }
+            MemOp::IndirectBaseIndex(..) => {
+                assert!(!op1.base().is_pc_rel());
+                // Using rsp as index register is interpreted as just base w/o offset.
+                //   https://wiki.osdev.org/X86-64_Instruction_Encoding#32.2F64-bit_addressing_2
+                // Disallow this case, as guard for the user.
+                assert!(!matches!(op1.index(), Reg64::rsp));
+                (0b00, 0b100)
+            }
         };
 
         let modrm = modrm(
-            mode,             /* mode */
-            op2.idx(),        /* reg */
-            op1.base().idx(), /* rm */
+            mode,      /* mode */
+            op2.idx(), /* reg */
+            rm,        /* rm */
         );
+
         let prefix = <Self as EncodeMR<T>>::legacy_prefix();
         let rex = <Self as EncodeMR<T>>::rex(&op1, op2);
 
         self.emit_optional(&[prefix, rex]);
         self.emit(&[opc, modrm]);
-        if let MemOp::IndirectDisp(_, disp) = op1 {
-            self.emit(&disp.to_ne_bytes());
+        match op1 {
+            MemOp::Indirect(..) => {}
+            MemOp::IndirectDisp(_, disp) => self.emit(&disp.to_ne_bytes()),
+            MemOp::IndirectBaseIndex(base, index) => self.emit(&[sib(0, index.idx(), base.idx())]),
         }
     }
 
@@ -650,8 +835,13 @@
     }
 
     fn rex(op1: &MemOp, op2: T) -> Option<u8> {
-        if op2.need_rex() || (op1.base().is_ext()) {
-            Some(rex(op2.rexw(), op2.idx(), 0, op1.base().idx()))
+        if op2.need_rex() || op1.base().is_ext() || op1.index().is_ext() {
+            Some(rex(
+                op2.rexw(),
+                op2.idx(),
+                op1.index().idx(),
+                op1.base().idx(),
+            ))
         } else {
             None
         }
@@ -674,8 +864,8 @@
     }
 
     fn rex(op1: &MemOp) -> Option<u8> {
-        if op1.base().is_ext() {
-            Some(rex(false, 0, 0, op1.base().idx()))
+        if op1.base().is_ext() || op1.index().is_ext() {
+            Some(rex(false, 0, op1.index().idx(), op1.base().idx()))
         } else {
             None
         }
@@ -689,4 +879,41 @@
     }
 }
 impl EncodeMI<Imm32> for Asm {}
+
+/// Encode helper for memory operand instructions.
+pub(crate) trait EncodeM<T: MemOpSized> {
+    fn legacy_prefix() -> Option<u8> {
+        None
+    }
+
+    fn rex(op1: &MemOp) -> Option<u8> {
+        if op1.base().is_ext() || op1.index().is_ext() || Self::is_64bit() {
+            Some(rex(
+                Self::is_64bit(),
+                0,
+                op1.index().idx(),
+                op1.base().idx(),
+            ))
+        } else {
+            None
+        }
+    }
+
+    fn is_64bit() -> bool {
+        false
+    }
+}
+
+impl EncodeM<MemOp8> for Asm {}
+impl EncodeM<MemOp16> for Asm {
+    fn legacy_prefix() -> Option<u8> {
+        Some(0x66)
+    }
+}
+impl EncodeM<MemOp32> for Asm {}
+impl EncodeM<MemOp64> for Asm {
+    fn is_64bit() -> bool {
+        true
+    }
+}
 
\ No newline at end of file diff --git a/src/juicebox_asm/imm.rs.html b/src/juicebox_asm/imm.rs.html index 306b800..5ddf841 100644 --- a/src/juicebox_asm/imm.rs.html +++ b/src/juicebox_asm/imm.rs.html @@ -1,5 +1,5 @@ -imm.rs - source -
1
+imm.rs - source

juicebox_asm/
imm.rs

+1
 2
 3
 4
@@ -61,8 +61,7 @@
 60
 61
 62
-63
-
//! Definition of different immediate types which are used as input operands for various
+63
//! Definition of different immediate types which are used as input operands for various
 //! instructions.
 
 /// Trait to interact with immediate operands.
@@ -71,7 +70,7 @@
     fn bytes(&self) -> &[u8];
 }
 
-macro_rules! impl_imm {
+macro_rules! impl_imm {
     (#[$doc:meta] $name:ident, $size:expr, from: { $( $from:ty ),* $(,)? }) => {
         #[$doc]
         pub struct $name([u8; $size]);
diff --git a/src/juicebox_asm/insn.rs.html b/src/juicebox_asm/insn.rs.html
index 029258c..b82f83d 100644
--- a/src/juicebox_asm/insn.rs.html
+++ b/src/juicebox_asm/insn.rs.html
@@ -1,5 +1,5 @@
-insn.rs - source
-    
1
+insn.rs - source

juicebox_asm/
insn.rs

+1
 2
 3
 4
@@ -102,7 +102,20 @@
 101
 102
 103
-
//! Trait definitions of various instructions.
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
//! Trait definitions of various instructions.
 
 mod add;
 mod call;
@@ -110,6 +123,7 @@
 mod cmovz;
 mod cmp;
 mod dec;
+mod inc;
 mod jmp;
 mod jnz;
 mod jz;
@@ -119,6 +133,7 @@
 mod push;
 mod ret;
 mod test;
+mod xor;
 
 /// Trait for [`add`](https://www.felixcloutier.com/x86/add) instruction kinds.
 pub trait Add<T, U> {
@@ -161,6 +176,12 @@
     fn dec(&mut self, op1: T);
 }
 
+/// Trait for [`inc`](https://www.felixcloutier.com/x86/inc) instruction kinds.
+pub trait Inc<T> {
+    /// Emit a increment instruction.
+    fn inc(&mut self, op1: T);
+}
+
 /// Trait for [`jmp`](https://www.felixcloutier.com/x86/jmp) instruction kinds.
 pub trait Jmp<T> {
     /// Emit an unconditional jump instruction.
@@ -205,4 +226,10 @@
     /// `SF`, `ZF`, and `PF` status flags, the result is discarded.
     fn test(&mut self, op1: T, op2: U);
 }
+
+/// Trait for [`xor`](https://www.felixcloutier.com/x86/xor) instruction kinds.
+pub trait Xor<T, U> {
+    /// Emit a xor instruction.
+    fn xor(&mut self, op1: T, op2: U);
+}
 
\ No newline at end of file diff --git a/src/juicebox_asm/insn/add.rs.html b/src/juicebox_asm/insn/add.rs.html index 6146498..e62bc4a 100644 --- a/src/juicebox_asm/insn/add.rs.html +++ b/src/juicebox_asm/insn/add.rs.html @@ -1,5 +1,5 @@ -add.rs - source -
1
+add.rs - source

juicebox_asm/insn/
add.rs

+1
 2
 3
 4
@@ -25,7 +25,18 @@
 24
 25
 26
-
use super::Add;
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
use super::Add;
 use crate::{Asm, Imm16, MemOp, Reg16, Reg32, Reg64};
 
 impl Add<Reg64, Reg64> for Asm {
@@ -40,6 +51,12 @@
     }
 }
 
+impl Add<MemOp, Reg64> for Asm {
+    fn add(&mut self, op1: MemOp, op2: Reg64) {
+        self.encode_mr(0x01, op1, op2);
+    }
+}
+
 impl Add<MemOp, Reg16> for Asm {
     fn add(&mut self, op1: MemOp, op2: Reg16) {
         self.encode_mr(0x01, op1, op2);
@@ -51,4 +68,10 @@
         self.encode_mi(0x81, 0, op1, op2);
     }
 }
+
+impl Add<Reg64, MemOp> for Asm {
+    fn add(&mut self, op1: Reg64, op2: MemOp) {
+        self.encode_rm(0x03, op1, op2);
+    }
+}
 
\ No newline at end of file diff --git a/src/juicebox_asm/insn/call.rs.html b/src/juicebox_asm/insn/call.rs.html index 3a70194..5f8ed48 100644 --- a/src/juicebox_asm/insn/call.rs.html +++ b/src/juicebox_asm/insn/call.rs.html @@ -1,13 +1,12 @@ -call.rs - source -
1
+call.rs - source

juicebox_asm/insn/
call.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use super::Call;
+8
use super::Call;
 use crate::{Asm, Reg64};
 
 impl Call<Reg64> for Asm {
diff --git a/src/juicebox_asm/insn/cmovnz.rs.html b/src/juicebox_asm/insn/cmovnz.rs.html
index 29bfb58..4e23126 100644
--- a/src/juicebox_asm/insn/cmovnz.rs.html
+++ b/src/juicebox_asm/insn/cmovnz.rs.html
@@ -1,13 +1,12 @@
-cmovnz.rs - source
-    
1
+cmovnz.rs - source

juicebox_asm/insn/
cmovnz.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use super::Cmovnz;
+8
use super::Cmovnz;
 use crate::{Asm, Reg64};
 
 impl Cmovnz<Reg64, Reg64> for Asm {
diff --git a/src/juicebox_asm/insn/cmovz.rs.html b/src/juicebox_asm/insn/cmovz.rs.html
index ecb62f1..a51f237 100644
--- a/src/juicebox_asm/insn/cmovz.rs.html
+++ b/src/juicebox_asm/insn/cmovz.rs.html
@@ -1,13 +1,12 @@
-cmovz.rs - source
-    
1
+cmovz.rs - source

juicebox_asm/insn/
cmovz.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use super::Cmovz;
+8
use super::Cmovz;
 use crate::{Asm, Reg64};
 
 impl Cmovz<Reg64, Reg64> for Asm {
diff --git a/src/juicebox_asm/insn/cmp.rs.html b/src/juicebox_asm/insn/cmp.rs.html
index c8bcee2..a4e5447 100644
--- a/src/juicebox_asm/insn/cmp.rs.html
+++ b/src/juicebox_asm/insn/cmp.rs.html
@@ -1,5 +1,5 @@
-cmp.rs - source
-    
1
+cmp.rs - source

juicebox_asm/insn/
cmp.rs

+1
 2
 3
 4
@@ -7,8 +7,19 @@
 6
 7
 8
-
use super::Cmp;
-use crate::{Asm, Imm16, MemOp};
+9
+10
+11
+12
+13
+14
use super::Cmp;
+use crate::{Asm, Imm16, Imm8, MemOp};
+
+impl Cmp<MemOp, Imm8> for Asm {
+    fn cmp(&mut self, op1: MemOp, op2: Imm8) {
+        self.encode_mi(0x80, 0x7, op1, op2);
+    }
+}
 
 impl Cmp<MemOp, Imm16> for Asm {
     fn cmp(&mut self, op1: MemOp, op2: Imm16) {
diff --git a/src/juicebox_asm/insn/dec.rs.html b/src/juicebox_asm/insn/dec.rs.html
index 1eed3b2..7a05154 100644
--- a/src/juicebox_asm/insn/dec.rs.html
+++ b/src/juicebox_asm/insn/dec.rs.html
@@ -1,5 +1,5 @@
-dec.rs - source
-    
1
+dec.rs - source

juicebox_asm/insn/
dec.rs

+1
 2
 3
 4
@@ -13,8 +13,31 @@
 12
 13
 14
-
use super::Dec;
-use crate::{Asm, Reg32, Reg64};
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
use super::Dec;
+use crate::{Asm, MemOp16, MemOp32, MemOp64, MemOp8, Reg32, Reg64};
 
 impl Dec<Reg64> for Asm {
     fn dec(&mut self, op1: Reg64) {
@@ -27,4 +50,28 @@
         self.encode_r(0xff, 1, op1);
     }
 }
+
+impl Dec<MemOp8> for Asm {
+    fn dec(&mut self, op1: MemOp8) {
+        self.encode_m(0xfe, 1, op1);
+    }
+}
+
+impl Dec<MemOp16> for Asm {
+    fn dec(&mut self, op1: MemOp16) {
+        self.encode_m(0xff, 1, op1);
+    }
+}
+
+impl Dec<MemOp32> for Asm {
+    fn dec(&mut self, op1: MemOp32) {
+        self.encode_m(0xff, 1, op1);
+    }
+}
+
+impl Dec<MemOp64> for Asm {
+    fn dec(&mut self, op1: MemOp64) {
+        self.encode_m(0xff, 1, op1);
+    }
+}
 
\ No newline at end of file diff --git a/src/juicebox_asm/insn/inc.rs.html b/src/juicebox_asm/insn/inc.rs.html new file mode 100644 index 0000000..05ce6bb --- /dev/null +++ b/src/juicebox_asm/insn/inc.rs.html @@ -0,0 +1,77 @@ +inc.rs - source

juicebox_asm/insn/
inc.rs

+1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
use super::Inc;
+use crate::{Asm, MemOp16, MemOp32, MemOp64, MemOp8, Reg32, Reg64};
+
+impl Inc<Reg64> for Asm {
+    fn inc(&mut self, op1: Reg64) {
+        self.encode_r(0xff, 0, op1);
+    }
+}
+
+impl Inc<Reg32> for Asm {
+    fn inc(&mut self, op1: Reg32) {
+        self.encode_r(0xff, 0, op1);
+    }
+}
+
+impl Inc<MemOp8> for Asm {
+    fn inc(&mut self, op1: MemOp8) {
+        self.encode_m(0xfe, 0, op1);
+    }
+}
+
+impl Inc<MemOp16> for Asm {
+    fn inc(&mut self, op1: MemOp16) {
+        self.encode_m(0xff, 0, op1);
+    }
+}
+
+impl Inc<MemOp32> for Asm {
+    fn inc(&mut self, op1: MemOp32) {
+        self.encode_m(0xff, 0, op1);
+    }
+}
+
+impl Inc<MemOp64> for Asm {
+    fn inc(&mut self, op1: MemOp64) {
+        self.encode_m(0xff, 0, op1);
+    }
+}
+
\ No newline at end of file diff --git a/src/juicebox_asm/insn/jmp.rs.html b/src/juicebox_asm/insn/jmp.rs.html index 88f3066..75b3912 100644 --- a/src/juicebox_asm/insn/jmp.rs.html +++ b/src/juicebox_asm/insn/jmp.rs.html @@ -1,13 +1,12 @@ -jmp.rs - source -
1
+jmp.rs - source

juicebox_asm/insn/
jmp.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use super::Jmp;
+8
use super::Jmp;
 use crate::{Asm, Label};
 
 impl Jmp<&mut Label> for Asm {
diff --git a/src/juicebox_asm/insn/jnz.rs.html b/src/juicebox_asm/insn/jnz.rs.html
index 40ae96c..14391d7 100644
--- a/src/juicebox_asm/insn/jnz.rs.html
+++ b/src/juicebox_asm/insn/jnz.rs.html
@@ -1,13 +1,12 @@
-jnz.rs - source
-    
1
+jnz.rs - source

juicebox_asm/insn/
jnz.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use super::Jnz;
+8
use super::Jnz;
 use crate::{Asm, Label};
 
 impl Jnz<&mut Label> for Asm {
diff --git a/src/juicebox_asm/insn/jz.rs.html b/src/juicebox_asm/insn/jz.rs.html
index 9a44a21..074c065 100644
--- a/src/juicebox_asm/insn/jz.rs.html
+++ b/src/juicebox_asm/insn/jz.rs.html
@@ -1,13 +1,12 @@
-jz.rs - source
-    
1
+jz.rs - source

juicebox_asm/insn/
jz.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use super::Jz;
+8
use super::Jz;
 use crate::{Asm, Label};
 
 impl Jz<&mut Label> for Asm {
diff --git a/src/juicebox_asm/insn/mov.rs.html b/src/juicebox_asm/insn/mov.rs.html
index 8f10e31..5bd4111 100644
--- a/src/juicebox_asm/insn/mov.rs.html
+++ b/src/juicebox_asm/insn/mov.rs.html
@@ -1,5 +1,5 @@
-mov.rs - source
-    
1
+mov.rs - source

juicebox_asm/insn/
mov.rs

+1
 2
 3
 4
@@ -112,8 +112,7 @@
 111
 112
 113
-114
-
use super::Mov;
+114
use super::Mov;
 use crate::{Asm, Imm16, Imm32, Imm64, Imm8, MemOp, Reg16, Reg32, Reg64, Reg8};
 
 // -- MOV : reg reg
diff --git a/src/juicebox_asm/insn/nop.rs.html b/src/juicebox_asm/insn/nop.rs.html
index 34afd35..ec71515 100644
--- a/src/juicebox_asm/insn/nop.rs.html
+++ b/src/juicebox_asm/insn/nop.rs.html
@@ -1,13 +1,12 @@
-nop.rs - source
-    
1
+nop.rs - source

juicebox_asm/insn/
nop.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use crate::Asm;
+8
use crate::Asm;
 
 impl Asm {
     /// Emit a [`nop`](https://www.felixcloutier.com/x86/nop) instruction.
diff --git a/src/juicebox_asm/insn/pop.rs.html b/src/juicebox_asm/insn/pop.rs.html
index 0852511..5b06e59 100644
--- a/src/juicebox_asm/insn/pop.rs.html
+++ b/src/juicebox_asm/insn/pop.rs.html
@@ -1,5 +1,5 @@
-pop.rs - source
-    
1
+pop.rs - source

juicebox_asm/insn/
pop.rs

+1
 2
 3
 4
@@ -12,8 +12,7 @@
 11
 12
 13
-14
-
use super::Pop;
+14
use super::Pop;
 use crate::{Asm, Reg16, Reg64};
 
 impl Pop<Reg64> for Asm {
diff --git a/src/juicebox_asm/insn/push.rs.html b/src/juicebox_asm/insn/push.rs.html
index e947e8b..636c6f6 100644
--- a/src/juicebox_asm/insn/push.rs.html
+++ b/src/juicebox_asm/insn/push.rs.html
@@ -1,5 +1,5 @@
-push.rs - source
-    
1
+push.rs - source

juicebox_asm/insn/
push.rs

+1
 2
 3
 4
@@ -12,8 +12,7 @@
 11
 12
 13
-14
-
use super::Push;
+14
use super::Push;
 use crate::{Asm, Reg16, Reg64};
 
 impl Push<Reg64> for Asm {
diff --git a/src/juicebox_asm/insn/ret.rs.html b/src/juicebox_asm/insn/ret.rs.html
index bc88856..b26e883 100644
--- a/src/juicebox_asm/insn/ret.rs.html
+++ b/src/juicebox_asm/insn/ret.rs.html
@@ -1,13 +1,12 @@
-ret.rs - source
-    
1
+ret.rs - source

juicebox_asm/insn/
ret.rs

+1
 2
 3
 4
 5
 6
 7
-8
-
use crate::Asm;
+8
use crate::Asm;
 
 impl Asm {
     /// Emit a [`ret`](https://www.felixcloutier.com/x86/ret) instruction.
diff --git a/src/juicebox_asm/insn/test.rs.html b/src/juicebox_asm/insn/test.rs.html
index 53a4e39..4c9bd7d 100644
--- a/src/juicebox_asm/insn/test.rs.html
+++ b/src/juicebox_asm/insn/test.rs.html
@@ -1,5 +1,5 @@
-test.rs - source
-    
1
+test.rs - source

juicebox_asm/insn/
test.rs

+1
 2
 3
 4
@@ -18,8 +18,7 @@
 17
 18
 19
-20
-
use super::Test;
+20
use super::Test;
 use crate::{Asm, Imm16, MemOp, Reg32, Reg64};
 
 impl Test<Reg64, Reg64> for Asm {
diff --git a/src/juicebox_asm/insn/xor.rs.html b/src/juicebox_asm/insn/xor.rs.html
new file mode 100644
index 0000000..2bd3dc8
--- /dev/null
+++ b/src/juicebox_asm/insn/xor.rs.html
@@ -0,0 +1,17 @@
+xor.rs - source

juicebox_asm/insn/
xor.rs

+1
+2
+3
+4
+5
+6
+7
+8
use super::Xor;
+use crate::{Asm, Reg64};
+
+impl Xor<Reg64, Reg64> for Asm {
+    fn xor(&mut self, op1: Reg64, op2: Reg64) {
+        self.encode_rr(&[0x31], op1, op2);
+    }
+}
+
\ No newline at end of file diff --git a/src/juicebox_asm/label.rs.html b/src/juicebox_asm/label.rs.html index d986d64..d46d49a 100644 --- a/src/juicebox_asm/label.rs.html +++ b/src/juicebox_asm/label.rs.html @@ -1,5 +1,5 @@ -label.rs - source -
1
+label.rs - source

juicebox_asm/
label.rs

+1
 2
 3
 4
@@ -81,8 +81,7 @@
 80
 81
 82
-83
-
//! Definition of the lable type which can be used as jump target and can be bound to a location in
+83
//! Definition of the lable type which can be used as jump target and can be bound to a location in
 //! the emitted code.
 
 use std::collections::HashSet;
diff --git a/src/juicebox_asm/lib.rs.html b/src/juicebox_asm/lib.rs.html
index d7d33f1..2b9ed8a 100644
--- a/src/juicebox_asm/lib.rs.html
+++ b/src/juicebox_asm/lib.rs.html
@@ -1,5 +1,5 @@
-lib.rs - source
-    
1
+lib.rs - source

juicebox_asm/
lib.rs

+1
 2
 3
 4
@@ -106,7 +106,63 @@
 105
 106
 107
-
//! A simple `x64` jit assembler with a minimal runtime to execute emitted code for fun.
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
//! A simple `x64` jit assembler with a minimal runtime to execute emitted code for fun.
 //!
 //! The following is an fibonacci example implementation.
 //! ```rust
@@ -196,12 +252,16 @@
 pub use rt::Runtime;
 
 /// Type representing a memory operand.
+#[derive(Clone, Copy)]
 pub enum MemOp {
     /// An indirect memory operand, eg `mov [rax], rcx`.
     Indirect(Reg64),
 
     /// An indirect memory operand with additional displacement, eg `mov [rax + 0x10], rcx`.
     IndirectDisp(Reg64, i32),
+
+    /// An indirect memory operand in the form base + index, eg `mov [rax + rcx], rdx`.
+    IndirectBaseIndex(Reg64, Reg64),
 }
 
 impl MemOp {
@@ -210,7 +270,60 @@
         match self {
             MemOp::Indirect(base) => *base,
             MemOp::IndirectDisp(base, ..) => *base,
+            MemOp::IndirectBaseIndex(base, ..) => *base,
+        }
+    }
+
+    /// Get the index register of the memory operand.
+    fn index(&self) -> Reg64 {
+        // Return zero index register for memory operands w/o index register.
+        let zero_index = Reg64::rax;
+        use reg::Reg;
+        assert_eq!(zero_index.idx(), 0);
+
+        match self {
+            MemOp::Indirect(..) => zero_index,
+            MemOp::IndirectDisp(..) => zero_index,
+            MemOp::IndirectBaseIndex(.., index) => *index,
         }
     }
 }
+
+/// Trait to give size hints for memory operands.
+trait MemOpSized {
+    fn mem_op(&self) -> MemOp;
+}
+
+macro_rules! impl_memop_sized {
+    ($(#[$doc:meta] $name:ident)+) => {
+        $(
+        #[$doc]
+        pub struct $name(MemOp);
+
+        impl $name {
+            /// Create a memory with size hint from a raw memory operand.
+            pub fn from(op: MemOp) -> Self {
+                Self(op)
+            }
+        }
+
+        impl MemOpSized for $name {
+            fn mem_op(&self) -> MemOp {
+                self.0
+            }
+        }
+        )+
+    };
+}
+
+impl_memop_sized!(
+    /// A memory operand with a word (8 bit) size hint.
+    MemOp8
+    /// A memory operand with a word (16 bit) size hint.
+    MemOp16
+    /// A memory operand with a dword (32 bit) size hint.
+    MemOp32
+    /// A memory operand with a qword (64 bit) size hint.
+    MemOp64
+);
 
\ No newline at end of file diff --git a/src/juicebox_asm/reg.rs.html b/src/juicebox_asm/reg.rs.html index f0612f6..edbf390 100644 --- a/src/juicebox_asm/reg.rs.html +++ b/src/juicebox_asm/reg.rs.html @@ -1,5 +1,5 @@ -reg.rs - source -
1
+reg.rs - source

juicebox_asm/
reg.rs

+1
 2
 3
 4
@@ -302,8 +302,7 @@
 301
 302
 303
-304
-
//! Definition of registers which are used as input operands for various instructions.
+304
//! Definition of registers which are used as input operands for various instructions.
 
 /// Trait to interact with register operands.
 pub(crate) trait Reg {
@@ -342,7 +341,7 @@
     }
 }
 
-macro_rules! enum_reg {
+macro_rules! enum_reg {
     (#[$doc:meta]  $name:ident, { $($reg:ident),+ $(,)? }) => {
         #[$doc]
         #[allow(non_camel_case_types)]
@@ -362,7 +361,7 @@
     };
 }
 
-macro_rules! impl_reg {
+macro_rules! impl_reg {
     (#[$doc:meta] $name:ident, $rexw:expr, { $($reg:ident),+ $(,)? }) => {
         enum_reg!(#[$doc] $name, { $( $reg, )+ });
 
diff --git a/src/juicebox_asm/rt.rs.html b/src/juicebox_asm/rt.rs.html
index eecdd6f..039fa77 100644
--- a/src/juicebox_asm/rt.rs.html
+++ b/src/juicebox_asm/rt.rs.html
@@ -1,5 +1,5 @@
-rt.rs - source
-    
1
+rt.rs - source

juicebox_asm/
rt.rs

+1
 2
 3
 4
@@ -267,8 +267,7 @@
 266
 267
 268
-269
-
//! Simple `mmap`ed runtime.
+269
//! Simple `mmap`ed runtime.
 //!
 //! This runtime supports adding code to executable pages and turn the added code into user
 //! specified function pointer.
diff --git a/src/tiny_vm/tiny_vm.rs.html b/src/tiny_vm/tiny_vm.rs.html
index e8937f6..13c5a44 100644
--- a/src/tiny_vm/tiny_vm.rs.html
+++ b/src/tiny_vm/tiny_vm.rs.html
@@ -1,5 +1,5 @@
-tiny_vm.rs - source
-    
1
+tiny_vm.rs - source

tiny_vm/
tiny_vm.rs

+1
 2
 3
 4
@@ -703,8 +703,7 @@
 702
 703
 704
-705
-
//! TinyVm example.
+705
//! TinyVm example.
 //!
 //! 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
-- 
cgit v1.2.3