public static DynamicMethod GenerateStubForMethodPointer(MethodInfo methodInfo) { List <Type> parameterTypes = new List <Type>(); parameterTypes.Add(typeof(RuntimeMethodHandle)); parameterTypes.Add(typeof(RuntimeTypeHandle)); DynamicMethod stub = new DynamicMethod( string.Format("stub_ftn_{0}_{1}", methodInfo.DeclaringType, methodInfo.Name), typeof(IntPtr), parameterTypes.ToArray(), StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); ilGenerator.DeclareLocal(typeof(MethodInfo)); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldarg_1); ilGenerator.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); ilGenerator.Emit(OpCodes.Stloc_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Call, typeof(MethodRewriter).GetMethod("CreateRewriter", new Type[] { typeof(MethodBase) })); ilGenerator.Emit(OpCodes.Call, typeof(MethodRewriter).GetMethod("Rewrite")); ilGenerator.Emit(OpCodes.Stloc_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetMethodPointer")); ilGenerator.Emit(OpCodes.Ret); return(stub); }
public static DynamicMethod GenerateStubForDirectLoad(MethodBase method) { DynamicMethod stub = new DynamicMethod( StubHelper.CreateStubNameFromMethod("stub_ldftn", method), typeof(IntPtr), Array.Empty <Type>(), StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); if (method.GetMethodBody() == null || StubHelper.IsIntrinsic(method)) { // Method has no body or is a compiler intrinsic, // simply forward arguments to original or shim if (method.IsConstructor) { ilGenerator.Emit(OpCodes.Ldftn, (ConstructorInfo)method); } else { ilGenerator.Emit(OpCodes.Ldftn, (MethodInfo)method); } ilGenerator.Emit(OpCodes.Ret); return(stub); } Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); // Inject method info into instruction stream if (method.IsConstructor) { ilGenerator.Emit(OpCodes.Ldtoken, (ConstructorInfo)method); } else { ilGenerator.Emit(OpCodes.Ldtoken, (MethodInfo)method); } ilGenerator.Emit(OpCodes.Ldtoken, method.DeclaringType); ilGenerator.Emit(OpCodes.Call, s_getMethodFromHandleMethod); // Rewrite method ilGenerator.MarkLabel(rewriteLabel); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Call, s_createRewriterMethod); ilGenerator.Emit(OpCodes.Call, s_rewriteMethod); // Retrieve pointer to rewritten method ilGenerator.Emit(OpCodes.Call, s_getMethodPointerMethod); ilGenerator.MarkLabel(returnLabel); ilGenerator.Emit(OpCodes.Ret); return(stub); }
public static DynamicMethod GenerateStubForVirtualLoad(MethodInfo method) { DynamicMethod stub = new DynamicMethod( StubHelper.CreateStubNameFromMethod("stub_ldvirtftn", method), typeof(IntPtr), new Type[] { method.DeclaringType.IsInterface ? typeof(object) : method.DeclaringType }, StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); if ((method.GetMethodBody() == null && !method.IsAbstract) || StubHelper.IsIntrinsic(method)) { // Method has no body or is a compiler intrinsic, // simply forward arguments to original or shim ilGenerator.Emit(OpCodes.Ldarg, 0); ilGenerator.Emit(OpCodes.Ldvirtftn, method); ilGenerator.Emit(OpCodes.Ret); return(stub); } ilGenerator.DeclareLocal(typeof(MethodInfo)); Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); // Inject method info into instruction stream ilGenerator.Emit(OpCodes.Ldtoken, method); ilGenerator.Emit(OpCodes.Ldtoken, method.DeclaringType); ilGenerator.Emit(OpCodes.Call, s_getMethodFromHandleMethod); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); ilGenerator.Emit(OpCodes.Stloc_0); // Resolve virtual method to object type ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Call, s_devirtualizeMethodMethod); // Rewrite resolved method ilGenerator.MarkLabel(rewriteLabel); ilGenerator.Emit(method.DeclaringType.IsInterface ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Call, s_createRewriterMethod); ilGenerator.Emit(OpCodes.Call, s_rewriteMethod); // Retrieve pointer to rewritten method ilGenerator.Emit(OpCodes.Call, s_getMethodPointerMethod); ilGenerator.MarkLabel(returnLabel); ilGenerator.Emit(OpCodes.Ret); return(stub); }
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(), 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); }
public MethodBase Rewrite() { List <Type> parameterTypes = new List <Type>(); if (!m_method.IsStatic) { Type thisType = m_isInterfaceDispatch ? typeof(object) : m_owningType; if (!m_isInterfaceDispatch && m_owningType.IsValueType) { thisType = thisType.MakeByRefType(); } parameterTypes.Add(thisType); } parameterTypes.AddRange(m_method.GetParameters().Select(p => p.ParameterType)); Type returnType = m_method.IsConstructor ? typeof(void) : (m_method as MethodInfo).ReturnType; DynamicMethod dynamicMethod = new DynamicMethod( StubHelper.CreateStubNameFromMethod("impl", m_method), returnType, parameterTypes.ToArray(), StubHelper.GetOwningModule(), true); var methodBody = m_method.GetMethodBody(); var locals = methodBody.LocalVariables; var targetInstructions = new Dictionary <int, Label>(); var handlers = new List <ExceptionHandler>(); var ilGenerator = dynamicMethod.GetILGenerator(); var instructions = m_method.GetInstructions(); foreach (var clause in methodBody.ExceptionHandlingClauses) { ExceptionHandler handler = new ExceptionHandler(); handler.Flags = clause.Flags; handler.CatchType = clause.Flags == ExceptionHandlingClauseOptions.Clause ? clause.CatchType : null; handler.TryStart = clause.TryOffset; handler.TryEnd = clause.TryOffset + clause.TryLength; handler.FilterStart = clause.Flags == ExceptionHandlingClauseOptions.Filter ? clause.FilterOffset : -1; 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) .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()); } } #if DEBUG Debug.WriteLine("\n" + m_method); #endif foreach (var instruction in instructions) { #if DEBUG Debug.WriteLine(instruction); #endif EmitILForExceptionHandlers(ilGenerator, instruction, handlers); if (targetInstructions.TryGetValue(instruction.Offset, out Label label)) { ilGenerator.MarkLabel(label); } if (s_IngoredOpCodes.Contains(instruction.OpCode)) { continue; } 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(instruction.OpCode.OperandType.ToString()); } } #if DEBUG var ilBytes = ilGenerator.GetILBytes(); var browsableDynamicMethod = new BrowsableDynamicMethod(dynamicMethod, new DynamicMethodBody(ilBytes, locals)); Debug.WriteLine("\n" + dynamicMethod); foreach (var instruction in browsableDynamicMethod.GetInstructions()) { Debug.WriteLine(instruction); } #endif return(dynamicMethod); }
public void TestGetOwningModule() { Assert.AreEqual(typeof(StubHelper).Module, StubHelper.GetOwningModule()); Assert.AreNotEqual(typeof(StubHelperTests).Module, StubHelper.GetOwningModule()); }
public static DynamicMethod GenerateStubForDirectCall(MethodBase method) { Type returnType = method.IsConstructor ? typeof(void) : (method as MethodInfo).ReturnType; List <Type> signatureParamTypes = new List <Type>(); if (!method.IsStatic) { Type thisType = method.DeclaringType; if (thisType.IsValueType) { thisType = thisType.MakeByRefType(); } signatureParamTypes.Add(thisType); } signatureParamTypes.AddRange(method.GetParameters().Select(p => p.ParameterType)); DynamicMethod stub = new DynamicMethod( StubHelper.CreateStubNameFromMethod("stub_call", method), returnType, signatureParamTypes.ToArray(), StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); if (method.GetMethodBody() == null || StubHelper.IsIntrinsic(method)) { // Method has no body or is a compiler intrinsic, // simply forward arguments to original or shim for (int i = 0; i < signatureParamTypes.Count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } if (method.IsConstructor) { ilGenerator.Emit(OpCodes.Call, (ConstructorInfo)method); } else { ilGenerator.Emit(OpCodes.Call, (MethodInfo)method); } ilGenerator.Emit(OpCodes.Ret); return(stub); } ilGenerator.DeclareLocal(typeof(IntPtr)); Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); // Inject method info into instruction stream if (method.IsConstructor) { ilGenerator.Emit(OpCodes.Ldtoken, (ConstructorInfo)method); } else { ilGenerator.Emit(OpCodes.Ldtoken, (MethodInfo)method); } ilGenerator.Emit(OpCodes.Ldtoken, method.DeclaringType); ilGenerator.Emit(OpCodes.Call, s_getMethodFromHandleMethod); // Rewrite method ilGenerator.MarkLabel(rewriteLabel); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Call, s_createRewriterMethod); ilGenerator.Emit(OpCodes.Call, s_rewriteMethod); // Retrieve pointer to rewritten method ilGenerator.Emit(OpCodes.Call, s_getMethodPointerMethod); ilGenerator.Emit(OpCodes.Stloc_0); // Setup stack and make indirect call for (int i = 0; i < signatureParamTypes.Count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.Standard, returnType, signatureParamTypes.ToArray(), null); ilGenerator.MarkLabel(returnLabel); ilGenerator.Emit(OpCodes.Ret); return(stub); }
public static DynamicMethod GenerateStubForObjectInitialization(ConstructorInfo constructor) { Type thisType = constructor.DeclaringType; if (thisType.IsValueType) { thisType = thisType.MakeByRefType(); } List <Type> signatureParamTypes = new List <Type>(); signatureParamTypes.Add(thisType); signatureParamTypes.AddRange(constructor.GetParameters().Select(p => p.ParameterType)); DynamicMethod stub = new DynamicMethod( StubHelper.CreateStubNameFromMethod("stub_newobj", constructor), constructor.DeclaringType, signatureParamTypes.Skip(1).ToArray(), StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); if (constructor.GetMethodBody() == null || StubHelper.IsIntrinsic(constructor)) { // Constructor has no body or is a compiler intrinsic, // simply forward arguments to original or shim for (int i = 0; i < signatureParamTypes.Count - 1; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Newobj, constructor); ilGenerator.Emit(OpCodes.Ret); return(stub); } ilGenerator.DeclareLocal(typeof(IntPtr)); ilGenerator.DeclareLocal(constructor.DeclaringType); Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); // Inject method info into instruction stream ilGenerator.Emit(OpCodes.Ldtoken, constructor); ilGenerator.Emit(OpCodes.Ldtoken, constructor.DeclaringType); ilGenerator.Emit(OpCodes.Call, s_getMethodFromHandleMethod); // Rewrite method ilGenerator.MarkLabel(rewriteLabel); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Call, s_createRewriterMethod); ilGenerator.Emit(OpCodes.Call, s_rewriteMethod); // Retrieve pointer to rewritten method ilGenerator.Emit(OpCodes.Call, s_getMethodPointerMethod); ilGenerator.Emit(OpCodes.Stloc_0); if (constructor.DeclaringType.IsValueType) { ilGenerator.Emit(OpCodes.Ldloca_S, (byte)1); ilGenerator.Emit(OpCodes.Dup); ilGenerator.Emit(OpCodes.Initobj, constructor.DeclaringType); } else { ilGenerator.Emit(OpCodes.Ldtoken, constructor.DeclaringType); ilGenerator.Emit(OpCodes.Call, s_getTypeFromHandleMethod); ilGenerator.Emit(OpCodes.Call, s_getUninitializedObjectMethod); ilGenerator.Emit(OpCodes.Dup); ilGenerator.Emit(OpCodes.Stloc_1); } // Setup stack and make indirect call for (int i = 0; i < signatureParamTypes.Count - 1; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.Standard, typeof(void), signatureParamTypes.ToArray(), null); ilGenerator.MarkLabel(returnLabel); ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Ret); return(stub); }
public static DynamicMethod GenerateStubForVirtualCall(MethodInfo method) { Type thisType = method.DeclaringType.IsInterface ? typeof(object) : method.DeclaringType; List <Type> signatureParamTypes = new List <Type>(); signatureParamTypes.Add(thisType); signatureParamTypes.AddRange(method.GetParameters().Select(p => p.ParameterType)); DynamicMethod stub = new DynamicMethod( StubHelper.CreateStubNameFromMethod("stub_callvirt", method), method.ReturnType, signatureParamTypes.ToArray(), StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); if ((method.GetMethodBody() == null && !method.IsAbstract) || StubHelper.IsIntrinsic(method)) { // Method has no body or is a compiler intrinsic, // simply forward arguments to original or shim for (int i = 0; i < signatureParamTypes.Count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Callvirt, method); ilGenerator.Emit(OpCodes.Ret); return(stub); } ilGenerator.DeclareLocal(typeof(MethodInfo)); ilGenerator.DeclareLocal(typeof(IntPtr)); Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); // Inject method info into instruction stream ilGenerator.Emit(OpCodes.Ldtoken, method); ilGenerator.Emit(OpCodes.Ldtoken, method.DeclaringType); ilGenerator.Emit(OpCodes.Call, s_getMethodFromHandleMethod); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); ilGenerator.Emit(OpCodes.Stloc_0); // Resolve virtual method to object type ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Call, s_devirtualizeMethodMethod); // Rewrite resolved method ilGenerator.MarkLabel(rewriteLabel); ilGenerator.Emit(method.DeclaringType.IsInterface ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Call, s_createRewriterMethod); ilGenerator.Emit(OpCodes.Call, s_rewriteMethod); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); // Retrieve pointer to rewritten method ilGenerator.Emit(OpCodes.Call, s_getMethodPointerMethod); ilGenerator.Emit(OpCodes.Stloc_1); // Setup stack and make indirect call for (int i = 0; i < signatureParamTypes.Count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.Standard, method.ReturnType, signatureParamTypes.ToArray(), null); ilGenerator.MarkLabel(returnLabel); ilGenerator.Emit(OpCodes.Ret); return(stub); }
public static DynamicMethod GenerateStubForConstructor(ConstructorInfo constructorInfo, OpCode opCode, bool forValueType) { ParameterInfo[] parameters = constructorInfo.GetParameters(); List <Type> signatureParamTypes = new List <Type>(); List <Type> parameterTypes = new List <Type>(); if (forValueType) { signatureParamTypes.Add(constructorInfo.DeclaringType.MakeByRefType()); } else { signatureParamTypes.Add(constructorInfo.DeclaringType); } signatureParamTypes.AddRange(parameters.Select(p => p.ParameterType)); if (opCode == OpCodes.Newobj) { parameterTypes.AddRange(parameters.Select(p => p.ParameterType)); } else { parameterTypes.AddRange(signatureParamTypes); } parameterTypes.Add(typeof(RuntimeMethodHandle)); parameterTypes.Add(typeof(RuntimeTypeHandle)); DynamicMethod stub = new DynamicMethod( string.Format("stub_ctor_{0}_{1}", constructorInfo.DeclaringType, constructorInfo.Name), opCode == OpCodes.Newobj ? constructorInfo.DeclaringType : typeof(void), parameterTypes.ToArray(), StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); ilGenerator.DeclareLocal(constructorInfo.DeclaringType); ilGenerator.DeclareLocal(typeof(ConstructorInfo)); ilGenerator.DeclareLocal(typeof(MethodInfo)); ilGenerator.DeclareLocal(typeof(int)); ilGenerator.DeclareLocal(typeof(IntPtr)); Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); ilGenerator.Emit(OpCodes.Ldarg, parameterTypes.Count - 2); ilGenerator.Emit(OpCodes.Ldarg, parameterTypes.Count - 1); ilGenerator.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); ilGenerator.Emit(OpCodes.Castclass, typeof(ConstructorInfo)); ilGenerator.Emit(OpCodes.Stloc_1); ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Ldnull); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetIndexOfMatchingShim", new Type[] { typeof(MethodBase), typeof(Object) })); ilGenerator.Emit(OpCodes.Stloc_3); ilGenerator.Emit(OpCodes.Ldloc_3); ilGenerator.Emit(OpCodes.Ldc_I4_M1); ilGenerator.Emit(OpCodes.Ceq); ilGenerator.Emit(OpCodes.Brtrue_S, rewriteLabel); ilGenerator.Emit(OpCodes.Ldloc_3); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetShimReplacementMethod")); ilGenerator.Emit(OpCodes.Stloc_2); ilGenerator.Emit(OpCodes.Ldloc_2); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetMethodPointer")); ilGenerator.Emit(OpCodes.Stloc, 4); ilGenerator.Emit(OpCodes.Ldloc_3); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetShimDelegateTarget")); for (int i = 0; i < signatureParamTypes.Count - 1; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Ldloc, 4); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.HasThis, constructorInfo.DeclaringType, signatureParamTypes.Skip(1).ToArray(), null); ilGenerator.Emit(OpCodes.Stloc_0); if (opCode == OpCodes.Call) { if (forValueType) { ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Stobj, constructorInfo.DeclaringType); } else { ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Starg, 0); } } ilGenerator.Emit(OpCodes.Br_S, returnLabel); ilGenerator.MarkLabel(rewriteLabel); if (opCode == OpCodes.Newobj) { if (forValueType) { ilGenerator.Emit(OpCodes.Ldloca, 0); ilGenerator.Emit(OpCodes.Initobj, constructorInfo.DeclaringType); } else { ilGenerator.Emit(OpCodes.Ldarg, parameterTypes.Count - 1); ilGenerator.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle")); ilGenerator.Emit(OpCodes.Call, typeof(FormatterServices).GetMethod("GetUninitializedObject")); ilGenerator.Emit(OpCodes.Stloc_0); } } ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Call, typeof(MethodRewriter).GetMethod("CreateRewriter", new Type[] { typeof(MethodBase) })); ilGenerator.Emit(OpCodes.Call, typeof(MethodRewriter).GetMethod("Rewrite")); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); ilGenerator.Emit(OpCodes.Stloc_2); int count = signatureParamTypes.Count; if (opCode == OpCodes.Newobj) { if (forValueType) { ilGenerator.Emit(OpCodes.Ldloca, 0); } else { ilGenerator.Emit(OpCodes.Ldloc_0); } count = count - 1; } for (int i = 0; i < count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Ldloc_2); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetMethodPointer")); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.Standard, typeof(void), signatureParamTypes.ToArray(), null); ilGenerator.MarkLabel(returnLabel); if (opCode == OpCodes.Newobj) { ilGenerator.Emit(OpCodes.Ldloc_0); } ilGenerator.Emit(OpCodes.Ret); return(stub); }
public static DynamicMethod GenerateStubForMethod(MethodInfo methodInfo) { ParameterInfo[] parameters = methodInfo.GetParameters(); List <Type> signatureParamTypes = new List <Type>(); List <Type> parameterTypes = new List <Type>(); if (!methodInfo.IsStatic) { if (methodInfo.IsForValueType()) { signatureParamTypes.Add(methodInfo.DeclaringType.MakeByRefType()); } else { signatureParamTypes.Add(methodInfo.DeclaringType); } } signatureParamTypes.AddRange(parameters.Select(p => p.ParameterType)); parameterTypes.AddRange(signatureParamTypes); parameterTypes.Add(typeof(RuntimeMethodHandle)); parameterTypes.Add(typeof(RuntimeTypeHandle)); DynamicMethod stub = new DynamicMethod( string.Format("stub_{0}_{1}", methodInfo.DeclaringType, methodInfo.Name), methodInfo.ReturnType, parameterTypes.ToArray(), StubHelper.GetOwningModule(), true); ILGenerator ilGenerator = stub.GetILGenerator(); ilGenerator.DeclareLocal(typeof(MethodInfo)); ilGenerator.DeclareLocal(typeof(int)); ilGenerator.DeclareLocal(typeof(IntPtr)); Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); ilGenerator.Emit(OpCodes.Ldarg, parameterTypes.Count - 2); ilGenerator.Emit(OpCodes.Ldarg, parameterTypes.Count - 1); ilGenerator.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new Type[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) })); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); ilGenerator.Emit(OpCodes.Stloc_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(methodInfo.IsStatic || methodInfo.IsForValueType() ? OpCodes.Ldnull : OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetIndexOfMatchingShim", new Type[] { typeof(MethodBase), typeof(Object) })); ilGenerator.Emit(OpCodes.Stloc_1); ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Ldc_I4_M1); ilGenerator.Emit(OpCodes.Ceq); ilGenerator.Emit(OpCodes.Brtrue_S, rewriteLabel); var methodBase = StubHelper.GetShimReplacementMethod(StubHelper.GetIndexOfMatchingShim(methodInfo as MethodBase, null)); if (StubHelper.MethodBaseIsShimmyDynamic(methodBase)) { var dynamicMethod = StubHelper.GetDynamicMethodFromDynamicMethodBase(methodBase); EmitArguments(ilGenerator, signatureParamTypes); ilGenerator.EmitCall(OpCodes.Call, dynamicMethod, null); } else { // do things the classic Pose way ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetShimReplacementMethod")); ilGenerator.Emit(OpCodes.Stloc_0); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetMethodPointer")); ilGenerator.Emit(OpCodes.Stloc_2); ilGenerator.Emit(OpCodes.Ldloc_1); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetShimDelegateTarget")); EmitArguments(ilGenerator, signatureParamTypes); ilGenerator.Emit(OpCodes.Ldloc_2); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.HasThis, methodInfo.ReturnType, signatureParamTypes.ToArray(), null); } ilGenerator.Emit(OpCodes.Br_S, returnLabel); ilGenerator.MarkLabel(rewriteLabel); ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Call, typeof(MethodRewriter).GetMethod("CreateRewriter", new Type[] { typeof(MethodBase) })); ilGenerator.Emit(OpCodes.Call, typeof(MethodRewriter).GetMethod("Rewrite")); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); ilGenerator.Emit(OpCodes.Stloc_0); for (int i = 0; i < signatureParamTypes.Count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); } ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.Emit(OpCodes.Call, typeof(StubHelper).GetMethod("GetMethodPointer")); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.Standard, methodInfo.ReturnType, signatureParamTypes.ToArray(), null); ilGenerator.MarkLabel(returnLabel); ilGenerator.Emit(OpCodes.Ret); return(stub); }