![]() |
|||
![]() ![]() |
![]() |
|
![]() |
Fields The getfield instruction pops a reference from the stack. This reference is used as an index into the constant pool to get a FieldRef out of the pool. The FieldRef is used by the virtual machine to find the appropriate field and put its value on the stack. For example, consider the simple class in Listing 5-5. It compiles to the byte codes shown in Listing 5-6. Listing 5-5 FieldExample public class FieldExample { int i; public int getField() { return i; } public void setField(int i) { this.i = i; } } Listing 5-6 FieldExample in byte code public class FieldExample extends java.lang.Object { int i; public int getField() { 0 aload_0 1 getfield 2 0 3 4 4 ireturn } public void setField(int) { 0 aload_0 1 iload_1 2 putfield 3 0 4 4 5 return } public void <init>() { 0 aload_0 1 invokespecial 2 0 3 3 4 return } } The first instruction in both the getField() and setField() methods is aload_0. This loads the reference from the zeroth local variable onto the stack. In a non-static method, this is always a reference to the current object. The next instruction in the getField() method is getfield. This pushes the value of the fourth entry in the constant pool onto the stack. Theres not enough information here yet to tell what that entry is. Ill soon revise the Disassembler class to make it more obvious exactly what that entry is. Then the value is returned. The setField() method also begins by pushing a reference to the current object onto the stack with aload_0. Then the first argument to the method, local variable 1, is pushed onto the stack. The putfield instruction pops this value from the stack and puts it in the field referred to by constant pool entry 4. Again, you dont know exactly what that field is from the byte code alone. You also need to look at the constant pool.
Static fields are similar except that the getstatic and putstatic instructions are used instead of getfield and putfield. The two bytes following the instruction are an index into the constant pool. That entry in the constant pool should contain a FieldRef structure. With getstatic, the value of that field is pushed onto the static. With putstatic, a value is popped from the stack and stored in that field. Methods There are four instructions in Java to call methods: invokevirtual, invokespecial, invokeinterface, and invokestatic. Invokevirtual is used for normal method calls. The invokeinterface instruction is used to call methods defined in interfaces. The invokestatic instruction is used to call static methods. Finally, the invokespecial instruction is used to call methods in the superclasses of the current object. Although these instructions differ in the kinds of methods they invoke, they all behave similarly. Each reads the next two bytes in the code array as an index into the constant pool. That pool entry is a Methodref. The Methodref is inspected to find out what arguments the method takes. These are popped from the stack and placed in the local variable array of the invoked method. Then control moves to the invoked method. If the invoked method returns a value, that value is pushed onto the stack of the current method. For example, consider the disassembly of the HelloWorld program in Listing 5-7. The main() method first gets the seventh static field from the constant pool. The seventh static field in the constant pool is another index into the constant pool, 4. The fourth entry in the constant pool is still another index into the constant pool, 28. Finally, the 28th entry in the constant pool is the static field you want, java.lang.System. A reference to this static object is placed on the operand stack. Next, the ldc instruction pushes the first item in the constant pool onto the stack. The first item in the pool is a string, the UTF8 value of which is stored at position 29. Therefore, a new string object is created with the value at position 29 in the pool Hello World! A reference to this string is pushed onto the stack.
|
![]() |
|