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
> mlvm-dev@openjdk.java.net
> http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

_______________________________________________
mlvm-dev mailing list
mlvm-dev@openjdk.java.net
http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev

Reply via email to