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