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);
 }