I’ve been trying to implement exception handling in Jack via using C++'s try/catch construct. Finally blocks are emitted by the Java compiler where appropriate, so i don’t need finally functionality.
I stumbled upon an interesting property of exception tables while implementing this. Here’s a piece of Java code:
public void forCatch() {
try {
for(int i = 0; i< 10; i++) {
if(i == 0) return;
}
} catch(Throwable t) {
}
}
That get’s compiled down to the following bytecode
0 iconst_0
1 istore_1
2 goto 13 (+11)
5 iload_1
6 ifne 10 (+4)
9 return
10 iinc 1 by 1
13 iload_1
14 bipush 10
16 if_icmplt 5 (-11)
19 goto 23 (+4)
22 astore_1
23 return
And the corresponding exception table looks like this:
start: 0 end: 9 handler: 22 cp_info #30 java/lang/Throwable
start: 10 end: 19 handler: 22 cp_info #30 java/lang/Throwable
I’m puzzled by the fact that the try block gets seemingly split up by the return statement inside the for loop.
Does anyone have an explanation for this?
The problem with this behaviour is, that i can’t create two try blocks (one from 0-9, another from 10-19), as code in the second block jumps into code in the first block. This is forbidden in C++ (can’t jump into a try block from outside), which makes sense as that would forgo setting up the exception handling (e.g. use setjmp to start the try block).
I was wondering if i coud merge entries in the table, to arrive at try/catch blocks that are consistent. I’d create merged try blocks, that store the end and start program counter, as well as a list of exceptions that get handled. I’d merge entries in the exception table if
- they have the same exception handler address (indicates that they belong to the same original try block)
- they share the same start and end program counter (nested try blocks need special handling though)
I’d be happy if someone had some input on this matter.