Pro Content

Upgrade to access all Cambridge 9618 lessons including JVM, CLR, JIT compilation, and bytecode execution models.

Upgrade to Pro →
← Back to Dashboard
📘 Paper 3 · 3.4 Translation
3.4.2 Virtual Machines for Intermediary Code
Cambridge 9618 · International A Level Computer Science · ~15 min read
Notes
Video
Slides
Quiz
Worksheet

Three Execution Approaches

When a programmer writes source code, there are three main approaches to turn it into running instructions. The intermediary code / bytecode approach sits between native compilation and pure interpretation:

1. Native Compilation
  • Source code → native machine code for a specific CPU
  • Runs at maximum speed — no runtime translation
  • Platform-specific — must recompile for each OS/CPU
  • Examples: C, C++, Go, Rust
2. Bytecode / Intermediary Code
  • Source code → bytecode → VM executes on any platform
  • Platform-independent — same bytecode, different VMs
  • Near-native speed with JIT compilation
  • Examples: Java (JVM), C# (.NET CLR), Python
3. Pure Interpretation
  • Source code translated and executed line by line
  • No intermediate representation
  • Slowest — full translation overhead every run
  • Examples: early BASIC, shell scripts
Execution pipelines
Native compilation (C/C++)
Source .c
Compiler (once)
Native .exe
CPU executes
Bytecode approach (Java)
Source .java
javac
Bytecode .class
JVM
CPU
Pure interpretation
Source code
Interpreter (every run)
CPU

Intermediary Code (Bytecode)

Bytecode (also called intermediary code or p-code) is an intermediate representation between source code and native machine code. It is designed to be:

  • Compact — smaller than source code, efficient to store and transfer
  • Platform-independent — not specific to any CPU architecture
  • Easy to execute by a software virtual machine
  • A lower-level representation than source code but still abstract — closer to machine code but not tied to one CPU
Java source → Bytecode example
// Java source
int x = 3 + 5;
System.out.println(x);
javac
; Bytecode (JVM instructions)
iconst_3
iconst_5
iadd
istore_1
getstatic java/lang/System/out
iload_1
invokevirtual println

Java Virtual Machine (JVM)

The JVM is the software virtual machine that executes Java bytecode. It provides a complete execution environment — abstracting away the underlying hardware and OS so the same .class files run anywhere.

  • JVM reads .class bytecode files and executes them
  • Each platform (Windows, macOS, Linux, Android) has its own JVM implementation
  • The JVM provides: bytecode execution, JIT compilation, memory management (garbage collection), and a security sandbox
  • "Write once, run anywhere" (WORA) — the key design principle

JIT Compilation vs Pure Interpretation

⚡ JIT Compilation
  • Identifies hot spots — frequently executed bytecode sections
  • Compiles hot bytecode to native machine code at runtime
  • Compiled native code is cached and reused
  • Near-native performance after warmup
  • Used by: JVM (Java), CLR (.NET), V8 (JavaScript)
  • Trade-off: initial startup slower (compilation cost)
🐌 Pure Interpretation
  • Each bytecode instruction fetched and interpreted one at a time
  • No compilation — each instruction goes through interpreter loop
  • Every execution of the same loop re-interprets all instructions
  • Slower — interpreter overhead on every instruction
  • Simpler to implement but much worse performance
  • No warmup cost — starts immediately

.NET CLR — Another Example

Microsoft's Common Language Runtime (CLR) is the virtual machine for the .NET framework. It works identically to the JVM concept:

JVM (Java)CLR (.NET)
Source language: Java, Kotlin, ScalaSource languages: C#, VB.NET, F#
Compiler produces: .class filesCompiler produces: .dll/.exe containing CIL
Intermediate code: Java bytecodeIntermediate code: CIL (Common Intermediate Language, formerly MSIL)
Runtime: JVMRuntime: CLR
JIT: JVM JIT compilerJIT: CLR JIT compiler
Memory: JVM garbage collectorMemory: CLR garbage collector

Key Benefits of the Bytecode VM Approach

