The Bytecoder internal intermediate representation is basically a directed graph. The key idea behind this is described in this paper.
Given this Java source code:
@Test
public void testSimpleLoop() {
int x = 0;
for (int i = 0; i < 100; i++) {
x = x + i;
}
}
the following intermediate representation graph is generated (in its first, unoptimized form):
This graph combines data flow analysis and control flow into one big graph. Using this graph makes data and control flow dependencies explicit and lays foundation for a variety of optimizations that can be performed on it to either reduce code size or improve execution speed. Optimizing the program simply becomes an optimizing the graph problem.
The following graph shows the further optimized version of the previous loop: