Exemplo n.º 1
0
 public static void MarkBlockAfter(this CecilILGenerator il, ExceptionBlock block)
 {
     if (block.blockType == ExceptionBlockType.EndExceptionBlock)
     {
         il.EndExceptionBlock();
     }
 }
Exemplo n.º 2
0
        public static LocalBuilder GetLocal(this CecilILGenerator il, VariableDefinition varDef)
        {
            var vars = (Dictionary <LocalBuilder, VariableDefinition>)AccessTools
                       .Field(typeof(CecilILGenerator), "_Variables")
                       .GetValue(il);
            var loc = vars.FirstOrDefault(kv => kv.Value == varDef).Key;

            if (loc != null)
            {
                return(loc);
            }
            // TODO: Remove once MonoMod allows to specify this manually
            var type   = varDef.VariableType.ResolveReflection();
            var pinned = varDef.VariableType.IsPinned;
            var index  = varDef.Index;

            loc = (LocalBuilder)(
                c_LocalBuilder_params == 4 ? c_LocalBuilder.Invoke(new object[] { index, type, null, pinned }) :
                c_LocalBuilder_params == 3 ? c_LocalBuilder.Invoke(new object[] { index, type, null }) :
                c_LocalBuilder_params == 2 ? c_LocalBuilder.Invoke(new object[] { type, null }) :
                c_LocalBuilder_params == 0 ? c_LocalBuilder.Invoke(new object[] { }) :
                throw new NotSupportedException()
                );

            f_LocalBuilder_position?.SetValue(loc, (ushort)index);
            f_LocalBuilder_is_pinned?.SetValue(loc, pinned);
            vars[loc] = varDef;
            return(loc);
        }
Exemplo n.º 3
0
        public static void MarkBlockBefore(this CecilILGenerator il, ExceptionBlock block)
        {
            switch (block.blockType)
            {
            case ExceptionBlockType.BeginExceptionBlock:
                il.BeginExceptionBlock();
                return;

            case ExceptionBlockType.BeginCatchBlock:
                il.BeginCatchBlock(block.catchType);
                return;

            case ExceptionBlockType.BeginExceptFilterBlock:
                il.BeginExceptFilterBlock();
                return;

            case ExceptionBlockType.BeginFaultBlock:
                il.BeginFaultBlock();
                return;

            case ExceptionBlockType.BeginFinallyBlock:
                il.BeginFinallyBlock();
                return;

            case ExceptionBlockType.EndExceptionBlock:
                return;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Exemplo n.º 4
0
        public static Dictionary <LocalBuilder, VariableDefinition> GetGenDictionary(this ILGenerator gen)
        {
            CecilILGenerator CecilGen = gen.GetProxiedShim <CecilILGenerator>();

            return((Dictionary <LocalBuilder, VariableDefinition>)AccessTools
                   .Field(typeof(CecilILGenerator), "_Variables")
                   .GetValue(CecilGen));
        }
Exemplo n.º 5
0
		/// <summary>Returns the methods unmodified list of CodeInstructions</summary>
		/// <param name="original">The original method</param>
		/// <param name="generator">A new generator that now contains all local variables and labels contained in the result</param>
		/// <returns>A list containing all the original CodeInstructions</returns>
		public static List<CodeInstruction> GetOriginalInstructions(MethodBase original, out ILGenerator generator)
		{
			// Create a copy
			var dmd = new DynamicMethodDefinition(original);
			// Create a manipulator to obtain the instructions
			var manipulator = new ILManipulator(dmd.Definition.Body);
			generator = new CecilILGenerator(dmd.GetILProcessor()).GetProxy();
			return manipulator.GetInstructions(generator);
		}
Exemplo n.º 6
0
        public static LocalBuilder GetLocal(this CecilILGenerator il, VariableDefinition varDef)
        {
            var vars = (Dictionary <LocalBuilder, VariableDefinition>)AccessTools
                       .Field(typeof(CecilILGenerator), "_Variables")
                       .GetValue(il);
            var loc = vars.FirstOrDefault(kv => kv.Value == varDef).Key;

            if (loc != null)
            {
                return(loc);
            }
            loc = il.DeclareLocal(varDef.VariableType.ResolveReflection());
            il.IL.Body.Variables.Remove(vars[loc]);
            vars[loc] = varDef;
            return(loc);
        }
Exemplo n.º 7
0
 public static void Emit(this CecilILGenerator il, OpCode opcode, object operand)
 {
     emitCodeDelegate(il, opcode, operand);
 }
Exemplo n.º 8
0
 internal Emitter(ILGenerator il, bool debug)
 {
     this.il    = il.GetProxiedShim <CecilILGenerator>();
     this.debug = debug;
 }
Exemplo n.º 9
0
        /// <summary>
        ///     Processes and writes IL to the provided method body.
        ///     Note that this cleans the existing method body (removes insturctions and exception handlers).
        /// </summary>
        /// <param name="body">Method body to write to.</param>
        /// <param name="original">Original method that transpiler can optionally call into</param>
        /// <exception cref="NotSupportedException">
        ///     One of IL opcodes contains a CallSide (e.g. calli), which is currently not
        ///     fully supported.
        /// </exception>
        /// <exception cref="ArgumentNullException">One of IL opcodes with an operand contains a null operand.</exception>
        public void WriteTo(MethodBody body, MethodBase original = null)
        {
            // Clean up the body of the target method
            body.Instructions.Clear();
            body.ExceptionHandlers.Clear();

            var il  = new CecilILGenerator(body.GetILProcessor());
            var cil = il.GetProxy();

            // Define an "empty" label
            // In Harmony, the first label can point to the end of the method
            // Apparently, some transpilers naively call new Label() to define a label and thus end up
            // using the first label without knowing it
            // By defining the first label we'll ensure label count is correct
            il.DefineLabel();

            // Step 1: Prepare labels for instructions
            Prepare(vDef => il.GetLocal(vDef), il.DefineLabel);

            // Step 2: Run the code instruction through transpilers
            var newInstructions = ApplyTranspilers(cil, original);

            // We don't remove trailing `ret`s because we need to do so only if prefixes/postfixes are present

            // Step 3: Emit code
            foreach (var ins in newInstructions)
            {
                ins.labels.ForEach(l => il.MarkLabel(l));
                ins.blocks.ForEach(b => il.MarkBlockBefore(b));

                // We don't replace `ret`s yet because we might not need to
                // We do that only if we add prefixes/postfixes
                // We also don't need to care for long/short forms thanks to Cecil/MonoMod

                // Temporary fix: CecilILGenerator doesn't properly handle ldarg
                switch (ins.opcode.OperandType)
                {
                case SRE.OperandType.InlineNone:
                    il.Emit(ins.opcode);
                    break;

                case SRE.OperandType.InlineSig:
                    throw new NotSupportedException(
                              "Emitting opcodes with CallSites is currently not fully implemented");

                default:
                    if (ins.operand == null)
                    {
                        throw new ArgumentNullException(nameof(ins.operand), $"Invalid argument for {ins}");
                    }

                    il.Emit(ins.opcode, ins.operand);
                    break;
                }

                ins.blocks.ForEach(b => il.MarkBlockAfter(b));
            }

            // Note: We lose all unassigned labels here along with any way to log them
            // On the contrary, we gain better logging anyway down the line by using Cecil

            // Step 4: Run the code through raw IL manipulators (if any)
            // TODO: IL Manipulators
        }