try-catch-finally is easy to understand by byte code

Hello, I'm Architect Jun, an architect who writes code and poems. Today, let's talk about try-catch-finally by byte code. I hope you can help everyone improve!!!

scene

For the following code:

public int test() { int x; try { x = 1; return x; } catch (Exception e) { x = 2; return x; } finally { x = 3; } }

Just hear the voice of Architecture King coming from the mountains:

Back to the rock bank, the trees always come out of the wall roots.

Who is going to upload or downlink?

conclusion

  • If the try statement does not have an exception belonging to Exception or its subclasses, the return value is 1

  • If present, return value is 2

  • If an exception other than Exception occurs, no return occurs and the method exits abnormally

explain

The byte code obtained from javap is as follows (body part):

public int test(); descriptor: ()I flags: ACC_PUBLIC Code: stack=1, locals=5, args_size=1 0: iconst_1 //Push int type constant 1 into operand stack - > operand stack: 1, local variable table: empty 1: istore_1 //Stack values of type int into local variable 1->operand stack: empty, local variable table: slot1=1, that is, x=1 2: iload_1 //Load int type values from local variable table 1 into operand stack->operand stack: 1, local variable table: slot1=1 3: istore_2 //Stack values of type int into local variable 2->operand stack: empty, local variable table: slot1=1,slot2=1 4: iconst_3 //Push int type constant 3 into operand stack - > operand stack: 3, local variable table: slot1=1,slot2=1 5: istore_1 //Stack values of type int into local variable 1->operand stack: empty, local variable table: slot1=3,slot2=1 6: iload_2 //Load int type values from local variable table 2 into operand stack->operand stack: 1, local variable table: slot1=3,slot2=1 7: ireturn //return int type, where the top of the operand stack is 1, so return 1 (no exception) 8: astore_2//When an exception occurs in rows 0 to 3 jump here, copy Exception e from the catch and save it in the local variable table 2->slot2 = e 9: iconst_ 2 //Push int type constant 2 into operand stack->operand stack: 2, local variable table: slot2=e 10: istore_1 //Stack values of type int into local variable table 1->Operand stack: empty, local variable table: slot1=2 11: iload_1 //Load int type values from local variable table 1 into operand stack->operand stack: 2, local variable table: slot1=2 12: istore_3 //Stack values of type int into local variable table 3->operand stack: empty, local variable table: slot1=2,slot3=2 13: iconst_3 //Push int type constant 3 into operand stack - > operand stack: 3, local variable table: slot1=2,slot3=2 14: istore_1 //Stack values of type int into local variable table 1->Operand stack: empty, local variable table: slot1=3,slot3=2 15: iload_3 //Load int type values from Local Variable Table 3 into Operand Stack->Operand Stack: 2, Local Variable Table: slot1=3,slot3=2 16: ireturn //Return int type, where the top of the operand stack is 2, so return 2(Exception case) 17: astore 4 //Exceptions that are not part of Exception and its subclasses are stored in Local Variable Table 4->Local Variable Table: slot4=Exception Reference 19: iconst_3 //Push int type constant 3 into operand stack->operand stack: 3, local variable table: slot4=exception reference 20: istore_1 //Put the value of type int out of the stack and into the local variable table 1->Operand stack: empty, local variable table: slot1=3, slot4=exception reference 21: aload 4 //push the exception reference in local variable table 4 into the top 23: athrow //throw the top exception Exception table: from to type 0 4 8 Class java/lang/Exception 0 4 17 Any 17 17 Any

Each line of byte code in the above Code is commented out, and the state of the operand stack and local variable table is analyzed.

Where the byte code line numbers 0 to 7 are the byte code streams without exceptions, and the return value is 1.

It should be noted that in the above Code, lines 4 and 5 are finally: x=3. The compiler automatically generates redundancy in the finally statement block content once after each possible branch path to implement finally semantics. There are also lines 13, 14, 19, 20.

Then let's look at the exception handling table:

Exception table:

     from    to  target type

         0     4     8   Class java/lang/Exception

         0     4    17   any

         8    13    17   any

        17    19    17   any

It means that in the byte number line number:

  • Rows 0 to 3 If Exception or its subclasses are found, skip to line 8. If other exceptions are found, skip to line 17 to handle them

  • 8 to 12 lines, skip to 17 lines

  • The fourth row in the exception table: 17 19 17 any (that is, end_pc, which is an exclusive historical design error, where from and target have the same problems and other related information to supplement, it may be that the virtual machine handles something special in response to a certain situation, can't or has to look through the source code~)

Combining this exception table with the comments in Code, you can see that if Exception and its subclass exceptions occur in a try statement, the byte code executed is lines 8-16 and the final return value is 2. If there are other exceptions, skip to line 17, execute lines 17-23, and eventually throw the exception without returning the method value.

Another problem you can see from the exception table is that if an exception occurs in the catch block (rows 8 to 12), it also jumps to line 17 for processing, executing the final block of code.

Note: For x=1; this statement, although iconst and istore are two byte codes in the byte code, they are still atomic operations. Atomic operations are not just one instruction, but an uninterruptable series of operations or operations. You can compare the non-atomic protocols of long and double.

Reference: Deep understanding of Java virtual machines

Tags: Java Database Spring Spring Boot

Posted on Sat, 27 Nov 2021 13:05:35 -0500 by katie77