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