Skip to content

IntegralPilot/rustc_codegen_jvm

Repository files navigation

rustc_codegen_jvm

A custom Rust compiler backend that compiles Rust directly to Java Virtual Machine (JVM) bytecode.

License: MIT/Apache-2.0 CI Rust: Nightly

Compile your Rust code into a self-contained, runnable .jar compatible with JVM 8+. By transparently mapping Rust constructs onto Java classes and interfaces, this backend bridges the safety and ergonomics of Rust with the reach of the JVM.

Why use this?

  • Fast iteration
    • 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.
  • Interop without the boilerplate
    • 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. For example, a Java class can implement a Rust trait and be passed directly into Rust code as a &dyn Trait object and no bindings layer is required.
  • Run anywhere a JVM runs
    • Because the output is standard bytecode rather than a native binary, your Rust code can target environments where native FFI is difficult or unavailable, including sandboxed environments like Minecraft mod loaders and Android (if you convert to DEX files).
  • Sandboxed by construction
    • Native code loaded via JNI can crash the entire JVM on a bad memory access. Rust compiled to JVM bytecode is checked by the JVM's own bytecode verifier, so those failures stay within the managed runtime. 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.

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.

I am so grateful for any stars and support!

Table of Contents

  1. Demos
  2. Features
  3. How It Works
  4. Interop Model
  5. Target Platforms
  6. Prerequisites
  7. Installation & Build
  8. Usage
  9. Running Tests
  10. Project Structure
  11. Contributing
  12. License

Demos

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

Features

Compiler optimisations

  • Constant folding & propagation
    • Evaluates constant expressions and known values at compile time.
  • Dead code elimination
    • Strips unreachable paths for clean, efficient bytecode.
  • Algebraic simplification
    • Reduces expressions using algebraic identities.

Rust Language Support

  • Control flow
    • if/else, match, for, while, and loop.
  • Data structures
    • arrays, slices, structs, tuples, and enums (both C-like and Rust-style).
  • Functions & closures
    • calls, recursion, function pointers (as values, parameters, return types, and in generics), and closure capture.
  • OOP constructs
    • impl blocks for ADTs, including self, &self, and &mut self.
  • Traits
    • dynamic dispatch via &dyn Trait.
  • Memory management
    • mutable borrowing, references, and dereferencing.
  • Unions
    • supported for primitive types (bool, i8f64) and structs composed of them.
  • Output
    • executable, self-contained .jar generation for binary crates.
  • Testing
    • integration coverage across debug and release modes for all of the above.

Current milestone: full support for the Rust core crate.

How It Works

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
Loading
  1. rustc frontend parses and type-checks your code, lowering it to Mid-level IR (MIR).
  2. lower1 generates a custom "Object-Oriented MIR" (OOMIR) by reshaping MIR into constructs closer to the JVM's object model.
  3. optimise1 applies constant folding, constant propagation, dead code elimination, and algebraic simplification.
  4. lower2 translates OOMIR into .class files via ristretto_classfile, including stack map frame generation.
  5. java-linker bundles the .class files with a small runtime shim into a self-contained, runnable .jar with an appropriate META-INF/MANIFEST.MF.

Interop Model

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.

Target Platforms

Because output is standard JVM bytecode rather than a native binary, rustc_codegen_jvm targets environments where native compilation isn't practical or allowed:

  • Any JVM 8+, including older or constrained runtimes without modern FFI features.
  • Android, by routing the .class output through an external DEX conversion pipeline.
  • Sandboxed or embedded JVM environments, such as Minecraft mod loaders, where loading native libraries is restricted or undesirable.

Prerequisites

  • Rust Nightly - rustup default nightly
  • JDK 8+ - java, javac, and jar must be on PATH
  • Python 3 - python3 must be on PATH

Installation & Build

Clone 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:

  • The Java library shim (library/)
  • The shim metadata file (core.json)
  • The java-linker executable
  • The rustc_codegen_jvm backend library
  • Configuration files (config.toml, jvm-unknown-unknown.json)

build.py checks file timestamps on subsequent runs, so only modified components are rebuilt.

Usage

  1. Configure your project In your target Rust project, create or update .cargo/config.toml using the template provided in the root of this repository. Your Cargo.toml must also enable per-profile compilation flags:

    cargo-features = ["profile-rustflags"]
  2. Build with Cargo

    cargo build           # Debug build
    cargo build --release # Optimised build
  3. Run the generated JAR

    java -jar target/debug/deps/your_crate*.jar   # Debug build
    java -jar target/release/deps/your_crate*.jar # Release build

Running Tests

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.

Project structure

.
├── 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

Contributing

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.

License

This project is dual-licensed under your choice of:

About

Toolchain to create JVM-ready Java bytecode from Rust MIR.

Resources

License

MIT, Apache-2.0 licenses found

Licenses found

MIT
LICENSE
Apache-2.0
LICENSE-Apache

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors