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