🌍
Portability
Same bytecode runs on any platform with the VM installed — Windows, Mac, Linux, Android. No recompilation per platform.
🔒
Security Sandbox
The VM can check bytecode before execution, preventing certain attacks. Code runs in a controlled environment with restricted access to the system.
🗑️
Automatic Memory Management
Garbage collection frees memory automatically — no manual malloc/free needed (unlike C). Prevents memory leaks and dangling pointers.
Runtime Optimisation
JIT compilers can optimise based on actual runtime behaviour — e.g. optimising loops that actually run frequently, which static compilers can't know ahead of time.

Disadvantages of the Bytecode VM Approach

  • Startup overhead: the JVM/CLR must load and initialise before any code runs; JIT compilation takes time during the warmup phase
  • Memory overhead: the VM itself uses significant RAM — the JVM runtime can require hundreds of MB even for small programs
  • Performance ceiling: even with JIT, rarely matches hand-optimised native code for CPU-intensive work
  • Complexity: the VM layer adds complexity to debugging and profiling
🗑️ Garbage Collection
The JVM and CLR both include automatic garbage collection. When an object is no longer referenced by any variable, the garbage collector identifies it as unreachable and frees its memory. This happens automatically without the programmer needing to call free() (as in C). Benefits: prevents memory leaks, eliminates dangling pointer bugs. Drawback: GC pauses can cause brief latency spikes ("stop-the-world" pauses).
Cambridge 9618 exam tip: Understand the TWO uses of "virtual machine" in 9618: (1) hardware VM (3.3.2) — hypervisor, Type 1/Type 2, running full guest OS; (2) bytecode VM (this lesson) — JVM/CLR, executes intermediary code, enables portability. For bytecode VMs: source → bytecode (by compiler) → VM → (JIT) → native code. Key advantages: portability (write once, run anywhere), security sandbox, automatic garbage collection. Key disadvantage: startup overhead, memory overhead vs native. Know both JVM (Java → .class bytecode) and CLR (.NET → CIL). JIT = hot bytecode compiled to native at runtime, faster than interpretation.
⚠️ Common Mistakes
  • Confusing the JVM with the Java compiler — javac compiles .java to .class bytecode; the JVM RUNS the bytecode — they are different programs
  • Saying JIT compiles at startup — JIT compiles HOT SPOTS (frequently executed sections) identified DURING runtime, not the whole program before execution
  • Saying bytecode is machine code — bytecode is NOT native machine code; it cannot run directly on a CPU; it must be interpreted or JIT-compiled by the VM
  • Confusing the JVM with hardware VMs — a hardware VM (hypervisor) runs a complete guest OS; a bytecode VM (JVM) runs bytecode for a single application; they use different mechanisms
  • Forgetting garbage collection — automatic memory management is a key feature of VMs like JVM and CLR; it frees unreachable objects automatically
✅ Notes completed!
Video coming soon
Click slide or press arrow keys to navigate

Worksheet — 3.4.2 VM for Intermediary Code

8 questions · Cambridge 9618 standard

