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