Browse Source

Made debugger type system thread-safe.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
b016131315
  1. 102
      src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs
  2. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

102
src/AddIns/Debugger/Debugger.Core/TypeSystemExtensions.cs

@ -7,9 +7,11 @@ using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Debugger.Interop.CorDebug; using Debugger.Interop.CorDebug;
using Debugger.MetaData; using Debugger.MetaData;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.NRefactory.TypeSystem.Implementation; using ICSharpCode.NRefactory.TypeSystem.Implementation;
using Mono.Cecil.Metadata; using Mono.Cecil.Metadata;
@ -27,10 +29,11 @@ namespace Debugger
class ModuleMetadataInfo class ModuleMetadataInfo
{ {
public readonly Module Module; public readonly Module Module;
public Dictionary<IUnresolvedEntity, uint> MetadataTokens = new Dictionary<IUnresolvedEntity, uint>(); Dictionary<IUnresolvedEntity, uint> metadataTokens = new Dictionary<IUnresolvedEntity, uint>();
public Dictionary<uint, IUnresolvedMethod> TokenToMethod = new Dictionary<uint, IUnresolvedMethod>(); Dictionary<uint, IUnresolvedMethod> tokenToMethod = new Dictionary<uint, IUnresolvedMethod>();
public Dictionary<IUnresolvedMember, ITypeReference[]> LocalVariableTypes = new Dictionary<IUnresolvedMember, ITypeReference[]>(); Dictionary<IUnresolvedMember, ITypeReference[]> localVariableTypes = new Dictionary<IUnresolvedMember, ITypeReference[]>();
readonly CecilLoader typeRefLoader; readonly CecilLoader typeRefLoader;
readonly ReaderWriterLockSlim rwLock = new ReaderWriterLockSlim();
public ModuleMetadataInfo(Module module, Mono.Cecil.ModuleDefinition cecilModule) public ModuleMetadataInfo(Module module, Mono.Cecil.ModuleDefinition cecilModule)
{ {
@ -42,24 +45,67 @@ namespace Debugger
public void AddMember(IUnresolvedEntity entity, Mono.Cecil.MemberReference cecilObject) public void AddMember(IUnresolvedEntity entity, Mono.Cecil.MemberReference cecilObject)
{ {
uint token = cecilObject.MetadataToken.ToUInt32(); rwLock.EnterWriteLock();
this.MetadataTokens[entity] = token; try {
uint token = cecilObject.MetadataToken.ToUInt32();
var cecilMethod = cecilObject as Mono.Cecil.MethodDefinition; metadataTokens[entity] = token;
if (cecilMethod != null) {
IUnresolvedMethod method = (IUnresolvedMethod)entity; var cecilMethod = cecilObject as Mono.Cecil.MethodDefinition;
this.TokenToMethod[token] = method; if (cecilMethod != null) {
if (cecilMethod.HasBody) { IUnresolvedMethod method = (IUnresolvedMethod)entity;
var locals = cecilMethod.Body.Variables; tokenToMethod[token] = method;
if (locals.Count > 0) { if (cecilMethod.HasBody) {
this.LocalVariableTypes[method] = locals.Select(v => typeRefLoader.ReadTypeReference(v.VariableType)).ToArray(); var locals = cecilMethod.Body.Variables;
} if (locals.Count > 0) {
if (cecilMethod.RVA != 0) { localVariableTypes[method] = locals.Select(v => typeRefLoader.ReadTypeReference(v.VariableType)).ToArray();
// The method was loaded from image - we can free the memory for the body }
// because Cecil will re-initialize it on demand if (cecilMethod.RVA != 0) {
cecilMethod.Body = null; // 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<ITypeReference> GetLocalVariableTypes(IUnresolvedMember member)
{
rwLock.EnterReadLock();
try {
ITypeReference[] result;
if (localVariableTypes.TryGetValue(member, out result))
return result;
else
return EmptyList<ITypeReference>.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) public static uint GetMetadataToken(this ITypeDefinition typeDefinition)
{ {
var info = GetInfo(typeDefinition.ParentAssembly); var info = GetInfo(typeDefinition.ParentAssembly);
return info.MetadataTokens[typeDefinition.Parts[0]]; return info.GetMetadataToken(typeDefinition.Parts[0]);
} }
public static uint GetMetadataToken(this IField field) public static uint GetMetadataToken(this IField field)
{ {
var info = GetInfo(field.ParentAssembly); var info = GetInfo(field.ParentAssembly);
return info.MetadataTokens[field.UnresolvedMember]; return info.GetMetadataToken(field.UnresolvedMember);
} }
public static uint GetMetadataToken(this IMethod method) public static uint GetMetadataToken(this IMethod method)
{ {
var info = GetInfo(method.ParentAssembly); var info = GetInfo(method.ParentAssembly);
return info.MetadataTokens[method.UnresolvedMember]; return info.GetMetadataToken(method.UnresolvedMember);
} }
public static IType GetLocalVariableType(this IMethod method, int index) public static IType GetLocalVariableType(this IMethod method, int index)
{ {
var info = GetInfo(method.ParentAssembly); var info = GetInfo(method.ParentAssembly);
var variableTypes = info.LocalVariableTypes[method.UnresolvedMember]; var variableTypes = info.GetLocalVariableTypes(method.UnresolvedMember);
return variableTypes[index].Resolve(new SimpleTypeResolveContext(method)); return variableTypes[index].Resolve(new SimpleTypeResolveContext(method));
} }
#endregion #endregion
@ -200,7 +246,7 @@ namespace Debugger
ITypeDefinition typeDef = type.GetDefinition(); ITypeDefinition typeDef = type.GetDefinition();
appDomain = GetAppDomain(typeDef.Compilation); appDomain = GetAppDomain(typeDef.Compilation);
var info = GetInfo(typeDef.ParentAssembly); 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); ICorDebugClass corClass = info.Module.CorModule.GetClassFromToken(token);
List<ICorDebugType> corGenArgs = new List<ICorDebugType>(); List<ICorDebugType> corGenArgs = new List<ICorDebugType>();
ParameterizedType pt = type as ParameterizedType; ParameterizedType pt = type as ParameterizedType;
@ -462,15 +508,17 @@ namespace Debugger
Module module = compilation.GetAppDomain().Process.GetModule(corFunction.GetModule()); Module module = compilation.GetAppDomain().Process.GetModule(corFunction.GetModule());
var info = GetInfo(module.Assembly); var info = GetInfo(module.Assembly);
uint functionToken = corFunction.GetToken(); uint functionToken = corFunction.GetToken();
IUnresolvedMethod unresolvedMethod; var unresolvedMethod = info.GetMethodFromToken(functionToken);
if (!info.TokenToMethod.TryGetValue(functionToken, out unresolvedMethod)) { if (unresolvedMethod == null) {
// The type containing this function wasn't loaded yet // The type containing this function wasn't loaded yet
uint classToken = corFunction.GetClass().GetToken(); uint classToken = corFunction.GetClass().GetToken();
var definition = ToTypeDefinitionReference(module, classToken).Resolve(new SimpleTypeResolveContext(module.Assembly)).GetDefinition(); var definition = ToTypeDefinitionReference(module, classToken).Resolve(new SimpleTypeResolveContext(module.Assembly)).GetDefinition();
if (definition == null) if (definition == null)
throw new InvalidOperationException("Could not find class for token " + classToken); 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 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)); return unresolvedMethod.Resolve(new SimpleTypeResolveContext(module.Assembly));
} }

6
src/Libraries/NRefactory/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -22,6 +22,8 @@
<DocumentationFile>bin\$(Configuration)\ICSharpCode.NRefactory.xml</DocumentationFile> <DocumentationFile>bin\$(Configuration)\ICSharpCode.NRefactory.xml</DocumentationFile>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<NoWarn>1591</NoWarn> <NoWarn>1591</NoWarn>
<TargetFrameworkProfile />
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' "> <PropertyGroup Condition=" '$(Platform)' == 'AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget> <PlatformTarget>AnyCPU</PlatformTarget>
@ -33,14 +35,14 @@
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<OutputPath>bin\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<Optimize>False</Optimize> <Optimize>False</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE;NET45</DefineConstants>
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>True</CheckForOverflowUnderflow>
<StartAction>Project</StartAction> <StartAction>Project</StartAction>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' "> <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<OutputPath>bin\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<Optimize>True</Optimize> <Optimize>True</Optimize>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE;NET45</DefineConstants>
<CheckForOverflowUnderflow>False</CheckForOverflowUnderflow> <CheckForOverflowUnderflow>False</CheckForOverflowUnderflow>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">

Loading…
Cancel
Save