2 * Copyright 2000-2015 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.
18 * @author Eugene Zhuravlev
20 package com.intellij.debugger.jdi;
22 import com.intellij.debugger.DebuggerBundle;
23 import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
24 import com.intellij.debugger.engine.evaluation.EvaluateException;
25 import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
26 import com.intellij.debugger.engine.jdi.ThreadReferenceProxy;
27 import com.intellij.openapi.diagnostic.Logger;
28 import com.intellij.openapi.util.Comparing;
30 import org.jetbrains.annotations.NonNls;
31 import org.jetbrains.annotations.NotNull;
35 public final class ThreadReferenceProxyImpl extends ObjectReferenceProxyImpl implements ThreadReferenceProxy {
36 private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.ThreadReferenceProxyImpl");
38 private String myName;
39 private int myFrameCount = -1;
40 // stack frames, 0 - bottom
41 private final List<StackFrameProxyImpl> myFramesFromBottom = new ArrayList<StackFrameProxyImpl>();
42 //cache build on the base of myFramesFromBottom 0 - top, initially nothing is cached
43 private List<StackFrameProxyImpl> myFrames = null;
45 private ThreadGroupReferenceProxyImpl myThreadGroupProxy;
47 public static final Comparator<ThreadReferenceProxyImpl> ourComparator = new Comparator<ThreadReferenceProxyImpl>() {
49 public int compare(ThreadReferenceProxyImpl th1, ThreadReferenceProxyImpl th2) {
50 int res = Comparing.compare(th2.isSuspended(), th1.isSuspended());
52 return th1.name().compareToIgnoreCase(th2.name());
58 public ThreadReferenceProxyImpl(VirtualMachineProxyImpl virtualMachineProxy, ThreadReference threadReference) {
59 super(virtualMachineProxy, threadReference);
63 public ThreadReference getThreadReference() {
64 DebuggerManagerThreadImpl.assertIsManagerThread();
65 return (ThreadReference)getObjectReference();
69 public VirtualMachineProxyImpl getVirtualMachine() {
70 DebuggerManagerThreadImpl.assertIsManagerThread();
71 return (VirtualMachineProxyImpl) myTimer;
74 public String name() {
78 myName = getThreadReference().name();
80 catch (ObjectCollectedException ignored) {
83 catch (IllegalThreadStateException ignored) {
90 public int getSuspendCount() {
91 DebuggerManagerThreadImpl.assertIsManagerThread();
92 //LOG.assertTrue((mySuspendCount > 0) == suspends());
94 return getThreadReference().suspendCount();
96 catch (ObjectCollectedException ignored) {
101 public void suspend() {
102 DebuggerManagerThreadImpl.assertIsManagerThread();
104 getThreadReference().suspend();
106 catch (ObjectCollectedException ignored) {
112 public String toString() {
113 //noinspection HardCodedStringLiteral
114 @NonNls String threadRefString;
116 threadRefString = getThreadReference().toString() ;
118 catch (ObjectCollectedException ignored) {
119 threadRefString = "[thread collected]";
121 return "ThreadReferenceProxyImpl: " + threadRefString + " " + super.toString();
124 public void resume() {
125 DebuggerManagerThreadImpl.assertIsManagerThread();
126 //JDI clears all caches on thread resume !!
127 final ThreadReference threadRef = getThreadReference();
128 if(LOG.isDebugEnabled()) {
129 LOG.debug("before resume" + threadRef);
131 getVirtualMachineProxy().clearCaches();
135 catch (ObjectCollectedException ignored) {
140 protected void clearCaches() {
141 DebuggerManagerThreadImpl.assertIsManagerThread();
148 public int status() {
150 return getThreadReference().status();
152 catch (IllegalThreadStateException e) {
153 return ThreadReference.THREAD_STATUS_ZOMBIE;
155 catch (ObjectCollectedException ignored) {
156 return ThreadReference.THREAD_STATUS_ZOMBIE;
160 public ThreadGroupReferenceProxyImpl threadGroupProxy() {
161 DebuggerManagerThreadImpl.assertIsManagerThread();
163 if(myThreadGroupProxy == null) {
164 ThreadGroupReference threadGroupRef;
166 threadGroupRef = getThreadReference().threadGroup();
168 catch (ObjectCollectedException ignored) {
169 threadGroupRef = null;
171 myThreadGroupProxy = getVirtualMachineProxy().getThreadGroupReferenceProxy(threadGroupRef);
173 return myThreadGroupProxy;
177 public int frameCount() throws EvaluateException {
178 DebuggerManagerThreadImpl.assertIsManagerThread();
180 if (myFrameCount == -1) {
181 final ThreadReference threadReference = getThreadReference();
183 myFrameCount = threadReference.frameCount();
185 catch(ObjectCollectedException ignored) {
188 catch (IncompatibleThreadStateException e) {
189 final boolean isSuspended;
191 isSuspended = threadReference.isSuspended();
193 catch (Throwable ignored) {
194 // unable to determine whether the thread is actually suspended, so propagating original exception
195 throw EvaluateExceptionUtil.createEvaluateException(e);
198 // give up because it seems to be really resumed
199 throw EvaluateExceptionUtil.createEvaluateException(e);
202 // JDI bug: although isSuspended() == true, frameCount() may throw IncompatibleThreadStateException
203 // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4783403
204 // unfortunately, impossible to get this information at the moment, so assume the frame count is null
208 catch (InternalException e) {
216 public List<StackFrameProxyImpl> frames() throws EvaluateException {
217 DebuggerManagerThreadImpl.assertIsManagerThread();
218 final ThreadReference threadRef = getThreadReference();
220 //LOG.assertTrue(threadRef.isSuspended());
223 if(myFrames == null) {
224 checkFrames(threadRef);
226 myFrames = new ArrayList<StackFrameProxyImpl>(frameCount());
227 for (ListIterator<StackFrameProxyImpl> iterator = myFramesFromBottom.listIterator(frameCount()); iterator.hasPrevious();) {
228 myFrames.add(iterator.previous());
232 catch (ObjectCollectedException ignored) {
233 return Collections.emptyList();
238 private void checkFrames(@NotNull final ThreadReference threadRef) throws EvaluateException {
239 if (myFramesFromBottom.size() < frameCount()) {
240 int count = frameCount();
241 List<StackFrame> frames;
243 frames = threadRef.frames(0, count - myFramesFromBottom.size());
245 catch (IncompatibleThreadStateException e) {
246 throw EvaluateExceptionUtil.createEvaluateException(e);
248 catch (InternalException e) {
249 throw EvaluateExceptionUtil.createEvaluateException(e);
252 int index = myFramesFromBottom.size() + 1;
253 for (ListIterator<StackFrame> iterator = frames.listIterator(count - myFramesFromBottom.size()); iterator.hasPrevious();) {
254 myFramesFromBottom.add(new StackFrameProxyImpl(this, iterator.previous(), index));
261 public StackFrameProxyImpl frame(int i) throws EvaluateException {
262 DebuggerManagerThreadImpl.assertIsManagerThread();
263 final ThreadReference threadReference = getThreadReference();
265 if(!threadReference.isSuspended()) {
268 checkFrames(threadReference);
269 final int frameCount = frameCount();
270 if (frameCount == 0) {
273 return myFramesFromBottom.get(frameCount - i - 1);
275 catch (ObjectCollectedException ignored) {
278 catch (IllegalThreadStateException ignored) {
283 public void popFrames(StackFrameProxyImpl stackFrame) throws EvaluateException {
284 DebuggerManagerThreadImpl.assertIsManagerThread();
286 getThreadReference().popFrames(stackFrame.getStackFrame());
288 catch (InvalidStackFrameException ignored) {
290 catch (ObjectCollectedException ignored) {
292 catch (InternalException e) {
293 if (e.errorCode() == 32) {
294 throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("drop.frame.error.no.information"));
296 else throw EvaluateExceptionUtil.createEvaluateException(e);
298 catch (IncompatibleThreadStateException e) {
299 throw EvaluateExceptionUtil.createEvaluateException(e);
303 getVirtualMachineProxy().clearCaches();
307 public boolean isSuspended() throws ObjectCollectedException {
309 DebuggerManagerThreadImpl.assertIsManagerThread();
310 return getThreadReference().isSuspended();
312 catch (IllegalThreadStateException e) {
313 // must be zombie thread
319 public boolean isAtBreakpoint() {
321 return getThreadReference().isAtBreakpoint();
322 } catch (InternalException e) {