Possible compiler bug: continue is skipped after or-condition
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Feb 17 15:31:46 UTC 2020
I'm with Bernard here - presumably, javac could have different code
generation strategies to allow for more or less source code fidelity. In
practice, the cost of doing this (and maintaining this moving forward)
is relatively high. In addition, I'm skeptical of doing anything without
taking a more holistic approach how which kind of concrete source to
bytecode fidelity level do we want to allow with flags XYZ, noting that,
currently, source vs. classfile mismatches originates not only in the
backend (because of optimizations such as the one described in this
thread), but also because of specific ways in which javac decides to
'compress' its internal AST representation -- for instance, javac
aggressively constant folds string concatenation expressions, if it
realizes that all components of the concatenation are constant - which
means no real concatenation will happen at runtime.
So, rather than focusing on this specific use case, I think it would be
more useful to collect _a list_ of all such use cases, describe how the
behavior e.g. with IDE debugger, and/or code coverage tool deviates from
expectations, and then see if we start to see some patterns emerging.
Maurizio
On 17/02/2020 14:45, B. Blaser wrote:
> Roland,
>
> I believe the current behavior to skip line 7, as you described below,
> looks correct.
> However, we could probably generate something closer to the source
> code when enabling debug with "-g" as we did for lambda factorization
> [1], for example.
> Maybe someone else could comment on this but I'm not sure the gain
> would worth the pain as you could certainly put a breakpoint on line
> 5.
>
> Any feedback is welcome,
> Bernard
>
> [1] http://mail.openjdk.java.net/pipermail/amber-dev/2018-March/002819.html
>
> On Sat, 15 Feb 2020 at 23:28, Roland Illig <roland.illig at gmx.de> wrote:
>> On 08.02.2020 20:05, Roland Illig wrote:
>>> /* - */ public class Demo {
>>> /* - */ static String[] strings = {"1a", "1b", "2", "3"};
>>> /* - */
>>> /* - */ public static void main(String[] args) {
>>> /* 5 */ for (String s : strings) {
>>> /* 6 */ if (s.equals("1a") || s.equals("1b")) {
>>> /* 7 */ continue;
>>> /* - */ }
>>> /* 9 */ if (s.equals("2")) {
>>> /* - */ continue;
>>> /* - */ }
>>> /* - */ System.out.println(s);
>>> /* - */ }
>>> /* - */ }
>>> /* - */ }
>> I investigated the problem a bit and found the cause.
>>
>> The documentation for Code.pendingJumps says:
>> > A chain for jumps to be resolved before the next opcode
>> > is emitted. We do this lazily to avoid jumps to jumps.
>>
>> This "jumps to jumps" that the pendingJumps successfully avoids is
>> exactly the code I expect to be generated. The first jump to line 7 is
>> necessary to visit the breakpoint there, even if that jump is followed
>> directly by another jump to line 5.
>>
>> I stepped through the code using a debugger, and when I skipped over the
>> following two lines in Code.branch once, the code was generated exactly
>> as I had expected it from the beginning.
>>
>> result = pendingJumps;
>> pendingJumps = null;
>>
>> Commenting these lines out will of course have other side effects, but
>> at least it makes the breakpoint in line 7 work again as expected.
More information about the compiler-dev
mailing list