Home : Course Map : Chapter 2 : Java : Supplements :
JVM Instruction Set : Part 1
JavaTech
Course Map
Chapter 2

Introduction
Essentials
Structure

Keywords
Primitive Types
Comments
Literals
Expressions
Operators
Statements
Casts & Mixing
Strings
Console Output 
   Demo
Exercises

    Supplements
Conditional: if-else
Repetitions
Flow Control

Java vs C/C++
JVM Instructions 1

     About JavaTech
     Codes List
     Exercises
     Feedback
     References
     Resources
     Tips
     Topic Index
     Course Guide
     What's New

In Chapter 1: Supplements : The JVM we gave an example of a Java class file in bytecode format using output from the javap tool. Here we will look at the instructions of the JVM that relate to the primitive data type and arithmetic topics discussed in the Java and Tech sections of this chapter. After the introduction to classes and arrays in later chapters, we will discuss the instructions that involve these structures in Chapter 5: Supplements : JVM Instructions Part 2 .

Opcodes & Data Types

The one byte instruction word in the Java Virtual Machine provides for up to 256 instructions but the bytecode currently only uses 200 of these in the class files plus 25 so-called "quick" commands that the JVM can use internally. New instructions may be added later.

Below we group the instructions according to their general operation and list them under their opcode mnemonic name. For example, the instruction code 0x04(4) is referred to by the opcode iconst_1, which pushes the integer value 1 onto the operand stack.

Recall that the JVM uses stacks (last-in-first-out memory buffers) rather than registers for the bytecode operations. It also loads/stores data values from/to a cache, usually referred to as the heap, that holds field values.

The i in iconst_1 indicates an operation involving an integer. As discussed in Chapter 2: Java Primitive Types, Java is a strongly typed language and so all data values must maintain a clear type identification. The opcodes reflect this design and many instructions differ only in the type of operands involved.

For example, all the following instructions push the value of 1 onto the stack but differ according to the type of the value:

  • iconst_1 pushes int 1 onto the stack
  • lconst_1 pushes long 1 onto the stack
  • fconst_1 pushes float 1.0 onto the stack
  • dconst_1 pushes double 1.0 onto the stack

Note that the long and double values require two of the 32 bit wide words on the stack.

The opcodes, however, are not completely symmetric with respect to types. For example, there are six of the int type constant value instructions for pushing values 0 (iconst_0) through 5 (iconst_5) onto the stack but only two such instructions for long type (lconst_0, lconst_1), three for float (fconst_0, fconst_1, fconst_2) and two for double (dconst_0, dconst_1).

This asymmetry comes from the designers wishing to conserve the finite number of instructions available and from the fact that the integer operations occur more frequently on average.

In the instructions below, the following letters indicate the particular data types:

  • i = int
  • l = long
  • f = float
  • d = double
  • b = byte
  • c = char
  • s = short
  • a = reference (for accessing objects - see Chapter 3.)

Arithmetic Opcodes

Each of the addition instructions - iadd, ladd, fadd, dadd - pops the top two operands from the stack, adds them, and then pushes the result on top of the stack. The data type of the operands and that of the instruction must match.

In the diagram below, val1 represents a 32 bit wide value on top of the stack and val2 represents the second value from the top. For the iadd instruction, the two operands must each contain an integer data type. The operation results in val1 holding the sum of the two values.

Stack Before operation Stack After

val1

val2

....
xadd
for
x
= i
or
x = f

val1 = sum

....
....

 

A fadd operation works in a similar manner except that the operands and sum will be float type values

The long and double operations expect the top two 32 bit words to hold the first operand and the third and fourth words to hold the second operand. Java follows a big-endian representation (most significant byte is at lowest memory address) so the first bytes (in the table called the hi segment) are the most significant.

Stack Before operation Stack Before

val1.hi

val1.lo
val2.hi
val2.lo
....
xadd
for
x
= l
or
x = d
val1.hi=sum.hi
val2.lo=sum.lo
....
....

...

 

Note that the JVM keeps track of the data types on the stack. So, for example, you cannot push two int values onto the stack and then treat them as a single long or double value. In the above case, you cannot push four int values onto the stack and then add them with the ladd or dadd.

