|exceptions & dataflow firstname.lastname@example.org (David James) (1998-02-03)|
|Re: exceptions & dataflow email@example.com (Anurag Acharya) (1998-02-07)|
|Re: exceptions & dataflow firstname.lastname@example.org (Sergey Solyanik) (1998-02-07)|
|Re: exceptions & dataflow email@example.com (Jason Merrill) (1998-02-08)|
|Re: exceptions & dataflow firstname.lastname@example.org (David L Moore) (1998-02-08)|
|Re: exceptions & dataflow email@example.com (David L Moore) (1998-02-09)|
|Re: exceptions & dataflow firstname.lastname@example.org (Sergey Solyanik) (1998-02-10)|
|Re: exceptions & dataflow email@example.com (Jason Merrill) (1998-02-10)|
|Re: exceptions & dataflow firstname.lastname@example.org (1998-02-10)|
|Re: exceptions & dataflow email@example.com (1998-02-10)|
|[7 later articles]|
|From:||Jason Merrill <firstname.lastname@example.org>|
|Date:||8 Feb 1998 13:32:47 -0500|
|Organization:||Cygnus Solutions, Sunnyvale, CA|
>>>>> Sergey Solyanik <email@example.com> writes:
> If you are working on Java-like language, one possible approach is to
> terminate basic blocks at each function call or instruction that can
> throw exceptions. Create conditional edges from these basic blocks to
> every catch block.
Yep, that's what we've been doing in egcs g++ (http://www.cygnus.com/egcs).
> Finallies do seem to complicate things significantly. For normal block
> exiting I cannot come up with anything better than duplicating the
> code when its practical, and spilling everything when it's not. One
> will apparently have to spill everything before any call site as well.
> Good thing about finally, though, is that it is either entered through
> normal try block exit (i. e. explicit jsr before jump out), but your
> either exit a function or transfer to catch block (which was
> anticipated by fake edges inserted above). So just spilling before
> each call and separating non-unrolled finallies from flow analysis
> seems to be enough.
I'm not sure what you're saying. I'm not very familiar with Java, but
finally blocks seem analogous to C++ implicit destructors in terms of
when they get run; the finally block is run on exit from the try block
by any means, and in C++ implicit destructors are run when a variable
goes out of scope by any means. I will call the two constructs
Our approach has been to treat cleanups as additional exception
regions. We duplicate the code for cleanups, so you have one copy
where flow continues into the rest of the program, and one that is
followed by a rethrow into an outer exception context. This seems to
work well, and there is no need to spill anything if register values
are preserved by your throw mechanism; flow handles this just fine.
In the case of finally, if you check the exception types inline, your
flow graph would have an edge from the case where none of the catch
blocks matched to the second copy of the finally block. If you check
the exception types in the throw mechanism, you would have edges from
each of the calls in the try block, just like your edges to the catch
If you can jump out of the exception region with return or break, you
can make a third or fourth copy. If you can jump out with goto (does
Java have goto?), this gets a bit more complicated, as you need to
decide where you're going to put the code for the cleanup. We put it
at the goto site, and have to do some fiddling with exception regions
to avoid having an exception thrown from the cleanup jump to the
I suppose it would be possible to use only one copy of a cleanup, but
that would require some sort of flag so it knows where to go once it's
> In Java, hardware exceptions can ony happen in very controlled manner
> (e. g. to test for null). If your language contains pointers, things
> are much worse and you'd have to break basic block with essentially
> any pointer dereference when you cannot prove that location exists.
We haven't decided yet what to do about this case. We'd like to find
a way to retain some basic block optimizations...
Return to the
Search the comp.compilers archives again.