PageRenderTime 83ms CodeModel.GetById 40ms app.highlight 7ms RepoModel.GetById 33ms app.codeStats 0ms

/src/LinFu.AOP/Emitters/InvokeMethodReplacement.cs

http://github.com/philiplaureano/LinFu
C# | 115 lines | 73 code | 17 blank | 25 comment | 0 complexity | 64a64585278c62c2777a343514ad4693 MD5 | raw file
  1using LinFu.AOP.Cecil.Interfaces;
  2using LinFu.AOP.Interfaces;
  3using LinFu.Reflection.Emit;
  4using Mono.Cecil;
  5using Mono.Cecil.Cil;
  6using MethodDefinitionExtensions = LinFu.AOP.Cecil.Extensions.MethodDefinitionExtensions;
  7
  8namespace LinFu.AOP.Cecil
  9{
 10    /// <summary>
 11    ///     Represents a class that emits the instructions that call the method replacement instead of the original method
 12    ///     body.
 13    /// </summary>
 14    public class InvokeMethodReplacement : IInstructionEmitter
 15    {
 16        private readonly VariableDefinition _classMethodReplacementProvider;
 17        private readonly Instruction _executeOriginalInstructions;
 18        private readonly VariableDefinition _invocationInfo;
 19        private readonly VariableDefinition _methodReplacementProvider;
 20
 21        /// <summary>
 22        ///     Initializes a new instance of the <see cref="InvokeMethodReplacement" /> class.
 23        /// </summary>
 24        /// <param name="executeOriginalInstructions">
 25        ///     The instruction label that will be used if the original instructions should
 26        ///     be executed.
 27        /// </param>
 28        /// <param name="methodReplacementProvider">
 29        ///     The variable that contains the <see cref="IMethodReplacementProvider" />
 30        ///     instance.
 31        /// </param>
 32        /// <param name="classMethodReplacementProvider">
 33        ///     The variable that contains the class-level
 34        ///     <see cref="IMethodReplacementProvider" /> instance.
 35        /// </param>
 36        /// <param name="invocationInfo">The variable that contains the <see cref="IInvocationInfo" /> instance.</param>
 37        public InvokeMethodReplacement(Instruction executeOriginalInstructions,
 38            VariableDefinition methodReplacementProvider,
 39            VariableDefinition classMethodReplacementProvider,
 40            VariableDefinition invocationInfo)
 41        {
 42            _executeOriginalInstructions = executeOriginalInstructions;
 43            _methodReplacementProvider = methodReplacementProvider;
 44            _classMethodReplacementProvider = classMethodReplacementProvider;
 45            _invocationInfo = invocationInfo;
 46        }
 47
 48
 49        /// <summary>
 50        ///     Emits the instructions that call the method replacement instead of the original method body.
 51        /// </summary>
 52        /// <param name="IL">The <see cref="ILProcessor" /> that points to the current method body.</param>
 53        public void Emit(ILProcessor IL)
 54        {
 55            var method = IL.Body.Method;
 56            var module = method.Module;
 57            
 58            var returnType = method.ReturnType;
 59            var methodReplacement = MethodDefinitionExtensions.AddLocal(method, typeof(IInterceptor));
 60
 61            GetMethodReplacementInstance(method, IL, methodReplacement, _methodReplacementProvider, _invocationInfo);
 62
 63            var skipGetClassMethodReplacement = IL.Create(OpCodes.Nop);
 64            IL.Emit(OpCodes.Ldloc, methodReplacement);
 65            IL.Emit(OpCodes.Brtrue, skipGetClassMethodReplacement);
 66
 67            GetMethodReplacementInstance(method, IL, methodReplacement, _classMethodReplacementProvider,
 68                _invocationInfo);
 69
 70            IL.Append(skipGetClassMethodReplacement);
 71            IL.Emit(OpCodes.Ldloc, methodReplacement);
 72            IL.Emit(OpCodes.Brfalse, _executeOriginalInstructions);
 73
 74            // var returnValue = replacement.Intercept(info);
 75            InvokeInterceptor(module, IL, methodReplacement, returnType, _invocationInfo);
 76        }
 77
 78
 79        private static void InvokeInterceptor(ModuleDefinition module, ILProcessor IL,
 80            VariableDefinition methodReplacement, TypeReference returnType,
 81            VariableDefinition invocationInfo)
 82        {
 83            var interceptMethod = module.ImportMethod<IInterceptor>("Intercept");
 84            IL.Emit(OpCodes.Ldloc, methodReplacement);
 85            IL.Emit(OpCodes.Ldloc, invocationInfo);
 86            IL.Emit(OpCodes.Callvirt, interceptMethod);
 87            IL.PackageReturnValue(module, returnType);
 88        }
 89
 90        private static void GetMethodReplacementInstance(MethodDefinition method,
 91            ILProcessor IL,
 92            VariableDefinition methodReplacement,
 93            VariableDefinition methodReplacementProvider,
 94            VariableDefinition invocationInfo)
 95        {
 96            var declaringType = method.DeclaringType;
 97            var module = declaringType.Module;
 98            var pushInstance = method.HasThis ? IL.Create(OpCodes.Ldarg_0) : IL.Create(OpCodes.Ldnull);
 99
100            var getReplacement = module.ImportMethod<IMethodReplacementProvider>("GetMethodReplacement");
101            IL.Emit(OpCodes.Ldloc, methodReplacementProvider);
102
103            var skipGetMethodReplacement = IL.Create(OpCodes.Nop);
104            IL.Emit(OpCodes.Brfalse, skipGetMethodReplacement);
105            IL.Emit(OpCodes.Ldloc, methodReplacementProvider);
106
107            IL.Append(pushInstance);
108            IL.Emit(OpCodes.Ldloc, invocationInfo);
109            IL.Emit(OpCodes.Callvirt, getReplacement);
110            IL.Emit(OpCodes.Stloc, methodReplacement);
111
112            IL.Append(skipGetMethodReplacement);
113        }
114    }
115}