Brought to you by EarthWeb
IT Library Logo

Click Here!
Click Here!

nav

EarthWeb Direct

EarthWeb Direct

EarthWeb sites: other sites

appendix D

Bytecodes Reference


CONTENTS

Let's look at a (progressively less and less) detailed description of each class of bytecodes.

For each bytecode, some brief text describes its function and a textual "picture" of the stack, both before and after the bytecode has been executed, is shown. This text picture will look like the following:

..., value1, value2 => ..., value3

This means that the bytecode expects two operands-value1 and value2-to be on the top of the stack, pops them both off the stack, operates on them to produce value3, and pushes value3 back onto the top of the stack. You should read each stack from right to left, with the rightmost value being the top of the stack. The ... is read as "the rest of the stack below," which is irrelevant to the current bytecode. All operands on the stack are 32 bits wide.

Because most bytecodes take their arguments from the stack and place their results back there, the brief text descriptions that follow only say something about the source or destination of values if they are not on the stack. For example, the description "Load integer from local variable." means that the integer is loaded onto the stack, and "Integer add." intends its integers to be taken from-and the result returned to-the stack.

Bytecodes that don't affect control flow simply move the pc onto the next bytecode that follows in sequence. Those that do affect the pc say so explicitly. Whenever you see byte1, byte2, and so forth, it refers to the first byte, second byte, and so on, that follow the opcode byte itself. After such a bytecode is executed, the pc automatically advances over these operand bytes to start the next bytecode in sequence.

Note
The next few sections are in "reference manual style," presenting each bytecode separately in all its (often redundant) detail; each bytecode is presented as an operation followed by an explanation. Later sections begin to collapse and coalesce this verbose style into something shorter and more readable. The verbose form is shown at first because the online reference manuals will look more like it, and because it drives home the point that each bytecode "function" comes in many, nearly identical bytecodes, one for each primitive type in Java.

Pushing Constants onto the Stack

bipush        ... => ..., value

Push 1-byte signed integer. byte1 is interpreted as a signed 8-bit value. This value is expanded to an int and pushed onto the operand stack.

sipush        ... => ..., value

Push 2-byte signed integer. byte1 and byte2 are assembled into a signed 16-bit value. This value is expanded to an int and pushed onto the operand stack.

ldc1          ... => ..., item

Push item from constant pool. byte1 is used as an unsigned 8-bit index into the constant pool of the current class. The item at that index is resolved and pushed onto the stack.

ldc2          ... => ..., item

Push item from constant pool. byte1 and byte2 are used to construct an unsigned 16-bit index into the constant pool of the current class. The item at that index is resolved and pushed onto the stack.

ldc2w         ... => ..., constant-word1, constant-word2

Push long or double from constant pool. byte1 and byte2 are used to construct an unsigned 16-bit index into the constant pool of the current class. The two-word constant at that index is resolved and pushed onto the stack.

aconst_null   ... => ..., null

Push the null object reference onto the stack.

iconst_m1     ... => ..., -1

Push the int -1 onto the stack.

iconst_<I>    ... => ..., <I>

Push the int <I> onto the stack. There are six of these bytecodes, one for each of the integers 0-5: iconst_0, iconst_1, iconst_2, iconst_3, iconst_4, and iconst_5.

lconst_<L>    ... => ..., <L>-word1, <L>-word2

Push the long <L> onto the stack. There are two of these bytecodes, one for each of the integers 0 and 1: lconst_0 and lconst_1.

fconst_<F>    ... => ..., <F>

Push the float <F> onto the stack. There are three of these bytecodes, one for each of the integers 0-2: fconst_0, fconst_1, and fconst_2.

dconst_<D>    ... => ..., <D>-word1, <D>-word2

Push the double <D> onto the stack. There are two of these bytecodes, one for each of the integers 0 and 1: dconst_0, and dconst_1.

Loading Local Variables onto the Stack

iload         ... => ..., value

Load int from local variable. Local variable byte1 in the current Java frame must contain an int. The value of that variable is pushed onto the operand stack.

iload_<I>     ... => ..., value

Load int from local variable. Local variable <I> in the current Java frame must contain an int. The value of that variable is pushed onto the operand stack. There are four of these bytecodes, one for each of the integers 0-3: iload_0, iload_1, iload_2, and iload_3.

