PageRenderTime 37ms CodeModel.GetById 31ms app.highlight 3ms RepoModel.GetById 1ms app.codeStats 0ms

/src/LinFu.AOP/Emitters/AddOriginalInstructions.cs

http://github.com/philiplaureano/LinFu
C# | 64 lines | 37 code | 9 blank | 18 comment | 10 complexity | 7cfe28f9023b5422439fafc2dafa0e82 MD5 | raw file
 1using System.Collections.Generic;
 2using System.Linq;
 3using LinFu.AOP.Cecil.Interfaces;
 4using Mono.Cecil.Cil;
 5
 6namespace LinFu.AOP.Cecil
 7{
 8    /// <summary>
 9    ///     Represents an instruction emitter that adds the original method instructions to a given method body.
10    /// </summary>
11    public class AddOriginalInstructions : IInstructionEmitter
12    {
13        private readonly Instruction _endLabel;
14        private readonly IEnumerable<Instruction> _oldInstructions;
15
16        /// <summary>
17        ///     Initializes a new instance of the <see cref="AddOriginalInstructions" /> class.
18        /// </summary>
19        /// <param name="oldInstructions">The original method instructions.</param>
20        /// <param name="endLabel">The instruction label that marks the end of the method body.</param>
21        public AddOriginalInstructions(IEnumerable<Instruction> oldInstructions, Instruction endLabel)
22        {
23            _oldInstructions = oldInstructions;
24            _endLabel = endLabel;
25        }
26
27
28        /// <summary>
29        ///     Adds the original instructions to a given method body.
30        /// </summary>
31        /// <param name="IL">The <see cref="ILProcessor" /> responsible for the target method body.</param>
32        public void Emit(ILProcessor IL)
33        {
34            var originalInstructions = new List<Instruction>(_oldInstructions);
35            var lastInstruction = originalInstructions.LastOrDefault();
36
37            if (lastInstruction != null && lastInstruction.OpCode == OpCodes.Ret)
38            {
39                // HACK: Convert the Ret instruction into a Nop
40                // instruction so that the code will
41                // fall through to the epilog
42                lastInstruction.OpCode = OpCodes.Br;
43                lastInstruction.Operand = _endLabel;
44            }
45
46            foreach (var instruction in (IEnumerable<Instruction>) originalInstructions)
47            {
48                if (instruction.OpCode != OpCodes.Ret || instruction == lastInstruction)
49                    continue;
50
51                if (lastInstruction == null)
52                    continue;
53
54                // HACK: Modify all ret instructions to call
55                // the epilog after execution
56                instruction.OpCode = OpCodes.Br;
57                instruction.Operand = lastInstruction;
58            }
59
60            // Emit the original instructions
61            foreach (var instruction in originalInstructions) IL.Append(instruction);
62        }
63    }
64}