diff --git a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/TreeViewNode.cs b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/TreeViewNode.cs index 5e3040cfa6..1752558873 100644 --- a/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/TreeViewNode.cs +++ b/src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/TreeModel/Adapters/TreeViewNode.cs @@ -88,6 +88,7 @@ namespace Debugger.AddIn.TreeModel if (loadChildsWhenExpanding) { loadChildsWhenExpanding = false; SetContentRecursive(this.Tree, this.Children, this.Content.ChildNodes); + this.IsExpandedOnce = true; } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj index 9c85b0b9bc..fb18b90013 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Debugger.Core.csproj @@ -202,7 +202,6 @@ - diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/ManagedCallback.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/ManagedCallback.cs index 9e9a322baf..a9d87998b0 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/ManagedCallback.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Debugger/Internal/ManagedCallback.cs @@ -58,11 +58,6 @@ namespace Debugger pauseProcessInsteadOfContinue = false; } - // Remove expired threads and functions - foreach(Thread thread in process.Threads) { - thread.CheckExpiration(); - } - process.NotifyPaused(new PauseSession(pausedReason)); } else { throw new DebuggerException("Invalid state at the start of callback"); diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/FrameID.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/FrameID.cs deleted file mode 100644 index b42701002c..0000000000 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/FrameID.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; - -namespace Debugger -{ - /// - /// Identifies frame on thread callstack - /// - struct FrameID { - uint chainIndex; - uint frameIndex; - - public uint ChainIndex { - get { - return chainIndex; - } - } - - public uint FrameIndex { - get { - return frameIndex; - } - } - - public FrameID(uint chainIndex, uint frameIndex) - { - this.chainIndex = chainIndex; - this.frameIndex = frameIndex; - } - - public override int GetHashCode() - { - return chainIndex.GetHashCode() ^ frameIndex.GetHashCode(); - } - - public override bool Equals(object obj) - { - if (!(obj is FrameID)) return false; - FrameID myFrameID = (FrameID)obj; - return this.chainIndex == myFrameID.chainIndex && this.frameIndex == myFrameID.frameIndex; - } - - public override string ToString() - { - return string.Format("{0},{1}", this.chainIndex, this.frameIndex); - } - } -} diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs index 26330814c1..32d745d746 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Process.cs @@ -141,12 +141,6 @@ namespace Debugger corProcess.Stop(5000); // TODO: Hardcoded value pauseSession = new PauseSession(PausedReason.ForcedBreak); - - // TODO: Code duplication from enter callback - // Remove expired threads and functions - foreach(Thread thread in this.Threads) { - thread.CheckExpiration(); - } Pause(true); } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/StackFrame.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/StackFrame.cs index b1a2714ffd..0b067bb41b 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/StackFrame.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/StackFrame.cs @@ -19,21 +19,16 @@ namespace Debugger /// A stack frame which is being executed on some thread. /// Use to obtain arguments or local variables. /// - public class StackFrame: DebuggerObject, IExpirable + public class StackFrame: DebuggerObject { Process process; + Thread thread; - MethodInfo methodInfo; - - ICorDebugFunction corFunction; ICorDebugILFrame corILFrame; object corILFramePauseSession; + ICorDebugFunction corFunction; - Stepper stepOutStepper; - - bool steppedOut = false; - Thread thread; - FrameID frameID; + MethodInfo methodInfo; /// The process in which this stack frame is executed [Debugger.Tests.Ignore] @@ -67,32 +62,17 @@ namespace Debugger /// True if stack frame stepped out and is not longer valid. public bool HasExpired { get { - return steppedOut || this.MethodInfo.Module.Unloaded; + return this.corILFramePauseSession != process.PauseSession; } } - /// Occurs when stack frame expires and is no longer usable - public event EventHandler Expired; - - /// Is called when stack frame expires and is no longer usable - internal protected virtual void OnExpired(EventArgs e) - { - if (!steppedOut) { - steppedOut = true; - process.TraceMessage("StackFrame " + this.ToString() + " expired"); - if (Expired != null) { - Expired(this, e); - } - } - } - - internal StackFrame(Thread thread, FrameID frameID, ICorDebugILFrame corILFrame) + internal StackFrame(Thread thread, ICorDebugILFrame corILFrame) { this.process = thread.Process; this.thread = thread; - this.frameID = frameID; - this.CorILFrame = corILFrame; - corFunction = corILFrame.Function; + this.corILFrame = corILFrame; + this.corILFramePauseSession = process.PauseSession; + this.corFunction = corILFrame.Function; DebugType debugType = DebugType.Create( this.Process, @@ -101,34 +81,19 @@ namespace Debugger ); MethodProps methodProps = process.GetModule(corFunction.Module).MetaData.GetMethodProps(corFunction.Token); this.methodInfo = new MethodInfo(debugType, methodProps); - - // Force some callback when stack frame steps out so that we can expire it - stepOutStepper = new Stepper(this, "StackFrame Tracker"); - stepOutStepper.StepOut(); - stepOutStepper.PauseWhenComplete = false; - - process.TraceMessage("StackFrame " + this.ToString() + " created"); } /// Returns diagnostic description of the frame public override string ToString() { - return this.MethodInfo.Name + "(" + frameID.ToString() + ")"; + return this.MethodInfo.FullName; } internal ICorDebugILFrame CorILFrame { get { if (HasExpired) throw new DebuggerException("StackFrame has expired"); - if (corILFramePauseSession != process.PauseSession) { - CorILFrame = thread.GetFrameAt(frameID).As(); - } return corILFrame; } - set { - if (value == null) throw new DebuggerException("Can not set frame to null"); - corILFrame = value; - corILFramePauseSession = process.PauseSession; - } } internal uint CorInstructionPtr { diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Thread.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Thread.cs index 6234e3b4b2..8066240eab 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Thread.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Threads/Thread.cs @@ -14,7 +14,7 @@ using Debugger.Wrappers.CorDebug; namespace Debugger { - public partial class Thread: DebuggerObject, IExpirable + public partial class Thread: DebuggerObject { Process process; @@ -251,7 +251,7 @@ namespace Debugger if (corFrame.Is()) { StackFrame stackFrame; try { - stackFrame = GetStackFrameFromCache(new FrameID(corChain.Index, corFrame.Index), corFrame.As()); + stackFrame = new StackFrame(this, corFrame.CastTo()); } catch (COMException) { // TODO continue; }; @@ -262,95 +262,6 @@ namespace Debugger } } - Dictionary functionCache = new Dictionary(); - - StackFrame GetStackFrameFromCache(FrameID frameID, ICorDebugILFrame corFrame) - { - StackFrame stackFrame; - if (functionCache.TryGetValue(frameID, out stackFrame) && !stackFrame.HasExpired) { - stackFrame.CorILFrame = corFrame; - return stackFrame; - } else { - stackFrame = new StackFrame(this, frameID, corFrame); - functionCache[frameID] = stackFrame; - return stackFrame; - } - } - - internal ICorDebugFrame GetFrameAt(FrameID frameID) - { - process.AssertPaused(); - - ICorDebugChainEnum corChainEnum = CorThread.EnumerateChains(); - if (frameID.ChainIndex >= corChainEnum.Count) throw new ArgumentException("Chain index too big", "chainIndex"); - corChainEnum.Skip(corChainEnum.Count - frameID.ChainIndex - 1); - - ICorDebugChain corChain = corChainEnum.Next(); - - if (corChain.IsManaged == 0) throw new ArgumentException("Chain is not managed", "chainIndex"); - - ICorDebugFrameEnum corFrameEnum = corChain.EnumerateFrames(); - if (frameID.FrameIndex >= corFrameEnum.Count) throw new ArgumentException("Frame index too big", "frameIndex"); - corFrameEnum.Skip(corFrameEnum.Count - frameID.FrameIndex - 1); - - return corFrameEnum.Next(); - } - - // See docs\Stepping.txt - internal void CheckExpiration() - { - try { - ICorDebugChainEnum chainEnum = CorThread.EnumerateChains(); - } catch (COMException e) { - // 0x8013132D: The state of the thread is invalid. - // 0x8013134F: Object is in a zombie state - // 0x80131301: Process was terminated. - if ((uint)e.ErrorCode == 0x8013132D || - (uint)e.ErrorCode == 0x8013134F || - (uint)e.ErrorCode == 0x80131301) { - - this.Expire(); - return; - } else throw; - } - - if (process.Evaluating) return; - - ICorDebugChainEnum corChainEnum = CorThread.EnumerateChains(); - int maxChainIndex = (int)corChainEnum.Count - 1; - - ICorDebugFrameEnum corFrameEnum = corChainEnum.Next().EnumerateFrames(); - // corFrameEnum.Count can return 0 in ExitThread callback - int maxFrameIndex = (int)corFrameEnum.Count - 1; - - ICorDebugFrame lastFrame = corFrameEnum.Next(); - - // Check the token of the current stack frame - stack frame can change if there are multiple handlers for an event - StackFrame stackFrame; - if (lastFrame != null && - functionCache.TryGetValue(new FrameID((uint)maxChainIndex, (uint)maxFrameIndex), out stackFrame) && - stackFrame.MethodInfo.MetadataToken != lastFrame.FunctionToken) { - - functionCache.Remove(new FrameID((uint)maxChainIndex, (uint)maxFrameIndex)); - stackFrame.OnExpired(EventArgs.Empty); - } - - // Expire all functions behind the current maximum - // Multiple functions can expire at once (test case: Step out of Button1Click in simple winforms application) - List> toBeRemoved = new List>(); - foreach(KeyValuePair kvp in functionCache) { - if ((kvp.Key.ChainIndex > maxChainIndex) || - (kvp.Key.ChainIndex == maxChainIndex && kvp.Key.FrameIndex > maxFrameIndex)) { - - toBeRemoved.Add(kvp); - } - } - foreach(KeyValuePair kvp in toBeRemoved){ - functionCache.Remove(kvp.Key); - kvp.Value.OnExpired(EventArgs.Empty); - } - } - [Debugger.Tests.ToStringOnly] public StackFrame SelectedStackFrame { get { diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs index 576228770c..b3255c1602 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/DebuggerTests.cs @@ -187,27 +187,26 @@ namespace Debugger.Tests [Test] public void FunctionLifetime() { - StackFrame stackFrame; - StartTest("FunctionLifetime"); WaitForPause(); - stackFrame = process.SelectedStackFrame; - ObjectDump("StackFrame", stackFrame); + StackFrame stackFrame = process.SelectedStackFrame; + ObjectDump("SelectedStackFrame", process.SelectedStackFrame); process.Continue(); // Go to the SubFunction WaitForPause(); - ObjectDump("StackFrame", stackFrame); - ObjectDump("SubStackFrame", process.SelectedStackFrame); + ObjectDump("Old StackFrame", stackFrame); + ObjectDump("SelectedStackFrame", process.SelectedStackFrame); process.Continue(); // Go back to Function WaitForPause(); - Assert.AreEqual(stackFrame, process.SelectedStackFrame); - ObjectDump("StackFrame", stackFrame); + ObjectDump("Old StackFrame", stackFrame); + ObjectDump("SelectedStackFrame", process.SelectedStackFrame); process.Continue(); // Setp out of function WaitForPause(); ObjectDump("Main", process.SelectedStackFrame); - ObjectDump("StackFrame", stackFrame); + ObjectDump("Old StackFrame", stackFrame); + ObjectDump("SelectedStackFrame", process.SelectedStackFrame); process.Continue(); process.WaitForExit(); diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/FunctionLifetime.xml b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/FunctionLifetime.xml index 1a7976a878..0c642ee73c 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/FunctionLifetime.xml +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/FunctionLifetime.xml @@ -5,7 +5,7 @@ mscorlib.dll FunctionLifetime.exe Break - + @@ -61,7 +61,7 @@ Break - + @@ -76,8 +76,8 @@ True - False - Start=23,4 End=23,18 + True + @@ -85,29 +85,8 @@ - 1 - - - 1 - - - False - - - - False - True - True - 1 - i - False - 1 - False - System.Int32 - - - - + + 0 @@ -116,7 +95,7 @@ - + @@ -156,7 +135,41 @@ Break - + + + + + Function + Debugger.Tests.TestPrograms.FunctionLifetime.Function + True + False + False + True + FunctionLifetime.exe + Debugger.Tests.TestPrograms.FunctionLifetime + + + True + True + + + + + 0 + + + + + + + + 0 + + + + + + @@ -251,7 +264,7 @@ - + @@ -285,6 +298,45 @@ + + + + + Main + Debugger.Tests.TestPrograms.FunctionLifetime.Main + False + True + False + True + FunctionLifetime.exe + Debugger.Tests.TestPrograms.FunctionLifetime + + + True + False + Start=17,4 End=17,40 + + + + 0 + + + + 0 + + + 0 + + + + + + 0 + + + + + \ No newline at end of file