1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Diagnostics; 7 using System.Runtime.CompilerServices; 8 using Internal.NativeFormat; 9 10 namespace Internal.TypeSystem 11 { 12 [Flags] 13 public enum MethodSignatureFlags 14 { 15 None = 0x0000, 16 // TODO: Generic, etc. 17 18 UnmanagedCallingConventionMask = 0x000F, 19 UnmanagedCallingConventionCdecl = 0x0001, 20 UnmanagedCallingConventionStdCall = 0x0002, 21 UnmanagedCallingConventionThisCall = 0x0003, 22 CallingConventionVarargs = 0x0005, 23 24 Static = 0x0010, 25 } 26 27 /// <summary> 28 /// Represents the parameter types, the return type, and flags of a method. 29 /// </summary> 30 public sealed partial class MethodSignature : TypeSystemEntity 31 { 32 internal MethodSignatureFlags _flags; 33 internal int _genericParameterCount; 34 internal TypeDesc _returnType; 35 internal TypeDesc[] _parameters; 36 MethodSignature(MethodSignatureFlags flags, int genericParameterCount, TypeDesc returnType, TypeDesc[] parameters)37 public MethodSignature(MethodSignatureFlags flags, int genericParameterCount, TypeDesc returnType, TypeDesc[] parameters) 38 { 39 _flags = flags; 40 _genericParameterCount = genericParameterCount; 41 _returnType = returnType; 42 _parameters = parameters; 43 44 Debug.Assert(parameters != null, "Parameters must not be null"); 45 } 46 47 public MethodSignatureFlags Flags 48 { 49 get 50 { 51 return _flags; 52 } 53 } 54 55 public bool IsStatic 56 { 57 get 58 { 59 return (_flags & MethodSignatureFlags.Static) != 0; 60 } 61 } 62 63 public int GenericParameterCount 64 { 65 get 66 { 67 return _genericParameterCount; 68 } 69 } 70 71 public TypeDesc ReturnType 72 { 73 get 74 { 75 return _returnType; 76 } 77 } 78 79 /// <summary> 80 /// Gets the parameter type at the specified index. 81 /// </summary> 82 [IndexerName("Parameter")] 83 public TypeDesc this[int index] 84 { 85 get 86 { 87 return _parameters[index]; 88 } 89 } 90 91 /// <summary> 92 /// Gets the number of parameters of this method signature. 93 /// </summary> 94 public int Length 95 { 96 get 97 { 98 return _parameters.Length; 99 } 100 } 101 Equals(MethodSignature otherSignature)102 public bool Equals(MethodSignature otherSignature) 103 { 104 // TODO: Generics, etc. 105 if (this._flags != otherSignature._flags) 106 return false; 107 108 if (this._genericParameterCount != otherSignature._genericParameterCount) 109 return false; 110 111 if (this._returnType != otherSignature._returnType) 112 return false; 113 114 if (this._parameters.Length != otherSignature._parameters.Length) 115 return false; 116 117 for (int i = 0; i < this._parameters.Length; i++) 118 { 119 if (this._parameters[i] != otherSignature._parameters[i]) 120 return false; 121 } 122 123 return true; 124 } 125 Equals(object obj)126 public override bool Equals(object obj) 127 { 128 return obj is MethodSignature && Equals((MethodSignature)obj); 129 } 130 GetHashCode()131 public override int GetHashCode() 132 { 133 return TypeHashingAlgorithms.ComputeMethodSignatureHashCode(_returnType.GetHashCode(), _parameters); 134 } 135 136 public override TypeSystemContext Context => _returnType.Context; 137 } 138 139 /// <summary> 140 /// Helper structure for building method signatures by cloning an existing method signature. 141 /// </summary> 142 /// <remarks> 143 /// This can potentially avoid array allocation costs for allocating the parameter type list. 144 /// </remarks> 145 public struct MethodSignatureBuilder 146 { 147 private MethodSignature _template; 148 private MethodSignatureFlags _flags; 149 private int _genericParameterCount; 150 private TypeDesc _returnType; 151 private TypeDesc[] _parameters; 152 MethodSignatureBuilderInternal.TypeSystem.MethodSignatureBuilder153 public MethodSignatureBuilder(MethodSignature template) 154 { 155 _template = template; 156 157 _flags = template._flags; 158 _genericParameterCount = template._genericParameterCount; 159 _returnType = template._returnType; 160 _parameters = template._parameters; 161 } 162 163 public MethodSignatureFlags Flags 164 { 165 set 166 { 167 _flags = value; 168 } 169 } 170 171 public TypeDesc ReturnType 172 { 173 set 174 { 175 _returnType = value; 176 } 177 } 178 179 [System.Runtime.CompilerServices.IndexerName("Parameter")] 180 public TypeDesc this[int index] 181 { 182 set 183 { 184 if (_parameters[index] == value) 185 return; 186 187 if (_template != null && _parameters == _template._parameters) 188 { 189 TypeDesc[] parameters = new TypeDesc[_parameters.Length]; 190 for (int i = 0; i < parameters.Length; i++) 191 parameters[i] = _parameters[i]; 192 _parameters = parameters; 193 } 194 _parameters[index] = value; 195 } 196 } 197 198 public int Length 199 { 200 set 201 { 202 _parameters = new TypeDesc[value]; 203 _template = null; 204 } 205 } 206 ToSignatureInternal.TypeSystem.MethodSignatureBuilder207 public MethodSignature ToSignature() 208 { 209 if (_template == null || 210 _flags != _template._flags || 211 _genericParameterCount != _template._genericParameterCount || 212 _returnType != _template._returnType || 213 _parameters != _template._parameters) 214 { 215 _template = new MethodSignature(_flags, _genericParameterCount, _returnType, _parameters); 216 } 217 218 return _template; 219 } 220 } 221 222 /// <summary> 223 /// Represents the fundamental base type for all methods within the type system. 224 /// </summary> 225 public abstract partial class MethodDesc : TypeSystemEntity 226 { 227 public static readonly MethodDesc[] EmptyMethods = new MethodDesc[0]; 228 229 private int _hashcode; 230 231 /// <summary> 232 /// Allows a performance optimization that skips the potentially expensive 233 /// construction of a hash code if a hash code has already been computed elsewhere. 234 /// Use to allow objects to have their hashcode computed 235 /// independently of the allocation of a MethodDesc object 236 /// For instance, compute the hashcode when looking up the object, 237 /// then when creating the object, pass in the hashcode directly. 238 /// The hashcode specified MUST exactly match the algorithm implemented 239 /// on this type normally. 240 /// </summary> SetHashCode(int hashcode)241 protected void SetHashCode(int hashcode) 242 { 243 _hashcode = hashcode; 244 Debug.Assert(hashcode == ComputeHashCode()); 245 } 246 GetHashCode()247 public sealed override int GetHashCode() 248 { 249 if (_hashcode != 0) 250 return _hashcode; 251 252 return AcquireHashCode(); 253 } 254 AcquireHashCode()255 private int AcquireHashCode() 256 { 257 _hashcode = ComputeHashCode(); 258 return _hashcode; 259 } 260 261 /// <summary> 262 /// Compute HashCode. Should only be overriden by a MethodDesc that represents an instantiated method. 263 /// </summary> ComputeHashCode()264 protected virtual int ComputeHashCode() 265 { 266 return TypeHashingAlgorithms.ComputeMethodHashCode(OwningType.GetHashCode(), TypeHashingAlgorithms.ComputeNameHashCode(Name)); 267 } 268 Equals(Object o)269 public override bool Equals(Object o) 270 { 271 // Its only valid to compare two MethodDescs in the same context 272 Debug.Assert(Object.ReferenceEquals(o, null) || !(o is MethodDesc) || Object.ReferenceEquals(((MethodDesc)o).Context, this.Context)); 273 return Object.ReferenceEquals(this, o); 274 } 275 276 /// <summary> 277 /// Gets the type that owns this method. This will be a <see cref="DefType"/> or 278 /// an <see cref="ArrayType"/>. 279 /// </summary> 280 public abstract TypeDesc OwningType 281 { 282 get; 283 } 284 285 /// <summary> 286 /// Gets the signature of the method. 287 /// </summary> 288 public abstract MethodSignature Signature 289 { 290 get; 291 } 292 293 /// <summary> 294 /// Gets the generic instantiation information of this method. 295 /// For generic definitions, retrieves the generic parameters of the method. 296 /// For generic instantiation, retrieves the generic arguments of the method. 297 /// </summary> 298 public virtual Instantiation Instantiation 299 { 300 get 301 { 302 return Instantiation.Empty; 303 } 304 } 305 306 /// <summary> 307 /// Gets a value indicating whether this method has a generic instantiation. 308 /// This will be true for generic method instantiations and generic definitions. 309 /// </summary> 310 public bool HasInstantiation 311 { 312 get 313 { 314 return this.Instantiation.Length != 0; 315 } 316 } 317 318 /// <summary> 319 /// Gets a value indicating whether this method is an instance constructor. 320 /// </summary> 321 public bool IsConstructor 322 { 323 get 324 { 325 // TODO: Precise check 326 // TODO: Cache? 327 return this.Name == ".ctor"; 328 } 329 } 330 331 /// <summary> 332 /// Gets a value indicating whether this is a public parameterless instance constructor 333 /// on a non-abstract type. 334 /// </summary> 335 public virtual bool IsDefaultConstructor 336 { 337 get 338 { 339 return OwningType.GetDefaultConstructor() == this; 340 } 341 } 342 343 /// <summary> 344 /// Gets a value indicating whether this method is a static constructor. 345 /// </summary> 346 public bool IsStaticConstructor 347 { 348 get 349 { 350 return this == this.OwningType.GetStaticConstructor(); 351 } 352 } 353 354 /// <summary> 355 /// Gets the name of the method as specified in the metadata. 356 /// </summary> 357 public virtual string Name 358 { 359 get 360 { 361 return null; 362 } 363 } 364 365 /// <summary> 366 /// Gets a value indicating whether the method is virtual. 367 /// </summary> 368 public virtual bool IsVirtual 369 { 370 get 371 { 372 return false; 373 } 374 } 375 376 /// <summary> 377 /// Gets a value indicating whether this virtual method should not override any 378 /// virtual methods defined in any of the base classes. 379 /// </summary> 380 public virtual bool IsNewSlot 381 { 382 get 383 { 384 return false; 385 } 386 } 387 388 /// <summary> 389 /// Gets a value indicating whether this virtual method needs to be overriden 390 /// by all non-abstract classes deriving from the method's owning type. 391 /// </summary> 392 public virtual bool IsAbstract 393 { 394 get 395 { 396 return false; 397 } 398 } 399 400 /// <summary> 401 /// Gets a value indicating that this method cannot be overriden. 402 /// </summary> 403 public virtual bool IsFinal 404 { 405 get 406 { 407 return false; 408 } 409 } 410 HasCustomAttribute(string attributeNamespace, string attributeName)411 public abstract bool HasCustomAttribute(string attributeNamespace, string attributeName); 412 413 /// <summary> 414 /// Retrieves the uninstantiated form of the method on the method's <see cref="OwningType"/>. 415 /// For generic methods, this strips method instantiation. For non-generic methods, returns 'this'. 416 /// To also strip instantiation of the owning type, use <see cref="GetTypicalMethodDefinition"/>. 417 /// </summary> GetMethodDefinition()418 public virtual MethodDesc GetMethodDefinition() 419 { 420 return this; 421 } 422 423 /// <summary> 424 /// Gets a value indicating whether this is a method definition. This property 425 /// is true for non-generic methods and for uninstantiated generic methods. 426 /// </summary> 427 public bool IsMethodDefinition 428 { 429 get 430 { 431 return GetMethodDefinition() == this; 432 } 433 } 434 435 /// <summary> 436 /// Retrieves the generic definition of the method on the generic definition of the owning type. 437 /// To only uninstantiate the method without uninstantiating the owning type, use <see cref="GetMethodDefinition"/>. 438 /// </summary> GetTypicalMethodDefinition()439 public virtual MethodDesc GetTypicalMethodDefinition() 440 { 441 return this; 442 } 443 444 /// <summary> 445 /// Gets a value indicating whether this is a typical definition. This property is true 446 /// if neither the owning type, nor the method are instantiated. 447 /// </summary> 448 public bool IsTypicalMethodDefinition 449 { 450 get 451 { 452 return GetTypicalMethodDefinition() == this; 453 } 454 } 455 456 /// <summary> 457 /// Gets a value indicating whether this is an uninstantiated generic method. 458 /// </summary> 459 public bool IsGenericMethodDefinition 460 { 461 get 462 { 463 return HasInstantiation && IsMethodDefinition; 464 } 465 } 466 467 public bool IsFinalizer 468 { 469 get 470 { 471 TypeDesc owningType = OwningType; 472 return (owningType.IsObject && Name == "Finalize") || (owningType.HasFinalizer && owningType.GetFinalizer() == this); 473 } 474 } 475 InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation)476 public virtual MethodDesc InstantiateSignature(Instantiation typeInstantiation, Instantiation methodInstantiation) 477 { 478 Instantiation instantiation = Instantiation; 479 TypeDesc[] clone = null; 480 481 for (int i = 0; i < instantiation.Length; i++) 482 { 483 TypeDesc uninst = instantiation[i]; 484 TypeDesc inst = uninst.InstantiateSignature(typeInstantiation, methodInstantiation); 485 if (inst != uninst) 486 { 487 if (clone == null) 488 { 489 clone = new TypeDesc[instantiation.Length]; 490 for (int j = 0; j < clone.Length; j++) 491 { 492 clone[j] = instantiation[j]; 493 } 494 } 495 clone[i] = inst; 496 } 497 } 498 499 MethodDesc method = this; 500 501 TypeDesc owningType = method.OwningType; 502 TypeDesc instantiatedOwningType = owningType.InstantiateSignature(typeInstantiation, methodInstantiation); 503 if (owningType != instantiatedOwningType) 504 { 505 method = Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), (InstantiatedType)instantiatedOwningType); 506 if (clone == null && instantiation.Length != 0) 507 return Context.GetInstantiatedMethod(method, instantiation); 508 } 509 510 return (clone == null) ? method : Context.GetInstantiatedMethod(method.GetMethodDefinition(), new Instantiation(clone)); 511 } 512 } 513 } 514