| 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 | #ifndef _BINDERMODULE_H_ |
| 7 | #define _BINDERMODULE_H_ |
| 8 | |
| 9 | class DataImage; |
| 10 | class Module; |
| 11 | class MethodTable; |
| 12 | class MethodDesc; |
| 13 | class FieldDesc; |
| 14 | |
| 15 | typedef const struct HardCodedMetaSig *LPHARDCODEDMETASIG; |
| 16 | |
| 17 | // As hard-coded metasigs are constant data ordinarily it |
| 18 | // wouldn't be necessary to use PTR access. However, access |
| 19 | // through the Binder class requires it. |
| 20 | typedef DPTR(const struct HardCodedMetaSig) PTR_HARDCODEDMETASIG; |
| 21 | |
| 22 | struct HardCodedMetaSig |
| 23 | { |
| 24 | const BYTE* m_pMetaSig; // metasig prefixed with INT8 length: |
| 25 | // length > 0 - resolved, lenght < 0 - has unresolved type references |
| 26 | }; |
| 27 | |
| 28 | #define DEFINE_METASIG(body) extern const body |
| 29 | #define DEFINE_METASIG_T(body) extern body |
| 30 | #define METASIG_BODY(varname, types) HardCodedMetaSig gsig_ ## varname; |
| 31 | #include "metasig.h" |
| 32 | |
| 33 | // |
| 34 | // Use the Binder objects to avoid doing unnecessary name lookup |
| 35 | // (esp. in the prejit case) |
| 36 | // |
| 37 | // E.g. MscorlibBinder::GetClass(CLASS__APP_DOMAIN); |
| 38 | // |
| 39 | |
| 40 | // BinderClassIDs are of the form CLASS__XXX |
| 41 | |
| 42 | enum BinderClassID |
| 43 | { |
| 44 | #define TYPEINFO(e,ns,c,s,g,ia,ip,if,im,gv) CLASS__ ## e, |
| 45 | #include "cortypeinfo.h" |
| 46 | #undef TYPEINFO |
| 47 | |
| 48 | #define DEFINE_CLASS(i,n,s) CLASS__ ## i, |
| 49 | #include "mscorlib.h" |
| 50 | |
| 51 | CLASS__MSCORLIB_COUNT, |
| 52 | |
| 53 | // Aliases for element type classids |
| 54 | CLASS__NIL = CLASS__ELEMENT_TYPE_END, |
| 55 | CLASS__VOID = CLASS__ELEMENT_TYPE_VOID, |
| 56 | CLASS__BOOLEAN = CLASS__ELEMENT_TYPE_BOOLEAN, |
| 57 | CLASS__CHAR = CLASS__ELEMENT_TYPE_CHAR, |
| 58 | CLASS__BYTE = CLASS__ELEMENT_TYPE_U1, |
| 59 | CLASS__SBYTE = CLASS__ELEMENT_TYPE_I1, |
| 60 | CLASS__INT16 = CLASS__ELEMENT_TYPE_I2, |
| 61 | CLASS__UINT16 = CLASS__ELEMENT_TYPE_U2, |
| 62 | CLASS__INT32 = CLASS__ELEMENT_TYPE_I4, |
| 63 | CLASS__UINT32 = CLASS__ELEMENT_TYPE_U4, |
| 64 | CLASS__INT64 = CLASS__ELEMENT_TYPE_I8, |
| 65 | CLASS__UINT64 = CLASS__ELEMENT_TYPE_U8, |
| 66 | CLASS__SINGLE = CLASS__ELEMENT_TYPE_R4, |
| 67 | CLASS__DOUBLE = CLASS__ELEMENT_TYPE_R8, |
| 68 | CLASS__STRING = CLASS__ELEMENT_TYPE_STRING, |
| 69 | CLASS__TYPED_REFERENCE = CLASS__ELEMENT_TYPE_TYPEDBYREF, |
| 70 | CLASS__INTPTR = CLASS__ELEMENT_TYPE_I, |
| 71 | CLASS__UINTPTR = CLASS__ELEMENT_TYPE_U, |
| 72 | CLASS__OBJECT = CLASS__ELEMENT_TYPE_OBJECT |
| 73 | }; |
| 74 | |
| 75 | |
| 76 | // BinderMethodIDs are of the form METHOD__XXX__YYY, |
| 77 | // where X is the class and Y is the method |
| 78 | |
| 79 | enum BinderMethodID : int |
| 80 | { |
| 81 | METHOD__NIL = 0, |
| 82 | |
| 83 | #define DEFINE_METHOD(c,i,s,g) METHOD__ ## c ## __ ## i, |
| 84 | #include "mscorlib.h" |
| 85 | |
| 86 | METHOD__MSCORLIB_COUNT, |
| 87 | }; |
| 88 | |
| 89 | // BinderFieldIDs are of the form FIELD__XXX__YYY, |
| 90 | // where X is the class and Y is the field |
| 91 | |
| 92 | enum BinderFieldID |
| 93 | { |
| 94 | FIELD__NIL = 0, |
| 95 | |
| 96 | #define DEFINE_FIELD(c,i,s) FIELD__ ## c ## __ ## i, |
| 97 | #include "mscorlib.h" |
| 98 | |
| 99 | FIELD__MSCORLIB_COUNT, |
| 100 | }; |
| 101 | |
| 102 | struct MscorlibClassDescription |
| 103 | { |
| 104 | PTR_CSTR nameSpace; |
| 105 | PTR_CSTR name; |
| 106 | }; |
| 107 | |
| 108 | struct MscorlibMethodDescription |
| 109 | { |
| 110 | BinderClassID classID; |
| 111 | PTR_CSTR name; |
| 112 | PTR_HARDCODEDMETASIG sig; |
| 113 | }; |
| 114 | |
| 115 | struct MscorlibFieldDescription |
| 116 | { |
| 117 | BinderClassID classID; |
| 118 | PTR_CSTR name; |
| 119 | }; |
| 120 | |
| 121 | class MscorlibBinder |
| 122 | { |
| 123 | public: |
| 124 | #ifdef DACCESS_COMPILE |
| 125 | friend class NativeImageDumper; |
| 126 | #endif |
| 127 | |
| 128 | // |
| 129 | // Note that the frequently called methods are intentionally static to reduce code bloat. |
| 130 | // Instance methods would push the address of the global object at every callsite. |
| 131 | // |
| 132 | |
| 133 | static PTR_Module GetModule(); |
| 134 | |
| 135 | // |
| 136 | // Retrieve structures from ID. |
| 137 | // |
| 138 | // Note that none of the MscorlibBinder methods trigger static |
| 139 | // constructors. The JITed code takes care of triggering them. |
| 140 | // |
| 141 | static PTR_MethodTable GetClass(BinderClassID id); |
| 142 | static MethodDesc * GetMethod(BinderMethodID id); |
| 143 | static FieldDesc * GetField(BinderFieldID id); |
| 144 | |
| 145 | // |
| 146 | // A slighly faster version that assumes that the class was fetched |
| 147 | // by the binder earlier. |
| 148 | // |
| 149 | static PTR_MethodTable GetExistingClass(BinderClassID id); |
| 150 | static MethodDesc * GetExistingMethod(BinderMethodID id); |
| 151 | static FieldDesc * GetExistingField(BinderFieldID id); |
| 152 | |
| 153 | // |
| 154 | // Utilities for classes |
| 155 | // |
| 156 | static FORCEINLINE BOOL IsClass(MethodTable *pMT, BinderClassID id) |
| 157 | { |
| 158 | return dac_cast<TADDR>(GetClass(id)) == dac_cast<TADDR>(pMT); |
| 159 | } |
| 160 | |
| 161 | // Get the class only if it has been loaded already |
| 162 | static PTR_MethodTable GetClassIfExist(BinderClassID id); |
| 163 | |
| 164 | static LPCUTF8 GetClassNameSpace(BinderClassID id); |
| 165 | static LPCUTF8 GetClassName(BinderClassID id); |
| 166 | |
| 167 | // |
| 168 | // Utilities for methods |
| 169 | // |
| 170 | static LPCUTF8 GetMethodName(BinderMethodID id); |
| 171 | static LPHARDCODEDMETASIG GetMethodSig(BinderMethodID id); |
| 172 | |
| 173 | static Signature GetMethodSignature(BinderMethodID id) |
| 174 | { |
| 175 | WRAPPER_NO_CONTRACT; |
| 176 | return GetSignature(GetMethodSig(id)); |
| 177 | } |
| 178 | |
| 179 | // |
| 180 | // Utilities for fields |
| 181 | // |
| 182 | static LPCUTF8 GetFieldName(BinderFieldID id); |
| 183 | |
| 184 | static DWORD GetFieldOffset(BinderFieldID id); |
| 185 | |
| 186 | // |
| 187 | // Utilities for exceptions |
| 188 | // |
| 189 | |
| 190 | static MethodTable *GetException(RuntimeExceptionKind kind) |
| 191 | { |
| 192 | WRAPPER_NO_CONTRACT; |
| 193 | _ASSERTE(kind <= kLastExceptionInMscorlib); // Not supported for exceptions defined outside mscorlib. |
| 194 | BinderClassID id = (BinderClassID) (kind + CLASS__MSCORLIB_COUNT); |
| 195 | return GetClass(id); |
| 196 | } |
| 197 | |
| 198 | static BOOL IsException(MethodTable *pMT, RuntimeExceptionKind kind) |
| 199 | { |
| 200 | WRAPPER_NO_CONTRACT; |
| 201 | _ASSERTE(kind <= kLastExceptionInMscorlib); // Not supported for exceptions defined outside mscorlib. |
| 202 | BinderClassID id = (BinderClassID) (kind + CLASS__MSCORLIB_COUNT); |
| 203 | return dac_cast<TADDR>(GetClassIfExist(id)) == dac_cast<TADDR>(pMT); |
| 204 | } |
| 205 | |
| 206 | static LPCUTF8 GetExceptionName(RuntimeExceptionKind kind) |
| 207 | { |
| 208 | WRAPPER_NO_CONTRACT; |
| 209 | _ASSERTE(kind <= kLastExceptionInMscorlib); // Not supported for exceptions defined outside mscorlib. |
| 210 | BinderClassID id = (BinderClassID) (kind + CLASS__MSCORLIB_COUNT); |
| 211 | return GetClassName(id); |
| 212 | } |
| 213 | |
| 214 | // |
| 215 | // Utilities for signature element types |
| 216 | // |
| 217 | |
| 218 | static PTR_MethodTable GetElementType(CorElementType type) |
| 219 | { |
| 220 | LIMITED_METHOD_DAC_CONTRACT; |
| 221 | return GetExistingClass((BinderClassID) (type)); |
| 222 | } |
| 223 | |
| 224 | // This should be called during CLR initialization only |
| 225 | static PTR_MethodTable LoadPrimitiveType(CorElementType et); |
| 226 | |
| 227 | // Get the metasig, do a one-time conversion if necessary |
| 228 | static Signature GetSignature(LPHARDCODEDMETASIG pHardcodedSig); |
| 229 | static Signature GetTargetSignature(LPHARDCODEDMETASIG pHardcodedSig); |
| 230 | |
| 231 | // |
| 232 | // Static initialization |
| 233 | // |
| 234 | static void Startup(); |
| 235 | |
| 236 | // |
| 237 | // These are called by initialization code: |
| 238 | // |
| 239 | static void AttachModule(Module *pModule); |
| 240 | |
| 241 | #ifdef FEATURE_PREJIT |
| 242 | // |
| 243 | // Store the binding arrays to a prejit image |
| 244 | // so we don't have to do name lookup at runtime |
| 245 | // |
| 246 | void BindAll(); |
| 247 | void Save(DataImage *image); |
| 248 | void Fixup(DataImage *image); |
| 249 | #endif |
| 250 | |
| 251 | #ifdef _DEBUG |
| 252 | void Check(); |
| 253 | void CheckExtended(); |
| 254 | #endif |
| 255 | |
| 256 | #ifdef DACCESS_COMPILE |
| 257 | void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); |
| 258 | #endif |
| 259 | |
| 260 | private: |
| 261 | |
| 262 | // We have two different instances of the binder in crossgen. The instance local methods |
| 263 | // are used when it is necessary to differentiate between them. |
| 264 | PTR_MethodTable LookupClassLocal(BinderClassID id); |
| 265 | MethodDesc * LookupMethodLocal(BinderMethodID id); |
| 266 | FieldDesc * LookupFieldLocal(BinderFieldID id); |
| 267 | |
| 268 | PTR_MethodTable GetClassLocal(BinderClassID id); |
| 269 | MethodDesc * GetMethodLocal(BinderMethodID id); |
| 270 | FieldDesc * GetFieldLocal(BinderFieldID id); |
| 271 | |
| 272 | static PTR_MethodTable LookupClass(BinderClassID id); |
| 273 | static MethodDesc * LookupMethod(BinderMethodID id); |
| 274 | static FieldDesc * LookupField(BinderFieldID id); |
| 275 | |
| 276 | static PTR_MethodTable LookupClassIfExist(BinderClassID id); |
| 277 | |
| 278 | Signature GetSignatureLocal(LPHARDCODEDMETASIG pHardcodedSig); |
| 279 | |
| 280 | bool ConvertType(const BYTE*& pSig, SigBuilder * pSigBuilder); |
| 281 | void BuildConvertedSignature(const BYTE* pSig, SigBuilder * pSigBuilder); |
| 282 | const BYTE* ConvertSignature(LPHARDCODEDMETASIG pHardcodedSig, const BYTE* pSig); |
| 283 | |
| 284 | void SetDescriptions(Module * pModule, |
| 285 | const MscorlibClassDescription * pClassDescriptions, USHORT nClasses, |
| 286 | const MscorlibMethodDescription * pMethodDescriptions, USHORT nMethods, |
| 287 | const MscorlibFieldDescription * pFieldDescriptions, USHORT nFields); |
| 288 | |
| 289 | void AllocateTables(); |
| 290 | |
| 291 | #ifdef _DEBUG |
| 292 | static void TriggerGCUnderStress(); |
| 293 | #endif |
| 294 | |
| 295 | PTR_Module m_pModule; |
| 296 | |
| 297 | DPTR(PTR_MethodTable) m_pClasses; |
| 298 | DPTR(PTR_MethodDesc) m_pMethods; |
| 299 | DPTR(PTR_FieldDesc) m_pFields; |
| 300 | |
| 301 | // This is necessary to avoid embeding copy of the descriptions into mscordacwks |
| 302 | DPTR(const MscorlibClassDescription) m_classDescriptions; |
| 303 | DPTR(const MscorlibMethodDescription) m_methodDescriptions; |
| 304 | DPTR(const MscorlibFieldDescription) m_fieldDescriptions; |
| 305 | |
| 306 | USHORT m_cClasses; |
| 307 | USHORT m_cMethods; |
| 308 | USHORT m_cFields; |
| 309 | |
| 310 | static CrstStatic s_SigConvertCrst; |
| 311 | |
| 312 | #ifdef _DEBUG |
| 313 | |
| 314 | struct OffsetAndSizeCheck |
| 315 | { |
| 316 | PTR_CSTR classNameSpace; |
| 317 | PTR_CSTR className; |
| 318 | SIZE_T expectedClassSize; |
| 319 | |
| 320 | PTR_CSTR fieldName; |
| 321 | SIZE_T expectedFieldOffset; |
| 322 | SIZE_T expectedFieldSize; |
| 323 | }; |
| 324 | |
| 325 | static const OffsetAndSizeCheck OffsetsAndSizes[]; |
| 326 | |
| 327 | #endif |
| 328 | }; |
| 329 | |
| 330 | // |
| 331 | // Global bound modules: |
| 332 | // |
| 333 | |
| 334 | GVAL_DECL(MscorlibBinder, g_Mscorlib); |
| 335 | |
| 336 | FORCEINLINE PTR_MethodTable MscorlibBinder::GetClass(BinderClassID id) |
| 337 | { |
| 338 | CONTRACTL |
| 339 | { |
| 340 | THROWS; |
| 341 | GC_TRIGGERS; |
| 342 | INJECT_FAULT(ThrowOutOfMemory()); |
| 343 | |
| 344 | PRECONDITION(id != CLASS__NIL); |
| 345 | PRECONDITION((&g_Mscorlib)->m_cClasses > 0); // Make sure mscorlib has been loaded. |
| 346 | PRECONDITION(id <= (&g_Mscorlib)->m_cClasses); |
| 347 | } |
| 348 | CONTRACTL_END; |
| 349 | |
| 350 | // Force a GC here under stress because type loading could trigger GC nondeterminsticly |
| 351 | INDEBUG(TriggerGCUnderStress()); |
| 352 | |
| 353 | PTR_MethodTable pMT = VolatileLoad(&((&g_Mscorlib)->m_pClasses[id])); |
| 354 | if (pMT == NULL) |
| 355 | return LookupClass(id); |
| 356 | return pMT; |
| 357 | } |
| 358 | |
| 359 | FORCEINLINE MethodDesc * MscorlibBinder::GetMethod(BinderMethodID id) |
| 360 | { |
| 361 | CONTRACTL |
| 362 | { |
| 363 | THROWS; |
| 364 | GC_TRIGGERS; |
| 365 | INJECT_FAULT(ThrowOutOfMemory()); |
| 366 | |
| 367 | PRECONDITION(id != METHOD__NIL); |
| 368 | PRECONDITION(id <= (&g_Mscorlib)->m_cMethods); |
| 369 | } |
| 370 | CONTRACTL_END; |
| 371 | |
| 372 | // Force a GC here under stress because type loading could trigger GC nondeterminsticly |
| 373 | INDEBUG(TriggerGCUnderStress()); |
| 374 | |
| 375 | MethodDesc * pMD = VolatileLoad(&((&g_Mscorlib)->m_pMethods[id])); |
| 376 | if (pMD == NULL) |
| 377 | return LookupMethod(id); |
| 378 | return pMD; |
| 379 | } |
| 380 | |
| 381 | FORCEINLINE FieldDesc * MscorlibBinder::GetField(BinderFieldID id) |
| 382 | { |
| 383 | CONTRACTL |
| 384 | { |
| 385 | THROWS; |
| 386 | GC_TRIGGERS; |
| 387 | INJECT_FAULT(ThrowOutOfMemory()); |
| 388 | |
| 389 | PRECONDITION(id != FIELD__NIL); |
| 390 | PRECONDITION(id <= (&g_Mscorlib)->m_cFields); |
| 391 | } |
| 392 | CONTRACTL_END; |
| 393 | |
| 394 | // Force a GC here under stress because type loading could trigger GC nondeterminsticly |
| 395 | INDEBUG(TriggerGCUnderStress()); |
| 396 | |
| 397 | FieldDesc * pFD = VolatileLoad(&((&g_Mscorlib)->m_pFields[id])); |
| 398 | if (pFD == NULL) |
| 399 | return LookupField(id); |
| 400 | return pFD; |
| 401 | } |
| 402 | |
| 403 | FORCEINLINE PTR_MethodTable MscorlibBinder::GetExistingClass(BinderClassID id) |
| 404 | { |
| 405 | LIMITED_METHOD_DAC_CONTRACT; |
| 406 | PTR_MethodTable pMT = (&g_Mscorlib)->m_pClasses[id]; |
| 407 | _ASSERTE(pMT != NULL); |
| 408 | return pMT; |
| 409 | } |
| 410 | |
| 411 | FORCEINLINE MethodDesc * MscorlibBinder::GetExistingMethod(BinderMethodID id) |
| 412 | { |
| 413 | LIMITED_METHOD_DAC_CONTRACT; |
| 414 | MethodDesc * pMD = (&g_Mscorlib)->m_pMethods[id]; |
| 415 | _ASSERTE(pMD != NULL); |
| 416 | return pMD; |
| 417 | } |
| 418 | |
| 419 | FORCEINLINE FieldDesc * MscorlibBinder::GetExistingField(BinderFieldID id) |
| 420 | { |
| 421 | LIMITED_METHOD_DAC_CONTRACT; |
| 422 | FieldDesc * pFD = (&g_Mscorlib)->m_pFields[id]; |
| 423 | _ASSERTE(pFD != NULL); |
| 424 | return pFD; |
| 425 | } |
| 426 | |
| 427 | FORCEINLINE PTR_MethodTable MscorlibBinder::GetClassIfExist(BinderClassID id) |
| 428 | { |
| 429 | CONTRACTL |
| 430 | { |
| 431 | GC_NOTRIGGER; |
| 432 | NOTHROW; |
| 433 | FORBID_FAULT; |
| 434 | MODE_ANY; |
| 435 | |
| 436 | PRECONDITION(id != CLASS__NIL); |
| 437 | PRECONDITION(id <= (&g_Mscorlib)->m_cClasses); |
| 438 | } |
| 439 | CONTRACTL_END; |
| 440 | |
| 441 | PTR_MethodTable pMT = VolatileLoad(&((&g_Mscorlib)->m_pClasses[id])); |
| 442 | if (pMT == NULL) |
| 443 | return LookupClassIfExist(id); |
| 444 | return pMT; |
| 445 | } |
| 446 | |
| 447 | |
| 448 | FORCEINLINE PTR_Module MscorlibBinder::GetModule() |
| 449 | { |
| 450 | LIMITED_METHOD_DAC_CONTRACT; |
| 451 | PTR_Module pModule = (&g_Mscorlib)->m_pModule; |
| 452 | _ASSERTE(pModule != NULL); |
| 453 | return pModule; |
| 454 | } |
| 455 | |
| 456 | FORCEINLINE LPCUTF8 MscorlibBinder::GetClassNameSpace(BinderClassID id) |
| 457 | { |
| 458 | LIMITED_METHOD_CONTRACT; |
| 459 | |
| 460 | _ASSERTE(id != CLASS__NIL); |
| 461 | _ASSERTE(id <= (&g_Mscorlib)->m_cClasses); |
| 462 | return (&g_Mscorlib)->m_classDescriptions[id].nameSpace; |
| 463 | } |
| 464 | |
| 465 | FORCEINLINE LPCUTF8 MscorlibBinder::GetClassName(BinderClassID id) |
| 466 | { |
| 467 | LIMITED_METHOD_CONTRACT; |
| 468 | |
| 469 | _ASSERTE(id != CLASS__NIL); |
| 470 | _ASSERTE(id <= (&g_Mscorlib)->m_cClasses); |
| 471 | return (&g_Mscorlib)->m_classDescriptions[id].name; |
| 472 | } |
| 473 | |
| 474 | FORCEINLINE LPCUTF8 MscorlibBinder::GetMethodName(BinderMethodID id) |
| 475 | { |
| 476 | LIMITED_METHOD_CONTRACT; |
| 477 | |
| 478 | _ASSERTE(id != METHOD__NIL); |
| 479 | _ASSERTE(id <= (&g_Mscorlib)->m_cMethods); |
| 480 | return (&g_Mscorlib)->m_methodDescriptions[id-1].name; |
| 481 | } |
| 482 | |
| 483 | FORCEINLINE LPHARDCODEDMETASIG MscorlibBinder::GetMethodSig(BinderMethodID id) |
| 484 | { |
| 485 | LIMITED_METHOD_CONTRACT; |
| 486 | |
| 487 | _ASSERTE(id != METHOD__NIL); |
| 488 | _ASSERTE(id <= (&g_Mscorlib)->m_cMethods); |
| 489 | return (&g_Mscorlib)->m_methodDescriptions[id-1].sig; |
| 490 | } |
| 491 | |
| 492 | FORCEINLINE LPCUTF8 MscorlibBinder::GetFieldName(BinderFieldID id) |
| 493 | { |
| 494 | LIMITED_METHOD_CONTRACT; |
| 495 | |
| 496 | _ASSERTE(id != FIELD__NIL); |
| 497 | _ASSERTE(id <= (&g_Mscorlib)->m_cFields); |
| 498 | return (&g_Mscorlib)->m_fieldDescriptions[id-1].name; |
| 499 | } |
| 500 | |
| 501 | #endif // _BINDERMODULE_H_ |
| 502 | |