提交 e00d2313 编写于 作者: C Charles Stoner

Merge pull request #5711 from cston/4106

Ignore ambiguous dynamic custom debug info

Custom debug info for dynamic locals and constants is associated by name and slot index,
where the slot index is 0 for constants. If there are multiple constants with the same name or
a constant matches the name of the first local (in separate scopes in each case), the custom
debug info is ambiguous, and is ignored.

Fixes #4106
...@@ -175,12 +175,19 @@ class Test ...@@ -175,12 +175,19 @@ class Test
{ {
public static void Main(string[] args) public static void Main(string[] args)
{ {
const dynamic d = null; {
const dynamic d = null;
const string c = null;
}
{
const dynamic c = null;
const dynamic d = null;
}
} }
}"; }";
var c = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.DebugDll); var c = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.DebugDll);
c.VerifyPdb(@" c.VerifyPdb(
<symbols> @"<symbols>
<methods> <methods>
<method containingType=""Test"" name=""Main"" parameterNames=""args""> <method containingType=""Test"" name=""Main"" parameterNames=""args"">
<customDebugInfo> <customDebugInfo>
...@@ -189,19 +196,148 @@ public static void Main(string[] args) ...@@ -189,19 +196,148 @@ public static void Main(string[] args)
</using> </using>
<dynamicLocals> <dynamicLocals>
<bucket flagCount=""1"" flags=""1"" slotId=""0"" localName=""d"" /> <bucket flagCount=""1"" flags=""1"" slotId=""0"" localName=""d"" />
<bucket flagCount=""1"" flags=""1"" slotId=""0"" localName=""c"" />
<bucket flagCount=""1"" flags=""1"" slotId=""0"" localName=""d"" />
</dynamicLocals> </dynamicLocals>
</customDebugInfo> </customDebugInfo>
<sequencePoints> <sequencePoints>
<entry offset=""0x0"" startLine=""5"" startColumn=""2"" endLine=""5"" endColumn=""3"" /> <entry offset=""0x0"" startLine=""5"" startColumn=""2"" endLine=""5"" endColumn=""3"" />
<entry offset=""0x1"" startLine=""7"" startColumn=""2"" endLine=""7"" endColumn=""3"" /> <entry offset=""0x1"" startLine=""6"" startColumn=""9"" endLine=""6"" endColumn=""10"" />
<entry offset=""0x2"" startLine=""9"" startColumn=""9"" endLine=""9"" endColumn=""10"" />
<entry offset=""0x3"" startLine=""10"" startColumn=""9"" endLine=""10"" endColumn=""10"" />
<entry offset=""0x4"" startLine=""13"" startColumn=""9"" endLine=""13"" endColumn=""10"" />
<entry offset=""0x5"" startLine=""14"" startColumn=""2"" endLine=""14"" endColumn=""3"" />
</sequencePoints> </sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x2""> <scope startOffset=""0x0"" endOffset=""0x6"">
<constant name=""d"" value=""null"" type=""Object"" /> <scope startOffset=""0x1"" endOffset=""0x3"">
<constant name=""d"" value=""null"" type=""Object"" />
<constant name=""c"" value=""null"" type=""String"" />
</scope>
<scope startOffset=""0x3"" endOffset=""0x5"">
<constant name=""c"" value=""null"" type=""Object"" />
<constant name=""d"" value=""null"" type=""Object"" />
</scope>
</scope> </scope>
</method> </method>
</methods> </methods>
</symbols> </symbols>");
"); }
[Fact]
public void EmitPDBDynamicDuplicateName()
{
string source = @"
class Test
{
public static void Main(string[] args)
{
{
dynamic a = null;
object b = null;
}
{
dynamic[] a = null;
dynamic b = null;
}
}
}";
var c = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.DebugDll);
c.VerifyPdb(
@"<symbols>
<methods>
<method containingType=""Test"" name=""Main"" parameterNames=""args"">
<customDebugInfo>
<using>
<namespace usingCount=""0"" />
</using>
<dynamicLocals>
<bucket flagCount=""1"" flags=""1"" slotId=""0"" localName=""a"" />
<bucket flagCount=""2"" flags=""01"" slotId=""2"" localName=""a"" />
<bucket flagCount=""1"" flags=""1"" slotId=""3"" localName=""b"" />
</dynamicLocals>
<encLocalSlotMap>
<slot kind=""0"" offset=""34"" />
<slot kind=""0"" offset=""64"" />
<slot kind=""0"" offset=""119"" />
<slot kind=""0"" offset=""150"" />
</encLocalSlotMap>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""5"" startColumn=""2"" endLine=""5"" endColumn=""3"" />
<entry offset=""0x1"" startLine=""6"" startColumn=""9"" endLine=""6"" endColumn=""10"" />
<entry offset=""0x2"" startLine=""7"" startColumn=""13"" endLine=""7"" endColumn=""30"" />
<entry offset=""0x4"" startLine=""8"" startColumn=""13"" endLine=""8"" endColumn=""29"" />
<entry offset=""0x6"" startLine=""9"" startColumn=""9"" endLine=""9"" endColumn=""10"" />
<entry offset=""0x7"" startLine=""10"" startColumn=""9"" endLine=""10"" endColumn=""10"" />
<entry offset=""0x8"" startLine=""11"" startColumn=""13"" endLine=""11"" endColumn=""32"" />
<entry offset=""0xa"" startLine=""12"" startColumn=""13"" endLine=""12"" endColumn=""30"" />
<entry offset=""0xc"" startLine=""13"" startColumn=""9"" endLine=""13"" endColumn=""10"" />
<entry offset=""0xd"" startLine=""14"" startColumn=""2"" endLine=""14"" endColumn=""3"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0xe"">
<scope startOffset=""0x1"" endOffset=""0x7"">
<local name=""a"" il_index=""0"" il_start=""0x1"" il_end=""0x7"" attributes=""0"" />
<local name=""b"" il_index=""1"" il_start=""0x1"" il_end=""0x7"" attributes=""0"" />
</scope>
<scope startOffset=""0x7"" endOffset=""0xd"">
<local name=""a"" il_index=""2"" il_start=""0x7"" il_end=""0xd"" attributes=""0"" />
<local name=""b"" il_index=""3"" il_start=""0x7"" il_end=""0xd"" attributes=""0"" />
</scope>
</scope>
</method>
</methods>
</symbols>");
}
[Fact]
public void EmitPDBDynamicVariableNameTooLong()
{
string source = @"
class Test
{
public static void Main(string[] args)
{
const dynamic a123456789012345678901234567890123456789012345678901234567890123 = null; // 64 chars
const dynamic b12345678901234567890123456789012345678901234567890123456789012 = null; // 63 chars
dynamic c123456789012345678901234567890123456789012345678901234567890123 = null; // 64 chars
dynamic d12345678901234567890123456789012345678901234567890123456789012 = null; // 63 chars
}
}";
var c = CreateCompilationWithMscorlibAndSystemCore(source, options: TestOptions.DebugDll);
c.VerifyPdb(
@"<symbols>
<methods>
<method containingType=""Test"" name=""Main"" parameterNames=""args"">
<customDebugInfo>
<using>
<namespace usingCount=""0"" />
</using>
<dynamicLocals>
<bucket flagCount=""0"" flags="""" slotId=""0"" localName="""" />
<bucket flagCount=""1"" flags=""1"" slotId=""1"" localName=""d12345678901234567890123456789012345678901234567890123456789012"" />
<bucket flagCount=""0"" flags="""" slotId=""0"" localName="""" />
<bucket flagCount=""1"" flags=""1"" slotId=""0"" localName=""b12345678901234567890123456789012345678901234567890123456789012"" />
</dynamicLocals>
<encLocalSlotMap>
<slot kind=""0"" offset=""234"" />
<slot kind=""0"" offset=""336"" />
</encLocalSlotMap>
</customDebugInfo>
<sequencePoints>
<entry offset=""0x0"" startLine=""5"" startColumn=""2"" endLine=""5"" endColumn=""3"" />
<entry offset=""0x1"" startLine=""8"" startColumn=""9"" endLine=""8"" endColumn=""89"" />
<entry offset=""0x3"" startLine=""9"" startColumn=""9"" endLine=""9"" endColumn=""88"" />
<entry offset=""0x5"" startLine=""10"" startColumn=""2"" endLine=""10"" endColumn=""3"" />
</sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x6"">
<local name=""c123456789012345678901234567890123456789012345678901234567890123"" il_index=""0"" il_start=""0x0"" il_end=""0x6"" attributes=""0"" />
<local name=""d12345678901234567890123456789012345678901234567890123456789012"" il_index=""1"" il_start=""0x0"" il_end=""0x6"" attributes=""0"" />
<constant name=""a123456789012345678901234567890123456789012345678901234567890123"" value=""null"" type=""Object"" />
<constant name=""b12345678901234567890123456789012345678901234567890123456789012"" value=""null"" type=""Object"" />
</scope>
</method>
</methods>
</symbols>");
} }
[Fact] [Fact]
......
...@@ -217,18 +217,18 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild ...@@ -217,18 +217,18 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild
foreach (ILocalDefinition local in methodBody.LocalVariables) foreach (ILocalDefinition local in methodBody.LocalVariables)
{ {
Debug.Assert(local.SlotIndex >= 0);
if (local.IsDynamic) if (local.IsDynamic)
{ {
dynamicLocals.Add(local); dynamicLocals.Add(local);
} }
} }
int dynamicVariableCount = dynamicLocals.Count;
foreach (var currentScope in methodBody.LocalScopes) foreach (var currentScope in methodBody.LocalScopes)
{ {
foreach (var localConstant in currentScope.Constants) foreach (var localConstant in currentScope.Constants)
{ {
Debug.Assert(localConstant.SlotIndex < 0);
if (localConstant.IsDynamic) if (localConstant.IsDynamic)
{ {
dynamicLocals.Add(localConstant); dynamicLocals.Add(localConstant);
...@@ -238,7 +238,9 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild ...@@ -238,7 +238,9 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild
Debug.Assert(dynamicLocals.Any()); // There must be at least one dynamic local if this point is reached Debug.Assert(dynamicLocals.Any()); // There must be at least one dynamic local if this point is reached
const int blobSize = 200;//DynamicAttribute - 64, DynamicAttributeLength - 4, SlotIndex -4, IdentifierName - 128 const int dynamicAttributeSize = 64;
const int identifierSize = 64;
const int blobSize = dynamicAttributeSize + 4 + 4 + identifierSize * 2;//DynamicAttribute: 64, DynamicAttributeLength: 4, SlotIndex: 4, IdentifierName: 128
var cmw = new BlobBuilder(); var cmw = new BlobBuilder();
cmw.WriteByte(CDI.CdiVersion); cmw.WriteByte(CDI.CdiVersion);
cmw.WriteByte(CDI.CdiKindDynamicLocals); cmw.WriteByte(CDI.CdiKindDynamicLocals);
...@@ -247,19 +249,18 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild ...@@ -247,19 +249,18 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild
cmw.WriteUInt32(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block cmw.WriteUInt32(4 + 4 + 4 + (uint)dynamicLocals.Count * blobSize);//Size of the Dynamic Block
cmw.WriteUInt32((uint)dynamicLocals.Count); cmw.WriteUInt32((uint)dynamicLocals.Count);
int localIndex = 0;
foreach (ILocalDefinition local in dynamicLocals) foreach (ILocalDefinition local in dynamicLocals)
{ {
if (local.Name.Length > 63)//Ignore and push empty information if (local.Name.Length >= identifierSize)//Ignore and push empty information
{ {
cmw.WriteBytes(0, blobSize); cmw.WriteBytes(0, blobSize);
continue; continue;
} }
var dynamicTransformFlags = local.DynamicTransformFlags; var dynamicTransformFlags = local.DynamicTransformFlags;
if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= 64) if (!dynamicTransformFlags.IsDefault && dynamicTransformFlags.Length <= dynamicAttributeSize)
{ {
byte[] flag = new byte[64]; byte[] flag = new byte[dynamicAttributeSize];
for (int k = 0; k < dynamicTransformFlags.Length; k++) for (int k = 0; k < dynamicTransformFlags.Length; k++)
{ {
if ((bool)dynamicTransformFlags[k].Value) if ((bool)dynamicTransformFlags[k].Value)
...@@ -272,25 +273,15 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild ...@@ -272,25 +273,15 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild
} }
else else
{ {
cmw.WriteBytes(0, 68); //Empty flag array and size. cmw.WriteBytes(0, dynamicAttributeSize + 4); //Empty flag array and size.
} }
if (localIndex < dynamicVariableCount) var localIndex = local.SlotIndex;
{ cmw.WriteUInt32((localIndex < 0) ? 0u : (uint)localIndex);
// Dynamic variable
cmw.WriteUInt32((uint)local.SlotIndex);
}
else
{
// Dynamic constant
cmw.WriteUInt32(0);
}
char[] localName = new char[64]; char[] localName = new char[identifierSize];
local.Name.CopyTo(0, localName, 0, local.Name.Length); local.Name.CopyTo(0, localName, 0, local.Name.Length);
cmw.WriteUTF16(localName); cmw.WriteUTF16(localName);
localIndex++;
} }
dynamicLocals.Free(); dynamicLocals.Free();
......
...@@ -189,7 +189,6 @@ internal sealed class EvaluationContext : EvaluationContextBase ...@@ -189,7 +189,6 @@ internal sealed class EvaluationContext : EvaluationContextBase
var containingScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance(); var containingScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes); typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes);
var methodContextReuseConstraints = allScopes.GetReuseConstraints(moduleVersionId, methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive); var methodContextReuseConstraints = allScopes.GetReuseConstraints(moduleVersionId, methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive);
allScopes.Free();
var localNames = containingScopes.GetLocalNames(); var localNames = containingScopes.GetLocalNames();
...@@ -201,7 +200,7 @@ internal sealed class EvaluationContext : EvaluationContextBase ...@@ -201,7 +200,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
try try
{ {
// TODO (https://github.com/dotnet/roslyn/issues/702): switch on the type of typedSymReader and call the appropriate helper. // TODO (https://github.com/dotnet/roslyn/issues/702): switch on the type of typedSymReader and call the appropriate helper.
methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion, localNames.FirstOrDefault()); methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion, allScopes);
var inScopeHoistedLocalIndices = methodDebugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref methodContextReuseConstraints); var inScopeHoistedLocalIndices = methodDebugInfo.GetInScopeHoistedLocalIndices(ilOffset, ref methodContextReuseConstraints);
inScopeHoistedLocals = new CSharpInScopeHoistedLocals(inScopeHoistedLocalIndices); inScopeHoistedLocals = new CSharpInScopeHoistedLocals(inScopeHoistedLocalIndices);
} }
...@@ -211,6 +210,8 @@ internal sealed class EvaluationContext : EvaluationContextBase ...@@ -211,6 +210,8 @@ internal sealed class EvaluationContext : EvaluationContextBase
} }
} }
allScopes.Free();
var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken);
var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle); var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle);
Debug.Assert((object)currentFrame != null); Debug.Assert((object)currentFrame != null);
...@@ -502,7 +503,7 @@ private static MethodSymbol GetSynthesizedMethod(CommonPEModuleBuilder moduleBui ...@@ -502,7 +503,7 @@ private static MethodSymbol GetSynthesizedMethod(CommonPEModuleBuilder moduleBui
private static void GetConstants( private static void GetConstants(
ArrayBuilder<LocalSymbol> builder, ArrayBuilder<LocalSymbol> builder,
MethodSymbol method, MethodSymbol method,
IEnumerable<ISymUnmanagedScope> scopes, ArrayBuilder<ISymUnmanagedScope> scopes,
MetadataDecoder metadataDecoder, MetadataDecoder metadataDecoder,
ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap, ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap,
SourceAssemblySymbol containingAssembly) SourceAssemblySymbol containingAssembly)
......
...@@ -15,7 +15,7 @@ internal static class SymUnmanagedReaderExtensions ...@@ -15,7 +15,7 @@ internal static class SymUnmanagedReaderExtensions
this ISymUnmanagedReader reader, this ISymUnmanagedReader reader,
int methodToken, int methodToken,
int methodVersion, int methodVersion,
string firstLocalName) ArrayBuilder<ISymUnmanagedScope> scopes)
{ {
ImmutableArray<string> externAliasStrings; ImmutableArray<string> externAliasStrings;
var importStringGroups = reader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings); var importStringGroups = reader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings);
...@@ -95,7 +95,7 @@ internal static class SymUnmanagedReaderExtensions ...@@ -95,7 +95,7 @@ internal static class SymUnmanagedReaderExtensions
customDebugInfoBytes, customDebugInfoBytes,
methodToken, methodToken,
methodVersion, methodVersion,
firstLocalName, scopes,
out dynamicLocalMap, out dynamicLocalMap,
out dynamicLocalConstantMap); out dynamicLocalConstantMap);
} }
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Debugger.Clr; using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation; using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
...@@ -48,7 +45,7 @@ static dynamic ForceDynamicAttribute() ...@@ -48,7 +45,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind); Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x01); VerifyCustomTypeInfo(locals[0], "d", 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -57,6 +54,7 @@ .maxstack 1 ...@@ -57,6 +54,7 @@ .maxstack 1
IL_0000: ldloc.0 IL_0000: ldloc.0
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -86,7 +84,7 @@ static dynamic ForceDynamicAttribute() ...@@ -86,7 +84,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, ((ArrayTypeSymbol)method.ReturnType).ElementType.TypeKind); Assert.Equal(TypeKind.Dynamic, ((ArrayTypeSymbol)method.ReturnType).ElementType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x02); VerifyCustomTypeInfo(locals[0], "d", 0x02);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -95,6 +93,7 @@ .maxstack 1 ...@@ -95,6 +93,7 @@ .maxstack 1
IL_0000: ldloc.0 IL_0000: ldloc.0
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -124,7 +123,7 @@ static dynamic ForceDynamicAttribute() ...@@ -124,7 +123,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, ((NamedTypeSymbol)method.ReturnType).TypeArguments.Single().TypeKind); Assert.Equal(TypeKind.Dynamic, ((NamedTypeSymbol)method.ReturnType).TypeArguments.Single().TypeKind);
VerifyCustomTypeInfo(locals[0], 0x02); VerifyCustomTypeInfo(locals[0], "d", 0x02);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -133,6 +132,7 @@ .maxstack 1 ...@@ -133,6 +132,7 @@ .maxstack 1
IL_0000: ldloc.0 IL_0000: ldloc.0
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -168,7 +168,7 @@ static dynamic ForceDynamicAttribute() ...@@ -168,7 +168,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind); Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x01); VerifyCustomTypeInfo(locals[0], "d", 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedFlags: DkmClrCompilationResultFlags.ReadOnlyResult, expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedFlags: DkmClrCompilationResultFlags.ReadOnlyResult, expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -176,6 +176,7 @@ .maxstack 1 ...@@ -176,6 +176,7 @@ .maxstack 1
IL_0000: ldnull IL_0000: ldnull
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -211,7 +212,7 @@ static dynamic ForceDynamicAttribute() ...@@ -211,7 +212,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, ((ArrayTypeSymbol)method.ReturnType).ElementType.TypeKind); Assert.Equal(TypeKind.Dynamic, ((ArrayTypeSymbol)method.ReturnType).ElementType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x02); VerifyCustomTypeInfo(locals[0], "d", 0x02);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedFlags: DkmClrCompilationResultFlags.ReadOnlyResult, expectedILOpt: @" VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedFlags: DkmClrCompilationResultFlags.ReadOnlyResult, expectedILOpt: @"
{ {
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -219,6 +220,7 @@ .maxstack 1 ...@@ -219,6 +220,7 @@ .maxstack 1
IL_0000: ldnull IL_0000: ldnull
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -259,7 +261,7 @@ class Generic<T> ...@@ -259,7 +261,7 @@ class Generic<T>
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, ((NamedTypeSymbol)method.ReturnType).TypeArguments.Single().TypeKind); Assert.Equal(TypeKind.Dynamic, ((NamedTypeSymbol)method.ReturnType).TypeArguments.Single().TypeKind);
VerifyCustomTypeInfo(locals[0], 0x02); VerifyCustomTypeInfo(locals[0], "d", 0x02);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedFlags: DkmClrCompilationResultFlags.ReadOnlyResult, expectedILOpt: @" VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedFlags: DkmClrCompilationResultFlags.ReadOnlyResult, expectedILOpt: @"
{ {
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -267,6 +269,265 @@ .maxstack 1 ...@@ -267,6 +269,265 @@ .maxstack 1
IL_0000: ldnull IL_0000: ldnull
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
}
[WorkItem(4106)]
[Fact]
public void LocalDuplicateConstantAndNonConstantDynamic()
{
var source =
@"class C
{
static void M()
{
{
#line 799
dynamic a = null;
const dynamic b = null;
}
{
const dynamic[] a = null;
#line 899
dynamic[] b = null;
}
}
}";
var compilation0 = CreateCompilationWithMscorlib(
source,
options: TestOptions.DebugDll,
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName());
var runtime = CreateRuntimeInstance(compilation0);
var context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 799);
var testData = new CompilationTestData();
var locals = ArrayBuilder<LocalAndMethod>.GetInstance();
string typeName;
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(2, locals.Count);
VerifyCustomTypeInfo(locals[0], "a", null); // Dynamic info ignored because ambiguous.
VerifyCustomTypeInfo(locals[1], "b", 0x01);
locals.Free();
context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 899);
testData = new CompilationTestData();
locals = ArrayBuilder<LocalAndMethod>.GetInstance();
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(2, locals.Count);
VerifyCustomTypeInfo(locals[0], "b", 0x02);
VerifyCustomTypeInfo(locals[1], "a", null); // Dynamic info ignored because ambiguous.
locals.Free();
}
[WorkItem(4106)]
[Fact]
public void LocalDuplicateConstantAndNonConstantNonDynamic()
{
var source =
@"class C
{
static void M()
{
{
#line 799
object a = null;
const dynamic b = null;
}
{
const dynamic[] a = null;
#line 899
object[] b = null;
}
}
}";
var compilation0 = CreateCompilationWithMscorlib(
source,
options: TestOptions.DebugDll,
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName());
var runtime = CreateRuntimeInstance(compilation0);
var context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 799);
var testData = new CompilationTestData();
var locals = ArrayBuilder<LocalAndMethod>.GetInstance();
string typeName;
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(2, locals.Count);
VerifyCustomTypeInfo(locals[0], "a", null);
VerifyCustomTypeInfo(locals[1], "b", 0x01);
locals.Free();
context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 899);
testData = new CompilationTestData();
locals = ArrayBuilder<LocalAndMethod>.GetInstance();
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(2, locals.Count);
VerifyCustomTypeInfo(locals[0], "b", null);
VerifyCustomTypeInfo(locals[1], "a", null); // Dynamic info ignored because ambiguous.
locals.Free();
}
[WorkItem(4106)]
[Fact]
public void LocalDuplicateConstantAndConstantDynamic()
{
var source =
@"class C
{
static void M()
{
{
const dynamic a = null;
const dynamic b = null;
#line 799
object e = null;
}
{
const dynamic[] a = null;
const dynamic[] c = null;
#line 899
object[] e = null;
}
{
#line 999
object e = null;
const dynamic a = null;
const dynamic c = null;
}
}
}";
var compilation0 = CreateCompilationWithMscorlib(
source,
options: TestOptions.DebugDll,
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName());
var runtime = CreateRuntimeInstance(compilation0);
var context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 799);
var testData = new CompilationTestData();
var locals = ArrayBuilder<LocalAndMethod>.GetInstance();
string typeName;
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(3, locals.Count);
VerifyCustomTypeInfo(locals[0], "e", null);
VerifyCustomTypeInfo(locals[1], "a", null); // Dynamic info ignored because ambiguous.
VerifyCustomTypeInfo(locals[2], "b", 0x01);
locals.Free();
context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 899);
testData = new CompilationTestData();
locals = ArrayBuilder<LocalAndMethod>.GetInstance();
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(3, locals.Count);
VerifyCustomTypeInfo(locals[0], "e", null);
VerifyCustomTypeInfo(locals[1], "a", null); // Dynamic info ignored because ambiguous.
VerifyCustomTypeInfo(locals[2], "c", null); // Dynamic info ignored because ambiguous.
locals.Free();
context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 999);
testData = new CompilationTestData();
locals = ArrayBuilder<LocalAndMethod>.GetInstance();
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(3, locals.Count);
VerifyCustomTypeInfo(locals[0], "e", null);
VerifyCustomTypeInfo(locals[1], "a", null); // Dynamic info ignored because ambiguous.
VerifyCustomTypeInfo(locals[2], "c", null); // Dynamic info ignored because ambiguous.
locals.Free();
}
[WorkItem(4106)]
[Fact]
public void LocalDuplicateConstantAndConstantNonDynamic()
{
var source =
@"class C
{
static void M()
{
{
const dynamic a = null;
const object c = null;
#line 799
object e = null;
}
{
const dynamic[] b = null;
#line 899
object[] e = null;
}
{
const object[] a = null;
#line 999
object e = null;
const dynamic[] c = null;
}
}
}";
var compilation0 = CreateCompilationWithMscorlib(
source,
options: TestOptions.DebugDll,
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName());
var runtime = CreateRuntimeInstance(compilation0);
var context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 799);
var testData = new CompilationTestData();
var locals = ArrayBuilder<LocalAndMethod>.GetInstance();
string typeName;
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(3, locals.Count);
VerifyCustomTypeInfo(locals[0], "e", null);
VerifyCustomTypeInfo(locals[1], "a", null); // Dynamic info ignored because ambiguous.
VerifyCustomTypeInfo(locals[2], "c", null);
locals.Free();
context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 899);
testData = new CompilationTestData();
locals = ArrayBuilder<LocalAndMethod>.GetInstance();
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(2, locals.Count);
VerifyCustomTypeInfo(locals[0], "e", null);
VerifyCustomTypeInfo(locals[1], "b", 0x02);
locals.Free();
context = CreateMethodContext(runtime, methodName: "C.M", atLineNumber: 999);
testData = new CompilationTestData();
locals = ArrayBuilder<LocalAndMethod>.GetInstance();
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(3, locals.Count);
VerifyCustomTypeInfo(locals[0], "e", null);
VerifyCustomTypeInfo(locals[1], "a", null);
VerifyCustomTypeInfo(locals[2], "c", null); // Dynamic info ignored because ambiguous.
locals.Free();
}
[Fact]
public void LocalsWithLongAndShortNames()
{
var source =
@"class C
{
static void M()
{
const dynamic a123456789012345678901234567890123456789012345678901234567890123 = null; // 64 chars
const dynamic b = null;
dynamic c123456789012345678901234567890123456789012345678901234567890123 = null; // 64 chars
dynamic d = null;
}
}";
var compilation0 = CreateCompilationWithMscorlib(
source,
options: TestOptions.DebugDll,
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName());
var runtime = CreateRuntimeInstance(compilation0);
var context = CreateMethodContext(runtime, methodName: "C.M");
var testData = new CompilationTestData();
var locals = ArrayBuilder<LocalAndMethod>.GetInstance();
string typeName;
context.CompileGetLocals(locals, argumentsOnly: false, typeName: out typeName, testData: testData);
Assert.Equal(4, locals.Count);
VerifyCustomTypeInfo(locals[0], "c123456789012345678901234567890123456789012345678901234567890123", null); // dynamic info dropped
VerifyCustomTypeInfo(locals[1], "d", 0x01);
VerifyCustomTypeInfo(locals[2], "a123456789012345678901234567890123456789012345678901234567890123", null); // dynamic info dropped
VerifyCustomTypeInfo(locals[3], "b", 0x01);
locals.Free();
} }
[Fact] [Fact]
...@@ -295,7 +556,7 @@ static dynamic ForceDynamicAttribute() ...@@ -295,7 +556,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind); Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x01); VerifyCustomTypeInfo(locals[0], "d", 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -303,6 +564,7 @@ .maxstack 1 ...@@ -303,6 +564,7 @@ .maxstack 1
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -331,7 +593,7 @@ static dynamic ForceDynamicAttribute() ...@@ -331,7 +593,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, ((ArrayTypeSymbol)method.ReturnType).ElementType.TypeKind); Assert.Equal(TypeKind.Dynamic, ((ArrayTypeSymbol)method.ReturnType).ElementType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x02); VerifyCustomTypeInfo(locals[0], "d", 0x02);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -339,6 +601,7 @@ .maxstack 1 ...@@ -339,6 +601,7 @@ .maxstack 1
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -367,7 +630,7 @@ static dynamic ForceDynamicAttribute() ...@@ -367,7 +630,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, ((NamedTypeSymbol)method.ReturnType).TypeArguments.Single().TypeKind); Assert.Equal(TypeKind.Dynamic, ((NamedTypeSymbol)method.ReturnType).TypeArguments.Single().TypeKind);
VerifyCustomTypeInfo(locals[0], 0x02); VerifyCustomTypeInfo(locals[0], "d", 0x02);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -375,6 +638,7 @@ .maxstack 1 ...@@ -375,6 +638,7 @@ .maxstack 1
IL_0000: ldarg.0 IL_0000: ldarg.0
IL_0001: ret IL_0001: ret
}"); }");
locals.Free();
} }
[WorkItem(1087216, "DevDiv")] [WorkItem(1087216, "DevDiv")]
...@@ -411,7 +675,7 @@ public class Inner<V, W> ...@@ -411,7 +675,7 @@ public class Inner<V, W>
Assert.Equal(1, locals.Count); Assert.Equal(1, locals.Count);
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method); AssertHasDynamicAttribute(method);
VerifyCustomTypeInfo(locals[0], 0x04, 0x03); VerifyCustomTypeInfo(locals[0], "d", 0x04, 0x03);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{ @"{
// Code size 2 (0x2) // Code size 2 (0x2)
...@@ -473,6 +737,7 @@ .maxstack 7 ...@@ -473,6 +737,7 @@ .maxstack 7
IL_0037: stind.ref IL_0037: stind.ref
IL_0038: ret IL_0038: ret
}"); }");
locals.Free();
} }
[Fact] [Fact]
...@@ -521,7 +786,7 @@ static void M() ...@@ -521,7 +786,7 @@ static void M()
diagnostics.Free(); diagnostics.Free();
Assert.Equal(locals.Count, 2); Assert.Equal(locals.Count, 2);
VerifyCustomTypeInfo(locals[0], 0x01); VerifyCustomTypeInfo(locals[0], "d1", 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d1", expectedILOpt: VerifyLocal(testData, typeName, locals[0], "<>m0", "d1", expectedILOpt:
@"{ @"{
// Code size 11 (0xb) // Code size 11 (0xb)
...@@ -531,7 +796,7 @@ .maxstack 1 ...@@ -531,7 +796,7 @@ .maxstack 1
IL_000a: ret IL_000a: ret
}"); }");
VerifyCustomTypeInfo(locals[1], 0x84, 0x00); // Note: read flags right-to-left in each byte: 0010 0001 0(000 0000) VerifyCustomTypeInfo(locals[1], "d2", 0x84, 0x00); // Note: read flags right-to-left in each byte: 0010 0001 0(000 0000)
VerifyLocal(testData, typeName, locals[1], "<>m1", "d2", expectedILOpt: VerifyLocal(testData, typeName, locals[1], "<>m1", "d2", expectedILOpt:
@"{ @"{
// Code size 16 (0x10) // Code size 16 (0x10)
...@@ -572,6 +837,7 @@ static void M() ...@@ -572,6 +837,7 @@ static void M()
Assert.Equal(1, locals.Count); Assert.Equal(1, locals.Count);
var method = testData.Methods.Single().Value.Method; var method = testData.Methods.Single().Value.Method;
AssertHasNoDynamicAttribute(method); AssertHasNoDynamicAttribute(method);
locals.Free();
} }
private static void AssertHasDynamicAttribute(IMethodSymbol method) private static void AssertHasDynamicAttribute(IMethodSymbol method)
...@@ -1118,8 +1384,9 @@ .maxstack 11 ...@@ -1118,8 +1384,9 @@ .maxstack 11
}"); }");
} }
private static void VerifyCustomTypeInfo(LocalAndMethod localAndMethod, params byte[] expectedBytes) private static void VerifyCustomTypeInfo(LocalAndMethod localAndMethod, string expectedName, params byte[] expectedBytes)
{ {
Assert.Equal(localAndMethod.LocalName, expectedName);
VerifyCustomTypeInfo(localAndMethod.GetCustomTypeInfo(), expectedBytes); VerifyCustomTypeInfo(localAndMethod.GetCustomTypeInfo(), expectedBytes);
} }
......
...@@ -590,7 +590,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ...@@ -590,7 +590,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Private Shared Sub GetConstants( Private Shared Sub GetConstants(
builder As ArrayBuilder(Of LocalSymbol), builder As ArrayBuilder(Of LocalSymbol),
method As MethodSymbol, method As MethodSymbol,
scopes As IEnumerable(Of ISymUnmanagedScope), scopes As ArrayBuilder(Of ISymUnmanagedScope),
metadataDecoder As MetadataDecoder) metadataDecoder As MetadataDecoder)
For Each scope In scopes For Each scope In scopes
......
...@@ -283,7 +283,7 @@ private void WriteCustomDebugInfo(byte[] bytes) ...@@ -283,7 +283,7 @@ private void WriteCustomDebugInfo(byte[] bytes)
WriteForwardToModuleCustomDebugInfo(record); WriteForwardToModuleCustomDebugInfo(record);
break; break;
case CustomDebugInfoKind.StateMachineHoistedLocalScopes: case CustomDebugInfoKind.StateMachineHoistedLocalScopes:
WriteStatemachineHoistedLocalScopesCustomDebugInfo(record); WriteStateMachineHoistedLocalScopesCustomDebugInfo(record);
break; break;
case CustomDebugInfoKind.ForwardIterator: case CustomDebugInfoKind.ForwardIterator:
WriteForwardIteratorCustomDebugInfo(record); WriteForwardIteratorCustomDebugInfo(record);
...@@ -402,7 +402,7 @@ private void WriteForwardToModuleCustomDebugInfo(CustomDebugInfoRecord record) ...@@ -402,7 +402,7 @@ private void WriteForwardToModuleCustomDebugInfo(CustomDebugInfoRecord record)
/// <remarks> /// <remarks>
/// Appears when there are locals in iterator methods. /// Appears when there are locals in iterator methods.
/// </remarks> /// </remarks>
private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoRecord record) private void WriteStateMachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoRecord record)
{ {
Debug.Assert(record.Kind == CustomDebugInfoKind.StateMachineHoistedLocalScopes); Debug.Assert(record.Kind == CustomDebugInfoKind.StateMachineHoistedLocalScopes);
...@@ -415,7 +415,7 @@ private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoR ...@@ -415,7 +415,7 @@ private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoR
_writer.WriteStartElement("slot"); _writer.WriteStartElement("slot");
_writer.WriteAttributeString("startOffset", AsILOffset(scope.StartOffset)); _writer.WriteAttributeString("startOffset", AsILOffset(scope.StartOffset));
_writer.WriteAttributeString("endOffset", AsILOffset(scope.EndOffset)); _writer.WriteAttributeString("endOffset", AsILOffset(scope.EndOffset));
_writer.WriteEndElement(); //bucket _writer.WriteEndElement(); //slot
} }
_writer.WriteEndElement(); _writer.WriteEndElement();
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using System.Linq;
using Microsoft.CodeAnalysis.Collections; using Microsoft.CodeAnalysis.Collections;
using Microsoft.DiaSymReader; using Microsoft.DiaSymReader;
using CDI = Microsoft.Cci.CustomDebugInfoConstants; using CDI = Microsoft.Cci.CustomDebugInfoConstants;
...@@ -479,7 +480,7 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana ...@@ -479,7 +480,7 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana
byte[] customDebugInfo, byte[] customDebugInfo,
int methodToken, int methodToken,
int methodVersion, int methodVersion,
string firstLocalName, ArrayBuilder<ISymUnmanagedScope> scopes,
out ImmutableDictionary<int, ImmutableArray<bool>> dynamicLocalMap, out ImmutableDictionary<int, ImmutableArray<bool>> dynamicLocalMap,
out ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap) out ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap)
{ {
...@@ -495,30 +496,20 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana ...@@ -495,30 +496,20 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana
ImmutableDictionary<int, ImmutableArray<bool>>.Builder localBuilder = null; ImmutableDictionary<int, ImmutableArray<bool>>.Builder localBuilder = null;
ImmutableDictionary<string, ImmutableArray<bool>>.Builder constantBuilder = null; ImmutableDictionary<string, ImmutableArray<bool>>.Builder constantBuilder = null;
foreach (DynamicLocalBucket bucket in DecodeDynamicLocalsRecord(record)) var buckets = RemoveAmbiguousLocals(DecodeDynamicLocalsRecord(record), scopes);
foreach (var bucket in buckets)
{ {
int flagCount = bucket.FlagCount;
ulong flags = bucket.Flags;
ArrayBuilder<bool> dynamicBuilder = ArrayBuilder<bool>.GetInstance(flagCount);
for (int i = 0; i < flagCount; i++)
{
dynamicBuilder.Add((flags & (1u << i)) != 0);
}
var slot = bucket.SlotId; var slot = bucket.SlotId;
var name = bucket.Name; var flags = GetFlags(bucket);
if (slot < 0)
// All constants have slot 0, but none of them can have the same name
// as the local that is actually in slot 0 (if there is one).
if (slot == 0 && (firstLocalName == null || firstLocalName != name))
{ {
constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder<string, ImmutableArray<bool>>(); constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder<string, ImmutableArray<bool>>();
constantBuilder.Add(name, dynamicBuilder.ToImmutableAndFree()); constantBuilder.Add(bucket.Name, flags);
} }
else else
{ {
localBuilder = localBuilder ?? ImmutableDictionary.CreateBuilder<int, ImmutableArray<bool>>(); localBuilder = localBuilder ?? ImmutableDictionary.CreateBuilder<int, ImmutableArray<bool>>();
localBuilder.Add(slot, dynamicBuilder.ToImmutableAndFree()); localBuilder.Add(slot, flags);
} }
} }
...@@ -533,6 +524,83 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana ...@@ -533,6 +524,83 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana
} }
} }
/// <summary>
/// If there dynamic locals or constants 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,
ArrayBuilder<ISymUnmanagedScope> scopes)
{
var localsAndConstants = PooledDictionary<string, object>.GetInstance();
var firstLocal = GetFirstLocal(scopes);
if (firstLocal != null)
{
localsAndConstants.Add(firstLocal.GetName(), firstLocal);
}
foreach (var scope in scopes)
{
foreach (var constant in scope.GetConstants())
{
var name = constant.GetName();
localsAndConstants[name] = localsAndConstants.ContainsKey(name) ? null : constant;
}
}
var builder = ArrayBuilder<DynamicLocalBucket>.GetInstance();
foreach (var local in locals)
{
int slot = local.SlotId;
var name = local.Name;
if (slot == 0)
{
object localOrConstant;
localsAndConstants.TryGetValue(name, out localOrConstant);
if (localOrConstant == null)
{
// Duplicate.
continue;
}
if (localOrConstant != firstLocal)
{
// Constant.
slot = -1;
}
}
builder.Add(new DynamicLocalBucket(local.FlagCount, local.Flags, slot, name));
}
var result = builder.ToImmutableAndFree();
localsAndConstants.Free();
return result;
}
private static ISymUnmanagedVariable GetFirstLocal(ArrayBuilder<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) private static void CheckVersion(byte globalVersion, int methodToken)
{ {
if (globalVersion != CDI.CdiVersion) if (globalVersion != CDI.CdiVersion)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册