On Oct 13, 2011, at 9:01 PM, Charles Oliver Nutter wrote:
> Ok Hotspot guys, I have a challenge for the JIT. I want to basically do this:
>
> try {
> ...
> } catch (Exception e) {
> if (!(e instanceof SomeException)) throw e;
> ... handle e as SomeException
> }
>
> instead of explicitly adding exception-handling for SomeException.
> There's a few reasons for this:
>
> * Wiring up exception-handling in method handles is rather cumbersome.
> If I could do it with a single wrapper it would make my life easier.
> * Similar to the "multicatch" problem in Java 7, I often want nearly
> the same boilerplate code for multiple exception types.
> * Because Ruby is dynamically typed, we can't statically determine the
> *actual* expected exception type at compile time, and so we must do a
> bulk catch with type checks.
>
> My question, then, is whether Hotspot can see through this (assuming
> everything inlines) and see that although we're doing a bulk catch
> only certain cases *actually* handle the resulting exception.
Are you expecting some performance penalty from doing this? Generally speaking
if you are throwing exceptions at all then you've already lost a bunch of
performance. The lookups and unwinding are probably negligible in the general
case.
If the exception is thrown from a callee, out of sight of the current
compilation, then the only thing that's used for deciding where to dispatch is
the exception handler table in the method. There JIT isn't even involved in
that case until the exception reaches the current nmethod. Take a look at
exception_handler_for_return_address, which finds the PC to dispatch to in the
caller frame.
So in your case you might jump to the exception handler, do the type check and
then simply unwind as you would have before. C2 does something similar to what
you've done when dispatching exceptions. A single try with multiple catches
sends all exceptions to a single entry point in the compiled code which then
type checks them and dispatches to the right location, as you've done.
catch_inline_exceptions in doCall.cpp does this. C1 relies on the exception
handler table and dispatches them individually, with a separate entry point for
each type mentioned in a catch. For locally thrown and caught exceptions C2
maybe convert that directly into control flow and possibly simplify type checks
along the way. C1 still goes the long route.
So basically I would be surprised if doing what you're doing would hurt the
speed of throwing and catching exceptions by a measurable amount in real
programs.
Where it might hurt you is with compiled code complexity, assuming that you are
spreading your try/catch over large blocks of code that might not really need
handlers. Remember that every exception handler creates extra control flow
edges which can complicate code generation. This is very hard to quantify and
may or may not matter but it seemed worth mentioning. Basically it can
increase compile time and possibly result in worse register allocations but
that's a very vague worry.
Anyway, if you're worried abut it, I would suggested writing some test cases
that match what your usage and see if you can measure differences. There could
be pathologies here we're unaware of.
tom
>
> Thoughts?
>
> - Charlie
> _______________________________________________
> mlvm-dev mailing list
> [email protected]
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev
_______________________________________________
mlvm-dev mailing list
[email protected]
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev