Inside Java Compilation: From Source Code to Optimized Bytecode

This article explains Java's compilation pipeline—from source parsing, symbol table construction, and annotation processing to semantic analysis and bytecode generation—and then details HotSpot's runtime JIT compilation, covering client vs server compilers, inlining, devirtualization, escape analysis, and on‑stack replacement.

JD Cloud Developers
JD Cloud Developers
JD Cloud Developers
Inside Java Compilation: From Source Code to Optimized Bytecode

1. Compilation Process

Compilation turns Java source files into .class files and consists of four steps.

1. Preparation

Initialize the annotation processing tool (APT).

2. Parsing and Symbol Table Construction

Source code is tokenized, an abstract syntax tree (AST) is built, and a symbol table (a key‑value map) is populated with variable names, constants, method signatures, literals, generated temporary files, and language tags. The compiler’s later phases operate on the AST.

3. Annotation Processors

Annotation processors are compiler plugins that read or modify any AST element, often used for code generation (e.g., Lombok, MapStruct). If the AST is changed, the compiler repeats the parsing step, forming a “round”. This is the only way developers can influence compilation.

4. Analysis and Bytecode Generation

After a correct AST is produced, semantic analysis validates the tree, followed by bytecode generation.

4.1 Annotation Checks

Checks declarations, variable‑assignment compatibility, and performs constant folding (e.g., int a = 1 + 2; becomes int a = 3;).

4.2 Data and Control‑Flow Analysis

Verifies that local variables are initialized before use, that every method path returns a value, and that checked exceptions are properly handled.

4.3 Desugaring

Removes Java syntactic sugar such as autoboxing, generics, and var‑args, converting them to fundamental language constructs.

4.4 Bytecode Generation

The final phase emits .class files from the AST and symbol table, adding a small amount of extra code.

2. Runtime (JIT) Compilation

Runtime compilation compiles hot code to native machine code to avoid interpretation overhead. The HotSpot JVM combines an interpreter with a Just‑In‑Time compiler.

2.1 When Compilation Happens

The Sun JDK uses a method invocation counter; once the counter exceeds a threshold (default 1500 in client mode, 10000 in server mode) the method is compiled. The thresholds can be tuned with -XX:CompileThreshold.

2.2 Compilation Modes

Two JIT compilers are available: the lightweight client compiler (C1) and the heavyweight server compiler (C2).

2.2.1 Client Compiler (C1)

Key optimizations include:

Method inlining – replaces getter/setter calls with direct field access.

Devirtualization – inlines calls when the concrete type is known.

Redundant code elimination – removes dead code such as unreachable log statements.

Example of inlining:

Order o = new Order();</code>
<code>o.setTotalAmount(o.getOrderAmount() * o.getCount());

After compilation:

Order o = new Order();</code>
<code>o.orderAmount = o.orderAmount * o.count;

Inlining can be disabled with -XX:-Inline, but it is strongly recommended to keep it enabled.

Devirtualization example:

public interface Animal { void eat(); }</code>
<code>public class Cat implements Animal { public void eat() { System.out.println("Cat eat !"); } }</code>
<code>public class Demo { public void execute(Animal animal) { animal.eat(); } }

If only Cat implements Animal, the compiled execute method becomes:

public void execute() { System.out.println("Cat eat !"); }

Redundant elimination example:

private static final boolean isDebug = false;</code>
<code>public void execute() { if (isDebug) { log.debug("do execute."); } System.out.println("done"); }

After C1 compilation the dead branch is removed:

public void execute() { System.out.println("done"); }

2.2.2 Server Compiler (C2)

C2 performs global optimizations such as escape analysis, scalar replacement, stack allocation, and lock elimination.

Escape Analysis & Scalar Replacement

If an object does not escape the method, its fields can be replaced by scalar variables.

Point point = new Point(1, 2);</code>
<code>System.out.println("point.x = " + point.x + "; point.y" + point.y);

After compilation:

int x = 1, y = 2;</code>
<code>System.out.println("point.x = " + x + "; point.y" + y);

Stack Allocation

When escape analysis shows an object does not escape, C2 allocates it on the stack instead of the heap, making allocation faster and automatically reclaimed at method exit.

Lock Elimination

Synchronized blocks on non‑escaping objects are removed.

Point point = new Point(1, 2);</code>
<code>synchronized(point) { System.out.println("point.x = " + point.x); }

After optimization:

Point point = new Point(1, 2);</code>
<code>System.out.println("point.x = " + point.x);

2.3 On‑Stack Replacement (OSR)

OSR recompiles only the hot loop body of a method, allowing the compiled code to be used for subsequent iterations while the rest of the method continues to be interpreted.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavabytecodeCompilationJITHotSpot
JD Cloud Developers
Written by

JD Cloud Developers

JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.