提交 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 ...@@ -28,9 +28,14 @@ internal struct DynamicTypeDecoder
private readonly ImmutableArray<bool> _dynamicTransformFlags; private readonly ImmutableArray<bool> _dynamicTransformFlags;
private readonly AssemblySymbol _containingAssembly; private readonly AssemblySymbol _containingAssembly;
private readonly bool _haveCustomModifierFlags; 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 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(!dynamicTransformFlags.IsEmpty);
Debug.Assert((object)containingAssembly != null); Debug.Assert((object)containingAssembly != null);
...@@ -38,6 +43,7 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have ...@@ -38,6 +43,7 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
_dynamicTransformFlags = dynamicTransformFlags; _dynamicTransformFlags = dynamicTransformFlags;
_containingAssembly = containingAssembly; _containingAssembly = containingAssembly;
_haveCustomModifierFlags = haveCustomModifierFlags; _haveCustomModifierFlags = haveCustomModifierFlags;
_checkLength = checkLength;
_index = 0; _index = 0;
} }
...@@ -63,7 +69,8 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have ...@@ -63,7 +69,8 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
{ {
return TransformTypeInternal(metadataType, containingModule.ContainingAssembly, return TransformTypeInternal(metadataType, containingModule.ContainingAssembly,
targetSymbolCustomModifierCount, targetSymbolRefKind, dynamicTransformFlags, targetSymbolCustomModifierCount, targetSymbolRefKind, dynamicTransformFlags,
haveCustomModifierFlags: true); haveCustomModifierFlags: true,
checkLength: true);
} }
// No DynamicAttribute applied to the target symbol, return unchanged metadataType. // No DynamicAttribute applied to the target symbol, return unchanged metadataType.
...@@ -74,10 +81,18 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have ...@@ -74,10 +81,18 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
TypeSymbol type, TypeSymbol type,
AssemblySymbol containingAssembly, AssemblySymbol containingAssembly,
RefKind targetSymbolRefKind, RefKind targetSymbolRefKind,
ImmutableArray<bool> dynamicTransformFlags) ImmutableArray<bool> dynamicTransformFlags,
bool checkLength = true)
{ {
Debug.Assert(containingAssembly is SourceAssemblySymbol); // Doesn't happen during decoding. 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( private static TypeSymbol TransformTypeInternal(
...@@ -86,7 +101,8 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have ...@@ -86,7 +101,8 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
int targetSymbolCustomModifierCount, int targetSymbolCustomModifierCount,
RefKind targetSymbolRefKind, RefKind targetSymbolRefKind,
ImmutableArray<bool> dynamicTransformFlags, ImmutableArray<bool> dynamicTransformFlags,
bool haveCustomModifierFlags) bool haveCustomModifierFlags,
bool checkLength)
{ {
Debug.Assert((object)metadataType != null); Debug.Assert((object)metadataType != null);
Debug.Assert((object)containingAssembly != null); Debug.Assert((object)containingAssembly != null);
...@@ -97,15 +113,17 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have ...@@ -97,15 +113,17 @@ private DynamicTypeDecoder(ImmutableArray<bool> dynamicTransformFlags, bool have
return new UnsupportedMetadataTypeSymbol(); 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. // 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)) if (decoder.HandleCustomModifiers(targetSymbolCustomModifierCount) && decoder.HandleParameterRefKind(targetSymbolRefKind))
{ {
TypeSymbol transformedType = decoder.TransformType(metadataType); 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; return transformedType;
} }
} }
...@@ -118,9 +136,10 @@ private TypeSymbol TransformType(TypeSymbol type) ...@@ -118,9 +136,10 @@ private TypeSymbol TransformType(TypeSymbol type)
{ {
Debug.Assert(_index >= 0); Debug.Assert(_index >= 0);
if (_index >= _dynamicTransformFlags.Length || if (!HasFlag ||
_dynamicTransformFlags[_index] && type.SpecialType != SpecialType.System_Object) PeekFlag() && type.SpecialType != SpecialType.System_Object)
{ {
// Bail, since flags are invalid.
return null; return null;
} }
...@@ -131,7 +150,7 @@ private TypeSymbol TransformType(TypeSymbol type) ...@@ -131,7 +150,7 @@ private TypeSymbol TransformType(TypeSymbol type)
if (type.SpecialType == SpecialType.System_Object) if (type.SpecialType == SpecialType.System_Object)
{ {
// Replace the given System.Object type with dynamic type if the corresponding dynamicTransformFlag is set to true. // 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); return TransformNamedType((NamedTypeSymbol)type);
...@@ -144,12 +163,12 @@ private TypeSymbol TransformType(TypeSymbol type) ...@@ -144,12 +163,12 @@ private TypeSymbol TransformType(TypeSymbol type)
case SymbolKind.DynamicType: case SymbolKind.DynamicType:
Debug.Assert(!_haveCustomModifierFlags, "This shouldn't happen during decoding."); Debug.Assert(!_haveCustomModifierFlags, "This shouldn't happen during decoding.");
return _dynamicTransformFlags[_index++] return ConsumeFlag()
? type ? type
: _containingAssembly.GetSpecialType(SpecialType.System_Object); : _containingAssembly.GetSpecialType(SpecialType.System_Object);
default: default:
_index++; ConsumeFlag();
return HandleCustomModifiers(type.CustomModifierCount()) ? type : null; return HandleCustomModifiers(type.CustomModifierCount()) ? type : null;
} }
} }
...@@ -167,20 +186,12 @@ private bool HandleCustomModifiers(int customModifiersCount) ...@@ -167,20 +186,12 @@ private bool HandleCustomModifiers(int customModifiersCount)
Debug.Assert(customModifiersCount >= 0); Debug.Assert(customModifiersCount >= 0);
if (customModifiersCount > 0) for (int i = 0; i < customModifiersCount; i++)
{ {
if (_index + customModifiersCount > _dynamicTransformFlags.Length) if (!HasFlag || ConsumeFlag())
{ {
return false; return false;
} }
for (int i = 0; i < customModifiersCount; i++, _index++)
{
if (_dynamicTransformFlags[_index])
{
return false;
}
}
} }
return true; return true;
...@@ -190,18 +201,16 @@ private bool HandleCustomModifiers(int customModifiersCount) ...@@ -190,18 +201,16 @@ private bool HandleCustomModifiers(int customModifiersCount)
private bool HandleParameterRefKind(RefKind refKind) private bool HandleParameterRefKind(RefKind refKind)
{ {
Debug.Assert(_index >= 0); Debug.Assert(_index >= 0);
return refKind == RefKind.None || return refKind == RefKind.None || !ConsumeFlag();
_index < _dynamicTransformFlags.Length && !_dynamicTransformFlags[_index++];
} }
private NamedTypeSymbol TransformNamedType(NamedTypeSymbol namedType, bool isContaining = false) 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. // Native compiler encodes a bool for the given namedType, but none for its containing types.
if (!isContaining) if (!isContaining)
{ {
_index++; var flag = ConsumeFlag();
Debug.Assert(!flag);
} }
NamedTypeSymbol containingType = namedType.ContainingType; NamedTypeSymbol containingType = namedType.ContainingType;
...@@ -279,9 +288,9 @@ private ImmutableArray<TypeSymbol> TransformTypeArguments(ImmutableArray<TypeSym ...@@ -279,9 +288,9 @@ private ImmutableArray<TypeSymbol> TransformTypeArguments(ImmutableArray<TypeSym
private ArrayTypeSymbol TransformArrayType(ArrayTypeSymbol arrayType) private ArrayTypeSymbol TransformArrayType(ArrayTypeSymbol arrayType)
{ {
Debug.Assert(!_dynamicTransformFlags[_index]); var flag = ConsumeFlag();
Debug.Assert(!flag);
_index++;
if (!HandleCustomModifiers(arrayType.CustomModifiers.Length)) if (!HandleCustomModifiers(arrayType.CustomModifiers.Length))
{ {
return null; return null;
...@@ -300,9 +309,9 @@ private ArrayTypeSymbol TransformArrayType(ArrayTypeSymbol arrayType) ...@@ -300,9 +309,9 @@ private ArrayTypeSymbol TransformArrayType(ArrayTypeSymbol arrayType)
private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType) private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType)
{ {
Debug.Assert(!_dynamicTransformFlags[_index]); var flag = ConsumeFlag();
Debug.Assert(!flag);
_index++;
if (!HandleCustomModifiers(pointerType.CustomModifiers.Length)) if (!HandleCustomModifiers(pointerType.CustomModifiers.Length))
{ {
return null; return null;
...@@ -318,5 +327,16 @@ private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType) ...@@ -318,5 +327,16 @@ private PointerTypeSymbol TransformPointerType(PointerTypeSymbol pointerType)
pointerType : pointerType :
new PointerTypeSymbol(transformedPointedAtType, pointerType.CustomModifiers); 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() ...@@ -3434,5 +3434,68 @@ static void Main()
CompileAndVerify(compilation2, expectedOutput: @"4"); 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) ...@@ -109,7 +109,9 @@ private PlaceholderLocalSymbol LookupPlaceholder(string name)
return null; 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( internal static PlaceholderLocalSymbol CreatePlaceholderLocal(
...@@ -123,6 +125,22 @@ private PlaceholderLocalSymbol LookupPlaceholder(string name) ...@@ -123,6 +125,22 @@ private PlaceholderLocalSymbol LookupPlaceholder(string name)
var type = typeNameDecoder.GetTypeSymbolForSerializedType(typeName); var type = typeNameDecoder.GetTypeSymbolForSerializedType(typeName);
Debug.Assert((object)type != null); 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; var id = alias.FullName;
switch (alias.Kind) switch (alias.Kind)
{ {
......
...@@ -2,9 +2,11 @@ ...@@ -2,9 +2,11 @@
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.ExpressionEvaluator;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Diagnostics; using System.Diagnostics;
using System.Linq;
namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator namespace Microsoft.CodeAnalysis.CSharp.ExpressionEvaluator
{ {
...@@ -59,16 +61,21 @@ internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymb ...@@ -59,16 +61,21 @@ internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymb
var typeType = compilation.GetWellKnownType(WellKnownType.System_Type); var typeType = compilation.GetWellKnownType(WellKnownType.System_Type);
var stringType = compilation.GetSpecialType(SpecialType.System_String); var stringType = compilation.GetSpecialType(SpecialType.System_String);
var guidConstructor = (MethodSymbol)compilation.GetWellKnownTypeMember(WellKnownMember.System_Guid__ctor);
// CreateVariable(Type type, string name) // CreateVariable(Type type, string name)
var method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName); var method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName);
var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType); 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); 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( var call = BoundCall.Synthesized(
syntax, syntax,
receiverOpt: null, receiverOpt: null,
method: method, method: method,
arguments: ImmutableArray.Create<BoundExpression>(type, name)); arguments: ImmutableArray.Create(type, name, customTypeInfoPayloadId, customTypeInfoPayload));
statements.Add(new BoundExpressionStatement(syntax, call)); statements.Add(new BoundExpressionStatement(syntax, call));
var initializer = node.InitializerOpt; var initializer = node.InitializerOpt;
...@@ -85,5 +92,51 @@ internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymb ...@@ -85,5 +92,51 @@ internal static BoundNode Rewrite(CSharpCompilation compilation, EENamedTypeSymb
statements.Add(new BoundExpressionStatement(syntax, assignment)); 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 @@ ...@@ -2,7 +2,6 @@
using System.Collections; using System.Collections;
using System.Collections.Immutable; using System.Collections.Immutable;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols; using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.ExpressionEvaluator;
...@@ -19,7 +18,7 @@ internal static ImmutableArray<TypeParameterSymbol> GetAllTypeParameters(this Me ...@@ -19,7 +18,7 @@ internal static ImmutableArray<TypeParameterSymbol> GetAllTypeParameters(this Me
return builder.ToImmutableAndFree(); 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(); bool[] dynamicFlags = CSharpCompilation.DynamicTransformsEncoder.Encode(method.ReturnType, method.ReturnTypeCustomModifiers.Length, RefKind.None).ToArray();
var dynamicFlagsInfo = new DynamicFlagsCustomTypeInfo(new BitArray(dynamicFlags)); 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. // 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.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.CodeAnalysis.Test.Utilities;
using Microsoft.VisualStudio.Debugger.Evaluation;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using Roslyn.Test.PdbUtilities; using Roslyn.Test.PdbUtilities;
using Roslyn.Test.Utilities; using Roslyn.Test.Utilities;
...@@ -393,10 +397,6 @@ public class Outer<T, U> ...@@ -393,10 +397,6 @@ public class Outer<T, U>
{ {
public class Inner<V, W> public class Inner<V, W>
{ {
public enum E
{
A
}
} }
} }
"; ";
...@@ -429,6 +429,124 @@ .maxstack 1 ...@@ -429,6 +429,124 @@ .maxstack 1
result = context.CompileAssignment("d", "d", out error); result = context.CompileAssignment("d", "d", out error);
Assert.Null(error); Assert.Null(error);
VerifyCustomTypeInfo(result, null); 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] [Fact]
......
...@@ -231,11 +231,11 @@ void M(object o) ...@@ -231,11 +231,11 @@ void M(object o)
string typeName; string typeName;
var diagnostics = DiagnosticBag.GetInstance(); var diagnostics = DiagnosticBag.GetInstance();
var builder = ArrayBuilder<Alias>.GetInstance(); var builder = ArrayBuilder<Alias>.GetInstance();
builder.Add(new Alias(AliasKind.Exception, "Error", "$exception", typeof(System.IO.IOException).AssemblyQualifiedName)); 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)); 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)); 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)); builder.Add(new Alias(AliasKind.ObjectId, "2", "2", typeof(bool).AssemblyQualifiedName, default(CustomTypeInfo)));
builder.Add(new Alias(AliasKind.DeclaredLocal, "o", "o", "C")); builder.Add(new Alias(AliasKind.DeclaredLocal, "o", "o", "C", default(CustomTypeInfo)));
var aliases = new ReadOnlyCollection<Alias>(builder.ToArrayAndFree()); var aliases = new ReadOnlyCollection<Alias>(builder.ToArrayAndFree());
var testData = new CompilationTestData(); 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. // 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;
using System.Collections;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
...@@ -14,19 +15,26 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator ...@@ -14,19 +15,26 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator
internal struct CustomTypeInfo internal struct CustomTypeInfo
{ {
public Guid PayloadTypeId; 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.PayloadTypeId = payloadTypeId;
this.Payload = payload; this.Payload = payload;
} }
public DynamicFlagsCustomTypeInfo ToDynamicFlagsCustomTypeInfo()
{
return PayloadTypeId == DynamicFlagsCustomTypeInfo.PayloadTypeId
? new DynamicFlagsCustomTypeInfo(new BitArray(Payload))
: default(DynamicFlagsCustomTypeInfo);
}
public DkmClrCustomTypeInfo ToDkmClrCustomTypeInfo() public DkmClrCustomTypeInfo ToDkmClrCustomTypeInfo()
{ {
return Payload == null return Payload == null
? null ? null
: DkmClrCustomTypeInfo.Create(PayloadTypeId, Payload); : DkmClrCustomTypeInfo.Create(PayloadTypeId, new ReadOnlyCollection<byte>(Payload));
} }
} }
} }
...@@ -45,7 +45,26 @@ public DynamicFlagsCustomTypeInfo(DkmClrCustomTypeInfo typeInfo) ...@@ -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()) if (!Any())
{ {
...@@ -69,13 +88,13 @@ internal ReadOnlyCollection<byte> GetCustomTypeInfoPayload() ...@@ -69,13 +88,13 @@ internal ReadOnlyCollection<byte> GetCustomTypeInfoPayload()
} }
} }
return new ReadOnlyCollection<byte>(bytes); return bytes;
} }
public DkmClrCustomTypeInfo GetCustomTypeInfo() public DkmClrCustomTypeInfo GetCustomTypeInfo()
{ {
var payload = GetCustomTypeInfoPayload(); 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() public DynamicFlagsCustomTypeInfo SkipOne()
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation; using Microsoft.VisualStudio.Debugger.Evaluation.ClrCompilation;
using Roslyn.Utilities; using Roslyn.Utilities;
using System; using System;
using System.Collections.ObjectModel;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
...@@ -21,31 +20,26 @@ internal enum AliasKind ...@@ -21,31 +20,26 @@ internal enum AliasKind
internal struct Alias 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(kind != AliasKind.None);
Debug.Assert(!string.IsNullOrEmpty(fullName)); Debug.Assert(!string.IsNullOrEmpty(fullName));
Debug.Assert(!string.IsNullOrEmpty(type)); Debug.Assert(!string.IsNullOrEmpty(type));
Debug.Assert((customTypeInfo == null) == (customTypeInfoId == default(Guid)));
this.Kind = kind; this.Kind = kind;
this.Name = name; this.Name = name;
this.FullName = fullName; this.FullName = fullName;
this.Type = type; this.Type = type;
this.CustomTypeInfo = customTypeInfo; this.CustomTypeInfo = customTypeInfo;
this.CustomTypeInfoId = customTypeInfoId;
} }
internal readonly AliasKind Kind; internal readonly AliasKind Kind;
internal readonly string Name; internal readonly string Name;
internal readonly string FullName; internal readonly string FullName;
internal readonly string Type; internal readonly string Type;
internal readonly ReadOnlyCollection<byte> CustomTypeInfo; internal readonly CustomTypeInfo CustomTypeInfo;
internal readonly Guid CustomTypeInfoId;
} }
internal delegate ReadOnlyCollection<Alias> GetAliases();
internal static class PseudoVariableUtilities internal static class PseudoVariableUtilities
{ {
internal static bool TryParseVariableName(string name, bool caseSensitive, out AliasKind kind, out string id, out int index) 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 ...@@ -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> /// <summary>
/// This satisfies a cref on <see cref="Microsoft.CodeAnalysis.WellKnownMemberNames"/>. /// This satisfies a cref on <see cref="Microsoft.CodeAnalysis.WellKnownMemberNames"/>.
/// </summary> /// </summary>
......
...@@ -505,7 +505,7 @@ private static MetadataReference GetIntrinsicAssemblyReference() ...@@ -505,7 +505,7 @@ private static MetadataReference GetIntrinsicAssemblyReference()
ldnull ldnull
throw 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 ldnull
throw throw
......
...@@ -21,16 +21,16 @@ internal InspectionContextImpl(ReadOnlyCollection<Alias> variables) ...@@ -21,16 +21,16 @@ internal InspectionContextImpl(ReadOnlyCollection<Alias> variables)
_variables = 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(); var builder = ArrayBuilder<Alias>.GetInstance();
builder.AddRange(_variables); 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())); return new InspectionContextImpl(new ReadOnlyCollection<Alias>(builder.ToArrayAndFree()));
} }
......
...@@ -113,7 +113,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ...@@ -113,7 +113,9 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Return Nothing Return Nothing
End If 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 End Function
Friend Shared Function CreatePlaceholderLocal( Friend Shared Function CreatePlaceholderLocal(
......
...@@ -56,17 +56,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ...@@ -56,17 +56,25 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim typeType = compilation.GetWellKnownType(WellKnownType.System_Type) Dim typeType = compilation.GetWellKnownType(WellKnownType.System_Type)
Dim stringType = compilation.GetSpecialType(SpecialType.System_String) 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) ' CreateVariable(type As Type, name As String)
Dim method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName) Dim method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName)
Dim type = New BoundGetType(syntax, New BoundTypeExpression(syntax, local.Type), typeType) Dim type = New BoundGetType(syntax, New BoundTypeExpression(syntax, local.Type), typeType)
Dim name = New BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType) 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( Dim expr = New BoundCall(
syntax, syntax,
method, method,
methodGroupOpt:=Nothing, methodGroupOpt:=Nothing,
receiverOpt:=Nothing, receiverOpt:=Nothing,
arguments:=ImmutableArray.Create(Of BoundExpression)(type, name), arguments:=ImmutableArray.Create(Of BoundExpression)(type, name, customTypeInfoPayloadId, customTypeInfoPayload),
constantValueOpt:=Nothing, constantValueOpt:=Nothing,
suppressObjectClone:=False, suppressObjectClone:=False,
type:=method.ReturnType) type:=method.ReturnType)
......
...@@ -137,11 +137,11 @@ End Class" ...@@ -137,11 +137,11 @@ End Class"
Dim typeName As String = Nothing Dim typeName As String = Nothing
Dim diagnostics = DiagnosticBag.GetInstance() Dim diagnostics = DiagnosticBag.GetInstance()
Dim builder = ArrayBuilder(Of [Alias]).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.Exception, "Error", "$exception", GetType(System.IO.IOException).AssemblyQualifiedName, customTypeInfo:=Nothing))
builder.Add(New [Alias](AliasKind.ReturnValue, "F returned", "$ReturnValue2", GetType(String).AssemblyQualifiedName)) 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)) 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)) builder.Add(New [Alias](AliasKind.ObjectId, "2", "2", GetType(Boolean).AssemblyQualifiedName, customTypeInfo:=Nothing))
builder.Add(New [Alias](AliasKind.DeclaredLocal, "o", "o", "C")) builder.Add(New [Alias](AliasKind.DeclaredLocal, "o", "o", "C", customTypeInfo:=Nothing))
Dim aliases = New ReadOnlyCollection(Of [Alias])(builder.ToArrayAndFree()) Dim aliases = New ReadOnlyCollection(Of [Alias])(builder.ToArrayAndFree())
Dim testData = New CompilationTestData() Dim testData = New CompilationTestData()
......
...@@ -802,18 +802,23 @@ End Class ...@@ -802,18 +802,23 @@ End Class
Assert.Null(errorMessage) Assert.Null(errorMessage)
testData.GetMethodData("<>x.<>m0").VerifyIL( testData.GetMethodData("<>x.<>m0").VerifyIL(
"{ "{
// Code size 33 (0x21) // Code size 43 (0x2b)
.maxstack 2 .maxstack 4
.locals init (T V_0) //F .locals init (T V_0, //F
System.Guid V_1)
IL_0000: ldtoken ""Object"" IL_0000: ldtoken ""Object""
IL_0005: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type"" IL_0005: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_000a: ldstr ""x"" IL_000a: ldstr ""x""
IL_000f: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String)"" IL_000f: ldloca.s V_1
IL_0014: ldstr ""x"" IL_0011: initobj ""System.Guid""
IL_0019: call ""Function Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress(Of Object)(String) As Object"" IL_0017: ldloc.1
IL_001e: ldnull IL_0018: ldnull
IL_001f: stind.ref IL_0019: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String, System.Guid, Byte())""
IL_0020: ret 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() testData = New CompilationTestData()
context.CompileExpression( context.CompileExpression(
...@@ -830,18 +835,23 @@ End Class ...@@ -830,18 +835,23 @@ End Class
Assert.Null(errorMessage) Assert.Null(errorMessage)
testData.GetMethodData("<>x.<>m0").VerifyIL( testData.GetMethodData("<>x.<>m0").VerifyIL(
"{ "{
// Code size 37 (0x25) // Code size 47 (0x2f)
.maxstack 2 .maxstack 4
.locals init (T V_0) //F .locals init (T V_0, //F
System.Guid V_1)
IL_0000: ldtoken ""Object"" IL_0000: ldtoken ""Object""
IL_0005: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type"" IL_0005: call ""Function System.Type.GetTypeFromHandle(System.RuntimeTypeHandle) As System.Type""
IL_000a: ldstr ""x"" IL_000a: ldstr ""x""
IL_000f: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String)"" IL_000f: ldloca.s V_1
IL_0014: ldstr ""x"" IL_0011: initobj ""System.Guid""
IL_0019: call ""Function Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.GetVariableAddress(Of Object)(String) As Object"" IL_0017: ldloc.1
IL_001e: call ""Function C.F(Of Object)(ByRef Object) As Object"" IL_0018: ldnull
IL_0023: pop IL_0019: call ""Sub Microsoft.VisualStudio.Debugger.Clr.IntrinsicMethods.CreateVariable(System.Type, String, System.Guid, Byte())""
IL_0024: ret 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 End Sub
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册