Bytecode format list

A guide on Recaf's simplified bytecode format for the assembler

Preface

This is a listing of the Java bytecode instructions ordered by the underlying bytecode library (ASM) grouping. For instance, ifeq and goto belong to the Jump group. Most of the groupings should make sense and seeing one or two of the instructions should key you into which other ones are also in the group. What differs this list from the official instruction specification is that the descriptions have been modified to fit how Recaf represents them.

Table of Contents

Insn

Opcode Stack: [before]→[after] Description
aconst_null null push a null reference onto the stack
dconst_0 0.0 push the constant 0.0 onto the stack
dconst_1 1.0 push the constant 1.0 onto the stack
fconst_0 0.0f push 0.0f on the stack
fconst_1 1.0f push 1.0f on the stack
fconst_2 2.0f push 2.0f on the stack
iconst_m1 -1 load the int value −1 onto the stack
iconst_0 0 load the int value 0 onto the stack
iconst_1 1 load the int value 1 onto the stack
iconst_2 2 load the int value 2 onto the stack
iconst_3 3 load the int value 3 onto the stack
iconst_4 4 load the int value 4 onto the stack
iconst_5 5 load the int value 5 onto the stack
lconst_0 0L push long 0L onto the stack
lconst_1 1L push long 1L onto the stack
arraylength arrayref → length get the length of an array
aaload arrayref, index → value load onto the stack a reference from an array
aastore arrayref, index, value → store into a reference in an array
baload arrayref, index → value load a byte or Boolean value from an array
bastore arrayref, index, value → store a byte or Boolean value into an array
caload arrayref, index → value load a char from an array
castore arrayref, index, value → store a char into an array
daload arrayref, index → value load a double from an array
dastore arrayref, index, value → store a double into an array
faload arrayref, index → value load a float from an array
fastore arrayref, index, value → store a float in an array
iaload arrayref, index → value load an int from an array
iastore arrayref, index, value → store an int into an array
laload arrayref, index → value load a long from an array
lastore arrayref, index, value → store a long to an array
saload arrayref, index → value load short from array
sastore arrayref, index, value → store short to array
d2f value → result convert: double to float
d2i value → result convert: double to int
d2l value → result convert: double to long
f2d value → result convert: float to double
f2i value → result convert: float to int
f2l value → result convert: float to long
i2b value → result convert: int to byte
i2c value → result convert: int to char
i2d value → result convert: int to double
i2f value → result convert: int to float
i2l value → result convert: int to long
i2s value → result convert: int to short
l2d value → result convert: long to double
l2f value → result convert: long to float
l2i value → result convert: long to int
areturn objectref → [empty] return a reference from a method
dreturn value → [empty] return a double from a method
freturn value → [empty] return a float
ireturn value → [empty] return an int from a method
lreturn value → [empty] return a long value
return → [empty] return void from method
dadd value1, value2 → result add two double values value2 + value1
ddiv value1, value2 → result divide two double values value2 / value1
dmul value1, value2 → result multiply two double values value2 * value1
drem value1, value2 → result get the remainder from a division between two double values (value2 - ((value1 / value2) * value2))
dsub value1, value2 → result subtract a double from another value2 - value1
fadd value1, value2 → result add two float values value2 + value1
fdiv value1, value2 → result divide two float values value2 / value1
fmul value1, value2 → result multiply two float values value2 * value1
frem value1, value2 → result get the remainder from a division between two float values (value2 - ((value1 / value2) * value2))
fsub value1, value2 → result subtract two float values value2 - value1
iadd value1, value2 → result add two int values value2 + value1
idiv value1, value2 → result divide two int values value2 / value1
imul value1, value2 → result multiply two int values value2 * value1
irem value1, value2 → result logical int remainder (value2 - ((value1 / value2) * value2))
isub value1, value2 → result int subtract value2 - value1
iand value1, value2 → result perform a bitwise AND on two int values value2 & value1
ior value1, value2 → result bitwise int OR value2 | value1
ixor value1, value2 → result int xor value2 ^ value1
ishl value1, value2 → result int shift left value2 << value1
ishr value1, value2 → result int arithmetic shift right value2 >> value1
iushr value1, value2 → result int logical shift right value2 >>> value1
ladd value1, value2 → result add two long values value2 + value1
ldiv value1, value2 → result divide two long values value2 / value1
lmul value1, value2 → result multiply two long values value2 * value1
lrem value1, value2 → result remainder of division of two long values (value2 - ((value1 / value2) * value2))
lsub value1, value2 → result subtract two long values value2 - value1
lshl value1, value2 → result bitwise shift left of a long value1 by int value2 positions value2 << value1
lshr value1, value2 → result bitwise shift right of a long value1 by int value2 positions value2 >> value1
lushr value1, value2 → result bitwise shift right of a long value1 by int value2 positions, unsigned value2 >>> value1
land value1, value2 → result bitwise AND of two long values value2 ^ value1
lor value1, value2 → result bitwise OR of two long values value2 | value1
lxor value1, value2 → result bitwise XOR of two long values value2 ^ value1
dneg value → result negate a double -value
fneg value → result negate a float -value
ineg value → result negate int -value
lneg value → result negate a long -value
dcmpg value1, value2 → result compare two double values
ComparisonValue
value1==NaN or
value2==NaN
1
value1 > value21
value1==value20
value1 < value2-1
dcmpl value1, value2 → result compare two double values
ComparisonValue
value1==NaN or
value2==NaN
-1
value1 > value21
value1==value20
value1 < value2-1
fcmpg value1, value2 → result compare two float values
ComparisonValue
value1==NaN or
value2==NaN
1
value1 > value21
value1==value20
value1 < value2-1
fcmpl value1, value2 → result compare two float values
ComparisonValue
value1==NaN or
value2==NaN
-1
value1 > value21
value1==value20
value1 < value2-1
lcmp value1, value2 → result compare two long values
ComparisonValue
value1==value20
value1 > value21
else-1
athrow objectref → [empty], objectref throws an error or exception (notice that the rest of the stack is cleared, leaving only a reference to the Throwable)
dup value → value, value duplicate the value on top of the stack
dup_x1 value2, value1 → value1, value2, value1 insert a copy of the top value into the stack two values from the top. value1 and value2 must not be of the type double or long.
dup_x2 value3, value2, value1 → value1, value3, value2, value1 insert a copy of the top value into the stack two (if value2 is double or long it takes up the entry of value3, too) or three values (if value2 is neither double nor long) from the top
dup2 {value2, value1} → {value2, value1}, {value2, value1} duplicate top two stack words (two values, if value1 is not double nor long; a single value, if value1 is double or long)
dup2_x1 value3, {value2, value1} → {value2, value1}, value3, {value2, value1} duplicate two words and insert beneath third word (see explanation above)
dup2_x2 {value4, value3}, {value2, value1} → {value2, value1}, {value4, value3}, {value2, value1} duplicate two words and insert beneath fourth word
pop value → discard the top value on the stack
pop2 {value2, value1} → discard the top two values on the stack (or one value, if it is a double or long)
swap value2, value1 → value1, value2 swaps two top words on the stack (note that value1 and value2 must not be double or long)
monitorenter objectref → enter monitor for object (“grab the lock” – start of synchronized() section)
monitorexit objectref → exit monitor for object (“release the lock” – end of synchronized() section)
nop [No change] do nothing

