PageRenderTime 162ms CodeModel.GetById 100ms app.highlight 5ms RepoModel.GetById 56ms app.codeStats 0ms

/src/LinFu.AOP/Emitters/AddMethodReplacementImplementation.cs

http://github.com/philiplaureano/LinFu
C# | 85 lines | 52 code | 17 blank | 16 comment | 0 complexity | 7c95984bac36340bd100e6166d5a3a35 MD5 | raw file
 1using System.Collections.Generic;
 2using LinFu.AOP.Cecil.Interfaces;
 3using LinFu.Reflection.Emit;
 4using Mono.Cecil.Cil;
 5
 6namespace LinFu.AOP.Cecil
 7{
 8    /// <summary>
 9    ///     Represents an instruction emitter that adds method body replacement support to a given method body.
10    /// </summary>
11    public class AddMethodReplacementImplementation : IInstructionEmitter
12    {
13        private readonly VariableDefinition _classMethodReplacementProvider;
14        private readonly VariableDefinition _interceptionDisabled;
15        private readonly VariableDefinition _invocationInfo;
16        private readonly VariableDefinition _methodReplacementProvider;
17        private readonly IEnumerable<Instruction> _oldInstructions;
18        private readonly VariableDefinition _returnValue;
19
20        /// <summary>
21        ///     Initializes a new instance of the <see cref="AddMethodReplacementImplementation" /> class.
22        /// </summary>
23        /// <param name="parameters">The set of parameters that describe the target method body.</param>
24        public AddMethodReplacementImplementation(IMethodBodyRewriterParameters parameters)
25        {
26            _oldInstructions = parameters.OldInstructions;
27            _interceptionDisabled = parameters.InterceptionDisabled;
28            _methodReplacementProvider = parameters.MethodReplacementProvider;
29            _classMethodReplacementProvider = parameters.ClassMethodReplacementProvider;
30            _invocationInfo = parameters.InvocationInfo;
31            _returnValue = parameters.ReturnValue;
32        }
33
34
35        /// <summary>
36        ///     Adds method body interception to the target method.
37        /// </summary>
38        /// <param name="IL">The <see cref="ILProcessor" /> pointing to the target method body.</param>
39        public void Emit(ILProcessor IL)
40        {
41            var method = IL.Body.Method;
42            var returnType = method.ReturnType;
43
44            var endLabel = IL.Create(OpCodes.Nop);
45            var executeOriginalInstructions = IL.Create(OpCodes.Nop);
46
47            // Execute the method body replacement if and only if
48            // interception is enabled
49            IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
50            IL.Emit(OpCodes.Brtrue, executeOriginalInstructions);
51
52            var invokeReplacement = IL.Create(OpCodes.Nop);
53
54            IL.Emit(OpCodes.Ldloc, _methodReplacementProvider);
55            IL.Emit(OpCodes.Brtrue, invokeReplacement);
56
57            IL.Emit(OpCodes.Ldloc, _classMethodReplacementProvider);
58            IL.Emit(OpCodes.Brtrue, invokeReplacement);
59
60            IL.Emit(OpCodes.Br, executeOriginalInstructions);
61            IL.Append(invokeReplacement);
62
63            // This is equivalent to the following code:
64            // var replacement = provider.GetMethodReplacement(info);
65            var invokeMethodReplacement = new InvokeMethodReplacement(executeOriginalInstructions,
66                _methodReplacementProvider,
67                _classMethodReplacementProvider, _invocationInfo);
68            invokeMethodReplacement.Emit(IL);
69
70            IL.Emit(OpCodes.Br, endLabel);
71
72
73            IL.Append(executeOriginalInstructions);
74            var addOriginalInstructions = new AddOriginalInstructions(_oldInstructions, endLabel);
75            addOriginalInstructions.Emit(IL);
76
77
78            // Mark the end of the method body
79            IL.Append(endLabel);
80
81            var saveReturnValue = new SaveReturnValue(returnType, _returnValue);
82            saveReturnValue.Emit(IL);
83        }
84    }
85}