/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/Test/Core/Metadata/ILBuilderVisualizer.cs
512 строк
23 KB
Fred Silberberg
Simplify sequence point display (#81104)
10 ноя 2025, 20:11
Не верифицирован
10 ноя 2025, 20:11
0544ad5
Код
Авторство
О чём код?
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Reflection.Emit; using System.Reflection.Metadata; using System.Text; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CodeGen; using Microsoft.CodeAnalysis.Emit; using Microsoft.CodeAnalysis.PooledObjects; using Microsoft.CodeAnalysis.Symbols; using Microsoft.Metadata.Tools; using Roslyn.Utilities; using Cci = Microsoft.Cci; namespace Roslyn.Test.Utilities { internal sealed class ILBuilderVisualizer : ILVisualizer { private readonly CommonPEModuleBuilder _module; private readonly SymbolDisplayFormat _symbolDisplayFormat; public ILBuilderVisualizer(CommonPEModuleBuilder module, SymbolDisplayFormat? symbolDisplayFormat = null) { _module = module; _symbolDisplayFormat = symbolDisplayFormat ?? SymbolDisplayFormat.ILVisualizationFormat; } public override string VisualizeUserString(uint token) { // Check for an encoding of the spelling of the current module's module version ID. if (token == 0x80000000) { return "##MVID##"; } return "\"" + _module.GetStringFromToken(token) + "\""; } public override string VisualizeSymbol(uint token, OperandType operandType) { if (operandType == OperandType.InlineTok) { switch ((Cci.MetadataWriter.RawTokenEncoding)(token >> 24)) { case Cci.MetadataWriter.RawTokenEncoding.GreatestMethodDefinitionRowId: return "Max Method Token Index"; case Cci.MetadataWriter.RawTokenEncoding.DocumentRowId: return "Source Document " + (token & 0x00ffffff).ToString(); } token &= 0xffffff; } object reference = _module.GetReferenceFromToken(token); ISymbol? symbol = ((reference as ISymbolInternal) ?? (reference as Cci.IReference)?.GetInternalSymbol())?.GetISymbol(); return string.Format("\"{0}\"", symbol == null ? (object)reference : symbol.ToDisplayString(_symbolDisplayFormat)); } public override string? VisualizeLocalType(object type) { return (((type as ISymbolInternal) ?? (type as Cci.IReference)?.GetInternalSymbol()) is ISymbolInternal symbol) ? symbol.GetISymbol().ToDisplayString(_symbolDisplayFormat) : type.ToString(); } /// <summary> /// Determine the list of spans ordered by handler /// block start, with outer handlers before inner. /// </summary> private static List<HandlerSpan>? GetHandlerSpans(ImmutableArray<Cci.ExceptionHandlerRegion> regions) { if (regions.IsDefaultOrEmpty) { return null; } var spans = new List<HandlerSpan>(); // Add unique try blocks. foreach (Cci.ExceptionHandlerRegion region in regions) { var span = new HandlerSpan(HandlerKind.Try, null, region.TryStartOffset, region.TryEndOffset); int n = spans.Count; if (n == 0 || span.CompareTo(spans[n - 1]) != 0) { spans.Add(span); } } // Add all handler blocks. foreach (Cci.ExceptionHandlerRegion region in regions) { HandlerSpan span; if (region.HandlerKind == System.Reflection.Metadata.ExceptionRegionKind.Filter) { span = new HandlerSpan(HandlerKind.Filter, null, region.FilterDecisionStartOffset, region.HandlerEndOffset, region.HandlerStartOffset); } else { HandlerKind kind; switch (region.HandlerKind) { case System.Reflection.Metadata.ExceptionRegionKind.Catch: kind = HandlerKind.Catch; break; case System.Reflection.Metadata.ExceptionRegionKind.Fault: kind = HandlerKind.Fault; break; case System.Reflection.Metadata.ExceptionRegionKind.Filter: kind = HandlerKind.Filter; break; default: kind = HandlerKind.Finally; break; } span = new HandlerSpan(kind, region.ExceptionType, region.HandlerStartOffset, region.HandlerEndOffset); } spans.Add(span); } spans.Sort(); return spans; } /// <remarks> /// Invoked via Reflection from <see cref="ILBuilder"/><c>.GetDebuggerDisplay()</c>. /// </remarks> internal static string ILBuilderToString( ILBuilder builder, Func<Cci.ILocalDefinition, LocalInfo>? mapLocal = null, IReadOnlyDictionary<int, string>? markers = null, SymbolDisplayFormat? ilFormat = null) { Debug.Assert(builder.LocalSlotManager != null); var sb = new StringBuilder(); var ilStream = builder.RealizedIL; if (mapLocal == null) { mapLocal = local => new LocalInfo(local.Name, local.Type, local.IsPinned, local.IsReference); } var locals = builder.LocalSlotManager.LocalsInOrder().SelectAsArray(mapLocal); var visualizer = new ILBuilderVisualizer(builder.module, ilFormat); if (!ilStream.IsDefault) { visualizer.DumpMethod(sb, builder.MaxStack, ilStream, locals, GetHandlerSpans(builder.RealizedExceptionHandlers), markers, builder.AreLocalsZeroed); } else { sb.AppendLine("{"); visualizer.VisualizeHeader(sb, 0, builder.MaxStack, locals); // serialize blocks as-is var current = builder.leaderBlock; while (current != null) { DumpBlockIL(current, sb); current = current.NextBlock; } sb.AppendLine("}"); } return sb.ToString(); } internal static string LocalSignatureToString( ILBuilder builder, Func<Cci.ILocalDefinition, LocalInfo>? mapLocal = null) { Debug.Assert(builder.LocalSlotManager != null); var sb = new StringBuilder(); if (mapLocal == null) { mapLocal = local => new LocalInfo(local.Name, local.Type, local.IsPinned, local.IsReference); } var locals = builder.LocalSlotManager.LocalsInOrder().SelectAsArray(mapLocal); var visualizer = new ILBuilderVisualizer(builder.module); visualizer.VisualizeHeader(sb, -1, -1, locals); return sb.ToString(); } #pragma warning disable IDE0051 // Remove unused private members, used for debugger display of BasicBlock via reflection private static string BasicBlockToString(ILBuilder.BasicBlock block) #pragma warning restore IDE0051 // Remove unused private members { StringBuilder sb = new StringBuilder(); DumpBlockIL(block, sb); return sb.ToString(); } private static void DumpBlockIL(ILBuilder.BasicBlock block, StringBuilder sb) { if (block is ILBuilder.SwitchBlock switchBlock) { DumpSwitchBlockIL(switchBlock, sb); } else { DumpBasicBlockIL(block, sb); } } private static void DumpBasicBlockIL(ILBuilder.BasicBlock block, StringBuilder sb) { var instrCnt = block.RegularInstructionsLength; if (instrCnt != 0) { var il = block.RegularInstructions.ToImmutableArray(); new ILBuilderVisualizer(block.builder.module).DumpILBlock(il, instrCnt, sb, Array.Empty<ILVisualizer.HandlerSpan>(), block.Start); } if (block.BranchCode != ILOpCode.Nop) { sb.Append(string.Format(" IL_{0:x4}:", block.RegularInstructionsLength + block.Start)); sb.Append(string.Format(" {0,-10}", GetInstructionName(block.BranchCode))); if (block.BranchCode.IsBranch()) { var branchBlock = block.BranchBlock; if (branchBlock == null) { // this happens if label is not yet marked. sb.Append(" <unmarked label>"); } else { sb.Append(string.Format(" IL_{0:x4}", branchBlock.Start)); } } sb.AppendLine(); } } private static void DumpSwitchBlockIL(ILBuilder.SwitchBlock block, StringBuilder sb) { var il = block.RegularInstructions.ToImmutableArray(); new ILBuilderVisualizer(block.builder.module).DumpILBlock(il, il.Length, sb, Array.Empty<HandlerSpan>(), block.Start); // switch (N, t1, t2... tN) // IL ==> ILOpCode.Switch < unsigned int32 > < int32 >... < int32 > sb.Append(string.Format(" IL_{0:x4}:", block.RegularInstructionsLength + block.Start)); sb.Append(string.Format(" {0,-10}", GetInstructionName(block.BranchCode))); sb.Append(string.Format(" IL_{0:x4}:", block.BranchesCount)); var blockBuilder = ArrayBuilder<ILBuilder.BasicBlock>.GetInstance(); block.GetBranchBlocks(blockBuilder); foreach (var branchBlock in blockBuilder) { if (branchBlock == null) { // this happens if label is not yet marked. sb.Append(" <unmarked label>"); } else { sb.Append(string.Format(" IL_{0:x4}", branchBlock.Start)); } } blockBuilder.Free(); sb.AppendLine(); } private static string GetInstructionName(ILOpCode opcode) { switch (opcode) { case ILOpCode.Nop: return "nop"; case ILOpCode.Break: return "break"; case ILOpCode.Ldarg_0: return "ldarg.0"; case ILOpCode.Ldarg_1: return "ldarg.1"; case ILOpCode.Ldarg_2: return "ldarg.2"; case ILOpCode.Ldarg_3: return "ldarg.3"; case ILOpCode.Ldloc_0: return "ldloc.0"; case ILOpCode.Ldloc_1: return "ldloc.1"; case ILOpCode.Ldloc_2: return "ldloc.2"; case ILOpCode.Ldloc_3: return "ldloc.3"; case ILOpCode.Stloc_0: return "stloc.0"; case ILOpCode.Stloc_1: return "stloc.1"; case ILOpCode.Stloc_2: return "stloc.2"; case ILOpCode.Stloc_3: return "stloc.3"; case ILOpCode.Ldarg_s: return "ldarg.s"; case ILOpCode.Ldarga_s: return "ldarga.s"; case ILOpCode.Starg_s: return "starg.s"; case ILOpCode.Ldloc_s: return "ldloc.s"; case ILOpCode.Ldloca_s: return "ldloca.s"; case ILOpCode.Stloc_s: return "stloc.s"; case ILOpCode.Ldnull: return "ldnull"; case ILOpCode.Ldc_i4_m1: return "ldc.i4.m1"; case ILOpCode.Ldc_i4_0: return "ldc.i4.0"; case ILOpCode.Ldc_i4_1: return "ldc.i4.1"; case ILOpCode.Ldc_i4_2: return "ldc.i4.2"; case ILOpCode.Ldc_i4_3: return "ldc.i4.3"; case ILOpCode.Ldc_i4_4: return "ldc.i4.4"; case ILOpCode.Ldc_i4_5: return "ldc.i4.5"; case ILOpCode.Ldc_i4_6: return "ldc.i4.6"; case ILOpCode.Ldc_i4_7: return "ldc.i4.7"; case ILOpCode.Ldc_i4_8: return "ldc.i4.8"; case ILOpCode.Ldc_i4_s: return "ldc.i4.s"; case ILOpCode.Ldc_i4: return "ldc.i4"; case ILOpCode.Ldc_i8: return "ldc.i8"; case ILOpCode.Ldc_r4: return "ldc.r4"; case ILOpCode.Ldc_r8: return "ldc.r8"; case ILOpCode.Dup: return "dup"; case ILOpCode.Pop: return "pop"; case ILOpCode.Jmp: return "jmp"; case ILOpCode.Call: return "call"; case ILOpCode.Calli: return "calli"; case ILOpCode.Ret: return "ret"; case ILOpCode.Br_s: return "br.s"; case ILOpCode.Brfalse_s: return "brfalse.s"; case ILOpCode.Brtrue_s: return "brtrue.s"; case ILOpCode.Beq_s: return "beq.s"; case ILOpCode.Bge_s: return "bge.s"; case ILOpCode.Bgt_s: return "bgt.s"; case ILOpCode.Ble_s: return "ble.s"; case ILOpCode.Blt_s: return "blt.s"; case ILOpCode.Bne_un_s: return "bne.un.s"; case ILOpCode.Bge_un_s: return "bge.un.s"; case ILOpCode.Bgt_un_s: return "bgt.un.s"; case ILOpCode.Ble_un_s: return "ble.un.s"; case ILOpCode.Blt_un_s: return "blt.un.s"; case ILOpCode.Br: return "br"; case ILOpCode.Brfalse: return "brfalse"; case ILOpCode.Brtrue: return "brtrue"; case ILOpCode.Beq: return "beq"; case ILOpCode.Bge: return "bge"; case ILOpCode.Bgt: return "bgt"; case ILOpCode.Ble: return "ble"; case ILOpCode.Blt: return "blt"; case ILOpCode.Bne_un: return "bne.un"; case ILOpCode.Bge_un: return "bge.un"; case ILOpCode.Bgt_un: return "bgt.un"; case ILOpCode.Ble_un: return "ble.un"; case ILOpCode.Blt_un: return "blt.un"; case ILOpCode.Switch: return "switch"; case ILOpCode.Ldind_i1: return "ldind.i1"; case ILOpCode.Ldind_u1: return "ldind.u1"; case ILOpCode.Ldind_i2: return "ldind.i2"; case ILOpCode.Ldind_u2: return "ldind.u2"; case ILOpCode.Ldind_i4: return "ldind.i4"; case ILOpCode.Ldind_u4: return "ldind.u4"; case ILOpCode.Ldind_i8: return "ldind.i8"; case ILOpCode.Ldind_i: return "ldind.i"; case ILOpCode.Ldind_r4: return "ldind.r4"; case ILOpCode.Ldind_r8: return "ldind.r8"; case ILOpCode.Ldind_ref: return "ldind.ref"; case ILOpCode.Stind_ref: return "stind.ref"; case ILOpCode.Stind_i1: return "stind.i1"; case ILOpCode.Stind_i2: return "stind.i2"; case ILOpCode.Stind_i4: return "stind.i4"; case ILOpCode.Stind_i8: return "stind.i8"; case ILOpCode.Stind_r4: return "stind.r4"; case ILOpCode.Stind_r8: return "stind.r8"; case ILOpCode.Add: return "add"; case ILOpCode.Sub: return "sub"; case ILOpCode.Mul: return "mul"; case ILOpCode.Div: return "div"; case ILOpCode.Div_un: return "div.un"; case ILOpCode.Rem: return "rem"; case ILOpCode.Rem_un: return "rem.un"; case ILOpCode.And: return "and"; case ILOpCode.Or: return "or"; case ILOpCode.Xor: return "xor"; case ILOpCode.Shl: return "shl"; case ILOpCode.Shr: return "shr"; case ILOpCode.Shr_un: return "shr.un"; case ILOpCode.Neg: return "neg"; case ILOpCode.Not: return "not"; case ILOpCode.Conv_i1: return "conv.i1"; case ILOpCode.Conv_i2: return "conv.i2"; case ILOpCode.Conv_i4: return "conv.i4"; case ILOpCode.Conv_i8: return "conv.i8"; case ILOpCode.Conv_r4: return "conv.r4"; case ILOpCode.Conv_r8: return "conv.r8"; case ILOpCode.Conv_u4: return "conv.u4"; case ILOpCode.Conv_u8: return "conv.u8"; case ILOpCode.Callvirt: return "callvirt"; case ILOpCode.Cpobj: return "cpobj"; case ILOpCode.Ldobj: return "ldobj"; case ILOpCode.Ldstr: return "ldstr"; case ILOpCode.Newobj: return "newobj"; case ILOpCode.Castclass: return "castclass"; case ILOpCode.Isinst: return "isinst"; case ILOpCode.Conv_r_un: return "conv.r.un"; case ILOpCode.Unbox: return "unbox"; case ILOpCode.Throw: return "throw"; case ILOpCode.Ldfld: return "ldfld"; case ILOpCode.Ldflda: return "ldflda"; case ILOpCode.Stfld: return "stfld"; case ILOpCode.Ldsfld: return "ldsfld"; case ILOpCode.Ldsflda: return "ldsflda"; case ILOpCode.Stsfld: return "stsfld"; case ILOpCode.Stobj: return "stobj"; case ILOpCode.Conv_ovf_i1_un: return "conv.ovf.i1.un"; case ILOpCode.Conv_ovf_i2_un: return "conv.ovf.i2.un"; case ILOpCode.Conv_ovf_i4_un: return "conv.ovf.i4.un"; case ILOpCode.Conv_ovf_i8_un: return "conv.ovf.i8.un"; case ILOpCode.Conv_ovf_u1_un: return "conv.ovf.u1.un"; case ILOpCode.Conv_ovf_u2_un: return "conv.ovf.u2.un"; case ILOpCode.Conv_ovf_u4_un: return "conv.ovf.u4.un"; case ILOpCode.Conv_ovf_u8_un: return "conv.ovf.u8.un"; case ILOpCode.Conv_ovf_i_un: return "conv.ovf.i.un"; case ILOpCode.Conv_ovf_u_un: return "conv.ovf.u.un"; case ILOpCode.Box: return "box"; case ILOpCode.Newarr: return "newarr"; case ILOpCode.Ldlen: return "ldlen"; case ILOpCode.Ldelema: return "ldelema"; case ILOpCode.Ldelem_i1: return "ldelem.i1"; case ILOpCode.Ldelem_u1: return "ldelem.u1"; case ILOpCode.Ldelem_i2: return "ldelem.i2"; case ILOpCode.Ldelem_u2: return "ldelem.u2"; case ILOpCode.Ldelem_i4: return "ldelem.i4"; case ILOpCode.Ldelem_u4: return "ldelem.u4"; case ILOpCode.Ldelem_i8: return "ldelem.i8"; case ILOpCode.Ldelem_i: return "ldelem.i"; case ILOpCode.Ldelem_r4: return "ldelem.r4"; case ILOpCode.Ldelem_r8: return "ldelem.r8"; case ILOpCode.Ldelem_ref: return "ldelem.ref"; case ILOpCode.Stelem_i: return "stelem.i"; case ILOpCode.Stelem_i1: return "stelem.i1"; case ILOpCode.Stelem_i2: return "stelem.i2"; case ILOpCode.Stelem_i4: return "stelem.i4"; case ILOpCode.Stelem_i8: return "stelem.i8"; case ILOpCode.Stelem_r4: return "stelem.r4"; case ILOpCode.Stelem_r8: return "stelem.r8"; case ILOpCode.Stelem_ref: return "stelem.ref"; case ILOpCode.Ldelem: return "ldelem"; case ILOpCode.Stelem: return "stelem"; case ILOpCode.Unbox_any: return "unbox.any"; case ILOpCode.Conv_ovf_i1: return "conv.ovf.i1"; case ILOpCode.Conv_ovf_u1: return "conv.ovf.u1"; case ILOpCode.Conv_ovf_i2: return "conv.ovf.i2"; case ILOpCode.Conv_ovf_u2: return "conv.ovf.u2"; case ILOpCode.Conv_ovf_i4: return "conv.ovf.i4"; case ILOpCode.Conv_ovf_u4: return "conv.ovf.u4"; case ILOpCode.Conv_ovf_i8: return "conv.ovf.i8"; case ILOpCode.Conv_ovf_u8: return "conv.ovf.u8"; case ILOpCode.Refanyval: return "refanyval"; case ILOpCode.Ckfinite: return "ckfinite"; case ILOpCode.Mkrefany: return "mkrefany"; case ILOpCode.Ldtoken: return "ldtoken"; case ILOpCode.Conv_u2: return "conv.u2"; case ILOpCode.Conv_u1: return "conv.u1"; case ILOpCode.Conv_i: return "conv.i"; case ILOpCode.Conv_ovf_i: return "conv.ovf.i"; case ILOpCode.Conv_ovf_u: return "conv.ovf.u"; case ILOpCode.Add_ovf: return "add.ovf"; case ILOpCode.Add_ovf_un: return "add.ovf.un"; case ILOpCode.Mul_ovf: return "mul.ovf"; case ILOpCode.Mul_ovf_un: return "mul.ovf.un"; case ILOpCode.Sub_ovf: return "sub.ovf"; case ILOpCode.Sub_ovf_un: return "sub.ovf.un"; case ILOpCode.Endfinally: return "endfinally"; case ILOpCode.Leave: return "leave"; case ILOpCode.Leave_s: return "leave.s"; case ILOpCode.Stind_i: return "stind.i"; case ILOpCode.Conv_u: return "conv.u"; case ILOpCode.Arglist: return "arglist"; case ILOpCode.Ceq: return "ceq"; case ILOpCode.Cgt: return "cgt"; case ILOpCode.Cgt_un: return "cgt.un"; case ILOpCode.Clt: return "clt"; case ILOpCode.Clt_un: return "clt.un"; case ILOpCode.Ldftn: return "ldftn"; case ILOpCode.Ldvirtftn: return "ldvirtftn"; case ILOpCode.Ldarg: return "ldarg"; case ILOpCode.Ldarga: return "ldarga"; case ILOpCode.Starg: return "starg"; case ILOpCode.Ldloc: return "ldloc"; case ILOpCode.Ldloca: return "ldloca"; case ILOpCode.Stloc: return "stloc"; case ILOpCode.Localloc: return "localloc"; case ILOpCode.Endfilter: return "endfilter"; case ILOpCode.Unaligned: return "unaligned."; case ILOpCode.Volatile: return "volatile."; case ILOpCode.Tail: return "tail."; case ILOpCode.Initobj: return "initobj"; case ILOpCode.Constrained: return "constrained."; case ILOpCode.Cpblk: return "cpblk"; case ILOpCode.Initblk: return "initblk"; case ILOpCode.Rethrow: return "rethrow"; case ILOpCode.Sizeof: return "sizeof"; case ILOpCode.Refanytype: return "refanytype"; case ILOpCode.Readonly: return "readonly."; } throw ExceptionUtilities.UnexpectedValue(opcode); } } }