<- Back to README | Quick Start | Class Files ->
YABR (Yet Another Bytecode Reader/Writer) is a Java bytecode manipulation library organized into two main subsystems: parsing and analysis.
+------------------+ +-------------------+ +------------------+
| Parser Layer | | Analysis Layer | | SSA Pipeline |
+------------------+ +-------------------+ +------------------+
| | | | | |
| ClassPool | | MethodEntry --+ | | SSA |
| | | | | | | | | |
| v | | v | | | v |
| ClassFile ---+ | | Bytecode API | | | Lifter |
| | | | | | | | | | |
| +-----+ | | | v | | | v |
| | | | | | CodeWriter | | | IRMethod |
| v v v | | | | | | |
| Methods Fields | | Visitors <----+ | | v |
| | | | | | | Transforms |
| v | | SSA System <--+ | | | |
| ConstPool | | | | v |
| Attributes | | | | Lowerer -> Back |
+------------------+ +-------------------+ +------------------+
| Package | Purpose |
|---|---|
com.tonic.parser |
Class file parsing and representation |
com.tonic.parser.constpool |
Constant pool items and management |
com.tonic.parser.attribute |
Class file attributes (Code, StackMapTable, etc.) |
com.tonic.analysis |
Bytecode manipulation (Bytecode, CodeWriter) |
com.tonic.analysis.instruction |
Individual bytecode instructions |
com.tonic.analysis.visitor |
Visitor patterns for traversal |
com.tonic.analysis.ssa |
SSA IR system |
com.tonic.analysis.ssa.ir |
IR instruction types |
com.tonic.analysis.ssa.cfg |
Control flow graph (IRMethod, IRBlock) |
com.tonic.analysis.ssa.lift |
Bytecode to SSA lifting |
com.tonic.analysis.ssa.lower |
SSA to bytecode lowering |
com.tonic.analysis.ssa.transform |
IR optimizations |
com.tonic.analysis.ssa.analysis |
Analysis passes (dominators, liveness) |
com.tonic.analysis.source.ast |
Source-level AST node definitions |
com.tonic.analysis.source.recovery |
IR to AST recovery |
com.tonic.analysis.source.lower |
AST to IR lowering |
com.tonic.analysis.source.emit |
Java source code generation |
com.tonic.analysis.frame |
StackMapTable frame computation |
com.tonic.analysis.source.decompile |
Full class decompilation |
com.tonic.analysis.source.editor |
AST expression/statement editing |
com.tonic.analysis.xref |
Cross-reference tracking (who calls what) |
com.tonic.analysis.dataflow |
Data flow graphs and taint analysis |
com.tonic.analysis.similarity |
Method similarity and duplicate detection |
com.tonic.analysis.callgraph |
Call graph construction and queries |
com.tonic.analysis.dependency |
Class dependency analysis |
com.tonic.analysis.typeinference |
Type and nullability inference |
com.tonic.analysis.pattern |
Code pattern search |
com.tonic.analysis.instrumentation |
Bytecode instrumentation hooks |
com.tonic.analysis.simulation |
Abstract bytecode simulation and metrics |
com.tonic.analysis.execution |
Concrete bytecode execution and debugging |
com.tonic.renamer |
Class/method/field renaming |
com.tonic.utill |
Utilities (AccessBuilder, Logger, etc.) |
com.tonic.demo |
Example programs |
ClassPool - Container for loaded classes. Automatically loads java.base classes on initialization.
ClassPool pool = ClassPool.getDefault();
ClassFile cf = pool.get("java/lang/String");ClassFile - Represents a complete .class file with fields, methods, and attributes.
ConstPool - Manages the constant pool entries (strings, class refs, method refs, etc.).
MethodEntry / FieldEntry - Individual method and field definitions.
Bytecode - High-level API for adding common bytecode instructions:
Bytecode bc = new Bytecode(method);
bc.addGetStatic("java/lang/System", "out", "Ljava/io/PrintStream;");
bc.addLdc("Hello");
bc.addInvokeVirtual("java/io/PrintStream", "println", "(Ljava/lang/String;)V");
bc.finalizeBytecode();CodeWriter - Low-level bytecode manipulation with direct instruction access.
Visitors - Three visitor patterns for different analysis levels:
AbstractClassVisitor- Class-level (fields, methods, attributes)AbstractBytecodeVisitor- Instruction-level bytecodeAbstractBlockVisitor- SSA IR block-level
SSA - Main entry point for SSA operations:
Bytecode --[lift]--> SSA IR --[transform]--> Optimized IR --[lower]--> Bytecode
The SSA pipeline:
- Lift - Convert stack-based bytecode to register-based IR
- Transform - Apply optimizations (constant folding, copy propagation, DCE)
- Lower - Convert IR back to bytecode
IRMethod - SSA-form method containing IRBlocks
IRBlock - Basic block with phi instructions and regular instructions
IRInstruction - 29 instruction types representing all JVM operations
.class file bytes
|
v
ClassFile(bytes) - verifies magic number (0xCAFEBABE)
|
v
ConstPool - parses constant pool entries
|
v
Fields, Methods, Attributes - parsed with CP references
|
v
ClassFile ready for manipulation
MethodEntry
|
v
CodeWriter - wraps CodeAttribute
|
v
Insert/append instructions
|
v
write() - updates CodeAttribute bytes
|
v
ClassFile.write() - produces modified .class
MethodEntry
|
v
BytecodeLifter.lift() - creates CFG, translates instructions
|
v
PhiInserter.insertPhis() - adds phi nodes at join points
|
v
VariableRenamer.rename() - converts to SSA form
|
v
IRTransforms - optimizations
|
v
BytecodeLowerer.lower() - back to bytecode
The AST layer provides source-level representation for bytecode analysis and transformation:
+--------------------------------------------------------------+
| Source AST Layer |
+----------------+-----------------+---------------------------+
| Recovery | AST Nodes | Emission |
| (IR -> AST) | (expr/stmt) | (AST -> Source) |
+----------------+-----------------+---------------------------+
| Lowering |
| (AST -> IR) |
+--------------------------------------------------------------+
MethodRecoverer - Converts SSA IR to structured AST:
BlockStmt ast = MethodRecoverer.recoverMethod(irMethod, methodEntry);SourceEmitter - Generates readable Java source:
String source = SourceEmitter.emit(ast);ASTLowerer - Converts AST back to SSA IR:
new ASTLowerer(constPool).replaceBody(ast, irMethod);The AST system enables:
- Source-level code analysis
- High-level code transformations
- Decompilation to readable Java
- Round-trip bytecode modification
ASTEditor - ExprEditor-style API for targeted AST transformations:
ASTEditor editor = new ASTEditor(methodBody, "methodName", "()V", "com/example/Class");
editor.onMethodCall((ctx, call) -> {
if (call.getMethodName().equals("deprecated")) {
return Replacement.with(ctx.factory().methodCall("newMethod").build());
}
return Replacement.keep();
});
editor.apply();The editor system provides:
- Handler-based interception of expressions and statements
- Type-safe replacement with AST nodes
- Predicate-based matchers for flexible filtering
- Factory for building new AST nodes
Renamer - High-level API for renaming classes, methods, and fields:
Renamer renamer = new Renamer(classPool);
renamer.mapClass("com/old/MyClass", "com/new/RenamedClass")
.mapMethodInHierarchy("com/old/Service", "process", "(I)V", "handle")
.mapField("com/old/Model", "data", "Ljava/lang/String;", "content")
.apply();The renamer handles:
- Constant pool reference updates across all classes
- Hierarchy-aware method renaming
- Descriptor and signature remapping
- Pre-application validation
BytecodeEngine - Concrete bytecode execution for debugging and REPL:
BytecodeContext ctx = new BytecodeContext.Builder()
.heapManager(new SimpleHeapManager())
.classResolver(new ClassResolver(pool))
.maxInstructions(100000)
.build();
BytecodeEngine engine = new BytecodeEngine(ctx);
BytecodeResult result = engine.execute(method, ConcreteValue.intValue(42));The execution system provides:
- Mutable stack/locals with concrete values (not abstract types)
- Full heap simulation with objects and arrays
- Native method handlers for JDK core methods
- Two invocation modes: recursive (internal) and delegated (external callback)
DebugSession - Interactive debugging support:
DebugSession session = new DebugSession(ctx);
session.addBreakpoint(new Breakpoint("MyClass", "method", "()V", 10));
session.start(method);
DebugState state = session.stepOver();The debugging system enables:
- Breakpoints at specific bytecode offsets
- Step into/over/out execution control
- Call stack and variable inspection
- Execution state snapshots for UI display
-
Lazy Loading - ClassPool loads built-in classes on demand from JRT (Java 9+) or rt.jar (Java 8)
-
Mutable Model - ClassFile and its components are mutable for easy manipulation
-
Visitor Pattern - Multiple visitor types allow analysis at different granularities
-
SSA for Optimization - SSA form simplifies dataflow analysis and enables powerful optimizations
-
Frame Computation - Automatic StackMapTable generation for Java 7+ verification
- Working with Class Files - ClassPool, ClassFile, ConstPool details
- Bytecode API - Bytecode and CodeWriter usage
- Visitors - Traversal and transformation patterns
- SSA Guide - SSA IR system in depth
- AST Guide - Source-level AST recovery, mutation, and emission
- AST Editor - ExprEditor-style AST transformations
- Analysis APIs - Call graph, xrefs, data flow, simulation, execution, and more
- Execution API - Concrete bytecode execution and debugging
- Renamer API - Class, method, and field renaming
- Frame Computation - StackMapTable generation