The other arithmetic operations follow a similar pattern:

Arithmetic Operations

Addition:

iadd, ladd, fadd, dadd
val1 + val2 => val1

Subtraction:

isub, lsub, fsub, dsub
val1 - val2 => val1

Multiplication:

imul, lmul, fmul, dmul
val1 * val2 => val1

Division:

idiv, ldiv, fdiv, ddiv
val1 / val2 => val1

Remainder:

irem, lrem, frem, drem
Remainder of val1/val2 => val1

Negate:

ineg, lneg, fneg, dneg
-val1 => val1

Local variable increment:

iinc
Exception to the rule that operands come from the stack . In this case, the next byte after the instruction provides an index to a local variable and the byte after that gives the amount to add to that local variable. No change to the stack occurs.

When wide is placed in front of iinc, it extends the increment's range from 8 bits to 16 bits.

See Java language arithmetic operators in Chapter 2: Java : Operators and also Increment & Decrement operators.

 

More notes on arithmetic instructions:

  • As discussed in Chapter 2: Tech : Floating Point Part 2, invalid FP operations such as a divide by zero do not produce an error condition. Instead, the result receives a special value, as in NaN for the zero divide case. See that section for the values that result for these exceptional cases.

  • On the stack, byte, char and short values reside in the 32 bit wide words, though the JVM keeps track of what type each word represents. So no particular speedup in the integer arithmetic instructions comes with using a more narrow data type. On the heap, however, the JVM can save space by storing the data according to its particular width.

The following Bit and Comparison instructions, while not arithmetic, also result in a new numerical value.

Bit Instructions

As with the other arithmetic operations, the bit instructions replace val1 and val2 with the result in val1.

Shift:

ishl
    Shift val1 left by val2 bits using the value in the lowest 5 bits of val2.

ishr

    Shift val1 right by val2 bits using the value in the lowest 5 bits of val2
    The upper bits are filled with the sign value.

iushr

      Same as ishr but fills left bits with zero.

lshl
, lshr, lushr

      Same as above except val1 is a long value and 6 bits of int val2 are used.

Bitwise OR:

ior
      Logical OR of bits in val1 and val2 for integer types.
lor
      Logical OR of bits in val1 and val2 for long types.

Bitwise AND:

iand
      Logical AND of bits in val1 and val2 for integer types
land
      Logical AND of bits in val1 and val2 for long types

Bitwise exclusive OR:

ixor
      Logical XOR of bits in val1 and val2 for integer types
lxor
      Logical XOR of bits in val1 and val2 for long types

The Java language equivalents can be seen at Chapter 2: Java : Operators : Boolean and Bitwise Operators.

 

Comparisons

In all cases below, the operation replaces val1 & val2 with result in an integer val1.

dcmpg
 Comparison of double values val1 and val2 results in an int val1 equal to
      0 if val1 == val2
      1 if va1 < val2
     -1 if val1 > val2
      1 if either val1 or val2 equal NaN.


dcmpl
Same as dcmpg except val1 = -1 if either val1 or val2 equal NaN.

fcmpg, fcmpl
Same as corresponding dcmpg,dcmpl except with float type values.

lcmp
Comparison of long values val1 and val2 results in an int val1 equal to
      0 if val1 == val2
      1 if va1 < val2
     -1 if val1 > val2

  
 

The Java language equivalents can be seen at Chapter 2: Java : Operators : Comparison.

 

More Opcodes

We list here more of the JVM opcodes, concentrating on those that carry out the Java language operations discussed in the Java track of this chapter. In Chapter 5: Supplements : Java Instructions Part 2 we concentrate on the instructions that deal with object handling.

As above, val1 and val2 correspond to the top two values on the stack. A val1 or val2 corresponds to one 32 bit word for an integer data type and two 32 bit words for one long data type.

Conversion Instructions

These instructions convert val1 from one type to another. In the form x2y, val1 of type x becomes converted to val1 of type y.

  • Widening:
    i2l, i2f, i2d, l2f, l2d
    , f2d


  • Narrowing:
    i2b, i2c, i2s, l2i, f2i, f2l, d2i, d2l, d2f

