- A class file consists of bytecode and a symbol table
- There are two kinds of types: primitives and references
- Reference types can be either a dynamically allocated class instance or an array.
- There is no way to distinguish primitive types within bytecode except for the operands used to
manipulate them. Each operand has a different version depending on the type: e.g.:
dadd are addition operands for
- Integral, signed numbers use two’s-component notation
- Primitive types memory:
byte, 8-bit, from
2^7 - 1
short, 16-bit, from
2^15 - 1
int, 32-bit, from
2^31 - 1
long, 64-bit, from
2^65 - 1
char is the only integral type that is unsigned and it represents a Unicode code point encoded in UTF-16
- There is a primitive type called
returnAddress, whose value can be pointers to the opcodes of JVM instructions.
pc (program counter) register contains the address of the current JVM instruction being executed.
There is one
pc per thread.
- Every thread contains a stack (created when the thread itself is created)
- Every stack stores frames
- There is a limited to the number of frames per stack, that may be tunable depending on the JVM implementation.
- If the limit of frames is reached, an
StackOverflow exception is thrown.
- When a new thread is created but there is no enough memory to create its initial stack,
OutOfMemoryError is thrown.
- Heap is the runtime data area where objects are allocated. It is shared by all threads and
is created when the JVM is started up.
- If a computation requires more heap than available
OutOfMemoryError is thrown.
- The method area is where the runtime constant pool, fields information and functions’ code is stored,
in a per-class basis. Shared by all threads.
- The runtime constant pool is a per-class representation of the class’ constant_pool table.
- Allocated in the method area.
- A frame stores partial results, performs dynamic linking, returns values from methods and dispatch exceptions.
- Created everytime a method is invoked, destroyed when the method terminates or throws.
- Local variables is an array of the variables of a frame (method)
- Size determined at compile time
- Can hold boolean, int, byte, char, short, float, reference and returnAddress.
- long and double are represented by two local variables
- Referenced by index
- Method parameters are assigned to local variables
- For class methods, starting at 0
- For isntance methods, starting at 1 (0 would be a reference to
- Operand stack is a LIFO stack where operands are pushed or pop by bytecode instructions.
- Constructors are named
<init> in the bytecode
- Class initializers are named
- When an exception is thrown and is not handled in the current method, local variables and operand
stack are discarded, the current frame is poped from the stack, and the exception rethrown in
the context of the invoker’s frame.
- If the exception propagates unhandled after reaching the last frame, its thread is terminated.
- JVM instructions are one byte opcodes
- Ignorning exceptions, the inner loop of a JVM looks like this:
atomically calc pc and fetch opcode at pc;
execute action for opcode;
} while( there is more to do);
- If operands are bigger than one byte, they are saved in big-endian order.
- Internally, the JVM does not handle
booleans. Instead, the compiler emits instructions
that operate on
store instructions push and pop data into and from the stack. The parameter for
the instruction is the index of a local variable. e.g.
iload 3 pushes the 4th local variable
in the frame to the stack.
- Comparisons between
double yield an integer, which is then tested using
one of the
int-specific instructions and the branching is performed.