/src/LinFu.AOP/Emitters/AddMethodReplacementImplementation.cs
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}