CD Notes
Deep dive into Java compilation process, bytecode format, and JVM architecture
The Java compiler (javac) has unique characteristics because Java is designed to run on a virtual machine. Understanding the Java compilation model provides insights into bytecode and JIT compilation.
Java Compilation Overview
Java differs from C/C++ because it compiles to bytecode (intermediate representation) rather than native machine code. This bytecode runs on the Java Virtual Machine (JVM).
Traditional Compiler (C/C++)
Source Code → Compiler → Machine Code → Execution
Java Compiler
Source Code → Compiler → Bytecode → JVM → Execution
(.java) (javac) (.class) (Interpreter/JIT)
Two-Stage Compilation Model
| Java Source Files (.java) | ||
|---|---|---|
| Lexical/Syntax/Semantic Analysis | ||
| Bytecode Generation | ||
| (.class files, classfile format) | ||
| Load .class files | ||
| Class Linking & Verification | ||
| Bytecode Interpretation (or JIT) |
Java Source Code to Bytecode
Example Java Code:
public class Add {
public static int add(int a, int b) {
return a + b;
}
public static void main(String[] args) {
int result = add(5, 3);
System.out.println(result);
}
}Java Bytecode (.class file content - disassembled):
| Length | 356 |
| 0 | iload_0 // Load first argument (a) onto stack |
| 1 | iload_1 // Load second argument (b) onto stack |
| 2 | iadd // Add two integers on stack |
| 3 | ireturn // Return result from method |
| 0 | iconst_5 // Push constant 5 onto stack |
| 1 | iconst_3 // Push constant 3 onto stack |
| 2 | invokestatic // Call add(5, 3) |
| 5 | istore_2 // Store result in local variable |
| 6 | getstatic // Get System.out |
| 9 | iload_2 // Load result |
| 10 | invokevirtual // Call println(result) |
| 13 | return // Return from main |
Javac Compilation Process
Java Class File Format
The .class file is a binary format containing bytecode and metadata:
Bytecode Instructions
Java bytecode uses stack-based operations. All operations work on a stack.
| Instruction | Meaning | Example |
|---|---|---|
| aload | Load object reference | aload_1 (load arg 1) |
| iload | Load integer | iload_0 (load arg 0) |
| fload | Load float | fload_0 |
| iadd | Add integers | iadd (pop two, add, push) |
| istore | Store integer | istore_2 (pop, store in var 2) |
| invokestatic | Call static method | invokestatic java/lang/Math.abs |
| invokevirtual | Call instance method | invokevirtual java/io/PrintStream.println |
| if_icmpeq | Branch if equal | if_icmpeq label |
| return | Return from method | return (void) |
| ireturn | Return integer | ireturn |
Bytecode Example: Stack Operations
Java Code:
int add(int a, int b) {
return a + b;
}Bytecode Execution (stack-based):
| Stack before | [] |
| iload_0 Stack | [5] (Load a=5) |
| iload_1 Stack | [5, 3] (Load b=3) |
| iadd Stack | [8] (5+3=8) |
| ireturn Stack | [] (Return 8) |
Binary Bytecode:
Bytecode: 1A 1B 60 AC
Where:
1A = iload_0 (opcode for load first arg)
1B = iload_1 (opcode for load second arg)
60 = iadd (opcode for integer addition)
AC = ireturn (opcode for return integer)Java Compilation Advantages
✓ Platform independence (WORA - Write Once, Run Anywhere) ✓ Bytecode verification for safety ✓ Runtime optimization via JIT ✓ Dynamic loading of classes ✓ Reflection capabilities ✓ Garbage collection built-in ✓ Security sandboxing possible
Javac Optimizations
While javac does some optimization, most happen at runtime:
| Phase | Optimization |
|---|---|
| Compile-time | Dead code elimination, constant folding |
| Runtime (JIT) | Inlining, loop unrolling, escape analysis |
| Runtime (JIT) | Adaptive optimization based on execution |
| Runtime | Speculative optimization |
Interview Q&A
Q: Why does Java compile to bytecode instead of machine code? A: Bytecode provides platform independence - the same bytecode runs on any JVM. This achieves "Write Once, Run Anywhere". Runtime JIT compilation converts bytecode to native code for performance.
Q: What is a .class file? A: A .class file is a binary file containing Java bytecode (intermediate representation), metadata about the class (fields, methods), and a constant pool with string/number constants.
Q: How does javac differ from C++ compilers? A: Javac compiles to bytecode (intermediate) rather than native machine code. The JVM then interprets or JIT-compiles bytecode at runtime. This provides platform independence but adds runtime overhead.
Q: What is the constant pool? A: The constant pool in a .class file stores all constants used by the class - strings, numbers, method names, class names. This allows strings to be defined once and referenced by index.
Q: What's the magic number in Java class files? A: The magic number 0xCAFEBABE at the start of every .class file identifies it as a valid Java class file. It's a signature preventing accidental binary file loading.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Java Compiler and Bytecode.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Compiler Design topic.
Search Terms
compiler-design, compiler design, compiler, design, modern, technologies, java, java compiler and bytecode
Related Compiler Design Topics