/// <summary> /// Add load library calls for all imported libs. /// </summary> private static void AddLoadLibraryCalls(TypeDefinition type, MethodDefinition classCtor) { var libs = type.Methods.Where(x => x.HasPInvokeInfo).Select(x => x.PInvokeInfo.Module.Name).Distinct().ToList(); var typeSystem = type.Module.TypeSystem; var loadLibMethod = new MethodReference("LoadLibrary", typeSystem.Void, typeSystem.LookupType("Java.Lang", "System")); loadLibMethod.Parameters.Add(new ParameterDefinition(typeSystem.String)); var seq = new ILSequence(); foreach (var libName in libs) { // Add System.LoadLibrary(libName) call seq.Append(new Instruction(OpCodes.Ldstr, libName)); seq.Append(new Instruction(OpCodes.Call, loadLibMethod)); } seq.InsertTo(0, classCtor.Body); }
private static Instruction[] GetCallArguments(MethodBody body, Instruction callInstruction) { var ilseq = new ILSequence(); foreach (var i in body.Instructions) { ilseq.Append(i); if (i == callInstruction) { break; } } Instruction[] args = callInstruction.GetCallArguments(ilseq, false); return(args); }
/// <summary> /// Inline the call to the given method /// </summary> private static void InlineCall(Instruction instruction, MethodBody body, MethodDefinition targetMethod) { // Prepare var prefixSeq = new ILSequence(); // Create "this" variable VariableDefinition thisVariable = null; if (targetMethod.HasThis) { thisVariable = new VariableDefinition(targetMethod.DeclaringType); body.Variables.Add(thisVariable); body.InitLocals = true; } // Store argument in variables var paramVariables = new List <VariableDefinition>(); foreach (var parameter in targetMethod.Parameters.Reverse()) { // Create variable var paramVariable = new VariableDefinition(parameter.ParameterType); body.Variables.Add(paramVariable); paramVariables.Insert(0, paramVariable); // Pop prefixSeq.Emit(OpCodes.Stloc, paramVariable); } // Store this argument (if any) if (thisVariable != null) { // Pop prefixSeq.Emit(OpCodes.Stloc, thisVariable); } // Clone variables first var source = targetMethod.Body; var variables = new List <VariableDefinition>(); foreach (var sv in source.Variables) { var clone = new VariableDefinition(sv.VariableType); variables.Add(clone); body.Variables.Add(clone); } // Now clone instructions var seq = new ILSequence(); foreach (var instr in source.Instructions) { var ni = new Instruction(instr.OpCode, instr.Operand); seq.Append(ni); ni.Offset = instr.Offset; // Convert variable opcodes switch (instr.OpCode.OperandType) { case OperandType.InlineVar: case OperandType.ShortInlineVar: { var index = source.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = variables[index]; } break; } // Convert parameter opcodes switch (instr.OpCode.Code) { case Code.Ldarg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloc; } break; case Code.Ldarga: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloca; } break; case Code.Starg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Stloc; } break; } } // Update branch targets for (var i = 0; i < seq.Length; i++) { var instr = seq[i]; var oldi = source.Instructions[i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { var olds = (Instruction[])oldi.Operand; var targets = new Instruction[olds.Length]; for (int j = 0; j < targets.Length; j++) { targets[j] = GetClone(seq, source.Instructions, olds[j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand); } } // Clone exception handlers if (source.HasExceptionHandlers) { body.ComputeOffsets(); CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers); } // Replace ret instructions var end = seq.Emit(OpCodes.Nop); var retInstructions = seq.Where(x => x.OpCode.Code == Code.Ret).ToList(); foreach (var ins in retInstructions) { ins.OpCode = OpCodes.Br; ins.Operand = end; } // cast return type of a generic method. TODO: better might be to // correctly resolve calls to generic instances as well (above) if (targetMethod.ReturnType.IsGenericParameter) { var methodRef = (MethodReference)instruction.Operand; TypeReference returnType = null; var gp = (GenericParameter)methodRef.ReturnType; if (gp.Type == GenericParameterType.Type) { var gi = methodRef.DeclaringType as IGenericInstance; if (gi != null && gi.HasGenericArguments) { returnType = gi.GenericArguments[gp.Position]; } } else if (gp.Type == GenericParameterType.Method) { var gi = methodRef as IGenericInstance; if (gi != null && gi.HasGenericArguments) { returnType = gi.GenericArguments[gp.Position]; } } if (returnType != null) { if (!returnType.IsPrimitive) { seq.Emit(OpCodes.Castclass, returnType); } // todo: handle primitive types. unbox them? are structs correctly handled? enums? } } // Insert cloned instructions prefixSeq.InsertTo(0, seq); seq.InsertToAfter(instruction, body); // Change replaced instruction to nop instruction.ChangeToNop(); // Update offsets body.ComputeOffsets(); }
/// <summary> /// Inline the call to the given ctor /// </summary> private static void InlineNewObjCall(Instruction instruction, MethodBody body, MethodDefinition ctor) { // Prepare var prefixSeq = new ILSequence(); ctor.Body.SimplifyMacros(); // Create "this" variable var thisVariable = new VariableDefinition(ctor.DeclaringType); body.Variables.Add(thisVariable); body.InitLocals = true; // Store argument in variables var paramVariables = new List <VariableDefinition>(); foreach (var parameter in ctor.Parameters.Reverse()) { // Create variable var paramVariable = new VariableDefinition(parameter.ParameterType); body.Variables.Add(paramVariable); paramVariables.Insert(0, paramVariable); // Pop prefixSeq.Emit(OpCodes.Stloc, paramVariable); } // Clone variables first var source = ctor.Body; var variables = new List <VariableDefinition>(); foreach (var sv in source.Variables) { var clone = new VariableDefinition(sv.VariableType); variables.Add(clone); body.Variables.Add(clone); } // Now clone instructions var seq = new ILSequence(); foreach (var instr in source.Instructions) { var ni = new Instruction(instr.OpCode, instr.Operand); seq.Append(ni); ni.Offset = instr.Offset; // Convert variable opcodes switch (instr.OpCode.OperandType) { case OperandType.InlineVar: case OperandType.ShortInlineVar: { var index = source.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = variables[index]; } break; } // Convert parameter opcodes switch (instr.OpCode.Code) { case Mono.Cecil.Cil.Code.Ldarg: { var index = ctor.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloc; } break; case Mono.Cecil.Cil.Code.Ldarga: { var index = ctor.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloca; } break; case Mono.Cecil.Cil.Code.Starg: { var index = ctor.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Stloc; } break; } } // Update branch targets for (var i = 0; i < seq.Length; i++) { var instr = seq[i]; var oldi = source.Instructions[i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { var olds = (Instruction[])oldi.Operand; var targets = new Instruction[olds.Length]; for (int j = 0; j < targets.Length; j++) { targets[j] = GetClone(seq, source.Instructions, olds[j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand); } } // Clone exception handlers if (source.HasExceptionHandlers) { CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers); } // Find call to "this" ctor var callToCtors = seq.Where(x => IsCallToThisCtor(x, ctor)).ToList(); if (callToCtors.Count == 0) { throw new CompilerException(string.Format("No call to another this ctor found in {0}", ctor)); } if (callToCtors.Count > 1) { throw new CompilerException(string.Format("Multiple calls to another this ctor found in {0}", ctor)); } var callToCtor = callToCtors[0]; // Change "ld this" to nop var args = callToCtor.GetCallArguments(seq, true); args[0].ChangeToNop(); // Replace ldarg.0 // Replace call to this ctor with newobj var callSeq = new ILSequence(); callSeq.Emit(OpCodes.Newobj, (MethodReference)callToCtor.Operand); callSeq.Emit(OpCodes.Stloc, thisVariable); // Save new object callToCtor.ChangeToNop(); callSeq.InsertToBefore(callToCtor, seq); // Replace ret instructions var end = seq.Emit(OpCodes.Ldloc, thisVariable); var retInstructions = seq.Where(x => x.OpCode.Code == Mono.Cecil.Cil.Code.Ret).ToList(); foreach (var ins in retInstructions) { ins.OpCode = OpCodes.Br; ins.Operand = end; } // Insert cloned instructions prefixSeq.InsertTo(0, seq); seq.InsertToAfter(instruction, body); // Change replaced instruction to nop instruction.ChangeToNop(); // Update offsets body.ComputeOffsets(); }
private static Instruction[] GetCallArguments(MethodBody body, Instruction callInstruction) { var ilseq = new ILSequence(); foreach (var i in body.Instructions) { ilseq.Append(i); if (i == callInstruction) break; } Instruction[] args = callInstruction.GetCallArguments(ilseq, false); return args; }
/// <summary> /// Inline the call to the given method /// </summary> private static void InlineCall(Instruction instruction, MethodBody body, MethodDefinition targetMethod) { // Prepare var prefixSeq = new ILSequence(); // Create "this" variable VariableDefinition thisVariable = null; if (targetMethod.HasThis) { thisVariable = new VariableDefinition(targetMethod.DeclaringType); body.Variables.Add(thisVariable); body.InitLocals = true; } // Store argument in variables var paramVariables = new List <VariableDefinition>(); foreach (var parameter in targetMethod.Parameters.Reverse()) { // Create variable var paramVariable = new VariableDefinition(parameter.ParameterType); body.Variables.Add(paramVariable); paramVariables.Insert(0, paramVariable); // Pop prefixSeq.Emit(OpCodes.Stloc, paramVariable); } // Store this argument (if any) if (thisVariable != null) { // Pop prefixSeq.Emit(OpCodes.Stloc, thisVariable); } // Clone variables first var source = targetMethod.Body; var variables = new List <VariableDefinition>(); foreach (var sv in source.Variables) { var clone = new VariableDefinition(sv.VariableType); variables.Add(clone); body.Variables.Add(clone); } // Now clone instructions var seq = new ILSequence(); foreach (var instr in source.Instructions) { var ni = new Instruction(instr.OpCode, instr.Operand); seq.Append(ni); ni.Offset = instr.Offset; // Convert variable opcodes switch (instr.OpCode.OperandType) { case OperandType.InlineVar: case OperandType.ShortInlineVar: { var index = source.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = variables[index]; } break; } // Convert parameter opcodes switch (instr.OpCode.Code) { case Code.Ldarg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloc; } break; case Code.Ldarga: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloca; } break; case Code.Starg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Stloc; } break; } } // Update branch targets for (var i = 0; i < seq.Length; i++) { var instr = seq[i]; var oldi = source.Instructions[i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { var olds = (Instruction[])oldi.Operand; var targets = new Instruction[olds.Length]; for (int j = 0; j < targets.Length; j++) { targets[j] = GetClone(seq, source.Instructions, olds[j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand); } } // Clone exception handlers if (source.HasExceptionHandlers) { body.ComputeOffsets(); CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers); } // Replace ret instructions var end = seq.Emit(OpCodes.Nop); var retInstructions = seq.Where(x => x.OpCode.Code == Code.Ret).ToList(); foreach (var ins in retInstructions) { ins.OpCode = OpCodes.Br; ins.Operand = end; } // Insert cloned instructions prefixSeq.InsertTo(0, seq); seq.InsertToAfter(instruction, body); // Change replaced instruction to nop instruction.ChangeToNop(); // Update offsets body.ComputeOffsets(); }
/// <summary> /// Inline the call to the given ctor /// </summary> private static void InlineNewObjCall(Instruction instruction, MethodBody body, MethodDefinition ctor) { // Prepare var prefixSeq = new ILSequence(); ctor.Body.SimplifyMacros(); // Create "this" variable var thisVariable = new VariableDefinition(ctor.DeclaringType); body.Variables.Add(thisVariable); body.InitLocals = true; // Store argument in variables var paramVariables = new List<VariableDefinition>(); foreach (var parameter in ctor.Parameters.Reverse()) { // Create variable var paramVariable = new VariableDefinition(parameter.ParameterType); body.Variables.Add(paramVariable); paramVariables.Insert(0, paramVariable); // Pop prefixSeq.Emit(OpCodes.Stloc, paramVariable); } // Clone variables first var source = ctor.Body; var variables = new List<VariableDefinition>(); foreach (var sv in source.Variables) { var clone = new VariableDefinition(sv.VariableType); variables.Add(clone); body.Variables.Add(clone); } // Now clone instructions var seq = new ILSequence(); foreach (var instr in source.Instructions) { var ni = new Instruction(instr.OpCode, instr.Operand); seq.Append(ni); ni.Offset = instr.Offset; // Convert variable opcodes switch (instr.OpCode.OperandType) { case OperandType.InlineVar: case OperandType.ShortInlineVar: { var index = source.Variables.IndexOf((VariableDefinition) instr.Operand); ni.Operand = variables[index]; } break; } // Convert parameter opcodes switch (instr.OpCode.Code) { case Mono.Cecil.Cil.Code.Ldarg: { var index = ctor.Parameters.IndexOf((ParameterDefinition) instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloc; } break; case Mono.Cecil.Cil.Code.Ldarga: { var index = ctor.Parameters.IndexOf((ParameterDefinition) instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloca; } break; case Mono.Cecil.Cil.Code.Starg: { var index = ctor.Parameters.IndexOf((ParameterDefinition) instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Stloc; } break; } } // Update branch targets for (var i = 0; i < seq.Length; i++) { var instr = seq[i]; var oldi = source.Instructions[i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { var olds = (Instruction[]) oldi.Operand; var targets = new Instruction[olds.Length]; for (int j = 0; j < targets.Length; j++) { targets[j] = GetClone(seq, source.Instructions, olds[j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetClone(seq, source.Instructions, (Instruction) oldi.Operand); } } // Clone exception handlers if (source.HasExceptionHandlers) { CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers); } // Find call to "this" ctor var callToCtors = seq.Where(x => IsCallToThisCtor(x, ctor)).ToList(); if (callToCtors.Count == 0) throw new CompilerException(string.Format("No call to another this ctor found in {0}", ctor)); if (callToCtors.Count > 1) throw new CompilerException(string.Format("Multiple calls to another this ctor found in {0}", ctor)); var callToCtor = callToCtors[0]; // Change "ld this" to nop var args = callToCtor.GetCallArguments(seq, true); args[0].ChangeToNop(); // Replace ldarg.0 // Replace call to this ctor with newobj var callSeq = new ILSequence(); callSeq.Emit(OpCodes.Newobj, (MethodReference) callToCtor.Operand); callSeq.Emit(OpCodes.Stloc, thisVariable); // Save new object callToCtor.ChangeToNop(); callSeq.InsertToBefore(callToCtor, seq); // Replace ret instructions var end = seq.Emit(OpCodes.Ldloc, thisVariable); var retInstructions = seq.Where(x => x.OpCode.Code == Mono.Cecil.Cil.Code.Ret).ToList(); foreach (var ins in retInstructions) { ins.OpCode = OpCodes.Br; ins.Operand = end; } // Insert cloned instructions prefixSeq.InsertTo(0, seq); seq.InsertToAfter(instruction, body); // Change replaced instruction to nop instruction.ChangeToNop(); // Update offsets body.ComputeOffsets(); }
/// <summary> /// Inline the call to the given method /// </summary> private static void InlineCall(Instruction instruction, MethodBody body, MethodDefinition targetMethod) { // Prepare var prefixSeq = new ILSequence(); // Create "this" variable VariableDefinition thisVariable = null; if (targetMethod.HasThis) { thisVariable = new VariableDefinition(targetMethod.DeclaringType); body.Variables.Add(thisVariable); body.InitLocals = true; } // Store argument in variables var paramVariables = new List<VariableDefinition>(); foreach (var parameter in targetMethod.Parameters.Reverse()) { // Create variable var paramVariable = new VariableDefinition(parameter.ParameterType); body.Variables.Add(paramVariable); paramVariables.Insert(0, paramVariable); // Pop prefixSeq.Emit(OpCodes.Stloc, paramVariable); } // Store this argument (if any) if (thisVariable != null) { // Pop prefixSeq.Emit(OpCodes.Stloc, thisVariable); } // Clone variables first var source = targetMethod.Body; var variables = new List<VariableDefinition>(); foreach (var sv in source.Variables) { var clone = new VariableDefinition(sv.VariableType); variables.Add(clone); body.Variables.Add(clone); } // Now clone instructions var seq = new ILSequence(); foreach (var instr in source.Instructions) { var ni = new Instruction(instr.OpCode, instr.Operand); seq.Append(ni); ni.Offset = instr.Offset; // Convert variable opcodes switch (instr.OpCode.OperandType) { case OperandType.InlineVar: case OperandType.ShortInlineVar: { var index = source.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = variables[index]; } break; } // Convert parameter opcodes switch (instr.OpCode.Code) { case Code.Ldarg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloc; } break; case Code.Ldarga: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloca; } break; case Code.Starg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Stloc; } break; } } // Update branch targets for (var i = 0; i < seq.Length; i++) { var instr = seq[i]; var oldi = source.Instructions[i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { var olds = (Instruction[])oldi.Operand; var targets = new Instruction[olds.Length]; for (int j = 0; j < targets.Length; j++) { targets[j] = GetClone(seq, source.Instructions, olds[j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand); } } // Clone exception handlers if (source.HasExceptionHandlers) { body.ComputeOffsets(); CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers); } // Replace ret instructions var end = seq.Emit(OpCodes.Nop); var retInstructions = seq.Where(x => x.OpCode.Code == Code.Ret).ToList(); foreach (var ins in retInstructions) { ins.OpCode = OpCodes.Br; ins.Operand = end; } // cast return type of a generic method. TODO: better might be to // correctly resolve calls to generic instances as well (above) if (targetMethod.ReturnType.IsGenericParameter) { var methodRef = (MethodReference)instruction.Operand; TypeReference returnType = null; var gp = (GenericParameter)methodRef.ReturnType; if (gp.Type == GenericParameterType.Type) { var gi = methodRef.DeclaringType as IGenericInstance; if (gi != null && gi.HasGenericArguments) returnType = gi.GenericArguments[gp.Position]; } else if (gp.Type == GenericParameterType.Method) { var gi = methodRef as IGenericInstance; if (gi != null && gi.HasGenericArguments) returnType = gi.GenericArguments[gp.Position]; } if (returnType != null) { if (!returnType.IsPrimitive) { seq.Emit(OpCodes.Castclass, returnType); } // todo: handle primitive types. unbox them? are structs correctly handled? enums? } } // Insert cloned instructions prefixSeq.InsertTo(0, seq); seq.InsertToAfter(instruction, body); // Change replaced instruction to nop instruction.ChangeToNop(); // Update offsets body.ComputeOffsets(); }
/// <summary> /// Inline the call to the given method /// </summary> private static void InlineCall(Instruction instruction, MethodBody body, MethodDefinition targetMethod) { // Prepare var prefixSeq = new ILSequence(); // Create "this" variable VariableDefinition thisVariable = null; if (targetMethod.HasThis) { thisVariable = new VariableDefinition(targetMethod.DeclaringType); body.Variables.Add(thisVariable); body.InitLocals = true; } // Store argument in variables var paramVariables = new List<VariableDefinition>(); foreach (var parameter in targetMethod.Parameters.Reverse()) { // Create variable var paramVariable = new VariableDefinition(parameter.ParameterType); body.Variables.Add(paramVariable); paramVariables.Insert(0, paramVariable); // Pop prefixSeq.Emit(OpCodes.Stloc, paramVariable); } // Store this argument (if any) if (thisVariable != null) { // Pop prefixSeq.Emit(OpCodes.Stloc, thisVariable); } // Clone variables first var source = targetMethod.Body; var variables = new List<VariableDefinition>(); foreach (var sv in source.Variables) { var clone = new VariableDefinition(sv.VariableType); variables.Add(clone); body.Variables.Add(clone); } // Now clone instructions var seq = new ILSequence(); foreach (var instr in source.Instructions) { var ni = new Instruction(instr.OpCode, instr.Operand); seq.Append(ni); ni.Offset = instr.Offset; // Convert variable opcodes switch (instr.OpCode.OperandType) { case OperandType.InlineVar: case OperandType.ShortInlineVar: { var index = source.Variables.IndexOf((VariableDefinition)instr.Operand); ni.Operand = variables[index]; } break; } // Convert parameter opcodes switch (instr.OpCode.Code) { case Code.Ldarg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloc; } break; case Code.Ldarga: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Ldloca; } break; case Code.Starg: { var index = targetMethod.Parameters.IndexOf((ParameterDefinition)instr.Operand); ni.Operand = (index >= 0) ? paramVariables[index] : thisVariable; ni.OpCode = OpCodes.Stloc; } break; } } // Update branch targets for (var i = 0; i < seq.Length; i++) { var instr = seq[i]; var oldi = source.Instructions[i]; if (instr.OpCode.OperandType == OperandType.InlineSwitch) { var olds = (Instruction[])oldi.Operand; var targets = new Instruction[olds.Length]; for (int j = 0; j < targets.Length; j++) { targets[j] = GetClone(seq, source.Instructions, olds[j]); } instr.Operand = targets; } else if (instr.OpCode.OperandType == OperandType.ShortInlineBrTarget || instr.OpCode.OperandType == OperandType.InlineBrTarget) { instr.Operand = GetClone(seq, source.Instructions, (Instruction)oldi.Operand); } } // Clone exception handlers if (source.HasExceptionHandlers) { body.ComputeOffsets(); CloneInstructions(seq, source.Instructions, body.ExceptionHandlers, source.ExceptionHandlers); } // Replace ret instructions var end = seq.Emit(OpCodes.Nop); var retInstructions = seq.Where(x => x.OpCode.Code == Code.Ret).ToList(); foreach (var ins in retInstructions) { ins.OpCode = OpCodes.Br; ins.Operand = end; } // Insert cloned instructions prefixSeq.InsertTo(0, seq); seq.InsertToAfter(instruction, body); // Change replaced instruction to nop instruction.ChangeToNop(); // Update offsets body.ComputeOffsets(); }