/src/LinFu.AOP/MethodBodyInterception/InterceptAndSurroundMethodBody.cs

http://github.com/philiplaureano/LinFu · C# · 116 lines · 61 code · 18 blank · 37 comment · 0 complexity · b7915b4a007be14ecb98d8821690ba50 MD5 · raw file

  1. using System.Collections.Generic;
  2. using LinFu.AOP.Cecil.Interfaces;
  3. using LinFu.AOP.Interfaces;
  4. using LinFu.Reflection.Emit;
  5. using Mono.Cecil;
  6. using Mono.Cecil.Cil;
  7. namespace LinFu.AOP.Cecil
  8. {
  9. /// <summary>
  10. /// Represents a method body rewriter that surrounds a method body with the necessary prolog and epilogs
  11. /// that enable method body interception.
  12. /// </summary>
  13. public class InterceptAndSurroundMethodBody : IMethodBodyRewriter
  14. {
  15. private readonly IInstructionEmitter _addMethodReplacement;
  16. private readonly IEmitInvocationInfo _emitter;
  17. private readonly IInstructionEmitter _getClassMethodReplacementProvider;
  18. private readonly IInstructionEmitter _getInstanceMethodReplacementProvider;
  19. private readonly IInstructionEmitter _getInterceptionDisabled;
  20. private readonly VariableDefinition _interceptionDisabled;
  21. private readonly IMethodBodyRewriterParameters _parameters;
  22. private readonly ISurroundMethodBody _surroundMethodBody;
  23. /// <summary>
  24. /// Initializes a new instance of the <see cref="InterceptAndSurroundMethodBody" /> class.
  25. /// </summary>
  26. /// <param name="emitter">The emitter that will instantiate the <see cref="IInvocationInfo" /> instance.</param>
  27. /// <param name="getInterceptionDisabled">The emitter that will determine whether or not method interception is enabled.</param>
  28. /// <param name="surroundMethodBody">
  29. /// The <see cref="ISurroundMethodBody" /> instance that will add the epilogs and prologs
  30. /// to the method body.
  31. /// </param>
  32. /// <param name="getInstanceMethodReplacementProvider">
  33. /// The emitter that will obtain the method replacement provider
  34. /// instance.
  35. /// </param>
  36. /// <param name="getClassMethodReplacementProvider">
  37. /// The emitter that will obtain the class-level method replacement
  38. /// provider instance.
  39. /// </param>
  40. /// <param name="addMethodReplacement">
  41. /// The instruction emitter that will add the call to obtain the method body replacement
  42. /// instance.
  43. /// </param>
  44. /// <param name="parameters">The parameters that describe the context of the method body rewrite.</param>
  45. public InterceptAndSurroundMethodBody(IEmitInvocationInfo emitter,
  46. IInstructionEmitter getInterceptionDisabled,
  47. ISurroundMethodBody surroundMethodBody,
  48. IInstructionEmitter getInstanceMethodReplacementProvider,
  49. IInstructionEmitter getClassMethodReplacementProvider,
  50. IInstructionEmitter addMethodReplacement,
  51. IMethodBodyRewriterParameters parameters)
  52. {
  53. _getInterceptionDisabled = getInterceptionDisabled;
  54. _surroundMethodBody = surroundMethodBody;
  55. _getInstanceMethodReplacementProvider = getInstanceMethodReplacementProvider;
  56. _getClassMethodReplacementProvider = getClassMethodReplacementProvider;
  57. _addMethodReplacement = addMethodReplacement;
  58. _parameters = parameters;
  59. _emitter = emitter;
  60. _interceptionDisabled = parameters.InterceptionDisabled;
  61. }
  62. /// <summary>
  63. /// Rewrites a target method using the given ILProcessor.
  64. /// </summary>
  65. /// <param name="method">The target method.</param>
  66. /// <param name="IL">The ILProcessor that will be used to rewrite the target method.</param>
  67. /// <param name="oldInstructions">The original instructions from the target method body.</param>
  68. public void Rewrite(MethodDefinition method, ILProcessor IL,
  69. IEnumerable<Instruction> oldInstructions)
  70. {
  71. var targetMethod = _parameters.TargetMethod;
  72. var worker = targetMethod.GetILGenerator();
  73. var module = worker.Body.Method.DeclaringType.Module;
  74. _getInterceptionDisabled.Emit(worker);
  75. // Construct the InvocationInfo instance
  76. var skipInvocationInfo = worker.Create(OpCodes.Nop);
  77. worker.Emit(OpCodes.Ldloc, _parameters.InterceptionDisabled);
  78. worker.Emit(OpCodes.Brtrue, skipInvocationInfo);
  79. var interceptedMethod = targetMethod;
  80. _emitter.Emit(targetMethod, interceptedMethod, _parameters.InvocationInfo);
  81. var skipGetReplacementProvider = IL.Create(OpCodes.Nop);
  82. // var provider = this.MethodReplacementProvider;
  83. IL.Emit(OpCodes.Ldloc, _interceptionDisabled);
  84. IL.Emit(OpCodes.Brtrue, skipGetReplacementProvider);
  85. _getInstanceMethodReplacementProvider.Emit(IL);
  86. _surroundMethodBody.AddProlog(worker);
  87. IL.Append(skipGetReplacementProvider);
  88. worker.Append(skipInvocationInfo);
  89. _getClassMethodReplacementProvider.Emit(worker);
  90. _addMethodReplacement.Emit(worker);
  91. // Save the return value
  92. _surroundMethodBody.AddEpilog(worker);
  93. //if (returnType != voidType)
  94. // worker.Emit(OpCodes.Ldloc, _parameters.ReturnValue);
  95. worker.Emit(OpCodes.Ret);
  96. }
  97. }
  98. }