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 
6 using System;
7 using System.Diagnostics;
8 using System.Runtime.CompilerServices;
9 using System.Reflection;
10 using System.Runtime;
11 using System.Threading;
12 using Internal.Metadata.NativeFormat;
13 using Internal.Runtime.CompilerServices;
14 
15 using Internal.TypeSystem;
16 
17 namespace Internal.TypeSystem.NativeFormat
18 {
19     public sealed class NativeFormatMethod : MethodDesc, NativeFormatMetadataUnit.IHandleObject
20     {
21         private static class MethodFlags
22         {
23             public const int BasicMetadataCache = 0x0001;
24             public const int Virtual = 0x0002;
25             public const int NewSlot = 0x0004;
26             public const int Abstract = 0x0008;
27             public const int Final = 0x0010;
28             public const int NoInlining = 0x0020;
29             public const int AggressiveInlining = 0x0040;
30             public const int RuntimeImplemented = 0x0080;
31             public const int InternalCall = 0x0100;
32             public const int Synchronized = 0x0200;
33 
34             public const int AttributeMetadataCache = 0x1000;
35             public const int Intrinsic = 0x2000;
36             public const int NativeCallable = 0x4000;
37             public const int RuntimeExport = 0x8000;
38         };
39 
40         private NativeFormatType _type;
41         private MethodHandle _handle;
42 
43         // Cached values
44         private ThreadSafeFlags _methodFlags;
45         private MethodSignature _signature;
46         private string _name;
47         private TypeDesc[] _genericParameters; // TODO: Optional field?
48 
NativeFormatMethod(NativeFormatType type, MethodHandle handle)49         internal NativeFormatMethod(NativeFormatType type, MethodHandle handle)
50         {
51             _type = type;
52             _handle = handle;
53 
54 #if DEBUG
55             // Initialize name eagerly in debug builds for convenience
56             InitializeName();
57 #endif
58         }
59 
60         Handle NativeFormatMetadataUnit.IHandleObject.Handle
61         {
62             get
63             {
64                 return _handle;
65             }
66         }
67 
68         NativeFormatType NativeFormatMetadataUnit.IHandleObject.Container
69         {
70             get
71             {
72                 return _type;
73             }
74         }
75 
76         public override TypeSystemContext Context
77         {
78             get
79             {
80                 return _type.Module.Context;
81             }
82         }
83 
84         public override TypeDesc OwningType
85         {
86             get
87             {
88                 return _type;
89             }
90         }
91 
InitializeSignature()92         private MethodSignature InitializeSignature()
93         {
94             var metadataReader = MetadataReader;
95 
96             NativeFormatSignatureParser parser = new NativeFormatSignatureParser(MetadataUnit, MetadataReader.GetMethod(_handle).Signature, metadataReader);
97             var signature = parser.ParseMethodSignature();
98             return (_signature = signature);
99         }
100 
101         public override MethodSignature Signature
102         {
103             get
104             {
105                 if (_signature == null)
106                     return InitializeSignature();
107                 return _signature;
108             }
109         }
110 
111         public NativeFormatModule NativeFormatModule
112         {
113             get
114             {
115                 return _type.NativeFormatModule;
116             }
117         }
118 
119         public MetadataReader MetadataReader
120         {
121             get
122             {
123                 return _type.MetadataReader;
124             }
125         }
126 
127         public NativeFormatMetadataUnit MetadataUnit
128         {
129             get
130             {
131                 return _type.MetadataUnit;
132             }
133         }
134 
135         public MethodHandle Handle
136         {
137             get
138             {
139                 return _handle;
140             }
141         }
142 
143         [MethodImpl(MethodImplOptions.NoInlining)]
InitializeMethodFlags(int mask)144         private int InitializeMethodFlags(int mask)
145         {
146             int flags = 0;
147 
148             if ((mask & MethodFlags.BasicMetadataCache) != 0)
149             {
150                 var methodAttributes = Attributes;
151                 var methodImplAttributes = ImplAttributes;
152 
153                 if ((methodAttributes & MethodAttributes.Virtual) != 0)
154                     flags |= MethodFlags.Virtual;
155 
156                 if ((methodAttributes & MethodAttributes.NewSlot) != 0)
157                     flags |= MethodFlags.NewSlot;
158 
159                 if ((methodAttributes & MethodAttributes.Abstract) != 0)
160                     flags |= MethodFlags.Abstract;
161 
162                 if ((methodAttributes & MethodAttributes.Final) != 0)
163                     flags |= MethodFlags.Final;
164 
165                 if ((methodImplAttributes & MethodImplAttributes.NoInlining) != 0)
166                     flags |= MethodFlags.NoInlining;
167 
168                 if ((methodImplAttributes & MethodImplAttributes.AggressiveInlining) != 0)
169                     flags |= MethodFlags.AggressiveInlining;
170 
171                 if ((methodImplAttributes & MethodImplAttributes.Runtime) != 0)
172                     flags |= MethodFlags.RuntimeImplemented;
173 
174                 if ((methodImplAttributes & MethodImplAttributes.InternalCall) != 0)
175                     flags |= MethodFlags.InternalCall;
176 
177                 if ((methodImplAttributes & MethodImplAttributes.Synchronized) != 0)
178                     flags |= MethodFlags.Synchronized;
179 
180                 flags |= MethodFlags.BasicMetadataCache;
181             }
182 
183             // Fetching custom attribute based properties is more expensive, so keep that under
184             // a separate cache that might not be accessed very frequently.
185             if ((mask & MethodFlags.AttributeMetadataCache) != 0)
186             {
187                 var metadataReader = this.MetadataReader;
188                 var methodDefinition = MetadataReader.GetMethod(_handle);
189 
190                 foreach (var attributeHandle in methodDefinition.CustomAttributes)
191                 {
192                     ConstantStringValueHandle nameHandle;
193                     string namespaceName;
194 
195                     if (!metadataReader.GetAttributeNamespaceAndName(attributeHandle, out namespaceName, out nameHandle))
196                         continue;
197 
198                     if (namespaceName.Equals("System.Runtime.CompilerServices"))
199                     {
200                         if (nameHandle.StringEquals("IntrinsicAttribute", metadataReader))
201                         {
202                             flags |= MethodFlags.Intrinsic;
203                         }
204                     }
205                     else
206                     if (namespaceName.Equals("System.Runtime.InteropServices"))
207                     {
208                         if (nameHandle.StringEquals("NativeCallableAttribute", metadataReader))
209                         {
210                             flags |= MethodFlags.NativeCallable;
211                         }
212                     }
213                     else
214                     if (namespaceName.Equals("System.Runtime"))
215                     {
216                         if (nameHandle.StringEquals("RuntimeExportAttribute", metadataReader))
217                         {
218                             flags |= MethodFlags.RuntimeExport;
219                         }
220                     }
221                 }
222 
223                 flags |= MethodFlags.AttributeMetadataCache;
224             }
225 
226             Debug.Assert((flags & mask) != 0);
227             _methodFlags.AddFlags(flags);
228 
229             return flags & mask;
230         }
231 
232         [MethodImpl(MethodImplOptions.AggressiveInlining)]
GetMethodFlags(int mask)233         private int GetMethodFlags(int mask)
234         {
235             int flags = _methodFlags.Value & mask;
236             if (flags != 0)
237                 return flags;
238             return InitializeMethodFlags(mask);
239         }
240 
241         public override bool IsVirtual
242         {
243             get
244             {
245                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Virtual) & MethodFlags.Virtual) != 0;
246             }
247         }
248 
249         public override bool IsNewSlot
250         {
251             get
252             {
253                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NewSlot) & MethodFlags.NewSlot) != 0;
254             }
255         }
256 
257         public override bool IsAbstract
258         {
259             get
260             {
261                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Abstract) & MethodFlags.Abstract) != 0;
262             }
263         }
264 
265         public override bool IsFinal
266         {
267             get
268             {
269                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Final) & MethodFlags.Final) != 0;
270             }
271         }
272 
273         public override bool IsNoInlining
274         {
275             get
276             {
277                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.NoInlining) & MethodFlags.NoInlining) != 0;
278             }
279         }
280 
281         public override bool IsAggressiveInlining
282         {
283             get
284             {
285                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.AggressiveInlining) & MethodFlags.AggressiveInlining) != 0;
286             }
287         }
288 
289         public override bool IsRuntimeImplemented
290         {
291             get
292             {
293                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.RuntimeImplemented) & MethodFlags.RuntimeImplemented) != 0;
294             }
295         }
296 
297         public override bool IsIntrinsic
298         {
299             get
300             {
301                 return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.Intrinsic) & MethodFlags.Intrinsic) != 0;
302             }
303         }
304 
305         public override bool IsInternalCall
306         {
307             get
308             {
309                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.InternalCall) & MethodFlags.InternalCall) != 0;
310             }
311         }
312 
313         public override bool IsSynchronized
314         {
315             get
316             {
317                 return (GetMethodFlags(MethodFlags.BasicMetadataCache | MethodFlags.Synchronized) & MethodFlags.Synchronized) != 0;
318             }
319         }
320 
321         public override bool IsNativeCallable
322         {
323             get
324             {
325                 return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.NativeCallable) & MethodFlags.NativeCallable) != 0;
326             }
327         }
328 
329         public override bool IsRuntimeExport
330         {
331             get
332             {
333                 return (GetMethodFlags(MethodFlags.AttributeMetadataCache | MethodFlags.RuntimeExport) & MethodFlags.RuntimeExport) != 0;
334             }
335         }
336 
337         public override bool IsDefaultConstructor
338         {
339             get
340             {
341                 MethodAttributes attributes = Attributes;
342                 return attributes.IsRuntimeSpecialName()
343                     && attributes.IsPublic()
344                     && Signature.Length == 0
345                     && Name == ".ctor"
346                     && !_type.IsAbstract;
347             }
348         }
349 
350         public MethodAttributes Attributes
351         {
352             get
353             {
354                 return MetadataReader.GetMethod(_handle).Flags;
355             }
356         }
357 
358         public MethodImplAttributes ImplAttributes
359         {
360             get
361             {
362                 return MetadataReader.GetMethod(_handle).ImplFlags;
363             }
364         }
365 
InitializeName()366         private string InitializeName()
367         {
368             var metadataReader = MetadataReader;
369             var name = metadataReader.GetString(MetadataReader.GetMethod(_handle).Name);
370             return (_name = name);
371         }
372 
373         public override string Name
374         {
375             get
376             {
377                 if (_name == null)
378                     return InitializeName();
379                 return _name;
380             }
381         }
382 
ComputeGenericParameters()383         private void ComputeGenericParameters()
384         {
385             var genericParameterHandles = MetadataReader.GetMethod(_handle).GenericParameters;
386             int count = genericParameterHandles.Count;
387             if (count > 0)
388             {
389                 TypeDesc[] genericParameters = new TypeDesc[count];
390                 int i = 0;
391                 foreach (var genericParameterHandle in genericParameterHandles)
392                 {
393                     genericParameters[i++] = new NativeFormatGenericParameter(MetadataUnit, genericParameterHandle);
394                 }
395                 Interlocked.CompareExchange(ref _genericParameters, genericParameters, null);
396             }
397             else
398             {
399                 _genericParameters = TypeDesc.EmptyTypes;
400             }
401         }
402 
403         public override Instantiation Instantiation
404         {
405             get
406             {
407                 if (_genericParameters == null)
408                     ComputeGenericParameters();
409                 return new Instantiation(_genericParameters);
410             }
411         }
412 
HasCustomAttribute(string attributeNamespace, string attributeName)413         public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
414         {
415             return MetadataReader.HasCustomAttribute(MetadataReader.GetMethod(_handle).CustomAttributes,
416                 attributeNamespace, attributeName);
417         }
418 
419         public override MethodNameAndSignature NameAndSignature
420         {
421             get
422             {
423                 int handleAsToken = _handle.ToInt();
424 
425                 TypeManagerHandle moduleHandle = Internal.Runtime.TypeLoader.ModuleList.Instance.GetModuleForMetadataReader(MetadataReader);
426                 return new MethodNameAndSignature(Name, RuntimeSignature.CreateFromMethodHandle(moduleHandle, handleAsToken));
427             }
428         }
429     }
430 }
431