| Crates.io | fucker |
| lib.rs | fucker |
| version | 0.6.1 |
| created_at | 2020-07-03 00:31:03.544+00 |
| updated_at | 2025-06-09 03:34:39.120408+00 |
| description | BrainFuck interpreter and optimizing JIT compiler |
| homepage | https://github.com/danthedaniel/BF-JIT |
| repository | https://github.com/danthedaniel/BF-JIT |
| max_upload_size | |
| id | 260819 |
| size | 115,207 |
A very over-engineered BrainFuck interpreter/optimizing JIT compiler written in rust. Done from first-principles without any research or examination of prior art*.
*Update:
The aarch64 implementation in src/runnable/jit/code_gen/aarch64.rs was written
almost entirely by Claude 4 Opus.
fucker [--int] <program>
fucker (-d | --debug) <program>
fucker (-h | --help)
Options:
-h --help Show this screen.
-d --debug Display intermediate language.
--int Use an interpreter instead of the JIT compiler.
BrainFuck is an esoteric programming language designed to be both turing complete and easy to compile. The environment provides the programmer with an a 30,000 cell array of unsigned bytes and a data pointer. There are only 8 single character commands:
+ : Increment the current memory cell by 1 (with wrapping overflow)- : Decrement the current memory cell by 1 (with wrapping underflow)> : Shift the data pointer to the next memory cell< : Shift the data pointer to the previous memory cell. : Output the current memory cell as an ASCII character, : Read one ASCII character from stdin[ : Jump to the matching ] if the current memory cell is 0] : Jump to the matching [ if the current memory cell is not 0The compiler first parses BrainFuck source code into an Abstract Syntax Tree (AST) representation. This intermediate representation enables optimizations before execution:
#[derive(Debug, Clone, PartialEq)]
pub enum AstNode {
Incr(u8), // Add to current cell
Decr(u8), // Subtract from current cell
Next(usize), // Move data pointer right
Prev(usize), // Move data pointer left
Print, // Output current cell as ASCII
Read, // Read ASCII input to current cell
Set(u8), // Set current cell to literal value
AddTo(isize), // Add current cell to offset cell, zero current
SubFrom(isize),// Subtract current cell from offset cell, zero current
MultiplyAddTo(isize, u8), // Multiply current cell and add to cell at offset, zero current
CopyTo(Vec<isize>), // Copy current cell to multiple offsets, zero current
Loop(VecDeque<AstNode>), // Loop while current cell != 0
}
The compiler implements several optimization passes during AST construction:
Sequential identical operations are combined into single instructions with counts:
++++ becomes Incr(4)>>>> becomes Next(4)---- becomes Decr(4)<<<< becomes Prev(4)This optimization alone provides an approximately 3x speedup on typical BrainFuck programs.
Common BrainFuck idioms are detected and replaced with optimized operations:
Zero loops: [-] or [+] → Set(0)
Move loops: [-<+>] → AddTo(-1)
AddTo) and subtraction (SubFrom) variantsOperations on literal values are computed at compile time:
Set(5) followed by Incr(3) becomes Set(8)The compiler supports two execution modes:
A traditional bytecode interpreter that executes the optimized AST directly. This provides:
The interpreter uses a simple virtual machine with:
A Just-In-Time compiler that generates native machine code for maximum performance.
Supported Architectures:
JIT Compilation Strategy: The JIT uses a hybrid approach combining Ahead-of-Time (AOT) and Just-in-Time compilation:
Code Generation:
r10/x19: Data pointer registerr11/x20: JIT context pointerr12/x21: Virtual function table pointerAssembly Code Examples:
The JIT compiler generates native assembly for each BrainFuck operation:
Increment (++++ → Incr(4)):
; x86-64
add BYTE PTR [r10], 4
; AArch64
ldrb w8, [x19]
add w8, w8, #4
strb w8, [x19]
Pointer movement (>>>> → Next(4)):
; x86-64
add r10, 4
; AArch64
add x19, x19, #4
Cell zeroing ([-] → Set(0)):
; x86-64
mov BYTE PTR [r10], 0
; AArch64
mov w8, #0
strb w8, [x19]
Move operation ([-<+>] → AddTo(-1)):
; x86-64
movzx eax, BYTE PTR [r10] ; Load current cell
add BYTE PTR [r10-1], al ; Add to target cell
mov BYTE PTR [r10], 0 ; Zero current cell
; AArch64
ldrb w8, [x19] ; Load current cell
ldrb w9, [x19, #-1] ; Load target cell
add w9, w9, w8 ; Add values
strb w9, [x19, #-1] ; Store to target
mov w8, #0 ; Zero current cell
strb w8, [x19]
Memory Management:
Loops are the most complex aspect of BrainFuck compilation:
Jump Resolution:
[) use conditional branches that skip the loop body]) use conditional branches that return to loop startBoth backends use an I/O system supporting:
The JIT compiler implements I/O through a virtual function table, allowing:
Ran on mandelbrot.bf.
| Version | Runtime |
|---|---|
| Naive Interpreter | 56.824s |
| Optimized Interpreter | 19.055s |
| Optimized JIT | 1.06s |
| Version | Runtime |
|---|---|
| Optimized Interpreter | 8.18s |
| Optimized JIT | 0.39s |