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 |
|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. |
|4 ||Same as goto and jsr but use a 32-bit number. |
|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. |
|2 ||Must be a constant pool index of a Class constant. |
|2 ||Must be a constant pool index of a Fieldref constant. |
|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.