Skip to content

Commit 361dc51

Browse files
committed
new README
1 parent 78b2ea8 commit 361dc51

File tree

1 file changed

+155
-68
lines changed

1 file changed

+155
-68
lines changed

Readme.md

Lines changed: 155 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,155 @@
1-
# Rust → JVM Toolchain 🚀
2-
3-
Welcome! This project provides a toolchain for compiling Rust code into Java bytecode, allowing it to run on the JVM.
4-
5-
## How It Works
6-
7-
The toolchain follows these steps:
8-
9-
1. **Parsing & MIR Generation**
10-
- Rust code is first parsed and converted into *MIR* (Mid-level Intermediate Representation) using `rustc`.
11-
12-
2. **MIR to Java Bytecode**
13-
- The MIR for each crate is translated into a Java Classfile (containing JVM bytecode) via `rustc_codegen_jvm`, which is the core of this repository.
14-
- Source code for this component is located in the `src` folder.
15-
16-
3. **Linking & `.jar` Generation**
17-
- Java Classfiles for all crates used in a library or executable are linked into a single `.jar` file, making it ready to run on the JVM.
18-
- This step is handled by `java-linker-rs`, a custom-built linker in this repository (found in the `java-linker` folder).
19-
20-
## Current Capabilities
21-
22-
- ✅ Compiling a minimal `no_std` & `no_core` Rust program with an empty `main` function.
23-
- ✅ Simple mathematical operations on `i32`s: addition, subtraction, mutliplication, division, modulo.
24-
- ✅ Calling other functions from the same library (including recursion).
25-
- ✅ if/else statements.
26-
27-
### Next Milestone:
28-
🚧 **Full support for the `core` crate** is in progress!
29-
30-
## How to Use the Toolchain
31-
32-
### Prerequisites
33-
- Ensure you're on the **latest nightly build** of Rust.
34-
- Install necessary Rust components:
35-
```sh
36-
rustup component add rust-src rustc-dev llvm-tools-preview
37-
```
38-
- Run the setup script:
39-
```sh
40-
chmod +x setup.sh && ./setup.sh
41-
```
42-
43-
### Compiling Rust to JVM Bytecode
44-
To use the toolchain for compiling your Rust project:
45-
```
46-
1. **Update the Target JSON**
47-
- Modify `jvm-unknown-unknown.json`, replacing the `../../..` (relative path to the project root from a test folder) part of the `linker` and `default-codegen-backend` lines to the absolute or relative path of where you cloned this repo.
48-
2. **Build Your Project**
49-
```sh
50-
cargo build --target /path/to/rustc_codegen_jvm/jvm-unknown-unknown.json
51-
```
52-
3. **Find & Run the Generated `.jar`**
53-
- The compiled `.jar` file will be in:
54-
```
55-
target/jvm-unknown-unknown/debug/[cratename].jar
56-
```
57-
- If it's a binary (not a library), run it using:
58-
```sh
59-
java -jar target/jvm-unknown-unknown/debug/[cratename].jar
60-
```
61-
62-
### Running Tests
63-
- If you modified the target JSON file, **revert the changes** before running tests.
64-
- Execute the test script:
65-
```sh
66-
python3 Tester.py
67-
```
68-
- Look for a **success message** 🎉
1+
# Rustc Codegen JVM 🚀
2+
3+
[![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](https://opensource.org/licenses/MIT)
4+
5+
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 JRE 8 and later versions.
6+
7+
## How It Works
8+
9+
The toolchain transforms Rust code into executable `.jar` files through several stages:
10+
11+
1. **Rustc Frontend (Parsing & MIR Generation)**
12+
* Your Rust code is parsed and lowered to *Mid-level Intermediate Representation (MIR)* by the standard `rustc` frontend.
13+
14+
2. **MIR to OOMIR (Object-Oriented MIR)**
15+
* 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`).
16+
17+
3. **OOMIR to JVM Classfile**
18+
* The OOMIR is then translated into standard Java `.class` files containing JVM bytecode. This is the core task of the `rustc_codegen_jvm` library in this repository (See `src/lower2.rs`). It utilizes the `ristretto_classfile` library for bytecode generation.
19+
20+
4. **Classfile Post-Processing (Stack Map Frames)**
21+
* 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+).
22+
23+
5. **Linking & `.jar` Generation**
24+
* 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 by `java-linker`, a custom linker built as part of this project (See `java-linker/`). It also generates the necessary `META-INF/MANIFEST.MF` file, marking the main class if applicable.
25+
26+
## Current Capabilities
27+
28+
This backend currently supports a subset of Rust features:
29+
30+
* ✅ Compiling minimal `no_std` & `no_core` Rust programs (like an empty `main`) using the `jvm-unknown-unknown` target.
31+
* ✅ Compiling simple programs using basic `core` features (like the `is_even_plus_one` test) using the host target.
32+
* ✅ Basic integer arithmetic operations on `i32`:
33+
* Addition (`+`), Subtraction (`-`), Multiplication (`*`), Division (`/`), Remainder (`%`).
34+
* Checked addition and subtraction (`checked_add`, `checked_sub`) returning `(result, overflowed_bool)` tuples.
35+
* ✅ Comparisons (`==`, `!=`, `<`, `<=`, `>`, `>=`).
36+
* ✅ Bitwise operations (`&`, `|`, `^`, `<<`, `>>`).
37+
* ✅ Basic control flow: `if`/`else` statements, `panic!` / `assert!` (with simple string messages).
38+
* ✅ Calling other `static` functions within the same crate (including recursion).
39+
* ✅ Basic variable assignment (`let x = y;`).
40+
* ✅ Generating executable `.jar` files for binary crates.
41+
42+
### Next Milestone:
43+
🚧 **Full support for the `core` crate** is the next major goal.
44+
45+
## Prerequisites
46+
47+
* **Rust Nightly:** Ensure you are using the latest **nightly** Rust toolchain. You can set this up with `rustup default nightly`.
48+
* **Rust Components:** Install necessary components:
49+
```bash
50+
rustup component add rust-src rustc-dev llvm-tools-preview
51+
```
52+
*(Note: The `rust-toolchain.toml` file in the repository should handle this automatically if you use `cargo` within the project.)*
53+
* **Java Development Kit (JDK):** A working JDK (version 8 or later recommended) is required to run the generated `.jar` files and the `asm-processor`. Make sure `java` is in your PATH.
54+
* **Gradle:** Required to build the `asm-processor` Kotlin project. Make sure `gradle` is in your PATH.
55+
56+
## Building the Toolchain
57+
58+
1. **Run Setup Script (if needed):**
59+
* The `setup.sh` script mainly adds rustup components, which `rust-toolchain.toml` might already handle. Ensure the components listed in Prerequisites are installed.
60+
2. **Build All Components:**
61+
* You can use the provided Makefile or build script:
62+
```bash
63+
# Using Make
64+
make all
65+
66+
# OR Using the build script
67+
chmod +x build.sh
68+
./build.sh
69+
```
70+
* This will:
71+
* Build the main `rustc_codegen_jvm` library (`target/debug/librustc_codegen_jvm.dylib`).
72+
* Build the `java-linker` (`java-linker/target/debug/java-linker`).
73+
* Build the `asm-processor` (`asm-processor/build/libs/asm-processor-*.jar`).
74+
75+
## Using the Toolchain (Compiling Another Rust Project)
76+
77+
To compile *your own* Rust project using this backend:
78+
79+
1. **Get the Toolchain:** Clone this repository and build it as described above. Let's assume you cloned it to `/path/to/rustc_codegen_jvm`. Ensure you build the toolchain first, as described in the previous section.
80+
81+
82+
2. **Configure Your Rust Project:**
83+
* In your *own* Rust project's directory, create a `.cargo/config.toml` file (if it doesn't exist).
84+
* Add the following content to the file:
85+
```toml
86+
[build]
87+
rustflags = [
88+
"-Z", "codegen-backend=/path/to/rustc_codegen_jvm/target/debug/librustc_codegen_jvm.dylib",
89+
"-C", "linker=/path/to/rustc_codegen_jvm/java-linker/target/debug/java-linker",
90+
"-C", "link-args=--asm-processor /path/to/rustc_codegen_jvm/asm-processor/build/libs/asm-processor-1.0-SNAPSHOT-all.jar"
91+
]
92+
```
93+
* **Important:** Replace `/path/to/rustc_codegen_jvm/...` with the path to where you cloned the repository. If you're not on macOS, changed `.dylib` to `.so` for Linux or `.dll` for Windows.
94+
95+
3. **Build Your Project:**
96+
* 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 use `core`, for now, so not recommended). Cargo will read the `.cargo/config.toml` and use the specified target and flags automatically.
97+
```bash
98+
cargo build
99+
# Or for release builds:
100+
# cargo build --release
101+
```
102+
103+
4. **Find & Run the Generated `.jar`:**
104+
* The compiled `.jar` file will be located in your project's `target` directory:
105+
* Debug: `target/debug/deps/[your_crate_name].jar`
106+
* Release: `target/release/deps/[your_crate_name].jar`
107+
* If your crate is a binary (`[[bin]]` or `src/main.rs`), run it using the `java` command:
108+
```bash
109+
java -jar target/jvm-unknown-unknown/debug/[your_crate_name].jar
110+
```
111+
112+
## Running This Project's Tests
113+
114+
This project includes integration tests managed by a Python script.
115+
116+
1. **Ensure Toolchain is Built:** Build the project using `make all` or `./build.sh`.
117+
2. **Check Target JSON:** Make sure the `jvm-unknown-unknown.json` file in the *root* of this repository has the **relative paths** starting with `../../../` for the linker and backend, as the tester expects this structure when running tests from subdirectories. If you changed them to absolute paths for external use, change them back temporarily.
118+
3. **Run the Tester:**
119+
```bash
120+
python3 Tester.py
121+
# For release mode tests:
122+
# python3 Tester.py --release
123+
```
124+
4. **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.
125+
126+
## Project Structure
127+
128+
* `src/`: Contains the source code for the `rustc_codegen_jvm` backend library.
129+
* `lib.rs`: Main backend integration point.
130+
* `lower1.rs`: MIR to OOMIR lowering pass.
131+
* `lower2.rs`: OOMIR to JVM bytecode generation pass.
132+
* `oomir.rs`: Definition of the Object-Oriented MIR (OOMIR).
133+
* `java-linker/`: Source code for the custom linker that creates `.jar` filesn from the generated `.class` files.
134+
* `asm-processor/`: Kotlin/Gradle project for the ASM-based bytecode post-processor that adds stack map frames to the generated `.class` files.
135+
* `tests/`: Integration tests.
136+
* `binary/`: Tests for compiling executable Rust crates.
137+
* `jvm-unknown-unknown.json`: The Rust target specification file.
138+
* `Tester.py`: Python script for running integration tests.
139+
* `Makefile`, `build.sh`: Scripts for building the entire toolchain.
140+
* `setup.sh`: Script to install Rust components.
141+
* `Cargo.toml`, `Cargo.lock`: Rust package definition and dependencies for the backend.
142+
* `LICENSE`, `LICENSE-Apache`: Project licenses.
143+
144+
## Contributing
145+
146+
Contributions are welcome! Feel free to open issues or pull requests.
147+
148+
## License
149+
150+
This project is dual-licensed under either of:
151+
152+
* MIT License ([LICENSE-MIT](LICENSE) or http://opensource.org/licenses/MIT)
153+
* Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-Apache) or http://www.apache.org/licenses/LICENSE-2.0)
154+
155+
at your option.

0 commit comments

Comments
 (0)