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;
29 import org.jetbrains.annotations.NonNls;
30 import org.jetbrains.annotations.NotNull;
34 public final class ThreadReferenceProxyImpl extends ObjectReferenceProxyImpl implements ThreadReferenceProxy {
35 private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.ThreadReferenceProxyImpl");
37 private String myName;
38 private int myFrameCount = -1;
39 // stack frames, 0 - bottom
40 private final List<StackFrameProxyImpl> myFramesFromBottom = new ArrayList<StackFrameProxyImpl>();
41 //cache build on the base of myFramesFromBottom 0 - top, initially nothing is cached
42 private List<StackFrameProxyImpl> myFrames = null;
44 private ThreadGroupReferenceProxyImpl myThreadGroupProxy;
46 public static final Comparator<ThreadReferenceProxyImpl> ourComparator = new Comparator<ThreadReferenceProxyImpl>() {
48 public int compare(ThreadReferenceProxyImpl th1, ThreadReferenceProxyImpl th2) {
49 return th1.name().compareToIgnoreCase(th2.name());
53 public ThreadReferenceProxyImpl(VirtualMachineProxyImpl virtualMachineProxy, ThreadReference threadReference) {
54 super(virtualMachineProxy, threadReference);
58 public ThreadReference getThreadReference() {
59 DebuggerManagerThreadImpl.assertIsManagerThread();
60 return (ThreadReference)getObjectReference();
64 public VirtualMachineProxyImpl getVirtualMachine() {
65 DebuggerManagerThreadImpl.assertIsManagerThread();
66 return (VirtualMachineProxyImpl) myTimer;
69 public String name() {
73 myName = getThreadReference().name();
75 catch (ObjectCollectedException ignored) {
78 catch (IllegalThreadStateException ignored) {
85 public int getSuspendCount() {
86 DebuggerManagerThreadImpl.assertIsManagerThread();
87 //LOG.assertTrue((mySuspendCount > 0) == suspends());
89 return getThreadReference().suspendCount();
91 catch (ObjectCollectedException ignored) {
96 public void suspend() {
97 DebuggerManagerThreadImpl.assertIsManagerThread();
99 getThreadReference().suspend();
101 catch (ObjectCollectedException ignored) {
107 public String toString() {
108 //noinspection HardCodedStringLiteral
109 @NonNls String threadRefString;
111 threadRefString = getThreadReference().toString() ;
113 catch (ObjectCollectedException ignored) {
114 threadRefString = "[thread collected]";
116 return "ThreadReferenceProxyImpl: " + threadRefString + " " + super.toString();
119 public void resume() {
120 DebuggerManagerThreadImpl.assertIsManagerThread();
121 //JDI clears all caches on thread resume !!
122 final ThreadReference threadRef = getThreadReference();
123 if(LOG.isDebugEnabled()) {
124 LOG.debug("before resume" + threadRef);
126 getVirtualMachineProxy().clearCaches();
130 catch (ObjectCollectedException ignored) {
135 protected void clearCaches() {
136 DebuggerManagerThreadImpl.assertIsManagerThread();
143 public int status() {
145 return getThreadReference().status();
147 catch (IllegalThreadStateException e) {
148 return ThreadReference.THREAD_STATUS_ZOMBIE;
150 catch (ObjectCollectedException ignored) {
151 return ThreadReference.THREAD_STATUS_ZOMBIE;
155 public ThreadGroupReferenceProxyImpl threadGroupProxy() {
156 DebuggerManagerThreadImpl.assertIsManagerThread();
158 if(myThreadGroupProxy == null) {
159 ThreadGroupReference threadGroupRef;
161 threadGroupRef = getThreadReference().threadGroup();
163 catch (ObjectCollectedException ignored) {
164 threadGroupRef = null;
166 myThreadGroupProxy = getVirtualMachineProxy().getThreadGroupReferenceProxy(threadGroupRef);
168 return myThreadGroupProxy;
172 public int frameCount() throws EvaluateException {
173 DebuggerManagerThreadImpl.assertIsManagerThread();
175 if (myFrameCount == -1) {
176 final ThreadReference threadReference = getThreadReference();
178 myFrameCount = threadReference.frameCount();
180 catch(ObjectCollectedException ignored) {
183 catch (IncompatibleThreadStateException e) {
184 final boolean isSuspended;
186 isSuspended = threadReference.isSuspended();
188 catch (Throwable ignored) {
189 // unable to determine whether the thread is actually suspended, so propagating original exception
190 throw EvaluateExceptionUtil.createEvaluateException(e);
193 // give up because it seems to be really resumed
194 throw EvaluateExceptionUtil.createEvaluateException(e);
197 // JDI bug: although isSuspended() == true, frameCount() may throw IncompatibleThreadStateException
198 // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4783403
199 // unfortunately, impossible to get this information at the moment, so assume the frame count is null
203 catch (InternalException e) {
211 public List<StackFrameProxyImpl> frames() throws EvaluateException {
212 DebuggerManagerThreadImpl.assertIsManagerThread();
213 final ThreadReference threadRef = getThreadReference();
215 //LOG.assertTrue(threadRef.isSuspended());
218 if(myFrames == null) {
219 checkFrames(threadRef);
221 myFrames = new ArrayList<StackFrameProxyImpl>(frameCount());
222 for (ListIterator<StackFrameProxyImpl> iterator = myFramesFromBottom.listIterator(frameCount()); iterator.hasPrevious();) {
223 myFrames.add(iterator.previous());
227 catch (ObjectCollectedException ignored) {
228 return Collections.emptyList();
233 private void checkFrames(@NotNull final ThreadReference threadRef) throws EvaluateException {
234 if (myFramesFromBottom.size() < frameCount()) {
235 int count = frameCount();
236 List<StackFrame> frames;
238 frames = threadRef.frames(0, count - myFramesFromBottom.size());
240 catch (IncompatibleThreadStateException e) {
241 throw EvaluateExceptionUtil.createEvaluateException(e);
243 catch (InternalException e) {
244 throw EvaluateExceptionUtil.createEvaluateException(e);
247 int index = myFramesFromBottom.size() + 1;
248 for (ListIterator<StackFrame> iterator = frames.listIterator(count - myFramesFromBottom.size()); iterator.hasPrevious();) {
249 myFramesFromBottom.add(new StackFrameProxyImpl(this, iterator.previous(), index));
256 public StackFrameProxyImpl frame(int i) throws EvaluateException {
257 DebuggerManagerThreadImpl.assertIsManagerThread();
258 final ThreadReference threadReference = getThreadReference();
260 if(!threadReference.isSuspended()) {
263 checkFrames(threadReference);
264 final int frameCount = frameCount();
265 if (frameCount == 0) {
268 return myFramesFromBottom.get(frameCount - i - 1);
270 catch (ObjectCollectedException ignored) {
273 catch (IllegalThreadStateException ignored) {
278 public void popFrames(StackFrameProxyImpl stackFrame) throws EvaluateException {
279 DebuggerManagerThreadImpl.assertIsManagerThread();
281 getThreadReference().popFrames(stackFrame.getStackFrame());
283 catch (InvalidStackFrameException ignored) {
285 catch (ObjectCollectedException ignored) {
287 catch (InternalException e) {
288 if (e.errorCode() == 32) {
289 throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("drop.frame.error.no.information"));
291 else throw EvaluateExceptionUtil.createEvaluateException(e);
293 catch (IncompatibleThreadStateException e) {
294 throw EvaluateExceptionUtil.createEvaluateException(e);
298 getVirtualMachineProxy().clearCaches();
302 public boolean isSuspended() throws ObjectCollectedException {
304 DebuggerManagerThreadImpl.assertIsManagerThread();
305 return getThreadReference().isSuspended();
307 catch (IllegalThreadStateException e) {
308 // must be zombie thread
314 public boolean isAtBreakpoint() {
316 return getThreadReference().isAtBreakpoint();
317 } catch (InternalException e) {