lload         ... => ..., value-word1, value-word2

Load long from local variable. Local variables byte1 and byte1 + 1 in the current Java frame must together contain a long integer. The values contained in those variables are pushed onto the operand stack.

lload_<L>     ... => ..., value-word1, value-word2

Load long from local variable. Local variables <L> and <L> + 1 in the current Java frame must together contain a long integer. The value contained in those variables is pushed onto the operand stack. There are four of these bytecodes, one for each of the integers 0-3: lload_0, lload_1, lload_2, and lload_3.

fload         ... => ..., value

Load float from local variable. Local variable byte1 in the current Java frame must contain a single-precision floating-point number. The value of that variable is pushed onto the operand stack.

fload_<F>     ... => ..., value

Load float from local variable. Local variable <F> in the current Java frame must contain a single-precision floating-point number. The value of that variable is pushed onto the operand stack. There are four of these bytecodes, one for each of the integers 0-3: fload_0, fload_1, fload_2, and fload_3.

dload         ... => ..., value-word1, value-word2

Load double from local variable. Local variables byte1 and byte1 + 1 in the current Java frame must together contain a double-precision floating-point number. The value contained in those variables is pushed onto the operand stack.

dload_<D>     ... => ..., value-word1, value-word2

Load double from local variable. Local variables <D> and <D> + 1 in the current Java frame must together contain a double-precision floating-point number. The value contained in those variables is pushed onto the operand stack. There are four of these bytecodes, one for each of the integers 0-3: dload_0, dload1, dload_2, and dload_3.

aload         ... => ..., value

Load object reference from local variable. Local variable byte1 in the current Java frame must contain a return address or reference to an object or array. The value of that variable is pushed onto the operand stack.

aload_<A>     ... => ..., value

Load object reference from local variable. Local variable <A> in the current Java frame must contain a return address or reference to an object. The value of that variable is pushed onto the operand stack. There are four of these bytecodes, one for each of the integers 0-3: aload_0, aload_1, aload_2, and aload_3.

Storing Stack Values into Local Variables

istore        ..., value => ...

Store int into local variable. value must be an int. Local variable byte1 in the current Java frame is set to value.

istore_<I>    ..., value => ...

Store int into local variable. value must be an int. Local variable <I> in the current Java frame is set to value. There are four of these bytecodes, one for each of the integers 0-3: istore_0, istore_1, istore_2, and istore_3.

lstore        ..., value-word1, value-word2 => ...

Store long into local variable. value must be a long integer. Local variables byte1 and byte1 + 1 in the current Java frame are set to value.

lstore_<L>    ..., value-word1, value-word2 => ...

Store long into local variable. value must be a long integer. Local variables <L> and <L> + 1 in the current Java frame are set to value. There are four of these bytecodes, one for each of the integers 0-3: lstore_0, lstore_1, lstore_2, and lstore_3.

fstore        ..., value => ...

Store float into local variable. value must be a single-precision floating-point number. Local variable byte1 in the current Java frame is set to value.

fstore_<F>    ..., value => ...

Store float into local variable. value must be a single-precision floating-point number. Local variable <F> in the current Java frame is set to value. There are four of these bytecodes, one for each of the integers 0-3: fstore_0, fstore_1, fstore_2, and fstore_3.

dstore        ..., value-word1, value-word2 => ...

Store double into local variable. value must be a double-precision floating-point number. Local variables byte1 and byte1 + 1 in the current Java frame are set to value.

dstore_<D>    ..., value-word1, value-word2 => ...

Store double into local variable. value must be a double-precision floating-point number. Local variables <D> and <D> + 1 in the current Java frame are set to value. There are four of these bytecodes, one for each of the integers 0-3: dstore_0, dstore_1, dstore_2, and dstore_3.

astore        ..., handle => ...

Store object reference into local variable. handle must be a return address or a reference to an object. Local variable byte1 in the current Java frame is set to value.

astore_<A>    ..., handle => ...

Store object reference into local variable. handle must be a return address or a reference to an object. Local variable <A> in the current Java frame is set to value. There are four of these bytecodes, one for each of the integers 0-3: astore_0, astore_1, astore_2, and astore_3.

iinc          -no change-