Integer

Opcode Stack: [before]→[after] Description
bipush
  • value
→ value push a byte onto the stack as an int value
sipush
  • value
→ value push a short onto the stack as an int value
newarray
  • descriptor
count → arrayref create new array with count elements of primitive type identified by descriptor
Type Descriptor alias
booleanZ
charC
floatF
doubleD
byteB
shortS
intI
longJ

Variable

Opcode Stack: [before]→[after] Description
iload
  • value
→ value load an int value from a local variable index
lload
  • value
→ value load a long value from a local variable index
fload
  • value
→ value load a float value from a local variable index
dload
  • value
→ value load a double value from a local variable index
aload
  • value
→ objectref load a reference onto the stack from a local variable index
istore
  • value
value → store int value into variable index
lstore
  • value
value → store a long value in a local variable index
fstore
  • value
value → store a float value into a local variable index
dstore
  • value
value → store a double value into a local variable index
astore
  • value
objectref → store a reference into a local variable index

Type

Opcode Stack: [before]→[after] Description
new
  • type
→ objectref create new object of type
anewarray
  • type
count → arrayref create a new array of references of length count and component type identified by type
checkcast
  • type
objectref → objectref checks whether an objectref is of a certain specified type
instanceof
  • type
objectref → result determines if an object objectref is of a given type