See Chapter 2: Java : Casts & Mixing Primitive Types and Chapter 2: More Casting & Mixing for discussions of conversions among data types in the Java language.

 

Flow Control Instructions

In all cases below, the stack values (either one or two values depending on the instruction) are popped off and no new stack value created. The <label> symbols represents an address (actually an offset relative to the current instruction) in the bytecode itself, not a stack value.

Conditional branch:

ifXX <label>
val1 is popped off the stack and compared to zero according to the XX test. If val1 satisfies XX, the process jumps to the instruction at the bytecode address indicated by <label>.

ifeq: jump if val1 == 0
iflt: jump if val1 <  0
ifle:
jump if val1 <= 0
ifne:
jump if val1 != 0
ifgt:
jump if val1 >  0
ifge:
jump if val1 >  0
ifnull:
jump if val1 >= 0
ifnonnull
: jump if val1 != null reference

if_icmpXX <label>
val1
and val2 are popped off the stack and compared to each other according to the XX test. If it they satisfy the test, the process jumps to the instruction at the byteocde address indicated by <label>.

if_icmpeq: jump if val2 == val1
if_icmpne
: jump if val2 != val1
if_icmplt
: jump if val2 <  val1
if_icmpgt
: jump if val2 >  val1
if_icmple
: jump if val2 <= val1
if_icmpge
: jump if val2 >= val1
if_acmpeq
: jump if reference val2 ==  reference val1
if_acmpne
: jump if reference val2 !=  reference val1

Compound conditional branch:

lookupswitch
   <key1> : <label1>
   <key2> : <label2>
   <key3> : <label3>
     ...
   <keyn> : <labeln>
   default: <defaultLabel>
val1
is popped off the stack. If it equals any of the key# values, the process jumps to the <label#> location in the bytecode. Otherwise, the process jumps to the location identified by <defaultLabel>. Implements the switch/case statement in the Java language.

tableswitch <low>, <high>
            <label1>
            <label2>
            <label3>
     ...
            <labeln>
   default: <defaultLabel>
val1
is popped off the stack. If it less than <low> or greater than <high> the process jumps to the location indicated by <defaultLabel>. Otherwise, the process jumps to the <labelM> for M=val1-low.

Unconditional branch:

goto <label>
The process jumps to the address given by the 16 bit offset value in <label>.

goto_w
<label>
The process jumps to the address given by the 32 bit offset value in <label>


jsr
<label>
The pushes the current location + 3 onto the stack and the jumps to the address of a subroutine given by the 16 bit offset value in <label> . The subroutine pops the address from the stack and stores it in a local variable. When it executes the ret command, the address is obtained from the local variable and the process goes to that location.

jsr_w
<label>
Same as jsr except it uses a 32 bit offset value in <label>.

ret
<variable>
In a subroutine this operation causes the process to jump to the address stored in the local variable indicated by <variable>.


See Chapter 2: Basics : Flow Control and Chapter 2: Basics : Conditional if-else Statements. See also Chapter 2: Java : Operators : Comparison.

 

Load & Store Instructions

Push a value from a variable onto the stack:

iload <var>
lload <var>
fload <var>
dload <var>
aload <var>

Take the value in local variable pointed to by index <var> of the type indicated by the first letter of the instruction and put it on top of the stack.

iload_<n>
lload_<n>
fload_<n>
dload_<n>
aload_<n>

Where n=(0, 1, 2 or 3), where n indicates an index to a local variable. Obtain the value in local variable n of type indicated by the first letter of the instruction and push it on top of the stack.

Load a constant value onto the operand stack:

bipush <byte>
Pushes a byte value onto the stack (sign extends it to fill the 32 bit wide stack word). The <byte> value follows the instruction in the bytecode.

sipush <short>
Pushes a 16 bit value onto the stack (sign extends it to fill the 32 bit wide stack word). Here the <short> value follows the instruction in the bytecode.

ldc <const>
Pushes a 32 bit constant onto the stack. Can be an int, float or String reference. Here the <const> 8 bit value follows the instruction in the bytecode and is an index into the constants pool, which is an array where the class stores constants (such as from literals), strings and other data.