Increment local variable by constant. Local variable byte1 in the current Java frame must contain an int. Its value is incremented by the value byte2, where byte2 is treated as a signed 8-bit quantity.

Managing Arrays

newarray        ..., size => result

Allocate new array. size must be an int; it represents the number of elements in the new array. byte1 is an internal code that indicates the type of array to allocate. Possible values for byte1 are as follows: T_BOOLEAN (4), T_chAR (5), T_FLOAT (6), T_DOUBLE (7), T_BYTE (8), T_SHORT (9), T_INT (10), and T_LONG (11).

An attempt is made to allocate a new array of the indicated type, capable of holding size elements. This will be the result. If size is less than zero, a NegativeArraySizeException is thrown. If there is not enough memory to allocate the array, an OutOfMemoryError is thrown. All elements of the array are initialized to their default values.

anewarray       ..., size => result

Allocate new array of objects. size must be an int; it represents the number of elements in the new array. byte1 and byte2 are used to construct an index into the constant pool of the current class. The item at that index is resolved. The resulting entry must be a class.

An attempt is made to allocate a new array of the indicated class type, capable of holding size elements. This will be the result. If size is less than 0, a NegativeArraySizeException is thrown. If there is not enough memory to allocate the array, an OutOfMemoryError is thrown. All elements of the array are initialized to null.

Note
anewarray is used to create a single dimension of an array of objects. For example, the request new Thread[7] generates the following bytecodes:
    bipush 7
    anewarray <Class "java.lang.Thread">
anewarray can also be used to create the outermost dimension of a multidimensional array. For example, the array declaration new int[6][] generates this:
    bipush 6
    anewarray <Class "[I">
(See the section "Method Signatures" for more information on strings such as "[I".)

multianewarray  ..., size1 size2...sizeN => result

Allocate new multidimensional array. Each size<I> must be an int; each represents the number of elements in a dimension of the array. byte1 and byte2 are used to construct an index into the constant pool of the current class. The item at that index is resolved. The resulting entry must be an array class of one or more dimensions.

byte3 is a positive integer representing the number of dimensions being created. It must be less than or equal to the number of dimensions of the array class. byte3 is also the number of elements that are popped off the stack. All must be ints greater than or equal to zero. These are used as the sizes of the dimensions. An attempt is made to allocate a new array of the indicated class type, capable of holding size<1> * size<2> * ... * <sizeN> elements. This will be the result. If any of the size<I> arguments on the stack is less than zero, a NegativeArraySizeException is thrown. If there is not enough memory to allocate the array, an OutOfMemoryError is thrown.

Note
new int[6][3][] generates these bytecodes:
    bipush 6
    bipush 3
    multianewarray <Class "[[[I"> 2
It's more efficient to use newarray or anewarray when creating arrays of single dimension.

arraylength     ..., array => ..., length

Get length of array. array must be a reference to an array object. The length of the array is determined and replaces array on the top of the stack. If array is null, a NullPointerException is thrown.

iaload          ..., array, index => ..., value
laload          ..., array, index => ..., value-word1, value-word2
faload          ..., array, index => ..., value
daload          ..., array, index => ..., value-word1, value-word2
aaload          ..., array, index => ..., value
baload          ..., array, index => ..., value
caload          ..., array, index => ..., value
saload          ..., array, index => ..., value

Load <type> from array. array must be an array of <type>s. index must be an int. The <type> value at position number index in array is retrieved and pushed onto the top of the stack. If array is null, a NullPointerException is thrown. If index is not within the bounds of array, an ArrayIndexOutOfBoundsException is thrown. <type> is, in turn, int, long, float, double, object reference, byte, char, and short. <type>s long and double have two word values, as you've seen in previous load bytecodes.

iastore         ..., array, index, value => ...
lastore         ..., array, index, value-word1, value-word2 => ...
fastore         ..., array, index, value => ...
dastore         ..., array, index, value-word1, value-word2 => ...
aastore         ..., array, index, value => ...
bastore         ..., array, index, value => ...
castore         ..., array, index, value => ...
sastore         ..., array, index, value => ...

Store into <type> array. array must be an array of <type>s, index must be an int, and value a <type>. The <type> value is stored at position index in array. If array is null, a NullPointerException is thrown. If index is not within the bounds of array, an ArrayIndexOutOfBoundsException is thrown. <type> is, in turn, int, long, float, double, object reference, byte, char, and short. <type>s long and double have two word values, as you've seen in previous store bytecodes.

