// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; using Mono.Cecil; using Mono.Cecil.Cil; namespace ICSharpCode.Decompiler.ILAst { public enum ILCode { // For convenience, the start is exactly identical to Mono.Cecil.Cil.Code // Instructions that should not be used are prepended by __ Nop, Break, __Ldarg_0, __Ldarg_1, __Ldarg_2, __Ldarg_3, __Ldloc_0, __Ldloc_1, __Ldloc_2, __Ldloc_3, __Stloc_0, __Stloc_1, __Stloc_2, __Stloc_3, __Ldarg_S, __Ldarga_S, __Starg_S, __Ldloc_S, __Ldloca_S, __Stloc_S, Ldnull, __Ldc_I4_M1, __Ldc_I4_0, __Ldc_I4_1, __Ldc_I4_2, __Ldc_I4_3, __Ldc_I4_4, __Ldc_I4_5, __Ldc_I4_6, __Ldc_I4_7, __Ldc_I4_8, __Ldc_I4_S, Ldc_I4, Ldc_I8, Ldc_R4, Ldc_R8, Dup, Pop, Jmp, Call, Calli, Ret, __Br_S, __Brfalse_S, __Brtrue_S, __Beq_S, __Bge_S, __Bgt_S, __Ble_S, __Blt_S, __Bne_Un_S, __Bge_Un_S, __Bgt_Un_S, __Ble_Un_S, __Blt_Un_S, Br, __Brfalse, Brtrue, __Beq, __Bge, __Bgt, __Ble, __Blt, __Bne_Un, __Bge_Un, __Bgt_Un, __Ble_Un, __Blt_Un, Switch, __Ldind_I1, __Ldind_U1, __Ldind_I2, __Ldind_U2, __Ldind_I4, __Ldind_U4, __Ldind_I8, __Ldind_I, __Ldind_R4, __Ldind_R8, Ldind_Ref, Stind_Ref, __Stind_I1, __Stind_I2, __Stind_I4, __Stind_I8, __Stind_R4, __Stind_R8, Add, Sub, Mul, Div, Div_Un, Rem, Rem_Un, And, Or, Xor, Shl, Shr, Shr_Un, Neg, Not, Conv_I1, Conv_I2, Conv_I4, Conv_I8, Conv_R4, Conv_R8, Conv_U4, Conv_U8, Callvirt, Cpobj, Ldobj, Ldstr, Newobj, Castclass, Isinst, Conv_R_Un, Unbox, Throw, Ldfld, Ldflda, Stfld, Ldsfld, Ldsflda, Stsfld, Stobj, Conv_Ovf_I1_Un, Conv_Ovf_I2_Un, Conv_Ovf_I4_Un, Conv_Ovf_I8_Un, Conv_Ovf_U1_Un, Conv_Ovf_U2_Un, Conv_Ovf_U4_Un, Conv_Ovf_U8_Un, Conv_Ovf_I_Un, Conv_Ovf_U_Un, Box, Newarr, Ldlen, Ldelema, Ldelem_I1, Ldelem_U1, Ldelem_I2, Ldelem_U2, Ldelem_I4, Ldelem_U4, Ldelem_I8, Ldelem_I, Ldelem_R4, Ldelem_R8, Ldelem_Ref, Stelem_I, Stelem_I1, Stelem_I2, Stelem_I4, Stelem_I8, Stelem_R4, Stelem_R8, Stelem_Ref, Ldelem_Any, Stelem_Any, Unbox_Any, Conv_Ovf_I1, Conv_Ovf_U1, Conv_Ovf_I2, Conv_Ovf_U2, Conv_Ovf_I4, Conv_Ovf_U4, Conv_Ovf_I8, Conv_Ovf_U8, Refanyval, Ckfinite, Mkrefany, Ldtoken, Conv_U2, Conv_U1, Conv_I, Conv_Ovf_I, Conv_Ovf_U, Add_Ovf, Add_Ovf_Un, Mul_Ovf, Mul_Ovf_Un, Sub_Ovf, Sub_Ovf_Un, Endfinally, Leave, __Leave_S, __Stind_I, Conv_U, Arglist, Ceq, Cgt, Cgt_Un, Clt, Clt_Un, Ldftn, Ldvirtftn, __Ldarg, __Ldarga, __Starg, Ldloc, Ldloca, Stloc, Localloc, Endfilter, Unaligned, Volatile, Tail, Initobj, Constrained, Cpblk, Initblk, No, Rethrow, Sizeof, Refanytype, Readonly, // Virtual codes - defined for convenience Ldexception, // Operand holds the CatchType for catch handler, null for filter LogicNot, LogicAnd, LogicOr, NullCoalescing, InitArray, // Array Initializer // new Class { Prop = 1, Collection = { { 2, 3 }, {4, 5} }} // is represented as: // InitObject(newobj Class, // CallSetter(Prop, InitializedObject, 1), // InitCollection(CallGetter(Collection, InitializedObject))), // Call(Add, InitializedObject, 2, 3), // Call(Add, InitializedObject, 4, 5))) InitObject, // Object initializer: first arg is newobj, remaining args are the initializing statements InitCollection, // Collection initializer: first arg is newobj, remaining args are the initializing statements InitializedObject, // Refers the the object being initialized (refers to first arg in parent InitObject or InitCollection instruction) TernaryOp, // ?: LoopOrSwitchBreak, LoopContinue, Ldc_Decimal, YieldBreak, YieldReturn, /// /// Represents the 'default(T)' instruction. /// /// Introduced by SimplifyLdObjAndStObj step DefaultValue, /// /// ILExpression with a single child: binary operator. /// This expression means that the binary operator will also assign the new value to its left-hand side. /// 'CompoundAssignment' must not be used for local variables, as inlining (and other) optimizations don't know that it modifies the variable. /// /// Introduced by MakeCompoundAssignments step CompoundAssignment, /// /// Represents the post-increment operator. /// The first argument is the address of the variable to increment (ldloca instruction). /// The second arugment is the amount the variable is incremented by (ldc.i4 instruction) /// /// Introduced by IntroducePostIncrement step PostIncrement, PostIncrement_Ovf, // checked variant of PostIncrement PostIncrement_Ovf_Un, // checked variant of PostIncrement, for unsigned integers /// Calls the getter of a static property (or indexer), or of an instance property on 'base' CallGetter, /// Calls the getter of an instance property (or indexer) CallvirtGetter, /// Calls the setter of a static property (or indexer), or of an instance property on 'base' /// This allows us to represent "while ((SomeProperty = val) != null) {}" CallSetter, /// Calls the setter of a instance property (or indexer) CallvirtSetter, /// Simulates getting the address of a property. Used as prefix on CallGetter or CallvirtGetter. /// Used for postincrement for properties, and to represent the Address() method on multi-dimensional arrays PropertyAddress } public static class ILCodeUtil { public static string GetName(this ILCode code) { return code.ToString().ToLowerInvariant().TrimStart('_').Replace('_','.'); } public static bool IsConditionalControlFlow(this ILCode code) { switch(code) { case ILCode.__Brfalse_S: case ILCode.__Brtrue_S: case ILCode.__Beq_S: case ILCode.__Bge_S: case ILCode.__Bgt_S: case ILCode.__Ble_S: case ILCode.__Blt_S: case ILCode.__Bne_Un_S: case ILCode.__Bge_Un_S: case ILCode.__Bgt_Un_S: case ILCode.__Ble_Un_S: case ILCode.__Blt_Un_S: case ILCode.__Brfalse: case ILCode.Brtrue: case ILCode.__Beq: case ILCode.__Bge: case ILCode.__Bgt: case ILCode.__Ble: case ILCode.__Blt: case ILCode.__Bne_Un: case ILCode.__Bge_Un: case ILCode.__Bgt_Un: case ILCode.__Ble_Un: case ILCode.__Blt_Un: case ILCode.Switch: return true; default: return false; } } public static bool IsUnconditionalControlFlow(this ILCode code) { switch(code) { case ILCode.Br: case ILCode.__Br_S: case ILCode.Leave: case ILCode.__Leave_S: case ILCode.Ret: case ILCode.Endfilter: case ILCode.Endfinally: case ILCode.Throw: case ILCode.Rethrow: case ILCode.LoopContinue: case ILCode.LoopOrSwitchBreak: case ILCode.YieldBreak: return true; default: return false; } } public static void ExpandMacro(ref ILCode code, ref object operand, MethodBody methodBody) { switch (code) { case ILCode.__Ldarg_0: code = ILCode.__Ldarg; operand = methodBody.GetParameter(0); break; case ILCode.__Ldarg_1: code = ILCode.__Ldarg; operand = methodBody.GetParameter(1); break; case ILCode.__Ldarg_2: code = ILCode.__Ldarg; operand = methodBody.GetParameter(2); break; case ILCode.__Ldarg_3: code = ILCode.__Ldarg; operand = methodBody.GetParameter(3); break; case ILCode.__Ldloc_0: code = ILCode.Ldloc; operand = methodBody.Variables[0]; break; case ILCode.__Ldloc_1: code = ILCode.Ldloc; operand = methodBody.Variables[1]; break; case ILCode.__Ldloc_2: code = ILCode.Ldloc; operand = methodBody.Variables[2]; break; case ILCode.__Ldloc_3: code = ILCode.Ldloc; operand = methodBody.Variables[3]; break; case ILCode.__Stloc_0: code = ILCode.Stloc; operand = methodBody.Variables[0]; break; case ILCode.__Stloc_1: code = ILCode.Stloc; operand = methodBody.Variables[1]; break; case ILCode.__Stloc_2: code = ILCode.Stloc; operand = methodBody.Variables[2]; break; case ILCode.__Stloc_3: code = ILCode.Stloc; operand = methodBody.Variables[3]; break; case ILCode.__Ldarg_S: code = ILCode.__Ldarg; break; case ILCode.__Ldarga_S: code = ILCode.__Ldarga; break; case ILCode.__Starg_S: code = ILCode.__Starg; break; case ILCode.__Ldloc_S: code = ILCode.Ldloc; break; case ILCode.__Ldloca_S: code = ILCode.Ldloca; break; case ILCode.__Stloc_S: code = ILCode.Stloc; break; case ILCode.__Ldc_I4_M1: code = ILCode.Ldc_I4; operand = -1; break; case ILCode.__Ldc_I4_0: code = ILCode.Ldc_I4; operand = 0; break; case ILCode.__Ldc_I4_1: code = ILCode.Ldc_I4; operand = 1; break; case ILCode.__Ldc_I4_2: code = ILCode.Ldc_I4; operand = 2; break; case ILCode.__Ldc_I4_3: code = ILCode.Ldc_I4; operand = 3; break; case ILCode.__Ldc_I4_4: code = ILCode.Ldc_I4; operand = 4; break; case ILCode.__Ldc_I4_5: code = ILCode.Ldc_I4; operand = 5; break; case ILCode.__Ldc_I4_6: code = ILCode.Ldc_I4; operand = 6; break; case ILCode.__Ldc_I4_7: code = ILCode.Ldc_I4; operand = 7; break; case ILCode.__Ldc_I4_8: code = ILCode.Ldc_I4; operand = 8; break; case ILCode.__Ldc_I4_S: code = ILCode.Ldc_I4; operand = (int) (sbyte) operand; break; case ILCode.__Br_S: code = ILCode.Br; break; case ILCode.__Brfalse_S: code = ILCode.__Brfalse; break; case ILCode.__Brtrue_S: code = ILCode.Brtrue; break; case ILCode.__Beq_S: code = ILCode.__Beq; break; case ILCode.__Bge_S: code = ILCode.__Bge; break; case ILCode.__Bgt_S: code = ILCode.__Bgt; break; case ILCode.__Ble_S: code = ILCode.__Ble; break; case ILCode.__Blt_S: code = ILCode.__Blt; break; case ILCode.__Bne_Un_S: code = ILCode.__Bne_Un; break; case ILCode.__Bge_Un_S: code = ILCode.__Bge_Un; break; case ILCode.__Bgt_Un_S: code = ILCode.__Bgt_Un; break; case ILCode.__Ble_Un_S: code = ILCode.__Ble_Un; break; case ILCode.__Blt_Un_S: code = ILCode.__Blt_Un; break; case ILCode.__Leave_S: code = ILCode.Leave; break; case ILCode.__Ldind_I: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break; case ILCode.__Ldind_I1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.SByte; break; case ILCode.__Ldind_I2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int16; break; case ILCode.__Ldind_I4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int32; break; case ILCode.__Ldind_I8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Int64; break; case ILCode.__Ldind_U1: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Byte; break; case ILCode.__Ldind_U2: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt16; break; case ILCode.__Ldind_U4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.UInt32; break; case ILCode.__Ldind_R4: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Single; break; case ILCode.__Ldind_R8: code = ILCode.Ldobj; operand = methodBody.Method.Module.TypeSystem.Double; break; case ILCode.__Stind_I: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.IntPtr; break; case ILCode.__Stind_I1: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Byte; break; case ILCode.__Stind_I2: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int16; break; case ILCode.__Stind_I4: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int32; break; case ILCode.__Stind_I8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Int64; break; case ILCode.__Stind_R4: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Single; break; case ILCode.__Stind_R8: code = ILCode.Stobj; operand = methodBody.Method.Module.TypeSystem.Double; break; } } public static ParameterDefinition GetParameter (this MethodBody self, int index) { var method = self.Method; if (method.HasThis) { if (index == 0) return self.ThisParameter; index--; } var parameters = method.Parameters; if (index < 0 || index >= parameters.Count) return null; return parameters [index]; } } }