Add support for specifying the debugging step size
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / engine / DebugProcessImpl.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.debugger.engine;
17
18 import com.intellij.Patches;
19 import com.intellij.debugger.*;
20 import com.intellij.debugger.actions.DebuggerAction;
21 import com.intellij.debugger.actions.DebuggerActions;
22 import com.intellij.debugger.apiAdapters.ConnectionServiceWrapper;
23 import com.intellij.debugger.engine.evaluation.*;
24 import com.intellij.debugger.engine.events.DebuggerCommandImpl;
25 import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
26 import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
27 import com.intellij.debugger.engine.requests.MethodReturnValueWatcher;
28 import com.intellij.debugger.engine.requests.RequestManagerImpl;
29 import com.intellij.debugger.impl.DebuggerContextImpl;
30 import com.intellij.debugger.impl.DebuggerSession;
31 import com.intellij.debugger.impl.DebuggerUtilsEx;
32 import com.intellij.debugger.impl.PrioritizedTask;
33 import com.intellij.debugger.jdi.StackFrameProxyImpl;
34 import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
35 import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
36 import com.intellij.debugger.settings.DebuggerSettings;
37 import com.intellij.debugger.settings.NodeRendererSettings;
38 import com.intellij.debugger.ui.breakpoints.BreakpointManager;
39 import com.intellij.debugger.ui.breakpoints.RunToCursorBreakpoint;
40 import com.intellij.debugger.ui.breakpoints.StepIntoBreakpoint;
41 import com.intellij.debugger.ui.tree.ValueDescriptor;
42 import com.intellij.debugger.ui.tree.render.*;
43 import com.intellij.execution.CantRunException;
44 import com.intellij.execution.ExecutionException;
45 import com.intellij.execution.ExecutionResult;
46 import com.intellij.execution.configurations.RemoteConnection;
47 import com.intellij.execution.process.*;
48 import com.intellij.execution.runners.ExecutionUtil;
49 import com.intellij.idea.ActionsBundle;
50 import com.intellij.openapi.Disposable;
51 import com.intellij.openapi.application.ApplicationManager;
52 import com.intellij.openapi.diagnostic.Logger;
53 import com.intellij.openapi.editor.Document;
54 import com.intellij.openapi.extensions.Extensions;
55 import com.intellij.openapi.project.Project;
56 import com.intellij.openapi.ui.Messages;
57 import com.intellij.openapi.util.Disposer;
58 import com.intellij.openapi.util.Pair;
59 import com.intellij.openapi.util.Ref;
60 import com.intellij.openapi.util.UserDataHolderBase;
61 import com.intellij.openapi.wm.ToolWindowId;
62 import com.intellij.openapi.wm.impl.status.StatusBarUtil;
63 import com.intellij.psi.PsiDocumentManager;
64 import com.intellij.psi.PsiFile;
65 import com.intellij.psi.search.GlobalSearchScope;
66 import com.intellij.ui.classFilter.ClassFilter;
67 import com.intellij.ui.classFilter.DebuggerClassFilterProvider;
68 import com.intellij.util.Alarm;
69 import com.intellij.util.EventDispatcher;
70 import com.intellij.util.StringBuilderSpinAllocator;
71 import com.intellij.util.concurrency.Semaphore;
72 import com.intellij.util.containers.ContainerUtil;
73 import com.intellij.util.containers.HashMap;
74 import com.intellij.util.ui.UIUtil;
75 import com.intellij.xdebugger.XDebugSession;
76 import com.intellij.xdebugger.impl.actions.XDebuggerActions;
77 import com.sun.jdi.*;
78 import com.sun.jdi.connect.*;
79 import com.sun.jdi.request.EventRequest;
80 import com.sun.jdi.request.EventRequestManager;
81 import com.sun.jdi.request.StepRequest;
82 import org.jetbrains.annotations.NonNls;
83 import org.jetbrains.annotations.NotNull;
84 import org.jetbrains.annotations.Nullable;
85
86 import javax.swing.*;
87 import java.io.IOException;
88 import java.net.UnknownHostException;
89 import java.util.*;
90 import java.util.concurrent.atomic.AtomicInteger;
91
92 public abstract class DebugProcessImpl extends UserDataHolderBase implements DebugProcess {
93   private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebugProcessImpl");
94
95   @NonNls private static final String SOCKET_ATTACHING_CONNECTOR_NAME = "com.sun.jdi.SocketAttach";
96   @NonNls private static final String SHMEM_ATTACHING_CONNECTOR_NAME = "com.sun.jdi.SharedMemoryAttach";
97   @NonNls private static final String SOCKET_LISTENING_CONNECTOR_NAME = "com.sun.jdi.SocketListen";
98   @NonNls private static final String SHMEM_LISTENING_CONNECTOR_NAME = "com.sun.jdi.SharedMemoryListen";
99
100   private final Project myProject;
101   private final RequestManagerImpl myRequestManager;
102
103   private volatile VirtualMachineProxyImpl myVirtualMachineProxy = null;
104   protected EventDispatcher<DebugProcessListener> myDebugProcessDispatcher = EventDispatcher.create(DebugProcessListener.class);
105   protected EventDispatcher<EvaluationListener> myEvaluationDispatcher = EventDispatcher.create(EvaluationListener.class);
106
107   private final List<ProcessListener> myProcessListeners = ContainerUtil.createLockFreeCopyOnWriteList();
108
109   protected static final int STATE_INITIAL   = 0;
110   protected static final int STATE_ATTACHED  = 1;
111   protected static final int STATE_DETACHING = 2;
112   protected static final int STATE_DETACHED  = 3;
113   protected final AtomicInteger myState = new AtomicInteger(STATE_INITIAL);
114
115   private ExecutionResult myExecutionResult;
116   private RemoteConnection myConnection;
117   private JavaDebugProcess myXDebugProcess;
118
119   private ConnectionServiceWrapper myConnectionService;
120   private Map<String, Connector.Argument> myArguments;
121
122   private final List<NodeRenderer> myRenderers = new ArrayList<NodeRenderer>();
123
124   // we use null key here
125   private final Map<Type, NodeRenderer> myNodeRenderersMap = new HashMap<Type, NodeRenderer>();
126
127   private final NodeRendererSettingsListener mySettingsListener = new NodeRendererSettingsListener() {
128     @Override
129     public void renderersChanged() {
130       myNodeRenderersMap.clear();
131       myRenderers.clear();
132       loadRenderers();
133     }
134   };
135
136   private final SuspendManagerImpl mySuspendManager = new SuspendManagerImpl(this);
137   protected CompoundPositionManager myPositionManager = null;
138   private volatile DebuggerManagerThreadImpl myDebuggerManagerThread;
139   private static final int LOCAL_START_TIMEOUT = 30000;
140
141   private final Semaphore myWaitFor = new Semaphore();
142   private boolean myIsFailed = false;
143   protected DebuggerSession mySession;
144   @Nullable protected MethodReturnValueWatcher myReturnValueWatcher;
145   private final Disposable myDisposable = Disposer.newDisposable();
146   private final Alarm myStatusUpdateAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD, myDisposable);
147
148   protected DebugProcessImpl(Project project) {
149     myProject = project;
150     myRequestManager = new RequestManagerImpl(this);
151     NodeRendererSettings.getInstance().addListener(mySettingsListener);
152     loadRenderers();
153   }
154
155   private void loadRenderers() {
156     getManagerThread().invoke(new DebuggerCommandImpl() {
157       @Override
158       protected void action() throws Exception {
159         try {
160           final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
161           for (final NodeRenderer renderer : rendererSettings.getAllRenderers()) {
162             if (renderer.isEnabled()) {
163               myRenderers.add(renderer);
164             }
165           }
166         }
167         finally {
168           DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
169             @Override
170             public void run() {
171               final DebuggerSession session = mySession;
172               if (session != null && session.isAttached()) {
173                 session.refresh(true);
174                 DebuggerAction.refreshViews(mySession.getXDebugSession());
175               }
176             }
177           });
178         }
179       }
180     });
181   }
182
183   @Nullable
184   public Pair<Method, Value> getLastExecutedMethod() {
185     final MethodReturnValueWatcher watcher = myReturnValueWatcher;
186     if (watcher == null) {
187       return null;
188     }
189     final Method method = watcher.getLastExecutedMethod();
190     if (method == null) {
191       return null;
192     }
193     return Pair.create(method, watcher.getLastMethodReturnValue());
194   }
195
196   public void setWatchMethodReturnValuesEnabled(boolean enabled) {
197     final MethodReturnValueWatcher watcher = myReturnValueWatcher;
198     if (watcher != null) {
199       watcher.setFeatureEnabled(enabled);
200     }
201   }
202
203   public boolean isWatchMethodReturnValuesEnabled() {
204     final MethodReturnValueWatcher watcher = myReturnValueWatcher;
205     return watcher != null && watcher.isFeatureEnabled();
206   }
207
208   public boolean canGetMethodReturnValue() {
209     return myReturnValueWatcher != null;
210   }
211
212   public NodeRenderer getAutoRenderer(ValueDescriptor descriptor) {
213     DebuggerManagerThreadImpl.assertIsManagerThread();
214     final Value value = descriptor.getValue();
215     Type type = value != null ? value.type() : null;
216
217     // in case evaluation is not possible, force default renderer
218     if (!DebuggerManagerEx.getInstanceEx(getProject()).getContext().isEvaluationPossible()) {
219       return getDefaultRenderer(type);
220     }
221
222     NodeRenderer renderer = myNodeRenderersMap.get(type);
223     if(renderer == null) {
224       for (final NodeRenderer nodeRenderer : myRenderers) {
225         if (nodeRenderer.isApplicable(type)) {
226           renderer = nodeRenderer;
227           break;
228         }
229       }
230       if (renderer == null) {
231         renderer = getDefaultRenderer(type);
232       }
233       myNodeRenderersMap.put(type, renderer);
234     }
235
236     return renderer;
237   }
238
239   public static NodeRenderer getDefaultRenderer(Value value) {
240     return getDefaultRenderer(value != null ? value.type() : null);
241   }
242
243   public static NodeRenderer getDefaultRenderer(Type type) {
244     final NodeRendererSettings settings = NodeRendererSettings.getInstance();
245
246     final PrimitiveRenderer primitiveRenderer = settings.getPrimitiveRenderer();
247     if(primitiveRenderer.isApplicable(type)) {
248       return primitiveRenderer;
249     }
250
251     final ArrayRenderer arrayRenderer = settings.getArrayRenderer();
252     if(arrayRenderer.isApplicable(type)) {
253       return arrayRenderer;
254     }
255
256     final ClassRenderer classRenderer = settings.getClassRenderer();
257     LOG.assertTrue(classRenderer.isApplicable(type), type.name());
258     return classRenderer;
259   }
260
261
262   @SuppressWarnings({"HardCodedStringLiteral"})
263   protected void commitVM(VirtualMachine vm) {
264     if (!isInInitialState()) {
265       LOG.error("State is invalid " + myState.get());
266     }
267     DebuggerManagerThreadImpl.assertIsManagerThread();
268     myPositionManager = createPositionManager();
269     if (LOG.isDebugEnabled()) {
270       LOG.debug("*******************VM attached******************");
271     }
272     checkVirtualMachineVersion(vm);
273
274     myVirtualMachineProxy = new VirtualMachineProxyImpl(this, vm);
275
276     String trace = System.getProperty("idea.debugger.trace");
277     if (trace != null) {
278       int mask = 0;
279       StringTokenizer tokenizer = new StringTokenizer(trace);
280       while (tokenizer.hasMoreTokens()) {
281         String token = tokenizer.nextToken();
282         if ("SENDS".compareToIgnoreCase(token) == 0) {
283           mask |= VirtualMachine.TRACE_SENDS;
284         }
285         else if ("RAW_SENDS".compareToIgnoreCase(token) == 0) {
286           mask |= 0x01000000;
287         }
288         else if ("RECEIVES".compareToIgnoreCase(token) == 0) {
289           mask |= VirtualMachine.TRACE_RECEIVES;
290         }
291         else if ("RAW_RECEIVES".compareToIgnoreCase(token) == 0) {
292           mask |= 0x02000000;
293         }
294         else if ("EVENTS".compareToIgnoreCase(token) == 0) {
295           mask |= VirtualMachine.TRACE_EVENTS;
296         }
297         else if ("REFTYPES".compareToIgnoreCase(token) == 0) {
298           mask |= VirtualMachine.TRACE_REFTYPES;
299         }
300         else if ("OBJREFS".compareToIgnoreCase(token) == 0) {
301           mask |= VirtualMachine.TRACE_OBJREFS;
302         }
303         else if ("ALL".compareToIgnoreCase(token) == 0) {
304           mask |= VirtualMachine.TRACE_ALL;
305         }
306       }
307
308       vm.setDebugTraceMode(mask);
309     }
310   }
311
312   private void stopConnecting() {
313     DebuggerManagerThreadImpl.assertIsManagerThread();
314
315     Map<String, Connector.Argument> arguments = myArguments;
316     try {
317       if (arguments == null) {
318         return;
319       }
320       if(myConnection.isServerMode()) {
321         ListeningConnector connector = (ListeningConnector)findConnector(SOCKET_LISTENING_CONNECTOR_NAME);
322         if (connector == null) {
323           LOG.error("Cannot find connector: " + SOCKET_LISTENING_CONNECTOR_NAME);
324         }
325         else {
326           connector.stopListening(arguments);
327         }
328       }
329       else {
330         if(myConnectionService != null) {
331           myConnectionService.close();
332         }
333       }
334     }
335     catch (IOException e) {
336       if (LOG.isDebugEnabled()) {
337         LOG.debug(e);
338       }
339     }
340     catch (IllegalConnectorArgumentsException e) {
341       if (LOG.isDebugEnabled()) {
342         LOG.debug(e);
343       }
344     }
345     catch (ExecutionException e) {
346       LOG.error(e);
347     }
348     finally {
349       closeProcess(true);
350     }
351   }
352
353   protected CompoundPositionManager createPositionManager() {
354     return new CompoundPositionManager(new PositionManagerImpl(this));
355   }
356
357   @Override
358   public void printToConsole(final String text) {
359     myExecutionResult.getProcessHandler().notifyTextAvailable(text, ProcessOutputTypes.SYSTEM);
360   }
361
362   @Override
363   public ProcessHandler getProcessHandler() {
364     return myExecutionResult.getProcessHandler();
365   }
366
367   /**
368    *
369    * @param suspendContext
370    * @param stepThread
371    * @param size the step size. One of {@link StepRequest#STEP_LINE} or {@link StepRequest#STEP_MIN}
372    * @param depth
373    * @param hint may be null
374    */
375   protected void doStep(final SuspendContextImpl suspendContext, final ThreadReferenceProxyImpl stepThread, int size, int depth,
376                         RequestHint hint) {
377     if (stepThread == null) {
378       return;
379     }
380     try {
381       final ThreadReference stepThreadReference = stepThread.getThreadReference();
382       if (LOG.isDebugEnabled()) {
383         LOG.debug("DO_STEP: creating step request for " + stepThreadReference);
384       }
385       deleteStepRequests(stepThreadReference);
386       EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager();
387       StepRequest stepRequest = requestManager.createStepRequest(stepThreadReference, size, depth);
388       if (!(hint != null && hint.isIgnoreFilters()) /*&& depth == StepRequest.STEP_INTO*/) {
389         final List<ClassFilter> activeFilters = new ArrayList<ClassFilter>();
390         DebuggerSettings settings = DebuggerSettings.getInstance();
391         if (settings.TRACING_FILTERS_ENABLED) {
392           for (ClassFilter filter : settings.getSteppingFilters()) {
393             if (filter.isEnabled()) {
394               activeFilters.add(filter);
395             }
396           }
397         }
398         for (DebuggerClassFilterProvider provider : Extensions.getExtensions(DebuggerClassFilterProvider.EP_NAME)) {
399           for (ClassFilter filter : provider.getFilters()) {
400             if (filter.isEnabled()) {
401               activeFilters.add(filter);
402             }
403           }
404         }
405
406         if (!activeFilters.isEmpty()) {
407           final String currentClassName = getCurrentClassName(stepThread);
408           if (currentClassName == null || !DebuggerUtilsEx.isFiltered(currentClassName, activeFilters)) {
409             // add class filters
410             for (ClassFilter filter : activeFilters) {
411               stepRequest.addClassExclusionFilter(filter.getPattern());
412             }
413           }
414         }
415       }
416
417       // suspend policy to match the suspend policy of the context:
418       // if all threads were suspended, then during stepping all the threads must be suspended
419       // if only event thread were suspended, then only this particular thread must be suspended during stepping
420       stepRequest.setSuspendPolicy(suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? EventRequest.SUSPEND_EVENT_THREAD : EventRequest.SUSPEND_ALL);
421
422       if (hint != null) {
423         //noinspection HardCodedStringLiteral
424         stepRequest.putProperty("hint", hint);
425       }
426       stepRequest.enable();
427     }
428     catch (ObjectCollectedException ignored) {
429
430     }
431   }
432
433   void deleteStepRequests(@Nullable final ThreadReference stepThread) {
434     EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager();
435     List<StepRequest> stepRequests = requestManager.stepRequests();
436     if (!stepRequests.isEmpty()) {
437       final List<StepRequest> toDelete = new ArrayList<StepRequest>(stepRequests.size());
438       for (final StepRequest request : stepRequests) {
439         ThreadReference threadReference = request.thread();
440         // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occurs
441         try {
442           if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN && (stepThread == null || stepThread.equals(threadReference))) {
443             toDelete.add(request);
444           }
445         }
446         catch (IllegalThreadStateException e) {
447           LOG.info(e); // undocumented by JDI: may be thrown when querying thread status
448         }
449       }
450       requestManager.deleteEventRequests(toDelete);
451     }
452   }
453
454   @Nullable
455   private static String getCurrentClassName(ThreadReferenceProxyImpl thread) {
456     try {
457       if (thread != null && thread.frameCount() > 0) {
458         StackFrameProxyImpl stackFrame = thread.frame(0);
459         if (stackFrame != null) {
460           Location location = stackFrame.location();
461           ReferenceType referenceType = location == null ? null : location.declaringType();
462           if (referenceType != null) {
463             return referenceType.name();
464           }
465         }
466       }
467     }
468     catch (EvaluateException ignored) {
469     }
470     return null;
471   }
472
473   private VirtualMachine createVirtualMachineInt() throws ExecutionException {
474     try {
475       if (myArguments != null) {
476         throw new IOException(DebuggerBundle.message("error.debugger.already.listening"));
477       }
478
479       final String address = myConnection.getAddress();
480       if (myConnection.isServerMode()) {
481         ListeningConnector connector = (ListeningConnector)findConnector(
482           myConnection.isUseSockets() ? SOCKET_LISTENING_CONNECTOR_NAME : SHMEM_LISTENING_CONNECTOR_NAME);
483         if (connector == null) {
484           throw new CantRunException(DebuggerBundle.message("error.debug.connector.not.found", DebuggerBundle.getTransportName(myConnection)));
485         }
486         myArguments = connector.defaultArguments();
487         if (myArguments == null) {
488           throw new CantRunException(DebuggerBundle.message("error.no.debug.listen.port"));
489         }
490
491         if (address == null) {
492           throw new CantRunException(DebuggerBundle.message("error.no.debug.listen.port"));
493         }
494         // negative port number means the caller leaves to debugger to decide at which port to listen
495         //noinspection HardCodedStringLiteral
496         final Connector.Argument portArg = myConnection.isUseSockets() ? myArguments.get("port") : myArguments.get("name");
497         if (portArg != null) {
498           portArg.setValue(address);
499         }
500         //noinspection HardCodedStringLiteral
501         final Connector.Argument timeoutArg = myArguments.get("timeout");
502         if (timeoutArg != null) {
503           timeoutArg.setValue("0"); // wait forever
504         }
505         connector.startListening(myArguments);
506         myDebugProcessDispatcher.getMulticaster().connectorIsReady();
507         try {
508           return connector.accept(myArguments);
509         }
510         finally {
511           if(myArguments != null) {
512             try {
513               connector.stopListening(myArguments);
514             }
515             catch (IllegalArgumentException ignored) {
516               // ignored
517             }
518             catch (IllegalConnectorArgumentsException ignored) {
519               // ignored
520             }
521           }
522         }
523       }
524       else { // is client mode, should attach to already running process
525         AttachingConnector connector = (AttachingConnector)findConnector(
526           myConnection.isUseSockets() ? SOCKET_ATTACHING_CONNECTOR_NAME : SHMEM_ATTACHING_CONNECTOR_NAME
527         );
528
529         if (connector == null) {
530           throw new CantRunException( DebuggerBundle.message("error.debug.connector.not.found", DebuggerBundle.getTransportName(myConnection)));
531         }
532         myArguments = connector.defaultArguments();
533         if (myConnection.isUseSockets()) {
534           //noinspection HardCodedStringLiteral
535           final Connector.Argument hostnameArg = myArguments.get("hostname");
536           if (hostnameArg != null && myConnection.getHostName() != null) {
537             hostnameArg.setValue(myConnection.getHostName());
538           }
539           if (address == null) {
540             throw new CantRunException(DebuggerBundle.message("error.no.debug.attach.port"));
541           }
542           //noinspection HardCodedStringLiteral
543           final Connector.Argument portArg = myArguments.get("port");
544           if (portArg != null) {
545             portArg.setValue(address);
546           }
547         }
548         else {
549           if (address == null) {
550             throw new CantRunException(DebuggerBundle.message("error.no.shmem.address"));
551           }
552           //noinspection HardCodedStringLiteral
553           final Connector.Argument nameArg = myArguments.get("name");
554           if (nameArg != null) {
555             nameArg.setValue(address);
556           }
557         }
558         //noinspection HardCodedStringLiteral
559         final Connector.Argument timeoutArg = myArguments.get("timeout");
560         if (timeoutArg != null) {
561           timeoutArg.setValue("0"); // wait forever
562         }
563
564         myDebugProcessDispatcher.getMulticaster().connectorIsReady();
565         try {
566           return connector.attach(myArguments);
567         }
568         catch (IllegalArgumentException e) {
569           throw new CantRunException(e.getLocalizedMessage());
570         }
571       }
572     }
573     catch (IOException e) {
574       throw new ExecutionException(processError(e), e);
575     }
576     catch (IllegalConnectorArgumentsException e) {
577       throw new ExecutionException(processError(e), e);
578     }
579     finally {
580       myArguments = null;
581       myConnectionService = null;
582     }
583   }
584
585   public void showStatusText(final String text) {
586     if (!myStatusUpdateAlarm.isDisposed()) {
587       myStatusUpdateAlarm.cancelAllRequests();
588       myStatusUpdateAlarm.addRequest(new Runnable() {
589         @Override
590         public void run() {
591           StatusBarUtil.setStatusBarInfo(myProject, text);
592         }
593       }, 50);
594     }
595   }
596
597   static Connector findConnector(String connectorName) throws ExecutionException {
598     VirtualMachineManager virtualMachineManager;
599     try {
600       virtualMachineManager = Bootstrap.virtualMachineManager();
601     }
602     catch (Error e) {
603       final String error = e.getClass().getName() + " : " + e.getLocalizedMessage();
604       throw new ExecutionException(DebuggerBundle.message("debugger.jdi.bootstrap.error", error));
605     }
606     List connectors;
607     if (SOCKET_ATTACHING_CONNECTOR_NAME.equals(connectorName) || SHMEM_ATTACHING_CONNECTOR_NAME.equals(connectorName)) {
608       connectors = virtualMachineManager.attachingConnectors();
609     }
610     else if (SOCKET_LISTENING_CONNECTOR_NAME.equals(connectorName) || SHMEM_LISTENING_CONNECTOR_NAME.equals(connectorName)) {
611       connectors = virtualMachineManager.listeningConnectors();
612     }
613     else {
614       return null;
615     }
616     for (Object connector1 : connectors) {
617       Connector connector = (Connector)connector1;
618       if (connectorName.equals(connector.name())) {
619         return connector;
620       }
621     }
622     return null;
623   }
624
625   private void checkVirtualMachineVersion(VirtualMachine vm) {
626     final String version = vm.version();
627     if ("1.4.0".equals(version)) {
628       SwingUtilities.invokeLater(new Runnable() {
629         @Override
630         public void run() {
631           Messages.showMessageDialog(
632             getProject(),
633             DebuggerBundle.message("warning.jdk140.unstable"), DebuggerBundle.message("title.jdk140.unstable"), Messages.getWarningIcon()
634           );
635         }
636       });
637     }
638   }
639
640   /*Event dispatching*/
641   public void addEvaluationListener(EvaluationListener evaluationListener) {
642     myEvaluationDispatcher.addListener(evaluationListener);
643   }
644
645   public void removeEvaluationListener(EvaluationListener evaluationListener) {
646     myEvaluationDispatcher.removeListener(evaluationListener);
647   }
648
649   @Override
650   public void addDebugProcessListener(DebugProcessListener listener) {
651     myDebugProcessDispatcher.addListener(listener);
652   }
653
654   @Override
655   public void removeDebugProcessListener(DebugProcessListener listener) {
656     myDebugProcessDispatcher.removeListener(listener);
657   }
658
659   public void addProcessListener(ProcessListener processListener) {
660     synchronized(myProcessListeners) {
661       if(getProcessHandler() != null) {
662         getProcessHandler().addProcessListener(processListener);
663       }
664       else {
665         myProcessListeners.add(processListener);
666       }
667     }
668   }
669
670   public void removeProcessListener(ProcessListener processListener) {
671     synchronized (myProcessListeners) {
672       if(getProcessHandler() != null) {
673         getProcessHandler().removeProcessListener(processListener);
674       }
675       else {
676         myProcessListeners.remove(processListener);
677       }
678     }
679   }
680
681   /* getters */
682   public RemoteConnection getConnection() {
683     return myConnection;
684   }
685
686   @Override
687   public ExecutionResult getExecutionResult() {
688     return myExecutionResult;
689   }
690
691   @Override
692   public Project getProject() {
693     return myProject;
694   }
695
696   public boolean canRedefineClasses() {
697     final VirtualMachineProxyImpl vm = myVirtualMachineProxy;
698     return vm != null && vm.canRedefineClasses();
699   }
700
701   public boolean canWatchFieldModification() {
702     final VirtualMachineProxyImpl vm = myVirtualMachineProxy;
703     return vm != null && vm.canWatchFieldModification();
704   }
705
706   public boolean isInInitialState() {
707     return myState.get() == STATE_INITIAL;
708   }
709
710   @Override
711   public boolean isAttached() {
712     return myState.get() == STATE_ATTACHED;
713   }
714
715   @Override
716   public boolean isDetached() {
717     return myState.get() == STATE_DETACHED;
718   }
719
720   @Override
721   public boolean isDetaching() {
722     return myState.get() == STATE_DETACHING;
723   }
724
725   @Override
726   public RequestManagerImpl getRequestsManager() {
727     return myRequestManager;
728   }
729
730   @Override
731   public VirtualMachineProxyImpl getVirtualMachineProxy() {
732     DebuggerManagerThreadImpl.assertIsManagerThread();
733     final VirtualMachineProxyImpl vm = myVirtualMachineProxy;
734     if (vm == null) {
735       throw new VMDisconnectedException();
736     }
737     return vm;
738   }
739
740   @Override
741   public void appendPositionManager(final PositionManager positionManager) {
742     DebuggerManagerThreadImpl.assertIsManagerThread();
743     myPositionManager.appendPositionManager(positionManager);
744   }
745
746   private volatile RunToCursorBreakpoint myRunToCursorBreakpoint;
747
748   public void cancelRunToCursorBreakpoint() {
749     DebuggerManagerThreadImpl.assertIsManagerThread();
750     final RunToCursorBreakpoint runToCursorBreakpoint = myRunToCursorBreakpoint;
751     if (runToCursorBreakpoint != null) {
752       myRunToCursorBreakpoint = null;
753       getRequestsManager().deleteRequest(runToCursorBreakpoint);
754       if (runToCursorBreakpoint.isRestoreBreakpoints()) {
755         final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
756         breakpointManager.enableBreakpoints(this);
757       }
758     }
759   }
760
761   protected void closeProcess(boolean closedByUser) {
762     DebuggerManagerThreadImpl.assertIsManagerThread();
763
764     if (myState.compareAndSet(STATE_INITIAL, STATE_DETACHING) || myState.compareAndSet(STATE_ATTACHED, STATE_DETACHING)) {
765       try {
766         getManagerThread().close();
767       }
768       finally {
769         final VirtualMachineProxyImpl vm = myVirtualMachineProxy;
770         myVirtualMachineProxy = null;
771         myPositionManager = null;
772         myReturnValueWatcher = null;
773         myNodeRenderersMap.clear();
774         myRenderers.clear();
775         DebuggerUtils.cleanupAfterProcessFinish(this);
776         myState.set(STATE_DETACHED);
777         try {
778           myDebugProcessDispatcher.getMulticaster().processDetached(this, closedByUser);
779         }
780         finally {
781           //if (DebuggerSettings.getInstance().UNMUTE_ON_STOP) {
782           //  XDebugSession session = mySession.getXDebugSession();
783           //  if (session != null) {
784           //    session.setBreakpointMuted(false);
785           //  }
786           //}
787           if (vm != null) {
788             try {
789               vm.dispose(); // to be on the safe side ensure that VM mirror, if present, is disposed and invalidated
790             }
791             catch (Throwable ignored) {
792             }
793           }
794           myWaitFor.up();
795         }
796       }
797
798     }
799   }
800
801   private static String formatMessage(String message) {
802     final int lineLength = 90;
803     StringBuilder buf = new StringBuilder(message.length());
804     int index = 0;
805     while (index < message.length()) {
806       buf.append(message.substring(index, Math.min(index + lineLength, message.length()))).append('\n');
807       index += lineLength;
808     }
809     return buf.toString();
810   }
811
812   public static String processError(Exception e) {
813     String message;
814
815     if (e instanceof VMStartException) {
816       VMStartException e1 = (VMStartException)e;
817       message = e1.getLocalizedMessage();
818     }
819     else if (e instanceof IllegalConnectorArgumentsException) {
820       IllegalConnectorArgumentsException e1 = (IllegalConnectorArgumentsException)e;
821       final List<String> invalidArgumentNames = e1.argumentNames();
822       message = formatMessage(DebuggerBundle.message("error.invalid.argument", invalidArgumentNames.size()) + ": "+ e1.getLocalizedMessage()) + invalidArgumentNames;
823       if (LOG.isDebugEnabled()) {
824         LOG.debug(e1);
825       }
826     }
827     else if (e instanceof CantRunException) {
828       message = e.getLocalizedMessage();
829     }
830     else if (e instanceof VMDisconnectedException) {
831       message = DebuggerBundle.message("error.vm.disconnected");
832     }
833     else if (e instanceof UnknownHostException) {
834       message = DebuggerBundle.message("error.unknown.host") + ":\n" + e.getLocalizedMessage();
835     }
836     else if (e instanceof IOException) {
837       IOException e1 = (IOException)e;
838       final StringBuilder buf = StringBuilderSpinAllocator.alloc();
839       try {
840         buf.append(DebuggerBundle.message("error.cannot.open.debugger.port")).append(" : ");
841         buf.append(e1.getClass().getName()).append(" ");
842         final String localizedMessage = e1.getLocalizedMessage();
843         if (localizedMessage != null && !localizedMessage.isEmpty()) {
844           buf.append('"');
845           buf.append(localizedMessage);
846           buf.append('"');
847         }
848         if (LOG.isDebugEnabled()) {
849           LOG.debug(e1);
850         }
851         message = buf.toString();
852       }
853       finally {
854         StringBuilderSpinAllocator.dispose(buf);
855       }
856     }
857     else if (e instanceof ExecutionException) {
858       message = e.getLocalizedMessage();
859     }
860     else  {
861       message = DebuggerBundle.message("error.exception.while.connecting", e.getClass().getName(), e.getLocalizedMessage());
862       if (LOG.isDebugEnabled()) {
863         LOG.debug(e);
864       }
865     }
866     return message;
867   }
868
869   public void dispose() {
870     NodeRendererSettings.getInstance().removeListener(mySettingsListener);
871     Disposer.dispose(myDisposable);
872     myRequestManager.setFilterThread(null);
873   }
874
875   @Override
876   public DebuggerManagerThreadImpl getManagerThread() {
877     if (myDebuggerManagerThread == null) {
878       synchronized (this) {
879         if (myDebuggerManagerThread == null) {
880           myDebuggerManagerThread = new DebuggerManagerThreadImpl(myDisposable, getProject());
881         }
882       }
883     }
884     return myDebuggerManagerThread;
885   }
886
887   private static int getInvokePolicy(SuspendContext suspendContext) {
888     //return ThreadReference.INVOKE_SINGLE_THREADED;
889     return suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD ? ObjectReference.INVOKE_SINGLE_THREADED : 0;
890   }
891
892   @Override
893   public void waitFor() {
894     LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread());
895     myWaitFor.waitFor();
896   }
897
898   @Override
899   public void waitFor(long timeout) {
900     LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread());
901     myWaitFor.waitFor(timeout);
902   }
903
904   private abstract class InvokeCommand <E extends Value> {
905     private final List myArgs;
906
907     protected InvokeCommand(List args) {
908       if (!args.isEmpty()) {
909         myArgs = new ArrayList(args);
910       }
911       else {
912         myArgs = args;
913       }
914     }
915
916     public String toString() {
917       return "INVOKE: " + super.toString();
918     }
919
920     protected abstract E invokeMethod(int invokePolicy, final List args) throws InvocationException,
921                                                                                 ClassNotLoadedException,
922                                                                                 IncompatibleThreadStateException,
923                                                                                 InvalidTypeException;
924
925
926     E start(EvaluationContextImpl evaluationContext, Method method, boolean internalEvaluate) throws EvaluateException {
927       while (true) {
928         try {
929           return startInternal(evaluationContext, method, internalEvaluate);
930         }
931         catch (ClassNotLoadedException e) {
932           ReferenceType loadedClass = null;
933           try {
934             if (evaluationContext.isAutoLoadClasses()) {
935               loadedClass = loadClass(evaluationContext, e.className(), evaluationContext.getClassLoader());
936             }
937           }
938           catch (Exception ignored) {
939             loadedClass = null;
940           }
941           if (loadedClass == null) {
942             throw EvaluateExceptionUtil.createEvaluateException(e);
943           }
944         }
945       }
946     }
947
948     E startInternal(EvaluationContextImpl evaluationContext, Method method, boolean internalEvaluate)
949       throws EvaluateException, ClassNotLoadedException {
950       DebuggerManagerThreadImpl.assertIsManagerThread();
951       SuspendContextImpl suspendContext = evaluationContext.getSuspendContext();
952       SuspendManagerUtil.assertSuspendContext(suspendContext);
953
954       ThreadReferenceProxyImpl invokeThread = suspendContext.getThread();
955
956       if (SuspendManagerUtil.isEvaluating(getSuspendManager(), invokeThread)) {
957         throw EvaluateExceptionUtil.NESTED_EVALUATION_ERROR;
958       }
959
960       Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), invokeThread);
961       final ThreadReference invokeThreadRef = invokeThread.getThreadReference();
962
963       myEvaluationDispatcher.getMulticaster().evaluationStarted(suspendContext);
964       beforeMethodInvocation(suspendContext, method, internalEvaluate);
965
966       Object resumeData = null;
967       try {
968         for (SuspendContextImpl suspendingContext : suspendingContexts) {
969           final ThreadReferenceProxyImpl suspendContextThread = suspendingContext.getThread();
970           if (suspendContextThread != invokeThread) {
971             if (LOG.isDebugEnabled()) {
972               LOG.debug("Resuming " + invokeThread + " that is paused by " + suspendContextThread);
973             }
974             LOG.assertTrue(suspendContextThread == null || !invokeThreadRef.equals(suspendContextThread.getThreadReference()));
975             getSuspendManager().resumeThread(suspendingContext, invokeThread);
976           }
977         }
978
979         resumeData = SuspendManagerUtil.prepareForResume(suspendContext);
980         suspendContext.setIsEvaluating(evaluationContext);
981
982         getVirtualMachineProxy().clearCaches();
983
984         return invokeMethodAndFork(suspendContext);
985       }
986       catch (InvocationException e) {
987         throw EvaluateExceptionUtil.createEvaluateException(e);
988       }
989       catch (IncompatibleThreadStateException e) {
990         throw EvaluateExceptionUtil.createEvaluateException(e);
991       }
992       catch (InvalidTypeException e) {
993         throw EvaluateExceptionUtil.createEvaluateException(e);
994       }
995       catch (ObjectCollectedException e) {
996         throw EvaluateExceptionUtil.createEvaluateException(e);
997       }
998       catch (UnsupportedOperationException e) {
999         throw EvaluateExceptionUtil.createEvaluateException(e);
1000       }
1001       catch (InternalException e) {
1002         throw EvaluateExceptionUtil.createEvaluateException(e);
1003       }
1004       finally {
1005         suspendContext.setIsEvaluating(null);
1006         if (resumeData != null) {
1007           SuspendManagerUtil.restoreAfterResume(suspendContext, resumeData);
1008         }
1009         for (SuspendContextImpl suspendingContext : mySuspendManager.getEventContexts()) {
1010           if (suspendingContexts.contains(suspendingContext) && !suspendingContext.isEvaluating() && !suspendingContext.suspends(invokeThread)) {
1011             mySuspendManager.suspendThread(suspendingContext, invokeThread);
1012           }
1013         }
1014
1015         if (LOG.isDebugEnabled()) {
1016           LOG.debug("getVirtualMachine().clearCaches()");
1017         }
1018         getVirtualMachineProxy().clearCaches();
1019         afterMethodInvocation(suspendContext, internalEvaluate);
1020
1021         myEvaluationDispatcher.getMulticaster().evaluationFinished(suspendContext);
1022       }
1023     }
1024
1025     private E invokeMethodAndFork(final SuspendContextImpl context) throws InvocationException,
1026                                                                            ClassNotLoadedException,
1027                                                                            IncompatibleThreadStateException,
1028                                                                            InvalidTypeException {
1029       final int invokePolicy = getInvokePolicy(context);
1030       final Exception[] exception = new Exception[1];
1031       final Value[] result = new Value[1];
1032       getManagerThread().startLongProcessAndFork(new Runnable() {
1033         @Override
1034         public void run() {
1035           ThreadReferenceProxyImpl thread = context.getThread();
1036           try {
1037             try {
1038               if (LOG.isDebugEnabled()) {
1039                 final VirtualMachineProxyImpl virtualMachineProxy = getVirtualMachineProxy();
1040                 virtualMachineProxy.logThreads();
1041                 LOG.debug("Invoke in " + thread.name());
1042                 assertThreadSuspended(thread, context);
1043               }
1044               if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
1045                 // ensure args are not collected
1046                 for (Object arg : myArgs) {
1047                   if (arg instanceof ObjectReference) {
1048                     ((ObjectReference)arg).disableCollection();
1049                   }
1050                 }
1051               }
1052               result[0] = invokeMethod(invokePolicy, myArgs);
1053             }
1054             finally {
1055               //  assertThreadSuspended(thread, context);
1056               if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
1057                 // ensure args are not collected
1058                 for (Object arg : myArgs) {
1059                   if (arg instanceof ObjectReference) {
1060                     ((ObjectReference)arg).enableCollection();
1061                   }
1062                 }
1063               }
1064             }
1065           }
1066           catch (Exception e) {
1067             exception[0] = e;
1068           }
1069         }
1070       });
1071
1072       if (exception[0] != null) {
1073         if (exception[0] instanceof InvocationException) {
1074           throw (InvocationException)exception[0];
1075         }
1076         else if (exception[0] instanceof ClassNotLoadedException) {
1077           throw (ClassNotLoadedException)exception[0];
1078         }
1079         else if (exception[0] instanceof IncompatibleThreadStateException) {
1080           throw (IncompatibleThreadStateException)exception[0];
1081         }
1082         else if (exception[0] instanceof InvalidTypeException) {
1083           throw (InvalidTypeException)exception[0];
1084         }
1085         else if (exception[0] instanceof RuntimeException) {
1086           throw (RuntimeException)exception[0];
1087         }
1088         else {
1089           LOG.assertTrue(false);
1090         }
1091       }
1092
1093       return (E)result[0];
1094     }
1095
1096     private void assertThreadSuspended(final ThreadReferenceProxyImpl thread, final SuspendContextImpl context) {
1097       LOG.assertTrue(context.isEvaluating());
1098       try {
1099         final boolean isSuspended = thread.isSuspended();
1100         LOG.assertTrue(isSuspended, thread);
1101       }
1102       catch (ObjectCollectedException ignored) {
1103       }
1104     }
1105   }
1106
1107   @Override
1108   public Value invokeMethod(@NotNull EvaluationContext evaluationContext, @NotNull ObjectReference objRef, @NotNull Method method, final List args) throws EvaluateException {
1109     return invokeInstanceMethod(evaluationContext, objRef, method, args, 0);
1110   }
1111
1112   @Override
1113   public Value invokeInstanceMethod(@NotNull EvaluationContext evaluationContext, @NotNull final ObjectReference objRef, final Method method,
1114                                     final List args, final int invocationOptions) throws EvaluateException {
1115     final ThreadReference thread = getEvaluationThread(evaluationContext);
1116     return new InvokeCommand<Value>(args) {
1117       @Override
1118       protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException {
1119         if (LOG.isDebugEnabled()) {
1120           LOG.debug("Invoke " + method.name());
1121         }
1122         return objRef.invokeMethod(thread, method, args, invokePolicy | invocationOptions);
1123       }
1124     }.start((EvaluationContextImpl)evaluationContext, method, false);
1125   }
1126
1127   private static ThreadReference getEvaluationThread(final EvaluationContext evaluationContext) throws EvaluateException {
1128     ThreadReferenceProxy evaluationThread = evaluationContext.getSuspendContext().getThread();
1129     if(evaluationThread == null) {
1130       throw EvaluateExceptionUtil.NULL_STACK_FRAME;
1131     }
1132     return evaluationThread.getThreadReference();
1133   }
1134
1135   @Override
1136   public Value invokeMethod(final EvaluationContext evaluationContext, final ClassType classType,
1137                             final Method method,
1138                             final List args) throws EvaluateException {
1139     return invokeMethod(evaluationContext, classType, method, args, false);
1140   }
1141
1142   public Value invokeMethod(@NotNull EvaluationContext evaluationContext,
1143                             @NotNull final ClassType classType,
1144                             @NotNull final Method method,
1145                             final List args,
1146                             boolean internalEvaluate) throws EvaluateException {
1147     final ThreadReference thread = getEvaluationThread(evaluationContext);
1148     return new InvokeCommand<Value>(args) {
1149       @Override
1150       protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException,
1151                                                                              ClassNotLoadedException,
1152                                                                              IncompatibleThreadStateException,
1153                                                                              InvalidTypeException {
1154         if (LOG.isDebugEnabled()) {
1155           LOG.debug("Invoke " + method.name());
1156         }
1157         return classType.invokeMethod(thread, method, args, invokePolicy);
1158       }
1159     }.start((EvaluationContextImpl)evaluationContext, method, internalEvaluate);
1160   }
1161
1162   @Override
1163   public ArrayReference newInstance(final ArrayType arrayType,
1164                                     final int dimension)
1165     throws EvaluateException {
1166     try {
1167       return arrayType.newInstance(dimension);
1168     }
1169     catch (Exception e) {
1170       throw EvaluateExceptionUtil.createEvaluateException(e);
1171     }
1172   }
1173
1174   @Override
1175   public ObjectReference newInstance(final EvaluationContext evaluationContext, final ClassType classType,
1176                                      final Method method,
1177                                      final List args) throws EvaluateException {
1178     final ThreadReference thread = getEvaluationThread(evaluationContext);
1179     InvokeCommand<ObjectReference> invokeCommand = new InvokeCommand<ObjectReference>(args) {
1180       @Override
1181       protected ObjectReference invokeMethod(int invokePolicy, final List args) throws InvocationException,
1182                                                                                        ClassNotLoadedException,
1183                                                                                        IncompatibleThreadStateException,
1184                                                                                        InvalidTypeException {
1185         if (LOG.isDebugEnabled()) {
1186           LOG.debug("New instance " + method.name());
1187         }
1188         return classType.newInstance(thread, method, args, invokePolicy);
1189       }
1190     };
1191     return invokeCommand.start((EvaluationContextImpl)evaluationContext, method, false);
1192   }
1193
1194   public void clearCashes(int suspendPolicy) {
1195     if (!isAttached()) return;
1196     switch (suspendPolicy) {
1197       case EventRequest.SUSPEND_ALL:
1198         getVirtualMachineProxy().clearCaches();
1199         break;
1200       case EventRequest.SUSPEND_EVENT_THREAD:
1201         getVirtualMachineProxy().clearCaches();
1202         //suspendContext.getThread().clearAll();
1203         break;
1204     }
1205   }
1206
1207   protected void beforeSuspend(SuspendContextImpl suspendContext) {
1208     clearCashes(suspendContext.getSuspendPolicy());
1209   }
1210
1211   private void beforeMethodInvocation(SuspendContextImpl suspendContext, Method method, boolean internalEvaluate) {
1212     if (LOG.isDebugEnabled()) {
1213       LOG.debug(
1214         "before invocation in  thread " + suspendContext.getThread().name() + " method " + (method == null ? "null" : method.name()));
1215     }
1216
1217     if (!internalEvaluate) {
1218       if (method != null) {
1219         showStatusText(DebuggerBundle.message("progress.evaluating", DebuggerUtilsEx.methodName(method)));
1220       }
1221       else {
1222         showStatusText(DebuggerBundle.message("title.evaluating"));
1223       }
1224     }
1225   }
1226
1227   private void afterMethodInvocation(SuspendContextImpl suspendContext, boolean internalEvaluate) {
1228     if (LOG.isDebugEnabled()) {
1229       LOG.debug("after invocation in  thread " + suspendContext.getThread().name());
1230     }
1231     if (!internalEvaluate) {
1232       showStatusText("");
1233     }
1234   }
1235
1236   @Override
1237   public ReferenceType findClass(EvaluationContext evaluationContext, String className,
1238                                  ClassLoaderReference classLoader) throws EvaluateException {
1239     try {
1240       DebuggerManagerThreadImpl.assertIsManagerThread();
1241       final VirtualMachineProxyImpl vmProxy = getVirtualMachineProxy();
1242       if (vmProxy == null) {
1243         throw new VMDisconnectedException();
1244       }
1245       ReferenceType result = null;
1246       for (final ReferenceType refType : vmProxy.classesByName(className)) {
1247         if (refType.isPrepared() && isVisibleFromClassLoader(classLoader, refType)) {
1248           result = refType;
1249           break;
1250         }
1251       }
1252       final EvaluationContextImpl evalContext = (EvaluationContextImpl)evaluationContext;
1253       if (result == null && evalContext.isAutoLoadClasses()) {
1254         return loadClass(evalContext, className, classLoader);
1255       }
1256       return result;
1257     }
1258     catch (InvocationException e) {
1259       throw EvaluateExceptionUtil.createEvaluateException(e);
1260     }
1261     catch (ClassNotLoadedException e) {
1262       throw EvaluateExceptionUtil.createEvaluateException(e);
1263     }
1264     catch (IncompatibleThreadStateException e) {
1265       throw EvaluateExceptionUtil.createEvaluateException(e);
1266     }
1267     catch (InvalidTypeException e) {
1268       throw EvaluateExceptionUtil.createEvaluateException(e);
1269     }
1270   }
1271
1272   private static boolean isVisibleFromClassLoader(final ClassLoaderReference fromLoader, final ReferenceType refType) {
1273     // IMPORTANT! Even if the refType is already loaded by some parent or bootstrap loader, it may not be visible from the given loader.
1274     // For example because there were no accesses yet from this loader to this class. So the loader is not in the list of "initialing" loaders
1275     // for this refType and the refType is not visible to the loader.
1276     // Attempt to evaluate method with this refType will yield ClassNotLoadedException.
1277     // The only way to say for sure whether the class is _visible_ to the given loader, is to use the following API call
1278     return fromLoader == null || fromLoader.equals(refType.classLoader()) || fromLoader.visibleClasses().contains(refType);
1279   }
1280
1281   private static String reformatArrayName(String className) {
1282     if (className.indexOf('[') == -1) return className;
1283
1284     int dims = 0;
1285     while (className.endsWith("[]")) {
1286       className = className.substring(0, className.length() - 2);
1287       dims++;
1288     }
1289
1290     StringBuilder buffer = StringBuilderSpinAllocator.alloc();
1291     try {
1292       for (int i = 0; i < dims; i++) {
1293         buffer.append('[');
1294       }
1295       String primitiveSignature = JVMNameUtil.getPrimitiveSignature(className);
1296       if(primitiveSignature != null) {
1297         buffer.append(primitiveSignature);
1298       }
1299       else {
1300         buffer.append('L');
1301         buffer.append(className);
1302         buffer.append(';');
1303       }
1304       return buffer.toString();
1305     }
1306     finally {
1307       StringBuilderSpinAllocator.dispose(buffer);
1308     }
1309   }
1310
1311   @SuppressWarnings({"HardCodedStringLiteral", "SpellCheckingInspection"})
1312   public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String qName, ClassLoaderReference classLoader)
1313     throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException, EvaluateException {
1314
1315     DebuggerManagerThreadImpl.assertIsManagerThread();
1316     qName = reformatArrayName(qName);
1317     ReferenceType refType = null;
1318     VirtualMachineProxyImpl virtualMachine = getVirtualMachineProxy();
1319     final List classClasses = virtualMachine.classesByName("java.lang.Class");
1320     if (!classClasses.isEmpty()) {
1321       ClassType classClassType = (ClassType)classClasses.get(0);
1322       final Method forNameMethod;
1323       if (classLoader != null) {
1324         //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
1325         forNameMethod = DebuggerUtils.findMethod(classClassType, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
1326       }
1327       else {
1328         //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1329         forNameMethod = DebuggerUtils.findMethod(classClassType, "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1330       }
1331       final List<Mirror> args = new ArrayList<Mirror>(); // do not use unmodifiable lists because the list is modified by JPDA
1332       final StringReference qNameMirror = virtualMachine.mirrorOf(qName);
1333       args.add(qNameMirror);
1334       if (classLoader != null) {
1335         args.add(virtualMachine.mirrorOf(true));
1336         args.add(classLoader);
1337       }
1338       final Value value = invokeMethod(evaluationContext, classClassType, forNameMethod, args);
1339       if (value instanceof ClassObjectReference) {
1340         refType = ((ClassObjectReference)value).reflectedType();
1341       }
1342     }
1343     return refType;
1344   }
1345
1346   public void logThreads() {
1347     if (LOG.isDebugEnabled()) {
1348       try {
1349         Collection<ThreadReferenceProxyImpl> allThreads = getVirtualMachineProxy().allThreads();
1350         for (ThreadReferenceProxyImpl threadReferenceProxy : allThreads) {
1351           LOG.debug("Thread name=" + threadReferenceProxy.name() + " suspendCount()=" + threadReferenceProxy.getSuspendCount());
1352         }
1353       }
1354       catch (Exception e) {
1355         LOG.debug(e);
1356       }
1357     }
1358   }
1359
1360   public SuspendManager getSuspendManager() {
1361     return mySuspendManager;
1362   }
1363
1364   @Override
1365   public CompoundPositionManager getPositionManager() {
1366     return myPositionManager;
1367   }
1368   //ManagerCommands
1369
1370   @Override
1371   public void stop(boolean forceTerminate) {
1372     getManagerThread().terminateAndInvoke(createStopCommand(forceTerminate), DebuggerManagerThreadImpl.COMMAND_TIMEOUT);
1373   }
1374
1375   public StopCommand createStopCommand(boolean forceTerminate) {
1376     return new StopCommand(forceTerminate);
1377   }
1378
1379   protected class StopCommand extends DebuggerCommandImpl {
1380     private final boolean myIsTerminateTargetVM;
1381
1382     public StopCommand(boolean isTerminateTargetVM) {
1383       myIsTerminateTargetVM = isTerminateTargetVM;
1384     }
1385
1386     @Override
1387     public Priority getPriority() {
1388       return Priority.HIGH;
1389     }
1390
1391     @Override
1392     protected void action() throws Exception {
1393       if (isAttached()) {
1394         final VirtualMachineProxyImpl virtualMachineProxy = getVirtualMachineProxy();
1395         if (myIsTerminateTargetVM) {
1396           virtualMachineProxy.exit(-1);
1397         }
1398         else {
1399           // some VMs (like IBM VM 1.4.2 bundled with WebSphere) does not resume threads on dispose() like it should
1400           try {
1401             virtualMachineProxy.resume();
1402           }
1403           finally {
1404             virtualMachineProxy.dispose();
1405           }
1406         }
1407       }
1408       else {
1409         stopConnecting();
1410       }
1411     }
1412   }
1413
1414   private class StepOutCommand extends ResumeCommand {
1415     private final int myStepSize;
1416
1417     public StepOutCommand(SuspendContextImpl suspendContext, int stepSize) {
1418       super(suspendContext);
1419       myStepSize = stepSize;
1420     }
1421
1422     @Override
1423     public void contextAction() {
1424       showStatusText(DebuggerBundle.message("status.step.out"));
1425       final SuspendContextImpl suspendContext = getSuspendContext();
1426       final ThreadReferenceProxyImpl thread = getContextThread();
1427       RequestHint hint = new RequestHint(thread, suspendContext, StepRequest.STEP_OUT);
1428       hint.setIgnoreFilters(mySession.shouldIgnoreSteppingFilters());
1429       applyThreadFilter(thread);
1430       final MethodReturnValueWatcher rvWatcher = myReturnValueWatcher;
1431       if (rvWatcher != null) {
1432         rvWatcher.enable(thread.getThreadReference());
1433       }
1434       doStep(suspendContext, thread, myStepSize, StepRequest.STEP_OUT, hint);
1435       super.contextAction();
1436     }
1437   }
1438
1439   private class StepIntoCommand extends ResumeCommand {
1440     private final boolean myForcedIgnoreFilters;
1441     private final MethodFilter mySmartStepFilter;
1442     @Nullable
1443     private final StepIntoBreakpoint myBreakpoint;
1444     private final int myStepSize;
1445
1446     public StepIntoCommand(SuspendContextImpl suspendContext, boolean ignoreFilters, @Nullable final MethodFilter methodFilter,
1447                            int stepSize) {
1448       super(suspendContext);
1449       myForcedIgnoreFilters = ignoreFilters || methodFilter != null;
1450       mySmartStepFilter = methodFilter;
1451       myBreakpoint = methodFilter instanceof BreakpointStepMethodFilter ?
1452         DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().addStepIntoBreakpoint(((BreakpointStepMethodFilter)methodFilter)) :
1453         null;
1454       myStepSize = stepSize;
1455     }
1456
1457     @Override
1458     public void contextAction() {
1459       showStatusText(DebuggerBundle.message("status.step.into"));
1460       final SuspendContextImpl suspendContext = getSuspendContext();
1461       final ThreadReferenceProxyImpl stepThread = getContextThread();
1462       final RequestHint hint = mySmartStepFilter != null?
1463                                new RequestHint(stepThread, suspendContext, mySmartStepFilter) :
1464                                new RequestHint(stepThread, suspendContext, StepRequest.STEP_INTO);
1465       if (myForcedIgnoreFilters) {
1466         try {
1467           mySession.setIgnoreStepFiltersFlag(stepThread.frameCount());
1468         }
1469         catch (EvaluateException e) {
1470           LOG.info(e);
1471         }
1472       }
1473       hint.setIgnoreFilters(myForcedIgnoreFilters || mySession.shouldIgnoreSteppingFilters());
1474       applyThreadFilter(stepThread);
1475       if (myBreakpoint != null) {
1476         myBreakpoint.setSuspendPolicy(suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? DebuggerSettings.SUSPEND_THREAD : DebuggerSettings.SUSPEND_ALL);
1477         myBreakpoint.createRequest(suspendContext.getDebugProcess());
1478         myRunToCursorBreakpoint = myBreakpoint;
1479       }
1480       doStep(suspendContext, stepThread, myStepSize, StepRequest.STEP_INTO, hint);
1481       super.contextAction();
1482     }
1483   }
1484
1485   private class StepOverCommand extends ResumeCommand {
1486     private final boolean myIsIgnoreBreakpoints;
1487     private final int myStepSize;
1488
1489     public StepOverCommand(SuspendContextImpl suspendContext, boolean ignoreBreakpoints, int stepSize) {
1490       super(suspendContext);
1491       myIsIgnoreBreakpoints = ignoreBreakpoints;
1492       myStepSize = stepSize;
1493     }
1494
1495     @Override
1496     public void contextAction() {
1497       showStatusText(DebuggerBundle.message("status.step.over"));
1498       final SuspendContextImpl suspendContext = getSuspendContext();
1499       final ThreadReferenceProxyImpl stepThread = getContextThread();
1500       // need this hint while stepping over for JSR45 support:
1501       // several lines of generated java code may correspond to a single line in the source file,
1502       // from which the java code was generated
1503       RequestHint hint = new RequestHint(stepThread, suspendContext, StepRequest.STEP_OVER);
1504       hint.setRestoreBreakpoints(myIsIgnoreBreakpoints);
1505       hint.setIgnoreFilters(myIsIgnoreBreakpoints || mySession.shouldIgnoreSteppingFilters());
1506
1507       applyThreadFilter(stepThread);
1508
1509       final MethodReturnValueWatcher rvWatcher = myReturnValueWatcher;
1510       if (rvWatcher != null) {
1511         rvWatcher.enable(stepThread.getThreadReference());
1512       }
1513
1514       doStep(suspendContext, stepThread, myStepSize, StepRequest.STEP_OVER, hint);
1515
1516       if (myIsIgnoreBreakpoints) {
1517         DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().disableBreakpoints(DebugProcessImpl.this);
1518       }
1519       super.contextAction();
1520     }
1521   }
1522
1523   private class RunToCursorCommand extends ResumeCommand {
1524     private final RunToCursorBreakpoint myRunToCursorBreakpoint;
1525     private final boolean myIgnoreBreakpoints;
1526
1527     private RunToCursorCommand(SuspendContextImpl suspendContext, Document document, int lineIndex, final boolean ignoreBreakpoints) {
1528       super(suspendContext);
1529       myIgnoreBreakpoints = ignoreBreakpoints;
1530       final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
1531       myRunToCursorBreakpoint = breakpointManager.addRunToCursorBreakpoint(document, lineIndex, ignoreBreakpoints);
1532     }
1533
1534     @Override
1535     public void contextAction() {
1536       showStatusText(DebuggerBundle.message("status.run.to.cursor"));
1537       cancelRunToCursorBreakpoint();
1538       if (myRunToCursorBreakpoint == null) {
1539         return;
1540       }
1541       if (myIgnoreBreakpoints) {
1542         final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
1543         breakpointManager.disableBreakpoints(DebugProcessImpl.this);
1544       }
1545       applyThreadFilter(getContextThread());
1546       final SuspendContextImpl context = getSuspendContext();
1547       myRunToCursorBreakpoint.setSuspendPolicy(context.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? DebuggerSettings.SUSPEND_THREAD : DebuggerSettings.SUSPEND_ALL);
1548       DebugProcessImpl debugProcess = context.getDebugProcess();
1549       myRunToCursorBreakpoint.createRequest(debugProcess);
1550       DebugProcessImpl.this.myRunToCursorBreakpoint = myRunToCursorBreakpoint;
1551
1552       if (debugProcess.getRequestsManager().getWarning(myRunToCursorBreakpoint) == null) {
1553         super.contextAction();
1554       }
1555       else {
1556         myDebugProcessDispatcher.getMulticaster().resumed(getSuspendContext());
1557         DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
1558           @Override
1559           public void run() {
1560             SourcePosition position = myRunToCursorBreakpoint.getSourcePosition();
1561             String name = position != null ? position.getFile().getName() : "<No File>";
1562             Messages.showErrorDialog(
1563               DebuggerBundle.message("error.running.to.cursor.no.executable.code", name, myRunToCursorBreakpoint.getLineIndex()+1),
1564               UIUtil.removeMnemonic(ActionsBundle.actionText(XDebuggerActions.RUN_TO_CURSOR)));
1565           }
1566         });
1567       }
1568     }
1569   }
1570
1571   public abstract class ResumeCommand extends SuspendContextCommandImpl {
1572
1573     private final ThreadReferenceProxyImpl myContextThread;
1574
1575     public ResumeCommand(SuspendContextImpl suspendContext) {
1576       super(suspendContext);
1577       final ThreadReferenceProxyImpl contextThread = getDebuggerContext().getThreadProxy();
1578       myContextThread = contextThread != null ? contextThread : (suspendContext != null? suspendContext.getThread() : null);
1579     }
1580
1581     @Override
1582     public Priority getPriority() {
1583       return Priority.HIGH;
1584     }
1585
1586     @Override
1587     public void contextAction() {
1588       showStatusText(DebuggerBundle.message("status.process.resumed"));
1589       getSuspendManager().resume(getSuspendContext());
1590       myDebugProcessDispatcher.getMulticaster().resumed(getSuspendContext());
1591     }
1592
1593     public ThreadReferenceProxyImpl getContextThread() {
1594       return myContextThread;
1595     }
1596
1597     protected void applyThreadFilter(ThreadReferenceProxy thread) {
1598       if (getSuspendContext().getSuspendPolicy() == EventRequest.SUSPEND_ALL) {
1599         // there could be explicit resume as a result of call to voteSuspend()
1600         // e.g. when breakpoint was considered invalid, in that case the filter will be applied _after_
1601         // resuming and all breakpoints in other threads will be ignored.
1602         // As resume() implicitly cleares the filter, the filter must be always applied _before_ any resume() action happens
1603         final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
1604         breakpointManager.applyThreadFilter(DebugProcessImpl.this, thread.getThreadReference());
1605       }
1606     }
1607   }
1608
1609   private class PauseCommand extends DebuggerCommandImpl {
1610     public PauseCommand() {
1611     }
1612
1613     @Override
1614     public void action() {
1615       if (!isAttached() || getVirtualMachineProxy().isPausePressed()) {
1616         return;
1617       }
1618       logThreads();
1619       getVirtualMachineProxy().suspend();
1620       logThreads();
1621       SuspendContextImpl suspendContext = mySuspendManager.pushSuspendContext(EventRequest.SUSPEND_ALL, 0);
1622       myDebugProcessDispatcher.getMulticaster().paused(suspendContext);
1623     }
1624   }
1625
1626   private class ResumeThreadCommand extends SuspendContextCommandImpl {
1627     private final ThreadReferenceProxyImpl myThread;
1628
1629     public ResumeThreadCommand(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
1630       super(suspendContext);
1631       myThread = thread;
1632     }
1633
1634     @Override
1635     public void contextAction() {
1636       if (getSuspendManager().isFrozen(myThread)) {
1637         getSuspendManager().unfreezeThread(myThread);
1638         return;
1639       }
1640
1641       final Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), myThread);
1642       for (SuspendContextImpl suspendContext : suspendingContexts) {
1643         if (suspendContext.getThread() == myThread) {
1644           getManagerThread().invoke(createResumeCommand(suspendContext));
1645         }
1646         else {
1647           getSuspendManager().resumeThread(suspendContext, myThread);
1648         }
1649       }
1650     }
1651   }
1652
1653   private class FreezeThreadCommand extends DebuggerCommandImpl {
1654     private final ThreadReferenceProxyImpl myThread;
1655
1656     public FreezeThreadCommand(ThreadReferenceProxyImpl thread) {
1657       myThread = thread;
1658     }
1659
1660     @Override
1661     protected void action() throws Exception {
1662       SuspendManager suspendManager = getSuspendManager();
1663       if (!suspendManager.isFrozen(myThread)) {
1664         suspendManager.freezeThread(myThread);
1665       }
1666     }
1667   }
1668
1669   private class PopFrameCommand extends SuspendContextCommandImpl {
1670     private final StackFrameProxyImpl myStackFrame;
1671
1672     public PopFrameCommand(SuspendContextImpl context, StackFrameProxyImpl frameProxy) {
1673       super(context);
1674       myStackFrame = frameProxy;
1675     }
1676
1677     @Override
1678     public void contextAction() {
1679       final ThreadReferenceProxyImpl thread = myStackFrame.threadProxy();
1680       try {
1681         if (!getSuspendManager().isSuspended(thread)) {
1682           notifyCancelled();
1683           return;
1684         }
1685       }
1686       catch (ObjectCollectedException ignored) {
1687         notifyCancelled();
1688         return;
1689       }
1690
1691       final SuspendContextImpl suspendContext = getSuspendContext();
1692       if (!suspendContext.suspends(thread)) {
1693         suspendContext.postponeCommand(this);
1694         return;
1695       }
1696
1697       if (myStackFrame.isBottom()) {
1698         DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
1699           @Override
1700           public void run() {
1701             Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.bottom.stackframe"), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
1702           }
1703         });
1704         return;
1705       }
1706
1707       try {
1708         thread.popFrames(myStackFrame);
1709       }
1710       catch (final EvaluateException e) {
1711         DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
1712           @Override
1713           public void run() {
1714             Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.stackframe", e.getLocalizedMessage()), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
1715           }
1716         });
1717         LOG.info(e);
1718       }
1719       finally {
1720         getSuspendManager().popFrame(suspendContext);
1721       }
1722     }
1723   }
1724
1725   @Override
1726   @NotNull
1727   public GlobalSearchScope getSearchScope() {
1728     LOG.assertTrue(mySession != null, "Accessing debug session before its initialization");
1729     return mySession.getSearchScope();
1730   }
1731
1732   @Nullable
1733   public ExecutionResult attachVirtualMachine(final DebugEnvironment environment,
1734                                               final DebuggerSession session) throws ExecutionException {
1735     mySession = session;
1736     myWaitFor.down();
1737
1738     ApplicationManager.getApplication().assertIsDispatchThread();
1739     LOG.assertTrue(isInInitialState());
1740
1741     myConnection = environment.getRemoteConnection();
1742
1743     createVirtualMachine(environment.getSessionName(), environment.isPollConnection());
1744
1745     ExecutionResult executionResult;
1746     try {
1747       synchronized (myProcessListeners) {
1748         executionResult = environment.createExecutionResult();
1749         myExecutionResult = executionResult;
1750         if (executionResult == null) {
1751           fail();
1752           return null;
1753         }
1754         for (ProcessListener processListener : myProcessListeners) {
1755           executionResult.getProcessHandler().addProcessListener(processListener);
1756         }
1757         myProcessListeners.clear();
1758       }
1759     }
1760     catch (ExecutionException e) {
1761       fail();
1762       throw e;
1763     }
1764
1765     // writing to volatile field ensures the other threads will see the right values in non-volatile fields
1766
1767     if (ApplicationManager.getApplication().isUnitTestMode()) {
1768       return executionResult;
1769     }
1770
1771     /*
1772     final Alarm debugPortTimeout = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
1773
1774     myExecutionResult.getProcessHandler().addProcessListener(new ProcessAdapter() {
1775       public void processTerminated(ProcessEvent event) {
1776         debugPortTimeout.cancelAllRequests();
1777       }
1778
1779       public void startNotified(ProcessEvent event) {
1780         debugPortTimeout.addRequest(new Runnable() {
1781           public void run() {
1782             if(isInInitialState()) {
1783               ApplicationManager.getApplication().schedule(new Runnable() {
1784                 public void run() {
1785                   String message = DebuggerBundle.message("status.connect.failed", DebuggerBundle.getAddressDisplayName(remoteConnection), DebuggerBundle.getTransportName(remoteConnection));
1786                   Messages.showErrorDialog(myProject, message, DebuggerBundle.message("title.generic.debug.dialog"));
1787                 }
1788               });
1789             }
1790           }
1791         }, LOCAL_START_TIMEOUT);
1792       }
1793     });
1794     */
1795
1796     return executionResult;
1797   }
1798
1799   private void fail() {
1800     synchronized (this) {
1801       if (myIsFailed) {
1802         // need this in order to prevent calling stop() twice
1803         return;
1804       }
1805       myIsFailed = true;
1806     }
1807     stop(false);
1808   }
1809
1810   private void createVirtualMachine(final String sessionName, final boolean pollConnection) {
1811     final Semaphore semaphore = new Semaphore();
1812     semaphore.down();
1813
1814     final Ref<Boolean> connectorIsReady = Ref.create(false);
1815     myDebugProcessDispatcher.addListener(new DebugProcessAdapter() {
1816       @Override
1817       public void connectorIsReady() {
1818         connectorIsReady.set(true);
1819         semaphore.up();
1820         myDebugProcessDispatcher.removeListener(this);
1821       }
1822     });
1823
1824     // reload to make sure that source positions are initialized
1825     DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().reloadBreakpoints();
1826
1827     getManagerThread().schedule(new DebuggerCommandImpl() {
1828       @Override
1829       protected void action() {
1830         VirtualMachine vm = null;
1831
1832         try {
1833           final long time = System.currentTimeMillis();
1834           while (System.currentTimeMillis() - time < LOCAL_START_TIMEOUT) {
1835             try {
1836               vm = createVirtualMachineInt();
1837               break;
1838             }
1839             catch (final ExecutionException e) {
1840               if (pollConnection && !myConnection.isServerMode() && e.getCause() instanceof IOException) {
1841                 synchronized (this) {
1842                   try {
1843                     wait(500);
1844                   }
1845                   catch (InterruptedException ignored) {
1846                     break;
1847                   }
1848                 }
1849               }
1850               else {
1851                 fail();
1852                 if (myExecutionResult != null || !connectorIsReady.get()) {
1853                   // propagate exception only in case we succeeded to obtain execution result,
1854                   // otherwise if the error is induced by the fact that there is nothing to debug, and there is no need to show
1855                   // this problem to the user
1856                   SwingUtilities.invokeLater(new Runnable() {
1857                     @Override
1858                     public void run() {
1859                       ExecutionUtil.handleExecutionError(myProject, ToolWindowId.DEBUG, sessionName, e);
1860                     }
1861                   });
1862                 }
1863                 break;
1864               }
1865             }
1866           }
1867         }
1868         finally {
1869           semaphore.up();
1870         }
1871
1872         if (vm != null) {
1873           final VirtualMachine vm1 = vm;
1874           afterProcessStarted(new Runnable() {
1875             @Override
1876             public void run() {
1877               getManagerThread().schedule(new DebuggerCommandImpl() {
1878                 @Override
1879                 protected void action() throws Exception {
1880                   commitVM(vm1);
1881                 }
1882               });
1883             }
1884           });
1885         }
1886       }
1887
1888       @Override
1889       protected void commandCancelled() {
1890         try {
1891           super.commandCancelled();
1892         }
1893         finally {
1894           semaphore.up();
1895         }
1896       }
1897     });
1898
1899     semaphore.waitFor();
1900   }
1901
1902   private void afterProcessStarted(final Runnable run) {
1903     class MyProcessAdapter extends ProcessAdapter {
1904       private boolean alreadyRun = false;
1905
1906       public synchronized void run() {
1907         if(!alreadyRun) {
1908           alreadyRun = true;
1909           run.run();
1910         }
1911         removeProcessListener(this);
1912       }
1913
1914       @Override
1915       public void startNotified(ProcessEvent event) {
1916         run();
1917       }
1918     }
1919     MyProcessAdapter processListener = new MyProcessAdapter();
1920     addProcessListener(processListener);
1921     if (myExecutionResult != null) {
1922       if (myExecutionResult.getProcessHandler().isStartNotified()) {
1923         processListener.run();
1924       }
1925     }
1926   }
1927
1928   public boolean isPausePressed() {
1929     final VirtualMachineProxyImpl vm = myVirtualMachineProxy;
1930     return vm != null && vm.isPausePressed();
1931   }
1932
1933   public DebuggerCommandImpl createPauseCommand() {
1934     return new PauseCommand();
1935   }
1936
1937   public ResumeCommand createResumeCommand(SuspendContextImpl suspendContext) {
1938     return createResumeCommand(suspendContext, PrioritizedTask.Priority.HIGH);
1939   }
1940
1941   public ResumeCommand createResumeCommand(SuspendContextImpl suspendContext, final PrioritizedTask.Priority priority) {
1942     final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
1943     return new ResumeCommand(suspendContext) {
1944       @Override
1945       public void contextAction() {
1946         breakpointManager.applyThreadFilter(DebugProcessImpl.this, null); // clear the filter on resume
1947         super.contextAction();
1948       }
1949
1950       @Override
1951       public Priority getPriority() {
1952         return priority;
1953       }
1954     };
1955   }
1956
1957   public ResumeCommand createStepOverCommand(SuspendContextImpl suspendContext, boolean ignoreBreakpoints) {
1958     return createStepOverCommand(suspendContext, ignoreBreakpoints, StepRequest.STEP_LINE);
1959   }
1960
1961   public ResumeCommand createStepOverCommand(SuspendContextImpl suspendContext, boolean ignoreBreakpoints, int stepSize) {
1962     return new StepOverCommand(suspendContext, ignoreBreakpoints, stepSize);
1963   }
1964
1965   public ResumeCommand createStepOutCommand(SuspendContextImpl suspendContext) {
1966     return createStepOutCommand(suspendContext, StepRequest.STEP_LINE);
1967   }
1968
1969   public ResumeCommand createStepOutCommand(SuspendContextImpl suspendContext, int stepSize) {
1970     return new StepOutCommand(suspendContext, stepSize);
1971   }
1972
1973   public ResumeCommand createStepIntoCommand(SuspendContextImpl suspendContext, boolean ignoreFilters, final MethodFilter smartStepFilter) {
1974     return createStepIntoCommand(suspendContext, ignoreFilters, smartStepFilter, StepRequest.STEP_LINE);
1975   }
1976
1977   public ResumeCommand createStepIntoCommand(SuspendContextImpl suspendContext, boolean ignoreFilters, final MethodFilter smartStepFilter,
1978                                              int stepSize) {
1979     return new StepIntoCommand(suspendContext, ignoreFilters, smartStepFilter, stepSize);
1980   }
1981
1982   public ResumeCommand createRunToCursorCommand(SuspendContextImpl suspendContext, Document document, int lineIndex,
1983                                                             final boolean ignoreBreakpoints)
1984     throws EvaluateException {
1985     RunToCursorCommand runToCursorCommand = new RunToCursorCommand(suspendContext, document, lineIndex, ignoreBreakpoints);
1986     if(runToCursorCommand.myRunToCursorBreakpoint == null) {
1987       final PsiFile psiFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
1988       throw new EvaluateException(DebuggerBundle.message("error.running.to.cursor.no.executable.code", psiFile != null? psiFile.getName() : "<No File>", lineIndex), null);
1989     }
1990     return runToCursorCommand;
1991   }
1992
1993   public DebuggerCommandImpl createFreezeThreadCommand(ThreadReferenceProxyImpl thread) {
1994     return new FreezeThreadCommand(thread);
1995   }
1996
1997   public SuspendContextCommandImpl createResumeThreadCommand(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
1998     return new ResumeThreadCommand(suspendContext, thread);
1999   }
2000
2001   public SuspendContextCommandImpl createPopFrameCommand(DebuggerContextImpl context, StackFrameProxyImpl stackFrame) {
2002     final SuspendContextImpl contextByThread =
2003       SuspendManagerUtil.findContextByThread(context.getDebugProcess().getSuspendManager(), stackFrame.threadProxy());
2004     return new PopFrameCommand(contextByThread, stackFrame);
2005   }
2006
2007   //public void setBreakpointsMuted(final boolean muted) {
2008   //  XDebugSession session = mySession.getXDebugSession();
2009   //  if (isAttached()) {
2010   //    getManagerThread().schedule(new DebuggerCommandImpl() {
2011   //      @Override
2012   //      protected void action() throws Exception {
2013   //        // set the flag before enabling/disabling cause it affects if breakpoints will create requests
2014   //        if (myBreakpointsMuted.getAndSet(muted) != muted) {
2015   //          final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
2016   //          if (muted) {
2017   //            breakpointManager.disableBreakpoints(DebugProcessImpl.this);
2018   //          }
2019   //          else {
2020   //            breakpointManager.enableBreakpoints(DebugProcessImpl.this);
2021   //          }
2022   //        }
2023   //      }
2024   //    });
2025   //  }
2026   //  else {
2027   //    session.setBreakpointMuted(muted);
2028   //  }
2029   //}
2030
2031   public DebuggerContextImpl getDebuggerContext() {
2032     return mySession.getContextManager().getContext();
2033   }
2034
2035   public void setXDebugProcess(JavaDebugProcess XDebugProcess) {
2036     myXDebugProcess = XDebugProcess;
2037   }
2038
2039   @Nullable
2040   public JavaDebugProcess getXdebugProcess() {
2041     return myXDebugProcess;
2042   }
2043
2044   public boolean areBreakpointsMuted() {
2045     XDebugSession session = mySession.getXDebugSession();
2046     return session != null && session.areBreakpointsMuted();
2047   }
2048
2049   public DebuggerSession getSession() {
2050     return mySession;
2051   }
2052 }