Stack Operations

nop        -no change-

Do nothing.

pop        ..., any => ...

Pop the top word from the stack.

pop2       ..., any2, any1 => ...

Pop the top two words from the stack.

dup        ..., any => ..., any, any

Duplicate the top word on the stack.

dup2       ..., any2, any1 => ..., any2, any1, any2,any1

Duplicate the top two words on the stack.

dup_x1     ..., any2, any1 => ..., any1, any2,any1

Duplicate the top word on the stack and insert the copy two words down in the stack.

dup2_x1    ..., any3, any2, any1 => ..., any2, any1, any3,any2,any1

Duplicate the top two words on the stack and insert the copies two words down in the stack.

dup_x2     ..., any3, any2, any1 => ..., any1, any3,any2,any1

Duplicate the top word on the stack and insert the copy three words down in the stack.

dup2_x2    ..., any4, any3, any2, any1 => ..., any2, any1, any4,any3,any2,any1

Duplicate the top two words on the stack and insert the copies three words down in the stack.

swap       ..., any2, any1 => ..., any1, any2

Swap the top two elements on the stack.

Arithmetic Operations

iadd       ..., v1, v2 => ..., result
ladd       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2
fadd       ..., v1, v2 => ..., result
dadd       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2

v1 and v2 must be <type>s. The vs are added and are replaced on the stack by their <type> sum. <type> is, in turn, int, long, float, and double.

isub       ..., v1, v2 => ..., result
lsub       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2
fsub       ..., v1, v2 => ..., result
dsub       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2

v1 and v2 must be <type>s. v2 is subtracted from v1, and both vs are replaced on the stack by their <type> difference. <type> is, in turn, int, long, float, and double.

imul       ..., v1, v2 => ..., result
lmul       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2
fmul       ..., v1, v2 => ..., result
dmul       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2

v1 and v2 must be <type>s. Both vs are replaced on the stack by their <type> product. <type> is, in turn, int, long, float, and double.

idiv       ..., v1, v2 => ..., result
ldiv       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2
fdiv       ..., v1, v2 => ..., result
ddiv       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2

v1 and v2 must be <type>s. v2 is divided by v1, and both vs are replaced on the stack by their <type> quotient. An attempt to divide by zero results in an ArithmeticException being thrown. <type> is, in turn, int, long, float, and double.

irem       ..., v1, v2 => ..., result
lrem       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2
frem       ..., v1, v2 => ..., result
drem       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2

v1 and v2 must be <type>s. v2 is divided by v1, and both vs are replaced on the stack by their <type> remainder. An attempt to divide by zero results in an ArithmeticException being thrown. <type> is, in turn, int, long, float, and double.

ineg       ..., value => ..., result
lneg       ..., value-word1, value-word2 => ..., result-word1, result-word2
fneg       ..., value => ..., result
dneg       ..., value-word1, value-word2 => ..., result-word1, result-word2

value must be a <type>. It is replaced on the stack by its arithmetic negation. <type> is, in turn, int, long, float, and double.

Note
Now that you're familiar with the look of the bytecodes, the summaries that follow will become shorter and shorter (for space reasons). You can always get any desired level of detail from the full virtual machine specification in the latest Java release.

Logical Operations

ishl       ..., v1, v2 => ..., result
lshl       ..., v1-word1, v1-word2, v2 => ..., r-word1, r-word2
ishr       ..., v1, v2 => ..., result
lshr       ..., v1-word1, v1-word2, v2 => ..., r-word1, r-word2
iushr      ..., v1, v2 => ..., result
lushr      ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2

For types int and long: arithmetic shift left, shift right, and logical shift right.

iand       ..., v1, v2 => ..., result
land       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2
ior        ..., v1, v2 => ..., result
lor        ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2
ixor       ..., v1, v2 => ..., result
lxor       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., r-word1, r-word2

For types int and long: bitwise AND, OR, and XOR.

Conversion Operations

