PageRenderTime 18ms CodeModel.GetById 10ms app.highlight 5ms RepoModel.GetById 1ms app.codeStats 0ms

/src/LinFu.AOP/MethodBodyInterception/InterceptAndSurroundMethodBody.cs

http://github.com/philiplaureano/LinFu
C# | 116 lines | 61 code | 18 blank | 37 comment | 0 complexity | b7915b4a007be14ecb98d8821690ba50 MD5 | raw file
  1using System.Collections.Generic;
  2using LinFu.AOP.Cecil.Interfaces;
  3using LinFu.AOP.Interfaces;
  4using LinFu.Reflection.Emit;
  5using Mono.Cecil;
  6using Mono.Cecil.Cil;
  7
  8namespace LinFu.AOP.Cecil
  9{
 10    /// <summary>
 11    ///     Represents a method body rewriter that surrounds a method body with the necessary prolog and epilogs
 12    ///     that enable method body interception.
 13    /// </summary>
 14    public class InterceptAndSurroundMethodBody : IMethodBodyRewriter
 15    {
 16        private readonly IInstructionEmitter _addMethodReplacement;
 17        private readonly IEmitInvocationInfo _emitter;
 18        private readonly IInstructionEmitter _getClassMethodReplacementProvider;
 19        private readonly IInstructionEmitter _getInstanceMethodReplacementProvider;
 20        private readonly IInstructionEmitter _getInterceptionDisabled;
 21        private readonly VariableDefinition _interceptionDisabled;
 22        private readonly IMethodBodyRewriterParameters _parameters;
 23        private readonly ISurroundMethodBody _surroundMethodBody;
 24
 25        /// <summary>
 26        ///     Initializes a new instance of the <see cref="InterceptAndSurroundMethodBody" /> class.
 27        /// </summary>
 28        /// <param name="emitter">The emitter that will instantiate the <see cref="IInvocationInfo" /> instance.</param>
 29        /// <param name="getInterceptionDisabled">The emitter that will determine whether or not method interception is enabled.</param>
 30        /// <param name="surroundMethodBody">
 31        ///     The <see cref="ISurroundMethodBody" /> instance that will add the epilogs and prologs
 32        ///     to the method body.
 33        /// </param>
 34        /// <param name="getInstanceMethodReplacementProvider">
 35        ///     The emitter that will obtain the method replacement provider
 36        ///     instance.
 37        /// </param>
 38        /// <param name="getClassMethodReplacementProvider">
 39        ///     The emitter that will obtain the class-level method replacement
 40        ///     provider instance.
 41        /// </param>
 42        /// <param name="addMethodReplacement">
 43        ///     The instruction emitter that will add the call to obtain the method body replacement
 44        ///     instance.
 45        /// </param>
 46        /// <param name="parameters">The parameters that describe the context of the method body rewrite.</param>
 47        public InterceptAndSurroundMethodBody(IEmitInvocationInfo emitter,
 48            IInstructionEmitter getInterceptionDisabled,
 49            ISurroundMethodBody surroundMethodBody,
 50            IInstructionEmitter getInstanceMethodReplacementProvider,
 51            IInstructionEmitter getClassMethodReplacementProvider,
 52            IInstructionEmitter addMethodReplacement,
 53            IMethodBodyRewriterParameters parameters)
 54        {
 55            _getInterceptionDisabled = getInterceptionDisabled;
 56            _surroundMethodBody = surroundMethodBody;
 57            _getInstanceMethodReplacementProvider = getInstanceMethodReplacementProvider;
 58            _getClassMethodReplacementProvider = getClassMethodReplacementProvider;
 59            _addMethodReplacement = addMethodReplacement;
 60            _parameters = parameters;
 61            _emitter = emitter;
 62
 63            _interceptionDisabled = parameters.InterceptionDisabled;
 64        }
 65
 66
 67        /// <summary>
 68        ///     Rewrites a target method using the given ILProcessor.
 69        /// </summary>
 70        /// <param name="method">The target method.</param>
 71        /// <param name="IL">The ILProcessor that will be used to rewrite the target method.</param>
 72        /// <param name="oldInstructions">The original instructions from the target method body.</param>
 73        public void Rewrite(MethodDefinition method, ILProcessor IL,
 74            IEnumerable<Instruction> oldInstructions)
 75        {
 76            var targetMethod = _parameters.TargetMethod;
 77            var worker = targetMethod.GetILGenerator();
 78            var module = worker.Body.Method.DeclaringType.Module;
 79
 80
 81            _getInterceptionDisabled.Emit(worker);
 82
 83            // Construct the InvocationInfo instance
 84            var skipInvocationInfo = worker.Create(OpCodes.Nop);
 85            worker.Emit(OpCodes.Ldloc, _parameters.InterceptionDisabled);
 86            worker.Emit(OpCodes.Brtrue, skipInvocationInfo);
 87
 88            var interceptedMethod = targetMethod;
 89            _emitter.Emit(targetMethod, interceptedMethod, _parameters.InvocationInfo);
 90
 91            var skipGetReplacementProvider = IL.Create(OpCodes.Nop);
 92
 93            // var provider = this.MethodReplacementProvider;
 94            IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
 95            IL.Emit(OpCodes.Brtrue, skipGetReplacementProvider);
 96
 97            _getInstanceMethodReplacementProvider.Emit(IL);
 98            _surroundMethodBody.AddProlog(worker);
 99
100            IL.Append(skipGetReplacementProvider);
101
102            worker.Append(skipInvocationInfo);
103            _getClassMethodReplacementProvider.Emit(worker);
104
105            _addMethodReplacement.Emit(worker);
106
107            // Save the return value
108            _surroundMethodBody.AddEpilog(worker);
109
110            //if (returnType != voidType)
111            //    worker.Emit(OpCodes.Ldloc, _parameters.ReturnValue);
112
113            worker.Emit(OpCodes.Ret);
114        }
115    }
116}