MetaIR is a graph-based intermediate representation (IR) for JVM bytecode, built on Cliff Click's Sea-of-Nodes concept. The framework leverages the Java Class-File API introduced in Java 24 (JEP 484).
Most parts of the IR are taken from Bytecoder - Framework to interpret and transpile JVM bytecode to JavaScript, OpenCL or WebAssembly. , but were rewritten to be more flexible and extensible.
- Analysis: Transform and inspect existing JVM bytecode
- Visualization: Debug functionality for graph representation
- Optimization: Built-in peephole optimizations for graph reduction
- Integration: Built-in integration with JUnit Platform
- Cross-Compilation: Foundation framework for cross-compiler development. Hello OpenCL and WebAssembly!
- MetaIR covers all aspects of JVM bytecode, including:
- Control Flow: Branching, loops, exception handling
- Data Flow: Local variables, stack, memory
- Memory aliasing: Memory allocation, memory access
Please take a look at the Mandelbrot OpenCL example to see it in action. More tutorials will follow.
- Built on Java Class-File API (JEP 484)
- Implements Sea-of-Nodes IR design
- Further examples and documentation: SeaOfNodes/Simple
- 🚧 Scheduling logic for machine code transformation is under development.
- An excellent tutorial about the Class-File API: Build A Compiler With The Java Class-File API by Dr. James Hamilton
- IR Sequencing: Beyond Relooper: recursive translation of unstructured control flow to structured control flow (functional pearl)
- Compilers - Nuts and bolts of Programming Languages: Compilers - Nuts and bolts of Programming Languages
A simple Java example with constructor invocation, demonstrating the use of the JUnit Platform integration:
import de.mirkosertic.metair.ir.test.MetaIRTest;
@MetaIRTest
public class NewInstanceTest {
public void newInstance() {
new NewInstanceTest();
}
}
Class-File API Debug YAML:
- method name: newInstance
flags: [PUBLIC]
method type: ()V
attributes: [Code]
code:
max stack: 2
max locals: 1
attributes: [LineNumberTable, LocalVariableTable]
line numbers:
- {start: 0, line number: 12}
- {start: 8, line number: 13}
local variables:
- {start: 0, end: 9, slot: 0, name: this, type: Lde/mirkosertic/metair/ir/examples/NewInstanceTest;}
//stack map frame @0: {locals: [de/mirkosertic/metair/ir/examples/NewInstanceTest], stack: []}
0: {opcode: NEW, type: de/mirkosertic/metair/ir/examples/NewInstanceTest}
3: {opcode: DUP}
4: {opcode: INVOKESPECIAL, owner: de/mirkosertic/metair/ir/examples/NewInstanceTest, method name: <init>, method type: ()V}
7: {opcode: POP}
8: {opcode: RETURN}
Generated IR (raw and unoptimized):
A full set of examples can be found in the MetaIR Test Suite. Each directory corresponds to a single testcase, and you will find the Class-File API Debug YAML and the generated IR (raw and unoptimized) as well in dot(graphviz) notation and as SVG images.