autoboxing support for debugger evaluators: method calls (IDEA-36597)
[fedora-idea.git] / java / debugger / impl / src / com / intellij / debugger / engine / DebugProcessImpl.java
blobc05df216afbfa627ba6c2f9e5f6f15eaeb3d0b85
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package com.intellij.debugger.engine;
18 import com.intellij.Patches;
19 import com.intellij.debugger.DebuggerBundle;
20 import com.intellij.debugger.DebuggerInvocationUtil;
21 import com.intellij.debugger.DebuggerManagerEx;
22 import com.intellij.debugger.PositionManager;
23 import com.intellij.debugger.actions.DebuggerActions;
24 import com.intellij.debugger.apiAdapters.ConnectionServiceWrapper;
25 import com.intellij.debugger.apiAdapters.TransportServiceWrapper;
26 import com.intellij.debugger.engine.evaluation.*;
27 import com.intellij.debugger.engine.events.DebuggerCommandImpl;
28 import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
29 import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
30 import com.intellij.debugger.engine.requests.MethodReturnValueWatcher;
31 import com.intellij.debugger.engine.requests.RequestManagerImpl;
32 import com.intellij.debugger.impl.DebuggerContextImpl;
33 import com.intellij.debugger.impl.DebuggerSession;
34 import com.intellij.debugger.impl.DebuggerUtilsEx;
35 import com.intellij.debugger.impl.PrioritizedTask;
36 import com.intellij.debugger.jdi.StackFrameProxyImpl;
37 import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
38 import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
39 import com.intellij.debugger.settings.DebuggerSettings;
40 import com.intellij.debugger.settings.NodeRendererSettings;
41 import com.intellij.debugger.ui.breakpoints.BreakpointManager;
42 import com.intellij.debugger.ui.breakpoints.RunToCursorBreakpoint;
43 import com.intellij.debugger.ui.tree.ValueDescriptor;
44 import com.intellij.debugger.ui.tree.render.*;
45 import com.intellij.execution.CantRunException;
46 import com.intellij.execution.ExecutionException;
47 import com.intellij.execution.ExecutionResult;
48 import com.intellij.execution.Executor;
49 import com.intellij.execution.configurations.CommandLineState;
50 import com.intellij.execution.configurations.RemoteConnection;
51 import com.intellij.execution.configurations.RunProfileState;
52 import com.intellij.execution.filters.ExceptionFilter;
53 import com.intellij.execution.filters.TextConsoleBuilder;
54 import com.intellij.execution.process.ProcessAdapter;
55 import com.intellij.execution.process.ProcessEvent;
56 import com.intellij.execution.process.ProcessListener;
57 import com.intellij.execution.process.ProcessOutputTypes;
58 import com.intellij.execution.runners.ProgramRunner;
59 import com.intellij.execution.runners.ProgramRunnerUtil;
60 import com.intellij.idea.ActionsBundle;
61 import com.intellij.openapi.application.ApplicationManager;
62 import com.intellij.openapi.diagnostic.Logger;
63 import com.intellij.openapi.editor.Document;
64 import com.intellij.openapi.extensions.Extensions;
65 import com.intellij.openapi.project.Project;
66 import com.intellij.openapi.ui.Messages;
67 import com.intellij.openapi.util.Comparing;
68 import com.intellij.openapi.util.Key;
69 import com.intellij.openapi.util.Pair;
70 import com.intellij.openapi.util.Ref;
71 import com.intellij.openapi.wm.WindowManager;
72 import com.intellij.psi.PsiDocumentManager;
73 import com.intellij.psi.PsiFile;
74 import com.intellij.psi.search.GlobalSearchScope;
75 import com.intellij.ui.classFilter.ClassFilter;
76 import com.intellij.ui.classFilter.DebuggerClassFilterProvider;
77 import com.intellij.util.Alarm;
78 import com.intellij.util.EventDispatcher;
79 import com.intellij.util.StringBuilderSpinAllocator;
80 import com.intellij.util.concurrency.Semaphore;
81 import com.sun.jdi.*;
82 import com.sun.jdi.connect.*;
83 import com.sun.jdi.request.EventRequest;
84 import com.sun.jdi.request.EventRequestManager;
85 import com.sun.jdi.request.StepRequest;
86 import org.jetbrains.annotations.NonNls;
87 import org.jetbrains.annotations.NotNull;
88 import org.jetbrains.annotations.Nullable;
90 import javax.swing.*;
91 import java.io.IOException;
92 import java.net.UnknownHostException;
93 import java.util.*;
94 import java.util.concurrent.atomic.AtomicBoolean;
95 import java.util.concurrent.atomic.AtomicInteger;
97 public abstract class DebugProcessImpl implements DebugProcess {
98 private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.DebugProcessImpl");
100 static final @NonNls String SOCKET_ATTACHING_CONNECTOR_NAME = "com.sun.jdi.SocketAttach";
101 static final @NonNls String SHMEM_ATTACHING_CONNECTOR_NAME = "com.sun.jdi.SharedMemoryAttach";
102 static final @NonNls String SOCKET_LISTENING_CONNECTOR_NAME = "com.sun.jdi.SocketListen";
103 static final @NonNls String SHMEM_LISTENING_CONNECTOR_NAME = "com.sun.jdi.SharedMemoryListen";
105 private final Project myProject;
106 private final RequestManagerImpl myRequestManager;
108 private VirtualMachineProxyImpl myVirtualMachineProxy = null;
109 protected EventDispatcher<DebugProcessListener> myDebugProcessDispatcher = EventDispatcher.create(DebugProcessListener.class);
110 protected EventDispatcher<EvaluationListener> myEvaluationDispatcher = EventDispatcher.create(EvaluationListener.class);
112 private final List<ProcessListener> myProcessListeners = new ArrayList<ProcessListener>();
114 protected static final int STATE_INITIAL = 0;
115 protected static final int STATE_ATTACHED = 1;
116 protected static final int STATE_DETACHING = 2;
117 protected static final int STATE_DETACHED = 3;
118 protected final AtomicInteger myState = new AtomicInteger(STATE_INITIAL);
120 private ExecutionResult myExecutionResult;
121 private RemoteConnection myConnection;
123 private ConnectionServiceWrapper myConnectionService;
124 private Map<String, Connector.Argument> myArguments;
126 private final List<NodeRenderer> myRenderers = new ArrayList<NodeRenderer>();
127 private final Map<Type, NodeRenderer> myNodeRederersMap = new com.intellij.util.containers.HashMap<Type, NodeRenderer>();
128 private final NodeRendererSettingsListener mySettingsListener = new NodeRendererSettingsListener() {
129 public void renderersChanged() {
130 myNodeRederersMap.clear();
131 myRenderers.clear();
132 loadRenderers();
136 private final SuspendManagerImpl mySuspendManager = new SuspendManagerImpl(this);
137 protected CompoundPositionManager myPositionManager = null;
138 private volatile DebuggerManagerThreadImpl myDebuggerManagerThread;
139 private final HashMap myUserData = new HashMap();
140 private static final int LOCAL_START_TIMEOUT = 15000;
142 private final Semaphore myWaitFor = new Semaphore();
143 private final AtomicBoolean myBreakpointsMuted = new AtomicBoolean(false);
144 private boolean myIsFailed = false;
145 protected DebuggerSession mySession;
146 protected @Nullable MethodReturnValueWatcher myReturnValueWatcher;
147 private final Alarm myStatusUpdateAlarm = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
149 protected DebugProcessImpl(Project project) {
150 myProject = project;
151 myRequestManager = new RequestManagerImpl(this);
152 NodeRendererSettings.getInstance().addListener(mySettingsListener);
153 loadRenderers();
156 private void loadRenderers() {
157 getManagerThread().invoke(new DebuggerCommandImpl() {
158 protected void action() throws Exception {
159 final NodeRendererSettings rendererSettings = NodeRendererSettings.getInstance();
160 for (final NodeRenderer renderer : rendererSettings.getAllRenderers()) {
161 if (renderer.isEnabled()) {
162 myRenderers.add(renderer);
169 @Nullable
170 public Pair<Method, Value> getLastExecutedMethod() {
171 if (myReturnValueWatcher == null) {
172 return null;
174 final Method method = myReturnValueWatcher.getLastExecutedMethod();
175 if (method == null) {
176 return null;
178 return new Pair<Method, Value>(method, myReturnValueWatcher.getLastMethodReturnValue());
181 public void setWatchMethodReturnValuesEnabled(boolean enabled) {
182 if (myReturnValueWatcher != null) {
183 myReturnValueWatcher.setFeatureEnabled(enabled);
187 public boolean isWatchMethodReturnValuesEnabled() {
188 return myReturnValueWatcher != null && myReturnValueWatcher.isFeatureEnabled();
191 public boolean canGetMethodReturnValue() {
192 return myReturnValueWatcher != null;
195 public NodeRenderer getAutoRenderer(ValueDescriptor descriptor) {
196 DebuggerManagerThreadImpl.assertIsManagerThread();
197 final Value value = descriptor.getValue();
198 Type type = value != null ? value.type() : null;
200 // in case evaluation is not possible, force default renderer
201 if (!DebuggerManagerEx.getInstanceEx(getProject()).getContext().isEvaluationPossible()) {
202 return getDefaultRenderer(type);
205 NodeRenderer renderer = myNodeRederersMap.get(type);
206 if(renderer == null) {
207 for (final NodeRenderer nodeRenderer : myRenderers) {
208 if (nodeRenderer.isApplicable(type)) {
209 renderer = nodeRenderer;
210 break;
213 if (renderer == null) {
214 renderer = getDefaultRenderer(type);
216 myNodeRederersMap.put(type, renderer);
219 return renderer;
222 public final NodeRenderer getDefaultRenderer(Value value) {
223 return getDefaultRenderer((value != null) ? value.type() : (Type)null);
226 public final NodeRenderer getDefaultRenderer(Type type) {
227 final NodeRendererSettings settings = NodeRendererSettings.getInstance();
229 final PrimitiveRenderer primitiveRenderer = settings.getPrimitiveRenderer();
230 if(primitiveRenderer.isApplicable(type)) {
231 return primitiveRenderer;
234 final ArrayRenderer arrayRenderer = settings.getArrayRenderer();
235 if(arrayRenderer.isApplicable(type)) {
236 return arrayRenderer;
239 final ClassRenderer classRenderer = settings.getClassRenderer();
240 LOG.assertTrue(classRenderer.isApplicable(type), type.name());
241 return classRenderer;
245 @SuppressWarnings({"HardCodedStringLiteral"})
246 protected void commitVM(VirtualMachine vm) {
247 if (!isInInitialState()) {
248 LOG.assertTrue(false, "State is invalid " + myState.get());
250 DebuggerManagerThreadImpl.assertIsManagerThread();
251 myPositionManager = createPositionManager();
252 if (LOG.isDebugEnabled()) {
253 LOG.debug("*******************VM attached******************");
255 checkVirtualMachineVersion(vm);
257 myVirtualMachineProxy = new VirtualMachineProxyImpl(this, vm);
259 String trace = System.getProperty("idea.debugger.trace");
260 if (trace != null) {
261 int mask = 0;
262 StringTokenizer tokenizer = new StringTokenizer(trace);
263 while (tokenizer.hasMoreTokens()) {
264 String token = tokenizer.nextToken();
265 if ("SENDS".compareToIgnoreCase(token) == 0) {
266 mask |= VirtualMachine.TRACE_SENDS;
268 else if ("RAW_SENDS".compareToIgnoreCase(token) == 0) {
269 mask |= 0x01000000;
271 else if ("RECEIVES".compareToIgnoreCase(token) == 0) {
272 mask |= VirtualMachine.TRACE_RECEIVES;
274 else if ("RAW_RECEIVES".compareToIgnoreCase(token) == 0) {
275 mask |= 0x02000000;
277 else if ("EVENTS".compareToIgnoreCase(token) == 0) {
278 mask |= VirtualMachine.TRACE_EVENTS;
280 else if ("REFTYPES".compareToIgnoreCase(token) == 0) {
281 mask |= VirtualMachine.TRACE_REFTYPES;
283 else if ("OBJREFS".compareToIgnoreCase(token) == 0) {
284 mask |= VirtualMachine.TRACE_OBJREFS;
286 else if ("ALL".compareToIgnoreCase(token) == 0) {
287 mask |= VirtualMachine.TRACE_ALL;
291 vm.setDebugTraceMode(mask);
295 private void stopConnecting() {
296 DebuggerManagerThreadImpl.assertIsManagerThread();
298 Map arguments = myArguments;
299 try {
300 if (arguments == null) {
301 return;
303 if(myConnection.isServerMode()) {
304 ListeningConnector connector = (ListeningConnector)findConnector(SOCKET_LISTENING_CONNECTOR_NAME);
305 if (connector == null) {
306 LOG.error("Cannot find connector: " + SOCKET_LISTENING_CONNECTOR_NAME);
308 connector.stopListening(arguments);
310 else {
311 if(myConnectionService != null) {
312 myConnectionService.close();
316 catch (IOException e) {
317 if (LOG.isDebugEnabled()) {
318 LOG.debug(e);
321 catch (IllegalConnectorArgumentsException e) {
322 if (LOG.isDebugEnabled()) {
323 LOG.debug(e);
326 catch (ExecutionException e) {
327 LOG.error(e);
329 finally {
330 closeProcess(true);
334 protected CompoundPositionManager createPositionManager() {
335 return new CompoundPositionManager(new PositionManagerImpl(this));
338 public void printToConsole(final String text) {
339 myExecutionResult.getProcessHandler().notifyTextAvailable(text, ProcessOutputTypes.SYSTEM);
344 * @param suspendContext
345 * @param stepThread
346 * @param depth
347 * @param hint may be null
349 protected void doStep(final SuspendContextImpl suspendContext, final ThreadReferenceProxyImpl stepThread, int depth, RequestHint hint) {
350 if (stepThread == null) {
351 return;
353 try {
354 if (LOG.isDebugEnabled()) {
355 LOG.debug("DO_STEP: creating step request for " + stepThread.getThreadReference());
357 deleteStepRequests();
358 EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager();
359 StepRequest stepRequest = requestManager.createStepRequest(stepThread.getThreadReference(), StepRequest.STEP_LINE, depth);
360 DebuggerSettings settings = DebuggerSettings.getInstance();
361 if (!(hint != null && hint.isIgnoreFilters()) /*&& depth == StepRequest.STEP_INTO*/) {
362 final List<ClassFilter> activeFilters = new ArrayList<ClassFilter>();
363 if (settings.TRACING_FILTERS_ENABLED) {
364 for (ClassFilter filter : settings.getSteppingFilters()) {
365 if (filter.isEnabled()) {
366 activeFilters.add(filter);
370 for (DebuggerClassFilterProvider provider : Extensions.getExtensions(DebuggerClassFilterProvider.EP_NAME)) {
371 for (ClassFilter filter : provider.getFilters()) {
372 if (filter.isEnabled()) {
373 activeFilters.add(filter);
378 if (!activeFilters.isEmpty()) {
379 final String currentClassName = getCurrentClassName(stepThread);
380 if (currentClassName == null || !DebuggerUtilsEx.isFiltered(currentClassName, activeFilters)) {
381 // add class filters
382 for (ClassFilter filter : activeFilters) {
383 stepRequest.addClassExclusionFilter(filter.getPattern());
389 // suspend policy to match the suspend policy of the context:
390 // if all threads were suspended, then during stepping all the threads must be suspended
391 // if only event thread were suspended, then only this particular thread must be suspended during stepping
392 stepRequest.setSuspendPolicy(suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD? EventRequest.SUSPEND_EVENT_THREAD : EventRequest.SUSPEND_ALL);
394 if (hint != null) {
395 //noinspection HardCodedStringLiteral
396 stepRequest.putProperty("hint", hint);
398 stepRequest.enable();
400 catch (ObjectCollectedException ignored) {
405 void deleteStepRequests() {
406 EventRequestManager requestManager = getVirtualMachineProxy().eventRequestManager();
407 List<StepRequest> stepRequests = requestManager.stepRequests();
408 if (stepRequests.size() > 0) {
409 final List<StepRequest> toDelete = new ArrayList<StepRequest>(stepRequests.size());
410 for (final StepRequest request : stepRequests) {
411 ThreadReference threadReference = request.thread();
412 // [jeka] on attempt to delete a request assigned to a thread with unknown status, a JDWP error occures
413 if (threadReference.status() != ThreadReference.THREAD_STATUS_UNKNOWN) {
414 toDelete.add(request);
417 requestManager.deleteEventRequests(toDelete);
421 @Nullable
422 private static String getCurrentClassName(ThreadReferenceProxyImpl thread) {
423 try {
424 if (thread != null && thread.frameCount() > 0) {
425 StackFrameProxyImpl stackFrame = thread.frame(0);
426 Location location = stackFrame.location();
427 ReferenceType referenceType = location.declaringType();
428 if (referenceType != null) {
429 return referenceType.name();
433 catch (EvaluateException e) {
435 return null;
438 private VirtualMachine createVirtualMachineInt() throws ExecutionException {
439 try {
440 if (myArguments != null) {
441 throw new IOException(DebuggerBundle.message("error.debugger.already.listening"));
444 final String address = myConnection.getAddress();
445 if (myConnection.isServerMode()) {
446 ListeningConnector connector = (ListeningConnector)findConnector(
447 myConnection.isUseSockets() ? SOCKET_LISTENING_CONNECTOR_NAME : SHMEM_LISTENING_CONNECTOR_NAME);
448 if (connector == null) {
449 throw new CantRunException(DebuggerBundle.message("error.debug.connector.not.found", DebuggerBundle.getTransportName(myConnection)));
451 myArguments = connector.defaultArguments();
452 if (myArguments == null) {
453 throw new CantRunException(DebuggerBundle.message("error.no.debug.listen.port"));
456 if (address == null) {
457 throw new CantRunException(DebuggerBundle.message("error.no.debug.listen.port"));
459 // negative port number means the caller leaves to debugger to decide at which hport to listen
460 //noinspection HardCodedStringLiteral
461 final Connector.Argument portArg = myConnection.isUseSockets() ? myArguments.get("port") : myArguments.get("name");
462 if (portArg != null) {
463 portArg.setValue(address);
465 //noinspection HardCodedStringLiteral
466 final Connector.Argument timeoutArg = myArguments.get("timeout");
467 if (timeoutArg != null) {
468 timeoutArg.setValue("0"); // wait forever
470 connector.startListening(myArguments);
471 myDebugProcessDispatcher.getMulticaster().connectorIsReady();
472 try {
473 return connector.accept(myArguments);
475 finally {
476 if(myArguments != null) {
477 try {
478 connector.stopListening(myArguments);
480 catch (IllegalArgumentException e) {
481 // ignored
483 catch (IllegalConnectorArgumentsException e) {
484 // ignored
489 else { // is client mode, should attach to already running process
490 AttachingConnector connector = (AttachingConnector)findConnector(
491 myConnection.isUseSockets() ? SOCKET_ATTACHING_CONNECTOR_NAME : SHMEM_ATTACHING_CONNECTOR_NAME
494 if (connector == null) {
495 throw new CantRunException( DebuggerBundle.message("error.debug.connector.not.found", DebuggerBundle.getTransportName(myConnection)));
497 myArguments = connector.defaultArguments();
498 if (myConnection.isUseSockets()) {
499 //noinspection HardCodedStringLiteral
500 final Connector.Argument hostnameArg = (Connector.Argument)myArguments.get("hostname");
501 if (hostnameArg != null && myConnection.getHostName() != null) {
502 hostnameArg.setValue(myConnection.getHostName());
504 if (address == null) {
505 throw new CantRunException(DebuggerBundle.message("error.no.debug.attach.port"));
507 //noinspection HardCodedStringLiteral
508 final Connector.Argument portArg = (Connector.Argument)myArguments.get("port");
509 if (portArg != null) {
510 portArg.setValue(address);
513 else {
514 if (address == null) {
515 throw new CantRunException(DebuggerBundle.message("error.no.shmem.address"));
517 //noinspection HardCodedStringLiteral
518 final Connector.Argument nameArg = myArguments.get("name");
519 if (nameArg != null) {
520 nameArg.setValue(address);
523 //noinspection HardCodedStringLiteral
524 final Connector.Argument timeoutArg = myArguments.get("timeout");
525 if (timeoutArg != null) {
526 timeoutArg.setValue("0"); // wait forever
529 myDebugProcessDispatcher.getMulticaster().connectorIsReady();
530 try {
531 if(SOCKET_ATTACHING_CONNECTOR_NAME.equals(connector.name()) && Patches.SUN_BUG_338675) {
532 String portString = myConnection.getAddress();
533 String hostString = myConnection.getHostName();
535 if (hostString == null || hostString.length() == 0) {
536 //noinspection HardCodedStringLiteral
537 hostString = "localhost";
539 hostString = hostString + ":";
541 final TransportServiceWrapper transportServiceWrapper = TransportServiceWrapper.getTransportService(connector.transport());
542 myConnectionService = transportServiceWrapper.attach(hostString + portString);
543 return myConnectionService.createVirtualMachine();
545 else {
546 return connector.attach(myArguments);
549 catch (IllegalArgumentException e) {
550 throw new CantRunException(e.getLocalizedMessage());
554 catch (IOException e) {
555 throw new ExecutionException(processError(e), e);
557 catch (IllegalConnectorArgumentsException e) {
558 throw new ExecutionException(processError(e), e);
560 finally {
561 myArguments = null;
562 myConnectionService = null;
566 public void showStatusText(final String text) {
567 myStatusUpdateAlarm.cancelAllRequests();
568 myStatusUpdateAlarm.addRequest(new Runnable() {
569 public void run() {
570 final WindowManager wm = WindowManager.getInstance();
571 if (wm != null) {
572 wm.getStatusBar(myProject).setInfo(text);
575 }, 50);
578 static Connector findConnector(String connectorName) throws ExecutionException {
579 VirtualMachineManager virtualMachineManager = null;
580 try {
581 virtualMachineManager = Bootstrap.virtualMachineManager();
583 catch (Error e) {
584 final String error = e.getClass().getName() + " : " + e.getLocalizedMessage();
585 throw new ExecutionException(DebuggerBundle.message("debugger.jdi.bootstrap.error", error));
587 List connectors;
588 if (SOCKET_ATTACHING_CONNECTOR_NAME.equals(connectorName) || SHMEM_ATTACHING_CONNECTOR_NAME.equals(connectorName)) {
589 connectors = virtualMachineManager.attachingConnectors();
591 else if (SOCKET_LISTENING_CONNECTOR_NAME.equals(connectorName) || SHMEM_LISTENING_CONNECTOR_NAME.equals(connectorName)) {
592 connectors = virtualMachineManager.listeningConnectors();
594 else {
595 return null;
597 for (Iterator it = connectors.iterator(); it.hasNext();) {
598 Connector connector = (Connector)it.next();
599 if (connectorName.equals(connector.name())) {
600 return connector;
603 return null;
606 private void checkVirtualMachineVersion(VirtualMachine vm) {
607 final String version = vm.version();
608 if ("1.4.0".equals(version)) {
609 SwingUtilities.invokeLater(new Runnable() {
610 public void run() {
611 Messages.showMessageDialog(
612 getProject(),
613 DebuggerBundle.message("warning.jdk140.unstable"), DebuggerBundle.message("title.jdk140.unstable"), Messages.getWarningIcon()
620 /*Event dispatching*/
621 public void addEvaluationListener(EvaluationListener evaluationListener) {
622 myEvaluationDispatcher.addListener(evaluationListener);
625 public void removeEvaluationListener(EvaluationListener evaluationListener) {
626 myEvaluationDispatcher.removeListener(evaluationListener);
629 public void addDebugProcessListener(DebugProcessListener listener) {
630 myDebugProcessDispatcher.addListener(listener);
633 public void removeDebugProcessListener(DebugProcessListener listener) {
634 myDebugProcessDispatcher.removeListener(listener);
637 public void addProcessListener(ProcessListener processListener) {
638 synchronized(myProcessListeners) {
639 if(getExecutionResult() != null) {
640 getExecutionResult().getProcessHandler().addProcessListener(processListener);
642 else {
643 myProcessListeners.add(processListener);
648 public void removeProcessListener(ProcessListener processListener) {
649 synchronized (myProcessListeners) {
650 if(getExecutionResult() != null) {
651 getExecutionResult().getProcessHandler().removeProcessListener(processListener);
653 else {
654 myProcessListeners.remove(processListener);
659 /* getters */
660 public RemoteConnection getConnection() {
661 return myConnection;
664 public ExecutionResult getExecutionResult() {
665 return myExecutionResult;
668 public <T> T getUserData(Key<T> key) {
669 return (T)myUserData.get(key);
672 public <T> void putUserData(Key<T> key, T value) {
673 myUserData.put(key, value);
676 public Project getProject() {
677 return myProject;
680 public boolean canRedefineClasses() {
681 return myVirtualMachineProxy != null && myVirtualMachineProxy.canRedefineClasses();
684 public boolean canWatchFieldModification() {
685 return myVirtualMachineProxy != null && myVirtualMachineProxy.canWatchFieldModification();
688 public boolean isInInitialState() {
689 return myState.get() == STATE_INITIAL;
692 public boolean isAttached() {
693 return myState.get() == STATE_ATTACHED;
696 public boolean isDetached() {
697 return myState.get() == STATE_DETACHED;
700 public boolean isDetaching() {
701 return myState.get() == STATE_DETACHING;
704 public RequestManagerImpl getRequestsManager() {
705 return myRequestManager;
708 public VirtualMachineProxyImpl getVirtualMachineProxy() {
709 DebuggerManagerThreadImpl.assertIsManagerThread();
710 if (myVirtualMachineProxy == null) {
711 throw new VMDisconnectedException();
713 return myVirtualMachineProxy;
716 public void appendPositionManager(final PositionManager positionManager) {
717 DebuggerManagerThreadImpl.assertIsManagerThread();
718 myPositionManager.appendPositionManager(positionManager);
719 DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().updateBreakpoints(this);
722 private RunToCursorBreakpoint myRunToCursorBreakpoint;
724 public void cancelRunToCursorBreakpoint() {
725 DebuggerManagerThreadImpl.assertIsManagerThread();
726 if (myRunToCursorBreakpoint != null) {
727 getRequestsManager().deleteRequest(myRunToCursorBreakpoint);
728 myRunToCursorBreakpoint.delete();
729 if (myRunToCursorBreakpoint.isRestoreBreakpoints()) {
730 final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
731 breakpointManager.enableBreakpoints(this);
733 myRunToCursorBreakpoint = null;
737 protected void closeProcess(boolean closedByUser) {
738 DebuggerManagerThreadImpl.assertIsManagerThread();
740 if (myState.compareAndSet(STATE_INITIAL, STATE_DETACHING) || myState.compareAndSet(STATE_ATTACHED, STATE_DETACHING)) {
741 myVirtualMachineProxy = null;
742 myPositionManager = null;
744 try {
745 getManagerThread().close();
747 finally {
748 myState.set(STATE_DETACHED);
749 try {
750 myDebugProcessDispatcher.getMulticaster().processDetached(this, closedByUser);
752 finally {
753 setBreakpointsMuted(false);
754 myWaitFor.up();
761 private static String formatMessage(String message) {
762 final int lineLength = 90;
763 StringBuffer buf = new StringBuffer(message.length());
764 int index = 0;
765 while (index < message.length()) {
766 buf.append(message.substring(index, Math.min(index + lineLength, message.length()))).append('\n');
767 index += lineLength;
769 return buf.toString();
772 public static String processError(Exception e) {
773 String message;
775 if (e instanceof VMStartException) {
776 VMStartException e1 = (VMStartException)e;
777 message = e1.getLocalizedMessage();
779 else if (e instanceof IllegalConnectorArgumentsException) {
780 IllegalConnectorArgumentsException e1 = (IllegalConnectorArgumentsException)e;
781 final List<String> invalidArgumentNames = e1.argumentNames();
782 message = formatMessage(DebuggerBundle.message("error.invalid.argument", invalidArgumentNames.size()) + ": "+ e1.getLocalizedMessage()) + invalidArgumentNames;
783 if (LOG.isDebugEnabled()) {
784 LOG.debug(e1);
787 else if (e instanceof CantRunException) {
788 message = e.getLocalizedMessage();
790 else if (e instanceof VMDisconnectedException) {
791 message = DebuggerBundle.message("error.vm.disconnected");
793 else if (e instanceof UnknownHostException) {
794 message = DebuggerBundle.message("error.unknown.host") + ":\n" + e.getLocalizedMessage();
796 else if (e instanceof IOException) {
797 IOException e1 = (IOException)e;
798 final StringBuilder buf = StringBuilderSpinAllocator.alloc();
799 try {
800 buf.append(DebuggerBundle.message("error.cannot.open.debugger.port")).append(" : ");
801 buf.append(e1.getClass().getName() + " ");
802 final String localizedMessage = e1.getLocalizedMessage();
803 if (localizedMessage != null && localizedMessage.length() > 0) {
804 buf.append('"');
805 buf.append(localizedMessage);
806 buf.append('"');
808 if (LOG.isDebugEnabled()) {
809 LOG.debug(e1);
811 message = buf.toString();
813 finally {
814 StringBuilderSpinAllocator.dispose(buf);
817 else if (e instanceof ExecutionException) {
818 message = e.getLocalizedMessage();
820 else {
821 message = DebuggerBundle.message("error.exception.while.connecting", e.getClass().getName(), e.getLocalizedMessage());
822 if (LOG.isDebugEnabled()) {
823 LOG.debug(e);
826 return message;
829 public void dispose() {
830 NodeRendererSettings.getInstance().removeListener(mySettingsListener);
831 myStatusUpdateAlarm.dispose();
834 public DebuggerManagerThreadImpl getManagerThread() {
835 if (myDebuggerManagerThread == null) {
836 synchronized (this) {
837 if (myDebuggerManagerThread == null) {
838 myDebuggerManagerThread = new DebuggerManagerThreadImpl();
842 return myDebuggerManagerThread;
845 private static int getInvokePolicy(SuspendContext suspendContext) {
846 //return ThreadReference.INVOKE_SINGLE_THREADED;
847 return suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD ? ThreadReference.INVOKE_SINGLE_THREADED : 0;
850 public void waitFor() {
851 LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread());
852 myWaitFor.waitFor();
855 public void waitFor(long timeout) {
856 LOG.assertTrue(!DebuggerManagerThreadImpl.isManagerThread());
857 myWaitFor.waitFor(timeout);
860 private abstract class InvokeCommand <E extends Value> {
861 private final List myArgs;
863 protected InvokeCommand(List args) {
864 if (args.size() > 0) {
865 myArgs = new ArrayList(args);
867 else {
868 myArgs = args;
872 public String toString() {
873 return "INVOKE: " + super.toString();
876 protected abstract E invokeMethod(int invokePolicy, final List args) throws InvocationException,
877 ClassNotLoadedException,
878 IncompatibleThreadStateException,
879 InvalidTypeException;
881 public E start(EvaluationContextImpl evaluationContext, Method method) throws EvaluateException {
882 DebuggerManagerThreadImpl.assertIsManagerThread();
883 SuspendContextImpl suspendContext = evaluationContext.getSuspendContext();
884 SuspendManagerUtil.assertSuspendContext(suspendContext);
886 ThreadReferenceProxyImpl invokeThread = suspendContext.getThread();
888 if (SuspendManagerUtil.isEvaluating(getSuspendManager(), invokeThread)) {
889 throw EvaluateExceptionUtil.NESTED_EVALUATION_ERROR;
892 Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), invokeThread);
893 final ThreadReference invokeThreadRef = invokeThread.getThreadReference();
895 myEvaluationDispatcher.getMulticaster().evaluationStarted(suspendContext);
896 beforeMethodInvocation(suspendContext, method);
898 Object resumeData = null;
899 try {
900 for (final SuspendContextImpl suspendingContext : suspendingContexts) {
901 final ThreadReferenceProxyImpl suspendContextThread = suspendingContext.getThread();
902 if (suspendContextThread != invokeThread) {
903 if (LOG.isDebugEnabled()) {
904 LOG.debug("Resuming " + invokeThread + " that is paused by " + suspendContextThread);
906 LOG.assertTrue(suspendContextThread == null || !invokeThreadRef.equals(suspendContextThread.getThreadReference()));
907 getSuspendManager().resumeThread(suspendingContext, invokeThread);
911 resumeData = SuspendManagerUtil.prepareForResume(suspendContext);
912 suspendContext.setIsEvaluating(evaluationContext);
914 getVirtualMachineProxy().clearCaches();
916 while (true) {
917 try {
918 return invokeMethodAndFork(suspendContext);
920 catch (ClassNotLoadedException e) {
921 ReferenceType loadedClass = null;
922 try {
923 loadedClass = evaluationContext.isAutoLoadClasses()? loadClass(evaluationContext, e.className(), evaluationContext.getClassLoader()) : null;
925 catch (EvaluateException ignored) {
926 loadedClass = null;
928 if (loadedClass == null) {
929 throw EvaluateExceptionUtil.createEvaluateException(e);
934 catch (ClassNotLoadedException e) {
935 throw EvaluateExceptionUtil.createEvaluateException(e);
937 catch (InvocationException e) {
938 throw EvaluateExceptionUtil.createEvaluateException(e);
940 catch (IncompatibleThreadStateException e) {
941 throw EvaluateExceptionUtil.createEvaluateException(e);
943 catch (InvalidTypeException e) {
944 throw EvaluateExceptionUtil.createEvaluateException(e);
946 catch (ObjectCollectedException e) {
947 throw EvaluateExceptionUtil.createEvaluateException(e);
949 catch (UnsupportedOperationException e) {
950 throw EvaluateExceptionUtil.createEvaluateException(e);
952 catch (InternalException e) {
953 throw EvaluateExceptionUtil.createEvaluateException(e);
955 finally {
956 suspendContext.setIsEvaluating(null);
957 if (resumeData != null) {
958 SuspendManagerUtil.restoreAfterResume(suspendContext, resumeData);
960 for (SuspendContextImpl suspendingContext : mySuspendManager.getEventContexts()) {
961 if (suspendingContexts.contains(suspendingContext) && !suspendingContext.isEvaluating() && !suspendingContext.suspends(invokeThread)) {
962 mySuspendManager.suspendThread(suspendingContext, invokeThread);
966 if (LOG.isDebugEnabled()) {
967 LOG.debug("getVirtualMachine().clearCaches()");
969 getVirtualMachineProxy().clearCaches();
970 afterMethodInvocation(suspendContext);
972 myEvaluationDispatcher.getMulticaster().evaluationFinished(suspendContext);
976 private E invokeMethodAndFork(final SuspendContextImpl context) throws InvocationException,
977 ClassNotLoadedException,
978 IncompatibleThreadStateException,
979 InvalidTypeException {
980 final int invokePolicy = getInvokePolicy(context);
981 final Exception[] exception = new Exception[1];
982 final Value[] result = new Value[1];
983 getManagerThread().startLongProcessAndFork(new Runnable() {
984 public void run() {
985 ThreadReferenceProxyImpl thread = context.getThread();
986 try {
987 try {
988 if (LOG.isDebugEnabled()) {
989 final VirtualMachineProxyImpl virtualMachineProxy = getVirtualMachineProxy();
990 virtualMachineProxy.logThreads();
991 LOG.debug("Invoke in " + thread.name());
992 assertThreadSuspended(thread, context);
994 if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
995 // ensure args are not collected
996 for (Object arg : myArgs) {
997 if (arg instanceof ObjectReference) {
998 ((ObjectReference)arg).disableCollection();
1002 result[0] = invokeMethod(invokePolicy, myArgs);
1004 finally {
1005 // assertThreadSuspended(thread, context);
1006 if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
1007 // ensure args are not collected
1008 for (Object arg : myArgs) {
1009 if (arg instanceof ObjectReference) {
1010 ((ObjectReference)arg).enableCollection();
1016 catch (Exception e) {
1017 exception[0] = e;
1022 if (exception[0] != null) {
1023 if (exception[0] instanceof InvocationException) {
1024 throw (InvocationException)exception[0];
1026 else if (exception[0] instanceof ClassNotLoadedException) {
1027 throw (ClassNotLoadedException)exception[0];
1029 else if (exception[0] instanceof IncompatibleThreadStateException) {
1030 throw (IncompatibleThreadStateException)exception[0];
1032 else if (exception[0] instanceof InvalidTypeException) {
1033 throw (InvalidTypeException)exception[0];
1035 else if (exception[0] instanceof RuntimeException) {
1036 throw (RuntimeException)exception[0];
1038 else {
1039 LOG.assertTrue(false);
1043 return (E)result[0];
1046 private void assertThreadSuspended(final ThreadReferenceProxyImpl thread, final SuspendContextImpl context) {
1047 LOG.assertTrue(context.isEvaluating());
1048 try {
1049 final boolean isSuspended = thread.isSuspended();
1050 LOG.assertTrue(isSuspended, thread);
1052 catch (ObjectCollectedException ignored) {
1057 public Value invokeMethod(final EvaluationContext evaluationContext, final ObjectReference objRef, final Method method, final List args) throws EvaluateException {
1058 return invokeInstanceMethod(evaluationContext, objRef, method, args, 0);
1061 public Value invokeInstanceMethod(final EvaluationContext evaluationContext, final ObjectReference objRef, final Method method,
1062 final List args, final int invocationOptions) throws EvaluateException {
1063 final ThreadReference thread = getEvaluationThread(evaluationContext);
1064 InvokeCommand<Value> invokeCommand = new InvokeCommand<Value>(args) {
1065 protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException {
1066 if (LOG.isDebugEnabled()) {
1067 LOG.debug("Invoke " + method.name());
1069 //try {
1070 // if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
1071 // // ensure target object wil not be collected
1072 // objRef.disableCollection();
1073 // }
1074 return objRef.invokeMethod(thread, method, args, invokePolicy | invocationOptions);
1076 //finally {
1077 // if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
1078 // objRef.enableCollection();
1079 // }
1083 return invokeCommand.start((EvaluationContextImpl)evaluationContext, method);
1086 private static ThreadReference getEvaluationThread(final EvaluationContext evaluationContext) throws EvaluateException {
1087 ThreadReferenceProxy evaluationThread = evaluationContext.getSuspendContext().getThread();
1088 if(evaluationThread == null) {
1089 throw EvaluateExceptionUtil.NULL_STACK_FRAME;
1091 return evaluationThread.getThreadReference();
1094 public Value invokeMethod(final EvaluationContext evaluationContext, final ClassType classType,
1095 final Method method,
1096 final List args) throws EvaluateException {
1098 final ThreadReference thread = getEvaluationThread(evaluationContext);
1099 InvokeCommand<Value> invokeCommand = new InvokeCommand<Value>(args) {
1100 protected Value invokeMethod(int invokePolicy, final List args) throws InvocationException,
1101 ClassNotLoadedException,
1102 IncompatibleThreadStateException,
1103 InvalidTypeException {
1104 if (LOG.isDebugEnabled()) {
1105 LOG.debug("Invoke " + method.name());
1107 return classType.invokeMethod(thread, method, args, invokePolicy);
1110 return invokeCommand.start((EvaluationContextImpl)evaluationContext, method);
1113 public ArrayReference newInstance(final ArrayType arrayType,
1114 final int dimension)
1115 throws EvaluateException {
1116 return arrayType.newInstance(dimension);
1119 public ObjectReference newInstance(final EvaluationContext evaluationContext, final ClassType classType,
1120 final Method method,
1121 final List args) throws EvaluateException {
1122 final ThreadReference thread = getEvaluationThread(evaluationContext);
1123 InvokeCommand<ObjectReference> invokeCommand = new InvokeCommand<ObjectReference>(args) {
1124 protected ObjectReference invokeMethod(int invokePolicy, final List args) throws InvocationException,
1125 ClassNotLoadedException,
1126 IncompatibleThreadStateException,
1127 InvalidTypeException {
1128 if (LOG.isDebugEnabled()) {
1129 LOG.debug("New instance " + method.name());
1131 return classType.newInstance(thread, method, args, invokePolicy);
1134 return invokeCommand.start((EvaluationContextImpl)evaluationContext, method);
1137 public void clearCashes(int suspendPolicy) {
1138 if (!isAttached()) return;
1139 switch (suspendPolicy) {
1140 case EventRequest.SUSPEND_ALL:
1141 getVirtualMachineProxy().clearCaches();
1142 break;
1143 case EventRequest.SUSPEND_EVENT_THREAD:
1144 getVirtualMachineProxy().clearCaches();
1145 //suspendContext.getThread().clearAll();
1146 break;
1150 protected void beforeSuspend(SuspendContextImpl suspendContext) {
1151 clearCashes(suspendContext.getSuspendPolicy());
1154 private void beforeMethodInvocation(SuspendContextImpl suspendContext, Method method) {
1155 if (LOG.isDebugEnabled()) {
1156 LOG.debug(
1157 "before invocation in thread " + suspendContext.getThread().name() + " method " + (method == null ? "null" : method.name()));
1160 if (method != null) {
1161 showStatusText(DebuggerBundle.message("progress.evaluating", DebuggerUtilsEx.methodName(method)));
1163 else {
1164 showStatusText(DebuggerBundle.message("title.evaluating"));
1168 private void afterMethodInvocation(SuspendContextImpl suspendContext) {
1169 if (LOG.isDebugEnabled()) {
1170 LOG.debug("after invocation in thread " + suspendContext.getThread().name());
1172 showStatusText("");
1175 public ReferenceType findClass(EvaluationContext evaluationContext, String className,
1176 ClassLoaderReference classLoader) throws EvaluateException {
1177 try {
1178 DebuggerManagerThreadImpl.assertIsManagerThread();
1179 ReferenceType result = null;
1180 final VirtualMachineProxyImpl vmProxy = getVirtualMachineProxy();
1181 if (vmProxy == null) {
1182 throw new VMDisconnectedException();
1184 for (final ReferenceType refType : vmProxy.classesByName(className)) {
1185 if (refType.isPrepared() && isVisibleFromClassLoader(classLoader, refType)) {
1186 result = refType;
1187 break;
1190 final EvaluationContextImpl evalContext = (EvaluationContextImpl)evaluationContext;
1191 if (result == null && evalContext.isAutoLoadClasses()) {
1192 return loadClass(evalContext, className, classLoader);
1194 return result;
1196 catch (InvocationException e) {
1197 throw EvaluateExceptionUtil.createEvaluateException(e);
1199 catch (ClassNotLoadedException e) {
1200 throw EvaluateExceptionUtil.createEvaluateException(e);
1202 catch (IncompatibleThreadStateException e) {
1203 throw EvaluateExceptionUtil.createEvaluateException(e);
1205 catch (InvalidTypeException e) {
1206 throw EvaluateExceptionUtil.createEvaluateException(e);
1210 private static boolean isVisibleFromClassLoader(final ClassLoaderReference fromLoader, final ReferenceType refType) {
1211 final ClassLoaderReference typeLoader = refType.classLoader();
1212 if (typeLoader == null) {
1213 return true; // optimization: if class is loaded by a bootstrap loader, it is visible from every other loader
1215 for (ClassLoaderReference checkLoader = fromLoader; checkLoader != null; checkLoader = getParentLoader(checkLoader)) {
1216 if (Comparing.equal(typeLoader, checkLoader)) {
1217 return true;
1220 return fromLoader != null? fromLoader.visibleClasses().contains(refType) : false;
1223 @SuppressWarnings({"HardCodedStringLiteral"})
1224 private static ClassLoaderReference getParentLoader(final ClassLoaderReference fromLoader) {
1225 final ReferenceType refType = fromLoader.referenceType();
1226 Field field = refType.fieldByName("parent");
1227 if (field == null) {
1228 final List allFields = refType.allFields();
1229 for (Iterator it = allFields.iterator(); it.hasNext();) {
1230 final Field candidateField = (Field)it.next();
1231 try {
1232 final Type checkedType = candidateField.type();
1233 if (checkedType instanceof ReferenceType && DebuggerUtilsEx.isAssignableFrom("java.lang.ClassLoader", (ReferenceType)checkedType)) {
1234 field = candidateField;
1235 break;
1238 catch (ClassNotLoadedException e) {
1239 // ignore this and continue,
1240 // java.lang.ClassLoader must be loaded at the moment of check, so if this happens, the field's type is definitely not java.lang.ClassLoader
1244 return field != null? (ClassLoaderReference)fromLoader.getValue(field) : null;
1247 private String reformatArrayName(String className) {
1248 if (className.indexOf('[') == -1) return className;
1250 int dims = 0;
1251 while (className.endsWith("[]")) {
1252 className = className.substring(0, className.length() - 2);
1253 dims++;
1256 StringBuilder buffer = StringBuilderSpinAllocator.alloc();
1257 try {
1258 for (int i = 0; i < dims; i++) {
1259 buffer.append('[');
1261 String primitiveSignature = JVMNameUtil.getPrimitiveSignature(className);
1262 if(primitiveSignature != null) {
1263 buffer.append(primitiveSignature);
1265 else {
1266 buffer.append('L');
1267 buffer.append(className);
1268 buffer.append(';');
1270 return buffer.toString();
1272 finally {
1273 StringBuilderSpinAllocator.dispose(buffer);
1277 @SuppressWarnings({"HardCodedStringLiteral"})
1278 public ReferenceType loadClass(EvaluationContextImpl evaluationContext, String qName, ClassLoaderReference classLoader)
1279 throws InvocationException, ClassNotLoadedException, IncompatibleThreadStateException, InvalidTypeException, EvaluateException {
1281 DebuggerManagerThreadImpl.assertIsManagerThread();
1282 qName = reformatArrayName(qName);
1283 ReferenceType refType = null;
1284 VirtualMachineProxyImpl virtualMachine = getVirtualMachineProxy();
1285 final List classClasses = virtualMachine.classesByName("java.lang.Class");
1286 if (classClasses.size() > 0) {
1287 ClassType classClassType = (ClassType)classClasses.get(0);
1288 final Method forNameMethod;
1289 if (classLoader != null) {
1290 //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
1291 forNameMethod = DebuggerUtils.findMethod(classClassType, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
1293 else {
1294 //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1295 forNameMethod = DebuggerUtils.findMethod(classClassType, "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1297 final List<Mirror> args = new ArrayList<Mirror>(); // do not use unmodifiable lists because the list is modified by JPDA
1298 final StringReference qNameMirror = virtualMachine.mirrorOf(qName);
1299 args.add(qNameMirror);
1300 if (classLoader != null) {
1301 args.add(virtualMachine.mirrorOf(true));
1302 args.add(classLoader);
1304 final Value value = invokeMethod(evaluationContext, classClassType, forNameMethod, args);
1305 if (value instanceof ClassObjectReference) {
1306 refType = ((ClassObjectReference)value).reflectedType();
1309 return refType;
1312 public void logThreads() {
1313 if (LOG.isDebugEnabled()) {
1314 try {
1315 Collection<ThreadReferenceProxyImpl> allThreads = getVirtualMachineProxy().allThreads();
1316 for (ThreadReferenceProxyImpl threadReferenceProxy : allThreads) {
1317 LOG.debug("Thread name=" + threadReferenceProxy.name() + " suspendCount()=" + threadReferenceProxy.getSuspendCount());
1320 catch (Exception e) {
1321 LOG.debug(e);
1326 public SuspendManager getSuspendManager() {
1327 return mySuspendManager;
1330 public CompoundPositionManager getPositionManager() {
1331 return myPositionManager;
1333 //ManagerCommands
1335 public void stop(boolean forceTerminate) {
1336 this.getManagerThread().terminateAndInvoke(createStopCommand(forceTerminate), DebuggerManagerThreadImpl.COMMAND_TIMEOUT);
1339 public StopCommand createStopCommand(boolean forceTerminate) {
1340 return new StopCommand(forceTerminate);
1343 protected class StopCommand extends DebuggerCommandImpl {
1344 private final boolean myIsTerminateTargetVM;
1346 public StopCommand(boolean isTerminateTargetVM) {
1347 myIsTerminateTargetVM = isTerminateTargetVM;
1350 public Priority getPriority() {
1351 return Priority.HIGH;
1354 protected void action() throws Exception {
1355 if (isAttached()) {
1356 final VirtualMachineProxyImpl virtualMachineProxy = getVirtualMachineProxy();
1357 if (myIsTerminateTargetVM) {
1358 virtualMachineProxy.exit(-1);
1360 else {
1361 // some VM's (like IBM VM 1.4.2 bundled with WebSpere) does not
1362 // resume threads on dispose() like it should
1363 virtualMachineProxy.resume();
1364 virtualMachineProxy.dispose();
1367 else {
1368 stopConnecting();
1373 private class StepOutCommand extends ResumeCommand {
1374 public StepOutCommand(SuspendContextImpl suspendContext) {
1375 super(suspendContext);
1378 public void contextAction() {
1379 showStatusText(DebuggerBundle.message("status.step.out"));
1380 final SuspendContextImpl suspendContext = getSuspendContext();
1381 final ThreadReferenceProxyImpl thread = suspendContext.getThread();
1382 RequestHint hint = new RequestHint(thread, suspendContext, StepRequest.STEP_OUT);
1383 hint.setIgnoreFilters(mySession.shouldIgnoreSteppingFilters());
1384 if (myReturnValueWatcher != null) {
1385 myReturnValueWatcher.setTrackingEnabled(true);
1387 doStep(suspendContext, thread, StepRequest.STEP_OUT, hint);
1388 super.contextAction();
1392 private class StepIntoCommand extends ResumeCommand {
1393 private final boolean myForcedIgnoreFilters;
1394 private final RequestHint.SmartStepFilter mySmartStepFilter;
1396 public StepIntoCommand(SuspendContextImpl suspendContext, boolean ignoreFilters, final @Nullable RequestHint.SmartStepFilter smartStepFilter) {
1397 super(suspendContext);
1398 myForcedIgnoreFilters = ignoreFilters || smartStepFilter != null;
1399 mySmartStepFilter = smartStepFilter;
1402 public void contextAction() {
1403 showStatusText(DebuggerBundle.message("status.step.into"));
1404 final SuspendContextImpl suspendContext = getSuspendContext();
1405 final ThreadReferenceProxyImpl stepThread = suspendContext.getThread();
1406 final RequestHint hint = mySmartStepFilter != null?
1407 new RequestHint(stepThread, suspendContext, mySmartStepFilter) :
1408 new RequestHint(stepThread, suspendContext, StepRequest.STEP_INTO);
1409 if (myForcedIgnoreFilters) {
1410 try {
1411 mySession.setIgnoreStepFiltersFlag(stepThread.frameCount());
1413 catch (EvaluateException e) {
1414 LOG.info(e);
1417 hint.setIgnoreFilters(myForcedIgnoreFilters || mySession.shouldIgnoreSteppingFilters());
1418 doStep(suspendContext, stepThread, StepRequest.STEP_INTO, hint);
1419 super.contextAction();
1423 private class StepOverCommand extends ResumeCommand {
1424 private final boolean myIsIgnoreBreakpoints;
1426 public StepOverCommand(SuspendContextImpl suspendContext, boolean ignoreBreakpoints) {
1427 super(suspendContext);
1428 myIsIgnoreBreakpoints = ignoreBreakpoints;
1431 public void contextAction() {
1432 showStatusText(DebuggerBundle.message("status.step.over"));
1433 final SuspendContextImpl suspendContext = getSuspendContext();
1434 final ThreadReferenceProxyImpl steppingThread = suspendContext.getThread();
1435 // need this hint whil stepping over for JSR45 support:
1436 // several lines of generated java code may correspond to a single line in the source file,
1437 // from which the java code was generated
1438 RequestHint hint = new RequestHint(steppingThread, suspendContext, StepRequest.STEP_OVER);
1439 hint.setRestoreBreakpoints(myIsIgnoreBreakpoints);
1440 hint.setIgnoreFilters(myIsIgnoreBreakpoints || mySession.shouldIgnoreSteppingFilters());
1442 if (myReturnValueWatcher != null) {
1443 myReturnValueWatcher.setTrackingEnabled(true);
1445 doStep(suspendContext, steppingThread, StepRequest.STEP_OVER, hint);
1447 if (myIsIgnoreBreakpoints) {
1448 DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager().disableBreakpoints(DebugProcessImpl.this);
1450 super.contextAction();
1454 private class RunToCursorCommand extends ResumeCommand {
1455 private final RunToCursorBreakpoint myRunToCursorBreakpoint;
1456 private final boolean myIgnoreBreakpoints;
1458 private RunToCursorCommand(SuspendContextImpl suspendContext, Document document, int lineIndex, final boolean ignoreBreakpoints) {
1459 super(suspendContext);
1460 myIgnoreBreakpoints = ignoreBreakpoints;
1461 final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
1462 myRunToCursorBreakpoint = breakpointManager.addRunToCursorBreakpoint(document, lineIndex, ignoreBreakpoints);
1465 public void contextAction() {
1466 showStatusText(DebuggerBundle.message("status.run.to.cursor"));
1467 cancelRunToCursorBreakpoint();
1468 if (myRunToCursorBreakpoint == null) {
1469 return;
1471 if (myIgnoreBreakpoints) {
1472 final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
1473 breakpointManager.disableBreakpoints(DebugProcessImpl.this);
1475 myRunToCursorBreakpoint.SUSPEND_POLICY = DebuggerSettings.SUSPEND_ALL;
1476 myRunToCursorBreakpoint.LOG_ENABLED = false;
1477 myRunToCursorBreakpoint.createRequest(getSuspendContext().getDebugProcess());
1478 DebugProcessImpl.this.myRunToCursorBreakpoint = myRunToCursorBreakpoint;
1479 super.contextAction();
1483 public abstract class ResumeCommand extends SuspendContextCommandImpl {
1485 public ResumeCommand(SuspendContextImpl suspendContext) {
1486 super(suspendContext);
1489 public Priority getPriority() {
1490 return Priority.HIGH;
1493 public void contextAction() {
1494 showStatusText(DebuggerBundle.message("status.process.resumed"));
1495 getSuspendManager().resume(getSuspendContext());
1496 myDebugProcessDispatcher.getMulticaster().resumed(getSuspendContext());
1500 private class PauseCommand extends DebuggerCommandImpl {
1501 public PauseCommand() {
1504 public void action() {
1505 if (!isAttached() || getVirtualMachineProxy().isPausePressed()) {
1506 return;
1508 logThreads();
1509 getVirtualMachineProxy().suspend();
1510 logThreads();
1511 SuspendContextImpl suspendContext = mySuspendManager.pushSuspendContext(EventRequest.SUSPEND_ALL, 0);
1512 myDebugProcessDispatcher.getMulticaster().paused(suspendContext);
1516 private class ResumeThreadCommand extends SuspendContextCommandImpl {
1517 private final ThreadReferenceProxyImpl myThread;
1519 public ResumeThreadCommand(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
1520 super(suspendContext);
1521 myThread = thread;
1524 public void contextAction() {
1525 if (getSuspendManager().isFrozen(myThread)) {
1526 getSuspendManager().unfreezeThread(myThread);
1527 return;
1530 final Set<SuspendContextImpl> suspendingContexts = SuspendManagerUtil.getSuspendingContexts(getSuspendManager(), myThread);
1531 for (Iterator<SuspendContextImpl> iterator = suspendingContexts.iterator(); iterator.hasNext();) {
1532 SuspendContextImpl suspendContext = iterator.next();
1533 if (suspendContext.getThread() == myThread) {
1534 DebugProcessImpl.this.getManagerThread().invoke(createResumeCommand(suspendContext));
1536 else {
1537 getSuspendManager().resumeThread(suspendContext, myThread);
1543 private class FreezeThreadCommand extends DebuggerCommandImpl {
1544 private final ThreadReferenceProxyImpl myThread;
1546 public FreezeThreadCommand(ThreadReferenceProxyImpl thread) {
1547 myThread = thread;
1550 protected void action() throws Exception {
1551 SuspendManager suspendManager = getSuspendManager();
1552 if (!suspendManager.isFrozen(myThread)) {
1553 suspendManager.freezeThread(myThread);
1558 private class PopFrameCommand extends SuspendContextCommandImpl {
1559 private final StackFrameProxyImpl myStackFrame;
1561 public PopFrameCommand(SuspendContextImpl context, StackFrameProxyImpl frameProxy) {
1562 super(context);
1563 myStackFrame = frameProxy;
1566 public void contextAction() {
1567 final ThreadReferenceProxyImpl thread = myStackFrame.threadProxy();
1568 try {
1569 if (!getSuspendManager().isSuspended(thread)) {
1570 notifyCancelled();
1571 return;
1574 catch (ObjectCollectedException e) {
1575 notifyCancelled();
1576 return;
1579 final SuspendContextImpl suspendContext = getSuspendContext();
1580 if (!suspendContext.suspends(thread)) {
1581 suspendContext.postponeCommand(this);
1582 return;
1585 if (myStackFrame.isBottom()) {
1586 DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
1587 public void run() {
1588 Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.bottom.stackframe"), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
1591 return;
1594 try {
1595 thread.popFrames(myStackFrame);
1597 catch (final EvaluateException e) {
1598 DebuggerInvocationUtil.swingInvokeLater(myProject, new Runnable() {
1599 public void run() {
1600 Messages.showMessageDialog(myProject, DebuggerBundle.message("error.pop.stackframe", e.getLocalizedMessage()), ActionsBundle.actionText(DebuggerActions.POP_FRAME), Messages.getErrorIcon());
1603 LOG.info(e);
1605 finally {
1606 getSuspendManager().popFrame(suspendContext);
1611 @NotNull
1612 public GlobalSearchScope getSearchScope() {
1613 LOG.assertTrue(mySession != null, "Accessing debug session before its initialization");
1614 return mySession.getSearchScope();
1617 public @Nullable ExecutionResult attachVirtualMachine(final Executor executor,
1618 final ProgramRunner runner,
1619 final DebuggerSession session,
1620 final RunProfileState state,
1621 final RemoteConnection remoteConnection,
1622 boolean pollConnection) throws ExecutionException {
1623 mySession = session;
1624 myWaitFor.down();
1626 ApplicationManager.getApplication().assertIsDispatchThread();
1627 LOG.assertTrue(isInInitialState());
1629 myConnection = remoteConnection;
1631 createVirtualMachine(state, pollConnection);
1633 try {
1634 synchronized (myProcessListeners) {
1635 if (state instanceof CommandLineState) {
1636 final TextConsoleBuilder consoleBuilder = ((CommandLineState)state).getConsoleBuilder();
1637 if (consoleBuilder != null) {
1638 consoleBuilder.addFilter(new ExceptionFilter(session.getSearchScope()));
1641 myExecutionResult = state.execute(executor, runner);
1642 if (myExecutionResult == null) {
1643 fail();
1644 return null;
1646 for (ProcessListener processListener : myProcessListeners) {
1647 myExecutionResult.getProcessHandler().addProcessListener(processListener);
1649 myProcessListeners.clear();
1652 catch (ExecutionException e) {
1653 fail();
1654 throw e;
1657 if (ApplicationManager.getApplication().isUnitTestMode()) {
1658 return myExecutionResult;
1662 final Alarm debugPortTimeout = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
1664 myExecutionResult.getProcessHandler().addProcessListener(new ProcessAdapter() {
1665 public void processTerminated(ProcessEvent event) {
1666 debugPortTimeout.cancelAllRequests();
1669 public void startNotified(ProcessEvent event) {
1670 debugPortTimeout.addRequest(new Runnable() {
1671 public void run() {
1672 if(isInInitialState()) {
1673 ApplicationManager.getApplication().schedule(new Runnable() {
1674 public void run() {
1675 String message = DebuggerBundle.message("status.connect.failed", DebuggerBundle.getAddressDisplayName(remoteConnection), DebuggerBundle.getTransportName(remoteConnection));
1676 Messages.showErrorDialog(myProject, message, DebuggerBundle.message("title.generic.debug.dialog"));
1681 }, LOCAL_START_TIMEOUT);
1686 return myExecutionResult;
1689 private void fail() {
1690 synchronized (this) {
1691 if (myIsFailed) {
1692 // need this in order to prevent calling stop() twice
1693 return;
1695 myIsFailed = true;
1697 stop(false);
1700 private void createVirtualMachine(final RunProfileState state, final boolean pollConnection) {
1701 final Semaphore semaphore = new Semaphore();
1702 semaphore.down();
1704 final Ref<Boolean> connectorIsReady = Ref.create(false);
1705 myDebugProcessDispatcher.addListener(new DebugProcessAdapter() {
1706 public void connectorIsReady() {
1707 connectorIsReady.set(true);
1708 semaphore.up();
1709 myDebugProcessDispatcher.removeListener(this);
1714 this.getManagerThread().schedule(new DebuggerCommandImpl() {
1715 protected void action() {
1716 VirtualMachine vm = null;
1718 try {
1719 final long time = System.currentTimeMillis();
1720 while (System.currentTimeMillis() - time < LOCAL_START_TIMEOUT) {
1721 try {
1722 vm = createVirtualMachineInt();
1723 break;
1725 catch (final ExecutionException e) {
1726 if (pollConnection && !myConnection.isServerMode() && e.getCause() instanceof IOException) {
1727 synchronized (this) {
1728 try {
1729 wait(500);
1731 catch (InterruptedException ie) {
1732 break;
1736 else {
1737 fail();
1738 if (myExecutionResult != null || !connectorIsReady.get()) {
1739 // propagate exception only in case we succeded to obtain execution result,
1740 // otherwise it the error is induced by the fact that there is nothing to debug, and there is no need to show
1741 // this problem to the user
1742 SwingUtilities.invokeLater(new Runnable() {
1743 public void run() {
1744 ProgramRunnerUtil.handleExecutionError(myProject, state.getRunnerSettings().getRunProfile(), e);
1748 break;
1753 finally {
1754 semaphore.up();
1757 if (vm != null) {
1758 final VirtualMachine vm1 = vm;
1759 afterProcessStarted(new Runnable() {
1760 public void run() {
1761 getManagerThread().schedule(new DebuggerCommandImpl() {
1762 protected void action() throws Exception {
1763 commitVM(vm1);
1771 protected void commandCancelled() {
1772 try {
1773 super.commandCancelled();
1775 finally {
1776 semaphore.up();
1781 semaphore.waitFor();
1784 private void afterProcessStarted(final Runnable run) {
1785 class MyProcessAdapter extends ProcessAdapter {
1786 private boolean alreadyRun = false;
1788 public synchronized void run() {
1789 if(!alreadyRun) {
1790 alreadyRun = true;
1791 run.run();
1793 removeProcessListener(this);
1796 public void startNotified(ProcessEvent event) {
1797 run();
1800 MyProcessAdapter processListener = new MyProcessAdapter();
1801 addProcessListener(processListener);
1802 if(myExecutionResult != null) {
1803 if(myExecutionResult.getProcessHandler().isStartNotified()) {
1804 processListener.run();
1809 public boolean isPausePressed() {
1810 return myVirtualMachineProxy != null && myVirtualMachineProxy.isPausePressed();
1813 public DebuggerCommandImpl createPauseCommand() {
1814 return new PauseCommand();
1817 public ResumeCommand createResumeCommand(SuspendContextImpl suspendContext) {
1818 return createResumeCommand(suspendContext, PrioritizedTask.Priority.HIGH);
1821 public ResumeCommand createResumeCommand(SuspendContextImpl suspendContext, final PrioritizedTask.Priority priority) {
1822 final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(getProject()).getBreakpointManager();
1823 return new ResumeCommand(suspendContext) {
1824 public void contextAction() {
1825 breakpointManager.applyThreadFilter(DebugProcessImpl.this, null); // clear the filter on resume
1826 super.contextAction();
1829 public Priority getPriority() {
1830 return priority;
1835 public ResumeCommand createStepOverCommand(SuspendContextImpl suspendContext, boolean ignoreBreakpoints) {
1836 return new StepOverCommand(suspendContext, ignoreBreakpoints);
1839 public ResumeCommand createStepOutCommand(SuspendContextImpl suspendContext) {
1840 return new StepOutCommand(suspendContext);
1843 public ResumeCommand createStepIntoCommand(SuspendContextImpl suspendContext, boolean ignoreFilters, final RequestHint.SmartStepFilter smartStepFilter) {
1844 return new StepIntoCommand(suspendContext, ignoreFilters, smartStepFilter);
1847 public ResumeCommand createRunToCursorCommand(SuspendContextImpl suspendContext, Document document, int lineIndex,
1848 final boolean ignoreBreakpoints)
1849 throws EvaluateException {
1850 RunToCursorCommand runToCursorCommand = new RunToCursorCommand(suspendContext, document, lineIndex, ignoreBreakpoints);
1851 if(runToCursorCommand.myRunToCursorBreakpoint == null) {
1852 final PsiFile psiFile = PsiDocumentManager.getInstance(getProject()).getPsiFile(document);
1853 throw new EvaluateException(DebuggerBundle.message("error.running.to.cursor.no.executable.code", psiFile != null? psiFile.getName() : "<No File>", lineIndex), null);
1855 return runToCursorCommand;
1858 public DebuggerCommandImpl createFreezeThreadCommand(ThreadReferenceProxyImpl thread) {
1859 return new FreezeThreadCommand(thread);
1862 public SuspendContextCommandImpl createResumeThreadCommand(SuspendContextImpl suspendContext, ThreadReferenceProxyImpl thread) {
1863 return new ResumeThreadCommand(suspendContext, thread);
1866 public SuspendContextCommandImpl createPopFrameCommand(DebuggerContextImpl context, StackFrameProxyImpl stackFrame) {
1867 final SuspendContextImpl contextByThread =
1868 SuspendManagerUtil.findContextByThread(context.getDebugProcess().getSuspendManager(), stackFrame.threadProxy());
1869 return new PopFrameCommand(contextByThread, stackFrame);
1872 public void setBreakpointsMuted(final boolean muted) {
1873 if (isAttached()) {
1874 getManagerThread().schedule(new DebuggerCommandImpl() {
1875 protected void action() throws Exception {
1876 // set the flag before enabling/disabling cause it affects if breakpoints will create requests
1877 if (myBreakpointsMuted.getAndSet(muted) != muted) {
1878 final BreakpointManager breakpointManager = DebuggerManagerEx.getInstanceEx(myProject).getBreakpointManager();
1879 if (muted) {
1880 breakpointManager.disableBreakpoints(DebugProcessImpl.this);
1882 else {
1883 breakpointManager.enableBreakpoints(DebugProcessImpl.this);
1889 else {
1890 myBreakpointsMuted.set(muted);
1895 public boolean areBreakpointsMuted() {
1896 return myBreakpointsMuted.get();