i2l         ..., value => ..., result-word1, result-word2
i2f         ..., value => ..., result
i2d         ..., value => ..., result-word1, result-word2
l2i         ..., value-word1, value-word2 => ..., result
l2f         ..., value-word1, value-word2 => ..., result
l2d         ..., value-word1, value-word2 => ..., result-word1, result-word2
f2i         ..., value => ..., result
f2l         ..., value => ..., result-word1, result-word2
f2d         ..., value => ..., result-word1, result-word2
d2i         ..., value-word1, value-word2 => ..., result
d2l         ..., value-word1, value-word2 => ..., result-word1, result-word2
d2f         ..., value-word1, value-word2 => ..., result

int2byte    ..., value => ..., result
int2char    ..., value => ..., result
int2short   ..., value => ..., result

These bytecodes convert from a value of type <lhs> to a result of type <rhs>. <lhs> and <rhs> can be any of i, l, f, and d, which represent int, long, float, and double, respectively. The final three bytecodes convert types that are self-explanatory.

Transfer of Control

ifeq        ..., value => ...
ifne        ..., value => ...
iflt        ..., value => ...
ifgt        ..., value => ...
ifle        ..., value => ...
ifge        ..., value => ...

if_icmpeq   ..., value1, value2 => ...
if_icmpne   ..., value1, value2 => ...
if_icmplt   ..., value1, value2 => ...
if_icmpgt   ..., value1, value2 => ...
if_icmple   ..., value1, value2 => ...
if_icmpge   ..., value1, value2 => ...

ifnull      ..., value => ...
ifnonnull   ..., value => ...

When value <rel> 0 is true in the first set of bytecodes, value1 <rel> value2 is true in the second set, or value is null (or not null) in the third, byte1 and byte2 are used to construct a signed 16-bit offset. Execution proceeds at that offset from the pc. Otherwise, execution proceeds at the bytecode following. <rel> is one of eq, ne, lt, gt, le, and ge, which represent equal, not equal, less than, greater than, less than or equal, and greater than or equal, respectively.

lcmp        ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., result

fcmpl       ..., v1, v2 => ..., result
dcmpl       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., result

fcmpg       ..., v1, v2 => ..., result
dcmpg       ..., v1-word1, v1-word2, v2-word1, v2-word2 => ..., result

v1 and v2 must be long, float, or double. They are both popped from the stack and compared. If v1 is greater than v2, the int value 1 is pushed onto the stack. If v1 is equal to v2, 0 is pushed onto the stack. If v1 is less than v2, -1 is pushed onto the stack. For floating-point, if either v1 or v2 is NaN, -1 is pushed onto the stack for the first pair of bytecodes, +1 for the second pair.

if_acmpeq   ..., value1, value2 => ...
if_acmpne   ..., value1, value2 => ...

Branch if object references are equal/not equal. value1 and value2 must be references to objects. They are both popped from the stack. If value1 is equal/not equal to value2, byte1 and byte2 are used to construct a signed 16-bit offset. Execution proceeds at that offset from the pc. Otherwise, execution proceeds at the bytecode following.

goto        -no change-
goto_w      -no change-

Branch always. byte1 and byte2 (plus byte3 and byte4 for goto_w) are used to construct a signed 16-bit (32-bit) offset. Execution proceeds at that offset from the pc.

jsr         ... => ..., return-address
jsr-w       ... => ..., return-address

Jump subroutine. The address of the bytecode immediately following the jsr is pushed onto the stack. byte1 and byte2 (plus byte3 and byte4 for goto_w) are used to construct a signed 16-bit (32-bit) offset. Execution proceeds at that offset from the pc.

ret         -no change-
ret2_w      -no change-

Return from subroutine. Local variable byte1 (plus byte2 for ret_w are assembled into a 16-bit index) in the current Java frame must contain a return address. The contents of that local variable are written into the pc.

Note
jsr pushes the address onto the stack, and ret gets it out of a local variable. This asymmetry is intentional. The jsr and ret bytecodes are used in the implementation of Java's finally keyword.

Method Return

return      ... => [empty]q

Return (void) from method. All values on the operand stack are discarded. The interpreter then returns control to its caller.

ireturn     ..., value => [empty]
lreturn     ..., value-word1, value-word2 => [empty]
freturn     ..., value => [empty]
dreturn     ..., value-word1, value-word2 => [empty]
areturn     ..., value => [empty]

