/ICSharpCode.Decompiler/FlowAnalysis/SsaInstruction.cs

http://github.com/icsharpcode/ILSpy · C# · 191 lines · 111 code · 14 blank · 66 comment · 33 complexity · eb6ef6c763e310373acf269bc2f50824 MD5 · raw file

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Diagnostics;
  20. using System.IO;
  21. using ICSharpCode.Decompiler.Disassembler;
  22. using Mono.Cecil;
  23. using Mono.Cecil.Cil;
  24. namespace ICSharpCode.Decompiler.FlowAnalysis
  25. {
  26. public enum SpecialOpCode
  27. {
  28. /// <summary>
  29. /// No special op code: SsaInstruction has a normal IL instruction
  30. /// </summary>
  31. None,
  32. /// <summary>
  33. /// Φ function: chooses the appropriate variable based on which CFG edge was used to enter this block
  34. /// </summary>
  35. Phi,
  36. /// <summary>
  37. /// Variable is read from before passing it by ref.
  38. /// This instruction constructs a managed reference to the variable.
  39. /// </summary>
  40. PrepareByRefCall,
  41. /// <summary>
  42. /// This instruction constructs a managed reference to the variable.
  43. /// The variable is not really read from.
  44. /// </summary>
  45. PrepareByOutCall,
  46. /// <summary>
  47. /// This instruction constructs a managed reference to the variable.
  48. /// The reference is used for a field access on a value type.
  49. /// </summary>
  50. PrepareForFieldAccess,
  51. /// <summary>
  52. /// Variable is written to after passing it by ref or out.
  53. /// </summary>
  54. WriteAfterByRefOrOutCall,
  55. /// <summary>
  56. /// Variable is not initialized.
  57. /// </summary>
  58. Uninitialized,
  59. /// <summary>
  60. /// Value is passed in as parameter
  61. /// </summary>
  62. Parameter,
  63. /// <summary>
  64. /// Value is a caught exception.
  65. /// TypeOperand is set to the exception type.
  66. /// </summary>
  67. Exception,
  68. /// <summary>
  69. /// Initialize a value type. Unlike the real initobj instruction, this one does not take an address
  70. /// but assigns to the target variable.
  71. /// TypeOperand is set to the type being created.
  72. /// </summary>
  73. InitObj
  74. }
  75. public sealed class SsaInstruction
  76. {
  77. public readonly SsaBlock ParentBlock;
  78. public readonly SpecialOpCode SpecialOpCode;
  79. /// <summary>
  80. /// The original IL instruction.
  81. /// May be null for "invented" instructions (SpecialOpCode != None).
  82. /// </summary>
  83. public readonly Instruction Instruction;
  84. /// <summary>
  85. /// Prefixes in front of the IL instruction.
  86. /// </summary>
  87. public readonly Instruction[] Prefixes;
  88. /// <summary>
  89. /// Gets the type operand. This is used only in combination with some special opcodes.
  90. /// </summary>
  91. public readonly TypeReference TypeOperand;
  92. public SsaVariable Target;
  93. public SsaVariable[] Operands;
  94. static readonly SsaVariable[] emptyVariableArray = {};
  95. static readonly Instruction[] emptyInstructionArray = {};
  96. public SsaInstruction(SsaBlock parentBlock, Instruction instruction, SsaVariable target, SsaVariable[] operands,
  97. Instruction[] prefixes = null, SpecialOpCode specialOpCode = SpecialOpCode.None,
  98. TypeReference typeOperand = null)
  99. {
  100. this.ParentBlock = parentBlock;
  101. this.Instruction = instruction;
  102. this.Prefixes = prefixes ?? emptyInstructionArray;
  103. this.Target = target;
  104. this.Operands = operands ?? emptyVariableArray;
  105. this.SpecialOpCode = specialOpCode;
  106. this.TypeOperand = typeOperand;
  107. Debug.Assert((typeOperand != null) == (specialOpCode == SpecialOpCode.Exception || specialOpCode == SpecialOpCode.InitObj));
  108. }
  109. /// <summary>
  110. /// Gets whether this instruction is a simple assignment from one variable to another.
  111. /// </summary>
  112. public bool IsMoveInstruction {
  113. get {
  114. return Target != null && Operands.Length == 1 && Instruction != null && OpCodeInfo.Get(Instruction.OpCode).IsMoveInstruction;
  115. }
  116. }
  117. public void ReplaceVariableInOperands(SsaVariable oldVar, SsaVariable newVar)
  118. {
  119. for (int i = 0; i < this.Operands.Length; i++) {
  120. if (this.Operands[i] == oldVar)
  121. this.Operands[i] = newVar;
  122. }
  123. }
  124. public override string ToString()
  125. {
  126. StringWriter w = new StringWriter();
  127. WriteTo(w);
  128. return w.ToString();
  129. }
  130. public void WriteTo(TextWriter writer)
  131. {
  132. foreach (Instruction prefix in this.Prefixes) {
  133. Disassembler.DisassemblerHelpers.WriteTo(prefix, new PlainTextOutput(writer));
  134. writer.WriteLine();
  135. }
  136. if (Instruction != null && Instruction.Offset >= 0) {
  137. writer.Write(CecilExtensions.OffsetToString(Instruction.Offset));
  138. writer.Write(": ");
  139. }
  140. if (Target != null) {
  141. writer.Write(Target.ToString());
  142. writer.Write(" = ");
  143. }
  144. if (IsMoveInstruction) {
  145. writer.Write(Operands[0].ToString());
  146. if (Instruction != null) {
  147. writer.Write(" (" + Instruction.OpCode.Name + ")");
  148. }
  149. } else {
  150. if (Instruction == null) {
  151. writer.Write(SpecialOpCode.ToString());
  152. } else {
  153. writer.Write(Instruction.OpCode.Name);
  154. if(null != Instruction.Operand) {
  155. writer.Write(' ');
  156. Disassembler.DisassemblerHelpers.WriteOperand(new PlainTextOutput(writer), Instruction.Operand);
  157. writer.Write(' ');
  158. }
  159. }
  160. if (TypeOperand != null) {
  161. writer.Write(' ');
  162. writer.Write(TypeOperand.ToString());
  163. writer.Write(' ');
  164. }
  165. if (Operands.Length > 0) {
  166. writer.Write('(');
  167. for (int i = 0; i < Operands.Length; i++) {
  168. if (i > 0)
  169. writer.Write(", ");
  170. writer.Write(Operands[i].ToString());
  171. }
  172. writer.Write(')');
  173. }
  174. }
  175. }
  176. }
  177. }