Slides:
A runtime system implements the execution model of a programming language and provides a runtime support.
The runtime system can be made of:
- code in the executing program generated by the compiler
- code running in other threads or processes during the program execution
- language libraries
- OS functionalities
- the interpreter/VM itself
The runtime support is needed for:
- memory management: push/pop activation records on stack, allocation and garbage collection on heap
- I/O management
- runtime environment interaction
- parallel execution threads/tasks/processes
- dynamic type checking and bounding
- dynamic linking
- debugging, JIT compilation, etc.
Includes all what is needed to run compiled Java programs (bytecode).
It is made by the JVM and the JCL (Java Class Library, aka Java API).
It is an abstract machine for the bytecode.
Oracle doesn't provide details about the implementation of the JVS, but there are specifications for a machine independent class file format. Every language that can be compiled in a .class file can be executed by the JVM.
Each JVM has an internal representation (implementation dependent) of classes, objects and primitive types.
The JVM is a multithreaded stack-based machine.
Each instruction implicity take the arguments from and put the operands to the top of the operand stack of the current frame.
The operand stack stores also local variables and intermediate results.
Are often allocated on the heap and contains:
- Local variable array: contains all the variables used during a method execution
- Operand stack: general-purpose registers
- Reference to constant pool of current class
- Return address
Primitive types:
- boolean
- byte, short, int, long, char
- float, double
- return address (internal, for exception handling)
Reference types:
- array
- class
- interface
Is left to the implementation. Must include the concrete value of null
, pointers to instance and class data, mutex locks and garbage collection flags.
- heap: arrays and objects (they have a non-fixed size)
- Non-Heap: objects considered logically part of the JVM
- Permanent generation: method area and interned strings
- Code cache: cache for the code compiled with the JIT compilation
Multiple threads are possible starting from a single main
. Moreover, there are several background threads for garbage collection, signal dispatching, JIT compilation, etc.
Threads have shared access to heap and persistent memory. The latter includes the method area, interned strings, and code cache for JIT compilation.
Each thread has its separate stack area. That area includes:
- PC: pointer counter to the next instruction in the method area
- Java stack: a stack of frames (activation records), a frame is added every time a method is invoked and destroyed every time the methods completes. Them are not allocated continuously.
- Native stack: used for invocation of native functions.
Contains:
- Classloader Reference
- From the class file:
- Run Time Constant Pool
- constants and symbolic references for dynamic binding (numeric and strings literals, class, methods and fields references, signatures)
- operands in bytecodes
- Field data
- Name
- Type
- Modifiers
- Attributes
- Method data
- Name
- Return Type
- Parameter Types (in order)
- Modifiers
- Attributes
- Method code (per method)
- Bytecodes
- Operand stack size
- Local variable size
- Local variable table
- Exception table
- LineNumberTable (which line of source code corresponds to which byte code instruction, for debugging)
- Per exception handler (one for each try/catch/finally clause)
- Start point
- End point
- PC offset for handler code
- Constant pool index for exception class being caught
- Run Time Constant Pool
Is applied on the heap
- object and arrays are created into the young generation
- object alive are moved from the eden space to the survivor space
- survived object are moved into the old generation, the others deallocated
- every time the old generation is full is garbage collected (the young generation is garbage collected constantly)
Before deallocating an object, the Garbage Collector calls the finalize
method. It is possible to override this method, although deprecated.
The finalization is called also on classes, usually when JVM exits. A class can be finalized only if no object of this class exists or the exist one are unrecheable.
Since interpret bytecode is not as fast as execute native code, the JVM look for bytecode that is executed several time and compile it to native code. This code is stored in the code cache area of the non-heap memory area.
- compile:
javac Class.java
- run:
java Class.class
- decompile:
javap -c -v Class.class
- bootstrap classloader
- class is linked and initialized
- main is invoked
- loading (finding binaries), linking (preparing executable) and initialization (
clinit
method) of additional classes
The linking consists in:
- verification: correctness, overflow and underflow, variables and types validity, data-flow analysis
- preparation: allocation of storage
- resolution (optional): loading of the referred classes and interfaces (can be postponed to first use)
- Calculate PC and fetch opcode
- if (operand) fetch operand
- execute op
- Byte aligned, the number that precede an instruction indicates its byte position. Each opcode occupies 1 byte.
- JVM supports 3 addressing modes:
- Intermediate, with a constant as part of instruction;
- Indexed, with the index of the local var array;
- Stack, pop from the top of the operand stack.
- JVM instructions are explicitly typed (
iload
,lload
, ...,istore
, ...):- i int
- l long
- s short
- b byte
- c char
- f float
- d double
- a for reference
- The computational type of the instruction is embedded in the opcode.
Different JVM data areas ⇒ different instruction for memory access:
- local var and arguments:
load
andstore
(operand stack) - fields in objects:
getfield
andputfield
(heap) - static fields:
getstatic
andputstatic
(method area)
- Array instructions: load, store, utilities (such as
newarray
,arraylength
). - Operand stack manipulation:
pop
,dup
,swap
. - Control transfer: unconditional (e.g.
goto
) or conditional (ifeq
,iflt
,ifgt
, ...). - Method invocation:
invokevirtual
on objects,invokeinterface
for interfaces,invokespecial
for constructors, private or superclass methods, andinvokestatic
for static methods. return
,ireturn
,lreturn
, etc.- Object allocation:
new
. - Special instructions:
nop
,athrow
(throws exception),instanceof
(verifies instances),checkcast
(checks a casting operation)