6 Replies Latest reply: Oct 16, 2008 6:22 PM by 843810 RSS

    Trace For -Loop variable

    843810
      I am trying to trace for-loop . The counter variable does not show the last value in the stack frame variables. For example if my code is as:
      public class ForCounter
      {
      public static void main(String args[])
      { 
      for (int i =0;i<=5;i++)
      {
      System.out.println(i);
      
      }
      }
      }
      My output is as:

      Event Location =ForCounter:5

      ForCounter.java:5 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      Event Location =ForCounter:7

      ForCounter.java:7 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 0
      Event Location =ForCounter:5

      ForCounter.java:5 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 0
      Event Location =ForCounter:7

      ForCounter.java:7 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 1
      Event Location =ForCounter:5

      ForCounter.java:5 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 1
      Event Location =ForCounter:7

      ForCounter.java:7 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 2
      Event Location =ForCounter:5

      ForCounter.java:5 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 2
      Event Location =ForCounter:7

      ForCounter.java:7 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 3
      Event Location =ForCounter:5

      ForCounter.java:5 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 3
      Event Location =ForCounter:7

      ForCounter.java:7 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 4

      Event Location =ForCounter:5

      ForCounter.java:5 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 4
      Event Location =ForCounter:7

      ForCounter.java:7 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 5
      Event Location =ForCounter:5

      ForCounter.java:5 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)
      int i = 5
      Event Location =ForCounter:10

      ForCounter.java:10 in method main() ****
      java.lang.String[] args = instance of java.lang.String[0] (id=38)

      *{color:#ff0000}the variable i doesnt get the value 6 as I expected in the comparison process? Any idea How can I see that?*
      *As I understood , the variable i values incremented and at the last step when the comparison failed the body of the for loop doesnt execute. ( 6 is not <= 5){color}*
        • 1. Re: Trace For -Loop variable
          800575
          Run javap -v on your .class file and checkout the bytecodes, the line number table, and the local variable table. Note that the increment of i and the test and branch are all on the same line. If you stop on that line the last time thru the loop, i will contain 5 (as you show below). If you then do a 'next' debugger command, the program will execute all the bytecodes on line 5 before it stops again. Thus, the next time it stops, i will have been bumped to 6, the compare against 5 will have failed, and you will be stopped at the line that follows the loop, at which point i is no longer defined.

          If you step across individual bytecodes, eg, the jdb stepi command, you will see i get a value of 6.
          • 2. Re: Trace For -Loop variable
            843810
            I am posting the code here to see what I mean. I need to compare these 2 programs that produces the same output. The stack frame trace must be the sme, but when I run the code on them. it doesn't work. I wish to know why in the for loop the value of i doesn't reach the value 4 as it showes in normal debugging. I am really thanx for your help.

            The two programs that I am comparing is:
            1-
            public class WhileCounter
            {
                 public static void main(String args[])
                 {     
                      int i = 0;
                     while ( i <= 3)
                      {
                           System.out.println(i);
                          i++;
                      
                      }
                 }
            }
            --------------------------------------------------------------------
            and
            2-
            public class ForCounter
            {
                 public static void main(String args[])
                 {     
                      for (int i =0;i<=3;i++)
                      {
                           System.out.println(i);
                          
                      }
                 }
            }
            --------------------------------------------------------------------------------
            The Trace program that I am using is :
            // ****** Trace.java ******
            import java.io.*;
            import java.util.*; 
            import com.sun.jdi.*;
            import com.sun.jdi.request.*;
            import com.sun.jdi.event.*;
            import com.sun.jdi.connect.*;
            class Trace {
             
                // Running remote VM
                private final VirtualMachine vm;
             
                // Thread transferring remote error stream to our error stream
                private Thread errThread = null;
             
                // Thread transferring remote output stream to our output stream
                private Thread outThread = null;
             
                /**
                 * main
                 */
                public static void main(String[] args) {
                 new Trace(args);
                }
             
                /**
                 * Launch target VM.
                 * Generate the trace.
                 */
                Trace(String[] args) {
                 PrintWriter writer = new PrintWriter(System.out);
             
                 // Launch target VM - Foo is the class to be executed
                    vm = launchTarget("WhileCounter");
                    generateTrace(writer);
                }
             
                /**
                 * Generate the trace.
                 * Enable events, start thread to display events,
                 * start threads to forward remote error and output streams,
                 * resume the remote VM, wait for the final event, and shutdown.
                 */
                void generateTrace(PrintWriter writer) {
                    vm.setDebugTraceMode(VirtualMachine.TRACE_NONE);
                    EventThread eventThread = new EventThread(vm, writer);
                    eventThread.start();
                    redirectOutput();
                    vm.resume();
             
                    // Shutdown begins when event thread terminates
                 try {
                     eventThread.join();
                     errThread.join(); // Make sure output is forwarded
                     outThread.join(); // before we exit
                 } catch (InterruptedException exc) {
                     // we don't interrupt
                 }
                 writer.close();
                }
             
                /**
                 * Launch target VM.
                 * Forward target's output and error.
                 */
                VirtualMachine launchTarget(String mainArgs) {
                 LaunchingConnector connector = findLaunchingConnector();
                 Map arguments = connectorArguments(connector, mainArgs);
                    try {
                     return connector.launch(arguments);
                    } catch (IOException exc) {
                        throw new Error("Unable to launch target VM: " + exc);
                    } catch (IllegalConnectorArgumentsException exc) {
                        throw new Error("Internal error: " + exc);
                    } catch (VMStartException exc) {
                        throw new Error("Target VM failed to initialize: " +
                               exc.getMessage());
                    }
                }
             
                void redirectOutput() {
                    Process process = vm.process();
             
                    // Copy target's output and error to our output and error.
                    errThread = new StreamRedirectThread("error reader", process.getErrorStream(), System.err);
                    outThread = new StreamRedirectThread("output reader",process.getInputStream(), System.out);
             
                    errThread.start();
                    outThread.start();
                }
             
                /**
                 * Find a com.sun.jdi.CommandLineLaunch connector
                 */
                LaunchingConnector findLaunchingConnector() {
                    List<Connector> connectors = Bootstrap.virtualMachineManager().allConnectors();
             
                    for(Connector connector: connectors)
                        if (connector.name().equals("com.sun.jdi.CommandLineLaunch"))
                            return (LaunchingConnector)connector;
             
                    throw new Error("No launching connector");
                }
             
                /**
                 * Return the launching connector's arguments.
                 */
                Map connectorArguments(LaunchingConnector connector, String mainArgs) {
                    Map arguments = connector.defaultArguments();
                    Connector.Argument mainArg =
                                    (Connector.Argument)arguments.get("main");
                    if (mainArg == null) {
                        throw new Error("Bad launching connector");
                    }
                 mainArg.setValue(mainArgs);
             
                 // Need a VM that supports watchpoints
                 Connector.Argument optionArg = (Connector.Argument)arguments.get("options");
                 if (optionArg == null) {
                     throw new Error("Bad launching connector");
                 }
                 optionArg.setValue("-classic");
             
                 return arguments;
                }
            }
            import java.io.*;
            import java.util.*; 
            import com.sun.jdi.*;
            import com.sun.jdi.request.*;
            import com.sun.jdi.event.*;
            import com.sun.jdi.connect.*;
            class EventThread extends Thread {
             
                private final VirtualMachine vm;   // Running VM
                private final PrintWriter writer;  // Where output goes
             
                private boolean connected = true;  // Connected to VM
                private boolean vmDied = true;     // VMDeath occurred
             
                // Maps ThreadReference to ThreadTrace instances
                private Map traceMap = new HashMap();
             
                EventThread(VirtualMachine vm, PrintWriter writer) {
                    super("Event-Handler");
                    this.vm = vm;
                    this.writer = writer;
                }
             
                /**
                 * Run the event handling thread.
                 * As long as we are connected, get event sets off
                 * the queue and dispatch the events within them.
                 */
                public void run() {
                    EventQueue queue = vm.eventQueue();
                    while (connected) {
                        try {
                            EventSet eventSet = queue.remove();
                      for(Event e: eventSet)
                          handleEvent(e);
             
                            eventSet.resume();
                        } catch (InterruptedException exc) {
                            // Ignore
                        } catch (VMDisconnectedException discExc) {
                            break;
                        }
                    }
                }
             
                /**
                 * This class keeps context on events in one thread.
                 * In this implementation, context is the indentation prefix.
                 */
                class ThreadTrace {
                    final ThreadReference thread;
             
                 ThreadTrace(ThreadReference thread) {
                        this.thread = thread;
             
                        // Create step event which will step through all lines
                        EventRequestManager mgr = vm.eventRequestManager();
                        StepRequest req = mgr.createStepRequest(thread,
                                                                StepRequest.STEP_LINE,
                                                                StepRequest.STEP_INTO);
                        req.setSuspendPolicy(EventRequest.SUSPEND_ALL);
                         req.addClassFilter("WhileCounter");
                        req.enable();
                 }
             
                 private void println(String str) {
                     writer.println(str);
                 }
             
                 void printStackFrame(StackFrame sf) {
                     try {
                      for(LocalVariable localvar: sf.visibleVariables()) {
                          println("Local variable: " + localvar.name() + " = "+sf.getValue(localvar));
                      }
                     } catch(AbsentInformationException e) {
                       println("Got AbsentInformationException");
                     }
                 }
             
                 void stepEvent(StepEvent event)  {
                     try {
                      if(!event.thread().frame(0).location().sourceName().equals("WhileCounter.java"))
                          return;
                     } catch(Exception e) {
                      return;
                     }
             
                     try {
                      StackFrame sf = event.thread().frame(0);
             
                      println("\n**** " + sf.location().sourceName() +
                           ":" + sf.location().lineNumber() +
                           " in method " + sf.location().method().name() + "() ****");
             
                      for(StackFrame s: event.thread().frames()) {
                          printStackFrame(s);
                      }
                     } catch(Exception e) {
                      //foo
                     }
                 }
                }
             
                /**
                 * Returns the ThreadTrace instance for the specified thread,
                 * creating one if needed.
                 */
                ThreadTrace threadTrace(ThreadReference thread) {
                 return (ThreadTrace)traceMap.get(thread);
                }
             
                /**
                 * Dispatch incoming events
                 */
                private void handleEvent(Event event) {
                 if (event instanceof StepEvent) {
                     stepEvent((StepEvent)event);
                 } else if(event instanceof VMStartEvent) {
                     startEvent((VMStartEvent)event);
                 }
                }
             
                // Create entry in traceMap
                private void startEvent(VMStartEvent event) {
                 traceMap.put(event.thread(), new ThreadTrace(event.thread()));
                }
             
                // Forward event for thread specific processing
                private void stepEvent(StepEvent event)  {
                 threadTrace(event.thread()).stepEvent(event);
                }
            }
            --------------------------------------------------------------------------------------------------------------
            import java.io.*;
            import java.util.*; 
            import com.sun.jdi.*;
            import com.sun.jdi.request.*;
            import com.sun.jdi.event.*;
            import com.sun.jdi.connect.*;
            /**
             * StreamRedirectThread is a thread which copies it's input to
             * it's output and terminates when it completes.
             */
            class StreamRedirectThread extends Thread {
             
                private final Reader in;
                private final Writer out;
             
                private static final int BUFFER_SIZE = 2048;
             
                /**
                 * Set up.
                 * @param name  Name of the thread
                 * @param in    Stream to copy from
                 * @param out   Stream to copy to
                 */
                StreamRedirectThread(String name, InputStream in, OutputStream out) {
                 super(name);
                 this.in = new InputStreamReader(in);
                 this.out = new OutputStreamWriter(out);
                 setPriority(Thread.MAX_PRIORITY-1);
                }
             
                public void run() {
                    try {
                     char[] cbuf = new char[BUFFER_SIZE];
                     int count;
                     while ((count = in.read(cbuf, 0, BUFFER_SIZE)) >= 0) {
                      out.write(cbuf, 0, count);
                     }
                        out.flush();
                 } catch(IOException exc) {
                     System.err.println("Child I/O Transfer - " + exc);
                 }
                }
            }
            -----------------------------------------------------------------------------------------------

            The output from WhileCounter.java

            --------------------Configuration: <Default>--------------------
            Warning: classic VM not supported; client VM will be used
            0
            1
            2
            3

            **** WhileCounter.java:5 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)

            **** WhileCounter.java:6 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 0

            **** WhileCounter.java:8 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 0

            **** WhileCounter.java:9 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 0

            **** WhileCounter.java:6 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 1

            **** WhileCounter.java:8 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 1

            **** WhileCounter.java:9 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 1

            **** WhileCounter.java:6 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 2

            **** WhileCounter.java:8 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 2

            **** WhileCounter.java:9 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 2

            **** WhileCounter.java:6 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 3

            **** WhileCounter.java:8 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 3

            **** WhileCounter.java:9 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 3

            **** WhileCounter.java:6 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 4

            **** WhileCounter.java:12 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 4

            Process completed.

            -------------------------------------------------------------------------------------
            The output for ForCounter.java is
            --------------------Configuration: <Default>--------------------
            Warning: classic VM not supported; client VM will be used
            0
            1
            2
            3

            **** ForCounter.java:5 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)

            **** ForCounter.java:7 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 0

            **** ForCounter.java:5 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 0

            **** ForCounter.java:7 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 1

            **** ForCounter.java:5 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 1

            **** ForCounter.java:7 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 2

            **** ForCounter.java:5 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 2

            **** ForCounter.java:7 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 3

            **** ForCounter.java:5 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)
            Local variable: i = 3

            **** ForCounter.java:10 in method main() ****
            Local variable: args = instance of java.lang.String[0] (id=29)

            Process completed.
            • 3. Re: Trace For -Loop variable
              800575
              Iman_S wrote:
              I wish to know why in the for loop the value of i doesn't reach the value 4 as it showes in normal debugging.
              By 'normal debugging' do you mean when running this under jdb? Can you show us a log of running under jdb where a print i gives a value of 4?
              Have you compared the javap -v output of your two programs , looking at what bytecodes are on which lines, and the scopes of the variable i? I think if you do, you will see the reason why the two programs behave differently. And remember that you are doing a STEP_LINE - see the definition of this in the JDI spec.
              • 4. Re: Trace For -Loop variable
                843810
                {color:#0000ff}*Thanks a lot Jim,*
                {color}
                Yes, by normal debugging I meant running under idb. and it works fine using stepi command for both programs
                yes you are right. I think the problem with STEP_LINE. When I change it with the code to
                 StepRequest req = mgr.createStepRequest(thread,StepRequest.STEP_MIN, StepRequest.STEP_INTO); 
                it works and the last value of i is correct and as I expect.

                *My problem now is that I need the debugging information to be simple and I use it in my application to explain the program flow. {color:#008000}STEP_MIN will not help{color}. Any advice from you to fix this issue is really appreciated. Thanks a lot.*
                • 5. Re: Trace For -Loop variable
                  800575
                  I doubt that there is anything simple that you could do. You could look into how NetBeans does partial expression evaluation, but that is very complex.
                  • 6. Re: Trace For -Loop variable
                    843810
                    Probably too late to be helpful but the difference is in the scope of the variable i. If you move the declaration of i outside of the for loop you should be fine.

                    When you declare the variable in the for loop it goes out of scope when the for loop exits. Thus you never see the value of 4. If you declare the int i before the for loop, then you're going to have the variable in scope after the for loop exits. That is necessary in the while loop version because there is no syntax for declaring the variable solely within the loop.