public void TestGetRuntimeMethodForVirtual() { Type type = typeof(StubHelperTests); MethodInfo methodInfo = type.GetMethod("TestGetRuntimeMethodForVirtual"); Assert.AreEqual(methodInfo, StubHelper.DevirtualizeMethod(type, methodInfo)); }
public static DynamicMethod GenerateStubForVirtualCall(MethodInfo method, TypeInfo constrainedType) { Type thisType = constrainedType.MakeByRefType(); MethodInfo actualMethod = StubHelper.DevirtualizeMethod(constrainedType, method); 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 ((actualMethod.GetMethodBody() == null && !actualMethod.IsAbstract) || StubHelper.IsIntrinsic(actualMethod)) { // 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.Call, actualMethod); ilGenerator.Emit(OpCodes.Ret); return(stub); } ilGenerator.DeclareLocal(typeof(IntPtr)); Label rewriteLabel = ilGenerator.DefineLabel(); Label returnLabel = ilGenerator.DefineLabel(); // Inject method info into instruction stream ilGenerator.Emit(OpCodes.Ldtoken, actualMethod); ilGenerator.Emit(OpCodes.Ldtoken, actualMethod.DeclaringType); ilGenerator.Emit(OpCodes.Call, s_getMethodFromHandleMethod); ilGenerator.Emit(OpCodes.Castclass, typeof(MethodInfo)); // Rewrite method ilGenerator.MarkLabel(rewriteLabel); ilGenerator.Emit(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_0); // Setup stack and make indirect call for (int i = 0; i < signatureParamTypes.Count; i++) { ilGenerator.Emit(OpCodes.Ldarg, i); if (i == 0) { if (!constrainedType.IsValueType) { ilGenerator.Emit(OpCodes.Ldind_Ref); signatureParamTypes[i] = constrainedType; } else { if (actualMethod.DeclaringType != constrainedType) { ilGenerator.Emit(OpCodes.Ldobj, constrainedType); ilGenerator.Emit(OpCodes.Box, constrainedType); signatureParamTypes[i] = actualMethod.DeclaringType; } } } } ilGenerator.Emit(OpCodes.Ldloc_0); ilGenerator.EmitCalli(OpCodes.Calli, CallingConventions.Standard, method.ReturnType, signatureParamTypes.ToArray(), null); ilGenerator.MarkLabel(returnLabel); ilGenerator.Emit(OpCodes.Ret); return(stub); }