[Mono-devel-list] SSA and try/catch/finally regions

Massimiliano Mantione massi at ximian.com
Tue Apr 5 03:05:20 EDT 2005

On Mon, 2005-04-04 at 22:23 +0200, Zoltan Varga wrote:
> with the current JIT, the liveness range of 'i' does not include the
> catch block, so if i is not made volatile, the JIT might allocate 'i'
> and a variable used in the catch block to the same global register,
> screwing things up.

Yes, the code has a comment pointing to bug #42136 about this.

But just to be sure I understand: if we had proper CFG edges,
the liveness range would be correct, would it?

My plan was to make sure the CFG had the following edges in
[1] Connection from the "end" of the try region to the catch
    region, *and* to the finally region if present, otherwise
    to the place where the control flow goes on.
[2] Connection from the end of the catch region to the
    start of the finally region, or to the place where the
    control flow goes on if there is no finally region.
[2] Connection from the end of the finally region to the
    place where the control flow goes on (like above, the one
    just "after" the whole try/catch/finally block).

A CFG of this shape looks like if the catch region were under
a conditional branch after the "end" of the try region, and
is then followed by the finally region.

Both the catch and the finally regions are dominated by the
try one (which is correct).
Also, the catch part is sort of "optional" (because in point
[1] we make it look that it can be "skipped"), while it is
evident that the finally region is "mandatory".
The only inaccuracy is the fact that in principle one could
reach the catch/finally regions from many places inside the
try region, which is not modeled in this CFG, because it is
done like if the try region were always executed entirely.

IMHO, trying to model correctly each edge from each point in
the try region that could throw an exception is overkill.
It is true that the resulting SSA representation would be
"perfect", but in practice all those "large" phi nodes would
not give us any useful information, because we cannot really
know which of those edges will be taken.

Instead, I was proposing to keep the CFG relatively simple.
The fact that some variables have "unpredictable" values
after the try block (because the try block *could* have not
been executed entirely) would be modeled using dummy store
instructions, which would force the SSA generation code to
give those variables a new SSA version.

I still have to check the exact places where those dummy
store instructions should be put.
Ideally, with a CFG of this shape, they should be put
exactly at the "end" of the try region.
In fact, it is the "exit" from the try region that we are
not modeling correctly, so it is that point that should be
If there is no single BB representing this "exit", I still
have to verify what would be the best thing to do... but
this is just an "implementation detail" ;-)
In any case, control flow transfers from the try region are
rigidly regulated and represented with special opcodes, so
it should not be hard tracking them.

This, for me, is a nice balance between the "perfectly
accurate" approach (one CFG edge for each place that could
throw an exception in the try region), and the "easy" one
(forget all optimizations on those variables in the whole
method because they are made volatile).
It gives you (almost?) all the optimization opportunities
of the accurate method, but keeps the CFG reasonable.

I hope I explained this clearly this time :-)


More information about the Mono-devel-list mailing list