Exception tables - what's going on here?

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

  1. they have the same exception handler address (indicates that they belong to the same original try block)
  2. 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.

I’m not so sure that attempting to use C++'s inbuilt try/catch mechanism is going to yield you good (or even working) results here.

Cas :slight_smile:

The alternative would be to use setjmp/longjmp. That would suffer from the same issues, namely, i can’t jump into a block guarded by setjmp. So, the problem stays the same independent of the mechanism used to implement exceptions.

It’s definitely a difficult puzzle. I thought about translating code from one language to C++. Exceptions were where I got stuck. You will probably want to know exactly what’s going on two create multiple entries in the exception table before moving forward.

It might be wrong to think of the exception table entry as a try-block. Try-catch blocks are probably at a higher level than bytecode. Maybe (emphasize “maybe”) you should think of start as the location where you attach an exception handler and end as the location where you remove an exception handler. Exception handlers can be chained like a stack. If an exception happens, the exception handler gets “called”, cleans up after its block of code, checks to see if it can handle that type of exception, then either runs its catch block or hands off control to the previous exception handler in the stack. Returning from a function would have to remove exception handlers one at a time until its own exception handlers are gone.

I don’t know whether the JVM actually treats exception handling that way (and if that’s the reason the blocks are “split”), so don’t take my advice without confirming it. One way or another, I don’t know how that could be done in C/C++, but let me know if there is a good solution for it.

I’m too lazy to look, but aren’t the ranges inclusive? If so then this is just the compiler spitting stuff out straight without any attempt to generate minimal data.

Exception handling in general…aren’t there frameworks for structured exception handing?

Yeah, Java try/catch blocks have no 1:1 mapping to exception table entries in general. However, for most setups that don’t include loops/return statements, the mapping is actually workable. I can live with their not being a strict mapping, i was just wondering why some try blocks get split up when a return statement is contained. Thanks for the input.

My feeling is that the compiler spits out exception table entries for each basic block, that would explain why it creates two entries for a single try block that contains a return statement.

Yes, but i try to keep the dependencies to a minimum. Most SEH libs for C do not offer anything that C++ exception handling is lacking for my use case. On the contrary, C++ will do the type checking for me, which makes things easier.

All i need to figure out is how to merge exception table entries, i think my ruleset above is sufficient to do that.

I don’t know C++, but in the worst case could you just wrap the whole method in a while/try/catch and use Duff’s device to jump to the correct place?