Return <type> from method. value must be a <type>. The value is pushed onto the stack of the previous execution environment. Any other values on the operand stack are discarded. The interpreter then returns control to its caller. <type> is, in turn, int, long, float, double, and object reference.

Note
The stack behavior of the "return" bytecodes may be confusing to anyone expecting the Java operand stack to be just like the C stack. Java's operand stack actually consists of a number of noncontiguous segments, each corresponding to a method call. A return bytecode empties the Java operand stack segment corresponding to the frame of the returning call, but does not affect the segment of any parent calls.

Table Jumping

tableswitch   ..., index => ...

tableswitch is a variable-length bytecode. Immediately after the tableswitch opcode, zero to three 0 bytes are inserted as padding so that the next byte begins at an address that is a multiple of four. After the padding are a series of signed 4-byte quantities: default-offset, low, high, and then (high - low + 1) further signed 4-byte offsets. These offsets are treated as a 0-based jump table.

The index must be an int. If index is less than low or index is greater than high, default-offset is added to the pc. Otherwise, the (index - low)th element of the jump table is extracted and added to the pc.

lookupswitch  ..., key => ...

lookupswitch is a variable-length bytecode. Immediately after the lookupswitch opcode, zero to three 0 bytes are inserted as padding so that the next byte begins at an address that is a multiple of four. Immediately after the padding is a series of pairs of signed 4-byte quantities. The first pair is special; it contains the default-offset and the number of pairs that follow. Each subsequent pair consists of a match and an offset.

The key on the stack must be an int. This key is compared to each of the matches. If it is equal to one of them, the corresponding offset is added to the pc. If the key does not match any of the matches, the default-offset is added to the pc.

Manipulating Object Fields

putfield      ..., handle, value => ...
putfield      ..., handle, value-word1, value-word2 => ...

Set field in object. byte1 and byte2 are used to construct an index into the constant pool of the current class. The constant pool item is a field reference to a class name and a field name. The item is resolved to a field block pointer containing the field's width and offset (both in bytes).

The field at that offset from the start of the instance pointed to by handle will be set to the value on the top of the stack. The first stack picture is for 32-bit, and the second for 64-bit-wide fields. This bytecode handles both. If handle is null, a NullPointerException is thrown. If the specified field is a static field, an IncompatibleClassChangeError is thrown.

getfield      ..., handle => ..., value
getfield      ..., handle => ..., value-word1, value-word2

Fetch field from object. byte1 and byte2 are used to construct an index into the constant pool of the current class. The constant pool item will be a field reference to a class name and a field name. The item is resolved to a field block pointer containing the field's width and offset (both in bytes).

handle must be a reference to an object. The value at offset into the object referenced by handle replaces handle on the top of the stack. The first stack picture is for 32-bit, and the second for 64-bit-wide fields. This bytecode handles both. If the specified field is a static field, an IncompatibleClassChangeError is thrown.

putstatic     ..., value => ...
putstatic     ..., value-word1, value-word2 => ...

Set static field in class. byte1 and byte2 are used to construct an index into the constant pool of the current class. The constant pool item will be a field reference to a static field of a class. That field will be set to have the value on the top of the stack. The first stack picture is for 32-bit, and the second for 64-bit-wide fields. This bytecode handles both. If the specified field is not a static field, an IncompatibleClassChangeError is thrown.

getstatic     ..., => ..., value_
getstatic     ..., => ..., value-word1, value-word2

Get static field from class. byte1 and byte2 are used to construct an index into the constant pool of the current class. The constant pool item will be a field reference to a static field of a class. The value of that field is placed on the top of the stack. The first stack picture is for 32-bit, and the second for 64-bit-wide fields. This bytecode handles both. If the specified field is not a static field, an IncompatibleClassChangeError is thrown.

Method Invocation

invokevirtual     ..., handle, [arg1, [arg2, ...]], ... => ...

Invoke instance method based on runtime type. The operand stack must contain a reference to an object and some number of arguments. byte1 and byte2 are used to construct an index into the constant pool of the current class. The item at that index in the constant pool contains the complete method signature. A pointer to the object's method table is retrieved from the object reference. The method signature is looked up in the method table. The method signature is guaranteed to exactly match one of the method signatures in the table.

