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
;
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
;
91 import java
.io
.IOException
;
92 import java
.net
.UnknownHostException
;
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();
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
) {
151 myRequestManager
= new RequestManagerImpl(this);
152 NodeRendererSettings
.getInstance().addListener(mySettingsListener
);
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
);
170 public Pair
<Method
, Value
> getLastExecutedMethod() {
171 if (myReturnValueWatcher
== null) {
174 final Method method
= myReturnValueWatcher
.getLastExecutedMethod();
175 if (method
== 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
;
213 if (renderer
== null) {
214 renderer
= getDefaultRenderer(type
);
216 myNodeRederersMap
.put(type
, 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");
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) {
271 else if ("RECEIVES".compareToIgnoreCase(token
) == 0) {
272 mask
|= VirtualMachine
.TRACE_RECEIVES
;
274 else if ("RAW_RECEIVES".compareToIgnoreCase(token
) == 0) {
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
;
300 if (arguments
== null) {
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
);
311 if(myConnectionService
!= null) {
312 myConnectionService
.close();
316 catch (IOException e
) {
317 if (LOG
.isDebugEnabled()) {
321 catch (IllegalConnectorArgumentsException e
) {
322 if (LOG
.isDebugEnabled()) {
326 catch (ExecutionException e
) {
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
347 * @param hint may be null
349 protected void doStep(final SuspendContextImpl suspendContext
, final ThreadReferenceProxyImpl stepThread
, int depth
, RequestHint hint
) {
350 if (stepThread
== null) {
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
)) {
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
);
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
);
422 private static String
getCurrentClassName(ThreadReferenceProxyImpl thread
) {
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
) {
438 private VirtualMachine
createVirtualMachineInt() throws ExecutionException
{
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();
473 return connector
.accept(myArguments
);
476 if(myArguments
!= null) {
478 connector
.stopListening(myArguments
);
480 catch (IllegalArgumentException e
) {
483 catch (IllegalConnectorArgumentsException e
) {
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
);
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();
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();
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
);
562 myConnectionService
= null;
566 public void showStatusText(final String text
) {
567 myStatusUpdateAlarm
.cancelAllRequests();
568 myStatusUpdateAlarm
.addRequest(new Runnable() {
570 final WindowManager wm
= WindowManager
.getInstance();
572 wm
.getStatusBar(myProject
).setInfo(text
);
578 static Connector
findConnector(String connectorName
) throws ExecutionException
{
579 VirtualMachineManager virtualMachineManager
= null;
581 virtualMachineManager
= Bootstrap
.virtualMachineManager();
584 final String error
= e
.getClass().getName() + " : " + e
.getLocalizedMessage();
585 throw new ExecutionException(DebuggerBundle
.message("debugger.jdi.bootstrap.error", error
));
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();
597 for (Iterator it
= connectors
.iterator(); it
.hasNext();) {
598 Connector connector
= (Connector
)it
.next();
599 if (connectorName
.equals(connector
.name())) {
606 private void checkVirtualMachineVersion(VirtualMachine vm
) {
607 final String version
= vm
.version();
608 if ("1.4.0".equals(version
)) {
609 SwingUtilities
.invokeLater(new Runnable() {
611 Messages
.showMessageDialog(
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
);
643 myProcessListeners
.add(processListener
);
648 public void removeProcessListener(ProcessListener processListener
) {
649 synchronized (myProcessListeners
) {
650 if(getExecutionResult() != null) {
651 getExecutionResult().getProcessHandler().removeProcessListener(processListener
);
654 myProcessListeners
.remove(processListener
);
660 public RemoteConnection
getConnection() {
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() {
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;
745 getManagerThread().close();
748 myState
.set(STATE_DETACHED
);
750 myDebugProcessDispatcher
.getMulticaster().processDetached(this, closedByUser
);
753 setBreakpointsMuted(false);
761 private static String
formatMessage(String message
) {
762 final int lineLength
= 90;
763 StringBuffer buf
= new StringBuffer(message
.length());
765 while (index
< message
.length()) {
766 buf
.append(message
.substring(index
, Math
.min(index
+ lineLength
, message
.length()))).append('\n');
769 return buf
.toString();
772 public static String
processError(Exception e
) {
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()) {
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();
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) {
805 buf
.append(localizedMessage
);
808 if (LOG
.isDebugEnabled()) {
811 message
= buf
.toString();
814 StringBuilderSpinAllocator
.dispose(buf
);
817 else if (e
instanceof ExecutionException
) {
818 message
= e
.getLocalizedMessage();
821 message
= DebuggerBundle
.message("error.exception.while.connecting", e
.getClass().getName(), e
.getLocalizedMessage());
822 if (LOG
.isDebugEnabled()) {
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());
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
);
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;
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();
918 return invokeMethodAndFork(suspendContext
);
920 catch (ClassNotLoadedException e
) {
921 ReferenceType loadedClass
= evaluationContext
.isAutoLoadClasses()?
loadClass(evaluationContext
, e
.className(), evaluationContext
.getClassLoader()) : null;
922 if (loadedClass
== null) {
923 throw EvaluateExceptionUtil
.createEvaluateException(e
);
928 catch (ClassNotLoadedException e
) {
929 throw EvaluateExceptionUtil
.createEvaluateException(e
);
931 catch (InvocationException e
) {
932 throw EvaluateExceptionUtil
.createEvaluateException(e
);
934 catch (IncompatibleThreadStateException e
) {
935 throw EvaluateExceptionUtil
.createEvaluateException(e
);
937 catch (InvalidTypeException e
) {
938 throw EvaluateExceptionUtil
.createEvaluateException(e
);
940 catch (ObjectCollectedException e
) {
941 throw EvaluateExceptionUtil
.createEvaluateException(e
);
943 catch (UnsupportedOperationException e
) {
944 throw EvaluateExceptionUtil
.createEvaluateException(e
);
946 catch (InternalException e
) {
947 throw EvaluateExceptionUtil
.createEvaluateException(e
);
950 suspendContext
.setIsEvaluating(null);
951 if (resumeData
!= null) {
952 SuspendManagerUtil
.restoreAfterResume(suspendContext
, resumeData
);
954 for (SuspendContextImpl suspendingContext
: mySuspendManager
.getEventContexts()) {
955 if (suspendingContexts
.contains(suspendingContext
) && !suspendingContext
.isEvaluating() && !suspendingContext
.suspends(invokeThread
)) {
956 mySuspendManager
.suspendThread(suspendingContext
, invokeThread
);
960 if (LOG
.isDebugEnabled()) {
961 LOG
.debug("getVirtualMachine().clearCaches()");
963 getVirtualMachineProxy().clearCaches();
964 afterMethodInvocation(suspendContext
);
966 myEvaluationDispatcher
.getMulticaster().evaluationFinished(suspendContext
);
970 private E
invokeMethodAndFork(final SuspendContextImpl context
) throws InvocationException
,
971 ClassNotLoadedException
,
972 IncompatibleThreadStateException
,
973 InvalidTypeException
{
974 final int invokePolicy
= getInvokePolicy(context
);
975 final Exception
[] exception
= new Exception
[1];
976 final Value
[] result
= new Value
[1];
977 getManagerThread().startLongProcessAndFork(new Runnable() {
979 ThreadReferenceProxyImpl thread
= context
.getThread();
982 if (LOG
.isDebugEnabled()) {
983 final VirtualMachineProxyImpl virtualMachineProxy
= getVirtualMachineProxy();
984 virtualMachineProxy
.logThreads();
985 LOG
.debug("Invoke in " + thread
.name());
986 assertThreadSuspended(thread
, context
);
988 if (!Patches
.IBM_JDK_DISABLE_COLLECTION_BUG
) {
989 // ensure args are not collected
990 for (Object arg
: myArgs
) {
991 if (arg
instanceof ObjectReference
) {
992 ((ObjectReference
)arg
).disableCollection();
996 result
[0] = invokeMethod(invokePolicy
, myArgs
);
999 // assertThreadSuspended(thread, context);
1000 if (!Patches
.IBM_JDK_DISABLE_COLLECTION_BUG
) {
1001 // ensure args are not collected
1002 for (Object arg
: myArgs
) {
1003 if (arg
instanceof ObjectReference
) {
1004 ((ObjectReference
)arg
).enableCollection();
1010 catch (Exception e
) {
1016 if (exception
[0] != null) {
1017 if (exception
[0] instanceof InvocationException
) {
1018 throw (InvocationException
)exception
[0];
1020 else if (exception
[0] instanceof ClassNotLoadedException
) {
1021 throw (ClassNotLoadedException
)exception
[0];
1023 else if (exception
[0] instanceof IncompatibleThreadStateException
) {
1024 throw (IncompatibleThreadStateException
)exception
[0];
1026 else if (exception
[0] instanceof InvalidTypeException
) {
1027 throw (InvalidTypeException
)exception
[0];
1029 else if (exception
[0] instanceof RuntimeException
) {
1030 throw (RuntimeException
)exception
[0];
1033 LOG
.assertTrue(false);
1037 return (E
)result
[0];
1040 private void assertThreadSuspended(final ThreadReferenceProxyImpl thread
, final SuspendContextImpl context
) {
1041 LOG
.assertTrue(context
.isEvaluating());
1043 final boolean isSuspended
= thread
.isSuspended();
1044 LOG
.assertTrue(isSuspended
, thread
);
1046 catch (ObjectCollectedException ignored
) {
1051 public Value
invokeMethod(final EvaluationContext evaluationContext
, final ObjectReference objRef
, final Method method
, final List args
) throws EvaluateException
{
1052 return invokeInstanceMethod(evaluationContext
, objRef
, method
, args
, 0);
1055 public Value
invokeInstanceMethod(final EvaluationContext evaluationContext
, final ObjectReference objRef
, final Method method
,
1056 final List args
, final int invocationOptions
) throws EvaluateException
{
1057 final ThreadReference thread
= getEvaluationThread(evaluationContext
);
1058 InvokeCommand
<Value
> invokeCommand
= new InvokeCommand
<Value
>(args
) {
1059 protected Value
invokeMethod(int invokePolicy
, final List args
) throws InvocationException
, ClassNotLoadedException
, IncompatibleThreadStateException
, InvalidTypeException
{
1060 if (LOG
.isDebugEnabled()) {
1061 LOG
.debug("Invoke " + method
.name());
1064 // if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
1065 // // ensure target object wil not be collected
1066 // objRef.disableCollection();
1068 return objRef
.invokeMethod(thread
, method
, args
, invokePolicy
| invocationOptions
);
1071 // if (!Patches.IBM_JDK_DISABLE_COLLECTION_BUG) {
1072 // objRef.enableCollection();
1077 return invokeCommand
.start((EvaluationContextImpl
)evaluationContext
, method
);
1080 private static ThreadReference
getEvaluationThread(final EvaluationContext evaluationContext
) throws EvaluateException
{
1081 ThreadReferenceProxy evaluationThread
= evaluationContext
.getSuspendContext().getThread();
1082 if(evaluationThread
== null) {
1083 throw EvaluateExceptionUtil
.NULL_STACK_FRAME
;
1085 return evaluationThread
.getThreadReference();
1088 public Value
invokeMethod(final EvaluationContext evaluationContext
, final ClassType classType
,
1089 final Method method
,
1090 final List args
) throws EvaluateException
{
1092 final ThreadReference thread
= getEvaluationThread(evaluationContext
);
1093 InvokeCommand
<Value
> invokeCommand
= new InvokeCommand
<Value
>(args
) {
1094 protected Value
invokeMethod(int invokePolicy
, final List args
) throws InvocationException
,
1095 ClassNotLoadedException
,
1096 IncompatibleThreadStateException
,
1097 InvalidTypeException
{
1098 if (LOG
.isDebugEnabled()) {
1099 LOG
.debug("Invoke " + method
.name());
1101 return classType
.invokeMethod(thread
, method
, args
, invokePolicy
);
1104 return invokeCommand
.start((EvaluationContextImpl
)evaluationContext
, method
);
1107 public ArrayReference
newInstance(final ArrayType arrayType
,
1108 final int dimension
)
1109 throws EvaluateException
{
1110 return arrayType
.newInstance(dimension
);
1113 public ObjectReference
newInstance(final EvaluationContext evaluationContext
, final ClassType classType
,
1114 final Method method
,
1115 final List args
) throws EvaluateException
{
1116 final ThreadReference thread
= getEvaluationThread(evaluationContext
);
1117 InvokeCommand
<ObjectReference
> invokeCommand
= new InvokeCommand
<ObjectReference
>(args
) {
1118 protected ObjectReference
invokeMethod(int invokePolicy
, final List args
) throws InvocationException
,
1119 ClassNotLoadedException
,
1120 IncompatibleThreadStateException
,
1121 InvalidTypeException
{
1122 if (LOG
.isDebugEnabled()) {
1123 LOG
.debug("New instance " + method
.name());
1125 return classType
.newInstance(thread
, method
, args
, invokePolicy
);
1128 return invokeCommand
.start((EvaluationContextImpl
)evaluationContext
, method
);
1131 public void clearCashes(int suspendPolicy
) {
1132 if (!isAttached()) return;
1133 switch (suspendPolicy
) {
1134 case EventRequest
.SUSPEND_ALL
:
1135 getVirtualMachineProxy().clearCaches();
1137 case EventRequest
.SUSPEND_EVENT_THREAD
:
1138 getVirtualMachineProxy().clearCaches();
1139 //suspendContext.getThread().clearAll();
1144 protected void beforeSuspend(SuspendContextImpl suspendContext
) {
1145 clearCashes(suspendContext
.getSuspendPolicy());
1148 private void beforeMethodInvocation(SuspendContextImpl suspendContext
, Method method
) {
1149 if (LOG
.isDebugEnabled()) {
1151 "before invocation in thread " + suspendContext
.getThread().name() + " method " + (method
== null ?
"null" : method
.name()));
1154 if (method
!= null) {
1155 showStatusText(DebuggerBundle
.message("progress.evaluating", DebuggerUtilsEx
.methodName(method
)));
1158 showStatusText(DebuggerBundle
.message("title.evaluating"));
1162 private void afterMethodInvocation(SuspendContextImpl suspendContext
) {
1163 if (LOG
.isDebugEnabled()) {
1164 LOG
.debug("after invocation in thread " + suspendContext
.getThread().name());
1169 public ReferenceType
findClass(EvaluationContext evaluationContext
, String className
,
1170 ClassLoaderReference classLoader
) throws EvaluateException
{
1172 DebuggerManagerThreadImpl
.assertIsManagerThread();
1173 ReferenceType result
= null;
1174 final VirtualMachineProxyImpl vmProxy
= getVirtualMachineProxy();
1175 if (vmProxy
== null) {
1176 throw new VMDisconnectedException();
1178 for (final ReferenceType refType
: vmProxy
.classesByName(className
)) {
1179 if (refType
.isPrepared() && isVisibleFromClassLoader(classLoader
, refType
)) {
1184 final EvaluationContextImpl evalContext
= (EvaluationContextImpl
)evaluationContext
;
1185 if (result
== null && evalContext
.isAutoLoadClasses()) {
1186 return loadClass(evalContext
, className
, classLoader
);
1190 catch (InvocationException e
) {
1191 throw EvaluateExceptionUtil
.createEvaluateException(e
);
1193 catch (ClassNotLoadedException e
) {
1194 throw EvaluateExceptionUtil
.createEvaluateException(e
);
1196 catch (IncompatibleThreadStateException e
) {
1197 throw EvaluateExceptionUtil
.createEvaluateException(e
);
1199 catch (InvalidTypeException e
) {
1200 throw EvaluateExceptionUtil
.createEvaluateException(e
);
1204 private static boolean isVisibleFromClassLoader(final ClassLoaderReference fromLoader
, final ReferenceType refType
) {
1205 final ClassLoaderReference typeLoader
= refType
.classLoader();
1206 if (typeLoader
== null) {
1207 return true; // optimization: if class is loaded by a bootstrap loader, it is visible from every other loader
1209 for (ClassLoaderReference checkLoader
= fromLoader
; checkLoader
!= null; checkLoader
= getParentLoader(checkLoader
)) {
1210 if (Comparing
.equal(typeLoader
, checkLoader
)) {
1214 return fromLoader
!= null? fromLoader
.visibleClasses().contains(refType
) : false;
1217 @SuppressWarnings({"HardCodedStringLiteral"})
1218 private static ClassLoaderReference
getParentLoader(final ClassLoaderReference fromLoader
) {
1219 final ReferenceType refType
= fromLoader
.referenceType();
1220 Field field
= refType
.fieldByName("parent");
1221 if (field
== null) {
1222 final List allFields
= refType
.allFields();
1223 for (Iterator it
= allFields
.iterator(); it
.hasNext();) {
1224 final Field candidateField
= (Field
)it
.next();
1226 final Type checkedType
= candidateField
.type();
1227 if (checkedType
instanceof ReferenceType
&& DebuggerUtilsEx
.isAssignableFrom("java.lang.ClassLoader", (ReferenceType
)checkedType
)) {
1228 field
= candidateField
;
1232 catch (ClassNotLoadedException e
) {
1233 // ignore this and continue,
1234 // 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
1238 return field
!= null?
(ClassLoaderReference
)fromLoader
.getValue(field
) : null;
1241 private String
reformatArrayName(String className
) {
1242 if (className
.indexOf('[') == -1) return className
;
1245 while (className
.endsWith("[]")) {
1246 className
= className
.substring(0, className
.length() - 2);
1250 StringBuilder buffer
= StringBuilderSpinAllocator
.alloc();
1252 for (int i
= 0; i
< dims
; i
++) {
1255 String primitiveSignature
= JVMNameUtil
.getPrimitiveSignature(className
);
1256 if(primitiveSignature
!= null) {
1257 buffer
.append(primitiveSignature
);
1261 buffer
.append(className
);
1264 return buffer
.toString();
1267 StringBuilderSpinAllocator
.dispose(buffer
);
1271 @SuppressWarnings({"HardCodedStringLiteral"})
1272 public ReferenceType
loadClass(EvaluationContextImpl evaluationContext
, String qName
, ClassLoaderReference classLoader
)
1273 throws InvocationException
, ClassNotLoadedException
, IncompatibleThreadStateException
, InvalidTypeException
, EvaluateException
{
1275 DebuggerManagerThreadImpl
.assertIsManagerThread();
1276 qName
= reformatArrayName(qName
);
1277 ReferenceType refType
= null;
1278 VirtualMachineProxyImpl virtualMachine
= getVirtualMachineProxy();
1279 final List classClasses
= virtualMachine
.classesByName("java.lang.Class");
1280 if (classClasses
.size() > 0) {
1281 ClassType classClassType
= (ClassType
)classClasses
.get(0);
1282 final Method forNameMethod
;
1283 if (classLoader
!= null) {
1284 //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
1285 forNameMethod
= DebuggerUtils
.findMethod(classClassType
, "forName", "(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;");
1288 //forNameMethod = classClassType.concreteMethodByName("forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1289 forNameMethod
= DebuggerUtils
.findMethod(classClassType
, "forName", "(Ljava/lang/String;)Ljava/lang/Class;");
1291 final List
<Mirror
> args
= new ArrayList
<Mirror
>(); // do not use unmodifiable lists because the list is modified by JPDA
1292 final StringReference qNameMirror
= virtualMachine
.mirrorOf(qName
);
1293 args
.add(qNameMirror
);
1294 if (classLoader
!= null) {
1295 args
.add(virtualMachine
.mirrorOf(true));
1296 args
.add(classLoader
);
1298 final Value value
= invokeMethod(evaluationContext
, classClassType
, forNameMethod
, args
);
1299 if (value
instanceof ClassObjectReference
) {
1300 refType
= ((ClassObjectReference
)value
).reflectedType();
1306 public void logThreads() {
1307 if (LOG
.isDebugEnabled()) {
1309 Collection
<ThreadReferenceProxyImpl
> allThreads
= getVirtualMachineProxy().allThreads();
1310 for (ThreadReferenceProxyImpl threadReferenceProxy
: allThreads
) {
1311 LOG
.debug("Thread name=" + threadReferenceProxy
.name() + " suspendCount()=" + threadReferenceProxy
.getSuspendCount());
1314 catch (Exception e
) {
1320 public SuspendManager
getSuspendManager() {
1321 return mySuspendManager
;
1324 public CompoundPositionManager
getPositionManager() {
1325 return myPositionManager
;
1329 public void stop(boolean forceTerminate
) {
1330 this.getManagerThread().terminateAndInvoke(createStopCommand(forceTerminate
), DebuggerManagerThreadImpl
.COMMAND_TIMEOUT
);
1333 public StopCommand
createStopCommand(boolean forceTerminate
) {
1334 return new StopCommand(forceTerminate
);
1337 protected class StopCommand
extends DebuggerCommandImpl
{
1338 private final boolean myIsTerminateTargetVM
;
1340 public StopCommand(boolean isTerminateTargetVM
) {
1341 myIsTerminateTargetVM
= isTerminateTargetVM
;
1344 public Priority
getPriority() {
1345 return Priority
.HIGH
;
1348 protected void action() throws Exception
{
1350 final VirtualMachineProxyImpl virtualMachineProxy
= getVirtualMachineProxy();
1351 if (myIsTerminateTargetVM
) {
1352 virtualMachineProxy
.exit(-1);
1355 // some VM's (like IBM VM 1.4.2 bundled with WebSpere) does not
1356 // resume threads on dispose() like it should
1357 virtualMachineProxy
.resume();
1358 virtualMachineProxy
.dispose();
1367 private class StepOutCommand
extends ResumeCommand
{
1368 public StepOutCommand(SuspendContextImpl suspendContext
) {
1369 super(suspendContext
);
1372 public void contextAction() {
1373 showStatusText(DebuggerBundle
.message("status.step.out"));
1374 final SuspendContextImpl suspendContext
= getSuspendContext();
1375 final ThreadReferenceProxyImpl thread
= suspendContext
.getThread();
1376 RequestHint hint
= new RequestHint(thread
, suspendContext
, StepRequest
.STEP_OUT
);
1377 hint
.setIgnoreFilters(mySession
.shouldIgnoreSteppingFilters());
1378 if (myReturnValueWatcher
!= null) {
1379 myReturnValueWatcher
.setTrackingEnabled(true);
1381 doStep(suspendContext
, thread
, StepRequest
.STEP_OUT
, hint
);
1382 super.contextAction();
1386 private class StepIntoCommand
extends ResumeCommand
{
1387 private final boolean myForcedIgnoreFilters
;
1388 private final RequestHint
.SmartStepFilter mySmartStepFilter
;
1390 public StepIntoCommand(SuspendContextImpl suspendContext
, boolean ignoreFilters
, final @Nullable RequestHint
.SmartStepFilter smartStepFilter
) {
1391 super(suspendContext
);
1392 myForcedIgnoreFilters
= ignoreFilters
|| smartStepFilter
!= null;
1393 mySmartStepFilter
= smartStepFilter
;
1396 public void contextAction() {
1397 showStatusText(DebuggerBundle
.message("status.step.into"));
1398 final SuspendContextImpl suspendContext
= getSuspendContext();
1399 final ThreadReferenceProxyImpl stepThread
= suspendContext
.getThread();
1400 final RequestHint hint
= mySmartStepFilter
!= null?
1401 new RequestHint(stepThread
, suspendContext
, mySmartStepFilter
) :
1402 new RequestHint(stepThread
, suspendContext
, StepRequest
.STEP_INTO
);
1403 if (myForcedIgnoreFilters
) {
1405 mySession
.setIgnoreStepFiltersFlag(stepThread
.frameCount());
1407 catch (EvaluateException e
) {
1411 hint
.setIgnoreFilters(myForcedIgnoreFilters
|| mySession
.shouldIgnoreSteppingFilters());
1412 doStep(suspendContext
, stepThread
, StepRequest
.STEP_INTO
, hint
);
1413 super.contextAction();
1417 private class StepOverCommand
extends ResumeCommand
{
1418 private final boolean myIsIgnoreBreakpoints
;
1420 public StepOverCommand(SuspendContextImpl suspendContext
, boolean ignoreBreakpoints
) {
1421 super(suspendContext
);
1422 myIsIgnoreBreakpoints
= ignoreBreakpoints
;
1425 public void contextAction() {
1426 showStatusText(DebuggerBundle
.message("status.step.over"));
1427 final SuspendContextImpl suspendContext
= getSuspendContext();
1428 final ThreadReferenceProxyImpl steppingThread
= suspendContext
.getThread();
1429 // need this hint whil stepping over for JSR45 support:
1430 // several lines of generated java code may correspond to a single line in the source file,
1431 // from which the java code was generated
1432 RequestHint hint
= new RequestHint(steppingThread
, suspendContext
, StepRequest
.STEP_OVER
);
1433 hint
.setRestoreBreakpoints(myIsIgnoreBreakpoints
);
1434 hint
.setIgnoreFilters(myIsIgnoreBreakpoints
|| mySession
.shouldIgnoreSteppingFilters());
1436 if (myReturnValueWatcher
!= null) {
1437 myReturnValueWatcher
.setTrackingEnabled(true);
1439 doStep(suspendContext
, steppingThread
, StepRequest
.STEP_OVER
, hint
);
1441 if (myIsIgnoreBreakpoints
) {
1442 DebuggerManagerEx
.getInstanceEx(myProject
).getBreakpointManager().disableBreakpoints(DebugProcessImpl
.this);
1444 super.contextAction();
1448 private class RunToCursorCommand
extends ResumeCommand
{
1449 private final RunToCursorBreakpoint myRunToCursorBreakpoint
;
1450 private final boolean myIgnoreBreakpoints
;
1452 private RunToCursorCommand(SuspendContextImpl suspendContext
, Document document
, int lineIndex
, final boolean ignoreBreakpoints
) {
1453 super(suspendContext
);
1454 myIgnoreBreakpoints
= ignoreBreakpoints
;
1455 final BreakpointManager breakpointManager
= DebuggerManagerEx
.getInstanceEx(myProject
).getBreakpointManager();
1456 myRunToCursorBreakpoint
= breakpointManager
.addRunToCursorBreakpoint(document
, lineIndex
, ignoreBreakpoints
);
1459 public void contextAction() {
1460 showStatusText(DebuggerBundle
.message("status.run.to.cursor"));
1461 cancelRunToCursorBreakpoint();
1462 if (myRunToCursorBreakpoint
== null) {
1465 if (myIgnoreBreakpoints
) {
1466 final BreakpointManager breakpointManager
= DebuggerManagerEx
.getInstanceEx(myProject
).getBreakpointManager();
1467 breakpointManager
.disableBreakpoints(DebugProcessImpl
.this);
1469 myRunToCursorBreakpoint
.SUSPEND_POLICY
= DebuggerSettings
.SUSPEND_ALL
;
1470 myRunToCursorBreakpoint
.LOG_ENABLED
= false;
1471 myRunToCursorBreakpoint
.createRequest(getSuspendContext().getDebugProcess());
1472 DebugProcessImpl
.this.myRunToCursorBreakpoint
= myRunToCursorBreakpoint
;
1473 super.contextAction();
1477 public abstract class ResumeCommand
extends SuspendContextCommandImpl
{
1479 public ResumeCommand(SuspendContextImpl suspendContext
) {
1480 super(suspendContext
);
1483 public Priority
getPriority() {
1484 return Priority
.HIGH
;
1487 public void contextAction() {
1488 showStatusText(DebuggerBundle
.message("status.process.resumed"));
1489 getSuspendManager().resume(getSuspendContext());
1490 myDebugProcessDispatcher
.getMulticaster().resumed(getSuspendContext());
1494 private class PauseCommand
extends DebuggerCommandImpl
{
1495 public PauseCommand() {
1498 public void action() {
1499 if (!isAttached() || getVirtualMachineProxy().isPausePressed()) {
1503 getVirtualMachineProxy().suspend();
1505 SuspendContextImpl suspendContext
= mySuspendManager
.pushSuspendContext(EventRequest
.SUSPEND_ALL
, 0);
1506 myDebugProcessDispatcher
.getMulticaster().paused(suspendContext
);
1510 private class ResumeThreadCommand
extends SuspendContextCommandImpl
{
1511 private final ThreadReferenceProxyImpl myThread
;
1513 public ResumeThreadCommand(SuspendContextImpl suspendContext
, ThreadReferenceProxyImpl thread
) {
1514 super(suspendContext
);
1518 public void contextAction() {
1519 if (getSuspendManager().isFrozen(myThread
)) {
1520 getSuspendManager().unfreezeThread(myThread
);
1524 final Set
<SuspendContextImpl
> suspendingContexts
= SuspendManagerUtil
.getSuspendingContexts(getSuspendManager(), myThread
);
1525 for (Iterator
<SuspendContextImpl
> iterator
= suspendingContexts
.iterator(); iterator
.hasNext();) {
1526 SuspendContextImpl suspendContext
= iterator
.next();
1527 if (suspendContext
.getThread() == myThread
) {
1528 DebugProcessImpl
.this.getManagerThread().invoke(createResumeCommand(suspendContext
));
1531 getSuspendManager().resumeThread(suspendContext
, myThread
);
1537 private class FreezeThreadCommand
extends DebuggerCommandImpl
{
1538 private final ThreadReferenceProxyImpl myThread
;
1540 public FreezeThreadCommand(ThreadReferenceProxyImpl thread
) {
1544 protected void action() throws Exception
{
1545 SuspendManager suspendManager
= getSuspendManager();
1546 if (!suspendManager
.isFrozen(myThread
)) {
1547 suspendManager
.freezeThread(myThread
);
1552 private class PopFrameCommand
extends SuspendContextCommandImpl
{
1553 private final StackFrameProxyImpl myStackFrame
;
1555 public PopFrameCommand(SuspendContextImpl context
, StackFrameProxyImpl frameProxy
) {
1557 myStackFrame
= frameProxy
;
1560 public void contextAction() {
1561 final ThreadReferenceProxyImpl thread
= myStackFrame
.threadProxy();
1563 if (!getSuspendManager().isSuspended(thread
)) {
1568 catch (ObjectCollectedException e
) {
1573 final SuspendContextImpl suspendContext
= getSuspendContext();
1574 if (!suspendContext
.suspends(thread
)) {
1575 suspendContext
.postponeCommand(this);
1579 if (myStackFrame
.isBottom()) {
1580 DebuggerInvocationUtil
.swingInvokeLater(myProject
, new Runnable() {
1582 Messages
.showMessageDialog(myProject
, DebuggerBundle
.message("error.pop.bottom.stackframe"), ActionsBundle
.actionText(DebuggerActions
.POP_FRAME
), Messages
.getErrorIcon());
1589 thread
.popFrames(myStackFrame
);
1591 catch (final EvaluateException e
) {
1592 DebuggerInvocationUtil
.swingInvokeLater(myProject
, new Runnable() {
1594 Messages
.showMessageDialog(myProject
, DebuggerBundle
.message("error.pop.stackframe", e
.getLocalizedMessage()), ActionsBundle
.actionText(DebuggerActions
.POP_FRAME
), Messages
.getErrorIcon());
1600 getSuspendManager().popFrame(suspendContext
);
1606 public GlobalSearchScope
getSearchScope() {
1607 LOG
.assertTrue(mySession
!= null, "Accessing debug session before its initialization");
1608 return mySession
.getSearchScope();
1611 public @Nullable ExecutionResult
attachVirtualMachine(final Executor executor
,
1612 final ProgramRunner runner
,
1613 final DebuggerSession session
,
1614 final RunProfileState state
,
1615 final RemoteConnection remoteConnection
,
1616 boolean pollConnection
) throws ExecutionException
{
1617 mySession
= session
;
1620 ApplicationManager
.getApplication().assertIsDispatchThread();
1621 LOG
.assertTrue(isInInitialState());
1623 myConnection
= remoteConnection
;
1625 createVirtualMachine(state
, pollConnection
);
1628 synchronized (myProcessListeners
) {
1629 if (state
instanceof CommandLineState
) {
1630 final TextConsoleBuilder consoleBuilder
= ((CommandLineState
)state
).getConsoleBuilder();
1631 if (consoleBuilder
!= null) {
1632 consoleBuilder
.addFilter(new ExceptionFilter(session
.getSearchScope()));
1635 myExecutionResult
= state
.execute(executor
, runner
);
1636 if (myExecutionResult
== null) {
1640 for (ProcessListener processListener
: myProcessListeners
) {
1641 myExecutionResult
.getProcessHandler().addProcessListener(processListener
);
1643 myProcessListeners
.clear();
1646 catch (ExecutionException e
) {
1651 if (ApplicationManager
.getApplication().isUnitTestMode()) {
1652 return myExecutionResult
;
1656 final Alarm debugPortTimeout = new Alarm(Alarm.ThreadToUse.SHARED_THREAD);
1658 myExecutionResult.getProcessHandler().addProcessListener(new ProcessAdapter() {
1659 public void processTerminated(ProcessEvent event) {
1660 debugPortTimeout.cancelAllRequests();
1663 public void startNotified(ProcessEvent event) {
1664 debugPortTimeout.addRequest(new Runnable() {
1666 if(isInInitialState()) {
1667 ApplicationManager.getApplication().schedule(new Runnable() {
1669 String message = DebuggerBundle.message("status.connect.failed", DebuggerBundle.getAddressDisplayName(remoteConnection), DebuggerBundle.getTransportName(remoteConnection));
1670 Messages.showErrorDialog(myProject, message, DebuggerBundle.message("title.generic.debug.dialog"));
1675 }, LOCAL_START_TIMEOUT);
1680 return myExecutionResult
;
1683 private void fail() {
1684 synchronized (this) {
1686 // need this in order to prevent calling stop() twice
1694 private void createVirtualMachine(final RunProfileState state
, final boolean pollConnection
) {
1695 final Semaphore semaphore
= new Semaphore();
1698 final Ref
<Boolean
> connectorIsReady
= Ref
.create(false);
1699 myDebugProcessDispatcher
.addListener(new DebugProcessAdapter() {
1700 public void connectorIsReady() {
1701 connectorIsReady
.set(true);
1703 myDebugProcessDispatcher
.removeListener(this);
1708 this.getManagerThread().schedule(new DebuggerCommandImpl() {
1709 protected void action() {
1710 VirtualMachine vm
= null;
1713 final long time
= System
.currentTimeMillis();
1714 while (System
.currentTimeMillis() - time
< LOCAL_START_TIMEOUT
) {
1716 vm
= createVirtualMachineInt();
1719 catch (final ExecutionException e
) {
1720 if (pollConnection
&& !myConnection
.isServerMode() && e
.getCause() instanceof IOException
) {
1721 synchronized (this) {
1725 catch (InterruptedException ie
) {
1732 if (myExecutionResult
!= null || !connectorIsReady
.get()) {
1733 // propagate exception only in case we succeded to obtain execution result,
1734 // otherwise it the error is induced by the fact that there is nothing to debug, and there is no need to show
1735 // this problem to the user
1736 SwingUtilities
.invokeLater(new Runnable() {
1738 ProgramRunnerUtil
.handleExecutionError(myProject
, state
.getRunnerSettings().getRunProfile(), e
);
1752 final VirtualMachine vm1
= vm
;
1753 afterProcessStarted(new Runnable() {
1755 getManagerThread().schedule(new DebuggerCommandImpl() {
1756 protected void action() throws Exception
{
1765 protected void commandCancelled() {
1767 super.commandCancelled();
1775 semaphore
.waitFor();
1778 private void afterProcessStarted(final Runnable run
) {
1779 class MyProcessAdapter
extends ProcessAdapter
{
1780 private boolean alreadyRun
= false;
1782 public synchronized void run() {
1787 removeProcessListener(this);
1790 public void startNotified(ProcessEvent event
) {
1794 MyProcessAdapter processListener
= new MyProcessAdapter();
1795 addProcessListener(processListener
);
1796 if(myExecutionResult
!= null) {
1797 if(myExecutionResult
.getProcessHandler().isStartNotified()) {
1798 processListener
.run();
1803 public boolean isPausePressed() {
1804 return myVirtualMachineProxy
!= null && myVirtualMachineProxy
.isPausePressed();
1807 public DebuggerCommandImpl
createPauseCommand() {
1808 return new PauseCommand();
1811 public ResumeCommand
createResumeCommand(SuspendContextImpl suspendContext
) {
1812 return createResumeCommand(suspendContext
, PrioritizedTask
.Priority
.HIGH
);
1815 public ResumeCommand
createResumeCommand(SuspendContextImpl suspendContext
, final PrioritizedTask
.Priority priority
) {
1816 final BreakpointManager breakpointManager
= DebuggerManagerEx
.getInstanceEx(getProject()).getBreakpointManager();
1817 return new ResumeCommand(suspendContext
) {
1818 public void contextAction() {
1819 breakpointManager
.applyThreadFilter(DebugProcessImpl
.this, null); // clear the filter on resume
1820 super.contextAction();
1823 public Priority
getPriority() {
1829 public ResumeCommand
createStepOverCommand(SuspendContextImpl suspendContext
, boolean ignoreBreakpoints
) {
1830 return new StepOverCommand(suspendContext
, ignoreBreakpoints
);
1833 public ResumeCommand
createStepOutCommand(SuspendContextImpl suspendContext
) {
1834 return new StepOutCommand(suspendContext
);
1837 public ResumeCommand
createStepIntoCommand(SuspendContextImpl suspendContext
, boolean ignoreFilters
, final RequestHint
.SmartStepFilter smartStepFilter
) {
1838 return new StepIntoCommand(suspendContext
, ignoreFilters
, smartStepFilter
);
1841 public ResumeCommand
createRunToCursorCommand(SuspendContextImpl suspendContext
, Document document
, int lineIndex
,
1842 final boolean ignoreBreakpoints
)
1843 throws EvaluateException
{
1844 RunToCursorCommand runToCursorCommand
= new RunToCursorCommand(suspendContext
, document
, lineIndex
, ignoreBreakpoints
);
1845 if(runToCursorCommand
.myRunToCursorBreakpoint
== null) {
1846 final PsiFile psiFile
= PsiDocumentManager
.getInstance(getProject()).getPsiFile(document
);
1847 throw new EvaluateException(DebuggerBundle
.message("error.running.to.cursor.no.executable.code", psiFile
!= null? psiFile
.getName() : "<No File>", lineIndex
), null);
1849 return runToCursorCommand
;
1852 public DebuggerCommandImpl
createFreezeThreadCommand(ThreadReferenceProxyImpl thread
) {
1853 return new FreezeThreadCommand(thread
);
1856 public SuspendContextCommandImpl
createResumeThreadCommand(SuspendContextImpl suspendContext
, ThreadReferenceProxyImpl thread
) {
1857 return new ResumeThreadCommand(suspendContext
, thread
);
1860 public SuspendContextCommandImpl
createPopFrameCommand(DebuggerContextImpl context
, StackFrameProxyImpl stackFrame
) {
1861 final SuspendContextImpl contextByThread
=
1862 SuspendManagerUtil
.findContextByThread(context
.getDebugProcess().getSuspendManager(), stackFrame
.threadProxy());
1863 return new PopFrameCommand(contextByThread
, stackFrame
);
1866 public void setBreakpointsMuted(final boolean muted
) {
1868 getManagerThread().schedule(new DebuggerCommandImpl() {
1869 protected void action() throws Exception
{
1870 // set the flag before enabling/disabling cause it affects if breakpoints will create requests
1871 if (myBreakpointsMuted
.getAndSet(muted
) != muted
) {
1872 final BreakpointManager breakpointManager
= DebuggerManagerEx
.getInstanceEx(myProject
).getBreakpointManager();
1874 breakpointManager
.disableBreakpoints(DebugProcessImpl
.this);
1877 breakpointManager
.enableBreakpoints(DebugProcessImpl
.this);
1884 myBreakpointsMuted
.set(muted
);
1889 public boolean areBreakpointsMuted() {
1890 return myBreakpointsMuted
.get();