Now that you know that the overall class structure is valid, you can look at the method bodies to see if the instructions within the method are correctly formed. Following are some of the questions to ask. Does each instruction begin with a recognized opcode? If the instruction takes a constant pool reference as an argument, does it point to an actual constant pool entry with the correct type? If the instruction uses a local variable, is the local variable range within the correct range? If the instruction is a branch, does it point to the beginning of an instruction? These requirements ensure that the JVM never has to deal with an unidentified instruction or with improper arguments once it is running. Because local variable numbers are always used as arguments to instructions, rather than as operands, the set of local variables that is used in the method is fixed. This makes it impossible to use an invalid local variable in a program that has been verified. Table 6.2 summarizes the argument requirements for instructions that require arguments. For example, take this Oolong program: .method public static main([Ljava/lang/String;)V getstatic java/lang/System/out Ljava/io/PrintStream; ldc "Hello, world" invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V return .end method Table 6.2. Argument verification requirements for instructions Instructions | Bytes | Argument Requirements | ifeq ifne iflt ifge ifgt ifle if_icmpeq if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne goto jsr ifnull ifnonnull | 2 | The two bytes are taken as a 16-bit signed integer. When added to the location of the beginning of the instruction, this gives a new location. This location must be the beginning of an instruction, not the middle of an instruction. | goto_w jsr_w | 4 | Same as goto and jsr but use a 32-bit number. | iload lload fload dload aload istore lstore fstore dstore astore ret bipush sipush | 1 | Taken as a one-byte unsigned number, must be less than the local variable count. | iinc | 2 | First byte must be less than the size of the local variable array. | ldc | 1 | Must be a constant pool index of a String, Integer, or Float constant. | ldc_w | 2 | Must be a constant pool index of a String, Integer, or Float constant. | ldc2_w | 2 | Must be a constant pool index of a Long or Double constant. | new anewarray checkcast instanceof | 2 | Must be a constant pool index of a Class constant. | getstatic putstatic getfield putfield | 2 | Must be a constant pool index of a Fieldref constant. | invokevirtual invokespecial invokestatic | 2 | Must be a constant pool index of a Methodref constant. | invokeinterface | 4 | First two must be a constant pool index of an InterfaceMethodref constant. Third byte must be the size of the arguments removed from the stack when the method is called. Last byte must be zero. | newarray | 1 | Must be between 4 and 11. | multianewarray | 3 | First two must be the constant pool index of a Class constant. Last byte must be less than or equal to the number of left brackets ([) at the beginning of the class name. | tableswitch | variable | Begins with 0 3 bytes of padding so that the next byte begins on a multiple of 4 from the beginning of the method. Followed by three four-byte numbers, default, high, and low. Must be followed by high low+1 groups of four bytes, each of which must form a valid jump offset as for goto_w. | lookupswitch | variable | Begins with 0 3 byte pad, like tableswitch. Followed by two four-byte numbers, default and npairs. Must be followed by npairs pairs of match and offset. Offset must be a valid jump offset as for goto_w. | wide | variable | If the first byte is the opcode for a load or store instruction or ret, then there must be two bytes that must be less than the total size of the variable pool. If the first byte is the opcode for a iinc instruction, then the next two bytes must be a valid local variable index, followed by two more bytes. | Here are the relevant parts of the class file to verify this requirement: There are four instructions. The first is a getstatic, whose argument is the constant 4, which is a Fieldref. The second is a ldc, which has argument 1, a String. The third is invokevirtual, which has argument 5, a Methodref. Finally, the last return instruction requires no arguments. All are correct, so this class file would pass this stage of testing. |