/* * @author Eugene Zhuravlev */ package com.intellij.debugger.jdi; import com.intellij.debugger.engine.DebuggerManagerThreadImpl; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; import com.intellij.debugger.engine.jdi.ThreadReferenceProxy; import com.intellij.openapi.diagnostic.Logger; import com.sun.jdi.IncompatibleThreadStateException; import com.sun.jdi.StackFrame; import com.sun.jdi.ThreadReference; import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.ListIterator; public final class ThreadReferenceProxyImpl extends ObjectReferenceProxyImpl implements ThreadReferenceProxy { private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.jdi.ThreadReferenceProxyImpl"); // cached data private String myName; private int myFrameCount = -1; // stackframes, 0 - bottom private List myFramesFromBottom = new ArrayList(); //cache build on the base of myFramesFromBottom 0 - top, initially nothing is cached private List myFrames = null; private ThreadGroupReferenceProxyImpl myThreadGroupProxy; public static Comparator ourComparator = new Comparator() { public int compare(ThreadReferenceProxyImpl th1, ThreadReferenceProxyImpl th2) { return th1.name().compareTo(th2.name()); } }; public ThreadReferenceProxyImpl(VirtualMachineProxyImpl virtualMachineProxy, ThreadReference threadReference) { super(virtualMachineProxy, threadReference); LOG.assertTrue(threadReference != null); } public ThreadReference getThreadReference() { DebuggerManagerThreadImpl.assertIsManagerThread(); return (ThreadReference)getObjectReference(); } public VirtualMachineProxyImpl getVirtualMachine() { DebuggerManagerThreadImpl.assertIsManagerThread(); return (VirtualMachineProxyImpl) myTimer; } public String name() { checkValid(); if (myName == null) { myName = getThreadReference().name(); } return myName; } public int getSuspendCount() { DebuggerManagerThreadImpl.assertIsManagerThread(); //LOG.assertTrue((mySuspendCount > 0) == suspends()); return getThreadReference().suspendCount(); } public void suspend() { DebuggerManagerThreadImpl.assertIsManagerThread(); getThreadReference().suspend(); clearCaches(); } public String toString() { return "ThreadReferenceProxyImpl: " + getThreadReference().toString() + " " + super.toString(); } public void resume() { DebuggerManagerThreadImpl.assertIsManagerThread(); //JDI clears all caches on thread resume !! if(LOG.isDebugEnabled()) { LOG.debug("before resume" + getThreadReference()); } getVirtualMachineProxy().clearCaches(); getThreadReference().resume(); } protected void clearCaches() { DebuggerManagerThreadImpl.assertIsManagerThread(); myFrames = null; myFrameCount = -1; super.clearCaches(); } public int suspendCount() { DebuggerManagerThreadImpl.assertIsManagerThread(); return getThreadReference().suspendCount(); } public int status() { return getThreadReference().status(); } public ThreadGroupReferenceProxyImpl threadGroupProxy() { DebuggerManagerThreadImpl.assertIsManagerThread(); checkValid(); if(myThreadGroupProxy == null) { myThreadGroupProxy = getVirtualMachineProxy().getThreadGroupReferenceProxy(getThreadReference().threadGroup()); } return myThreadGroupProxy; } public int frameCount() throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); checkValid(); if (myFrameCount == -1) { try { final ThreadReference threadReference = getThreadReference(); myFrameCount = threadReference.frameCount(); } catch (IncompatibleThreadStateException e) { if (!isSuspended()) { // give up because it seems to be really resumed throw EvaluateExceptionUtil.createEvaluateException(e); } else { // JDI bug: although isSuspended() == true, frameCount() may throw IncompatibleTharedStateException // unfortunately, impossible to get this information at the moment, so assume the frame count is null myFrameCount = 0; } } } return myFrameCount; } public List frames() throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); LOG.assertTrue(getThreadReference().isSuspended()); checkValid(); if(myFrames == null) { checkFrames(); myFrames = new ArrayList(frameCount()); for (ListIterator iterator = myFramesFromBottom.listIterator(frameCount()); iterator.hasPrevious();) { StackFrameProxyImpl stackFrameProxy = iterator.previous(); myFrames.add(stackFrameProxy); } } return myFrames; } private void checkFrames() throws EvaluateException { if (myFramesFromBottom.size() < frameCount()) { int count = frameCount(); List frames = null; try { frames = getThreadReference().frames(0, count - myFramesFromBottom.size()); } catch (IncompatibleThreadStateException e) { throw EvaluateExceptionUtil.createEvaluateException(e); } int index = myFramesFromBottom.size() + 1; for (ListIterator iterator = frames.listIterator(count - myFramesFromBottom.size()); iterator.hasPrevious();) { StackFrame stackFrame = iterator.previous(); myFramesFromBottom.add(new StackFrameProxyImpl(this, stackFrame, index)); index++; } } } public StackFrameProxyImpl frame(int i) throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); if(!getThreadReference().isSuspended()) return null; checkFrames(); return myFramesFromBottom.get(frameCount() - i - 1); } public void popFrames(StackFrameProxyImpl stackFrame) throws EvaluateException { DebuggerManagerThreadImpl.assertIsManagerThread(); try { getThreadReference().popFrames(stackFrame.getStackFrame()); } catch (IncompatibleThreadStateException e) { throw EvaluateExceptionUtil.createEvaluateException(e); } clearCaches(); } public boolean isSuspended() { DebuggerManagerThreadImpl.assertIsManagerThread(); return getThreadReference().isSuspended(); } }