A custom Rust compiler backend that compiles Rust directly to Java Virtual Machine (JVM) bytecode.
Compile your Rust code into a self-contained, runnable .jar compatible with JVM 8+. This backend transparently compiles Rust constructs to Java classes and interfaces, enabling rich interop between JVM and Rust code at a level mostly unreachable by FFI solutions.
Looking ahead, it is envisioned that with further work this backend could benefit any Rust project, not just those requiring JVM integration. In future, by leveraging this backend and the JVM's robust debugging tools and hot-swapping capabilities, Rust developers could iterate quickly during local development to avoid the compile-time bottlenecks of the native toolchain, before compiling to a native binary for release.
It should be noted that this project is still in early development, but is supporting more of the Rust language as time goes on! The eventual goal is a potential upstreaming with main rustc, though that is definently a while away!
I am so grateful for any stars and support!
Rust enums, generics, function pointers, unions and other supported constructs map directly onto JVM classes and interfaces (see Interop Model). Because of this, rustc_codegen_jvm can achieve a level of ergonomic interop with Java that comparable native solutions can't easily. For example, you can make a Java class that implements a Rust trait and pass it as a &dyn Trait object to Rust functions, because traits just become normal Java interfaces, where this would be (to my knowledge) quite hard, with bridge and FFI solutions.
Fresh compilation for most small test crates takes under 1 second, making the backend practical for rapid experimentation compared to native compilation. Due to the rich hot reload and debugging ecosystem of the JVM, my vision is that this project can in future make rapidly iterating on Rust code (which is a known drawback of Rust) fast and enjoyable. Though there is still lots of work to be done on both making this compiler faster, and making it easy for Rust code to tap into that ecosystem!
Because the output is standard bytecode rather than a native binary, your Rust code can target environments where native FFI solutions like Panama are difficult or unavailable, including sandboxed environments like Minecraft mod loaders and Android (if you convert to DEX files).
Future visions for the project include it being able to help you leverage the JVM's safety to debug undefined behaviour, like Miri but faster because of the JVM's JIT.
These examples live in tests/binary, are compiled to JVM bytecode, and are verified on every CI run as part of the integration test suite. Most small examples cold-compile and run in under 1 second - verify it yourself with Instrument.py.
| Example | Demonstrates |
|---|---|
| RSA | Encryption / decryption |
| Binary search | Classic search algorithm |
| Fibonacci | Recursive sequence generation |
| Collatz conjecture | Iterative mathematical verification |
| Large prime generator | Numeric computation at scale |
| Enums / Structs | Nested data structures - tuples, arrays, slices |
| Impl blocks / Traits | Trait implementations, including dynamic dispatch |
| Function pointers | Function pointers as values, fields, parameters, returns, and generic members |
| Unions | unsafe union handling, running on the JVM |
if/else, match, for, while, and loop.impl blocks for ADTs, including self, &self, and &mut self.&dyn Trait.bool, i8–f64) and structs composed of them..jar generation for binary crates.Current milestone: full support for the Rust core crate.
graph TD
A[Rust Source Code] -->|rustc frontend| B(MIR)
B -->|lower1| C(OOMIR)
C -->|optimise1| D(Optimised OOMIR)
D -->|lower2| E[JVM .class files]
E -->|java-linker| F[Executable .jar]
style A fill:#f9d0c4,stroke:#333,stroke-width:2px
style C fill:#d4e6f1,stroke:#333,stroke-width:2px
style F fill:#d5f5e3,stroke:#333,stroke-width:2px
rustc frontend parses and type-checks your code, lowering it to Mid-level IR (MIR)..class files via ristretto_classfile, including stack map frame generation..class files with a small runtime shim into a self-contained, runnable .jar with an appropriate META-INF/MANIFEST.MF.Rust types map onto the JVM's class model directly, which is what makes interop feel native from both sides:
| Rust construct | JVM representation |
|---|---|
struct |
A standard JVM class, with fields and methods generated 1:1 |
enum |
An abstract parent class with an abstract getVariantIdx, and one concrete subclass per variant |
union |
A JVM class over the union's shared memory layout |
trait |
A Java interface - any type implementing the trait implements the interface |
fn(A, B) -> R |
A generated single-method Java interface for that signature, with adapter classes for Rust function definitions |
impl methods (self, &self, &mut self) |
Instance methods on the generated class |
&dyn Trait |
The generated Java interface type, usable as a normal Java argument or return type |
For supported constructs, there is no manual marshalling and no bindings layer to maintain, unlike JNI or Project Panama.
The generated classfiles also carry extra metadata so that IDEs like IntelliJ IDEA offer autocomplete, tooltips, and refactoring support for Rust-defined types directly from Java.
Because output is standard JVM bytecode rather than a native binary, rustc_codegen_jvm targets environments where native compilation isn't practical or allowed:
.class output through an external DEX conversion pipeline.rustup default nightlyjava, javac, and jar must be on PATHpython3 must be on PATHClone the repository and build all components with the provided build script:
git clone https://github.com/IntegralPilot/rustc_codegen_jvm.git
cd rustc_codegen_jvm
# On Linux or macOS:
./build.py all
# On Windows:
python build.py all
This builds the following, in dependency order:
library/)core.json)java-linker executablerustc_codegen_jvm backend libraryconfig.toml, jvm-unknown-unknown.json)build.py checks file timestamps on subsequent runs, so only modified components are rebuilt.
.cargo/config.toml using the template provided in the root of this repository. Your Cargo.toml must also enable per-profile compilation flags:toml
cargo-features = ["profile-rustflags"]
bash
cargo build # Debug build
cargo build --release # Optimised build
bash
java -jar target/debug/deps/your_crate*.jar # Debug build
java -jar target/release/deps/your_crate*.jar # Release build
Ensure the toolchain is built first:
# On Linux/macOS:
./build.py all
# On Windows:
python build.py all
Then run the test suite:
python Tester.py # Debug mode
python Tester.py --release # Release mode
Results are printed to the console, and temporary test artifacts are written to .generated/ for inspection. The runner defaults to your local CPU core count; override it with -j / --jobs.
.
├── src/ # rustc_codegen_jvm compiler backend
│ ├── lib.rs
│ ├── lower1/ # MIR -> OOMIR conversion
│ ├── optimise1/ # OOMIR optimiser
│ ├── lower2/ # OOMIR -> JVM bytecode translation
│ └── oomir.rs # OOMIR data definitions
├── java-linker/ # Bundles compiled .class files into .jar archives
├── tests/binary/ # Integration tests and example source crates
├── library/ # Java shim implementation for the Rust core library
├── shim-metadata-gen/ # Tool to generate core.json metadata
├── build.py # Orchestrator build script
├── config.toml.template # Cargo configuration template
├── jvm-unknown-unknown.json.template
├── Tester.py # Automated test runner
└── LICENSE, LICENSE-Apache
Issues and pull requests are welcome and would be greatly appreciated!
If you'd like to get involved but aren't sure where to start, open a thread on the Discussions page - I am happy to help scope out a task list. For larger changes, opening an issue first to discuss the approach is appreciated.
This project is dual-licensed under your choice of:
$ claude mcp add rustc_codegen_jvm \
-- python -m otcore.mcp_server <graph>