byte // 1-byte signed 2's complement integer
short // 2-byte signed 2's complement integer
int // 4-byte signed 2's complement integer
long // 8-byte signed 2's complement integer
float // 4-byte IEEE 754 single-precision float
double // 8-byte IEEE 754 double-precision float
char // 2-byte unsigned Unicode character
Nearly all Java type checking is done at compile time. Data of the primitive types shown above need not be tagged by the hardware to allow execution of Java. Instead, the bytecodes that operate on primitive values indicate the types of the operands so that, for example, the iadd
, ladd
, fadd
, and dadd
instructions each add two numbers, whose types are int
, long
, float
, and double
, respectively
The virtual machine doesn't have separate instructions for boolean
types. Intead, integer instructions, including integer returns, are used to operate on boolean
values; byte
arrays are used for arrays of boolean
.
The virtual machine specifies that floating point be done in IEEE 754 format, with support for gradual underflow. Older computer architectures that do not have support for IEEE format may run Java numeric programs very slowly.
Other virtual machine data types include:
object // 4-byte reference to a Java object
returnAddress // 4 bytes, used with jsr/ret/jsr_w/ret_w instructions
Note: Java arrays are treated as objects.This specification does not require any particular internal structure for objects. In our implementation an object reference is to a handle, which is a pair of pointers: one to a method table for the object, and the other to the data allocated for the object. Other implementations may use inline caching, rather than method table dispatch; such methods are likely to be faster on hardware that is emerging between now and the year 2000.
Programs represented by Java Virtual Machine bytecodes are expected to maintain proper type discipline and an implementation may refuse to execute a bytecode program that appears to violate such type discipline.
While the Java Virtual Machines would appear to be limited by the bytecode definition to running on a 32-bit address space machine, it is possible to build a version of the Java Virtual Machine that automatically translates the bytecodes into a 64-bit form. A description of this transformation is beyond the scope of this specification.
pc
register contains the address of the next bytecode to be executed.Each method has memory space allocated for it to hold:
vars
register,
optop
register, and
frame
register.
All of these registers are 32 bits wide.
vars
register. Local variables are all 32 bits wide. Long integers and double precision floats are considered to take up two local variables but are addressed by the index of the first local variable. (For example, a local variable with index n containing a double precision float actually occupies storage at indices n and n+1.) The virtual machine specification does not require 64-bit values in local variables to be 64-bit aligned. Implementors are free to decide the appropriate way to divide long integers and double precision floats into two words.
Instructions are provided to load the values of local variables onto the operand stack and store values from the operand stack into local variables.
The operand stack is 32 bits wide. It is used to pass parameters to methods and receive method results, as well as to supply parameters for operations and save operation results.
For example, the iadd
instruction adds two integers together. It expects that the integers to be added are the top two words on the operand stack, pushed there by previous instructions. Both integers are popped from the stack, added, and their sum pushed back onto the operand stack. Subcomputations may be nested on the operand stack, and result in a single operand that can be used by the nesting computation.
Each primitive data type has specialized instructions that know how to operate on operands of that type. Each operand requires a single location on the stack, except for long
and double
, which require two locations.
Operands must be operated on by operators appropriate to their type. It is illegal, for example, to push two int
s and then treat them as a long
. This restriction is enforced, in the Sun implementation, by the bytecode verifier. However, a small number of operations (the dup
opcodes and swap
) operate on runtime data areas as raw values of a given width without regard to type.
In our description of the virtual machine instructions below, the effect of an instruction's execution on the operand stack is represented textually, with the stack growing from left to right, and each 32-bit word separately represented. Thus:
Stack: ...,shows an operation that begins by having value2 on top of the stack with value1 just beneath it. As a result of the execution of the instruction, value1 and value2 are popped from the stack and replaced by value3, which has been calculated by the instruction. The remainder of the stack, represented by an ellipsis, is unaffected by the instruction's execution.value1, value2 => ..., value3
The types long
and double
take two 32-bit words on the operand stack:
Stack: ... => ...,This specification does not say how the two words are selected from the 64-bitvalue-word1, value-word2
long
or double
value; it is only necessary that a particular implementation be internally consistent.
This late binding of the methods and variables makes changes in other classes that a method uses less likely to break this code.
The execution environment is used in this case to restore the registers of the caller, with the program counter of the caller appropriately incremented to skip the method call instruction. Execution then continues in the calling method's execution environment.
Error
or Exception
, which are subclasses of Throwable
, may arise in a program because of:
Thread.stop
, from another thread,
throw
statement.
catch
clause describes the instruction range for which it is active, describes the type of exception that it is to handle, and has the address of the code to handle it.
catch
clause if the instruction that caused the exception is in the appropriate instruction range, and the exception type is a subtype of the type of exception that the catch
clause handles. If a matching catch
clause is found, the system branches to the specified handler. If no handler is found, the process is repeated until all the nested catch clauses of the current method have been exhausted.
catch
clauses in the list is important. The virtual machine execution continues at the first matching catch clause. Because Java code is structured, it is always possible to sort all the exception handlers for one method into a single list that, for any possible program counter value, can be searched in linear order to find the proper (innermost containing applicable) exception handler for an exception occuring at that program counter value.
catch
clause then the current method is said to have as its outcome the uncaught exception. The execution state of the method that called this method is restored from the execution environment, and the propagation of the exception continues, as though the exception had just occurred in this caller.
The inner loop of the virtual machine execution is effectively:
do {
fetch an opcode byte
execute an action depending on the value of the opcode
} while (there is more to do);
The number and size of the additional operands is determined by the opcode. If an additional operand is more than one byte in size, then it is stored in big-endian order -- high order byte first. For example, a 16-bit parameter is stored as two bytes whose value is:
first_byte * 256 + second_byte
The bytecode instruction stream is only byte-aligned, with the exception being the tableswitch
and lookupswitch
instructions, which force alignment to a 4-byte boundary within their instructions.These decisions keep the virtual machine code for a compiled Java program compact and reflect a conscious bias in favor of compactness at some possible cost in performance.
The amount of code per method is limited to 65535 bytes by the sizes of the indices in the code in the exception table, the line number table, and the local variable table. This may be fixed for 1.0beta2.
Besides this limit, the only other limitation of note is that the number of words of arguments in a method call is limited to 255.