public MethodBase Rewrite() { List <Type> parameterTypes = new List <Type>(); if (!_method.IsStatic) { if (_method.IsForValueType()) { parameterTypes.Add(_method.DeclaringType.MakeByRefType()); } else { parameterTypes.Add(_method.DeclaringType); } } parameterTypes.AddRange(_method.GetParameters().Select(p => p.ParameterType)); Type returnType = _method.IsConstructor ? typeof(void) : (_method as MethodInfo).ReturnType; DynamicMethod dynamicMethod = new DynamicMethod( string.Format("dynamic_{0}_{1}", _method.DeclaringType, _method.Name), returnType, parameterTypes.ToArray(), StubHelper.GetOwningModule(), true); MethodDisassembler disassembler = new MethodDisassembler(_method); MethodBody methodBody = _method.GetMethodBody(); IList <LocalVariableInfo> locals = methodBody.LocalVariables; Dictionary <int, Label> targetInstructions = new Dictionary <int, Label>(); List <ExceptionHandler> handlers = new List <ExceptionHandler>(); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); var instructions = disassembler.GetILInstructions(); foreach (var clause in methodBody.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler(); handler.Flag = clause.Flags.ToString(); handler.CatchType = handler.Flag == "Clause" ? clause.CatchType : null; handler.TryStart = clause.TryOffset; handler.TryEnd = (clause.TryOffset + clause.TryLength); handler.HandlerStart = clause.HandlerOffset; handler.HandlerEnd = (clause.HandlerOffset + clause.HandlerLength); handlers.Add(handler); } foreach (var local in locals) { ilGenerator.DeclareLocal(local.LocalType, local.IsPinned); } var ifTargets = instructions .Where(i => (i.Operand as Instruction) != null) .Where(i => !s_IgnoredOpCodes.Contains(i.OpCode)) .Select(i => (i.Operand as Instruction)); foreach (Instruction instruction in ifTargets) { targetInstructions.TryAdd(instruction.Offset, ilGenerator.DefineLabel()); } var switchTargets = instructions .Where(i => (i.Operand as Instruction[]) != null) .Select(i => (i.Operand as Instruction[])); foreach (Instruction[] _instructions in switchTargets) { foreach (Instruction _instruction in _instructions) { targetInstructions.TryAdd(_instruction.Offset, ilGenerator.DefineLabel()); } } foreach (var instruction in instructions) { EmitILForExceptionHandlers(ilGenerator, instruction, handlers); if (s_IgnoredOpCodes.Contains(instruction.OpCode)) { continue; } if (targetInstructions.TryGetValue(instruction.Offset, out Label label)) { ilGenerator.MarkLabel(label); } switch (instruction.OpCode.OperandType) { case OperandType.InlineNone: EmitILForInlineNone(ilGenerator, instruction); break; case OperandType.InlineI: EmitILForInlineI(ilGenerator, instruction); break; case OperandType.InlineI8: EmitILForInlineI8(ilGenerator, instruction); break; case OperandType.ShortInlineI: EmitILForShortInlineI(ilGenerator, instruction); break; case OperandType.InlineR: EmitILForInlineR(ilGenerator, instruction); break; case OperandType.ShortInlineR: EmitILForShortInlineR(ilGenerator, instruction); break; case OperandType.InlineString: EmitILForInlineString(ilGenerator, instruction); break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: EmitILForInlineBrTarget(ilGenerator, instruction, targetInstructions); break; case OperandType.InlineSwitch: EmitILForInlineSwitch(ilGenerator, instruction, targetInstructions); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: EmitILForInlineVar(ilGenerator, instruction); break; case OperandType.InlineTok: case OperandType.InlineType: case OperandType.InlineField: case OperandType.InlineMethod: EmitILForInlineMember(ilGenerator, instruction); break; default: throw new NotSupportedException(); } } return(dynamicMethod); }
public MethodBase Rewrite() { List <Type> parameterTypes = new List <Type>(); if (!_method.IsStatic) { if (_method.IsForValueType()) { parameterTypes.Add(_method.DeclaringType.MakeByRefType()); } else { parameterTypes.Add(_method.DeclaringType); } } parameterTypes.AddRange(_method.GetParameters().Select(p => p.ParameterType)); Type returnType = _method.IsConstructor ? typeof(void) : (_method as MethodInfo).ReturnType; DynamicMethod dynamicMethod = new DynamicMethod( string.Format("dynamic_{0}_{1}", _method.DeclaringType, _method.Name), returnType, parameterTypes.ToArray()); MethodDisassembler disassembler = new MethodDisassembler(_method); IList <LocalVariableInfo> locals = _method.GetMethodBody().LocalVariables; ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); var instructions = disassembler.GetILInstructions(); Dictionary <int, Label> targetInstructions = new Dictionary <int, Label>(); foreach (var local in locals) { ilGenerator.DeclareLocal(local.LocalType, local.IsPinned); } var ifTargets = instructions .Where(i => (i.Operand as Instruction) != null) .Select(i => (i.Operand as Instruction)); foreach (Instruction instruction in ifTargets) { targetInstructions.TryAdd(instruction.Offset, ilGenerator.DefineLabel()); } var switchTargets = instructions .Where(i => (i.Operand as Instruction[]) != null) .Select(i => (i.Operand as Instruction[])); foreach (Instruction[] _instructions in switchTargets) { foreach (Instruction _instruction in _instructions) { targetInstructions.TryAdd(_instruction.Offset, ilGenerator.DefineLabel()); } } foreach (var instruction in instructions) { if (targetInstructions.TryGetValue(instruction.Offset, out Label label)) { ilGenerator.MarkLabel(label); } switch (instruction.OpCode.OperandType) { case OperandType.InlineNone: EmitILForInlineNone(ilGenerator, instruction); break; case OperandType.InlineI: EmitILForInlineI(ilGenerator, instruction); break; case OperandType.InlineI8: EmitILForInlineI8(ilGenerator, instruction); break; case OperandType.ShortInlineI: EmitILForShortInlineI(ilGenerator, instruction); break; case OperandType.InlineR: EmitILForInlineR(ilGenerator, instruction); break; case OperandType.ShortInlineR: EmitILForShortInlineR(ilGenerator, instruction); break; case OperandType.InlineString: EmitILForInlineString(ilGenerator, instruction); break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: EmitILForInlineBrTarget(ilGenerator, instruction, targetInstructions); break; case OperandType.InlineSwitch: EmitILForInlineSwitch(ilGenerator, instruction, targetInstructions); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: EmitILForInlineVar(ilGenerator, instruction); break; case OperandType.InlineTok: case OperandType.InlineType: case OperandType.InlineField: case OperandType.InlineMethod: EmitILForInlineMember(ilGenerator, instruction); break; default: throw new NotSupportedException(); } } return(dynamicMethod); }
public MethodBase Rewrite() { List <Type> parameterTypes = new List <Type>(); if (!_method.IsStatic) { if (_method.IsForValueType()) { parameterTypes.Add(_method.DeclaringType.MakeByRefType()); } else { parameterTypes.Add(_method.DeclaringType); } } parameterTypes.AddRange(_method.GetParameters().Select(p => p.ParameterType)); Type returnType = _method.IsConstructor ? typeof(void) : (_method as MethodInfo).ReturnType; DynamicMethod dynamicMethod = new DynamicMethod(string.Format("dynamic_{0}_{1}", _method.DeclaringType, _method.Name), returnType, parameterTypes.ToArray(), StubHelper.GetOwningModule(), true); MethodDisassembler disassembler = new MethodDisassembler(_method); MethodBody methodBody = _method.GetMethodBody(); IList <LocalVariableInfo> locals = methodBody.LocalVariables; Dictionary <int, Label> targetInstructions = new Dictionary <int, Label>(); List <ExceptionHandler> handlers = new List <ExceptionHandler>(); ILGenerator ilGenerator = dynamicMethod.GetILGenerator(); var instructions = disassembler.GetILInstructions(); var code = _method.GetMethodBody(); foreach (var clause in methodBody.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler(); handler.Flag = clause.Flags.ToString(); handler.CatchType = handler.Flag == "Clause" ? clause.CatchType : null; handler.TryStart = clause.TryOffset; handler.TryEnd = (clause.TryOffset + clause.TryLength); handler.HandlerStart = clause.HandlerOffset; handler.HandlerEnd = (clause.HandlerOffset + clause.HandlerLength); handlers.Add(handler); } foreach (var local in locals) { ilGenerator.DeclareLocal(local.LocalType, local.IsPinned); } var ifTargets = instructions .Where(i => (i.Operand as Instruction) != null) .Where(i => !s_IgnoredOpCodes.Contains(i.OpCode)) .Select(i => (i.Operand as Instruction)); foreach (Instruction instruction in ifTargets) { targetInstructions.TryAdd(instruction.Offset, ilGenerator.DefineLabel()); } var switchTargets = instructions .Where(i => (i.Operand as Instruction[]) != null) .Select(i => (i.Operand as Instruction[])); foreach (Instruction[] _instructions in switchTargets) { foreach (Instruction _instruction in _instructions) { targetInstructions.TryAdd(_instruction.Offset, ilGenerator.DefineLabel()); } } foreach (var instruction in instructions) { EmitILForExceptionHandlers(ilGenerator, instruction, handlers); if (s_IgnoredOpCodes.Contains(instruction.OpCode)) { continue; } if (targetInstructions.TryGetValue(instruction.Offset, out Label label)) { ilGenerator.MarkLabel(label); } // If a constrained instruction is a prefix for an interface, we know any value types // must have implemented the interface explicitly, and thus both the constrained and // callvirt instructions can be replaced by a simple call instruction. // This is necessary as Invoking methods by reflection doesn't seem to work the same way as the CLR which // replaces constrained/callvirt pairs to simple calls on the type itself, and the fact that it doesn't do this // seems to break Pose and the calls to Method.Invoke if (instruction.OpCode == OpCodes.Constrained) { _lastInstruction = instruction; _wasLastInstructionConstrained = true; _lastType = instruction.Operand as TypeInfo; continue; } if (_wasLastInstructionConstrained) { _wasLastInstructionConstrained = false; if (instruction.OpCode == OpCodes.Callvirt && ((instruction.Operand as MethodInfo)?.DeclaringType?.IsInterface ?? false)) { // emit Nops for constrained call (size is 6) // TODO: Get size from actual offset difference and emit that number of nops... though constrained is always 6 and very unlikely to change EmitILNop(ilGenerator); EmitILNop(ilGenerator); EmitILNop(ilGenerator); EmitILNop(ilGenerator); EmitILNop(ilGenerator); EmitILNop(ilGenerator); // change operand and continue var currentMethodInfo = instruction.Operand as MethodInfo; var replacementMethodInfo = _lastType.GetMethod(currentMethodInfo.Name); EmitILForMethod(ilGenerator, instruction, replacementMethodInfo, true); continue; } EmitILForInlineMember(ilGenerator, _lastInstruction); _lastInstruction = null; _lastType = null; } else { _wasLastInstructionConstrained = false; } switch (instruction.OpCode.OperandType) { case OperandType.InlineNone: EmitILForInlineNone(ilGenerator, instruction); break; case OperandType.InlineI: EmitILForInlineI(ilGenerator, instruction); break; case OperandType.InlineI8: EmitILForInlineI8(ilGenerator, instruction); break; case OperandType.ShortInlineI: EmitILForShortInlineI(ilGenerator, instruction); break; case OperandType.InlineR: EmitILForInlineR(ilGenerator, instruction); break; case OperandType.ShortInlineR: EmitILForShortInlineR(ilGenerator, instruction); break; case OperandType.InlineString: EmitILForInlineString(ilGenerator, instruction); break; case OperandType.ShortInlineBrTarget: case OperandType.InlineBrTarget: EmitILForInlineBrTarget(ilGenerator, instruction, targetInstructions); break; case OperandType.InlineSwitch: EmitILForInlineSwitch(ilGenerator, instruction, targetInstructions); break; case OperandType.ShortInlineVar: case OperandType.InlineVar: EmitILForInlineVar(ilGenerator, instruction); break; case OperandType.InlineTok: case OperandType.InlineType: case OperandType.InlineField: case OperandType.InlineMethod: EmitILForInlineMember(ilGenerator, instruction); break; default: throw new NotSupportedException(); } } return(dynamicMethod); }