[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Options for replacing use of UnitGraph() constructor (continued)
(This is the question where I solicit input from people who
know how VMs should interpret the Java specification.)
vranganath> So, what is the meaning of unit graph in the
vranganath> situation when a unchecked exception is thrown
vranganath> after the execution of the following statement
vranganath> and omitExceptionalEdges is true.
vranganath> try {
vranganath> b = 5; //1
vranganath> a = b + c; //2
vranganath> //3
vranganath> } catch (Throwable e) {
vranganath> print a; //4
vranganath> }
vranganath> Clearly the 2 has no side-effect. It has the
vranganath> effect of setting a. (Or do you consider the
vranganath> latter as side-effect?) Similarly 1. Now
vranganath> clearly, a can be set at when control reaches 4
vranganath> if the async exception happens after a is
vranganath> assinged b+c but before 2 completes. This is
vranganath> possible according to JVM spec quoted below (JVM
vranganath> 1ed 2.15.2)
vranganath> "Java permits a small but bounded amount of
vranganath> execution to occur before an asynchronous
vranganath> exception is thrown. This dealy is permitted to
vranganath> allow optimized code to detect and throw these
vranganath> exceptions at points where it is practical to
vranganath> handle them while obeying the semantics of Java
vranganath> language."
You're correct, ExceptionalUnitGraph's constructor does not
consider 2 to have a side effect. I do not think it is clear
that 'a' may be set when control reaches 4 (unless there is some
code elided on line 3), though I agree with you that the
specification might allow that interpretation. Hence my appeal
for specification lawyers. More later.
vranganath> So, 2 "excepted" but no edges are added in the
vranganath> graph according to the javadocs of
vranganath> ExceptionalUnitGraph when
vranganath> omitExceptionalUnitEdges is true.
vranganath> "omitExceptingUnitEdges - indicates whether the
vranganath> CFG should omit edges to a handler from trapped
vranganath> Units which may throw an exception which the
vranganath> handler catches but which have no potential side
vranganath> effects."
Again, your description of how ExceptionalUnitGraph would treat
this example is accurate.
vranganath> and so the data flow analyses gives incorrect
vranganath> result by claiming the assignment to a at 2 is
vranganath> invisible at 4.
vranganath> If the above analysis is correct, then all units
vranganath> protected by an async exception catch block
vranganath> should have an outgoing exceptional edge to the
vranganath> corresponding handler. This is not true for sync
vranganath> exceptions. So, shouldn't the logic distinguish
vranganath> between exception sorts while pruning the edges
vranganath> in the CFG?
That's a good point and I'm glad you raised it, since I didn't
think of the special case of asynchronous exceptions myself.
Nevertheless, the current behaviour of ExceptionalUnitGraph can
be considered correct even in the light of section 2.15.2 of the
specification. It depends on how you split the hairs.
First, note that because the issue only arises in the case of
asynchronous exceptions, the only units affected are those which
are
a) protected by a handler which catches some asynchronous
exception type, and
b) have no successors which are themselves in the scope of
the same handler.
If the unit (let's call it x) does have a successor in the scope
of the same handler (call the successor y and the handler h),
then y can also throw exceptions to h (since any unit
can throw any asynchronous exception). Then ExceptionalUnitGraph
will add a CFG edge from x to h because x is a predecessor of y.
So, under what circumstances might x throw an asynchronous
exception to h without having any successors that do as well? In
the case where x is an unconditional branch whose target is
outside of the protected area, or if x is the last unit in the
protected area. Let's modify the example to have one example of
each possibility.
try {
if (moon == FULL) { //0
e = 0; //1
goto unprotected_target //2
}
b = 5; //3
a = b + c; //4
d = a / 2; //5
} catch (Throwable e) {
print e,b,a,d; //6
}
As you point out, a condition corresponding to an asynchronous
exception can occur at any point during the execution of this
code, and the VM can opt to delay delivering the exception until
it reaches a program point after that which was executing when
the exceptional condition arose.
ExceptionalUnitGraph will create CFG edges from lines 0, 1, 3,
and 4 to line 6 because each of those instructions have
successors which may throw a asynchronous exception that 6
catches. So the graph will indicate that at line 6, each of
variables e, b, and a may or may not have been assigned a new
value.
You're suggesting that there should also be an edge from 5 to 6
to indicate that d may have been assigned a new value when
control reaches line 6. To indicate why I think that
interpretation of the specification is incorrect, let's look at
the case of line 2 first.
Let's say an asynchronous error condition arises before line 2 is
executed, but the VM does not deliver it until after line 2 is
executed. In that case, control will have passed to the target of
the branch (what else can executing a goto mean?). That target is
outside the protected area, so when the VM delivers the exception
object, it will not be caught by the handler. So line 6 cannot be
executed as a result of an exception being delayed until after
line 2 executes.
Similarly I argue that if the exception is delayed until after
line 5 has assigned a new value to the variable d, then it is
being delivered after line 5 has completed execution. But when
line 5 has completed execution, the flow of control has exited
the protected area, so the exception will not be caught by line
6.
As I admitted at the outset, this is splitting hairs. I honestly
do believe that this is the sensible way to interpret the
specification, but I also concede that in practice there may be some
VM implementations that would deliver the asynchronous exception
to line 6 after performing line 5's assignment to d. Perhaps to
be safe ExceptionalUnitGraph should add edges to asynchronous
exception handlers from all protected units, regardless of
whether the units have side effects---on that issue I await input from people
with more experience interpreting the Java specs than I have.
In the meantime, feel free to leave omitExceptingUnits
set to false).