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