Welcome! This project provides a custom Rust compiler backend (rustc_codegen_jvm
) that compiles Rust code into Java Virtual Machine (JVM) bytecode. This allows Rust programs to run on the JVM. Currently, the generated bytecode supports JVM 8 and later versions.
The toolchain transforms Rust code into executable .jar
files through several stages:
-
Rustc Frontend (Parsing & MIR Generation)
- Your Rust code is parsed and lowered to Mid-level Intermediate Representation (MIR) by the standard
rustc
frontend.
- Your Rust code is parsed and lowered to Mid-level Intermediate Representation (MIR) by the standard
-
MIR to OOMIR (Object-Oriented MIR)
- The MIR is lowered further into a custom intermediate representation called OOMIR. This step simplifies MIR constructs into a representation closer to object-oriented concepts, making the translation to JVM bytecode more manageable. (See
src/lower1.rs
).
- The MIR is lowered further into a custom intermediate representation called OOMIR. This step simplifies MIR constructs into a representation closer to object-oriented concepts, making the translation to JVM bytecode more manageable. (See
-
OOMIR to JVM Classfile
- The OOMIR is then translated into standard Java
.class
files containing JVM bytecode. This is the core task of therustc_codegen_jvm
library in this repository (Seesrc/lower2.rs
). It utilizes theristretto_classfile
library for bytecode generation.
- The OOMIR is then translated into standard Java
-
Classfile Post-Processing (Stack Map Frames)
- The generated
.class
files are processed by a dedicated tool (asm-processor
, written in Kotlin using the ASM library). This tool calculates and inserts Stack Map Frames, which are required for class verification in modern JVM versions (Java 7+).
- The generated
-
Linking &
.jar
Generation- Finally, the processed
.class
files for the crate and its dependencies (though dependency handling is currently basic) are linked together into a single executable.jar
file. This step is handled byjava-linker
, a custom linker built as part of this project (Seejava-linker/
). It also generates the necessaryMETA-INF/MANIFEST.MF
file, marking the main class if applicable.
- Finally, the processed
This backend currently supports a subset of Rust features:
- ✅ Compiling minimal
no_std
&no_core
Rust programs (like an emptymain
) using thejvm-unknown-unknown
target. - ✅ Compiling simple programs using basic
core
features (like theis_even_plus_one
test) using the host target. - ✅ Basic integer arithmetic operations on all types of numbers:
- Addition (
+
), Subtraction (-
), Multiplication (*
), Division (/
), Remainder (%
). - Checked addition and subtraction (
checked_add
,checked_sub
) returning(result, overflowed_bool)
tuples.
- Addition (
- ✅ Comparisons (
==
,!=
,<
,<=
,>
,>=
). - ✅ Bitwise operations (
&
,|
,^
,<<
,>>
). - ✅ Basic control flow:
if
/else
statements,panic!
/assert!
(including multiple arguments and formatting ({}
) of most rust primitives) - ✅ Calling other
static
functions within the same crate (including recursion). - ✅ Basic variable assignment (
let x = y;
). - ✅ Arrays and slices.
- ✅ Floats (
f32
,f64
). - ✅ Generating executable
.jar
files for binary crates.
🚧 Full support for the core
crate is the next major goal.
- Rust Nightly: Ensure you are using the latest nightly Rust toolchain. You can set this up with
rustup default nightly
. Some rust components are needed but will be automatically installed by the Makefile. - Java Development Kit (JDK): A working JDK (version 8 or later recommended) is required to run the generated
.jar
files and theasm-processor
. Make surejava
is in your PATH. - Gradle: Required to build the
asm-processor
Kotlin project. Make suregradle
is in your PATH. - Python 3: Required to run the integration tests and generate files from templates. Make sure
python3
is in your PATH.
- Build All Components:
- You can use the provided Makefile or build script:
# Using Make make all
- This will:
- Build the main
rustc_codegen_jvm
library (target/debug/librustc_codegen_jvm.[dll/dylib/so]
). - Build the
java-linker
(java-linker/target/debug/java-linker
). - Build the
asm-processor
(asm-processor/build/libs/asm-processor-*.jar
). - Build the Kotlin shim of the Rust core library (
library
). - Generate the
config.toml
andjvm-unknown-unknown.json
files from their templates.
- Build the main
To compile your own Rust project using this backend:
-
Get the Toolchain: Clone this repository and build it as described above. Ensure you build the toolchain first, as described in the previous section, by running
make all
. You will need to re-runmake gen-files
if you change the absolute path of where this repository is stored since building. -
Configure Your Rust Project:
- In your own Rust project's directory, create a
.cargo/config.toml
file (if it doesn't exist). - Copy the contents from the
config.toml
file generated specifically for your system, that can be found in the root of this project after runningmake all
. If since running make, you've moved this repo to a different directory, you'll need to run at leastmake gen-files
.
- In your own Rust project's directory, create a
-
Build Your Project:
- Run the standard Cargo build command, targeting the host target (using the
jvm-unknown-unknown
target is an emerging feature and means you can't even usecore
, for now, so not recommended). Cargo will read the.cargo/config.toml
and use the specified target and flags automatically.
cargo build # Or for release builds: # cargo build --release
- Run the standard Cargo build command, targeting the host target (using the
-
Find & Run the Generated
.jar
:- The compiled
.jar
file will be located in your project'starget
directory:- Debug:
target/debug/deps/[your_crate_name].jar
- Release:
target/release/deps/[your_crate_name].jar
- Debug:
- If your crate is a binary (
[[bin]]
orsrc/main.rs
), run it using thejava
command:java -jar target/jvm-unknown-unknown/debug/[your_crate_name].jar
- The compiled
This project includes integration tests managed by a Python script.
- Ensure Toolchain is Built: Build the project using
make all
. If you've changed the path of the repository, runmake gen-files
to regenerate the configuration files. - Run the Tester:
python3 Tester.py # For release mode tests: # python3 Tester.py --release
- Check Output: Look for the final "✅ All tests passed!" message. If tests fail, the script will generate
.generated
files in the respective test directories (tests/binary/*
) containing error details or output diffs.
src/
: Contains the source code for therustc_codegen_jvm
backend library.lib.rs
: Main backend integration point.lower1.rs
: MIR to OOMIR lowering pass.lower2.rs
: OOMIR to JVM bytecode generation pass.oomir.rs
: Definition of the Object-Oriented MIR (OOMIR).
java-linker/
: Source code for the custom linker that creates.jar
filesn from the generated.class
files.asm-processor/
: Kotlin/Gradle project for the ASM-based bytecode post-processor that adds stack map frames to the generated.class
files.tests/
: Integration tests.binary/
: Tests for compiling executable Rust crates.
library/
: Source code for a minimal Kotlin-based implementation of the Rust core library. This serves as a temporary substitute to bootstrap the project until the backend can fully compile the Rust core library itself.shim-metadata-gen
: A tool for generating metadata for the Kotlin core library, called at compiletime to provide nessecary info (descriptors) to the codegen backend. It's generated metadata is embedded in the generated library, so not needed at runtime.core.json
: Metadata for the core library, generated by this tool.
jvm-unknown-unknown.json.template
: The template for Rust target specification file (currently experimental & not recommended, useconfig.toml
in your project instead).config.toml.template
: The template for the Cargo configuration file for the toolchain.Tester.py
: Python script for running integration tests.GenerateFiles.py
: Python script for generating theconfig.toml
file and thejvm-unknown-unknown.json
file from their templates, making them suited to your system.Makefile
Scripts for building the entire toolchain.setup.sh
: Script to install Rust components.Cargo.toml
,Cargo.lock
: Rust package definition and dependencies for the backend.LICENSE
,LICENSE-Apache
: Project licenses.
Contributions are welcome! Feel free to open issues or pull requests.
This project is dual-licensed under either of:
- MIT License (LICENSE-MIT or http://opensource.org/licenses/MIT)
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.