Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8164614

Code generator/debugger optimizes code so that I cannot set breakpoints on break statements and some loop statements

XMLWordPrintable

    • Icon: Enhancement Enhancement
    • Resolution: Not an Issue
    • Icon: P4 P4
    • 10
    • 8u92
    • core-svc
    • x86
    • os_x

      A DESCRIPTION OF THE REQUEST :
      Consider the program below. This is a simplified version of an actual program generated by ANTLR that I was trying to debug, to demonstrate the problem.

      My IDE (IntelliJ Idea) allows me to set breakpoints on the lines marked, but they are never hit because the Java compiler optimizes the bytecodes so that there is no place for the breakpoint to be placed.

      Looking at the bytecodes using javap -c, I see that the way the code has been optimized, there are no lines corresponding to the above marked places. The fact that my IDE does not warn me that breakpoints at those places are not going to work may be a bug in the IDE.

      However, it seriously impacts my ability to debug and single step through code when I cannot stop at the start or exit of a loop.

      JUSTIFICATION :
      When considering this request, please bear in mind that the sample program is intentionally simplified for clarity. In real code, it seriously impacts my ability to debug when seemingly valid statements are never reached. I set breakpoints and they are never reached. I single step and the cursor jumps down a page, outside of the loop I am in, even though it was positioned at an if statement prior to the step. I am left scratching my head, wondering how I got out of the loop.

      When I debug code that ANTLR generated, or that is in an open source package in compiled form, it is not practical to find all the places I want to stop and modify the code and recompile it so that there is an executable statement at the point I want to stop.

      As another example of how awkward the debugging can be, consider a method whose first statement is a loop statement. There is no convenient way to set a breakpoint when that method is entered.

      In other languages, using the -g option (debug) turns off optimizations so that the code generator makes sure to generate code (perhaps even inserting a no-op) so the debugger will behave predictably. However, it appears that Java does not do this automatically when -g is used, and I cannot find any way to set the level of optimization in Java.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      I would like to be able to set a breakpoint at the start of a loop, and at break statements in the loop (or break statements in a switch statement) and know for sure that the debugger will stop there. See my example program above.

      I would like to be able to single step through a loop and have the cursor stop at the loop entry, and also at the point where I am exiting the loop.

      This behavior should probably be automatic when compiling with -g, but it could also be controlled with an optional switch (e.g., -gg) that would make sure every place where one would expect to set a breakpoint would correspond to a position in the bytecodes.
      ACTUAL -
      Setting a breakpoint on a loop statement may or may not work, depending on whether the compiler actually generates any bytecodes before the first statement within the loop.

      Setting a breakpoint on a break statement in a loop or switch statement is similarly a shot in the dark. Unless I dump the byte codes with javap, I cannot know if the debugger will stop when it logically gets to that point.

      ---------- BEGIN SOURCE ----------
      /**
       * Debugger single step does not stop at seemingly valid statements.
       * Also, a breakpoint at those places is never hit.
       */
      public class SingleStep {
          public static void main(String[] args) {
              int blahblahblah = 0;
              while (2 * 2 * 2 * 2 == 16) { // Never get to this line
                  if (args.length > 10) {
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                      blahblahblah++;
                      blahblahblah--;
                  }
                  break; // Never get to this line
              }
              System.out.println(blahblahblah);
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The workaround is to insert dummy statements before the ones where I want to stop. However, this approach does not work if I am debugging code for which I do not have source (e.g., open source code in a jar file). This workaround is very tedious for generated code, such as a parser that is generated by ANTLR for a reasonably rich language. Furthermore, it must be repeated every time the file is regenerated.

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: