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

Problem with stepping after class redefine

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P2 P2
    • 7
    • hs11, 5.0u14, 6u2
    • hotspot
    • None
    • generic
    • generic

      We have found a problem with ignored step over requests submitted after a class redefine. It was encountered after "Compile on Save" feature was implemented in NetBeans, which is followed by redefinition of the changed classes.

      Basically the behavior is: after a method is redefined, step over such redefined method behaves as plain resume, the step event is not received.

      A sample application that demonstrates the problem is attached.
      Brief description:

      1) When "Compile on Save" is active, it allows to run or debug application that have compile errors. The parts of the application that can not be compiled throw RuntimeException in the bytecode.

      2) When the app is being debugged and such RuntimeException is triggered (we submit ExceptionRequest for that), we suspend the execution of the appropriate thread and wait if the user fix the compilation error in the source code.

      3) If the user fixes the compile error, we redefine the class and pop from the top frame so that we re-execute the (now fixed) method.

      4) If step over is submitted now, no step event is received. The strange thing is, that step into works fine. But even after step into is performed several times, or some line breakpoints are hit, next step over will just continue the thread and no event comes. It looks like it's not possible to step over the redefined method.

      Description of the sample application testcase:
      The testcase should be started via "run" script. It debugs an application that has a method which throws RuntimeException. (App.run())
      The debugger receives the exception and redefines the App class with changed run() method. Then it pops, submits a step over and resumes the thread (EventThread.doFixAndStep()). However, the app is finished and no step event is received.
      This test case is interesting. Here is the App.java file:

      % cat -n src/stepafterredefineclasses/App.java
           1 /*
           2 * To change this template, choose Tools | Templates
           3 * and open the template in the editor.
           4 */
           5
           6 package stepafterredefineclasses;
           7
           8 /**
           9 *
          10 * @author martin
          11 */
          12 public class App {
          13
          14 /**
          15 * @param args the command line arguments
          16 */
          17 public static void main(String[] args) {
          18 for (int i = 0; i < 10; i++) {
          19 run(i);
          20 }
          21 System.err.println("Something after the loop.");
          22 }
          23
          24 private static void run(int i) {
          25 XXX//System.err.println(i);
          26 }
          27 }

      Line 25 in App.java will keep the code from compiling.


      Here is the App.class file:

      % javap -c -private -classpath build/classes stepafterredefineclasses/App
      Compiled from "App.java"
      public class stepafterredefineclasses.App extends java.lang.Object{
      public stepafterredefineclasses.App();
        Code:
         0: aload_0
         1: invokespecial #1; //Method java/lang/Object."<init>":()V
         4: return

      public static void main(java.lang.String[]);
        Code:
         0: iconst_0
         1: istore_1
         2: iload_1
         3: bipush 10
         5: if_icmpge 18
         8: iload_1
         9: invokestatic #2; //Method run:(I)V
         12: iinc 1, 1
         15: goto 2
         18: getstatic #3; //Field java/lang/System.err:Ljava/io/PrintStream;
         21: ldc #4; //String Something after the loop.
         23: invokevirtual #5; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
         26: return

      private static void run(int);
        Code:
         0: new #6; //class java/lang/RuntimeException
         3: dup
         4: ldc #7; //String Uncompilable source code - not a statement
         6: invokespecial #8; //Method java/lang/RuntimeException."<init>":(Ljava/lang/String;)V
         9: athrow

      }


      The above App.class files blows up (as expected)
      when we try to run it:

      % java -classpath build/classes stepafterredefineclasses/App
      Exception in thread "main" java.lang.RuntimeException: Uncompilable source code - not a statement
              at stepafterredefineclasses.App.run(App.java:25)
              at stepafterredefineclasses.App.main(App.java:19)



      This App.class failure is meant to simulate the following:

      % javac src/stepafterredefineclasses/App.java
      src/stepafterredefineclasses/App.java:25: not a statement
              XXX//System.err.println(i);
              ^
      src/stepafterredefineclasses/App.java:25: ';' expected
              XXX//System.err.println(i);
                 ^
      2 errors


      What the JDI test does is catch a RuntimeException in the
      running App code and simulate a fix-and-recompile by
      redefining the "broken" class with a new class that isn't
      broken.

      The user thread is in App.run() when the exception is caught
      by the debugger. The debugger redefines App.class with the
      right bits, pops the current frame which takes the thread
      back to App.main(line 19) and then tries to do a "step over"
      to get over the call to run().

      The "step over" event never happens. However, the new version
      of run() is executed.

      If the "step over" is replaced by a "step in", then the "step
      in" event happens and the new version of run is also executed.

            dsamersoff Dmitriy Samersoff
            mentlich Martin Entlicher
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: