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