提交 77e7b3af 编写于 作者: T Tomas Matousek

Move GetCSharpDynamicLocalInfo to EE

上级 8b893b5e
......@@ -6,6 +6,7 @@
using System.Diagnostics;
using System.Linq;
using System.Reflection.Metadata;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.DiaSymReader;
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
......@@ -264,7 +265,7 @@ private static bool TryCreateImportRecordFromCSharpImportString(EESymbolProvider
.SelectAsArray(s => new HoistedLocalScopeRecord(s.StartOffset, s.EndOffset - s.StartOffset + 1));
}
CustomDebugInfoReader.GetCSharpDynamicLocalInfo(
GetCSharpDynamicLocalInfo(
customDebugInfoBytes,
methodToken,
methodVersion,
......@@ -273,6 +274,128 @@ private static bool TryCreateImportRecordFromCSharpImportString(EESymbolProvider
out dynamicLocalConstantMap);
}
/// <exception cref="InvalidOperationException">Bad data.</exception>
private static void GetCSharpDynamicLocalInfo(
byte[] customDebugInfo,
int methodToken,
int methodVersion,
IEnumerable<ISymUnmanagedScope> scopes,
out ImmutableDictionary<int, ImmutableArray<bool>> dynamicLocalMap,
out ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap)
{
dynamicLocalMap = ImmutableDictionary<int, ImmutableArray<bool>>.Empty;
dynamicLocalConstantMap = ImmutableDictionary<string, ImmutableArray<bool>>.Empty;
var record = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfo, CustomDebugInfoKind.DynamicLocals);
if (record.IsDefault)
{
return;
}
ImmutableDictionary<int, ImmutableArray<bool>>.Builder localBuilder = null;
ImmutableDictionary<string, ImmutableArray<bool>>.Builder constantBuilder = null;
var dynamicLocals = RemoveAmbiguousLocals(CustomDebugInfoReader.DecodeDynamicLocalsRecord(record), scopes);
foreach (var dynamicLocal in dynamicLocals)
{
int slot = dynamicLocal.SlotId;
var flags = GetFlags(dynamicLocal);
if (slot < 0)
{
constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder<string, ImmutableArray<bool>>();
constantBuilder[dynamicLocal.Name] = flags;
}
else
{
localBuilder = localBuilder ?? ImmutableDictionary.CreateBuilder<int, ImmutableArray<bool>>();
localBuilder[slot] = flags;
}
}
if (localBuilder != null)
{
dynamicLocalMap = localBuilder.ToImmutable();
}
if (constantBuilder != null)
{
dynamicLocalConstantMap = constantBuilder.ToImmutable();
}
}
private static ImmutableArray<bool> GetFlags(DynamicLocalInfo bucket)
{
int flagCount = bucket.FlagCount;
ulong flags = bucket.Flags;
var builder = ArrayBuilder<bool>.GetInstance(flagCount);
for (int i = 0; i < flagCount; i++)
{
builder.Add((flags & (1u << i)) != 0);
}
return builder.ToImmutableAndFree();
}
/// <summary>
/// Dynamic CDI encodes slot id and name for each dynamic local variable, but only name for a constant.
/// Constants have slot id set to 0. As a result there is a potential for ambiguity. If a variable in a slot 0
/// and a constant defined anywhere in the method body have the same name we can't say which one
/// the dynamic flags belong to (if there is a dynamic record for at least one of them).
///
/// This method removes ambiguous dynamic records.
/// </summary>
private static ImmutableArray<DynamicLocalInfo> RemoveAmbiguousLocals(
ImmutableArray<DynamicLocalInfo> dynamicLocals,
IEnumerable<ISymUnmanagedScope> scopes)
{
const byte DuplicateName = 0;
const byte VariableName = 1;
const byte ConstantName = 2;
var localNames = PooledDictionary<string, byte>.GetInstance();
var firstLocal = scopes.SelectMany(scope => scope.GetLocals()).FirstOrDefault(variable => variable.GetSlot() == 0);
if (firstLocal != null)
{
localNames.Add(firstLocal.GetName(), VariableName);
}
foreach (var scope in scopes)
{
foreach (var constant in scope.GetConstants())
{
string name = constant.GetName();
localNames[name] = localNames.ContainsKey(name) ? DuplicateName : ConstantName;
}
}
var builder = ArrayBuilder<DynamicLocalInfo>.GetInstance();
foreach (var dynamicLocal in dynamicLocals)
{
int slot = dynamicLocal.SlotId;
var name = dynamicLocal.Name;
if (slot == 0)
{
byte localOrConstant;
localNames.TryGetValue(name, out localOrConstant);
if (localOrConstant == DuplicateName)
{
continue;
}
if (localOrConstant == ConstantName)
{
slot = -1;
}
}
builder.Add(new DynamicLocalInfo(dynamicLocal.FlagCount, dynamicLocal.Flags, slot, name));
}
var result = builder.ToImmutableAndFree();
localNames.Free();
return result;
}
private static void ReadVisualBasicImportsDebugInfo(
ISymUnmanagedReader reader,
int methodToken,
......
......@@ -453,12 +453,12 @@ private void WriteDynamicLocalsCustomDebugInfo(CustomDebugInfoRecord record)
_writer.WriteStartElement("dynamicLocals");
var buckets = CDI.DecodeDynamicLocalsRecord(record.Data);
var dynamicLocals = CDI.DecodeDynamicLocalsRecord(record.Data);
foreach (DynamicLocalBucket bucket in buckets)
foreach (DynamicLocalInfo dynamicLocal in dynamicLocals)
{
ulong flags = bucket.Flags;
int flagCount = bucket.FlagCount;
ulong flags = dynamicLocal.Flags;
int flagCount = dynamicLocal.FlagCount;
PooledStringBuilder pooled = PooledStringBuilder.GetInstance();
StringBuilder flagsBuilder = pooled.Builder;
......@@ -470,8 +470,8 @@ private void WriteDynamicLocalsCustomDebugInfo(CustomDebugInfoRecord record)
_writer.WriteStartElement("bucket");
_writer.WriteAttributeString("flagCount", CultureInvariantToString(flagCount));
_writer.WriteAttributeString("flags", pooled.ToStringAndFree());
_writer.WriteAttributeString("slotId", CultureInvariantToString(bucket.SlotId));
_writer.WriteAttributeString("localName", bucket.Name);
_writer.WriteAttributeString("slotId", CultureInvariantToString(dynamicLocal.SlotId));
_writer.WriteAttributeString("localName", dynamicLocal.Name);
_writer.WriteEndElement(); //bucket
}
......
......@@ -226,12 +226,12 @@ public static string DecodeForwardIteratorRecord(ImmutableArray<byte> bytes)
/// Exposed for <see cref="T:Roslyn.Test.PdbUtilities.PdbToXmlConverter"/>.
/// </remarks>
/// <exception cref="InvalidOperationException">Bad data.</exception>
public static ImmutableArray<DynamicLocalBucket> DecodeDynamicLocalsRecord(ImmutableArray<byte> bytes)
public static ImmutableArray<DynamicLocalInfo> DecodeDynamicLocalsRecord(ImmutableArray<byte> bytes)
{
int offset = 0;
int bucketCount = ReadInt32(bytes, ref offset);
var builder = ArrayBuilder<DynamicLocalBucket>.GetInstance(bucketCount);
var builder = ArrayBuilder<DynamicLocalInfo>.GetInstance(bucketCount);
for (int i = 0; i < bucketCount; i++)
{
const int FlagBytesCount = 64;
......@@ -269,8 +269,7 @@ public static ImmutableArray<DynamicLocalBucket> DecodeDynamicLocalsRecord(Immut
var name = pooled.ToStringAndFree();
var bucket = new DynamicLocalBucket(flagCount, flags, slotId, name);
builder.Add(bucket);
builder.Add(new DynamicLocalInfo(flagCount, flags, slotId, name));
}
return builder.ToImmutableAndFree();
......@@ -475,140 +474,6 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana
return importStrings;
}
/// <exception cref="InvalidOperationException">Bad data.</exception>
public static void GetCSharpDynamicLocalInfo(
byte[] customDebugInfo,
int methodToken,
int methodVersion,
IEnumerable<ISymUnmanagedScope> scopes,
out ImmutableDictionary<int, ImmutableArray<bool>> dynamicLocalMap,
out ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap)
{
dynamicLocalMap = ImmutableDictionary<int, ImmutableArray<bool>>.Empty;
dynamicLocalConstantMap = ImmutableDictionary<string, ImmutableArray<bool>>.Empty;
var record = TryGetCustomDebugInfoRecord(customDebugInfo, CustomDebugInfoKind.DynamicLocals);
if (record.IsDefault)
{
return;
}
ImmutableDictionary<int, ImmutableArray<bool>>.Builder localBuilder = null;
ImmutableDictionary<string, ImmutableArray<bool>>.Builder constantBuilder = null;
var buckets = RemoveAmbiguousLocals(DecodeDynamicLocalsRecord(record), scopes);
foreach (var bucket in buckets)
{
var slot = bucket.SlotId;
var flags = GetFlags(bucket);
if (slot < 0)
{
constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder<string, ImmutableArray<bool>>();
constantBuilder[bucket.Name] = flags;
}
else
{
localBuilder = localBuilder ?? ImmutableDictionary.CreateBuilder<int, ImmutableArray<bool>>();
localBuilder[slot] = flags;
}
}
if (localBuilder != null)
{
dynamicLocalMap = localBuilder.ToImmutable();
}
if (constantBuilder != null)
{
dynamicLocalConstantMap = constantBuilder.ToImmutable();
}
}
/// <summary>
/// If there are dynamic locals or constants associated with SlotId == 0, check all locals and
/// constants with SlotId == 0 for duplicate names and discard duplicates since we
/// cannot determine which local or constant the dynamic info is associated with.
/// </summary>
private static ImmutableArray<DynamicLocalBucket> RemoveAmbiguousLocals(
ImmutableArray<DynamicLocalBucket> locals,
IEnumerable<ISymUnmanagedScope> scopes)
{
const byte DuplicateName = 0;
const byte VariableName = 1;
const byte ConstantName = 2;
var localNames = PooledDictionary<string, byte>.GetInstance();
var firstLocal = GetFirstLocal(scopes);
if (firstLocal != null)
{
localNames.Add(firstLocal.GetName(), VariableName);
}
foreach (var scope in scopes)
{
foreach (var constant in scope.GetConstants())
{
var name = constant.GetName();
localNames[name] = localNames.ContainsKey(name) ? DuplicateName : ConstantName;
}
}
var builder = ArrayBuilder<DynamicLocalBucket>.GetInstance();
foreach (var local in locals)
{
int slot = local.SlotId;
var name = local.Name;
if (slot == 0)
{
byte localOrConstant;
localNames.TryGetValue(name, out localOrConstant);
if (localOrConstant == DuplicateName)
{
continue;
}
if (localOrConstant == ConstantName)
{
slot = -1;
}
}
builder.Add(new DynamicLocalBucket(local.FlagCount, local.Flags, slot, name));
}
var result = builder.ToImmutableAndFree();
localNames.Free();
return result;
}
private static ISymUnmanagedVariable GetFirstLocal(IEnumerable<ISymUnmanagedScope> scopes)
{
foreach (var scope in scopes)
{
foreach (var local in scope.GetLocals())
{
if (local.GetSlot() == 0)
{
return local;
}
}
}
return null;
}
private static ImmutableArray<bool> GetFlags(DynamicLocalBucket bucket)
{
int flagCount = bucket.FlagCount;
ulong flags = bucket.Flags;
var builder = ArrayBuilder<bool>.GetInstance(flagCount);
for (int i = 0; i < flagCount; i++)
{
builder.Add((flags & (1u << i)) != 0);
}
return builder.ToImmutableAndFree();
}
private static void CheckVersion(byte globalVersion, int methodToken)
{
if (globalVersion != CDI.CdiVersion)
......@@ -1032,14 +897,14 @@ public StateMachineHoistedLocalScope(int startoffset, int endOffset)
}
}
internal struct DynamicLocalBucket
internal struct DynamicLocalInfo
{
public readonly int FlagCount;
public readonly ulong Flags;
public readonly int SlotId;
public readonly string Name;
public DynamicLocalBucket(int flagCount, ulong flags, int slotId, string name)
public DynamicLocalInfo(int flagCount, ulong flags, int slotId, string name)
{
this.FlagCount = flagCount;
this.Flags = flags;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册