using System.Reflection.Metadata; using Roslyn.Utilities; namespace Microsoft.CodeAnalysis.CodeGen; internal static class ILOpCodeExtensions { public static int Size(this ILOpCode opcode) { if ((int)opcode <= 255) { return 1; } return 2; } public static ILOpCode GetLeaveOpcode(this ILOpCode opcode) { return opcode switch { ILOpCode.Br => ILOpCode.Leave, ILOpCode.Br_s => ILOpCode.Leave_s, _ => throw ExceptionUtilities.UnexpectedValue(opcode), }; } public static bool HasVariableStackBehavior(this ILOpCode opcode) { if (opcode - 40 <= ILOpCode.Ldarg_0 || opcode == ILOpCode.Callvirt || opcode == ILOpCode.Newobj) { return true; } return false; } public static bool IsControlTransfer(this ILOpCode opcode) { if (opcode.IsBranch()) { return true; } switch (opcode) { case ILOpCode.Jmp: case ILOpCode.Ret: case ILOpCode.Switch: case ILOpCode.Throw: case ILOpCode.Endfinally: case ILOpCode.Endfilter: case ILOpCode.Rethrow: return true; default: return false; } } public static bool IsConditionalBranch(this ILOpCode opcode) { if (opcode - 44 <= ILOpCode.Stloc_1 || opcode - 57 <= ILOpCode.Stloc_1) { return true; } return false; } public static bool IsRelationalBranch(this ILOpCode opcode) { if (opcode - 46 <= ILOpCode.Ldloc_3 || opcode - 59 <= ILOpCode.Ldloc_3) { return true; } return false; } public static bool CanFallThrough(this ILOpCode opcode) { switch (opcode) { case ILOpCode.Jmp: case ILOpCode.Ret: case ILOpCode.Br_s: case ILOpCode.Br: case ILOpCode.Throw: case ILOpCode.Endfinally: case ILOpCode.Leave: case ILOpCode.Leave_s: case ILOpCode.Rethrow: return false; default: return true; } } public static int NetStackBehavior(this ILOpCode opcode) { return opcode.StackPushCount() - opcode.StackPopCount(); } public static int StackPopCount(this ILOpCode opcode) { switch (opcode) { case ILOpCode.Nop: case ILOpCode.Break: case ILOpCode.Ldarg_0: case ILOpCode.Ldarg_1: case ILOpCode.Ldarg_2: case ILOpCode.Ldarg_3: case ILOpCode.Ldloc_0: case ILOpCode.Ldloc_1: case ILOpCode.Ldloc_2: case ILOpCode.Ldloc_3: return 0; case ILOpCode.Stloc_0: case ILOpCode.Stloc_1: case ILOpCode.Stloc_2: case ILOpCode.Stloc_3: return 1; case ILOpCode.Ldarg_s: case ILOpCode.Ldarga_s: return 0; case ILOpCode.Starg_s: return 1; case ILOpCode.Ldloc_s: case ILOpCode.Ldloca_s: return 0; case ILOpCode.Stloc_s: return 1; case ILOpCode.Ldnull: case ILOpCode.Ldc_i4_m1: case ILOpCode.Ldc_i4_0: case ILOpCode.Ldc_i4_1: case ILOpCode.Ldc_i4_2: case ILOpCode.Ldc_i4_3: case ILOpCode.Ldc_i4_4: case ILOpCode.Ldc_i4_5: case ILOpCode.Ldc_i4_6: case ILOpCode.Ldc_i4_7: case ILOpCode.Ldc_i4_8: case ILOpCode.Ldc_i4_s: case ILOpCode.Ldc_i4: case ILOpCode.Ldc_i8: case ILOpCode.Ldc_r4: case ILOpCode.Ldc_r8: return 0; case ILOpCode.Dup: case ILOpCode.Pop: return 1; case ILOpCode.Jmp: return 0; case ILOpCode.Call: case ILOpCode.Calli: case ILOpCode.Ret: return -1; case ILOpCode.Br_s: return 0; case ILOpCode.Brfalse_s: case ILOpCode.Brtrue_s: return 1; case ILOpCode.Beq_s: case ILOpCode.Bge_s: case ILOpCode.Bgt_s: case ILOpCode.Ble_s: case ILOpCode.Blt_s: case ILOpCode.Bne_un_s: case ILOpCode.Bge_un_s: case ILOpCode.Bgt_un_s: case ILOpCode.Ble_un_s: case ILOpCode.Blt_un_s: return 2; case ILOpCode.Br: return 0; case ILOpCode.Brfalse: case ILOpCode.Brtrue: return 1; case ILOpCode.Beq: case ILOpCode.Bge: case ILOpCode.Bgt: case ILOpCode.Ble: case ILOpCode.Blt: case ILOpCode.Bne_un: case ILOpCode.Bge_un: case ILOpCode.Bgt_un: case ILOpCode.Ble_un: case ILOpCode.Blt_un: return 2; case ILOpCode.Switch: case ILOpCode.Ldind_i1: case ILOpCode.Ldind_u1: case ILOpCode.Ldind_i2: case ILOpCode.Ldind_u2: case ILOpCode.Ldind_i4: case ILOpCode.Ldind_u4: case ILOpCode.Ldind_i8: case ILOpCode.Ldind_i: case ILOpCode.Ldind_r4: case ILOpCode.Ldind_r8: case ILOpCode.Ldind_ref: return 1; case ILOpCode.Stind_ref: case ILOpCode.Stind_i1: case ILOpCode.Stind_i2: case ILOpCode.Stind_i4: case ILOpCode.Stind_i8: case ILOpCode.Stind_r4: case ILOpCode.Stind_r8: case ILOpCode.Add: case ILOpCode.Sub: case ILOpCode.Mul: case ILOpCode.Div: case ILOpCode.Div_un: case ILOpCode.Rem: case ILOpCode.Rem_un: case ILOpCode.And: case ILOpCode.Or: case ILOpCode.Xor: case ILOpCode.Shl: case ILOpCode.Shr: case ILOpCode.Shr_un: return 2; case ILOpCode.Neg: case ILOpCode.Not: case ILOpCode.Conv_i1: case ILOpCode.Conv_i2: case ILOpCode.Conv_i4: case ILOpCode.Conv_i8: case ILOpCode.Conv_r4: case ILOpCode.Conv_r8: case ILOpCode.Conv_u4: case ILOpCode.Conv_u8: return 1; case ILOpCode.Callvirt: return -1; case ILOpCode.Cpobj: return 2; case ILOpCode.Ldobj: return 1; case ILOpCode.Ldstr: return 0; case ILOpCode.Newobj: return -1; case ILOpCode.Castclass: case ILOpCode.Isinst: case ILOpCode.Conv_r_un: case ILOpCode.Unbox: case ILOpCode.Throw: case ILOpCode.Ldfld: case ILOpCode.Ldflda: return 1; case ILOpCode.Stfld: return 2; case ILOpCode.Ldsfld: case ILOpCode.Ldsflda: return 0; case ILOpCode.Stsfld: return 1; case ILOpCode.Stobj: return 2; case ILOpCode.Conv_ovf_i1_un: case ILOpCode.Conv_ovf_i2_un: case ILOpCode.Conv_ovf_i4_un: case ILOpCode.Conv_ovf_i8_un: case ILOpCode.Conv_ovf_u1_un: case ILOpCode.Conv_ovf_u2_un: case ILOpCode.Conv_ovf_u4_un: case ILOpCode.Conv_ovf_u8_un: case ILOpCode.Conv_ovf_i_un: case ILOpCode.Conv_ovf_u_un: case ILOpCode.Box: case ILOpCode.Newarr: case ILOpCode.Ldlen: return 1; case ILOpCode.Ldelema: case ILOpCode.Ldelem_i1: case ILOpCode.Ldelem_u1: case ILOpCode.Ldelem_i2: case ILOpCode.Ldelem_u2: case ILOpCode.Ldelem_i4: case ILOpCode.Ldelem_u4: case ILOpCode.Ldelem_i8: case ILOpCode.Ldelem_i: case ILOpCode.Ldelem_r4: case ILOpCode.Ldelem_r8: case ILOpCode.Ldelem_ref: return 2; case ILOpCode.Stelem_i: case ILOpCode.Stelem_i1: case ILOpCode.Stelem_i2: case ILOpCode.Stelem_i4: case ILOpCode.Stelem_i8: case ILOpCode.Stelem_r4: case ILOpCode.Stelem_r8: case ILOpCode.Stelem_ref: return 3; case ILOpCode.Ldelem: return 2; case ILOpCode.Stelem: return 3; case ILOpCode.Unbox_any: case ILOpCode.Conv_ovf_i1: case ILOpCode.Conv_ovf_u1: case ILOpCode.Conv_ovf_i2: case ILOpCode.Conv_ovf_u2: case ILOpCode.Conv_ovf_i4: case ILOpCode.Conv_ovf_u4: case ILOpCode.Conv_ovf_i8: case ILOpCode.Conv_ovf_u8: case ILOpCode.Refanyval: case ILOpCode.Ckfinite: case ILOpCode.Mkrefany: return 1; case ILOpCode.Ldtoken: return 0; case ILOpCode.Conv_u2: case ILOpCode.Conv_u1: case ILOpCode.Conv_i: case ILOpCode.Conv_ovf_i: case ILOpCode.Conv_ovf_u: return 1; case ILOpCode.Add_ovf: case ILOpCode.Add_ovf_un: case ILOpCode.Mul_ovf: case ILOpCode.Mul_ovf_un: case ILOpCode.Sub_ovf: case ILOpCode.Sub_ovf_un: return 2; case ILOpCode.Endfinally: case ILOpCode.Leave: case ILOpCode.Leave_s: return 0; case ILOpCode.Stind_i: return 2; case ILOpCode.Conv_u: return 1; case ILOpCode.Arglist: return 0; case ILOpCode.Ceq: case ILOpCode.Cgt: case ILOpCode.Cgt_un: case ILOpCode.Clt: case ILOpCode.Clt_un: return 2; case ILOpCode.Ldftn: return 0; case ILOpCode.Ldvirtftn: return 1; case ILOpCode.Ldarg: case ILOpCode.Ldarga: return 0; case ILOpCode.Starg: return 1; case ILOpCode.Ldloc: case ILOpCode.Ldloca: return 0; case ILOpCode.Stloc: case ILOpCode.Localloc: case ILOpCode.Endfilter: return 1; case ILOpCode.Unaligned: case ILOpCode.Volatile: case ILOpCode.Tail: return 0; case ILOpCode.Initobj: return 1; case ILOpCode.Constrained: return 0; case ILOpCode.Cpblk: case ILOpCode.Initblk: return 3; case ILOpCode.Rethrow: case ILOpCode.Sizeof: return 0; case ILOpCode.Refanytype: return 1; case ILOpCode.Readonly: return 0; default: throw ExceptionUtilities.UnexpectedValue(opcode); } } public static int StackPushCount(this ILOpCode opcode) { switch (opcode) { case ILOpCode.Nop: case ILOpCode.Break: return 0; case ILOpCode.Ldarg_0: case ILOpCode.Ldarg_1: case ILOpCode.Ldarg_2: case ILOpCode.Ldarg_3: case ILOpCode.Ldloc_0: case ILOpCode.Ldloc_1: case ILOpCode.Ldloc_2: case ILOpCode.Ldloc_3: return 1; case ILOpCode.Stloc_0: case ILOpCode.Stloc_1: case ILOpCode.Stloc_2: case ILOpCode.Stloc_3: return 0; case ILOpCode.Ldarg_s: case ILOpCode.Ldarga_s: return 1; case ILOpCode.Starg_s: return 0; case ILOpCode.Ldloc_s: case ILOpCode.Ldloca_s: return 1; case ILOpCode.Stloc_s: return 0; case ILOpCode.Ldnull: case ILOpCode.Ldc_i4_m1: case ILOpCode.Ldc_i4_0: case ILOpCode.Ldc_i4_1: case ILOpCode.Ldc_i4_2: case ILOpCode.Ldc_i4_3: case ILOpCode.Ldc_i4_4: case ILOpCode.Ldc_i4_5: case ILOpCode.Ldc_i4_6: case ILOpCode.Ldc_i4_7: case ILOpCode.Ldc_i4_8: case ILOpCode.Ldc_i4_s: case ILOpCode.Ldc_i4: case ILOpCode.Ldc_i8: case ILOpCode.Ldc_r4: case ILOpCode.Ldc_r8: return 1; case ILOpCode.Dup: return 2; case ILOpCode.Pop: case ILOpCode.Jmp: return 0; case ILOpCode.Call: case ILOpCode.Calli: return -1; case ILOpCode.Ret: case ILOpCode.Br_s: case ILOpCode.Brfalse_s: case ILOpCode.Brtrue_s: case ILOpCode.Beq_s: case ILOpCode.Bge_s: case ILOpCode.Bgt_s: case ILOpCode.Ble_s: case ILOpCode.Blt_s: case ILOpCode.Bne_un_s: case ILOpCode.Bge_un_s: case ILOpCode.Bgt_un_s: case ILOpCode.Ble_un_s: case ILOpCode.Blt_un_s: case ILOpCode.Br: case ILOpCode.Brfalse: case ILOpCode.Brtrue: case ILOpCode.Beq: case ILOpCode.Bge: case ILOpCode.Bgt: case ILOpCode.Ble: case ILOpCode.Blt: case ILOpCode.Bne_un: case ILOpCode.Bge_un: case ILOpCode.Bgt_un: case ILOpCode.Ble_un: case ILOpCode.Blt_un: case ILOpCode.Switch: return 0; case ILOpCode.Ldind_i1: case ILOpCode.Ldind_u1: case ILOpCode.Ldind_i2: case ILOpCode.Ldind_u2: case ILOpCode.Ldind_i4: case ILOpCode.Ldind_u4: case ILOpCode.Ldind_i8: case ILOpCode.Ldind_i: case ILOpCode.Ldind_r4: case ILOpCode.Ldind_r8: case ILOpCode.Ldind_ref: return 1; case ILOpCode.Stind_ref: case ILOpCode.Stind_i1: case ILOpCode.Stind_i2: case ILOpCode.Stind_i4: case ILOpCode.Stind_i8: case ILOpCode.Stind_r4: case ILOpCode.Stind_r8: return 0; case ILOpCode.Add: case ILOpCode.Sub: case ILOpCode.Mul: case ILOpCode.Div: case ILOpCode.Div_un: case ILOpCode.Rem: case ILOpCode.Rem_un: case ILOpCode.And: case ILOpCode.Or: case ILOpCode.Xor: case ILOpCode.Shl: case ILOpCode.Shr: case ILOpCode.Shr_un: case ILOpCode.Neg: case ILOpCode.Not: case ILOpCode.Conv_i1: case ILOpCode.Conv_i2: case ILOpCode.Conv_i4: case ILOpCode.Conv_i8: case ILOpCode.Conv_r4: case ILOpCode.Conv_r8: case ILOpCode.Conv_u4: case ILOpCode.Conv_u8: return 1; case ILOpCode.Callvirt: return -1; case ILOpCode.Cpobj: return 0; case ILOpCode.Ldobj: case ILOpCode.Ldstr: case ILOpCode.Newobj: case ILOpCode.Castclass: case ILOpCode.Isinst: case ILOpCode.Conv_r_un: case ILOpCode.Unbox: return 1; case ILOpCode.Throw: return 0; case ILOpCode.Ldfld: case ILOpCode.Ldflda: return 1; case ILOpCode.Stfld: return 0; case ILOpCode.Ldsfld: case ILOpCode.Ldsflda: return 1; case ILOpCode.Stsfld: case ILOpCode.Stobj: return 0; case ILOpCode.Conv_ovf_i1_un: case ILOpCode.Conv_ovf_i2_un: case ILOpCode.Conv_ovf_i4_un: case ILOpCode.Conv_ovf_i8_un: case ILOpCode.Conv_ovf_u1_un: case ILOpCode.Conv_ovf_u2_un: case ILOpCode.Conv_ovf_u4_un: case ILOpCode.Conv_ovf_u8_un: case ILOpCode.Conv_ovf_i_un: case ILOpCode.Conv_ovf_u_un: case ILOpCode.Box: case ILOpCode.Newarr: case ILOpCode.Ldlen: case ILOpCode.Ldelema: case ILOpCode.Ldelem_i1: case ILOpCode.Ldelem_u1: case ILOpCode.Ldelem_i2: case ILOpCode.Ldelem_u2: case ILOpCode.Ldelem_i4: case ILOpCode.Ldelem_u4: case ILOpCode.Ldelem_i8: case ILOpCode.Ldelem_i: case ILOpCode.Ldelem_r4: case ILOpCode.Ldelem_r8: case ILOpCode.Ldelem_ref: return 1; case ILOpCode.Stelem_i: case ILOpCode.Stelem_i1: case ILOpCode.Stelem_i2: case ILOpCode.Stelem_i4: case ILOpCode.Stelem_i8: case ILOpCode.Stelem_r4: case ILOpCode.Stelem_r8: case ILOpCode.Stelem_ref: return 0; case ILOpCode.Ldelem: return 1; case ILOpCode.Stelem: return 0; case ILOpCode.Unbox_any: case ILOpCode.Conv_ovf_i1: case ILOpCode.Conv_ovf_u1: case ILOpCode.Conv_ovf_i2: case ILOpCode.Conv_ovf_u2: case ILOpCode.Conv_ovf_i4: case ILOpCode.Conv_ovf_u4: case ILOpCode.Conv_ovf_i8: case ILOpCode.Conv_ovf_u8: case ILOpCode.Refanyval: case ILOpCode.Ckfinite: case ILOpCode.Mkrefany: case ILOpCode.Ldtoken: case ILOpCode.Conv_u2: case ILOpCode.Conv_u1: case ILOpCode.Conv_i: case ILOpCode.Conv_ovf_i: case ILOpCode.Conv_ovf_u: case ILOpCode.Add_ovf: case ILOpCode.Add_ovf_un: case ILOpCode.Mul_ovf: case ILOpCode.Mul_ovf_un: case ILOpCode.Sub_ovf: case ILOpCode.Sub_ovf_un: return 1; case ILOpCode.Endfinally: case ILOpCode.Leave: case ILOpCode.Leave_s: case ILOpCode.Stind_i: return 0; case ILOpCode.Conv_u: case ILOpCode.Arglist: case ILOpCode.Ceq: case ILOpCode.Cgt: case ILOpCode.Cgt_un: case ILOpCode.Clt: case ILOpCode.Clt_un: case ILOpCode.Ldftn: case ILOpCode.Ldvirtftn: case ILOpCode.Ldarg: case ILOpCode.Ldarga: return 1; case ILOpCode.Starg: return 0; case ILOpCode.Ldloc: case ILOpCode.Ldloca: return 1; case ILOpCode.Stloc: return 0; case ILOpCode.Localloc: return 1; case ILOpCode.Endfilter: case ILOpCode.Unaligned: case ILOpCode.Volatile: case ILOpCode.Tail: case ILOpCode.Initobj: case ILOpCode.Constrained: case ILOpCode.Cpblk: case ILOpCode.Initblk: case ILOpCode.Rethrow: return 0; case ILOpCode.Sizeof: case ILOpCode.Refanytype: return 1; case ILOpCode.Readonly: return 0; default: throw ExceptionUtilities.UnexpectedValue(opcode); } } }