Method bodies are one of the few areas in which it is not always possible to return to the source code format. For one thing, you completely lose all of the information about the identifiers inside a method or in a methods argument list in the compilation phase. Theres no way to get it back. Furthermore, .java source code keywords like for and while dont always map in a one-to-one fashion onto the byte code equivalents. For example, for every for loop, theres an equivalent while loop that produces the same byte code. Given only the byte code, theres no way to tell which one was in the source code. Finally, optimizing compilers essentially rewrite .java source code before turning it into byte code. When you reverse the process, you get back the rewritten source code, not the original.
Although fully accurate decompilation is, in general, not possible, with practice you can learn to understand what the byte codes say. The fundamental problem is that theres often more than one way to say the same thing. However, if you care only about the meaning of what was said, rather than the exact way in which it was expressed, you can extract the meaning from the byte codes. You learn to do this in this chapter.
The code in a method body is a linear sequence of bytes. Each byte has an unsigned value between zero and 255. The interpretation of each byte depends on its position. The zeroth byte is always a .java byte code instruction (an opcode, for short). Bytes after that point can be either byte code instructions or arguments for byte code instructions. For example, if the byte at position zero in a method is 16, then the byte at position one is not a byte code, but rather a signed byte to be pushed onto the stack. Data values embedded directly in the code like this are sometimes called literals.
The only way to distinguish between opcodes and literals is by starting with the instruction at position zero in the code array and working forward. For example, if the byte zero is 16 and opcode 16 is known to take a one-byte argument, then byte one must be the literal argument for the instruction and byte two must be the next opcode.
Most instructions have a precisely defined number of bytes that should be read as literals following the opcode itself. Opcode 16 always takes exactly one byte as an argument, never zero bytes and never more than one byte. Arguments that by their nature do not take up a fixed number of bytes, such as arrays and strings, are not directly included in the code array. Instead, a 2-byte index into the constant pool is given. Therefore, once you know the possible byte codes and their arguments, you can distinguish between instructions and data. Java enforces the dichotomy between code and data very strictly. This is an essential feature of Javas security.
Human beings arent very good at remembering the meanings of many small numbers like the 200-plus opcodes. Sun has therefore defined mnemonic strings for these codes. These strings are listed in Table 5-1.
Table 5-1 .java byte codes
|
Byte Code
| Mnemonic
| Number of Bytes in the Argument
| Meaning
|
|
0
| nop
| 0
| Do nothing (no operation); skip to the next instruction.
|
1
| aconst_null
| 0
| Push null onto the stack.
|
2
| iconst_m1
| 0
| Push the int -1 onto the stack.
|
3
| iconst_0
| 0
| Push the int 0 onto the stack.
|
4
| iconst_1
| 0
| Push the int 1 onto the stack.
|
5
| iconst_2
| 0
| Push the int 2 onto the stack.
|
6
| iconst_3
| 0
| Push the int 3 onto the stack.
|
7
| iconst_4
| 0
| Push the int 4 onto the stack.
|
8
| iconst_5
| 0
| Push the int 5 onto the stack.
|
9
| lconst_0
| 0
| Push the long 0 onto the stack.
|
10
| lconst_1
| 0
| Push the long 1 onto the stack.
|
11
| fconst_0
| 0
| Push the float 0.0 onto the stack.
|
12
| fconst_1
| 0
| Push the float 1.0 onto the stack.
|
13
| fconst_2
| 0
| Push the float 2.0 onto the stack.
|
14
| dconst_0
| 0
| Push the double 0.0 onto the stack.
|
15
| dconst_1
| 0
| Push the double 1.0 onto the stack.
|
16
| bipush
| 1
| Sign-extend the byte to an int, and push it onto the stack.
|
17
| sipush
| 2
| Combine the bytes into a short, sign-extend it to an int, and push it onto the stack.
|
18
| ldc
| 1
| Push the integer, float, or string at the specified index in the constant pool onto the stack.
|
19
| ldc_w
| 2
| Push the integer, float, or string at the specified index in the constant pool onto the stack.
|
20
| ldc2_w
| 2
| Push the long or double at the specified index in the constant pool onto the stack.
|
21
| iload
| 1
| Push the int local variable at the specified index onto the stack.
|
22
| lload
| 1
| Push the long local variable at the specified index onto the stack.
|
23
| fload
| 1
| Push the float local variable at the specified index onto the stack.
|
24
| dload
| 1
| Push the double local variable at the specified index onto the stack.
|
25
| aload
| 1
| Push the reference at the specified index onto the stack.
|
26
| iload_0
| 0
| Push the int variable at the zeroth position in the local frame onto the stack.
|
27
| iload_1
| 0
| Push the int variable at the first position in the local frame onto the stack.
|
28
| iload_2
| 0
| Push the int variable at the second position in the local frame onto the stack.
|
29
| iload_3
| 0
| Push the int variable at the third position in the local frame onto the stack.
|
30
| lload_0
| 0
| Push the long variable at the zeroth position in the local frame onto the stack.
|
31
| lload_1
| 0
| Push the long variable at the first position in the local frame onto the stack.
|
32
| lload_2
| 0
| Push the long variable at the second position in the local frame onto the stack.
|
33
| lload_3
| 0
| Push the long variable at the third position in the local frame onto the stack.
|
34
| fload_0
| 0
| Push the float variable at the zeroth position in the local frame onto the stack.
|
35
| fload_1
| 0
| Push the float variable at the first position in the local frame onto the stack.
|
36
| fload_2
| 0
| Push the float variable at the second position in the local frame onto the stack.
|
37
| fload_3
| 0
| Push the float variable at the third position in the local frame onto the stack.
|
38
| dload_0
| 0
| Push the double variable at the zeroth position in the local frame onto the stack.
|
39
| dload_1
| 0
| Push the double variable at the first position in the local frame onto the stack.
|
40
| dload_2
| 0
| Push the double variable at the second position in the local frame onto the stack.
|
41
| dload_3
| 0
| Push the double variable at the third position in the local frame onto the stack.
|
42
| aload_0
| 0
| Push the reference variable at the zeroth position in the local frame onto the stack.
|
43
| aload_1
| 0
| Push the reference variable at the first position in the local frame onto the stack.
|
44
| aload_2
| 0
| Push the reference variable at the second position in the local frame onto the stack.
|
45
| aload_3
| 0
| Push the reference variable at the third position in the local frame onto the stack.
|
46
| iaload
| 0
| Push an int from an array onto the stack.
|
47
| laload
| 0
| Push a long from an array onto the stack.
|
48
| faload
| 0
| Push a float from an array onto the stack.
|
49
| daload
| 0
| Push a double from an array onto the stack.
|
50
| aaload
| 0
| Push a reference from an array onto the stack.
|
51
| baload
| 0
| Push a byte or Boolean from an array onto the stack.
|
52
| caload
| 0
| Push a char from an array onto the stack.
|
53
| saload
| 0
| Push a short from an array onto the stack.
|
54
| istore
| 1
| Store an int into the local variable at the specified index.
|
55
| lstore
| 1
| Store a long into the local variable at the specified index.
|
56
| fstore
| 1
| Store a float into the local variable at the specified index.
|
57
| dstore
| 1
| Store a double into the local variable at the specified index.
|
58
| astore
| 1
| Store a reference into the local variable at the specified index.
|
59
| istore_0
| 0
| Pop an int value from the stack, and store it in the local variable at index 0.
|
60
| istore_1
| 0
| Pop an int value from the stack, and store it in the local variable at index 1.
|
61
| istore_2
| 0
| Pop an int value from the stack, and store it in the local variable at index 2.
|
62
| istore_3
| 0
| Pop an int value from the stack, and store it in the local variable at index 3.
|
63
| lstore_0
| 0
| Pop a long value from the stack, and store it in the local variable at index 0.
|
64
| lstore_1
| 0
| Pop a long value from the stack, and store it in the local variable at index 1.
|
65
| lstore_2
| 0
| Pop a long value from the stack, and store it in the local variable at index 2.
|
66
| lstore_3
| 0
| Pop a long value from the stack, and store it in the local variable at index 3.
|
67
| fstore_0
| 0
| Pop a float value from the stack, and store it in the local variable at index 0.
|
68
| fstore_1
| 0
| Pop a float value from the stack, and store it in the local variable at index 1.
|
69
| fstore_2
| 0
| Pop a float value from the stack, and store it in the local variable at index 2.
|
70
| fstore_3
| 0
| Pop a float value from the stack, and store it in the local variable at index 3.
|
71
| dstore_0
| 0
| Pop a double value from the stack, and store it in the local variable at index 0.
|
72
| dstore_1
| 0
| Pop a double value from the stack, and store it in the local variable at index 1.
|
73
| dstore_2
| 0
| Pop a double value from the stack, and store it in the local variable at index 2.
|
74
| dstore_3
| 0
| Pop a double value from the stack, and store it in the local variable at index 3.
|
75
| astore_0
| 0
| Pop a reference value from the stack, and store it in the local variable at index 0.
|
76
| astore_1
| 0
| Pop a reference value from the stack, and store it in the local variable at index 1.
|
77
| astore_2
| 0
| Pop a reference value from the stack, and store it in the local variable at index 2.
|
78
| astore_3
| 0
| Pop a reference value from the stack, and store it in the local variable at index 3.
|
79
| iastore
| 0
| Store a value from the stack into an int array.
|
80
| lastore
| 0
| Store a value from the stack into a long array.
|
81
| fastore
| 0
| Store a value from the stack into a float array.
|
82
| dastore
| 0
| Store a value from the stack into a double array.
|
83
| aastore
| 0
| Store a value from the stack into a reference array.
|
84
| bastore
| 0
| Store a value from the stack into a byte or Boolean array.
|
85
| castore
| 0
| Store a value from the stack into a char array.
|
86
| sastore
| 0
| Store a value from the stack into a short array.
|
87
| pop
| 0
| Pop a word from the stack, and throw it away.
|
88
| pop2
| 0
| Pop two words from the stack, and throw them away.
|
89
| dup
| 0
| Duplicate the top word of the stack onto the top of the stack.
|
90
| dup_x1
| 0
| Duplicate the top word of the stack, and put it two down in the stack.
|
91
| dup_x2
| 0
| Duplicate the top word of the stack, and put it three down in the stack.
|
92
| dup2
| 0
| Duplicate the top two words on the stack onto the top of the stack.
|
93
| dup2_x1
| 0
| Duplicate the top two words of the stack, and put them three down in the stack.
|
94
| dup2_x2
| 0
| Duplicate the top two words of the stack, and put them four down in the stack.
|
95
| swap
|
| Swap the top two words on the stack.
|
96
| iadd
| 0
| Add two ints.
|
97
| ladd
| 0
| Add two longs.
|
98
| fadd
| 0
| Add two floats.
|
99
| dadd
| 0
| Add two doubles.
|
100
| isub
| 0
| Subtract two ints.
|
101
| lsub
| 0
| Subtract two longs.
|
102
| fsub
| 0
| Subtract two floats.
|
103
| dsub
| 0
| Subtract two doubles.
|
104
| imul
| 0
| Multiply two ints.
|
105
| lmul
| 0
| Multiply two longs.
|
106
| fmul
| 0
| Multiply two floats.
|
107
| dmul
| 0
| Multiply two doubles.
|
108
| idiv
| 0
| Divide two ints.
|
109
| ldiv
| 0
| Divide two longs.
|
110
| fdiv
| 0
| Divide two floats.
|
111
| ddiv
| 0
| Divide two doubles.
|
112
| irem
| 0
| Take the remainder of two ints.
|
113
| lrem
| 0
| Take the remainder of two longs.
|
114
| frem
| 0
| Take the remainder of two floats.
|
115
| drem
| 0
| Take the remainder of two doubles.
|
116
| ineg
| 0
| Change the sign of the int on the top of the stack.
|
117
| lneg
| 0
| Change the sign of the long on the top of the stack.
|
118
| fneg
| 0
| Change the sign of the float on the top of the stack.
|
119
| dneg
| 0
| Change the sign of the double on the top of the stack.
|
120
| ishl
| 0
| Shift an int left.
|
121
| lshl
| 0
| Shift a long left.
|
122
| ishr
| 0
| Shift an int right with sign extension.
|
123
| lshr
| 0
| Shift a long right with sign extension.
|
124
| iushr
| 0
| Shift an int right without sign extension.
|
125
| lushr
| 0
| Shift a long right without sign extension.
|
126
| iand
| 0
| Bitwise and of the two ints on the top of the stack.
|
127
| land
| 0
| Bitwise and of the two longs on the top of the stack.
|
128
| ior
| 0
| Bitwise or of the two ints on the top of the stack.
|
129
| lor
| 0
| Bitwise or of the two longs on the top of the stack.
|
130
| ixor
| 0
| Bitwise exclusive-or of the two ints on the top of the stack.
|
131
| lxor
| 0
| Bitwise exclusive-or of the two longs on the top of the stack.
|
132
| iinc
| 2
| Increment the local variable at the first argument by the signed byte at the second argument.
|
133
| i2l
| 0
| Convert int to long.
|
134
| i2f
| 0
| Convert int to float.
|
135
| i2d
| 0
| Convert int to double.
|
136
| l2i
| 0
| Convert long to int.
|
137
| l2f
| 0
| Convert long to float.
|
138
| l2d
| 0
| Convert long to double.
|
139
| f2i
| 0
| Convert float to int.
|
140
| f2l
| 0
| Convert float to long.
|
141
| f2d
| 0
| Convert float to double.
|
142
| d2i
| 0
| Convert double to int.
|
143
| d2l
| 0
| Convert double to long.
|
144
| d2f
| 0
| Convert double to float.
|
145
| i2b
| 0
| Convert int to byte.
|
146
| i2c
| 0
| Convert int to char.
|
147
| i2s
| 0
| Convert int to short.
|
148
| lcmp
| 0
| Compare two longs.
|
149
| fcmpl
| 0
| Compare two floats.
|
150
| fcmpg
| 0
| Compare two floats.
|
151
| dcmpl
| 0
| Compare two doubles.
|
152
| dcmpg
| 0
| Compare two doubles.
|
153
| ifeq
| 2
| Branch if the int on the top of the stack is equal to zero.
|
154
| ifne
| 2
| Branch if the int on the top of the stack is not equal to zero.
|
155
| iflt
| 2
| Branch if the int on the top of the stack is less than zero.
|
156
| ifge
| 2
| Branch if the int on the top of the stack is greater than or equal to zero.
|
157
| ifgt
| 2
| Branch if the int on the top of the stack is greater than zero.
|
158
| ifle
| 2
| Branch if the int on the top of the stack is less than or equal to zero.
|
159
| if_icmpeq
| 2
| Branch if the two ints on the top of the stack are equal.
|
160
| if_icmpne
| 2
| Branch if the two ints on the top of the stack are not equal.
|
161
| if_icmplt
| 2
| Branch if the int second from the top of the stack is less than the int on the top of the stack.
|
162
| if_icmpge
| 2
| Branch if the int second from the top of the stack is greater than or equal to the int on the top of the stack.
|
163
| if_icmpgt
| 2
| Branch if the int second from the top of the stack is greater than the int on the top of the stack.
|
164
| if_icmple
| 2
| Branch if the int second from the top of the stack is less than or equal to the int on the top of the stack.
|
165
| if_acmpeq
| 2
| Branch to the address specified in the argument if the two references on the top of the stack are equal.
|
166
| if_acmpne
| 2
| Branch to the address specified in the argument if the two references on the top of the stack are not equal.
|
167
| goto
| 2
| Go to address specified in the arguments.
|
168
| jsr
| 2
| Jump to a subroutine.
|
169
| ret
| 1
| Return from a subroutine.
|
170
| tableswitch
| variable
| Compare value and branch.
|
171
| lookupswitch
| variable
| Compare value and branch.
|
172
| ireturn
| 0
| Return an int from a method.
|
173
| lreturn
| 0
| Return a long from a method.
|
174
| freturn
| 0
| Return a float from a method.
|
175
| dreturn
| 0
| Return a double from a method.
|
176
| areturn
| 0
| Return a reference from a method.
|
177
| return
| 0
| Return void from method.
|
178
| getstatic
| 2
| Get a static field from a class.
|
179
| putstatic
| 2
| Sets a static field in a class.
|
180
| getfield
| 2
| Get a field from an object.
|
181
| putfield
| 2
| Set a field in an object.
|
182
| invokevirtual
| 2
| Call an instance method.
|
183
| invokespecial
| 2
| Call a constructor in special circumstances.
|
184
| invokestatic
| 2
| Call a static method.
|
185
| invokeinterface
| 4
| Call an interface method.
|
186
|
|
| Not used in Java 1.0.2.
|
187
| new
| 2
| Create a new object.
|
188
| newarray
| 1
| Create a new array of primitive types.
|
189
| anewarray
| 2
| Create a new array of references.
|
190
| arraylength
| 0
| Get the length of an array.
|
191
| athrow
| 0
| Throw exception or error.
|
192
| checkcast
| 2
| Check casts between object types.
|
193
| instanceof
| 2
| Determine if an object has a given type.
|
194
| monitorenter
| 0
| Allow a thread to take ownership of the monitor associated with an object.
|
195
| monitorexit
| 0
| Allow a thread to give up ownership of the monitor associated with an object.
|
196
| wide
| 4 or 6
| Extend the local variable index used by the iload, aload, fload, dload, istore, astore, fstore, dstore, ret, and iinc instructions.
|
197
| multianewarray
| 3
| Create a new multidimensional array.
|
198
| ifnull
| 2
| Branch to the address specified in the arguments if the reference popped from the top of the stack is null.
|
199
| ifnonnull
| 2
| Branch to the address specified in the arguments if the reference popped from the top of the stack is not null.
|
200
| goto_w
| 4
| Branch to the address specified in the arguments.
|
201
| jsr_w
| 4
| Jump to the subroutine at the address specified in the arguments.
|
|
Although these mnemonics may seem just as cryptic as the raw bytes at first glance, they do have a logic to them. For example, opcodes that begin with the letter i commonly operate on int types. Instructions that begin with the letter l operate on longs. Instructions that begin with f operate on floats, and instructions that begin with d operate on doubles. Instructions that begin with a operate on references. Opcodes that contain the word add generally add things. Opcodes that contain the word sub generally subtract things. You get the idea. The rest of this chapter looks at what these instructions do. By the time you finish this chapter, these mnemonics will make perfect sense to you.