/Mono.Cecil.Cil/MethodBody.cs
C# | 263 lines | 194 code | 60 blank | 9 comment | 37 complexity | 14cc1463a84ed50cbd0de20590085069 MD5 | raw file
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 11using System; 12using System.Threading; 13 14using Mono.Collections.Generic; 15 16namespace Mono.Cecil.Cil { 17 18 public sealed class MethodBody { 19 20 readonly internal MethodDefinition method; 21 22 internal ParameterDefinition this_parameter; 23 internal int max_stack_size; 24 internal int code_size; 25 internal bool init_locals; 26 internal MetadataToken local_var_token; 27 28 internal Collection<Instruction> instructions; 29 internal Collection<ExceptionHandler> exceptions; 30 internal Collection<VariableDefinition> variables; 31 32 public MethodDefinition Method { 33 get { return method; } 34 } 35 36 public int MaxStackSize { 37 get { return max_stack_size; } 38 set { max_stack_size = value; } 39 } 40 41 public int CodeSize { 42 get { return code_size; } 43 } 44 45 public bool InitLocals { 46 get { return init_locals; } 47 set { init_locals = value; } 48 } 49 50 public MetadataToken LocalVarToken { 51 get { return local_var_token; } 52 set { local_var_token = value; } 53 } 54 55 public Collection<Instruction> Instructions { 56 get { 57 if (instructions == null) 58 Interlocked.CompareExchange (ref instructions, new InstructionCollection (method), null); 59 60 return instructions; 61 } 62 } 63 64 public bool HasExceptionHandlers { 65 get { return !exceptions.IsNullOrEmpty (); } 66 } 67 68 public Collection<ExceptionHandler> ExceptionHandlers { 69 get { 70 if (exceptions == null) 71 Interlocked.CompareExchange (ref exceptions, new Collection<ExceptionHandler> (), null); 72 73 return exceptions; 74 } 75 } 76 77 public bool HasVariables { 78 get { return !variables.IsNullOrEmpty (); } 79 } 80 81 public Collection<VariableDefinition> Variables { 82 get { 83 if (variables == null) 84 Interlocked.CompareExchange (ref variables, new VariableDefinitionCollection (), null); 85 86 return variables; 87 } 88 } 89 90 public ParameterDefinition ThisParameter { 91 get { 92 if (method == null || method.DeclaringType == null) 93 throw new NotSupportedException (); 94 95 if (!method.HasThis) 96 return null; 97 98 if (this_parameter == null) 99 Interlocked.CompareExchange (ref this_parameter, CreateThisParameter (method), null); 100 101 return this_parameter; 102 } 103 } 104 105 static ParameterDefinition CreateThisParameter (MethodDefinition method) 106 { 107 var parameter_type = method.DeclaringType as TypeReference; 108 109 if (parameter_type.HasGenericParameters) { 110 var instance = new GenericInstanceType (parameter_type, parameter_type.GenericParameters.Count); 111 for (int i = 0; i < parameter_type.GenericParameters.Count; i++) 112 instance.GenericArguments.Add (parameter_type.GenericParameters [i]); 113 114 parameter_type = instance; 115 116 } 117 118 if (parameter_type.IsValueType || parameter_type.IsPrimitive) 119 parameter_type = new ByReferenceType (parameter_type); 120 121 return new ParameterDefinition (parameter_type, method); 122 } 123 124 public MethodBody (MethodDefinition method) 125 { 126 this.method = method; 127 } 128 129 public ILProcessor GetILProcessor () 130 { 131 return new ILProcessor (this); 132 } 133 } 134 135 sealed class VariableDefinitionCollection : Collection<VariableDefinition> { 136 137 internal VariableDefinitionCollection () 138 { 139 } 140 141 internal VariableDefinitionCollection (int capacity) 142 : base (capacity) 143 { 144 } 145 146 protected override void OnAdd (VariableDefinition item, int index) 147 { 148 item.index = index; 149 } 150 151 protected override void OnInsert (VariableDefinition item, int index) 152 { 153 item.index = index; 154 155 for (int i = index; i < size; i++) 156 items [i].index = i + 1; 157 } 158 159 protected override void OnSet (VariableDefinition item, int index) 160 { 161 item.index = index; 162 } 163 164 protected override void OnRemove (VariableDefinition item, int index) 165 { 166 item.index = -1; 167 168 for (int i = index + 1; i < size; i++) 169 items [i].index = i - 1; 170 } 171 } 172 173 class InstructionCollection : Collection<Instruction> { 174 175 readonly MethodDefinition method; 176 177 internal InstructionCollection (MethodDefinition method) 178 { 179 this.method = method; 180 } 181 182 internal InstructionCollection (MethodDefinition method, int capacity) 183 : base (capacity) 184 { 185 this.method = method; 186 } 187 188 protected override void OnAdd (Instruction item, int index) 189 { 190 if (index == 0) 191 return; 192 193 var previous = items [index - 1]; 194 previous.next = item; 195 item.previous = previous; 196 } 197 198 protected override void OnInsert (Instruction item, int index) 199 { 200 if (size == 0) 201 return; 202 203 var current = items [index]; 204 if (current == null) { 205 var last = items [index - 1]; 206 last.next = item; 207 item.previous = last; 208 return; 209 } 210 211 var previous = current.previous; 212 if (previous != null) { 213 previous.next = item; 214 item.previous = previous; 215 } 216 217 current.previous = item; 218 item.next = current; 219 } 220 221 protected override void OnSet (Instruction item, int index) 222 { 223 var current = items [index]; 224 225 item.previous = current.previous; 226 item.next = current.next; 227 228 current.previous = null; 229 current.next = null; 230 } 231 232 protected override void OnRemove (Instruction item, int index) 233 { 234 var previous = item.previous; 235 if (previous != null) 236 previous.next = item.next; 237 238 var next = item.next; 239 if (next != null) 240 next.previous = item.previous; 241 242 RemoveSequencePoint (item); 243 244 item.previous = null; 245 item.next = null; 246 } 247 248 void RemoveSequencePoint (Instruction instruction) 249 { 250 var debug_info = method.debug_info; 251 if (debug_info == null || !debug_info.HasSequencePoints) 252 return; 253 254 var sequence_points = debug_info.sequence_points; 255 for (int i = 0; i < sequence_points.Count; i++) { 256 if (sequence_points [i].Offset == instruction.offset) { 257 sequence_points.RemoveAt (i); 258 return; 259 } 260 } 261 } 262 } 263}