Q1Describe what bytecode (intermediary code) is and how it differs from both source code and native machine code.[3]
✅ Mark scheme
Bytecode is an intermediate code representation between source code and native machine code [1]; unlike source code, bytecode is not human-readable and is closer to machine instructions — it has already been parsed and compiled from the source language [1]; unlike native machine code, bytecode is not specific to any CPU architecture — it cannot be executed directly by a CPU and must be processed by a virtual machine (JVM/CLR); it is platform-independent [1].
Q2Explain how the JVM enables a Java program to run on both Windows and Linux without recompilation.[3]
✅ Mark scheme
The Java compiler (javac) compiles Java source code (.java) into platform-independent bytecode (.class files) once [1]; both Windows and Linux have their own implementations of the JVM — the JVM on each platform reads the same .class bytecode files and translates them to native machine code for that specific platform [1]; because the bytecode is not tied to any CPU or OS, the same .class files run on any machine with a JVM installed — write once, run anywhere [1].
Q3Compare JIT compilation to pure interpretation of bytecode. Which gives better runtime performance and why?[4]
✅ Mark scheme
JIT compilation gives better runtime performance [1]; JIT identifies frequently-executed sections of bytecode (hot spots) and compiles them to native machine code at runtime — the compiled native code is cached and reused each time those sections execute [1]; pure interpretation must process each bytecode instruction through the interpreter loop every time it executes — including in tight loops where the same instructions execute millions of times; this adds substantial overhead [1]; with JIT, after the initial warmup compilation, the code runs at native speed because the CPU is executing compiled machine code, not going through an interpreter [1].
Q4State two advantages and one disadvantage of using a bytecode VM approach compared to compiling directly to native machine code.[3]
✅ Mark scheme
Advantages — any two from: portability — same bytecode runs on any platform with a compatible VM, no platform-specific recompilation [1]; security sandbox — the VM can validate bytecode before execution and restrict access to system resources [1]; automatic garbage collection — the VM manages memory automatically, preventing leaks and dangling pointers [1]; runtime optimisation — JIT can optimise based on actual execution patterns, which ahead-of-time compilers cannot do [1]; disadvantage: startup and memory overhead — the VM itself requires loading/initialising, JIT compilation takes time, and the runtime uses significant RAM compared to a lean native executable [1].
Q5What is the equivalent of the JVM for .NET programs? What intermediate code does it execute?[2]
✅ Mark scheme
The CLR — Common Language Runtime [1]; it executes CIL — Common Intermediate Language (also accepted: MSIL — Microsoft Intermediate Language) [1].
Q6A student says "bytecode virtual machines and hardware hypervisors are the same thing — both are virtual machines." Evaluate this claim.[3]
✅ Mark scheme
The student is partially correct — both are called virtual machines and both virtualise something [1]; however they are fundamentally different: a hardware hypervisor (Type 1/Type 2) virtualises a complete computer system — it allows a full guest operating system to run, managing virtual CPU, RAM, and I/O; used for running multiple OS instances on one physical machine [1]; a bytecode VM (JVM/CLR) virtualises an execution environment for a specific language runtime — it runs bytecode for a single application, providing portability across platforms; it does NOT run a complete OS [1]. The term "virtual machine" covers both concepts but they solve entirely different problems.
Q7Explain the role of the Java Virtual Machine (JVM) in executing Java programs. Describe how a Java source file becomes a running program, naming every intermediate step and artefact produced.[5]
✅ Mark scheme
Step 1: Java source code (.java) is compiled by the Java compiler (javac) [1]; Step 2: compiler produces bytecode stored in a .class file — platform-independent intermediate code [1]; Step 3: the JVM on the target machine loads the .class file and either interprets it or uses Just-In-Time (JIT) compilation to convert bytecode to native machine code [1]; JVM executes the machine code, managing memory (garbage collection), security, and platform abstraction [1]; the JVM must be installed on each target machine, but the same .class file runs unchanged on Windows, macOS, and Linux — "write once, run anywhere" [1].
Q8Explain what Just-In-Time (JIT) compilation is and how it differs from both ahead-of-time compilation and pure interpretation. State one advantage and one disadvantage of JIT compilation compared to traditional ahead-of-time compilation.[4]
✅ Mark scheme
JIT: compiles bytecode (or source) to native machine code at runtime, just before execution — not before the program is distributed [1]; differs from ahead-of-time: AOT compiles to machine code before distribution; JIT compiles during execution [1]; differs from pure interpretation: pure interpreters translate each instruction on every execution; JIT compiles hot code paths once and caches the machine code for reuse [1]; Advantage: JIT-compiled code runs near native speed and can optimise based on actual runtime data (e.g. branch prediction based on observed behaviour) [1]; Disadvantage: compilation overhead occurs at startup / first execution — JIT-compiled programs have a warm-up delay before reaching full performance [1]. Award max 4.
Topic Quiz
Question 1 of 10
You scored
out of 10
Card 1 of 8
Click to reveal definition
🎉
All cards reviewed!
TermDefinition
🎯

Mini Test — 3.4.2 VM for Intermediary Code

10 questions · 10 marks · 10 minutes

← 3.4.1 Language Translators
61 of 82 · Cambridge 9618
3.5.1 Security Threats →