/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

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