Now the invokevirtual instruction calls the method referenced by entry 6 in the constant pool. Entry 6 in the constant pool has ClassIndex 3 and NameAndTypeIndex 9. These are other entries in the constant pool. Entry 3 points to the UTF8 at entry 14, which is java/io/PrintStream. This tells you that a method of a java.io.PrintStream object is to be invoked. The NameAndTypeIndex points to entry 9. There you see a NameAndType entry with a NameIndex of 12 and a DescriptorIndex of 21. Entry 12 is println so the specific method being called is println(). Entry 21 is (Ljava/lang/String;)V, which tells you that the method takes a single string as an argument and returns void.
Listing 5-7 HelloWorld disassembled
import java.io.PrintStream;
class HelloWorld extends java.lang.Object {
public static void main(java.lang.String[]) {
0 getstatic
1 0
2 7
3 ldc
4 1
5 invokevirtual
6 0
7 6
8 return
}
public void <init>() {
0 aload_0
1 invokespecial
2 0
3 8
4 return
}
}
/*
1: String 29
2: ClassInfo 30
3: ClassInfo 14
4: ClassInfo 28
5: ClassInfo 22
6: MethodRef ClassIndex: 3; NameAndTypeIndex: 9
7: FieldRef ClassIndex: 4; NameAndTypeIndex: 10
8: MethodRef ClassIndex: 5; NameAndTypeIndex: 11
9: NameAndType NameIndex: 12; DescriptorIndex: 21
10: NameAndType NameIndex: 20; DescriptorIndex: 27
11: NameAndType NameIndex: 26; DescriptorIndex: 31
12: UTF8 println
13: UTF8 ConstantValue
14: UTF8 java/io/PrintStream
15: UTF8 Exceptions
16: UTF8 LineNumberTable
17: UTF8 SourceFile
18: UTF8 LocalVariables
19: UTF8 Code
20: UTF8 out
21: UTF8 (Ljava/lang/String;)V
22: UTF8 java/lang/Object
23: UTF8 main
24: UTF8 HelloWorld.java
25: UTF8 ([Ljava/lang/String;)V
26: UTF8 <init>
27: UTF8 Ljava/io/PrintStream;
28: UTF8 java/lang/System
29: UTF8 Hello World!
30: UTF8 HelloWorld
31: UTF8 ()V
*/
The init method also uses an invoke instruction:, invokespecial. This invokes the method described by entry 8 in the constant pool. Entry 8 has a ClassIndex of five and a NameAndTypeIndex of 11. Looking at entry 5, you are referred to the UTF8 at entry 22, java/lang/Object. You are therefore invoking a method in java.lang.Object. Looking at entry 11, youre referred to the NameIndex at entry 26 and the DescriptorIndex at entry 31. Entry 26 is <init> and entry 31 is ()V. Therefore, the invokespecial instruction is invoking the noargs constructor from java.lang.Object. Remember that the first action of every constructor is to invoke a constructor for the superclass.
The invokestatic and invokeinterface instructions behave exactly the same way. The only difference is that invokestatic invokes static methods and invokeinterface invokes methods from interfaces.
Returning values from methods
Returning values from methods is straightforward. You can return an int, a float, a long, a double, a reference, or nothing at all. In byte code, the last line of each method will be one of the six return instructions. A value of the appropriate type is popped from the stack and pushed onto the top of the stack of the calling method. After that, all data for this method call is disposed of. The six return instructions are
ireturn
| pop an int from the stack and return it
|
lreturn
pop a long from the stack and return it
freturn
pop a float from the stack and return it
dreturn
pop a double from the stack and return it
areturn
pop a reference from the stack and return it
return
return to the calling method but do not put any value on the stack
| | | | | | | | | |
Youve seen examples of these instructions at the end of every complete disassembled method in this chapter. Even if theres no return statement in the source code, the compiler inserts a generic return statement at the end of each method.
|