private void Replace(CilWorker IL, Instruction oldInstruction, MethodReference targetMethod, MethodDefinition hostMethod, Instruction endLabel, Instruction callOriginalMethod) { var returnType = targetMethod.ReturnType.ReturnType; var module = hostMethod.DeclaringType.Module; if (!hostMethod.IsStatic) GetInstanceProvider(IL); var pushInstance = hostMethod.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull); // If all else fails, use the static method replacement provider IL.Append(pushInstance); IL.Emit(OpCodes.Ldloc, _invocationInfo); IL.Emit(OpCodes.Call, _getStaticProvider); IL.Emit(OpCodes.Stloc, _staticProvider); var restoreArgumentStack = IL.Create(OpCodes.Nop); var callReplacement = IL.Create(OpCodes.Nop); var useStaticProvider = IL.Create(OpCodes.Nop); #region Use the instance method replacement provider IL.Emit(OpCodes.Ldloc, _instanceProvider); IL.Emit(OpCodes.Brfalse, useStaticProvider); EmitCanReplace(IL, hostMethod, _instanceProvider); IL.Emit(OpCodes.Ldloc, _canReplaceFlag); IL.Emit(OpCodes.Brfalse, useStaticProvider); EmitGetMethodReplacement(IL, hostMethod, _instanceProvider); IL.Emit(OpCodes.Ldloc, _replacement); IL.Emit(OpCodes.Brtrue, callReplacement); #endregion IL.Append(useStaticProvider); // if (!MethodReplacementProvider.CanReplace(info)) // CallOriginalMethod(); EmitCanReplace(IL, hostMethod, _staticProvider); IL.Emit(OpCodes.Ldloc, _canReplaceFlag); IL.Emit(OpCodes.Brfalse, restoreArgumentStack); EmitGetMethodReplacement(IL, hostMethod, _staticProvider); IL.Append(callReplacement); // if (replacement == null) // CallOriginalMethod(); IL.Emit(OpCodes.Ldloc, _replacement); IL.Emit(OpCodes.Brfalse, restoreArgumentStack); EmitInterceptorCall(IL); IL.PackageReturnValue(module, returnType); IL.Emit(OpCodes.Br, endLabel); IL.Append(restoreArgumentStack); // Reconstruct the method arguments if the interceptor // cannot be found // Push the target instance ReconstructMethodArguments(IL, targetMethod); // Mark the CallOriginalMethod instruction label IL.Append(callOriginalMethod); // Call the original method IL.Append(oldInstruction); }
private static void InvokeInterceptor(ModuleDefinition module, CilWorker IL, VariableDefinition methodReplacement, TypeReference returnType, VariableDefinition invocationInfo) { var interceptMethod = module.ImportMethod<IInterceptor>("Intercept"); IL.Emit(OpCodes.Ldloc, methodReplacement); IL.Emit(OpCodes.Ldloc, invocationInfo); IL.Emit(OpCodes.Callvirt, interceptMethod); IL.PackageReturnValue(module, returnType); }