KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > debugger > jpda > actions > StepActionProvider


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.netbeans.modules.debugger.jpda.actions;
20
21 import com.sun.jdi.Location;
22 import com.sun.jdi.ThreadReference;
23 import com.sun.jdi.VMDisconnectedException;
24 import com.sun.jdi.IncompatibleThreadStateException;
25 import com.sun.jdi.VirtualMachine;
26 import com.sun.jdi.event.Event;
27 import com.sun.jdi.event.LocatableEvent;
28 import com.sun.jdi.request.StepRequest;
29 import java.util.Arrays JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Set JavaDoc;
34 import java.util.logging.Logger JavaDoc;
35 import org.netbeans.api.debugger.ActionsManager;
36 import org.netbeans.api.debugger.DebuggerManager;
37 import org.netbeans.api.debugger.Session;
38 import org.netbeans.api.debugger.jpda.JPDABreakpoint;
39 import org.netbeans.api.debugger.jpda.MethodBreakpoint;
40 import org.netbeans.api.debugger.jpda.Variable;
41 import org.netbeans.modules.debugger.jpda.ExpressionPool;
42 import org.netbeans.modules.debugger.jpda.JPDAStepImpl.MethodExitBreakpointListener;
43 import org.netbeans.modules.debugger.jpda.JPDAStepImpl.SingleThreadedStepWatch;
44 import org.netbeans.modules.debugger.jpda.SourcePath;
45 import org.netbeans.modules.debugger.jpda.breakpoints.MethodBreakpointImpl;
46 import org.netbeans.spi.debugger.ContextProvider;
47 import org.netbeans.api.debugger.jpda.JPDADebugger;
48 import org.netbeans.api.debugger.jpda.JPDAThread;
49 import org.netbeans.api.debugger.jpda.SmartSteppingFilter;
50 import org.netbeans.modules.debugger.jpda.JPDADebuggerImpl;
51 import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
52 import org.netbeans.modules.debugger.jpda.util.Executor;
53 import org.netbeans.spi.debugger.ActionsProvider;
54 import org.netbeans.spi.debugger.jpda.EditorContext.Operation;
55 import org.openide.ErrorManager;
56 import org.openide.util.NbBundle;
57
58
59 /**
60  * Implements non visual part of stepping through code in JPDA debugger.
61  * It supports standart debugging actions StepInto, Over, Out, RunToCursor,
62  * and Go. And advanced "smart tracing" action.
63  *
64  * @author Jan Jancura
65  */

