From my understanding, throw
is a primative jvm command. When this is called, the JVM "checks if the current call stack can catch it". if it can't, then java simply pops the call stack almost exactly as if a return was called. then the jvm "checks if the current call stack can catch it" and so on recursively.
My question: how is it algorithmically possible for the JVM to know where in the call stack can catch a given exception? Is there metadata stored in each call stack entry mapping exceptions to code blocks? is there a static data structure in the heap that somehow keeps track of this? because somewhere there has to be data keeping track of that.
The JVM specification has details about this.
In particular, section 4.7.3 gives details about the exception table, which is a series of entries saying which exceptions are caught between which instructions. Section 3.12 gives a concrete example of this.
How this metadata is mapped into native code for the JIT is a different matter, of course - and implementation-specific. For example, there could be some mapping back from each instruction location in the native JITted code back to the original bytecode location, at which point the exception table can be consulted to find the right handler.
Generally speaking: When an exception is thrown the JVM extracts the "call stack". This identifies which bytecode or machine instruction was being executed at each level in the call stack, along with the class and method associated with that location.
Then, for each method in the stack (starting with the method where the exception occurred and working backwards), the JVM looks (in the internal class object) at the method's table mapping try/catch ranges to bytecode/machine instruction ranges.
If a "match" is found in the table for a method, and the type of exception being thrown is a class being monitored for in the found range, then control is transferred to the catch
entry point, after setting the exception into a sort of parameter location so the catch
clause can reference it.
If a "match" is not found in the table then the call stack is effectively "popped", placing the next earlier method on top of the stack, and the above search for a "match" in the earlier method's table of try/catch ranges is repeated.
This of course is an over-simplification. There is a lot of extra logic involved in handling finally
ranges, eg, and several "edge" cases.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With