The result of the lookup is an index into the method table of the named class that's used to look in the method table of the object's runtime type, where a pointer to the method block for the matched method is found. The method block indicates the type of method (native, synchronized, and so on) and the number of arguments (nargs) expected on the operand stack.

If the method is marked synchronized, the monitor associated with handle is entered.

The base of the local variables array for the new Java stack frame is set to point to handle on the stack, making handle and the supplied arguments (arg1, arg2, and so on) the first nargs local variables of the new frame. The total number of local variables used by the method is determined, and the execution environment of the new frame is pushed after leaving sufficient room for the locals. The base of the operand stack for this method invocation is set to the first word after the execution environment. Finally, execution continues with the first bytecode of the matched method.

If handle is null, a NullPointerException is thrown. If during the method invocation a stack overflow is detected, a StackOverflowError is thrown.

invokenonvirtual  ..., handle, [arg1, [arg2, ...]], ... => ...

Invoke instance method based on compile-time type. The operand stack must contain a reference (handle) to an object and some number of arguments. byte1 and byte2 are used to construct an index into the constant pool of the current class. The item at that index in the constant pool contains the complete method signature and class. The method signature is looked up in the method table of the class indicated. The method signature is guaranteed to exactly match one of the method signatures in the table.

The result of the lookup is a method block. The method block indicates the type of method (native, synchronized, and so on) and the number of arguments (nargs) expected on the operand stack. (The last three paragraphs are identical to the previous bytecode.)

invokestatic      ..., , [arg1, [arg2, ...]], ... => ...

Invoke class (static) method. The operand stack must contain some number of arguments. byte1 and byte2 are used to construct an index into the constant pool of the current class. The item at that index in the constant pool contains the complete method signature and class. The method signature is looked up in the method table of the class indicated. The method signature is guaranteed to match one of the method signatures in the class's method table exactly.

The result of the lookup is a method block. The method block indicates the type of method (native, synchronized, and so on) and the number of arguments (nargs) expected on the operand stack.

If the method is marked synchronized, the monitor associated with the class is entered. (The last two paragraphs are identical to those in invokevirtual, except that no NullPointerException can be thrown.)

invokeinterface   ..., handle, [arg1, [arg2, ...]], ...=> ...

Invoke interface method. The operand stack must contain a reference (handle) to an object and some number of arguments. byte1 and byte2 are used to construct an index into the constant pool of the current class. The item at that index in the constant pool contains the complete method signature. A pointer to the object's method table is retrieved from the object reference. The method signature is looked up in the method table. The method signature is guaranteed to exactly match one of the method signatures in the table.

The result of the lookup is a method block. The method block indicates the type of method (native, synchronized, and so on) but, unlike the other "invoke" bytecodes, the number of available arguments (nargs) is taken from byte3; byte4 is reserved for future use. (The last three paragraphs are identical to those in invokevirtual.)

Exception Handling

Sathrow            ..., handle => [undefined]

Throw exception. handle must be a handle to an exception object. That exception, which must be an instance of Throwable (or a subclass), is thrown. The current Java stack frame is searched for the most recent catch clause that handles the exception. If a matching "catch list" entry is found, the pc is reset to the address indicated by the catch-list pointer, and execution continues there.

If no appropriate catch clause is found in the current stack frame, that frame is popped and the exception is rethrown, starting the process all over again in the parent frame. If handle is null, a NullPointerException is thrown instead.

Miscellaneous Object Operations

new               ... => ..., handle

Create new object. byte1 and byte2 are used to construct an index into the constant pool of the current class. The item at that index should be a class name that can be resolved to a class pointer. A new instance of that class is then created and a reference (handle) for the instance is placed on the top of the stack.

checkcast         ..., handle => ..., [handle | ...]

Make sure object is of given type. handle must be a reference to an object. byte1 and byte2 are used to construct an index into the constant pool of the current class. The string at that index of the constant pool is presumed to be a class name that can be resolved to a class pointer.

checkcast determines whether handle can be cast to a reference to an object of that class. (A null handle can be cast to any class.) If handle can be legally cast, execution proceeds at the next bytecode, and the handle remains on the stack. If not, a ClassCastException is thrown and the stack is emptied.

instanceof        ..., handle => ..., result

