MethodBody.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. //
  2. // Author:
  3. // Jb Evain (jbevain@gmail.com)
  4. //
  5. // Copyright (c) 2008 - 2015 Jb Evain
  6. // Copyright (c) 2008 - 2011 Novell, Inc.
  7. //
  8. // Licensed under the MIT/X11 license.
  9. //
  10. using System;
  11. using System.Threading;
  12. using Mono.Collections.Generic;
  13. namespace Mono.Cecil.Cil {
  14. public sealed class MethodBody {
  15. readonly internal MethodDefinition method;
  16. internal ParameterDefinition this_parameter;
  17. internal int max_stack_size;
  18. internal int code_size;
  19. internal bool init_locals;
  20. internal MetadataToken local_var_token;
  21. internal Collection<Instruction> instructions;
  22. internal Collection<ExceptionHandler> exceptions;
  23. internal Collection<VariableDefinition> variables;
  24. public MethodDefinition Method {
  25. get { return method; }
  26. }
  27. public int MaxStackSize {
  28. get { return max_stack_size; }
  29. set { max_stack_size = value; }
  30. }
  31. public int CodeSize {
  32. get { return code_size; }
  33. }
  34. public bool InitLocals {
  35. get { return init_locals; }
  36. set { init_locals = value; }
  37. }
  38. public MetadataToken LocalVarToken {
  39. get { return local_var_token; }
  40. set { local_var_token = value; }
  41. }
  42. public Collection<Instruction> Instructions {
  43. get { return instructions ?? (instructions = new InstructionCollection (method)); }
  44. }
  45. public bool HasExceptionHandlers {
  46. get { return !exceptions.IsNullOrEmpty (); }
  47. }
  48. public Collection<ExceptionHandler> ExceptionHandlers {
  49. get { return exceptions ?? (exceptions = new Collection<ExceptionHandler> ()); }
  50. }
  51. public bool HasVariables {
  52. get { return !variables.IsNullOrEmpty (); }
  53. }
  54. public Collection<VariableDefinition> Variables {
  55. get { return variables ?? (variables = new VariableDefinitionCollection ()); }
  56. }
  57. public ParameterDefinition ThisParameter {
  58. get {
  59. if (method == null || method.DeclaringType == null)
  60. throw new NotSupportedException ();
  61. if (!method.HasThis)
  62. return null;
  63. if (this_parameter == null)
  64. Interlocked.CompareExchange (ref this_parameter, CreateThisParameter (method), null);
  65. return this_parameter;
  66. }
  67. }
  68. static ParameterDefinition CreateThisParameter (MethodDefinition method)
  69. {
  70. var parameter_type = method.DeclaringType as TypeReference;
  71. if (parameter_type.HasGenericParameters) {
  72. var instance = new GenericInstanceType (parameter_type);
  73. for (int i = 0; i < parameter_type.GenericParameters.Count; i++)
  74. instance.GenericArguments.Add (parameter_type.GenericParameters [i]);
  75. parameter_type = instance;
  76. }
  77. if (parameter_type.IsValueType || parameter_type.IsPrimitive)
  78. parameter_type = new ByReferenceType (parameter_type);
  79. return new ParameterDefinition (parameter_type, method);
  80. }
  81. public MethodBody (MethodDefinition method)
  82. {
  83. this.method = method;
  84. }
  85. public ILProcessor GetILProcessor ()
  86. {
  87. return new ILProcessor (this);
  88. }
  89. }
  90. sealed class VariableDefinitionCollection : Collection<VariableDefinition> {
  91. internal VariableDefinitionCollection ()
  92. {
  93. }
  94. internal VariableDefinitionCollection (int capacity)
  95. : base (capacity)
  96. {
  97. }
  98. protected override void OnAdd (VariableDefinition item, int index)
  99. {
  100. item.index = index;
  101. }
  102. protected override void OnInsert (VariableDefinition item, int index)
  103. {
  104. item.index = index;
  105. for (int i = index; i < size; i++)
  106. items [i].index = i + 1;
  107. }
  108. protected override void OnSet (VariableDefinition item, int index)
  109. {
  110. item.index = index;
  111. }
  112. protected override void OnRemove (VariableDefinition item, int index)
  113. {
  114. item.index = -1;
  115. for (int i = index + 1; i < size; i++)
  116. items [i].index = i - 1;
  117. }
  118. }
  119. class InstructionCollection : Collection<Instruction> {
  120. readonly MethodDefinition method;
  121. internal InstructionCollection (MethodDefinition method)
  122. {
  123. this.method = method;
  124. }
  125. internal InstructionCollection (MethodDefinition method, int capacity)
  126. : base (capacity)
  127. {
  128. this.method = method;
  129. }
  130. protected override void OnAdd (Instruction item, int index)
  131. {
  132. if (index == 0)
  133. return;
  134. var previous = items [index - 1];
  135. previous.next = item;
  136. item.previous = previous;
  137. }
  138. protected override void OnInsert (Instruction item, int index)
  139. {
  140. if (size == 0)
  141. return;
  142. var current = items [index];
  143. if (current == null) {
  144. var last = items [index - 1];
  145. last.next = item;
  146. item.previous = last;
  147. return;
  148. }
  149. var previous = current.previous;
  150. if (previous != null) {
  151. previous.next = item;
  152. item.previous = previous;
  153. }
  154. current.previous = item;
  155. item.next = current;
  156. }
  157. protected override void OnSet (Instruction item, int index)
  158. {
  159. var current = items [index];
  160. item.previous = current.previous;
  161. item.next = current.next;
  162. current.previous = null;
  163. current.next = null;
  164. }
  165. protected override void OnRemove (Instruction item, int index)
  166. {
  167. var previous = item.previous;
  168. if (previous != null)
  169. previous.next = item.next;
  170. var next = item.next;
  171. if (next != null)
  172. next.previous = item.previous;
  173. RemoveSequencePoint (item);
  174. item.previous = null;
  175. item.next = null;
  176. }
  177. void RemoveSequencePoint (Instruction instruction)
  178. {
  179. var debug_info = method.debug_info;
  180. if (debug_info == null || !debug_info.HasSequencePoints)
  181. return;
  182. var sequence_points = debug_info.sequence_points;
  183. for (int i = 0; i < sequence_points.Count; i++) {
  184. if (sequence_points [i].Offset == instruction.offset) {
  185. sequence_points.RemoveAt (i);
  186. return;
  187. }
  188. }
  189. }
  190. }
  191. }