![]() |
|||
![]() ![]() |
![]() |
|
![]() |
Theres only one new opcode in any of these: athrow. Exception handling is implemented mostly with a series of goto instructions. For example, look at the catchException() method: void catchException() { 0 iconst_5 1 newarray 10 3 astore_1 4 aload_1 5 iconst_5 6 bipush 7 8 iastore 9 return 10 astore_2 11 getstatic 17 14 aload_2 15 invokevirtual 20 18 return } The catch clause is not actually included in the byte code as such. One block of code from instruction 0 through instruction 9 handles the normal form of execution. Its terminated with the return opcode in instruction 9. Then the catch clause is included in instruction 10 through instruction 15. The ExceptionsTable for a method tells the virtual machine which sets of instructions handle which exceptions. The throwCheckedException() and throwRuntimeException() methods are very similar and quite simple. In essence, each just creates a new Exception object on the stack using standard constructors. Then, when the exception is on top of the stack, ready to go, the athrow instruction actually throws it. When the program runs, the virtual machine will see this exception and will work its way up the call chain looking for the nearest catch clause that can handle the exception. If it doesnt find one, it shuts down the thread that threw the exception. void finallyTest() { 0 aload_0 1 invokevirtual 13 4 goto 14 7 astore_3 8 getstatic 17 11 aload_3 12 invokevirtual 20 15 goto 3 18 jsr 10 21 return 22 astore_1 23 jsr 5 26 aload_1 27 athrow 28 astore_2 29 getstatic 18 32 ldc 2 34 invokevirtual 19 37 ret 2 } The finallyTest() method demonstrates one more instruction, jsr. The jsr opcode ensures that the code in a finally clause is executed. You should notice that there are two jsr instructions: one in line 18 and one in line 23. The jsr at line 18 jumps 10 places ahead to line 28. The jsr at line 23 jumps five places ahead, also to line 28. Theyre both executing the same finally clause, one from inside the main body of the code and one from inside the catch clause. The ret instruction in line 37 causes control to return to the point in the method where it started. It is not the same as the return instruction that exits the method. Type checkingTwo opcodes check the types of values operated on. The opcode instanceof implements the instanceof operator and compares the types of two references on the stack, whereas checkcast checks to see whether a cast between two types is permitted. instanceof The instanceof instruction is used to compile the instanceof operator. It determines whether a particular object is an instance of a specified class. A reference to the object is popped from the stack. The two bytes after the instanceof instruction in the code array are an index into the constant pool where a ClassInfo structure will be found. If the object is a non-null instance of the class, then the int value 1 is pushed onto the stack. Otherwise, 0 is pushed onto the stack. Whether an object is an instance of a class is determined exactly as it is for the instanceof operator in .java source code. checkcast The checkcast instruction pops a reference from the stack and compares that object to a ClassInfo structure in the constant pool. The index to the ClassInfo structure in the constant pool is read from the two bytes in the code array immediately following the checkcast instruction. If the object can be cast to the given type, then the reference to it is pushed back onto the stack. There is thus no net change in the stack. However, if the object may not be cast to the specified type, then a ClassCastException is thrown. The rules for determining whether to push back the reference or throw an exception are the same as the rules given in the Java Language Specification for determining whether a cast is permitted. The checkcast instruction behaves very much like the instanceof instruction. The two differences are what each instruction does to the stack and the treatment of null. Instanceof puts an int onto the stack. Checkcast puts a reference onto the stack or throws a ClassCastException. Null is not an instance of any type, but it may be cast to any type. Threads: monitorenter and monitorexitMost of Javas thread support is either in the class libraries or in other parts of the virtual machine. The only part that requires direct byte code support is synchronization. There are two instructions that allow a thread to place and release locks on objects. These are monitorenter and monitorexit. Each object is associated with a unique monitor. When a thread executes the monitorenter instruction, it pops a reference to an object from the stack and tries to take possession of the monitor for that object. If some other thread already possesses that monitor, then this thread stops and waits for the monitor to be released. To release a monitor, a thread uses the monitorexit instruction. A reference to the object whose monitor is to be released is popped from the stack.
|
![]() |
|