/// <summary> /// Emits the instructions that call the method replacement instead of the original method body. /// </summary> /// <param name="IL">The <see cref="ILProcessor" /> that points to the current method body.</param> public void Emit(ILProcessor IL) { var method = IL.Body.Method; var module = method.Module; var returnType = method.ReturnType; var methodReplacement = MethodDefinitionExtensions.AddLocal(method, typeof(IInterceptor)); GetMethodReplacementInstance(method, IL, methodReplacement, _methodReplacementProvider, _invocationInfo); var skipGetClassMethodReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brtrue, skipGetClassMethodReplacement); GetMethodReplacementInstance(method, IL, methodReplacement, _classMethodReplacementProvider, _invocationInfo); IL.Append(skipGetClassMethodReplacement); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brfalse, _executeOriginalInstructions); // var returnValue = replacement.Intercept(info); InvokeInterceptor(module, IL, methodReplacement, returnType, _invocationInfo); }
/// <summary> /// Emits the instructions that call the method replacement instead of the original method body. /// </summary> /// <param name="IL">The <see cref="CilWorker"/> that points to the current method body.</param> public void Emit(CilWorker IL) { ModuleDefinition module = IL.GetModule(); MethodDefinition method = IL.GetMethod(); TypeReference returnType = method.ReturnType.ReturnType; VariableDefinition methodReplacement = MethodDefinitionExtensions.AddLocal(method, typeof(IInterceptor)); GetMethodReplacementInstance(method, IL, methodReplacement, _methodReplacementProvider, _invocationInfo); Instruction skipGetClassMethodReplacement = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brtrue, skipGetClassMethodReplacement); GetMethodReplacementInstance(method, IL, methodReplacement, _classMethodReplacementProvider, _invocationInfo); IL.Append(skipGetClassMethodReplacement); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Brfalse, _executeOriginalInstructions); // var returnValue = replacement.Intercept(info); InvokeInterceptor(module, IL, methodReplacement, returnType, _invocationInfo); }
/// <summary> /// Emits the IL to save information about /// the method currently being executed. /// </summary> /// <seealso cref="IInvocationInfo"/> /// <param name="targetMethod">The target method currently being executed.</param> /// <param name="interceptedMethod">The method that will be passed to the <paramref name="invocationInfo"/> as the currently executing method.</param> /// <param name="invocationInfo">The local variable that will store the resulting <see cref="IInvocationInfo"/> instance.</param> public void Emit(MethodDefinition targetMethod, MethodReference interceptedMethod, VariableDefinition invocationInfo) { var module = targetMethod.DeclaringType.Module; var currentMethod = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(MethodBase)); var parameterTypes = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(Type[])); var arguments = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(object[])); var typeArguments = MethodDefinitionExtensions.AddLocal(targetMethod, typeof(Type[])); var systemType = module.ImportType(typeof(Type)); var IL = targetMethod.GetILGenerator(); #region Initialize the InvocationInfo constructor arguments // Type[] typeArguments = new Type[genericTypeCount]; var genericParameterCount = targetMethod.GenericParameters.Count; IL.Emit(OpCodes.Ldc_I4, genericParameterCount); IL.Emit(OpCodes.Newarr, systemType); IL.Emit(OpCodes.Stloc, typeArguments); // object[] arguments = new object[argumentCount]; IL.PushArguments(targetMethod, module, arguments); // object target = this; if (targetMethod.HasThis) { IL.Emit(OpCodes.Ldarg_0); } else { IL.Emit(OpCodes.Ldnull); } IL.PushMethod(interceptedMethod, module); IL.Emit(OpCodes.Stloc, currentMethod); // MethodBase targetMethod = currentMethod as MethodBase; IL.Emit(OpCodes.Ldloc, currentMethod); // Push the generic type arguments onto the stack if (genericParameterCount > 0) { IL.PushGenericArguments(targetMethod, module, typeArguments); } // Make sure that the generic methodinfo is instantiated with the // proper type arguments if (targetMethod.GenericParameters.Count > 0) { var methodInfoType = module.Import(typeof(MethodInfo)); IL.Emit(OpCodes.Isinst, methodInfoType); var getIsGenericMethodDef = module.ImportMethod <MethodInfo>("get_IsGenericMethodDefinition"); IL.Emit(OpCodes.Dup); IL.Emit(OpCodes.Callvirt, getIsGenericMethodDef); // Determine if the current method is a generic method // definition var skipMakeGenericMethod = IL.Create(OpCodes.Nop); IL.Emit(OpCodes.Brfalse, skipMakeGenericMethod); // Instantiate the specific generic method instance var makeGenericMethod = module.ImportMethod <MethodInfo>("MakeGenericMethod", typeof(Type[])); IL.Emit(OpCodes.Ldloc, typeArguments); IL.Emit(OpCodes.Callvirt, makeGenericMethod); IL.Append(skipMakeGenericMethod); } if (_pushStackTrace) { IL.PushStackTrace(module); } else { IL.Emit(OpCodes.Ldnull); } // Save the parameter types IL.Emit(OpCodes.Ldc_I4, targetMethod.Parameters.Count); IL.Emit(OpCodes.Newarr, systemType); IL.Emit(OpCodes.Stloc, parameterTypes); IL.SaveParameterTypes(targetMethod, module, parameterTypes); IL.Emit(OpCodes.Ldloc, parameterTypes); // Push the type arguments back onto the stack IL.Emit(OpCodes.Ldloc, typeArguments); // Save the return type var getTypeFromHandle = module.Import(_getTypeFromHandle); var returnType = targetMethod.ReturnType.ReturnType; IL.Emit(OpCodes.Ldtoken, returnType); IL.Emit(OpCodes.Call, getTypeFromHandle); // Push the arguments back onto the stack IL.Emit(OpCodes.Ldloc, arguments); #endregion // InvocationInfo info = new InvocationInfo(...); var infoConstructor = module.Import(_invocationInfoConstructor); IL.Emit(OpCodes.Newobj, infoConstructor); IL.Emit(OpCodes.Stloc, invocationInfo); }