IterateInstructions() public static method

Yields method instructions but skips hotpatch code if the method is hotpatch-instrumented.
public static IterateInstructions ( Mono.Cecil method ) : IEnumerable
method Mono.Cecil
return IEnumerable
Example #1
0
        /// <summary>
        /// Generate "position independent" representation of IL.
        ///
        /// We need to do this extra work because even if we skip
        /// instrumentation prologue of functions when iterating
        /// instructions, typical "toString()" representation of
        /// Cecil.Cil.Instructions contains absolute instruction
        /// positions.
        /// </summary>
        string ConcatBody(Cecil.MethodDefinition method)
        {
            const string skipAddr = "IL_0000: ";

            var sb = new System.Text.StringBuilder();

            foreach (var ins in Instrument.IterateInstructions(method))
            {
                if (ins.Operand is Cecil.Cil.Instruction)
                {
                    // instructions that refer to other instructions, like
                    // branches.

                    var insOperand = (Cecil.Cil.Instruction)(ins.Operand);
                    var offset     = insOperand.Offset - ins.Offset;

                    sb.AppendLine(String.Format("{0} {1}", ins.OpCode, offset));
                }
                else
                {
                    sb.AppendLine(ins.ToString().Substring(skipAddr.Length));
                }
            }
            return(sb.ToString());
        }
Example #2
0
        public DynamicMethod RecompileMethod(Cecil.MethodDefinition methodDef)
        {
            Debug.Trace("Recompiling method: {0}", methodDef.FullName);

            var declaringType = FindType(methodDef.DeclaringType);
            var returnType    = FindType(methodDef.ReturnType);

            Type[] paramTypes = methodDef.Parameters.Select((paramDef) => {
                return(FindType(paramDef.ParameterType));
            }).ToArray();

            if (!methodDef.IsStatic)
            {
                paramTypes = new Type[] { declaringType }.Concat(paramTypes).ToArray();
            }

            var         dynMethod = new DynamicMethod(methodDef.Name, returnType, paramTypes, true);
            ILGenerator il        = dynMethod.GetILGenerator();

            dynMethod.InitLocals = methodDef.Body.InitLocals;
            foreach (var variable in methodDef.Body.Variables)
            {
                var localType = FindType(variable.VariableType);
                Debug.Trace("Declaring local (cecil type: {0}) of type (runtime type: {1})", variable.VariableType, localType);
                il.DeclareLocal(localType);
            }

            var labels = new Dictionary <Cecil.Cil.Instruction, Label>();

            foreach (var inst in methodDef.Body.Instructions)
            {
                if (inst.Operand != null && inst.Operand.GetType() == typeof(Cecil.Cil.Instruction))
                {
                    var opinst = (Cecil.Cil.Instruction)(inst.Operand);
                    labels[opinst] = il.DefineLabel();
                }
            }

            foreach (var inst in Instrument.IterateInstructions(methodDef))
            {
                Debug.Trace("Emitting: {0}", inst);

                Label label;
                if (labels.TryGetValue(inst, out label))
                {
                    il.MarkLabel(label);
                }

                var ilop = FindOpcode(inst.OpCode);

                if (inst.Operand != null)
                {
                    var operand     = inst.Operand;
                    var operandType = operand.GetType();

                    // Dynamic dispatch implementation:

                    // We have to run different processing code depending on the type of instruction
                    // operand. Visitor pattern cannot be implemented here, because we don't actually
                    // own the classes that are the operands (and some of them are primitive or system
                    // types).

                    // Therefore, dynamic dispatcher is used. Method for each operand type is implemented
                    // in this class, and reflection is used to find correct method to call.

                    // In newer .net versions we would be able to do EmitInstruction(il, ilop, (dynamic)operand),
                    // but the .net version we are targeting (because of Unity compatibility) does not
                    // have `dynamic`.

                    if (operandType == typeof(Cecil.Cil.Instruction))
                    {
                        //branch location
                        var operandInst = (Cecil.Cil.Instruction)operand;

                        il.Emit(ilop, labels[operandInst]);
                    }
                    else if (primitiveOperandTypes.Contains(operandType))
                    {
                        //if operand is primitive, call il.Emit directly
                        Reflection.MethodInfo method;
                        if (!EmitPrimitiveCache.TryGetValue(operandType, out method))
                        {
                            method = typeof(ILGenerator).GetMethod("Emit", new Type[] { typeof(OpCode), operandType });
                            EmitPrimitiveCache[operandType] = method;
                        }

                        if (method == null)
                        {
                            throw new Exception(String.Format("Emit method for primitive type {0} not found.", operandType.Name));
                        }

                        method.Invoke(il, new object[] { ilop, operand });
                    }
                    else
                    {
                        //or else, call our EmitInstruction
                        Reflection.MethodInfo method;
                        if (!EmitInstructionCache.TryGetValue(operandType, out method))
                        {
                            method = GetType().GetMethod("EmitInstruction",
                                                         bindingAttr: bflags_all_instance,
                                                         binder: null,
                                                         modifiers: null,
                                                         types: new Type[] { typeof(ILGenerator), typeof(OpCode), operandType });
                            EmitInstructionCache[operandType] = method;
                        }

                        if (method == null)
                        {
                            throw new Exception(String.Format("Don't know what to do with operand {0}", operandType.Name));
                        }

                        method.Invoke(this, new object[] { il, ilop, operand });
                    }
                }
                else
                {
                    il.Emit(ilop);
                }
            }

            return(dynMethod);
        }