(WIP) Java bytecode into Rust decompiler
Find a file
2026-02-03 13:49:20 +00:00
bcode-flow first-iteration support for try blocks 2026-02-03 13:49:20 +00:00
common add common java-related types used by other crates 2026-01-20 14:12:32 +00:00
parser-raw add parser for the raw .class file 2026-01-20 14:12:34 +00:00
parser-resolve first-iteration support for try blocks 2026-02-03 13:49:20 +00:00
test-utils first-iteration support for try blocks 2026-02-03 13:49:20 +00:00
.gitignore ignore local testing classes 2026-01-20 14:18:42 +00:00
Cargo.lock [Cargo.lock] 2026-01-20 14:18:05 +00:00
Cargo.toml add CLI util for testing a specific method 2026-01-20 14:16:47 +00:00
README.md add initial version of the control flow parser 2026-01-20 14:14:21 +00:00

Ferrobean is a project aiming to turn java code into Rust code. At the moment, this is accomplished by parsing the bytecode and decompiling it into the Rust source.

Curent state

java.base

  • parses all the bytecode
  • parses most of the control flow

Diversions from the spec

In my model, return never throws. As per spec, return can throw InvalidMonitorStateException, while existing from a synchronized method without a held monitor.

In my model, InvalidMonitorState is thrown by the calling scope.

javac on my machine generates exception handling tables such that they avoid handling exceptions thrown by return. However, the bytecode technically can be written such that these exceptions are handled, and in this case, generated Rust code will exhibit different behavior.

At the moment, following limitations apply to exception handling:

  • Handler handling exception thrown by itself will not work correctly: it will try to handle it exactly once.
  • Handlers are assumed to be blocks of code, i.e. range of thee code covered by a single handler is assumed to be a contiguous code block.
  • Limitation above has some consequences alleviated: if there are several ranges or code covered by a single handler, they still will be merged into a single try block, but the "gaps" in this range, will be wrapped into special "negative try" blocks, specifically disabling some of the handlers.
  • However, handling still can work incorrectly, even with them. Consider the following handling table:
start end handler
1 6 6
2 5 7
3 4 6

With current implementation, it instead behaves like

start end handler
1 6 6
2 5 7

i.e. a fully-contained handler is ignored, and assumed to be a part of the bigger handler. from my experimentation, there's no way to generate such table with javac, but the possibility of forging a bytecode such that it handles exceptions in a spec-non-compliant way is out there.

My model also assumes that there can be two handlers with identical full range, but different gap ranges.

  • I assume there can be no direct jumps to handlers