From b016131315137d1fa81d6acf17346de77f2e21fe Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sat, 28 Jul 2012 13:34:34 +0200 Subject: [PATCH] Made debugger type system thread-safe. --- .../Debugger.Core/TypeSystemExtensions.cs | 102 +++++++++++++----- .../ICSharpCode.NRefactory.csproj | 6 +- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs b/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs index 3173880da5..e7065d7d41 100644 --- a/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs +++ b/src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs @@ -7,9 +7,11 @@ using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; +using System.Threading; using System.Threading.Tasks; using Debugger.Interop.CorDebug; using Debugger.MetaData; +using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem.Implementation; using Mono.Cecil.Metadata; @@ -27,10 +29,11 @@ namespace Debugger class ModuleMetadataInfo { public readonly Module Module; - public Dictionary MetadataTokens = new Dictionary(); - public Dictionary TokenToMethod = new Dictionary(); - public Dictionary LocalVariableTypes = new Dictionary(); + Dictionary metadataTokens = new Dictionary(); + Dictionary tokenToMethod = new Dictionary(); + Dictionary localVariableTypes = new Dictionary(); readonly CecilLoader typeRefLoader; + readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim(); public ModuleMetadataInfo(Module module, Mono.Cecil.ModuleDefinition cecilModule) { @@ -42,24 +45,67 @@ namespace Debugger public void AddMember(IUnresolvedEntity entity, Mono.Cecil.MemberReference cecilObject) { - uint token = cecilObject.MetadataToken.ToUInt32(); - this.MetadataTokens[entity] = token; - - var cecilMethod = cecilObject as Mono.Cecil.MethodDefinition; - if (cecilMethod != null) { - IUnresolvedMethod method = (IUnresolvedMethod)entity; - this.TokenToMethod[token] = method; - if (cecilMethod.HasBody) { - var locals = cecilMethod.Body.Variables; - if (locals.Count > 0) { - this.LocalVariableTypes[method] = locals.Select(v => typeRefLoader.ReadTypeReference(v.VariableType)).ToArray(); - } - if (cecilMethod.RVA != 0) { - // The method was loaded from image - we can free the memory for the body - // because Cecil will re-initialize it on demand - cecilMethod.Body = null; + rwLock.EnterWriteLock(); + try { + uint token = cecilObject.MetadataToken.ToUInt32(); + metadataTokens[entity] = token; + + var cecilMethod = cecilObject as Mono.Cecil.MethodDefinition; + if (cecilMethod != null) { + IUnresolvedMethod method = (IUnresolvedMethod)entity; + tokenToMethod[token] = method; + if (cecilMethod.HasBody) { + var locals = cecilMethod.Body.Variables; + if (locals.Count > 0) { + localVariableTypes[method] = locals.Select(v => typeRefLoader.ReadTypeReference(v.VariableType)).ToArray(); + } + if (cecilMethod.RVA != 0) { + // The method was loaded from image - we can free the memory for the body + // because Cecil will re-initialize it on demand + cecilMethod.Body = null; + } } } + } finally { + rwLock.ExitWriteLock(); + } + } + + public IReadOnlyList GetLocalVariableTypes(IUnresolvedMember member) + { + rwLock.EnterReadLock(); + try { + ITypeReference[] result; + if (localVariableTypes.TryGetValue(member, out result)) + return result; + else + return EmptyList.Instance; + } finally { + rwLock.ExitReadLock(); + } + } + + public uint GetMetadataToken(IUnresolvedEntity entity) + { + rwLock.EnterReadLock(); + try { + return metadataTokens[entity]; + } finally { + rwLock.ExitReadLock(); + } + } + + public IUnresolvedMethod GetMethodFromToken(uint functionToken) + { + rwLock.EnterReadLock(); + try { + IUnresolvedMethod method; + if (tokenToMethod.TryGetValue(functionToken, out method)) + return method; + else + return null; + } finally { + rwLock.ExitReadLock(); } } } @@ -132,25 +178,25 @@ namespace Debugger public static uint GetMetadataToken(this ITypeDefinition typeDefinition) { var info = GetInfo(typeDefinition.ParentAssembly); - return info.MetadataTokens[typeDefinition.Parts[0]]; + return info.GetMetadataToken(typeDefinition.Parts[0]); } public static uint GetMetadataToken(this IField field) { var info = GetInfo(field.ParentAssembly); - return info.MetadataTokens[field.UnresolvedMember]; + return info.GetMetadataToken(field.UnresolvedMember); } public static uint GetMetadataToken(this IMethod method) { var info = GetInfo(method.ParentAssembly); - return info.MetadataTokens[method.UnresolvedMember]; + return info.GetMetadataToken(method.UnresolvedMember); } public static IType GetLocalVariableType(this IMethod method, int index) { var info = GetInfo(method.ParentAssembly); - var variableTypes = info.LocalVariableTypes[method.UnresolvedMember]; + var variableTypes = info.GetLocalVariableTypes(method.UnresolvedMember); return variableTypes[index].Resolve(new SimpleTypeResolveContext(method)); } #endregion @@ -200,7 +246,7 @@ namespace Debugger ITypeDefinition typeDef = type.GetDefinition(); appDomain = GetAppDomain(typeDef.Compilation); var info = GetInfo(typeDef.ParentAssembly); - uint token = info.MetadataTokens[typeDef.Parts[0]]; + uint token = info.GetMetadataToken(typeDef.Parts[0]); ICorDebugClass corClass = info.Module.CorModule.GetClassFromToken(token); List corGenArgs = new List(); ParameterizedType pt = type as ParameterizedType; @@ -462,15 +508,17 @@ namespace Debugger Module module = compilation.GetAppDomain().Process.GetModule(corFunction.GetModule()); var info = GetInfo(module.Assembly); uint functionToken = corFunction.GetToken(); - IUnresolvedMethod unresolvedMethod; - if (!info.TokenToMethod.TryGetValue(functionToken, out unresolvedMethod)) { + var unresolvedMethod = info.GetMethodFromToken(functionToken); + if (unresolvedMethod == null) { // The type containing this function wasn't loaded yet uint classToken = corFunction.GetClass().GetToken(); var definition = ToTypeDefinitionReference(module, classToken).Resolve(new SimpleTypeResolveContext(module.Assembly)).GetDefinition(); if (definition == null) throw new InvalidOperationException("Could not find class for token " + classToken); definition.Methods.ToList(); // enforce loading the methods so that they get added to the dictionary - unresolvedMethod = info.TokenToMethod[functionToken]; + unresolvedMethod = info.GetMethodFromToken(functionToken); + if (unresolvedMethod == null) + throw new InvalidOperationException("Could not find function with token " + functionToken); } return unresolvedMethod.Resolve(new SimpleTypeResolveContext(module.Assembly)); } diff --git a/src/Libraries/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/src/Libraries/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 7189df55a6..4e09de2114 100644 --- a/src/Libraries/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/src/Libraries/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -22,6 +22,8 @@ bin\$(Configuration)\ICSharpCode.NRefactory.xml 4 1591 + + v4.5 AnyCPU @@ -33,14 +35,14 @@ bin\Debug\ False - DEBUG;TRACE + DEBUG;TRACE;NET45 True Project bin\Release\ True - TRACE + TRACE;NET45 False