Field

Opcode Stack: [before]→[after] Description
getfield
  • owner
  • name
  • desc
objectref → value get an instance field defined by the owner class and the field’s name and desc
getstatic
  • owner
  • name
  • desc
→ value get a static field defined by the owner class and the field’s name and desc
putfield
  • owner
  • name
  • desc
objectref, value → set an instance field defined by the owner class and the field’s name and desc
putstatic
  • owner
  • name
  • desc
value → set a static field defined by the owner class and the field’s name and desc

Method

Opcode Stack: [before]→[after] Description
invokeinterface
  • owner
  • name
  • desc
objectref, [arg1, arg2, …] → result invokes an interface method defined by the owner class and the method’s name and desc on object objectref and puts the result on the stack (might be void)
invokespecial
  • owner
  • name
  • desc
objectref, [arg1, arg2, …] → result invokes an instance method defined by the owner class and the method’s name and desc on object objectref and puts the result on the stack (might be void)
invokestatic
  • owner
  • name
  • desc
[arg1, arg2, …] → result invokes a static method defined by the owner class and the method’s name and desc and puts the result on the stack (might be void)
invokevirtual
  • owner
  • name
  • desc
objectref, [arg1, arg2, …] → result invokes a virtual method defined by the owner class and the method’s name and desc on object objectref and puts the result on the stack (might be void)

InvokeDynamic

Opcode Stack: [before]→[after] Description
invokedynamic
  • definition
    • name, desc
  • bootstrap handle
    • owner, name, desc
  • bootstrap arguments[]
[arg1, arg2 …] → result invokes a dynamic method and puts the result on the stack (might be void). The callsite handles the dynamic invocation.

Jump

Opcode Stack: [before]→[after] Description
goto
  • label
[no change] jump to label
if_acmpeq
  • label
value1, value2 → if references value1 == value2, jump to label
if_acmpne
  • label
value1, value2 → if references value1 != value2, jump to label
if_icmpeq
  • label
value1, value2 → if ints value1 == value2, jump to label
if_icmpge
  • label
value1, value2 → if ints value1 >= value2, jump to label
if_icmpgt
  • label
value1, value2 → if ints value1 > value2, jump to label
if_icmple
  • label
value1, value2 → if ints value1 <= value2, jump to label
if_icmplt
  • label
value1, value2 → if ints value1 < value2, jump to label
if_icmpne
  • label
value1, value2 → if ints value1 != value2, jump to label
ifeq
  • label
value → if value == 0, jump to label
ifge
  • label
value → if value >= 0, jump to label
ifgt
  • label
value → if value > 0, jump to label
ifle
  • label
value → if value <= 0, jump to label
iflt
  • label
value → if value < 0, jump to label
ifne
  • label
value → if value != 0, jump to label
ifnonnull
  • label
value → if value != null, jump to label
ifnull
  • label
value → if value == null, jump to label

Ldc

Opcode Stack: [before]→[after] Description
ldc
  • value
→ value push a constant value (String, int, float, long, double, Class, or Handle) onto the stack

Increment

Opcode Stack: [before]→[after] Description
iinc
  • index
  • amount
[No change] increment local variable index by a given amount (byte)

MultiANewArray

Opcode Stack: [before]→[after] Description
multianewarray
  • desc
  • dims
count1, [count2,…] → arrayref create a new array of dims dimensions of type identified by desc

Switch

Opcode Stack: [before]→[after] Description
lookupswitch key → a target address is looked up from a table using a key and execution continues from the instruction at that address
tableswitch index → continue execution from an address in the table at offset index

Label

Opcode Stack: [before]→[after] Description
label [No change] marker in bytecode for the beginning of a block of opcodes; referenced by jump and switch instructions.

Line

Opcode Stack: [before]→[after] Description
line
  • line
[No change] marker for where the next instruction denotes the beginning of a given line in the original source.