Determine whether object is of given type. handle must be a reference to an object. byte1 and byte2 are used to construct an index into the constant pool of the current class. The string at that index of the constant pool is presumed to be a class name that can be resolved to a class pointer.

If handle is null, the result is 0 (false). Otherwise, instanceof determines whether handle can be cast to a reference to an object of that class. The result is 1 (true) if it can, and 0 (false) otherwise.

Monitors

monitorenter      ..., handle => ...

Enter monitored region of code. handle must be a reference to an object. The interpreter attempts to obtain exclusive access via a lock mechanism to handle. If another thread already has handle locked, the current thread waits until the handle is unlocked. If the current thread already has handle locked, execution continues normally. If handle has no lock on it, this bytecode obtains an exclusive lock. (A null in either bytecode throws NullPointerException.)

Smonitorexit       ..., handle => ...

Exit monitored region of code. handle must be a reference to an object. The lock on handle is released. If this is the last lock that this thread has on that handle (one thread is allowed to have multiple locks on a single handle), other threads that are waiting for handle are allowed to proceed. (A null in either bytecode throws NullPointerException.)

Debugging

breakpoint        -no change-

Call breakpoint handler. The breakpoint bytecode is used to overwrite a bytecode to force control temporarily back to the debugger prior to the effect of the overwritten bytecode. The original bytecode's operands (if any) are not overwritten, and the original bytecode is restored when the breakpoint bytecode is removed.

The _quick Bytecodes

The following discussion, straight out of the Java virtual machine documentation, shows you an example of the cleverness mentioned earlier that's needed to make a bytecode interpreter fast:

The following set of pseudo-bytecodes, suffixed by _quick, are all variants of standard Java bytecodes. They are used by the runtime to improve the execution speed of the bytecode interpreter. They aren't officially part of the virtual machine specification and are invisible outside a Java virtual machine implementation. However, inside that implementation they have proven to be an effective op-timization.
First, you should know that the javac Java compiler still generates only non-_quick bytecodes. Second, all bytecodes that have a _quick variant reference the constant pool. When _quick optimization is turned on, each non-_quick bytecode (that has a _quick variant) resolves the specified item in the constant pool, signals an error if the item in the constant pool could not be resolved for some reason, turns itself into the _quick variant of itself, and then performs its intended operation.
This is identical to the actions of the non-_quick bytecode, except for the step of overwriting itself with its _quick variant. The _quick variant of a bytecode assumes that the item in the constant pool has already been resolved, and that this resolution did not produce any errors. It simply performs the intended operation on the resolved item.

Thus, as your bytecodes are being interpreted, they are automatically getting faster and faster! Here are all the _quick variants in the current Java runtime:

ldc1_quick
ldc2_quick
ldc2w_quick

anewarray_quick
multinewarray_quick

putfield_quick
putfield2_quick
getfield_quick
getfield2_quick
putstatic_quick
putstatic2_quick
getstatic_quick
getstatic2_quick

invokevirtual_quick
invokevirtualobject_quick
invokenonvirtual_quick
invokestatic_quick
invokeinterface_quick

new_quick
checkcast_quick
instanceof_quick

If you'd like to go back in this appendix and look at what each of these does, you can find the name of the original bytecode on which a _quick variant is based simply by removing the _quick from its name. The bytecodes putstatic, getstatic, putfield, and getfield have two _quick variants each, one for each stack picture in their original descriptions. invokevirtual has two variants: one for objects and one for arrays (to do fast lookups in java.lang.Object).

Note
One last note on the _quick optimization, regarding the unusual handling of the constant pool (for detail fanatics only): When a class is read in, an array constant_pool[] of size nconstants is created and assigned to a field in the class. constant_pool[0] is set to point to a dynamically allocated array that indicates which fields in the constant_pool have already been resolved. Constant_pool[1] through constant_pool[nconstants - 1] are set to point at the "type" field that corresponds to this constant item.
When a bytecode is executed that references the constant pool, an index is generated, and constant_pool[0] is checked to see whether the index has already been resolved. If so, the value of constant_pool[index] is returned. If not, the value of constant_pool[index] is resolved to be the actual pointer or data, and overwrites whatever value was already in constant_pool[index].


footer nav
Use of this site is subject certain Terms & Conditions.
Copyright (c) 1996-1999 EarthWeb, Inc.. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Please read our privacy policy for details.