This discussion is archived
6 Replies Latest reply: Oct 16, 2008 4:22 PM by 843810 RSS

Trace For -Loop variable

843810 Newbie
Currently Being Moderated
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 Newbie
    Currently Being Moderated
    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 Newbie
    Currently Being Moderated
    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 Newbie
    Currently Being Moderated
    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 Newbie
    Currently Being Moderated
    {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 Newbie
    Currently Being Moderated
    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 Newbie
    Currently Being Moderated
    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.