From ac76eaa00909174ca72ee85ee314919e993a1595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 23 Jul 2009 08:59:59 +0000 Subject: [PATCH] Type caching simplified; Fixed a bug for AppDomains - the AppDomain for threads can change git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4521 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Project/Src/Control/StackFrame.cs | 18 ++- .../Project/Src/Control/Thread.cs | 14 +-- .../Project/Src/Internal/ManagedCallback.cs | 2 +- .../Project/Src/Metadata/DebugType-Helpers.cs | 14 +-- .../Project/Src/Metadata/DebugType.cs | 118 +++--------------- .../CorDebug/Autogenerated/ICorDebugType.cs | 4 +- .../Project/Debugger.Tests.csproj | 3 +- .../Project/Src/TestPrograms/AppDomains.cs | 82 ++++++++++++ 8 files changed, 129 insertions(+), 126 deletions(-) create mode 100644 src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AppDomains.cs diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs index 54bc20da2e..b50689a10a 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/StackFrame.cs @@ -5,13 +5,15 @@ // $Revision$ // +using System; using System.Collections.Generic; using System.Runtime.InteropServices; -using Debugger.MetaData; using Debugger.Expressions; +using Debugger.MetaData; using Debugger.Wrappers.CorDebug; using Debugger.Wrappers.CorSym; +using Debugger.Wrappers.MetaData; namespace Debugger { @@ -22,6 +24,7 @@ namespace Debugger public class StackFrame: DebuggerObject { Thread thread; + AppDomain appDomain; Process process; ICorDebugILFrame corILFrame; @@ -35,7 +38,7 @@ namespace Debugger /// The process in which this stack frame is executed [Debugger.Tests.Ignore] public AppDomain AppDomain { - get { return thread.AppDomain; } + get { return appDomain; } } [Debugger.Tests.Ignore] @@ -91,16 +94,21 @@ namespace Debugger { this.process = thread.Process; this.thread = thread; + this.appDomain = process.AppDomains[corILFrame.Function.Class.Module.Assembly.AppDomain]; this.corILFrame = corILFrame; this.corILFramePauseSession = process.PauseSession; this.corFunction = corILFrame.Function; this.chainIndex = chainIndex; this.frameIndex = frameIndex; + MetaDataImport metaData = thread.Process.Modules[corFunction.Class.Module].MetaData; + ICorDebugType[] genArgs = corILFrame.CastTo().EnumerateTypeParameters().ToList().ToArray(); + Array.Resize(ref genArgs, metaData.GetGenericParamCount(corFunction.Class.Token)); + DebugType debugType = DebugType.Create( this.AppDomain, corFunction.Class, - corILFrame.CastTo().EnumerateTypeParameters().ToList().ToArray() + genArgs ); this.methodInfo = debugType.GetMethod(corFunction.Token); } @@ -266,7 +274,7 @@ namespace Debugger /// public Value GetThisValue() { - return new Value(thread.AppDomain, new ThisReferenceExpression(), GetThisCorValue()); + return new Value(appDomain, new ThisReferenceExpression(), GetThisCorValue()); } ICorDebugValue GetThisCorValue() @@ -303,7 +311,7 @@ namespace Debugger /// Zero-based index public Value GetArgumentValue(int index) { - return new Value(thread.AppDomain, new ParameterIdentifierExpression(this.MethodInfo, index), GetArgumentCorValue(index)); + return new Value(appDomain, new ParameterIdentifierExpression(this.MethodInfo, index), GetArgumentCorValue(index)); } ICorDebugValue GetArgumentCorValue(int index) diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs index d36cbdd328..50c91d4b21 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs @@ -17,7 +17,7 @@ namespace Debugger { public partial class Thread: DebuggerObject { - AppDomain appDomain; + // AppDomain for thread can be changing Process process; uint id; @@ -37,11 +37,6 @@ namespace Debugger public event EventHandler NameChanged; public event EventHandler Exited; - [Debugger.Tests.Ignore] - public AppDomain AppDomain { - get { return appDomain; } - } - [Debugger.Tests.Ignore] public Process Process { get { return process; } @@ -88,10 +83,9 @@ namespace Debugger } } - internal Thread(AppDomain appDomain, ICorDebugThread corThread) + internal Thread(Process process, ICorDebugThread corThread) { - this.appDomain = appDomain; - this.process = appDomain.Process; + this.process = process; this.corThread = corThread; this.id = CorThread.ID; } @@ -166,7 +160,7 @@ namespace Debugger process.AssertPaused(); ICorDebugValue corValue = this.CorThread.Object; - return new Value(appDomain, new EmptyExpression(), corValue); + return new Value(process.AppDomains[this.CorThread.AppDomain], new EmptyExpression(), corValue); } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs index efcf06a60b..dff8f4655e 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Internal/ManagedCallback.cs @@ -367,7 +367,7 @@ namespace Debugger // and we continue from this callback anyway EnterCallback(PausedReason.Other, "CreateThread " + pThread.ID, pAppDomain); - process.Threads.Add(new Thread(process.AppDomains[pAppDomain], pThread)); + process.Threads.Add(new Thread(process, pThread)); ExitCallback(); } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType-Helpers.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType-Helpers.cs index 4c8f84389d..1c60dba421 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType-Helpers.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType-Helpers.cs @@ -297,23 +297,23 @@ namespace Debugger.MetaData #endregion - private bool primitiveTypeCached = false; - private System.Type primitiveTypeCache; + private bool primitiveTypeCached; + private System.Type primitiveType; /// Returns simple managed type coresponding to the primitive type. [Tests.Ignore] public System.Type PrimitiveType { get { - if (!this.primitiveTypeCached) { - this.primitiveTypeCache = getPrimitiveType(); - this.primitiveTypeCached = true; + if (!primitiveTypeCached) { + primitiveTypeCached = true; + primitiveType = GetPrimitiveType(); } - return this.primitiveTypeCache; + return primitiveType; } } /// Returns simple managed type coresponding to the primitive type. - private System.Type getPrimitiveType() + private System.Type GetPrimitiveType() { if (corElementType == CorElementType.VALUETYPE) { CorElementType corType; diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs index 19cd887f84..9afb3cdb35 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Metadata/DebugType.cs @@ -45,7 +45,7 @@ namespace Debugger.MetaData List members = new List(); // Stores all DebugType instances. FullName is the key - static Dictionary> loadedTypes = new Dictionary>(); + static Dictionary loadedTypes = new Dictionary(); void AssertClassOrValueType() { @@ -66,9 +66,7 @@ namespace Debugger.MetaData } internal ICorDebugType CorType { - get { - return corType; - } + get { return corType; } } /// @@ -102,9 +100,7 @@ namespace Debugger.MetaData /// Returns a string describing the type including the namespace /// and generic arguments but excluding the assembly name. public string FullName { - get { - return fullName; - } + get { return fullName; } } /// Returns the number of dimensions of an array @@ -118,9 +114,7 @@ namespace Debugger.MetaData /// Gets a list of all interfaces that this type implements public List Interfaces { - get { - return interfaces; - } + get { return interfaces; } } /// Return an interface with the given name @@ -290,16 +284,6 @@ namespace Debugger.MetaData } } - internal uint? AppDomainID { - get { - if (IsClass || IsValueType) { - return this.Module.AppDomainID; - } else { - return null; - } - } - } - /// /// Gets the type from which this type inherits. /// @@ -356,11 +340,6 @@ namespace Debugger.MetaData this.name = GetName(false); } - public static DebugType Create(Module module, uint token) - { - return Create(module, token, null); - } - public static DebugType Create(Module module, uint token, DebugType declaringType) { CorTokenType tokenType = (CorTokenType)(token & 0xFF000000); @@ -374,11 +353,6 @@ namespace Debugger.MetaData } } - public static DebugType Create(Module module, byte[] sig) - { - return Create(module, sig, null); - } - /// Type definition to use to resolve numbered generic references public static DebugType Create(Module module, byte[] sig, DebugType declaringType) { @@ -478,7 +452,7 @@ namespace Debugger.MetaData throw new DebuggerException("Can not find type " + fullTypeName); } - static public DebugType Create(AppDomain appDomain, ICorDebugClass corClass, params ICorDebugType[] typeArguments) + static public DebugType Create(AppDomain appDomain, ICorDebugClass corClass, params ICorDebugType[] genericArguments) { MetaDataImport metaData = appDomain.Process.Modules[corClass.Module].MetaData; @@ -495,12 +469,13 @@ namespace Debugger.MetaData } } - int getArgsCount = metaData.GetGenericParamCount(corClass.Token); + if (genericArguments.Length != metaData.GetGenericParamCount(corClass.Token)) { + throw new DebuggerException("Incorrect number of generic arguments"); + } - Array.Resize(ref typeArguments, getArgsCount); ICorDebugType corType = corClass.CastTo().GetParameterizedType( isValueType ? (uint)CorElementType.VALUETYPE : (uint)CorElementType.CLASS, - typeArguments + genericArguments ); return Create(appDomain, corType); @@ -509,41 +484,23 @@ namespace Debugger.MetaData /// Obtains instance of DebugType. Same types will return identical instance. static public DebugType Create(AppDomain appDomain, ICorDebugType corType) { + if (loadedTypes.ContainsKey(corType)) return loadedTypes[corType]; + DateTime startTime = Util.HighPrecisionTimer.Now; DebugType type = new DebugType(appDomain, corType); - // Get types with matching names from cache - List typesWithMatchingName; - if (!loadedTypes.TryGetValue(type.FullName, out typesWithMatchingName)) { - // No types with such name - create a new list - typesWithMatchingName = new List(1); - loadedTypes.Add(type.FullName, typesWithMatchingName); - } + // Loading of memebers might access the type again + loadedTypes[corType] = type; - // Try to find the type - foreach(DebugType loadedType in typesWithMatchingName) { - if (loadedType.Equals(type)) { - TimeSpan totalTime = Util.HighPrecisionTimer.Now - startTime; - if (appDomain.Process.Options.Verbose) { - appDomain.Process.TraceMessage("Type " + type.FullName + " was loaded already (" + totalTime.TotalMilliseconds + " ms)"); - } - return loadedType; // Type was loaded before - } - } - - // This has to be done before LoadMemberInfo since it might use it - typesWithMatchingName.Add(type); - - // The type is not in the cache, finish loading it and add it to the cache if (type.IsClass || type.IsValueType) { type.LoadMemberInfo(); } - type.AppDomain.Process.Exited += delegate { typesWithMatchingName.Remove(type); }; + type.AppDomain.Process.Exited += delegate { loadedTypes.Remove(corType); }; TimeSpan totalTime2 = Util.HighPrecisionTimer.Now - startTime; - string prefix = type.IsInterface ? "interface" : "type"; if (appDomain.Process.Options.Verbose) { + string prefix = type.IsInterface ? "interface" : "type"; appDomain.Process.TraceMessage("Loaded {0} {1} ({2} ms)", prefix, type.FullName, totalTime2.TotalMilliseconds); foreach(DebugType inter in type.Interfaces) { appDomain.Process.TraceMessage(" - Implements {0}", inter.FullName); @@ -554,13 +511,13 @@ namespace Debugger.MetaData } /// Returns all non-generic types defined in the given module + /// Generic types can not be returned, because we do not how to instanciate them public static List GetDefinedTypesInModule(Module module) { - // TODO: Generic types List types = new List(); foreach(TypeDefProps typeDef in module.MetaData.EnumTypeDefProps()) { if (module.MetaData.GetGenericParamCount(typeDef.Token) == 0) { - types.Add(DebugType.Create(module, typeDef.Token)); + types.Add(DebugType.Create(module, typeDef.Token, null)); } } return types; @@ -685,48 +642,9 @@ namespace Debugger.MetaData return (GetMembers(bindingFlags).Count > 0); } - /// Compares two types - public override bool Equals(object obj) - { - DebugType other = obj as DebugType; - if (other != null && this.AppDomain == other.AppDomain) { - if (this.IsArray) { - return other.IsArray && - other.GetArrayRank() == this.GetArrayRank() && - other.ElementType.Equals(this.ElementType); - } - if (this.IsPrimitive) { - return other.IsPrimitive && - other.PrimitiveType == this.PrimitiveType && - other.IsValueType == this.IsValueType; - } - if (this.IsClass || this.IsValueType) { - return (other.IsClass || other.IsValueType) && - other.Module == this.Module && - other.Token == this.Token; - } - if (this.IsPointer) { - return other.IsPointer && - other.ElementType.Equals(this.ElementType); - } - if (this.IsVoid) { - return other.IsVoid; - } - throw new DebuggerException("Unknown type"); - } else { - return false; - } - } - - /// Get hash code of the object - public override int GetHashCode() - { - return base.GetHashCode(); - } - public override string ToString() { - return string.Format("{0}", this.fullName); + return string.Format("{0}", this.FullName); } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/Autogenerated/ICorDebugType.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/Autogenerated/ICorDebugType.cs index 4a20c5e7e8..ae460f9156 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/Autogenerated/ICorDebugType.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Wrappers/CorDebug/Autogenerated/ICorDebugType.cs @@ -1,4 +1,4 @@ -// +// // // // @@ -85,7 +85,7 @@ namespace Debugger.Wrappers.CorDebug public override int GetHashCode() { - return base.GetHashCode(); + return wrappedObject.GetHashCode(); } public override bool Equals(object o) diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj index 5e06bf0d3e..02fe5d4243 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj @@ -42,6 +42,7 @@ + @@ -99,4 +100,4 @@ - + \ No newline at end of file diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AppDomains.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AppDomains.cs new file mode 100644 index 0000000000..a4858251d6 --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/AppDomains.cs @@ -0,0 +1,82 @@ +// +// +// +// +// $Revision$ +// + +using System; + +namespace Debugger.Tests.TestPrograms +{ + public class AppDomains + { + public static void Main() + { + int one = 1; + System.Diagnostics.Debugger.Break(); + System.AppDomain appDomain = System.AppDomain.CreateDomain("myDomain"); + RemoteObj printer = (RemoteObj)appDomain.CreateInstanceAndUnwrap(typeof(RemoteObj).Assembly.FullName, typeof(RemoteObj).FullName); + printer.Foo(); + } + } + + public class RemoteObj: MarshalByRefObject + { + public void Foo() + { + int two = 2; + string appDomainName = System.AppDomain.CurrentDomain.FriendlyName + " Id=" + System.AppDomain.CurrentDomain.Id; + System.Diagnostics.Debugger.Break(); + } + } +} + +#if TEST_CODE +namespace Debugger.Tests { + using Debugger.MetaData; + + public partial class DebuggerTests + { + [NUnit.Framework.Test] + public void AppDomains() + { + StartTest("AppDomains.cs"); + + DebugType type1 = process.SelectedStackFrame.GetLocalVariableValue("one").Type; + DebugType type1b = process.SelectedStackFrame.GetLocalVariableValue("one").Type; + ObjectDump("SameDomainEqual", type1 == type1b); + process.Continue(); + ObjectDump("AppDomainName", process.SelectedStackFrame.GetLocalVariableValue("appDomainName").AsString); + DebugType type2 = process.SelectedStackFrame.GetLocalVariableValue("two").Type; + ObjectDump("OtherDomainEqual", type1 == type2); + ObjectDump("AppDomainsEqual", type1.AppDomain == type2.AppDomain); + ObjectDump("AppDomainIDsEqual", type1.AppDomain.ID == type2.AppDomain.ID); + + EndTest(); + } + } +} +#endif + +#if EXPECTED_OUTPUT + + + + + mscorlib.dll (No symbols) + AppDomains.exe (Has symbols) + Break AppDomains.cs:17,4-17,40 + True + mscorlib.dll (No symbols) + AppDomains.exe (Has symbols) + Break AppDomains.cs:30,4-30,40 + myDomain Id=2 + False + False + False + + + +#endif // EXPECTED_OUTPUT \ No newline at end of file