private static MethodBody GenerateBody(MethodDefinition method) { MethodBody body = new MethodBody(method); ILProcessor processor = body.GetILProcessor(); Dictionary <Instruction, VariableDefinition> Branches = new Dictionary <Instruction, VariableDefinition>(); Dictionary <int, VariableDefinition> Locals = new Dictionary <int, VariableDefinition>(); // create an instance of DynamicMethod processor.CreateDynamicMethod(method); VariableDefinition dynamicMethod = new VariableDefinition(TypeReferences["DynamicMethod"]); processor.Body.Variables.Add(dynamicMethod); processor.Emit(OpCodes.Stloc, dynamicMethod); processor.Emit(OpCodes.Ldloc, dynamicMethod); // generate an ILGenerator object from the DynamicMethod VariableDefinition ilgenerator = new VariableDefinition(TypeReferences["ILGenerator"]); processor.Body.Variables.Add(ilgenerator); processor.Emit(OpCodes.Callvirt, MethodReferences["GetILGenerator"]); processor.Emit(OpCodes.Stloc, ilgenerator); // pre-emission phase (runs after DynamicMethod and ILGenerator are instantiated) foreach (Instruction instruction in method.Body.Instructions) { // output instructions & operand types to console Console.Write(instruction.Offset + ": " + instruction.OpCode.Name); Console.Write(instruction.Operand == null ? "\n" : " -> " + instruction.Operand.GetType() + "\n"); // define branch variables ('Label' objects) if (instruction.Operand is Instruction) { // ignore leave.s branching, since it's used for exception handling if (instruction.OpCode == OpCodes.Leave_S) { continue; } Instruction target = instruction.Operand as Instruction; if (Branches.ContainsKey(target)) { continue; } VariableDefinition label = new VariableDefinition(TypeReferences["Label"]); processor.Body.Variables.Add(label); processor.Emit(OpCodes.Ldloc, ilgenerator); processor.Emit(OpCodes.Callvirt, MethodReferences["DefineLabel"]); processor.Emit(OpCodes.Stloc, label); Branches.Add(target, label); } } // define local variables for (int vI = 0; vI < method.Body.Variables.Count; vI++) { VariableDefinition local = new VariableDefinition(TypeReferences["LocalBuilder"]); processor.Body.Variables.Add(local); TypeReference variableType = method.Body.Variables[vI].VariableType; processor.Emit(OpCodes.Ldloc, ilgenerator); processor.EmitType(variableType); processor.Emit(OpCodes.Callvirt, MethodReferences["DeclareLocal"]); processor.Emit(OpCodes.Stloc, local); Locals.Add(vI, local); } // iterate through instructions, writer ILGenerator.Emit calls for (int iI = 0; iI < method.Body.Instructions.Count; iI++) { // the current instruction Instruction instruction = method.Body.Instructions[iI]; foreach (ExceptionHandler exH in method.Body.ExceptionHandlers) { if (exH.TryStart == instruction) { processor.Emit(OpCodes.Ldloc, ilgenerator); processor.Emit(OpCodes.Callvirt, MethodReferences["TryStart"]); processor.Emit(OpCodes.Pop); // pop TryStart return value from eval stack } else if (exH.HandlerStart == instruction) { processor.Emit(OpCodes.Ldloc, ilgenerator); if (exH.HandlerType == ExceptionHandlerType.Catch) { processor.EmitType(exH.CatchType); processor.Emit(OpCodes.Callvirt, MethodReferences["CatchBlock"]); } else if (exH.HandlerType == ExceptionHandlerType.Finally) { processor.Emit(OpCodes.Callvirt, MethodReferences["FinallyBlock"]); } } else if (exH.TryEnd == instruction || exH.HandlerEnd == instruction) { processor.Emit(OpCodes.Ldloc, ilgenerator); processor.Emit(OpCodes.Callvirt, MethodReferences["TryEnd"]); } } // ignore leave.s branching, since it's used for exception handling if (instruction.OpCode == OpCodes.Leave_S) { continue; } // mark a label for this instruction, if we have a branch going here if (Branches.ContainsKey(instruction)) { processor.Emit(OpCodes.Ldloc, ilgenerator); processor.EmitMarkLabel(Branches[instruction]); } // load ilgenerator object into memory to make Emit call from it processor.Emit(OpCodes.Ldloc, ilgenerator); // determine index of stloc/ldloc call based on OpCode int stlocIndex = instruction.GetStlocIndex(); int ldlocIndex = instruction.GetLdlocIndex(); // modify stloc/ldloc implementation to use LocalBuilder if (stlocIndex > -1 || ldlocIndex > -1) { // new determine new OpCode & local variable index bool isStloc = stlocIndex > -1; instruction.OpCode = isStloc ? OpCodes.Stloc : OpCodes.Ldloc; int localIndex = isStloc ? stlocIndex : ldlocIndex; // load OpCode (param #1) and LocalBuilder object (param #2) onto eval stack // make ILGenerator.Emit call with these 2 params to fix local variables in ILGenerator methods processor.Emit(OpCodes.Ldsfld, Utils.GetReflectedOpCode(instruction)); processor.Emit(OpCodes.Ldloc, Locals[localIndex]); processor.Emit(OpCodes.Callvirt, Utils.GetILGeneratorEmitter(typeof(System.Reflection.Emit.LocalBuilder))); continue; } // load the OpCode to be emitted onto the eval stack (param #1) processor.Emit(OpCodes.Ldsfld, Utils.GetReflectedOpCode(instruction)); // type of ILGenerator.Emit function to invoke. // if null, Emit will be invoked without an operand. // all operands must be handled in the following if/else blocks Type EmitType = null; // handle operands (note: each operand needs to be handled differently) // this will be used in the ILGenerator.Emit call (param #2) if (instruction.Operand != null) { if (instruction.Operand is FieldDefinition) { FieldDefinition fieldDefinition = instruction.Operand as FieldDefinition; processor.EmitFieldGetter(fieldDefinition); EmitType = typeof(System.Reflection.FieldInfo); } else if (instruction.Operand is MethodDefinition) { MethodDefinition methodDefinition = instruction.Operand as MethodDefinition; processor.EmitMethodGetter(methodDefinition); EmitType = methodDefinition.IsConstructor ? typeof(System.Reflection.ConstructorInfo) : typeof(System.Reflection.MethodInfo); } else if (instruction.Operand is MethodReference) { MethodReference methodReference = instruction.Operand as MethodReference; processor.EmitMethodGetter(methodReference); EmitType = typeof(System.Reflection.MethodInfo); } else if (instruction.Operand.GetType() == typeof(sbyte)) { sbyte value = Convert.ToSByte(instruction.Operand); processor.Emit(OpCodes.Ldc_I4_S, value); EmitType = typeof(sbyte); } else if (instruction.Operand.GetType() == typeof(string)) { string value = Convert.ToString(instruction.Operand); processor.Emit(OpCodes.Ldstr, value); EmitType = typeof(string); } else if (instruction.Operand.GetType() == typeof(int)) { int value = Convert.ToInt32(instruction.Operand); processor.Emit(OpCodes.Ldc_I4, value); EmitType = typeof(int); } else if (instruction.Operand.GetType() == typeof(float)) { float value = Convert.ToSingle(instruction.Operand); processor.Emit(OpCodes.Ldc_R4, value); EmitType = typeof(float); } else if (instruction.Operand is Instruction) { Instruction targetInstruction = instruction.Operand as Instruction; processor.Emit(OpCodes.Ldloc, Branches[targetInstruction]); EmitType = typeof(System.Reflection.Emit.Label); } else if (instruction.Operand is TypeReference) { TypeReference typeReference = instruction.Operand as TypeReference; processor.EmitType(typeReference); EmitType = typeof(Type); } else { Console.WriteLine("UNHANDLED OPERAND: opcode = " + instruction.OpCode.Name + ", type = " + instruction.Operand.GetType()); } } // if we're emitting a 'call' or 'callvirt' opcode, use the ILGenerator.EmitCall function if (instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt) { // null = 3rd param in EmitCall (1st was the opcode, 2nd was the MethodInfo) processor.Emit(OpCodes.Ldnull); processor.Emit(OpCodes.Callvirt, MethodReferences["EmitCall"]); continue; } // call the ILGenerator.Emit func // if EmitType is null, second parameter (operand) is ignored processor.Emit(OpCodes.Callvirt, Utils.GetILGeneratorEmitter(EmitType)); } // load the DynamicMethod object back onto the stack processor.Emit(OpCodes.Ldloc, dynamicMethod); // object parameter in DynamicMethod.Invoke, should always be null (param #1) processor.Emit(OpCodes.Ldnull); // create an array of objects to hold parameters to send to DynamicMethod.Invoke (param #2) processor.Emit(OpCodes.Ldc_I4_S, Convert.ToSByte(method.Parameters.Count)); processor.Emit(OpCodes.Newarr, Module.TypeSystem.Object); // load parameters into the created array for (int pI = 0; pI < method.Parameters.Count; pI++) { ParameterDefinition parameter = method.Parameters[pI]; processor.Emit(OpCodes.Dup); processor.Emit(OpCodes.Ldc_I4_S, Convert.ToSByte(pI)); processor.Emit(OpCodes.Ldarg_S, parameter); processor.Emit(OpCodes.Box, parameter.ParameterType); processor.Emit(OpCodes.Stelem_Ref); } // call the invoker processor.Emit(OpCodes.Callvirt, MethodReferences["Invoker"]); // cast the returned object to the return type if (method.ReturnType != Module.TypeSystem.Void) { processor.Emit(OpCodes.Unbox_Any, method.ReturnType); } else { processor.Emit(OpCodes.Pop); } // return the remaining value on the stack (result of dynamic method) processor.Emit(OpCodes.Ret); return(body); }