PageRenderTime 63ms CodeModel.GetById 57ms app.highlight 3ms RepoModel.GetById 2ms app.codeStats 0ms

/src/LinFu.AOP/Emitters/SurroundMethodBody.cs

http://github.com/philiplaureano/LinFu
C# | 155 lines | 94 code | 23 blank | 38 comment | 3 complexity | 0cf25185cda3d08ea3bebd690e615866 MD5 | raw file
  1using System;
  2using LinFu.AOP.Cecil.Interfaces;
  3using LinFu.AOP.Interfaces;
  4using LinFu.Reflection.Emit;
  5using Mono.Cecil.Cil;
  6
  7namespace LinFu.AOP.Cecil
  8{
  9    /// <summary>
 10    ///     Represents a class that surrounds a call site with calls to an <see cref="IAroundInvoke" /> instance.
 11    /// </summary>
 12    public class SurroundMethodBody : ISurroundMethodBody
 13    {
 14        private readonly VariableDefinition _aroundInvokeProvider;
 15        private readonly IInstructionEmitter _getMethodReplacementProvider;
 16        private readonly VariableDefinition _interceptionDisabled;
 17        private readonly VariableDefinition _invocationInfo;
 18        private readonly VariableDefinition _methodReplacementProvider;
 19        private readonly string _providerName;
 20        private readonly Type _registryType;
 21        private readonly VariableDefinition _returnValue;
 22
 23        private VariableDefinition _surroundingClassImplementation;
 24        private VariableDefinition _surroundingImplementation;
 25
 26        /// <summary>
 27        ///     Initializes a new instance of the <see cref="IMethodBodyRewriterParameters" /> class.
 28        /// </summary>
 29        /// <param name="parameters">The parameters that describe the context of the emitter call.</param>
 30        /// <param name="providerName">The name of the <see cref="IAroundInvokeProvider" /> property.</param>
 31        public SurroundMethodBody(IMethodBodyRewriterParameters parameters, string providerName)
 32        {
 33            _methodReplacementProvider = parameters.MethodReplacementProvider;
 34            _aroundInvokeProvider = parameters.AroundInvokeProvider;
 35            _invocationInfo = parameters.InvocationInfo;
 36            _returnValue = parameters.ReturnValue;
 37            _interceptionDisabled = parameters.InterceptionDisabled;
 38            _providerName = providerName;
 39
 40            var getMethodReplacementProvider = new GetMethodReplacementProvider(_methodReplacementProvider,
 41                parameters.TargetMethod,
 42                parameters.GetMethodReplacementProviderMethod);
 43
 44            _getMethodReplacementProvider = getMethodReplacementProvider;
 45            _registryType = parameters.RegistryType;
 46        }
 47
 48        /// <summary>
 49        ///     Initializes a new instance of the <see cref="IMethodBodyRewriterParameters" /> class.
 50        /// </summary>
 51        /// <param name="methodReplacementProvider">
 52        ///     The variable that contains the <see cref="IMethodReplacementProvider" />
 53        ///     instance.
 54        /// </param>
 55        /// <param name="aroundInvokeProvider">The variable that contains the <see cref="IAroundInvokeProvider" /> instance</param>
 56        /// <param name="invocationInfo">The variable that contains the <see cref="IInvocationInfo" /> instance.</param>
 57        /// <param name="interceptionDisabled">The variable that determines whether or not interception is disabled</param>
 58        /// <param name="returnValue">The variable that contains the method return value.</param>
 59        /// <param name="registryType">
 60        ///     The interception registry type that will be responsible for handling class-level
 61        ///     interception events.
 62        /// </param>
 63        /// <param name="providerName">The name of the <see cref="IAroundInvokeProvider" /> property.</param>
 64        public SurroundMethodBody(VariableDefinition methodReplacementProvider,
 65            VariableDefinition aroundInvokeProvider,
 66            VariableDefinition invocationInfo,
 67            VariableDefinition interceptionDisabled,
 68            VariableDefinition returnValue,
 69            Type registryType,
 70            string providerName)
 71        {
 72            _methodReplacementProvider = methodReplacementProvider;
 73            _aroundInvokeProvider = aroundInvokeProvider;
 74            _invocationInfo = invocationInfo;
 75            _interceptionDisabled = interceptionDisabled;
 76            _returnValue = returnValue;
 77            _registryType = registryType;
 78            _providerName = providerName;
 79        }
 80
 81
 82        /// <summary>
 83        ///     Adds a prolog to the given method body.
 84        /// </summary>
 85        /// <param name="IL">The <see cref="ILProcessor" /> that points to the given method body.</param>
 86        public void AddProlog(ILProcessor IL)
 87        {
 88            var method = IL.Body.Method;
 89            _surroundingImplementation = method.AddLocal<IAroundInvoke>();
 90            _surroundingClassImplementation = method.AddLocal<IAroundInvoke>();
 91
 92            var skipProlog = IL.Create(OpCodes.Nop);
 93            var declaringType = method.DeclaringType;
 94            var module = declaringType.Module;
 95            var modifiableType = module.ImportType<IModifiableType>();
 96
 97            if (method.HasThis)
 98            {
 99                IL.Emit(OpCodes.Ldarg_0);
100                IL.Emit(OpCodes.Isinst, modifiableType);
101                IL.Emit(OpCodes.Brfalse, skipProlog);
102            }
103
104            IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
105            IL.Emit(OpCodes.Brtrue, skipProlog);
106
107            // var provider = this.MethodReplacementProvider;
108
109            if (_getMethodReplacementProvider != null)
110                _getMethodReplacementProvider.Emit(IL);
111
112            var getAroundInvokeProvider = new GetAroundInvokeProvider(_aroundInvokeProvider, _providerName);
113            getAroundInvokeProvider.Emit(IL);
114
115            // if (aroundInvokeProvider != null ) {
116            var skipGetSurroundingImplementation = IL.Create(OpCodes.Nop);
117            var getSurroundingImplementationInstance = new GetSurroundingImplementationInstance(_aroundInvokeProvider,
118                _invocationInfo,
119                _surroundingImplementation,
120                skipGetSurroundingImplementation);
121
122            getSurroundingImplementationInstance.Emit(IL);
123
124            // }
125
126            IL.Append(skipGetSurroundingImplementation);
127            var emitBeforeInvoke = new EmitBeforeInvoke(_invocationInfo, _surroundingClassImplementation,
128                _surroundingImplementation, _registryType);
129            emitBeforeInvoke.Emit(IL);
130
131            IL.Append(skipProlog);
132        }
133
134        /// <summary>
135        ///     Adds an epilog to the given method body.
136        /// </summary>
137        /// <param name="IL">The <see cref="ILProcessor" /> that points to the given method body.</param>
138        public void AddEpilog(ILProcessor IL)
139        {
140            var skipEpilog = IL.Create(OpCodes.Nop);
141
142            // if (!IsInterceptionDisabled && surroundingImplementation != null) {
143            IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
144            IL.Emit(OpCodes.Brtrue, skipEpilog);
145
146            // surroundingImplementation.AfterInvoke(invocationInfo, returnValue);
147            var emitAfterInvoke = new EmitAfterInvoke(_surroundingImplementation, _surroundingClassImplementation,
148                _invocationInfo, _returnValue);
149            emitAfterInvoke.Emit(IL);
150
151            // }
152            IL.Append(skipEpilog);
153        }
154    }
155}