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

Ignore ambiguous dynamic custom debug info

上级 f1d5768d
......@@ -175,12 +175,19 @@ class Test
{
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);
c.VerifyPdb(@"
<symbols>
c.VerifyPdb(
@"<symbols>
<methods>
<method containingType=""Test"" name=""Main"" parameterNames=""args"">
<customDebugInfo>
......@@ -189,19 +196,148 @@ public static void Main(string[] args)
</using>
<dynamicLocals>
<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>
</customDebugInfo>
<sequencePoints>
<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>
<scope startOffset=""0x0"" endOffset=""0x2"">
<constant name=""d"" value=""null"" type=""Object"" />
<scope startOffset=""0x0"" endOffset=""0x6"">
<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>
</method>
</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]
......
......@@ -217,18 +217,18 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild
foreach (ILocalDefinition local in methodBody.LocalVariables)
{
Debug.Assert(local.SlotIndex >= 0);
if (local.IsDynamic)
{
dynamicLocals.Add(local);
}
}
int dynamicVariableCount = dynamicLocals.Count;
foreach (var currentScope in methodBody.LocalScopes)
{
foreach (var localConstant in currentScope.Constants)
{
Debug.Assert(localConstant.SlotIndex < 0);
if (localConstant.IsDynamic)
{
dynamicLocals.Add(localConstant);
......@@ -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
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();
cmw.WriteByte(CDI.CdiVersion);
cmw.WriteByte(CDI.CdiKindDynamicLocals);
......@@ -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((uint)dynamicLocals.Count);
int localIndex = 0;
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);
continue;
}
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++)
{
if ((bool)dynamicTransformFlags[k].Value)
......@@ -272,25 +273,15 @@ private static void SerializeDynamicLocalInfo(IMethodBody methodBody, ArrayBuild
}
else
{
cmw.WriteBytes(0, 68); //Empty flag array and size.
cmw.WriteBytes(0, dynamicAttributeSize + 4); //Empty flag array and size.
}
if (localIndex < dynamicVariableCount)
{
// Dynamic variable
cmw.WriteUInt32((uint)local.SlotIndex);
}
else
{
// Dynamic constant
cmw.WriteUInt32(0);
}
var localIndex = local.SlotIndex;
cmw.WriteUInt32((localIndex < 0) ? 0u : (uint)localIndex);
char[] localName = new char[64];
char[] localName = new char[identifierSize];
local.Name.CopyTo(0, localName, 0, local.Name.Length);
cmw.WriteUTF16(localName);
localIndex++;
}
dynamicLocals.Free();
......
......@@ -189,7 +189,6 @@ internal sealed class EvaluationContext : EvaluationContextBase
var containingScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes);
var methodContextReuseConstraints = allScopes.GetReuseConstraints(moduleVersionId, methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive);
allScopes.Free();
var localNames = containingScopes.GetLocalNames();
......@@ -201,7 +200,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
try
{
// 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);
inScopeHoistedLocals = new CSharpInScopeHoistedLocals(inScopeHoistedLocalIndices);
}
......@@ -211,6 +210,8 @@ internal sealed class EvaluationContext : EvaluationContextBase
}
}
allScopes.Free();
var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken);
var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle);
Debug.Assert((object)currentFrame != null);
......@@ -502,7 +503,7 @@ private static MethodSymbol GetSynthesizedMethod(CommonPEModuleBuilder moduleBui
private static void GetConstants(
ArrayBuilder<LocalSymbol> builder,
MethodSymbol method,
IEnumerable<ISymUnmanagedScope> scopes,
ArrayBuilder<ISymUnmanagedScope> scopes,
MetadataDecoder metadataDecoder,
ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap,
SourceAssemblySymbol containingAssembly)
......
......@@ -15,7 +15,7 @@ internal static class SymUnmanagedReaderExtensions
this ISymUnmanagedReader reader,
int methodToken,
int methodVersion,
string firstLocalName)
ArrayBuilder<ISymUnmanagedScope> scopes)
{
ImmutableArray<string> externAliasStrings;
var importStringGroups = reader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings);
......@@ -95,7 +95,7 @@ internal static class SymUnmanagedReaderExtensions
customDebugInfoBytes,
methodToken,
methodVersion,
firstLocalName,
scopes,
out dynamicLocalMap,
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.
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Microsoft.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Debugger.Clr;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
......@@ -48,7 +45,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x01);
VerifyCustomTypeInfo(locals[0], "d", 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{
// Code size 2 (0x2)
......@@ -57,6 +54,7 @@ .maxstack 1
IL_0000: ldloc.0
IL_0001: ret
}");
locals.Free();
}
[Fact]
......@@ -86,7 +84,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
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:
@"{
// Code size 2 (0x2)
......@@ -95,6 +93,7 @@ .maxstack 1
IL_0000: ldloc.0
IL_0001: ret
}");
locals.Free();
}
[Fact]
......@@ -124,7 +123,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
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:
@"{
// Code size 2 (0x2)
......@@ -133,6 +132,7 @@ .maxstack 1
IL_0000: ldloc.0
IL_0001: ret
}");
locals.Free();
}
[Fact]
......@@ -168,7 +168,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
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:
@"{
// Code size 2 (0x2)
......@@ -176,6 +176,7 @@ .maxstack 1
IL_0000: ldnull
IL_0001: ret
}");
locals.Free();
}
[Fact]
......@@ -211,7 +212,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
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: @"
{
// Code size 2 (0x2)
......@@ -219,6 +220,7 @@ .maxstack 1
IL_0000: ldnull
IL_0001: ret
}");
locals.Free();
}
[Fact]
......@@ -259,7 +261,7 @@ class Generic<T>
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
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: @"
{
// Code size 2 (0x2)
......@@ -267,6 +269,265 @@ .maxstack 1
IL_0000: ldnull
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]
......@@ -295,7 +556,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
Assert.Equal(TypeKind.Dynamic, method.ReturnType.TypeKind);
VerifyCustomTypeInfo(locals[0], 0x01);
VerifyCustomTypeInfo(locals[0], "d", 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{
// Code size 2 (0x2)
......@@ -303,6 +564,7 @@ .maxstack 1
IL_0000: ldarg.0
IL_0001: ret
}");
locals.Free();
}
[Fact]
......@@ -331,7 +593,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
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:
@"{
// Code size 2 (0x2)
......@@ -339,6 +601,7 @@ .maxstack 1
IL_0000: ldarg.0
IL_0001: ret
}");
locals.Free();
}
[Fact]
......@@ -367,7 +630,7 @@ static dynamic ForceDynamicAttribute()
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
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:
@"{
// Code size 2 (0x2)
......@@ -375,6 +638,7 @@ .maxstack 1
IL_0000: ldarg.0
IL_0001: ret
}");
locals.Free();
}
[WorkItem(1087216, "DevDiv")]
......@@ -411,7 +675,7 @@ public class Inner<V, W>
Assert.Equal(1, locals.Count);
var method = testData.Methods.Single().Value.Method;
AssertHasDynamicAttribute(method);
VerifyCustomTypeInfo(locals[0], 0x04, 0x03);
VerifyCustomTypeInfo(locals[0], "d", 0x04, 0x03);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d", expectedILOpt:
@"{
// Code size 2 (0x2)
......@@ -473,6 +737,7 @@ .maxstack 7
IL_0037: stind.ref
IL_0038: ret
}");
locals.Free();
}
[Fact]
......@@ -521,7 +786,7 @@ static void M()
diagnostics.Free();
Assert.Equal(locals.Count, 2);
VerifyCustomTypeInfo(locals[0], 0x01);
VerifyCustomTypeInfo(locals[0], "d1", 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d1", expectedILOpt:
@"{
// Code size 11 (0xb)
......@@ -531,7 +796,7 @@ .maxstack 1
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:
@"{
// Code size 16 (0x10)
......@@ -572,6 +837,7 @@ static void M()
Assert.Equal(1, locals.Count);
var method = testData.Methods.Single().Value.Method;
AssertHasNoDynamicAttribute(method);
locals.Free();
}
private static void AssertHasDynamicAttribute(IMethodSymbol method)
......@@ -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);
}
......
......@@ -590,7 +590,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Private Shared Sub GetConstants(
builder As ArrayBuilder(Of LocalSymbol),
method As MethodSymbol,
scopes As IEnumerable(Of ISymUnmanagedScope),
scopes As ArrayBuilder(Of ISymUnmanagedScope),
metadataDecoder As MetadataDecoder)
For Each scope In scopes
......
......@@ -283,7 +283,7 @@ private void WriteCustomDebugInfo(byte[] bytes)
WriteForwardToModuleCustomDebugInfo(record);
break;
case CustomDebugInfoKind.StateMachineHoistedLocalScopes:
WriteStatemachineHoistedLocalScopesCustomDebugInfo(record);
WriteStateMachineHoistedLocalScopesCustomDebugInfo(record);
break;
case CustomDebugInfoKind.ForwardIterator:
WriteForwardIteratorCustomDebugInfo(record);
......@@ -402,7 +402,7 @@ private void WriteForwardToModuleCustomDebugInfo(CustomDebugInfoRecord record)
/// <remarks>
/// Appears when there are locals in iterator methods.
/// </remarks>
private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoRecord record)
private void WriteStateMachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoRecord record)
{
Debug.Assert(record.Kind == CustomDebugInfoKind.StateMachineHoistedLocalScopes);
......@@ -415,7 +415,7 @@ private void WriteStatemachineHoistedLocalScopesCustomDebugInfo(CustomDebugInfoR
_writer.WriteStartElement("slot");
_writer.WriteAttributeString("startOffset", AsILOffset(scope.StartOffset));
_writer.WriteAttributeString("endOffset", AsILOffset(scope.EndOffset));
_writer.WriteEndElement(); //bucket
_writer.WriteEndElement(); //slot
}
_writer.WriteEndElement();
......
......@@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Microsoft.CodeAnalysis.Collections;
using Microsoft.DiaSymReader;
using CDI = Microsoft.Cci.CustomDebugInfoConstants;
......@@ -479,7 +480,7 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana
byte[] customDebugInfo,
int methodToken,
int methodVersion,
string firstLocalName,
ArrayBuilder<ISymUnmanagedScope> scopes,
out ImmutableDictionary<int, ImmutableArray<bool>> dynamicLocalMap,
out ImmutableDictionary<string, ImmutableArray<bool>> dynamicLocalConstantMap)
{
......@@ -495,30 +496,20 @@ public static ImmutableArray<string> GetVisualBasicImportStrings(this ISymUnmana
ImmutableDictionary<int, ImmutableArray<bool>>.Builder localBuilder = 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 name = bucket.Name;
// 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))
var flags = GetFlags(bucket);
if (slot < 0)
{
constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder<string, ImmutableArray<bool>>();
constantBuilder.Add(name, dynamicBuilder.ToImmutableAndFree());
constantBuilder.Add(bucket.Name, flags);
}
else
{
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
}
}
/// <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)
{
if (globalVersion != CDI.CdiVersion)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册