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