Ldc_w <const>
Same as ldc but the <const> value is a 16 bit index into the constants pool.

ldc2_w <const>
Pushes a 64 bit constant onto the stack (as two 32 bit wide words). Can be an long or double. Here the <const> 16 bit value follows the instruction in the bytecode and is an index into the constants pool, which is an array where the class stores constants (such as from literals), strings and other data.

iconst_<n>
Where n=(0,1,2,3,4 or 5) push the value n of type int onto the stack.

lconst_<n>
Where n=(0 or 1) push the value n of type long onto the stack.

fconst_<n>
Where n=(0, 1, or 2) push the value n of type float onto the stack ( 0.0, 1.0, or 2.0, resp.)

dconst_<n>
Where n=(0 or 1) push the value n of type double onto the stack ( 0.0 or 1.0, or 2.0, resp.)

iconst_m1
Push -1 onto the stack

aconst_null
Push null reference onto the stack

Store a value from the operand stack into a local variable:

istore <var>
lstore <var>
fstore <var>
dstore <var>
astore <var>

Pop val1 off the stack and store in local variable indexed by <var> of the type indicated by the first letter of the instruction.

istore_n
lstore_n
fstore_n
dstore_n
astore_n
For n = (0,1,2,or 3), where n indicates an index to the zeroth through third local variable. Pop val1 off the stack and store in the nth local variable of the type indicated by the first letter of the instruction.

Extend index:

wide
When placed in front of these instructions - aload,dload,iload,fload,lload, astore,dstore,istore,fstore,lstore,ret - the index to local variable is extended from 8 bits to 16 bits. (Also, used with iinc to extend its increment size to 16 bits.)

See assignments in Chapter 2: Java : Expressions, assignment operators in Chapter 2: Java : Operators, declarations in Chapter 2: Java : Statements.

 

Stack Instructions

pop items off the stack:

pop
Discard the word currently on top of the stack. Removes, for example, a single int value.

pop2
Discard the two words currently on top of the stack. Removes, for example, two int values or one long value.

duplicate items on the stack:

dup
Duplicate the word currently on top of the stack. So
val1 => val1
        val1
Can't be used if
val1 is the high end of a 2 word type, i.e. long or double. Must use dup2 in that case.

dup2
Duplicate the word currently on top of the stack. So
val1 => val1
val2    val2
        val1
        val2

dup_x1
Duplicate the word on top of the stack and insert the copy below the second word on the stack:
val1 => val1
val2      val2
        val1

Can't be used if
val1 or val2 are part of a 2 word type, i.e. long or double. Must use dup2_x1 in that case.

dup2_x1
Duplicate the 2 words on top of the stack and insert the copy below the third word on the stack:
val1 => val1
val2      val2
val3    val3
        val1
        val2

dup_x2
Duplicate the word on top of the stack and insert the copy below the third word on the stack:
val1 => val1
val2      val2
val3    val3
        val1

Can't be used if
val1 is part of a 2 word type, i.e. long or double. Must use dup2_x1 in that case.

dup2_x2
Duplicate the 2 words on top of the stack and insert the copy below the fourth word on the stack:
val1 => val1
val2      val2
val3    val3
val4    val4
        val1
        val2

Swap values on the stack:

swap
Swaps the top two words on the stack:
val1 => val2
val2      val1

References & Web Resources

Latest update: Oct. 4, 2005

            Tech
Arithmetic Ops
Math Class
More on Integers
FP : Overview
FP : Java  
  
Demo 1
More Mix/Cast
  Demo 2
Exercises

           Physics
Differential Eq.
Euler Method
  
Demo 1
Predictor-Corrector
  
Demo 2
Exercises

  Part I Part II Part III
Java Core 1  2  3  4  5  6  7  8  9  10  11  12 13 14 15 16 17
18 19 20
21
22 23 24
Supplements

1  2  3  4  5  6  7  8  9  10  11  12

Tech 1  2  3  4  5  6  7  8  9  10  11  12
Physics 1  2  3  4  5  6  7  8  9  10  11  12

Java is a trademark of Sun Microsystems, Inc.