提交 9dd256f4 编写于 作者: A Andrew Casey

Merge pull request #2252 from amcasey/DD1087216_3

Add support for "dynamic" Immediate window locals
......@@ -28,9 +28,14 @@ internal struct DynamicTypeDecoder
private readonly ImmutableArray<bool> _dynamicTransformFlags;
private readonly AssemblySymbol _containingAssembly;
private readonly bool _haveCustomModifierFlags;
private readonly bool _checkLength;
/// <remarks>
/// Should be accessed through <see cref="HasFlag"/>, <see cref="PeekFlag"/>, and <see cref="ConsumeFlag"/>.
/// </remarks>
private int _index;
private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool haveCustomModifierFlags, AssemblySymbol containingAssembly)
private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool haveCustomModifierFlags, bool checkLength, AssemblySymbol containingAssembly)
{
Debug.Assert(!dynamicTransformFlags.IsEmpty);
Debug.Assert((object)containingAssembly != null);
......@@ -38,6 +43,7 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
_dynamicTransformFlags = dynamicTransformFlags;
_containingAssembly = containingAssembly;
_haveCustomModifierFlags = haveCustomModifierFlags;
_checkLength = checkLength;
_index = 0;
}
......@@ -63,7 +69,8 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
{
return TransformTypeInternal(metadataType, containingModule.ContainingAssembly,
targetSymbolCustomModifierCount, targetSymbolRefKind, dynamicTransformFlags,
haveCustomModifierFlags: true);
haveCustomModifierFlags: true,
checkLength: true);
}
// No DynamicAttribute applied to the target symbol, return unchanged metadataType.
......@@ -74,10 +81,18 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
TypeSymbol type,
AssemblySymbol containingAssembly,
RefKind targetSymbolRefKind,
ImmutableArray<bool> dynamicTransformFlags)
ImmutableArray<bool> dynamicTransformFlags,
bool checkLength = true)
{
Debug.Assert(containingAssembly is SourceAssemblySymbol); // Doesn't happen during decoding.
return TransformTypeInternal(type, containingAssembly, 0, targetSymbolRefKind, dynamicTransformFlags, haveCustomModifierFlags: false);
return TransformTypeInternal(
type,
containingAssembly,
0,
targetSymbolRefKind,
dynamicTransformFlags,
haveCustomModifierFlags: false,
checkLength: checkLength);
}
private static TypeSymbol TransformTypeInternal(
......@@ -86,7 +101,8 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
int targetSymbolCustomModifierCount,
RefKind targetSymbolRefKind,
ImmutableArray<bool> dynamicTransformFlags,
bool haveCustomModifierFlags)
bool haveCustomModifierFlags,
bool checkLength)
{
Debug.Assert((object)metadataType != null);
Debug.Assert((object)containingAssembly != null);
......@@ -97,15 +113,17 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
return new UnsupportedMetadataTypeSymbol();
}
var decoder = new DynamicTypeDecoder(dynamicTransformFlags, haveCustomModifierFlags, containingAssembly);
var decoder = new DynamicTypeDecoder(dynamicTransformFlags, haveCustomModifierFlags, checkLength, containingAssembly);
// Native compiler encodes bools (always false) for custom modifiers and parameter ref-kinds, if ref-kind is ref or out.
if (decoder.HandleCustomModifiers(targetSymbolCustomModifierCount) && decoder.HandleParameterRefKind(targetSymbolRefKind))
{
TypeSymbol transformedType = decoder.TransformType(metadataType);
if ((object)transformedType != null && decoder._index == dynamicTransformFlags.Length)
if ((object)transformedType != null && (!checkLength || decoder._index == dynamicTransformFlags.Length))
{
// Even when we're not checking the length, there shouldn't be any unconsumed "true"s.
Debug.Assert(checkLength || decoder._dynamicTransformFlags.LastIndexOf(true) < decoder._index);
return transformedType;
}
}
......@@ -118,9 +136,10 @@ private TypeSymbol TransformType(TypeSymbol type)
{
Debug.Assert(_index >= 0);
if (_index >= _dynamicTransformFlags.Length ||
_dynamicTransformFlags[_index] && type.SpecialType != SpecialType.System_Object)
if (!HasFlag ||
PeekFlag() && type.SpecialType != SpecialType.System_Object)
{
// Bail, since flags are invalid.
return null;
}
......@@ -131,7 +150,7 @@ private TypeSymbol TransformType(TypeSymbol type)
if (type.SpecialType == SpecialType.System_Object)
{
// Replace the given System.Object type with dynamic type if the corresponding dynamicTransformFlag is set to true.
return _dynamicTransformFlags[_index++] ? DynamicTypeSymbol.Instance : type;
return ConsumeFlag() ? DynamicTypeSymbol.Instance : type;
}
return TransformNamedType((NamedTypeSymbol)type);
......@@ -144,12 +163,12 @@ private TypeSymbol TransformType(TypeSymbol type)
case SymbolKind.DynamicType:
Debug.Assert(!_haveCustomModifierFlags, "This shouldn't happen during decoding.");
return _dynamicTransformFlags[_index++]
return ConsumeFlag()
? type
: _containingAssembly.GetSpecialType(SpecialType.System_Object);
default:
_index++;
ConsumeFlag();
return HandleCustomModifiers(type.CustomModifierCount()) ? type : null;
}
}
......@@ -167,20 +186,12 @@ private bool HandleCustomModifiers(int customModifiersCount)
Debug.Assert(customModifiersCount >= 0);
if (customModifiersCount > 0)
for (int i = 0; i < customModifiersCount; i++)
{
if (_index + customModifiersCount > _dynamicTransformFlags.Length)
if (!HasFlag || ConsumeFlag())
{
return false;
}
for (int i = 0; i < customModifiersCount; i++, _index++)
{
if (_dynamicTransformFlags[_index])
{
return false;
}
}
}
return true;
......@@ -190,18 +201,16 @@ private bool HandleCustomModifiers(int customModifiersCount)
private bool HandleParameterRefKind(RefKind refKind)
{
Debug.Assert(_index >= 0);
return refKind == RefKind.None ||
_index < _dynamicTransformFlags.Length && !_dynamicTransformFlags[_index++];
return refKind == RefKind.None || !ConsumeFlag();
}
private NamedTypeSymbol TransformNamedType(NamedTypeSymbol namedType, bool isContaining = false)
{
Debug.Assert(!_dynamicTransformFlags[_index] || isContaining);
// Native compiler encodes a bool for the given namedType, but none for its containing types.
if (!isContaining)
{
_index++;
var flag = ConsumeFlag();
Debug.Assert(!flag);
}
NamedTypeSymbol containingType = namedType.ContainingType;
......@@ -279,9 +288,9 @@ private ImmutableArray<TypeSymbol> TransformTypeArguments(ImmutableArray<TypeSym
private ArrayTypeSymbol TransformArrayType(ArrayTypeSymbol arrayType)
{
Debug.Assert(!_dynamicTransformFlags[_index]);
var flag = ConsumeFlag();
Debug.Assert(!flag);
_index++;
if (!HandleCustomModifiers(arrayType.CustomModifiers.Length))
{
return null;
......@@ -300,9 +309,9 @@ private ArrayTypeSymbol TransformArrayType(ArrayTypeSymbol arrayType)
private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType)
{
Debug.Assert(!_dynamicTransformFlags[_index]);
var flag = ConsumeFlag();
Debug.Assert(!flag);
_index++;
if (!HandleCustomModifiers(pointerType.CustomModifiers.Length))
{
return null;
......@@ -318,5 +327,16 @@ private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType)
pointerType :
new PointerTypeSymbol(transformedPointedAtType, pointerType.CustomModifiers);
}
private bool HasFlag => _index < _dynamicTransformFlags.Length || !_checkLength;
private bool PeekFlag() => _index < _dynamicTransformFlags.Length && _dynamicTransformFlags[_index];
private bool ConsumeFlag()
{
var result = PeekFlag();
_index++;
return result;
}
}
}
......@@ -3434,5 +3434,68 @@ static void Main()
CompileAndVerify(compilation2, expectedOutput: @"4");
}
[Fact]
public void IncorrectArrayLength()
{
var il = @"
.assembly extern mscorlib { }
.assembly extern System.Core { }
.assembly IncorrectArrayLength { }
.class private auto ansi beforefieldinit D
extends [mscorlib]System.Object
{
.field public class Generic`2<object,object> MissingTrue
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[])
= {bool[2](false true)}
.field public class Generic`2<object,object> MissingFalse
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[])
= {bool[2](false true)}
.field public class Generic`2<object,object> ExtraTrue
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[])
= {bool[4](false true false true)}
.field public class Generic`2<object,object> ExtraFalse
.custom instance void [System.Core]System.Runtime.CompilerServices.DynamicAttribute::.ctor(bool[])
= {bool[4](false true false false)}
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
ldarg.0
call instance void [mscorlib]System.Object::.ctor()
ret
}
} // end of class D
.class public auto ansi beforefieldinit Generic`2<T,U>
extends [mscorlib]System.Object
{
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method Generic`2::.ctor
} // end of class Generic`2
";
var comp = CreateCompilationWithCustomILSource("", il, new[] { SystemCoreRef }, appendDefaultHeader: false);
var global = comp.GlobalNamespace;
var typeD = global.GetMember<NamedTypeSymbol>("D");
var typeG = global.GetMember<NamedTypeSymbol>("Generic");
var typeObject = comp.GetSpecialType(SpecialType.System_Object);
var typeGConstructed = typeG.Construct(typeObject, typeObject);
Assert.Equal(typeGConstructed, typeD.GetMember<FieldSymbol>("MissingTrue").Type);
Assert.Equal(typeGConstructed, typeD.GetMember<FieldSymbol>("MissingFalse").Type);
Assert.Equal(typeGConstructed, typeD.GetMember<FieldSymbol>("ExtraTrue").Type);
Assert.Equal(typeGConstructed, typeD.GetMember<FieldSymbol>("ExtraFalse").Type);
}
}
}
......@@ -109,7 +109,9 @@ private PlaceholderLocalSymbol LookupPlaceholder(string name)
return null;
}
return CreatePlaceholderLocal(_typeNameDecoder, _containingMethod, new Alias(kind, id, id, typeName));
// The old API (GetObjectTypeNameById) doesn't return custom type info,
// but the new one (GetAliases) will.
return CreatePlaceholderLocal(_typeNameDecoder, _containingMethod, new Alias(kind, id, id, typeName, default(CustomTypeInfo)));
}
internal static PlaceholderLocalSymbol CreatePlaceholderLocal(
......@@ -123,6 +125,22 @@ private PlaceholderLocalSymbol LookupPlaceholder(string name)
var type = typeNameDecoder.GetTypeSymbolForSerializedType(typeName);
Debug.Assert((object)type != null);
var dynamicFlagsInfo = alias.CustomTypeInfo.ToDynamicFlagsCustomTypeInfo();
if (dynamicFlagsInfo.Any())
{
var flagsBuilder = ArrayBuilder<bool>.GetInstance();
dynamicFlagsInfo.CopyTo(flagsBuilder);
var dynamicType = DynamicTypeDecoder.TransformTypeWithoutCustomModifierFlags(
type,
containingMethod.ContainingAssembly,
RefKind.None,
flagsBuilder.ToImmutableAndFree(),
checkLength: false);
Debug.Assert(dynamicType != null);
Debug.Assert(dynamicType != type);
type = dynamicType;
}
var id = alias.FullName;
switch (alias.Kind)
{
......
......@@ -2,9 +2,11 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{
......@@ -59,16 +61,21 @@ internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymb
var typeType = compilation.GetWellKnownType(WellKnownType.System_Type);
var stringType = compilation.GetSpecialType(SpecialType.System_String);
var guidConstructor = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Guid__ctor);
// CreateVariable(Type type, string name)
var method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName);
var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType);
var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType);
bool hasCustomTypeInfoPayload;
var customTypeInfoPayload = GetCustomTypeInfoPayload(local, syntax, compilation, out hasCustomTypeInfoPayload);
var customTypeInfoPayloadId = GetCustomTypeInfoPayloadId(syntax, guidConstructor, hasCustomTypeInfoPayload);
var call = BoundCall.Synthesized(
syntax,
receiverOpt: null,
method: method,
arguments: ImmutableArray.Create<BoundExpression>(type, name));
arguments: ImmutableArray.Create(type, name, customTypeInfoPayloadId, customTypeInfoPayload));
statements.Add(new BoundExpressionStatement(syntax, call));
var initializer = node.InitializerOpt;
......@@ -85,5 +92,51 @@ internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymb
statements.Add(new BoundExpressionStatement(syntax, assignment));
}
}
private static BoundExpression GetCustomTypeInfoPayloadId(CSharpSyntaxNode syntax, MethodSymbol guidConstructor, bool hasCustomTypeInfoPayload)
{
if (!hasCustomTypeInfoPayload)
{
return new BoundDefaultOperator(syntax, guidConstructor.ContainingType);
}
var value = ConstantValue.Create(DynamicFlagsCustomTypeInfo.PayloadTypeId.ToString());
return new BoundObjectCreationExpression(
syntax,
guidConstructor,
new BoundLiteral(syntax, value, guidConstructor.ContainingType));
}
private static BoundExpression GetCustomTypeInfoPayload(LocalSymbol local, CSharpSyntaxNode syntax, CSharpCompilation compilation, out bool hasCustomTypeInfoPayload)
{
var byteArrayType = new ArrayTypeSymbol(
compilation.Assembly,
compilation.GetSpecialType(SpecialType.System_Byte));
var flags = CSharpCompilation.DynamicTransformsEncoder.Encode(local.Type, customModifiersCount: 0, refKind: RefKind.None).ToArray();
var bytes = new DynamicFlagsCustomTypeInfo(new BitArray(flags)).GetCustomTypeInfoPayload();
hasCustomTypeInfoPayload = bytes != null;
if (!hasCustomTypeInfoPayload)
{
return new BoundLiteral(syntax, ConstantValue.Null, byteArrayType);
}
var byteType = byteArrayType.ElementType;
var intType = compilation.GetSpecialType(SpecialType.System_Int32);
var numBytes = bytes.Length;
var initializerExprs = ArrayBuilder<BoundExpression>.GetInstance(numBytes);
foreach (var b in bytes)
{
initializerExprs.Add(new BoundLiteral(syntax, ConstantValue.Create(b), byteType));
}
var lengthExpr = new BoundLiteral(syntax, ConstantValue.Create(numBytes), intType);
return new BoundArrayCreation(
syntax,
ImmutableArray.Create<BoundExpression>(lengthExpr),
new BoundArrayInitialization(syntax, initializerExprs.ToImmutableAndFree()),
byteArrayType);
}
}
}
......@@ -2,7 +2,6 @@
using System.Collections;
using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator;
......@@ -19,7 +18,7 @@ internal static ImmutableArray<TypeParameterSymbol> GetAllTypeParameters(this Me
return builder.ToImmutableAndFree();
}
internal static ReadOnlyCollection<byte> GetCustomTypeInfoPayload(this MethodSymbol method)
internal static byte[] GetCustomTypeInfoPayload(this MethodSymbol method)
{
bool[] dynamicFlags = CSharpCompilation.DynamicTransformsEncoder.Encode(method.ReturnType, method.ReturnTypeCustomModifiers.Length, RefKind.None).ToArray();
var dynamicFlagsInfo = new DynamicFlagsCustomTypeInfo(new BitArray(dynamicFlags));
......
// 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.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using Roslyn.Test.PdbUtilities;
using Roslyn.Test.Utilities;
......@@ -393,10 +397,6 @@ public class Outer<T, U>
{
public class Inner<V, W>
{
public enum E
{
A
}
}
}
";
......@@ -429,6 +429,124 @@ .maxstack 1
result = context.CompileAssignment("d", "d", out error);
Assert.Null(error);
VerifyCustomTypeInfo(result, null);
ResultProperties resultProperties;
ImmutableArray<AssemblyIdentity> missingAssemblyIdentities;
testData = new CompilationTestData();
result = context.CompileExpression(
InspectionContextFactory.Empty,
"var dd = d;",
DkmEvaluationFlags.None,
DiagnosticFormatter.Instance,
out resultProperties,
out error,
out missingAssemblyIdentities,
EnsureEnglishUICulture.PreferredOrNull,
testData);
Assert.Null(error);
VerifyCustomTypeInfo(result, null);
Assert.Empty(missingAssemblyIdentities);
Assert.Equal(resultProperties.Flags, DkmClrCompilationResultFlags.PotentialSideEffect | DkmClrCompilationResultFlags.ReadOnlyResult);
testData.GetMethodData("<>x.<>m0").VerifyIL(
@"{
// Code size 57 (0x39)
.maxstack 7
IL_0000: ldtoken ""Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic>""
IL_0005: call ""System.Type System.Type.GetTypeFromHandle(System.RuntimeTypeHandle)""
IL_000a: ldstr ""dd""
IL_000f: ldstr ""826d6ec1-dc4b-46af-be05-cd3f1a1fd4ac""
IL_0014: newobj ""System.Guid..ctor(string)""
IL_0019: ldc.i4.2
IL_001a: newarr ""byte""
IL_001f: dup
IL_0020: ldc.i4.0
IL_0021: ldc.i4.4
IL_0022: stelem.i1
IL_0023: dup
IL_0024: ldc.i4.1
IL_0025: ldc.i4.3
IL_0026: stelem.i1
IL_0027: call ""void Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, string, System.Guid, byte[])""
IL_002c: ldstr ""dd""
IL_0031: call ""Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic> Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress<Outer<dynamic[], object[]>.Inner<Outer<object, dynamic>[], dynamic>>(string)""
IL_0036: ldarg.0
IL_0037: stind.ref
IL_0038: ret
}");
}
[Fact]
public void DynamicAliases()
{
var source =
@"class C
{
static void M()
{
}
}";
var compilation0 = CreateCompilationWithMscorlib(
source,
options: TestOptions.DebugDll,
assemblyName: ExpressionCompilerUtilities.GenerateUniqueName());
var runtime = CreateRuntimeInstance(compilation0);
var context = CreateMethodContext(runtime, methodName: "C.M");
var locals = ArrayBuilder<LocalAndMethod>.GetInstance();
string typeName;
var diagnostics = DiagnosticBag.GetInstance();
var builder = ArrayBuilder<Alias>.GetInstance();
builder.Add(new Alias(
AliasKind.DeclaredLocal,
"d1",
"d1",
typeof(object).AssemblyQualifiedName,
MakeCustomTypeInfo(true)));
builder.Add(new Alias(
AliasKind.DeclaredLocal,
"d2",
"d2",
typeof(Dictionary<Dictionary<dynamic, Dictionary<object[], dynamic[]>>, object>).AssemblyQualifiedName,
MakeCustomTypeInfo(false, false, true, false, false, false, false, true, false)));
var aliases = new ReadOnlyCollection<Alias>(builder.ToArrayAndFree());
var testData = new CompilationTestData();
context.CompileGetLocals(
aliases,
locals,
argumentsOnly: false,
diagnostics: diagnostics,
typeName: out typeName,
testData: testData);
diagnostics.Free();
Assert.Equal(locals.Count, 2);
VerifyCustomTypeInfo(locals[0], 0x01);
VerifyLocal(testData, typeName, locals[0], "<>m0", "d1", expectedILOpt:
@"{
// Code size 11 (0xb)
.maxstack 1
IL_0000: ldstr ""d1""
IL_0005: call ""object Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetObjectByAlias(string)""
IL_000a: ret
}");
VerifyCustomTypeInfo(locals[1], 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)
.maxstack 1
IL_0000: ldstr ""d2""
IL_0005: call ""object Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetObjectByAlias(string)""
IL_000a: castclass ""System.Collections.Generic.Dictionary<System.Collections.Generic.Dictionary<dynamic, System.Collections.Generic.Dictionary<object[], dynamic[]>>, object>""
IL_000f: ret
}");
locals.Free();
}
private static CustomTypeInfo MakeCustomTypeInfo(params bool[] flags)
{
var dynamicFlagsInfo = new DynamicFlagsCustomTypeInfo(new BitArray(flags));
return new CustomTypeInfo(DynamicFlagsCustomTypeInfo.PayloadTypeId, dynamicFlagsInfo.GetCustomTypeInfoPayload());
}
[Fact]
......
......@@ -231,11 +231,11 @@ void M(object o)
string typeName;
var diagnostics = DiagnosticBag.GetInstance();
var builder = ArrayBuilder<Alias>.GetInstance();
builder.Add(new Alias(AliasKind.Exception, "Error", "$exception", typeof(System.IO.IOException).AssemblyQualifiedName));
builder.Add(new Alias(AliasKind.ReturnValue, "F returned", "$ReturnValue2", typeof(string).AssemblyQualifiedName));
builder.Add(new Alias(AliasKind.ReturnValue, "G returned", "$ReturnValue", typeof(object).AssemblyQualifiedName));
builder.Add(new Alias(AliasKind.ObjectId, "2", "2", typeof(bool).AssemblyQualifiedName));
builder.Add(new Alias(AliasKind.DeclaredLocal, "o", "o", "C"));
builder.Add(new Alias(AliasKind.Exception, "Error", "$exception", typeof(System.IO.IOException).AssemblyQualifiedName, default(CustomTypeInfo)));
builder.Add(new Alias(AliasKind.ReturnValue, "F returned", "$ReturnValue2", typeof(string).AssemblyQualifiedName, default(CustomTypeInfo)));
builder.Add(new Alias(AliasKind.ReturnValue, "G returned", "$ReturnValue", typeof(object).AssemblyQualifiedName, default(CustomTypeInfo)));
builder.Add(new Alias(AliasKind.ObjectId, "2", "2", typeof(bool).AssemblyQualifiedName, default(CustomTypeInfo)));
builder.Add(new Alias(AliasKind.DeclaredLocal, "o", "o", "C", default(CustomTypeInfo)));
var aliases = new ReadOnlyCollection<Alias>(builder.ToArrayAndFree());
var testData = new CompilationTestData();
......
// 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;
using System.Collections;
using System.Collections.ObjectModel;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
......@@ -14,19 +15,26 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator
internal struct CustomTypeInfo
{
public Guid PayloadTypeId;
public ReadOnlyCollection<byte> Payload;
public byte[] Payload;
public CustomTypeInfo(Guid payloadTypeId, ReadOnlyCollection<byte> payload)
public CustomTypeInfo(Guid payloadTypeId, byte[] payload)
{
this.PayloadTypeId = payloadTypeId;
this.Payload = payload;
}
public DynamicFlagsCustomTypeInfo ToDynamicFlagsCustomTypeInfo()
{
return PayloadTypeId == DynamicFlagsCustomTypeInfo.PayloadTypeId
? new DynamicFlagsCustomTypeInfo(new BitArray(Payload))
: default(DynamicFlagsCustomTypeInfo);
}
public DkmClrCustomTypeInfo ToDkmClrCustomTypeInfo()
{
return Payload == null
? null
: DkmClrCustomTypeInfo.Create(PayloadTypeId, Payload);
: DkmClrCustomTypeInfo.Create(PayloadTypeId, new ReadOnlyCollection<byte>(Payload));
}
}
}
......@@ -45,7 +45,26 @@ public DynamicFlagsCustomTypeInfo(DkmClrCustomTypeInfo typeInfo)
}
}
internal ReadOnlyCollection<byte> GetCustomTypeInfoPayload()
/// <remarks>
/// Not guarantee to add the same number of flags as would
/// appear in a <see cref="System.Runtime.CompilerServices.DynamicAttribute"/>.
/// It may have more (for padding) or fewer (for compactness) falses.
/// It is, however, guaranteed to include the last true.
/// </remarks>
internal void CopyTo(ArrayBuilder<bool> builder)
{
if (_bits == null)
{
return;
}
for (int b = 0; b < _bits.Length; b++)
{
builder.Add(_bits[b]);
}
}
internal byte[] GetCustomTypeInfoPayload()
{
if (!Any())
{
......@@ -69,13 +88,13 @@ internal ReadOnlyCollection<byte> GetCustomTypeInfoPayload()
}
}
return new ReadOnlyCollection<byte>(bytes);
return bytes;
}
public DkmClrCustomTypeInfo GetCustomTypeInfo()
{
var payload = GetCustomTypeInfoPayload();
return payload == null ? null : DkmClrCustomTypeInfo.Create(PayloadTypeId, payload);
return payload == null ? null : DkmClrCustomTypeInfo.Create(PayloadTypeId, new ReadOnlyCollection<byte>(payload));
}
public DynamicFlagsCustomTypeInfo SkipOne()
......
......@@ -3,7 +3,6 @@
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using Roslyn.Utilities;
using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
......@@ -21,31 +20,26 @@ internal enum AliasKind
internal struct Alias
{
internal Alias(AliasKind kind, string name, string fullName, string type, ReadOnlyCollection<byte> customTypeInfo = null, Guid customTypeInfoId = default(Guid))
internal Alias(AliasKind kind, string name, string fullName, string type, CustomTypeInfo customTypeInfo)
{
Debug.Assert(kind != AliasKind.None);
Debug.Assert(!string.IsNullOrEmpty(fullName));
Debug.Assert(!string.IsNullOrEmpty(type));
Debug.Assert((customTypeInfo == null) == (customTypeInfoId == default(Guid)));
this.Kind = kind;
this.Name = name;
this.FullName = fullName;
this.Type = type;
this.CustomTypeInfo = customTypeInfo;
this.CustomTypeInfoId = customTypeInfoId;
}
internal readonly AliasKind Kind;
internal readonly string Name;
internal readonly string FullName;
internal readonly string Type;
internal readonly ReadOnlyCollection<byte> CustomTypeInfo;
internal readonly Guid CustomTypeInfoId;
internal readonly CustomTypeInfo CustomTypeInfo;
}
internal delegate ReadOnlyCollection<Alias> GetAliases();
internal static class PseudoVariableUtilities
{
internal static bool TryParseVariableName(string name, bool caseSensitive, out AliasKind kind, out string id, out int index)
......
......@@ -48,6 +48,14 @@ internal class ExtensionAttribute : Attribute
{
}
/// <summary>
/// This satisfies a cref on <see cref="Microsoft.CodeAnalysis.ExpressionEvaluator.DynamicFlagsCustomTypeInfo.CopyTo"/>.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter | AttributeTargets.ReturnValue)]
internal class DynamicAttribute : Attribute
{
}
/// <summary>
/// This satisfies a cref on <see cref="Microsoft.CodeAnalysis.WellKnownMemberNames"/>.
/// </summary>
......
......@@ -505,7 +505,7 @@ private static MetadataReference GetIntrinsicAssemblyReference()
ldnull
throw
}
.method public static void CreateVariable(class [mscorlib]System.Type 'type', string name)
.method public static void CreateVariable(class [mscorlib]System.Type 'type', string name, valuetype [mscorlib]System.Guid customTypeInfoPayloadTypeId, uint8[] customTypeInfoPayload)
{
ldnull
throw
......
......@@ -21,16 +21,16 @@ internal InspectionContextImpl(ReadOnlyCollection<Alias> variables)
_variables = variables;
}
internal InspectionContextImpl Add(string id, Type type)
internal InspectionContextImpl Add(string id, Type type, CustomTypeInfo customTypeInfo = default(CustomTypeInfo))
{
return Add(id, type.AssemblyQualifiedName);
return Add(id, type.AssemblyQualifiedName, customTypeInfo);
}
internal InspectionContextImpl Add(string id, string typeName)
internal InspectionContextImpl Add(string id, string typeName, CustomTypeInfo customTypeInfo = default(CustomTypeInfo))
{
var builder = ArrayBuilder<Alias>.GetInstance();
builder.AddRange(_variables);
builder.Add(new Alias(GetPseudoVariableKind(id), id, id, typeName));
builder.Add(new Alias(GetPseudoVariableKind(id), id, id, typeName, customTypeInfo));
return new InspectionContextImpl(new ReadOnlyCollection<Alias>(builder.ToArrayAndFree()));
}
......
......@@ -113,7 +113,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Return Nothing
End If
Return CreatePlaceholderLocal(_typeNameDecoder, _containingMethod, New [Alias](kind, id, id, typeName))
' The old API (GetObjectTypeNameById) doesn't return custom type info,
' but the new one (GetAliases) will.
Return CreatePlaceholderLocal(_typeNameDecoder, _containingMethod, New [Alias](kind, id, id, typeName, customTypeInfo:=Nothing))
End Function
Friend Shared Function CreatePlaceholderLocal(
......
......@@ -56,17 +56,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim typeType = compilation.GetWellKnownType(WellKnownType.System_Type)
Dim stringType = compilation.GetSpecialType(SpecialType.System_String)
Dim guidType = compilation.GetWellKnownType(WellKnownType.System_Guid)
Dim byteArrayType = New ArrayTypeSymbol(
compilation.GetSpecialType(SpecialType.System_Byte),
ImmutableArray(Of CustomModifier).Empty,
rank:=1,
compilation:=compilation)
' CreateVariable(type As Type, name As String)
Dim method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName)
Dim type = New BoundGetType(syntax, New BoundTypeExpression(syntax, local.Type), typeType)
Dim name = New BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType)
Dim customTypeInfoPayloadId = New BoundObjectCreationExpression(syntax, Nothing, ImmutableArray(Of BoundExpression).Empty, Nothing, guidType)
Dim customTypeInfoPayload = New BoundLiteral(syntax, ConstantValue.Null, byteArrayType)
Dim expr = New BoundCall(
syntax,
method,
methodGroupOpt:=Nothing,
receiverOpt:=Nothing,
arguments:=ImmutableArray.Create(Of BoundExpression)(type, name),
arguments:=ImmutableArray.Create(Of BoundExpression)(type, name, customTypeInfoPayloadId, customTypeInfoPayload),
constantValueOpt:=Nothing,
suppressObjectClone:=False,
type:=method.ReturnType)
......
......@@ -137,11 +137,11 @@ End Class"
Dim typeName As String = Nothing
Dim diagnostics = DiagnosticBag.GetInstance()
Dim builder = ArrayBuilder(Of [Alias]).GetInstance()
builder.Add(New [Alias](AliasKind.Exception, "Error", "$exception", GetType(System.IO.IOException).AssemblyQualifiedName))
builder.Add(New [Alias](AliasKind.ReturnValue, "F returned", "$ReturnValue2", GetType(String).AssemblyQualifiedName))
builder.Add(New [Alias](AliasKind.ReturnValue, "G returned", "$ReturnValue", GetType(Object).AssemblyQualifiedName))
builder.Add(New [Alias](AliasKind.ObjectId, "2", "2", GetType(Boolean).AssemblyQualifiedName))
builder.Add(New [Alias](AliasKind.DeclaredLocal, "o", "o", "C"))
builder.Add(New [Alias](AliasKind.Exception, "Error", "$exception", GetType(System.IO.IOException).AssemblyQualifiedName, customTypeInfo:=Nothing))
builder.Add(New [Alias](AliasKind.ReturnValue, "F returned", "$ReturnValue2", GetType(String).AssemblyQualifiedName, customTypeInfo:=Nothing))
builder.Add(New [Alias](AliasKind.ReturnValue, "G returned", "$ReturnValue", GetType(Object).AssemblyQualifiedName, customTypeInfo:=Nothing))
builder.Add(New [Alias](AliasKind.ObjectId, "2", "2", GetType(Boolean).AssemblyQualifiedName, customTypeInfo:=Nothing))
builder.Add(New [Alias](AliasKind.DeclaredLocal, "o", "o", "C", customTypeInfo:=Nothing))
Dim aliases = New ReadOnlyCollection(Of [Alias])(builder.ToArrayAndFree())
Dim testData = New CompilationTestData()
......
......@@ -802,18 +802,23 @@ End Class
Assert.Null(errorMessage)
testData.GetMethodData("<>x.<>m0").VerifyIL(
"{
// Code size 33 (0x21)
.maxstack 2
.locals init (T V_0) //F
// Code size 43 (0x2b)
.maxstack 4
.locals init (T V_0, //F
System.Guid V_1)
IL_0000: ldtoken ""Object""
IL_0005: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_000a: ldstr ""x""
IL_000f: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String)""
IL_0014: ldstr ""x""
IL_0019: call ""Function Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress(Of Object)(String) As Object""
IL_001e: ldnull
IL_001f: stind.ref
IL_0020: ret
IL_000f: ldloca.s V_1
IL_0011: initobj ""System.Guid""
IL_0017: ldloc.1
IL_0018: ldnull
IL_0019: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String, System.Guid, Byte())""
IL_001e: ldstr ""x""
IL_0023: call ""Function Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress(Of Object)(String) As Object""
IL_0028: ldnull
IL_0029: stind.ref
IL_002a: ret
}")
testData = New CompilationTestData()
context.CompileExpression(
......@@ -830,18 +835,23 @@ End Class
Assert.Null(errorMessage)
testData.GetMethodData("<>x.<>m0").VerifyIL(
"{
// Code size 37 (0x25)
.maxstack 2
.locals init (T V_0) //F
// Code size 47 (0x2f)
.maxstack 4
.locals init (T V_0, //F
System.Guid V_1)
IL_0000: ldtoken ""Object""
IL_0005: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_000a: ldstr ""x""
IL_000f: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String)""
IL_0014: ldstr ""x""
IL_0019: call ""Function Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress(Of Object)(String) As Object""
IL_001e: call ""Function C.F(Of Object)(ByRef Object) As Object""
IL_0023: pop
IL_0024: ret
IL_000f: ldloca.s V_1
IL_0011: initobj ""System.Guid""
IL_0017: ldloc.1
IL_0018: ldnull
IL_0019: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String, System.Guid, Byte())""
IL_001e: ldstr ""x""
IL_0023: call ""Function Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress(Of Object)(String) As Object""
IL_0028: call ""Function C.F(Of Object)(ByRef Object) As Object""
IL_002d: pop
IL_002e: ret
}")
End Sub
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册