66 public class StepActionProvider extends JPDADebuggerActionProvider
67 implements Executor {
68     
69     private StepRequest stepRequest;
70     private ContextProvider lookupProvider;
71     private MethodExitBreakpointListener lastMethodExitBreakpointListener;
72     private SingleThreadedStepWatch stepWatch;
73
74     
75     private static boolean ssverbose =
76         System.getProperty ("netbeans.debugger.smartstepping") != null;
77     private static Logger JavaDoc logger = Logger.getLogger("org.netbeans.modules.debugger.jpda.jdievents"); // NOI18N
78

79
80     private static int getJDIAction (Object JavaDoc action) {
81         if (action == ActionsManager.ACTION_STEP_OUT)
82             return StepRequest.STEP_OUT;
83         if (action == ActionsManager.ACTION_STEP_OVER)
84             return StepRequest.STEP_OVER;
85         throw new IllegalArgumentException JavaDoc ();
86     }
87     
88     
89     public StepActionProvider (ContextProvider lookupProvider) {
90         super (
91             (JPDADebuggerImpl) lookupProvider.lookupFirst
92                 (null, JPDADebugger.class)
93         );
94         this.lookupProvider = lookupProvider;
95         setProviderToDisableOnLazyAction(this);
96     }
97
98
99     // ActionProviderSupport ...................................................
100

101     public Set JavaDoc getActions () {
102         return new HashSet JavaDoc<Object JavaDoc>(Arrays.asList (new Object JavaDoc[] {
103             ActionsManager.ACTION_STEP_OUT,
104             ActionsManager.ACTION_STEP_OVER
105         }));
106     }
107     
108     public void doAction (final Object JavaDoc action) {
109         runAction(action);
110     }
111     
112     public void postAction(final Object JavaDoc action,
113                            final Runnable JavaDoc actionPerformedNotifier) {
114         doLazyAction(new Runnable JavaDoc() {
115             public void run() {
116                 try {
117                     runAction(action);
118                 } finally {
119                     actionPerformedNotifier.run();
120                 }
121             }
122         });
123     }
124     
125     public void runAction(final Object JavaDoc action) {
126         synchronized (getDebuggerImpl ().LOCK) {
127             //S ystem.out.println("\nStepAction.doAction");
128
try {
129                 // 1) init info about current state & remove old
130
// requests in the current thread
131
JPDAThreadImpl resumeThread = (JPDAThreadImpl) getDebuggerImpl().getCurrentThread();
132                 ThreadReference tr = resumeThread.getThreadReference ();
133                 removeStepRequests (tr);
134
135                 // 2) create new step request
136
VirtualMachine vm = getDebuggerImpl ().getVirtualMachine ();
137                 if (vm == null) return ; // There's nothing to do without the VM.
138
stepRequest = vm.eventRequestManager ().createStepRequest (
139                         tr,
140                         StepRequest.STEP_LINE,
141                         getJDIAction (action)
142                     );
143                 stepRequest.addCountFilter (1);
144                 getDebuggerImpl ().getOperator ().register (stepRequest, StepActionProvider.this);
145                 int suspendPolicy = getDebuggerImpl().getSuspend();
146                 stepRequest.setSuspendPolicy(suspendPolicy);
147                 try {
148                     stepRequest.enable ();
149                 } catch (IllegalThreadStateException JavaDoc itsex) {
150                     // the thread named in the request has died.
151
// Or suspend count > 1 !
152
//itsex.printStackTrace();
153
//System.err.println("Thread: "+tr.name()+", suspended = "+tr.isSuspended()+", suspend count = "+tr.suspendCount()+", status = "+tr.status());
154
logger.warning(itsex.getLocalizedMessage()+"\nThread: "+tr.name()+", suspended = "+tr.isSuspended()+", suspend count = "+tr.suspendCount()+", status = "+tr.status());
155                     getDebuggerImpl ().getOperator ().unregister(stepRequest);
156                     return ;
157                 }
158                 logger.fine("JDI Request (action "+action+"): " + stepRequest);
159                 if (action == ActionsManager.ACTION_STEP_OUT) {
160                     addMethodExitBP(tr);
161                 }
162
163                 // 3) resume JVM
164
if (suspendPolicy == JPDADebugger.SUSPEND_EVENT_THREAD) {
165                     stepWatch = new SingleThreadedStepWatch(getDebuggerImpl(), stepRequest);
166                     getDebuggerImpl().resumeCurrentThread();
167                     //resumeThread.resume();
168
} else {
169                     getDebuggerImpl ().resume ();
170                 }
171             } catch (VMDisconnectedException e) {
172                 ErrorManager.getDefault().notify(ErrorManager.USER,
173                     ErrorManager.getDefault().annotate(e,
174                         NbBundle.getMessage(StepActionProvider.class,
175                             "VMDisconnected")));
176             }
177             //S ystem.out.println("/nStepAction.doAction end");
178
}
179     }
180     
181     private void addMethodExitBP(ThreadReference tr) {
182         if (!MethodBreakpointImpl.canGetMethodReturnValues(tr.virtualMachine())) {
183             return ;
184         }
185         Location loc;
186         try {
187             loc = tr.frame(0).location();
188         } catch (IncompatibleThreadStateException ex) {
189             logger.fine("Incompatible Thread State: "+ex.getLocalizedMessage());
190             return ;
191         }
192         String JavaDoc classType = loc.declaringType().name();
193         String JavaDoc methodName = loc.method().name();
194         MethodBreakpoint mb = MethodBreakpoint.create(classType, methodName);
195         //mb.setMethodName(methodName);
196
mb.setBreakpointType(MethodBreakpoint.TYPE_METHOD_EXIT);
197         mb.setHidden(true);
198         mb.setSuspend(JPDABreakpoint.SUSPEND_NONE);
199         lastMethodExitBreakpointListener = new MethodExitBreakpointListener(mb);
200         mb.addJPDABreakpointListener(lastMethodExitBreakpointListener);
201         DebuggerManager.getDebuggerManager().addBreakpoint(mb);
202     }
203     
204     protected void checkEnabled (int debuggerState) {
205         Iterator JavaDoc i = getActions ().iterator ();
206         while (i.hasNext ())
207             setEnabled (
208                 i.next (),
209                 (debuggerState == getDebuggerImpl ().STATE_STOPPED) &&
210                 (getDebuggerImpl ().getCurrentThread () != null)
211             );
212     }
213     
214     // Executor ................................................................
215

216     /**
217      * Executes all step actions and smart stepping.
218      *
219      * Should be called from Operator only.
220      */

221     public boolean exec (Event ev) {
222         // TODO: fetch current engine from the Event
223
// 1) init info about current state
224
if (stepWatch != null) {
225             stepWatch.done();
226             stepWatch = null;
227         }
228         LocatableEvent event = (LocatableEvent) ev;
229         String JavaDoc className = event.location ().declaringType ().name ();
230         ThreadReference tr = event.thread ();
231         if (stepRequest.depth() == StepRequest.STEP_OUT) {
232             setLastOperation(tr);
233         }
234         synchronized (getDebuggerImpl ().LOCK) {
235             //S ystem.out.println("/nStepAction.exec");
236

237             // 2) remove step request
238
//removeStepRequests (((LocatableEvent) ev).thread ());
239

240             
241             // 3) ignore step events in not current threads
242
JPDAThreadImpl ct = (JPDAThreadImpl) getDebuggerImpl ().
243                 getCurrentThread ();
244             if (ct != null &&
245                 !ct.getThreadReference ().equals (tr)
246             ) {
247                 // step finished in different thread => ignore
248
return true; // resume debugging
249
}
250             
251             int suspendPolicy = getDebuggerImpl().getSuspend();
252             
253             // 4) stop execution here?
254

255             // Synthetic method?
256
try {
257                 if (ct.getThreadReference().frame(0).location().method().isSynthetic()) {
258                     //S ystem.out.println("In synthetic method -> STEP OVER/OUT again");
259

260                     removeStepRequests (ct.getThreadReference ());
261                     int step = ((StepRequest)ev.request()).depth();
262                     VirtualMachine vm = getDebuggerImpl ().getVirtualMachine ();
263                     if (vm == null) {
264                         return false; // The session has finished
265
}
266                     stepRequest = vm.eventRequestManager ().createStepRequest (
267                         ct.getThreadReference (),
268                         StepRequest.STEP_LINE,
269                         step
270                     );
271                     stepRequest.addCountFilter(1);
272                     getDebuggerImpl ().getOperator ().register (stepRequest, this);
273                     stepRequest.setSuspendPolicy (suspendPolicy);
274                     try {
275                         stepRequest.enable ();
276                     } catch (IllegalThreadStateException JavaDoc itsex) {
277                         // the thread named in the request has died.
278
getDebuggerImpl ().getOperator ().unregister(stepRequest);
279                         stepRequest = null;
280                     }
281                     return true;
282                 }
283             } catch (IncompatibleThreadStateException e) {
284                 ErrorManager.getDefault().notify(e);
285             }
286             
287             // Not synthetic
288
boolean fsh = getSmartSteppingFilterImpl ().stopHere (className);
289             if (ssverbose)
290                 System.out.println("SS SmartSteppingFilter.stopHere (" +
291                     className + ") ? " + fsh
292                 );
293             if (fsh) {
294                 JPDAThread t = getDebuggerImpl ().getThread (tr);
295                 if (getCompoundSmartSteppingListener ().stopHere
296                      (lookupProvider, t, getSmartSteppingFilterImpl ())
297                 ) {
298                     // YES!
299
Session session = (Session) lookupProvider.lookupFirst(null, Session.class);
300                     if (session != null) {
301                         DebuggerManager.getDebuggerManager().setCurrentSession(session);
302                     }
303                     getDebuggerImpl ().setStoppedState (tr);
304                     //S ystem.out.println("/nStepAction.exec end - do not resume");
305
return false; // do not resume
306
}
307             }
308
309             // do not stop here -> start smart stepping!
310
if (ssverbose)
311                 System.out.println("\nSS: SMART STEPPING START! ********** ");
312             boolean stepInto = ((StepRequest) ev.request ()).depth () ==
313                             StepRequest.STEP_INTO;
314             getStepIntoActionProvider ().doAction
315                 (ActionsManager.ACTION_STEP_INTO);
316             //S ystem.out.println("/nStepAction.exec end - resume");
317
return true; // resume
318
}
319     }
320     
321     private void setLastOperation(ThreadReference tr) {
322         Location loc;
323         try {
324             loc = tr.frame(0).location();
325         } catch (IncompatibleThreadStateException itsex) {
326             logger.fine("Incompatible Thread State: "+itsex.getLocalizedMessage());
327             return ;
328         }
329         Session currentSession = DebuggerManager.getDebuggerManager().getCurrentSession();
330         String JavaDoc language = currentSession == null ? null : currentSession.getCurrentLanguage();
331         SourcePath sourcePath = getDebuggerImpl().getEngineContext();
332         String JavaDoc url = sourcePath.getURL(loc, language);
333         ExpressionPool exprPool = getDebuggerImpl().getExpressionPool();
334         ExpressionPool.Expression expr = exprPool.getExpressionAt(loc, url);
335         if (expr == null) {
336             return ;
337         }
338         Operation[] ops = expr.getOperations();
339         // code index right after the method call (step out)
340
int codeIndex = (int) loc.codeIndex();
341         byte[] bytecodes = loc.method().bytecodes();
342         if (codeIndex >= 5 && (bytecodes[codeIndex - 5] & 0xFF) == 185) { // invokeinterface
343
codeIndex -= 5;
344         } else {
345             codeIndex -= 3; // invokevirtual, invokespecial, invokestatic
346
}
347         int opIndex = expr.findNextOperationIndex(codeIndex - 1);
348         Operation lastOperation;
349         if (opIndex >= 0 && ops[opIndex].getBytecodeIndex() == codeIndex) {
350             lastOperation = ops[opIndex];
351         } else {
352             return ;
353         }
354         if (lastMethodExitBreakpointListener != null) {
355             Variable returnValue = lastMethodExitBreakpointListener.getReturnValue();
356             lastMethodExitBreakpointListener.destroy();
357             lastMethodExitBreakpointListener = null;
358             lastOperation.setReturnValue(returnValue);
359         }
360         JPDAThreadImpl jtr = (JPDAThreadImpl) getDebuggerImpl().getThread(tr);
361         jtr.addLastOperation(lastOperation);
362         jtr.setCurrentOperation(lastOperation);
363     }
364     
365     private StepIntoActionProvider stepIntoActionProvider;
366     
367     private StepIntoActionProvider getStepIntoActionProvider () {
368         if (stepIntoActionProvider == null) {
369             List JavaDoc l = lookupProvider.lookup (null, ActionsProvider.class);
370             int i, k = l.size ();
371             for (i = 0; i < k; i++)
372                 if (l.get (i) instanceof StepIntoActionProvider)
373                     stepIntoActionProvider = (StepIntoActionProvider) l.get (i);
374         }
375         return stepIntoActionProvider;
376     }
377
378     private SmartSteppingFilterImpl smartSteppingFilterImpl;
379     
380     private SmartSteppingFilterImpl getSmartSteppingFilterImpl () {
381         if (smartSteppingFilterImpl == null)
382             smartSteppingFilterImpl = (SmartSteppingFilterImpl) lookupProvider.
383                 lookupFirst (null, SmartSteppingFilter.class);
384         return smartSteppingFilterImpl;
385     }
386
387     private CompoundSmartSteppingListener compoundSmartSteppingListener;
388     
389     private CompoundSmartSteppingListener getCompoundSmartSteppingListener () {
390         if (compoundSmartSteppingListener == null)
391             compoundSmartSteppingListener = (CompoundSmartSteppingListener) lookupProvider.
392                 lookupFirst (null, CompoundSmartSteppingListener.class);
393         return compoundSmartSteppingListener;
394     }
395 }
396
Popular Tags