| 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 | // File: methodtable.inl |
| 6 | // |
| 7 | |
| 8 | |
| 9 | // |
| 10 | |
| 11 | // |
| 12 | // ============================================================================ |
| 13 | |
| 14 | #ifndef _METHODTABLE_INL_ |
| 15 | #define _METHODTABLE_INL_ |
| 16 | |
| 17 | #include "methodtable.h" |
| 18 | #include "genericdict.h" |
| 19 | #include "threadstatics.h" |
| 20 | |
| 21 | //========================================================================================== |
| 22 | inline PTR_EEClass MethodTable::GetClass_NoLogging() |
| 23 | { |
| 24 | LIMITED_METHOD_DAC_CONTRACT; |
| 25 | |
| 26 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
| 27 | |
| 28 | #ifdef _DEBUG |
| 29 | LowBits lowBits = union_getLowBits(addr); |
| 30 | if (lowBits == UNION_EECLASS) |
| 31 | { |
| 32 | return PTR_EEClass(addr); |
| 33 | } |
| 34 | else if (lowBits == UNION_METHODTABLE) |
| 35 | { |
| 36 | // pointer to canonical MethodTable. |
| 37 | TADDR canonicalMethodTable = union_getPointer(addr); |
| 38 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT)); |
| 39 | } |
| 40 | #ifdef FEATURE_PREJIT |
| 41 | else if (lowBits == UNION_INDIRECTION) |
| 42 | { |
| 43 | // pointer to indirection cell that points to canonical MethodTable |
| 44 | TADDR canonicalMethodTable = *PTR_TADDR(union_getPointer(addr)); |
| 45 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT)); |
| 46 | } |
| 47 | #endif |
| 48 | #ifdef DACCESS_COMPILE |
| 49 | // Minidumps don't guarantee that every member of every class will be able to work here. |
| 50 | #else |
| 51 | _ASSERTE(!"Malformed m_pEEClass in MethodTable" ); |
| 52 | #endif |
| 53 | return NULL; |
| 54 | |
| 55 | #else |
| 56 | |
| 57 | if ((addr & 2) == 0) |
| 58 | { |
| 59 | // pointer to EEClass |
| 60 | return PTR_EEClass(addr); |
| 61 | } |
| 62 | |
| 63 | #ifdef FEATURE_PREJIT |
| 64 | if ((addr & 1) != 0) |
| 65 | { |
| 66 | // pointer to indirection cell that points to canonical MethodTable |
| 67 | TADDR canonicalMethodTable = *PTR_TADDR(addr - 3); |
| 68 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(canonicalMethodTable), &MethodTable::m_pCanonMT)); |
| 69 | } |
| 70 | #endif |
| 71 | |
| 72 | // pointer to canonical MethodTable. |
| 73 | return PTR_EEClass(ReadPointer((MethodTable *) PTR_MethodTable(addr - 2), &MethodTable::m_pCanonMT)); |
| 74 | #endif |
| 75 | } |
| 76 | |
| 77 | //========================================================================================== |
| 78 | inline PTR_EEClass MethodTable::GetClass() |
| 79 | { |
| 80 | LIMITED_METHOD_DAC_CONTRACT; |
| 81 | |
| 82 | _ASSERTE_IMPL(GetClass_NoLogging() != NULL); |
| 83 | |
| 84 | g_IBCLogger.LogEEClassAndMethodTableAccess(this); |
| 85 | return GetClass_NoLogging(); |
| 86 | } |
| 87 | |
| 88 | //========================================================================================== |
| 89 | inline Assembly * MethodTable::GetAssembly() |
| 90 | { |
| 91 | WRAPPER_NO_CONTRACT; |
| 92 | return GetModule()->GetAssembly(); |
| 93 | } |
| 94 | |
| 95 | //========================================================================================== |
| 96 | // DO NOT ADD ANY ASSERTS OR ANY OTHER CODE TO THIS METHOD. |
| 97 | // DO NOT USE THIS METHOD. |
| 98 | // Yes folks, for better or worse the debugger pokes supposed object addresses |
| 99 | // to try to see if objects are valid, possibly firing an AccessViolation or |
| 100 | // worse. Thus it is "correct" behaviour for this to AV, and incorrect |
| 101 | // behaviour for it to assert if called on an invalid pointer. |
| 102 | inline PTR_EEClass MethodTable::GetClassWithPossibleAV() |
| 103 | { |
| 104 | CANNOT_HAVE_CONTRACT; |
| 105 | SUPPORTS_DAC; |
| 106 | return GetClass_NoLogging(); |
| 107 | } |
| 108 | |
| 109 | //========================================================================================== |
| 110 | inline BOOL MethodTable::IsClassPointerValid() |
| 111 | { |
| 112 | WRAPPER_NO_CONTRACT; |
| 113 | SUPPORTS_DAC; |
| 114 | |
| 115 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
| 116 | |
| 117 | LowBits lowBits = union_getLowBits(addr); |
| 118 | if (lowBits == UNION_EECLASS) |
| 119 | { |
| 120 | return !m_pEEClass.IsNull(); |
| 121 | } |
| 122 | else if (lowBits == UNION_METHODTABLE) |
| 123 | { |
| 124 | // pointer to canonical MethodTable. |
| 125 | TADDR canonicalMethodTable = union_getPointer(addr); |
| 126 | return !PTR_MethodTable(canonicalMethodTable)->m_pEEClass.IsNull(); |
| 127 | } |
| 128 | #ifdef FEATURE_PREJIT |
| 129 | else if (lowBits == UNION_INDIRECTION) |
| 130 | { |
| 131 | // pointer to indirection cell that points to canonical MethodTable |
| 132 | TADDR canonicalMethodTable = *PTR_TADDR(union_getPointer(addr)); |
| 133 | if (CORCOMPILE_IS_POINTER_TAGGED(canonicalMethodTable)) |
| 134 | return FALSE; |
| 135 | return !PTR_MethodTable(canonicalMethodTable)->m_pEEClass.IsNull(); |
| 136 | } |
| 137 | #endif |
| 138 | _ASSERTE(!"Malformed m_pEEClass in MethodTable" ); |
| 139 | return FALSE; |
| 140 | } |
| 141 | |
| 142 | //========================================================================================== |
| 143 | // Does this immediate item live in an NGEN module? |
| 144 | inline BOOL MethodTable::IsZapped() |
| 145 | { |
| 146 | LIMITED_METHOD_DAC_CONTRACT; |
| 147 | |
| 148 | #ifdef FEATURE_PREJIT |
| 149 | return GetFlag(enum_flag_IsZapped); |
| 150 | #else |
| 151 | return FALSE; |
| 152 | #endif |
| 153 | } |
| 154 | |
| 155 | //========================================================================================== |
| 156 | // For types that are part of an ngen-ed assembly this gets the |
| 157 | // Module* that contains this methodtable. |
| 158 | inline PTR_Module MethodTable::GetZapModule() |
| 159 | { |
| 160 | LIMITED_METHOD_DAC_CONTRACT; |
| 161 | |
| 162 | PTR_Module zapModule = NULL; |
| 163 | if (IsZapped()) |
| 164 | { |
| 165 | zapModule = ReadPointer(this, &MethodTable::m_pLoaderModule); |
| 166 | } |
| 167 | |
| 168 | return zapModule; |
| 169 | } |
| 170 | |
| 171 | //========================================================================================== |
| 172 | inline PTR_Module MethodTable::GetLoaderModule() |
| 173 | { |
| 174 | LIMITED_METHOD_DAC_CONTRACT; |
| 175 | return ReadPointer(this, &MethodTable::m_pLoaderModule); |
| 176 | } |
| 177 | |
| 178 | inline PTR_LoaderAllocator MethodTable::GetLoaderAllocator() |
| 179 | { |
| 180 | LIMITED_METHOD_DAC_CONTRACT; |
| 181 | return GetLoaderModule()->GetLoaderAllocator(); |
| 182 | } |
| 183 | |
| 184 | |
| 185 | |
| 186 | #ifndef DACCESS_COMPILE |
| 187 | //========================================================================================== |
| 188 | inline void MethodTable::SetLoaderModule(Module* pModule) |
| 189 | { |
| 190 | WRAPPER_NO_CONTRACT; |
| 191 | m_pLoaderModule.SetValue(pModule); |
| 192 | } |
| 193 | |
| 194 | inline void MethodTable::SetLoaderAllocator(LoaderAllocator* pAllocator) |
| 195 | { |
| 196 | LIMITED_METHOD_CONTRACT; |
| 197 | _ASSERTE(pAllocator == GetLoaderAllocator()); |
| 198 | |
| 199 | if (pAllocator->IsCollectible()) |
| 200 | { |
| 201 | SetFlag(enum_flag_Collectible); |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | #endif |
| 206 | |
| 207 | //========================================================================================== |
| 208 | inline WORD MethodTable::GetNumNonVirtualSlots() |
| 209 | { |
| 210 | LIMITED_METHOD_DAC_CONTRACT; |
| 211 | return HasNonVirtualSlots() ? GetClass()->GetNumNonVirtualSlots() : 0; |
| 212 | } |
| 213 | |
| 214 | //========================================================================================== |
| 215 | inline WORD MethodTable::GetNumInstanceFields() |
| 216 | { |
| 217 | WRAPPER_NO_CONTRACT; |
| 218 | return (GetClass()->GetNumInstanceFields()); |
| 219 | } |
| 220 | |
| 221 | //========================================================================================== |
| 222 | inline WORD MethodTable::GetNumStaticFields() |
| 223 | { |
| 224 | LIMITED_METHOD_DAC_CONTRACT; |
| 225 | return (GetClass()->GetNumStaticFields()); |
| 226 | } |
| 227 | |
| 228 | //========================================================================================== |
| 229 | inline WORD MethodTable::GetNumThreadStaticFields() |
| 230 | { |
| 231 | LIMITED_METHOD_DAC_CONTRACT; |
| 232 | return (GetClass()->GetNumThreadStaticFields()); |
| 233 | } |
| 234 | |
| 235 | //========================================================================================== |
| 236 | inline DWORD MethodTable::GetNumInstanceFieldBytes() |
| 237 | { |
| 238 | LIMITED_METHOD_DAC_CONTRACT; |
| 239 | return(GetBaseSize() - GetClass()->GetBaseSizePadding()); |
| 240 | } |
| 241 | |
| 242 | //========================================================================================== |
| 243 | inline WORD MethodTable::GetNumIntroducedInstanceFields() |
| 244 | { |
| 245 | LIMITED_METHOD_DAC_CONTRACT; |
| 246 | |
| 247 | WORD wNumFields = GetNumInstanceFields(); |
| 248 | |
| 249 | MethodTable * pParentMT = GetParentMethodTable(); |
| 250 | if (pParentMT != NULL) |
| 251 | { |
| 252 | WORD wNumParentFields = pParentMT->GetNumInstanceFields(); |
| 253 | |
| 254 | // If this assert fires, then our bookkeeping is bad. Perhaps we incremented the count |
| 255 | // of fields on the base class w/o incrementing the count in the derived class. (EnC scenarios). |
| 256 | _ASSERTE(wNumFields >= wNumParentFields); |
| 257 | |
| 258 | wNumFields -= wNumParentFields; |
| 259 | } |
| 260 | |
| 261 | return(wNumFields); |
| 262 | } |
| 263 | |
| 264 | //========================================================================================== |
| 265 | inline DWORD MethodTable::GetAlignedNumInstanceFieldBytes() |
| 266 | { |
| 267 | WRAPPER_NO_CONTRACT; |
| 268 | return((GetNumInstanceFieldBytes() + 3) & (~3)); |
| 269 | } |
| 270 | |
| 271 | //========================================================================================== |
| 272 | inline PTR_FieldDesc MethodTable::GetApproxFieldDescListRaw() |
| 273 | { |
| 274 | WRAPPER_NO_CONTRACT; |
| 275 | // Careful about using this method. If it's possible that fields may have been added via EnC, then |
| 276 | // must use the FieldDescIterator as any fields added via EnC won't be in the raw list |
| 277 | |
| 278 | return GetClass()->GetFieldDescList(); |
| 279 | } |
| 280 | |
| 281 | #ifdef FEATURE_COMINTEROP |
| 282 | //========================================================================================== |
| 283 | inline DWORD MethodTable::IsComClassInterface() |
| 284 | { |
| 285 | WRAPPER_NO_CONTRACT; |
| 286 | return GetClass()->IsComClassInterface(); |
| 287 | } |
| 288 | |
| 289 | //========================================================================================== |
| 290 | inline DWORD MethodTable::IsComImport() |
| 291 | { |
| 292 | WRAPPER_NO_CONTRACT; |
| 293 | return GetClass()->IsComImport(); |
| 294 | } |
| 295 | |
| 296 | //========================================================================================== |
| 297 | // Sparse VTables. These require a SparseVTableMap in the EEClass in |
| 298 | // order to record how the CLR's vtable slots map across to COM |
| 299 | // Interop slots. |
| 300 | // |
| 301 | inline int MethodTable::IsSparseForCOMInterop() |
| 302 | { |
| 303 | WRAPPER_NO_CONTRACT; |
| 304 | return GetClass()->IsSparseForCOMInterop(); |
| 305 | } |
| 306 | |
| 307 | //========================================================================================== |
| 308 | inline int MethodTable::IsComEventItfType() |
| 309 | { |
| 310 | WRAPPER_NO_CONTRACT; |
| 311 | _ASSERTE(GetClass()); |
| 312 | return GetClass()->IsComEventItfType(); |
| 313 | } |
| 314 | |
| 315 | #endif // FEATURE_COMINTEROP |
| 316 | |
| 317 | //========================================================================================== |
| 318 | inline DWORD MethodTable::GetAttrClass() |
| 319 | { |
| 320 | WRAPPER_NO_CONTRACT; |
| 321 | return GetClass()->GetAttrClass(); |
| 322 | } |
| 323 | |
| 324 | //========================================================================================== |
| 325 | inline BOOL MethodTable::SupportsGenericInterop(TypeHandle::InteropKind interopKind, |
| 326 | MethodTable::Mode mode /*= modeAll*/) |
| 327 | { |
| 328 | LIMITED_METHOD_CONTRACT; |
| 329 | |
| 330 | #ifdef FEATURE_COMINTEROP |
| 331 | return ((IsInterface() || IsDelegate()) && // interface or delegate |
| 332 | HasInstantiation() && // generic |
| 333 | !IsSharedByGenericInstantiations() && // unshared |
| 334 | !ContainsGenericVariables() && // closed over concrete types |
| 335 | // defined in .winmd or one of the redirected mscorlib interfaces |
| 336 | ((((mode & modeProjected) != 0) && IsProjectedFromWinRT()) || |
| 337 | (((mode & modeRedirected) != 0) && (IsWinRTRedirectedInterface(interopKind) || IsWinRTRedirectedDelegate())))); |
| 338 | #else // FEATURE_COMINTEROP |
| 339 | return FALSE; |
| 340 | #endif // FEATURE_COMINTEROP |
| 341 | } |
| 342 | |
| 343 | |
| 344 | //========================================================================================== |
| 345 | inline BOOL MethodTable::IsNotTightlyPacked() |
| 346 | { |
| 347 | WRAPPER_NO_CONTRACT; |
| 348 | return GetClass()->IsNotTightlyPacked(); |
| 349 | } |
| 350 | |
| 351 | //========================================================================================== |
| 352 | inline BOOL MethodTable::HasFieldsWhichMustBeInited() |
| 353 | { |
| 354 | WRAPPER_NO_CONTRACT; |
| 355 | return GetClass()->HasFieldsWhichMustBeInited(); |
| 356 | } |
| 357 | |
| 358 | //========================================================================================== |
| 359 | inline BOOL MethodTable::IsAbstract() |
| 360 | { |
| 361 | WRAPPER_NO_CONTRACT; |
| 362 | return GetClass()->IsAbstract(); |
| 363 | } |
| 364 | |
| 365 | //========================================================================================== |
| 366 | |
| 367 | #ifdef FEATURE_COMINTEROP |
| 368 | //========================================================================================== |
| 369 | inline void MethodTable::SetHasGuidInfo() |
| 370 | { |
| 371 | LIMITED_METHOD_CONTRACT; |
| 372 | _ASSERTE(IsInterface() || (HasCCWTemplate() && IsDelegate())); |
| 373 | |
| 374 | // for delegates, having CCW template implies having GUID info |
| 375 | if (IsInterface()) |
| 376 | SetFlag(enum_flag_IfInterfaceThenHasGuidInfo); |
| 377 | } |
| 378 | |
| 379 | //========================================================================================== |
| 380 | inline BOOL MethodTable::HasGuidInfo() |
| 381 | { |
| 382 | LIMITED_METHOD_DAC_CONTRACT; |
| 383 | |
| 384 | if (IsInterface()) |
| 385 | return GetFlag(enum_flag_IfInterfaceThenHasGuidInfo); |
| 386 | |
| 387 | // HasCCWTemplate() is intentionally checked first here to avoid hitting |
| 388 | // g_pMulticastDelegateClass == NULL inside IsDelegate() during startup |
| 389 | return HasCCWTemplate() && IsDelegate(); |
| 390 | } |
| 391 | |
| 392 | //========================================================================================== |
| 393 | // True IFF the type has a GUID explicitly assigned to it (including WinRT generic interfaces |
| 394 | // where the GUID is computed). |
| 395 | inline BOOL MethodTable::HasExplicitGuid() |
| 396 | { |
| 397 | CONTRACTL { |
| 398 | THROWS; |
| 399 | GC_TRIGGERS; |
| 400 | MODE_ANY; |
| 401 | SUPPORTS_DAC; |
| 402 | } CONTRACTL_END; |
| 403 | |
| 404 | GUID guid; |
| 405 | GetGuid(&guid, FALSE); |
| 406 | return (guid != GUID_NULL); |
| 407 | } |
| 408 | |
| 409 | //========================================================================================== |
| 410 | inline void MethodTable::SetHasCCWTemplate() |
| 411 | { |
| 412 | LIMITED_METHOD_CONTRACT; |
| 413 | SetFlag(enum_flag_HasCCWTemplate); |
| 414 | } |
| 415 | |
| 416 | //========================================================================================== |
| 417 | inline BOOL MethodTable::HasCCWTemplate() |
| 418 | { |
| 419 | LIMITED_METHOD_DAC_CONTRACT; |
| 420 | return GetFlag(enum_flag_HasCCWTemplate); |
| 421 | } |
| 422 | |
| 423 | //========================================================================================== |
| 424 | inline void MethodTable::SetHasRCWPerTypeData() |
| 425 | { |
| 426 | LIMITED_METHOD_CONTRACT; |
| 427 | SetFlag(enum_flag_HasRCWPerTypeData); |
| 428 | } |
| 429 | |
| 430 | //========================================================================================== |
| 431 | inline BOOL MethodTable::HasRCWPerTypeData() |
| 432 | { |
| 433 | LIMITED_METHOD_DAC_CONTRACT; |
| 434 | return GetFlag(enum_flag_HasRCWPerTypeData); |
| 435 | } |
| 436 | |
| 437 | //========================================================================================== |
| 438 | // Get the GUID used for WinRT interop |
| 439 | // * if the type is not a WinRT type or a redirected interfae return FALSE |
| 440 | inline BOOL MethodTable::GetGuidForWinRT(GUID *pGuid) |
| 441 | { |
| 442 | CONTRACTL { |
| 443 | THROWS; |
| 444 | GC_TRIGGERS; |
| 445 | MODE_ANY; |
| 446 | SUPPORTS_DAC; |
| 447 | } CONTRACTL_END; |
| 448 | |
| 449 | BOOL bRes = FALSE; |
| 450 | if ((IsProjectedFromWinRT() && !HasInstantiation()) || |
| 451 | (SupportsGenericInterop(TypeHandle::Interop_NativeToManaged) && IsLegalNonArrayWinRTType())) |
| 452 | { |
| 453 | bRes = SUCCEEDED(GetGuidNoThrow(pGuid, TRUE, FALSE)); |
| 454 | } |
| 455 | |
| 456 | return bRes; |
| 457 | } |
| 458 | |
| 459 | #endif // FEATURE_COMINTEROP |
| 460 | |
| 461 | //========================================================================================== |
| 462 | // Is pParentMT System.Enum? (Cannot be called before System.Enum is loaded.) |
| 463 | inline BOOL MethodTable::IsEnum() |
| 464 | { |
| 465 | LIMITED_METHOD_DAC_CONTRACT; |
| 466 | |
| 467 | // We should not be calling this before our parent method table pointer |
| 468 | // is valid . |
| 469 | _ASSERTE_IMPL(IsParentMethodTablePointerValid()); |
| 470 | |
| 471 | PTR_MethodTable pParentMT = GetParentMethodTable(); |
| 472 | |
| 473 | // Make sure that we are not using this method during startup |
| 474 | _ASSERTE(g_pEnumClass != NULL); |
| 475 | |
| 476 | return (pParentMT == g_pEnumClass); |
| 477 | } |
| 478 | |
| 479 | //========================================================================================== |
| 480 | // Is pParentMT either System.ValueType or System.Enum? |
| 481 | inline BOOL MethodTable::IsValueType() |
| 482 | { |
| 483 | LIMITED_METHOD_DAC_CONTRACT; |
| 484 | |
| 485 | g_IBCLogger.LogMethodTableAccess(this); |
| 486 | |
| 487 | return GetFlag(enum_flag_Category_ValueType_Mask) == enum_flag_Category_ValueType; |
| 488 | } |
| 489 | |
| 490 | //========================================================================================== |
| 491 | inline CorElementType MethodTable::GetArrayElementType() |
| 492 | { |
| 493 | WRAPPER_NO_CONTRACT; |
| 494 | |
| 495 | _ASSERTE (IsArray()); |
| 496 | return dac_cast<PTR_ArrayClass>(GetClass())->GetArrayElementType(); |
| 497 | } |
| 498 | |
| 499 | //========================================================================================== |
| 500 | inline DWORD MethodTable::GetRank() |
| 501 | { |
| 502 | LIMITED_METHOD_DAC_CONTRACT; |
| 503 | |
| 504 | _ASSERTE (IsArray()); |
| 505 | if (GetFlag(enum_flag_Category_IfArrayThenSzArray)) |
| 506 | return 1; // ELEMENT_TYPE_SZARRAY |
| 507 | else |
| 508 | return dac_cast<PTR_ArrayClass>(GetClass())->GetRank(); |
| 509 | } |
| 510 | |
| 511 | //========================================================================================== |
| 512 | inline BOOL MethodTable::IsTruePrimitive() |
| 513 | { |
| 514 | LIMITED_METHOD_DAC_CONTRACT; |
| 515 | return GetFlag(enum_flag_Category_Mask) == enum_flag_Category_TruePrimitive; |
| 516 | } |
| 517 | |
| 518 | //========================================================================================== |
| 519 | inline void MethodTable::SetIsTruePrimitive() |
| 520 | { |
| 521 | LIMITED_METHOD_DAC_CONTRACT; |
| 522 | SetFlag(enum_flag_Category_TruePrimitive); |
| 523 | } |
| 524 | |
| 525 | //========================================================================================== |
| 526 | inline BOOL MethodTable::IsBlittable() |
| 527 | { |
| 528 | WRAPPER_NO_CONTRACT; |
| 529 | #ifndef DACCESS_COMPILE |
| 530 | _ASSERTE(GetClass()); |
| 531 | return GetClass()->IsBlittable(); |
| 532 | #else // DACCESS_COMPILE |
| 533 | DacNotImpl(); |
| 534 | return false; |
| 535 | #endif // DACCESS_COMPILE |
| 536 | } |
| 537 | |
| 538 | //========================================================================================== |
| 539 | inline BOOL MethodTable::HasClassConstructor() |
| 540 | { |
| 541 | WRAPPER_NO_CONTRACT; |
| 542 | return GetFlag(enum_flag_HasCctor); |
| 543 | } |
| 544 | |
| 545 | //========================================================================================== |
| 546 | inline void MethodTable::SetHasClassConstructor() |
| 547 | { |
| 548 | WRAPPER_NO_CONTRACT; |
| 549 | return SetFlag(enum_flag_HasCctor); |
| 550 | } |
| 551 | |
| 552 | //========================================================================================== |
| 553 | inline WORD MethodTable::GetClassConstructorSlot() |
| 554 | { |
| 555 | WRAPPER_NO_CONTRACT; |
| 556 | _ASSERTE(HasClassConstructor()); |
| 557 | |
| 558 | // The class constructor slot is the first non-vtable slot |
| 559 | return GetNumVirtuals(); |
| 560 | } |
| 561 | |
| 562 | //========================================================================================== |
| 563 | inline BOOL MethodTable::HasDefaultConstructor() |
| 564 | { |
| 565 | WRAPPER_NO_CONTRACT; |
| 566 | return GetFlag(enum_flag_HasDefaultCtor); |
| 567 | } |
| 568 | |
| 569 | //========================================================================================== |
| 570 | inline void MethodTable::SetHasDefaultConstructor() |
| 571 | { |
| 572 | WRAPPER_NO_CONTRACT; |
| 573 | return SetFlag(enum_flag_HasDefaultCtor); |
| 574 | } |
| 575 | |
| 576 | //========================================================================================== |
| 577 | inline WORD MethodTable::GetDefaultConstructorSlot() |
| 578 | { |
| 579 | WRAPPER_NO_CONTRACT; |
| 580 | _ASSERTE(HasDefaultConstructor()); |
| 581 | |
| 582 | // The default ctor slot is right after cctor slot if there is one |
| 583 | return GetNumVirtuals() + (HasClassConstructor() ? 1 : 0); |
| 584 | } |
| 585 | |
| 586 | //========================================================================================== |
| 587 | inline BOOL MethodTable::HasLayout() |
| 588 | { |
| 589 | WRAPPER_NO_CONTRACT; |
| 590 | _ASSERTE(GetClass()); |
| 591 | return GetClass()->HasLayout(); |
| 592 | } |
| 593 | |
| 594 | //========================================================================================== |
| 595 | inline MethodDesc* MethodTable::GetMethodDescForSlot(DWORD slot) |
| 596 | { |
| 597 | CONTRACTL |
| 598 | { |
| 599 | NOTHROW; |
| 600 | GC_NOTRIGGER; |
| 601 | SO_TOLERANT; |
| 602 | MODE_ANY; |
| 603 | } |
| 604 | CONTRACTL_END; |
| 605 | |
| 606 | PCODE pCode = GetRestoredSlot(slot); |
| 607 | |
| 608 | // This is an optimization that we can take advantage of if we're trying to get the MethodDesc |
| 609 | // for an interface virtual, since their slots usually point to stub. |
| 610 | if (IsInterface() && slot < GetNumVirtuals()) |
| 611 | { |
| 612 | return MethodDesc::GetMethodDescFromStubAddr(pCode); |
| 613 | } |
| 614 | |
| 615 | return MethodTable::GetMethodDescForSlotAddress(pCode); |
| 616 | } |
| 617 | |
| 618 | #ifndef DACCESS_COMPILE |
| 619 | |
| 620 | //========================================================================================== |
| 621 | inline INT32 MethodTable::MethodIterator::GetNumMethods() const |
| 622 | { |
| 623 | LIMITED_METHOD_CONTRACT; |
| 624 | // assert that number of methods hasn't changed during the iteration |
| 625 | CONSISTENCY_CHECK( m_pMethodData->GetNumMethods() == static_cast< UINT32 >( m_iMethods ) ); |
| 626 | return m_iMethods; |
| 627 | } |
| 628 | |
| 629 | //========================================================================================== |
| 630 | // Returns TRUE if it's valid to request data from the current position |
| 631 | inline BOOL MethodTable::MethodIterator::IsValid() const |
| 632 | { |
| 633 | LIMITED_METHOD_CONTRACT; |
| 634 | return m_iCur >= 0 && m_iCur < GetNumMethods(); |
| 635 | } |
| 636 | |
| 637 | //========================================================================================== |
| 638 | inline BOOL MethodTable::MethodIterator::MoveTo(UINT32 idx) |
| 639 | { |
| 640 | LIMITED_METHOD_CONTRACT; |
| 641 | m_iCur = (INT32)idx; |
| 642 | return IsValid(); |
| 643 | } |
| 644 | |
| 645 | //========================================================================================== |
| 646 | inline BOOL MethodTable::MethodIterator::Prev() |
| 647 | { |
| 648 | WRAPPER_NO_CONTRACT; |
| 649 | if (IsValid()) |
| 650 | --m_iCur; |
| 651 | return (IsValid()); |
| 652 | } |
| 653 | |
| 654 | //========================================================================================== |
| 655 | inline BOOL MethodTable::MethodIterator::Next() |
| 656 | { |
| 657 | WRAPPER_NO_CONTRACT; |
| 658 | if (IsValid()) |
| 659 | ++m_iCur; |
| 660 | return (IsValid()); |
| 661 | } |
| 662 | |
| 663 | //========================================================================================== |
| 664 | inline void MethodTable::MethodIterator::MoveToBegin() |
| 665 | { |
| 666 | WRAPPER_NO_CONTRACT; |
| 667 | m_iCur = 0; |
| 668 | } |
| 669 | |
| 670 | //========================================================================================== |
| 671 | inline void MethodTable::MethodIterator::MoveToEnd() |
| 672 | { |
| 673 | WRAPPER_NO_CONTRACT; |
| 674 | m_iCur = GetNumMethods() - 1; |
| 675 | } |
| 676 | |
| 677 | //========================================================================================== |
| 678 | inline UINT32 MethodTable::MethodIterator::GetSlotNumber() const { |
| 679 | LIMITED_METHOD_CONTRACT; |
| 680 | CONSISTENCY_CHECK(IsValid()); |
| 681 | return (UINT32)m_iCur; |
| 682 | } |
| 683 | |
| 684 | //========================================================================================== |
| 685 | inline UINT32 MethodTable::MethodIterator::GetImplSlotNumber() const { |
| 686 | WRAPPER_NO_CONTRACT; |
| 687 | CONSISTENCY_CHECK(IsValid()); |
| 688 | return (UINT32)m_pMethodData->GetImplSlotNumber(m_iCur); |
| 689 | } |
| 690 | |
| 691 | //========================================================================================== |
| 692 | inline BOOL MethodTable::MethodIterator::IsVirtual() const { |
| 693 | LIMITED_METHOD_CONTRACT; |
| 694 | CONSISTENCY_CHECK(IsValid()); |
| 695 | return m_iCur < (INT32)(GetNumVirtuals()); |
| 696 | } |
| 697 | |
| 698 | //========================================================================================== |
| 699 | inline UINT32 MethodTable::MethodIterator::GetNumVirtuals() const { |
| 700 | LIMITED_METHOD_CONTRACT; |
| 701 | return m_pMethodData->GetNumVirtuals();; |
| 702 | } |
| 703 | |
| 704 | //========================================================================================== |
| 705 | inline DispatchSlot MethodTable::MethodIterator::GetTarget() const { |
| 706 | LIMITED_METHOD_CONTRACT; |
| 707 | CONSISTENCY_CHECK(IsValid()); |
| 708 | return m_pMethodData->GetImplSlot(m_iCur); |
| 709 | } |
| 710 | |
| 711 | //========================================================================================== |
| 712 | inline MethodDesc *MethodTable::MethodIterator::GetMethodDesc() const { |
| 713 | LIMITED_METHOD_CONTRACT; |
| 714 | CONSISTENCY_CHECK(IsValid()); |
| 715 | MethodDesc *pMD = m_pMethodData->GetImplMethodDesc(m_iCur); |
| 716 | CONSISTENCY_CHECK(CheckPointer(pMD)); |
| 717 | return pMD; |
| 718 | } |
| 719 | |
| 720 | //========================================================================================== |
| 721 | inline MethodDesc *MethodTable::MethodIterator::GetDeclMethodDesc() const { |
| 722 | LIMITED_METHOD_CONTRACT; |
| 723 | CONSISTENCY_CHECK(IsValid()); |
| 724 | MethodDesc *pMD = m_pMethodData->GetDeclMethodDesc(m_iCur); |
| 725 | CONSISTENCY_CHECK(CheckPointer(pMD)); |
| 726 | CONSISTENCY_CHECK(pMD->GetSlot() == GetSlotNumber()); |
| 727 | return pMD; |
| 728 | } |
| 729 | |
| 730 | #endif // DACCESS_COMPILE |
| 731 | |
| 732 | //========================================================================================== |
| 733 | // Non-canonical types share the method bodies with the canonical type. So the canonical |
| 734 | // type can be said to own the method bodies. Hence, by default, IntroducedMethodIterator |
| 735 | // only lets you iterate methods of the canonical type. You have to pass in |
| 736 | // restrictToCanonicalTypes=FALSE to iterate methods through a non-canonical type. |
| 737 | |
| 738 | inline MethodTable::IntroducedMethodIterator::IntroducedMethodIterator( |
| 739 | MethodTable *pMT, |
| 740 | BOOL restrictToCanonicalTypes /* = TRUE */ ) |
| 741 | { |
| 742 | WRAPPER_NO_CONTRACT; |
| 743 | CONSISTENCY_CHECK(pMT->IsCanonicalMethodTable() || !restrictToCanonicalTypes); |
| 744 | |
| 745 | SetChunk(pMT->GetClass()->GetChunks()); |
| 746 | } |
| 747 | |
| 748 | //========================================================================================== |
| 749 | FORCEINLINE BOOL MethodTable::IntroducedMethodIterator::Next() |
| 750 | { |
| 751 | WRAPPER_NO_CONTRACT; |
| 752 | CONSISTENCY_CHECK(IsValid()); |
| 753 | |
| 754 | // Check whether the next MethodDesc is still within the bounds of the current chunk |
| 755 | TADDR pNext = dac_cast<TADDR>(m_pMethodDesc) + m_pMethodDesc->SizeOf(); |
| 756 | |
| 757 | if (pNext < m_pChunkEnd) |
| 758 | { |
| 759 | // Just skip to the next method in the same chunk |
| 760 | m_pMethodDesc = PTR_MethodDesc(pNext); |
| 761 | } |
| 762 | else |
| 763 | { |
| 764 | _ASSERTE(pNext == m_pChunkEnd); |
| 765 | |
| 766 | // We have walked all the methods in the current chunk. Move on |
| 767 | // to the next chunk. |
| 768 | SetChunk(m_pChunk->GetNextChunk()); |
| 769 | } |
| 770 | |
| 771 | return IsValid(); |
| 772 | } |
| 773 | |
| 774 | //========================================================================================== |
| 775 | inline BOOL MethodTable::IntroducedMethodIterator::IsValid() const |
| 776 | { |
| 777 | LIMITED_METHOD_CONTRACT; |
| 778 | return m_pMethodDesc != NULL; |
| 779 | } |
| 780 | |
| 781 | //========================================================================================== |
| 782 | inline MethodDesc * MethodTable::IntroducedMethodIterator::GetMethodDesc() const |
| 783 | { |
| 784 | WRAPPER_NO_CONTRACT; |
| 785 | CONSISTENCY_CHECK(IsValid()); |
| 786 | return m_pMethodDesc; |
| 787 | } |
| 788 | |
| 789 | //========================================================================================== |
| 790 | inline DWORD MethodTable::GetIndexOfVtableIndirection(DWORD slotNum) |
| 791 | { |
| 792 | LIMITED_METHOD_DAC_CONTRACT; |
| 793 | _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK); |
| 794 | |
| 795 | return slotNum >> VTABLE_SLOTS_PER_CHUNK_LOG2; |
| 796 | } |
| 797 | |
| 798 | //========================================================================================== |
| 799 | inline DWORD MethodTable::GetStartSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals) |
| 800 | { |
| 801 | LIMITED_METHOD_DAC_CONTRACT; |
| 802 | _ASSERTE(indirectionIndex < GetNumVtableIndirections(wNumVirtuals)); |
| 803 | |
| 804 | return indirectionIndex * VTABLE_SLOTS_PER_CHUNK; |
| 805 | } |
| 806 | |
| 807 | //========================================================================================== |
| 808 | inline DWORD MethodTable::GetEndSlotForVtableIndirection(UINT32 indirectionIndex, DWORD wNumVirtuals) |
| 809 | { |
| 810 | LIMITED_METHOD_DAC_CONTRACT; |
| 811 | _ASSERTE(indirectionIndex < GetNumVtableIndirections(wNumVirtuals)); |
| 812 | |
| 813 | DWORD end = (indirectionIndex + 1) * VTABLE_SLOTS_PER_CHUNK; |
| 814 | |
| 815 | if (end > wNumVirtuals) |
| 816 | { |
| 817 | end = wNumVirtuals; |
| 818 | } |
| 819 | |
| 820 | return end; |
| 821 | } |
| 822 | |
| 823 | //========================================================================================== |
| 824 | inline UINT32 MethodTable::GetIndexAfterVtableIndirection(UINT32 slotNum) |
| 825 | { |
| 826 | LIMITED_METHOD_DAC_CONTRACT; |
| 827 | _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK); |
| 828 | |
| 829 | return (slotNum & (VTABLE_SLOTS_PER_CHUNK - 1)); |
| 830 | } |
| 831 | |
| 832 | //========================================================================================== |
| 833 | inline DWORD MethodTable::GetNumVtableIndirections(DWORD wNumVirtuals) |
| 834 | { |
| 835 | LIMITED_METHOD_DAC_CONTRACT; |
| 836 | _ASSERTE((1 << VTABLE_SLOTS_PER_CHUNK_LOG2) == VTABLE_SLOTS_PER_CHUNK); |
| 837 | |
| 838 | return (wNumVirtuals + (VTABLE_SLOTS_PER_CHUNK - 1)) >> VTABLE_SLOTS_PER_CHUNK_LOG2; |
| 839 | } |
| 840 | |
| 841 | //========================================================================================== |
| 842 | inline DPTR(MethodTable::VTableIndir_t) MethodTable::GetVtableIndirections() |
| 843 | { |
| 844 | LIMITED_METHOD_DAC_CONTRACT; |
| 845 | return dac_cast<DPTR(VTableIndir_t)>(dac_cast<TADDR>(this) + sizeof(MethodTable)); |
| 846 | } |
| 847 | |
| 848 | //========================================================================================== |
| 849 | inline DWORD MethodTable::GetNumVtableIndirections() |
| 850 | { |
| 851 | WRAPPER_NO_CONTRACT; |
| 852 | |
| 853 | return GetNumVtableIndirections(GetNumVirtuals_NoLogging()); |
| 854 | } |
| 855 | |
| 856 | //========================================================================================== |
| 857 | inline MethodTable::VtableIndirectionSlotIterator::VtableIndirectionSlotIterator(MethodTable *pMT) |
| 858 | : m_pSlot(pMT->GetVtableIndirections()), |
| 859 | m_i((DWORD) -1), |
| 860 | m_count(pMT->GetNumVtableIndirections()), |
| 861 | m_pMT(pMT) |
| 862 | { |
| 863 | WRAPPER_NO_CONTRACT; |
| 864 | } |
| 865 | |
| 866 | //========================================================================================== |
| 867 | inline MethodTable::VtableIndirectionSlotIterator::VtableIndirectionSlotIterator(MethodTable *pMT, DWORD index) |
| 868 | : m_pSlot(pMT->GetVtableIndirections() + index), |
| 869 | m_i(index), |
| 870 | m_count(pMT->GetNumVtableIndirections()), |
| 871 | m_pMT(pMT) |
| 872 | { |
| 873 | WRAPPER_NO_CONTRACT; |
| 874 | PRECONDITION(index != (DWORD) -1 && index < m_count); |
| 875 | } |
| 876 | |
| 877 | //========================================================================================== |
| 878 | inline BOOL MethodTable::VtableIndirectionSlotIterator::Next() |
| 879 | { |
| 880 | LIMITED_METHOD_DAC_CONTRACT; |
| 881 | PRECONDITION(!Finished()); |
| 882 | if (m_i != (DWORD) -1) |
| 883 | m_pSlot++; |
| 884 | return (++m_i < m_count); |
| 885 | } |
| 886 | |
| 887 | //========================================================================================== |
| 888 | inline BOOL MethodTable::VtableIndirectionSlotIterator::Finished() |
| 889 | { |
| 890 | LIMITED_METHOD_DAC_CONTRACT; |
| 891 | return (m_i == m_count); |
| 892 | } |
| 893 | |
| 894 | //========================================================================================== |
| 895 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetIndex() |
| 896 | { |
| 897 | LIMITED_METHOD_DAC_CONTRACT; |
| 898 | return m_i; |
| 899 | } |
| 900 | |
| 901 | //========================================================================================== |
| 902 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetOffsetFromMethodTable() |
| 903 | { |
| 904 | WRAPPER_NO_CONTRACT; |
| 905 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
| 906 | |
| 907 | return GetVtableOffset() + sizeof(VTableIndir_t) * m_i; |
| 908 | } |
| 909 | |
| 910 | //========================================================================================== |
| 911 | inline DPTR(MethodTable::VTableIndir2_t) MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot() |
| 912 | { |
| 913 | LIMITED_METHOD_DAC_CONTRACT; |
| 914 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
| 915 | |
| 916 | return m_pSlot->GetValueMaybeNull(dac_cast<TADDR>(m_pSlot)); |
| 917 | } |
| 918 | |
| 919 | //========================================================================================== |
| 920 | #ifndef DACCESS_COMPILE |
| 921 | inline void MethodTable::VtableIndirectionSlotIterator::SetIndirectionSlot(DPTR(MethodTable::VTableIndir2_t) pChunk) |
| 922 | { |
| 923 | LIMITED_METHOD_CONTRACT; |
| 924 | m_pSlot->SetValueMaybeNull(pChunk); |
| 925 | } |
| 926 | #endif |
| 927 | |
| 928 | //========================================================================================== |
| 929 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetStartSlot() |
| 930 | { |
| 931 | WRAPPER_NO_CONTRACT; |
| 932 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
| 933 | |
| 934 | return GetStartSlotForVtableIndirection(m_i, m_pMT->GetNumVirtuals()); |
| 935 | } |
| 936 | |
| 937 | //========================================================================================== |
| 938 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetEndSlot() |
| 939 | { |
| 940 | WRAPPER_NO_CONTRACT; |
| 941 | PRECONDITION(m_i != (DWORD) -1 && m_i < m_count); |
| 942 | |
| 943 | return GetEndSlotForVtableIndirection(m_i, m_pMT->GetNumVirtuals()); |
| 944 | } |
| 945 | |
| 946 | //========================================================================================== |
| 947 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetNumSlots() |
| 948 | { |
| 949 | WRAPPER_NO_CONTRACT; |
| 950 | |
| 951 | return GetEndSlot() - GetStartSlot(); |
| 952 | } |
| 953 | |
| 954 | //========================================================================================== |
| 955 | inline DWORD MethodTable::VtableIndirectionSlotIterator::GetSize() |
| 956 | { |
| 957 | WRAPPER_NO_CONTRACT; |
| 958 | |
| 959 | return GetNumSlots() * sizeof(PCODE); |
| 960 | } |
| 961 | |
| 962 | //========================================================================================== |
| 963 | // Create a new iterator over the vtable indirection slots |
| 964 | // The iterator starts just before the first item |
| 965 | inline MethodTable::VtableIndirectionSlotIterator MethodTable::IterateVtableIndirectionSlots() |
| 966 | { |
| 967 | WRAPPER_NO_CONTRACT; |
| 968 | return VtableIndirectionSlotIterator(this); |
| 969 | } |
| 970 | |
| 971 | //========================================================================================== |
| 972 | // Create a new iterator over the vtable indirection slots, starting at the index specified |
| 973 | inline MethodTable::VtableIndirectionSlotIterator MethodTable::IterateVtableIndirectionSlotsFrom(DWORD index) |
| 974 | { |
| 975 | WRAPPER_NO_CONTRACT; |
| 976 | return VtableIndirectionSlotIterator(this, index); |
| 977 | } |
| 978 | |
| 979 | #ifndef DACCESS_COMPILE |
| 980 | #ifdef FEATURE_COMINTEROP |
| 981 | |
| 982 | //========================================================================================== |
| 983 | inline ComCallWrapperTemplate *MethodTable::GetComCallWrapperTemplate() |
| 984 | { |
| 985 | LIMITED_METHOD_CONTRACT; |
| 986 | if (HasCCWTemplate()) |
| 987 | { |
| 988 | return *GetCCWTemplatePtr(); |
| 989 | } |
| 990 | return GetClass()->GetComCallWrapperTemplate(); |
| 991 | } |
| 992 | |
| 993 | //========================================================================================== |
| 994 | inline BOOL MethodTable::SetComCallWrapperTemplate(ComCallWrapperTemplate *pTemplate) |
| 995 | { |
| 996 | CONTRACTL |
| 997 | { |
| 998 | THROWS; |
| 999 | GC_NOTRIGGER; |
| 1000 | MODE_ANY; |
| 1001 | } |
| 1002 | CONTRACTL_END; |
| 1003 | |
| 1004 | if (HasCCWTemplate()) |
| 1005 | { |
| 1006 | TypeHandle th(this); |
| 1007 | g_IBCLogger.LogTypeMethodTableWriteableAccess(&th); |
| 1008 | return (InterlockedCompareExchangeT(EnsureWritablePages(GetCCWTemplatePtr()), pTemplate, NULL) == NULL); |
| 1009 | } |
| 1010 | g_IBCLogger.LogEEClassCOWTableAccess(this); |
| 1011 | return GetClass_NoLogging()->SetComCallWrapperTemplate(pTemplate); |
| 1012 | } |
| 1013 | |
| 1014 | #ifdef FEATURE_COMINTEROP_UNMANAGED_ACTIVATION |
| 1015 | //========================================================================================== |
| 1016 | inline ClassFactoryBase *MethodTable::GetComClassFactory() |
| 1017 | { |
| 1018 | LIMITED_METHOD_CONTRACT; |
| 1019 | return GetClass()->GetComClassFactory(); |
| 1020 | } |
| 1021 | |
| 1022 | //========================================================================================== |
| 1023 | inline BOOL MethodTable::SetComClassFactory(ClassFactoryBase *pFactory) |
| 1024 | { |
| 1025 | CONTRACTL |
| 1026 | { |
| 1027 | THROWS; |
| 1028 | GC_NOTRIGGER; |
| 1029 | MODE_ANY; |
| 1030 | } |
| 1031 | CONTRACTL_END; |
| 1032 | |
| 1033 | g_IBCLogger.LogEEClassCOWTableAccess(this); |
| 1034 | return GetClass_NoLogging()->SetComClassFactory(pFactory); |
| 1035 | } |
| 1036 | #endif // FEATURE_COMINTEROP_UNMANAGED_ACTIVATION |
| 1037 | #endif // FEATURE_COMINTEROP |
| 1038 | #endif // DACCESS_COMPILE |
| 1039 | |
| 1040 | #ifdef FEATURE_COMINTEROP |
| 1041 | //========================================================================================== |
| 1042 | inline BOOL MethodTable::IsProjectedFromWinRT() |
| 1043 | { |
| 1044 | LIMITED_METHOD_DAC_CONTRACT; |
| 1045 | _ASSERTE(GetClass()); |
| 1046 | return GetClass()->IsProjectedFromWinRT(); |
| 1047 | } |
| 1048 | |
| 1049 | //========================================================================================== |
| 1050 | inline BOOL MethodTable::IsExportedToWinRT() |
| 1051 | { |
| 1052 | LIMITED_METHOD_DAC_CONTRACT; |
| 1053 | _ASSERTE(GetClass()); |
| 1054 | return GetClass()->IsExportedToWinRT(); |
| 1055 | } |
| 1056 | |
| 1057 | //========================================================================================== |
| 1058 | inline BOOL MethodTable::IsWinRTDelegate() |
| 1059 | { |
| 1060 | LIMITED_METHOD_DAC_CONTRACT; |
| 1061 | return (IsProjectedFromWinRT() && IsDelegate()) || IsWinRTRedirectedDelegate(); |
| 1062 | } |
| 1063 | |
| 1064 | #else // FEATURE_COMINTEROP |
| 1065 | |
| 1066 | //========================================================================================== |
| 1067 | inline BOOL MethodTable::IsProjectedFromWinRT() |
| 1068 | { |
| 1069 | LIMITED_METHOD_DAC_CONTRACT; |
| 1070 | return FALSE; |
| 1071 | } |
| 1072 | |
| 1073 | //========================================================================================== |
| 1074 | inline BOOL MethodTable::IsExportedToWinRT() |
| 1075 | { |
| 1076 | LIMITED_METHOD_DAC_CONTRACT; |
| 1077 | return FALSE; |
| 1078 | } |
| 1079 | |
| 1080 | //========================================================================================== |
| 1081 | inline BOOL MethodTable::IsWinRTDelegate() |
| 1082 | { |
| 1083 | LIMITED_METHOD_DAC_CONTRACT; |
| 1084 | return FALSE; |
| 1085 | } |
| 1086 | |
| 1087 | #endif // FEATURE_COMINTEROP |
| 1088 | |
| 1089 | //========================================================================================== |
| 1090 | inline UINT32 MethodTable::GetNativeSize() |
| 1091 | { |
| 1092 | LIMITED_METHOD_CONTRACT; |
| 1093 | _ASSERTE(GetClass()); |
| 1094 | return GetClass()->GetNativeSize(); |
| 1095 | } |
| 1096 | |
| 1097 | //========================================================================================== |
| 1098 | inline PTR_MethodTable MethodTable::GetCanonicalMethodTable() |
| 1099 | { |
| 1100 | LIMITED_METHOD_DAC_CONTRACT; |
| 1101 | |
| 1102 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
| 1103 | |
| 1104 | #ifdef _DEBUG |
| 1105 | LowBits lowBits = union_getLowBits(addr); |
| 1106 | if (lowBits == UNION_EECLASS) |
| 1107 | { |
| 1108 | return dac_cast<PTR_MethodTable>(this); |
| 1109 | } |
| 1110 | else if (lowBits == UNION_METHODTABLE) |
| 1111 | { |
| 1112 | // pointer to canonical MethodTable. |
| 1113 | return PTR_MethodTable(union_getPointer(addr)); |
| 1114 | } |
| 1115 | #ifdef FEATURE_PREJIT |
| 1116 | else if (lowBits == UNION_INDIRECTION) |
| 1117 | { |
| 1118 | return PTR_MethodTable(*PTR_TADDR(union_getPointer(addr))); |
| 1119 | } |
| 1120 | #endif |
| 1121 | _ASSERTE(!"Malformed m_pCanonMT in MethodTable" ); |
| 1122 | return NULL; |
| 1123 | #else |
| 1124 | |
| 1125 | if ((addr & 2) == 0) |
| 1126 | return dac_cast<PTR_MethodTable>(this); |
| 1127 | |
| 1128 | #ifdef FEATURE_PREJIT |
| 1129 | if ((addr & 1) != 0) |
| 1130 | return PTR_MethodTable(*PTR_TADDR(addr - 3)); |
| 1131 | #endif |
| 1132 | |
| 1133 | return PTR_MethodTable(addr - 2); |
| 1134 | #endif |
| 1135 | } |
| 1136 | |
| 1137 | //========================================================================================== |
| 1138 | inline TADDR MethodTable::GetCanonicalMethodTableFixup() |
| 1139 | { |
| 1140 | LIMITED_METHOD_DAC_CONTRACT; |
| 1141 | |
| 1142 | #ifdef FEATURE_PREJIT |
| 1143 | TADDR addr = ReadPointer(this, &MethodTable::m_pCanonMT); |
| 1144 | LowBits lowBits = union_getLowBits(addr); |
| 1145 | if (lowBits == UNION_INDIRECTION) |
| 1146 | { |
| 1147 | // pointer to canonical MethodTable. |
| 1148 | return *PTR_TADDR(union_getPointer(addr)); |
| 1149 | } |
| 1150 | else |
| 1151 | #endif |
| 1152 | { |
| 1153 | return NULL; |
| 1154 | } |
| 1155 | } |
| 1156 | |
| 1157 | //========================================================================================== |
| 1158 | #ifndef DACCESS_COMPILE |
| 1159 | FORCEINLINE BOOL MethodTable::IsEquivalentTo(MethodTable *pOtherMT COMMA_INDEBUG(TypeHandlePairList *pVisited /*= NULL*/)) |
| 1160 | { |
| 1161 | WRAPPER_NO_CONTRACT; |
| 1162 | |
| 1163 | if (this == pOtherMT) |
| 1164 | return TRUE; |
| 1165 | |
| 1166 | #ifdef FEATURE_TYPEEQUIVALENCE |
| 1167 | // bail early for normal types |
| 1168 | if (!HasTypeEquivalence() || !pOtherMT->HasTypeEquivalence()) |
| 1169 | return FALSE; |
| 1170 | |
| 1171 | if (IsEquivalentTo_Worker(pOtherMT COMMA_INDEBUG(pVisited))) |
| 1172 | return TRUE; |
| 1173 | #endif // FEATURE_TYPEEQUIVALENCE |
| 1174 | |
| 1175 | return FALSE; |
| 1176 | } |
| 1177 | #endif |
| 1178 | |
| 1179 | //========================================================================================== |
| 1180 | inline IMDInternalImport* MethodTable::GetMDImport() |
| 1181 | { |
| 1182 | LIMITED_METHOD_CONTRACT; |
| 1183 | return GetModule()->GetMDImport(); |
| 1184 | } |
| 1185 | |
| 1186 | //========================================================================================== |
| 1187 | inline BOOL MethodTable::IsSealed() |
| 1188 | { |
| 1189 | LIMITED_METHOD_CONTRACT; |
| 1190 | return GetClass()->IsSealed(); |
| 1191 | } |
| 1192 | |
| 1193 | //========================================================================================== |
| 1194 | inline BOOL MethodTable::IsManagedSequential() |
| 1195 | { |
| 1196 | LIMITED_METHOD_CONTRACT; |
| 1197 | return GetClass()->IsManagedSequential(); |
| 1198 | } |
| 1199 | |
| 1200 | //========================================================================================== |
| 1201 | inline BOOL MethodTable::HasExplicitSize() |
| 1202 | { |
| 1203 | LIMITED_METHOD_CONTRACT; |
| 1204 | return GetClass()->HasExplicitSize(); |
| 1205 | } |
| 1206 | |
| 1207 | //========================================================================================== |
| 1208 | inline DWORD MethodTable::GetPerInstInfoSize() |
| 1209 | { |
| 1210 | LIMITED_METHOD_DAC_CONTRACT; |
| 1211 | return GetNumDicts() * sizeof(PerInstInfoElem_t); |
| 1212 | } |
| 1213 | |
| 1214 | //========================================================================================== |
| 1215 | inline EEClassLayoutInfo *MethodTable::GetLayoutInfo() |
| 1216 | { |
| 1217 | LIMITED_METHOD_CONTRACT; |
| 1218 | PRECONDITION(HasLayout()); |
| 1219 | return GetClass()->GetLayoutInfo(); |
| 1220 | } |
| 1221 | |
| 1222 | //========================================================================================== |
| 1223 | // These come after the pointers to the generic dictionaries (if any) |
| 1224 | inline DWORD MethodTable::GetInterfaceMapSize() |
| 1225 | { |
| 1226 | LIMITED_METHOD_DAC_CONTRACT; |
| 1227 | |
| 1228 | DWORD cbIMap = GetNumInterfaces() * sizeof(InterfaceInfo_t); |
| 1229 | #ifdef FEATURE_COMINTEROP |
| 1230 | cbIMap += (HasDynamicInterfaceMap() ? sizeof(DWORD_PTR) : 0); |
| 1231 | #endif |
| 1232 | return cbIMap; |
| 1233 | } |
| 1234 | |
| 1235 | //========================================================================================== |
| 1236 | // These are the generic dictionaries themselves and are come after |
| 1237 | // the interface map. In principle they need not be inline in the method table. |
| 1238 | inline DWORD MethodTable::GetInstAndDictSize() |
| 1239 | { |
| 1240 | LIMITED_METHOD_DAC_CONTRACT; |
| 1241 | |
| 1242 | if (!HasInstantiation()) |
| 1243 | return 0; |
| 1244 | else |
| 1245 | return DictionaryLayout::GetFirstDictionaryBucketSize(GetNumGenericArgs(), GetClass()->GetDictionaryLayout()); |
| 1246 | } |
| 1247 | |
| 1248 | //========================================================================================== |
| 1249 | inline BOOL MethodTable::IsSharedByGenericInstantiations() |
| 1250 | { |
| 1251 | LIMITED_METHOD_DAC_CONTRACT; |
| 1252 | |
| 1253 | g_IBCLogger.LogMethodTableAccess(this); |
| 1254 | |
| 1255 | return TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_SharedInst); |
| 1256 | } |
| 1257 | |
| 1258 | //========================================================================================== |
| 1259 | inline BOOL MethodTable::IsCanonicalMethodTable() |
| 1260 | { |
| 1261 | LIMITED_METHOD_DAC_CONTRACT; |
| 1262 | |
| 1263 | return (union_getLowBits(ReadPointer(this, &MethodTable::m_pCanonMT)) == UNION_EECLASS); |
| 1264 | } |
| 1265 | |
| 1266 | //========================================================================================== |
| 1267 | FORCEINLINE BOOL MethodTable::HasInstantiation() |
| 1268 | { |
| 1269 | LIMITED_METHOD_DAC_CONTRACT; |
| 1270 | |
| 1271 | // Generics flags cannot be expressed in terms of GetFlag() |
| 1272 | return !TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_NonGeneric); |
| 1273 | } |
| 1274 | |
| 1275 | //========================================================================================== |
| 1276 | inline void MethodTable::SetHasInstantiation(BOOL fTypicalInstantiation, BOOL fSharedByGenericInstantiations) |
| 1277 | { |
| 1278 | LIMITED_METHOD_CONTRACT; |
| 1279 | _ASSERTE(!IsStringOrArray()); |
| 1280 | SetFlag(fTypicalInstantiation ? enum_flag_GenericsMask_TypicalInst : |
| 1281 | (fSharedByGenericInstantiations ? enum_flag_GenericsMask_SharedInst : enum_flag_GenericsMask_GenericInst)); |
| 1282 | } |
| 1283 | //========================================================================================== |
| 1284 | inline BOOL MethodTable::IsGenericTypeDefinition() |
| 1285 | { |
| 1286 | LIMITED_METHOD_DAC_CONTRACT; |
| 1287 | |
| 1288 | // Generics flags cannot be expressed in terms of GetFlag() |
| 1289 | return TestFlagWithMask(enum_flag_GenericsMask, enum_flag_GenericsMask_TypicalInst); |
| 1290 | } |
| 1291 | |
| 1292 | //========================================================================================== |
| 1293 | inline PTR_InterfaceInfo MethodTable::GetInterfaceMap() |
| 1294 | { |
| 1295 | LIMITED_METHOD_DAC_CONTRACT; |
| 1296 | |
| 1297 | return ReadPointer(this, &MethodTable::m_pInterfaceMap); |
| 1298 | } |
| 1299 | |
| 1300 | //========================================================================================== |
| 1301 | FORCEINLINE TADDR MethodTable::GetMultipurposeSlotPtr(WFLAGS2_ENUM flag, const BYTE * offsets) |
| 1302 | { |
| 1303 | LIMITED_METHOD_DAC_CONTRACT; |
| 1304 | |
| 1305 | _ASSERTE(GetFlag(flag)); |
| 1306 | |
| 1307 | DWORD offset = offsets[GetFlag((WFLAGS2_ENUM)(flag - 1))]; |
| 1308 | |
| 1309 | if (offset >= sizeof(MethodTable)) { |
| 1310 | offset += GetNumVtableIndirections() * sizeof(VTableIndir_t); |
| 1311 | } |
| 1312 | |
| 1313 | return dac_cast<TADDR>(this) + offset; |
| 1314 | } |
| 1315 | |
| 1316 | //========================================================================================== |
| 1317 | // This method is dependent on the declared order of optional members |
| 1318 | // If you add or remove an optional member or reorder them please change this method |
| 1319 | FORCEINLINE DWORD MethodTable::GetOffsetOfOptionalMember(OptionalMemberId id) |
| 1320 | { |
| 1321 | LIMITED_METHOD_CONTRACT; |
| 1322 | |
| 1323 | DWORD offset = c_OptionalMembersStartOffsets[GetFlag(enum_flag_MultipurposeSlotsMask)]; |
| 1324 | |
| 1325 | offset += GetNumVtableIndirections() * sizeof(VTableIndir_t); |
| 1326 | |
| 1327 | #undef METHODTABLE_OPTIONAL_MEMBER |
| 1328 | #define METHODTABLE_OPTIONAL_MEMBER(NAME, TYPE, GETTER) \ |
| 1329 | if (id == OptionalMember_##NAME) { \ |
| 1330 | return offset; \ |
| 1331 | } \ |
| 1332 | C_ASSERT(sizeof(TYPE) % sizeof(UINT_PTR) == 0); /* To insure proper alignment */ \ |
| 1333 | if (Has##NAME()) { \ |
| 1334 | offset += sizeof(TYPE); \ |
| 1335 | } |
| 1336 | |
| 1337 | METHODTABLE_OPTIONAL_MEMBERS() |
| 1338 | |
| 1339 | _ASSERTE(!"Wrong optional member" || id == OptionalMember_Count); |
| 1340 | return offset; |
| 1341 | } |
| 1342 | |
| 1343 | //========================================================================================== |
| 1344 | inline DWORD MethodTable::GetOptionalMembersAllocationSize(DWORD dwMultipurposeSlotsMask, |
| 1345 | BOOL needsGenericsStaticsInfo, |
| 1346 | BOOL needsGuidInfo, |
| 1347 | BOOL needsCCWTemplate, |
| 1348 | BOOL needsRCWPerTypeData, |
| 1349 | BOOL needsTokenOverflow) |
| 1350 | { |
| 1351 | LIMITED_METHOD_CONTRACT; |
| 1352 | |
| 1353 | DWORD size = c_OptionalMembersStartOffsets[dwMultipurposeSlotsMask] - sizeof(MethodTable); |
| 1354 | |
| 1355 | if (needsGenericsStaticsInfo) |
| 1356 | size += sizeof(GenericsStaticsInfo); |
| 1357 | if (needsGuidInfo) |
| 1358 | size += sizeof(UINT_PTR); |
| 1359 | if (needsCCWTemplate) |
| 1360 | size += sizeof(UINT_PTR); |
| 1361 | if (needsRCWPerTypeData) |
| 1362 | size += sizeof(UINT_PTR); |
| 1363 | if (dwMultipurposeSlotsMask & enum_flag_HasInterfaceMap) |
| 1364 | size += sizeof(UINT_PTR); |
| 1365 | if (needsTokenOverflow) |
| 1366 | size += sizeof(UINT_PTR); |
| 1367 | |
| 1368 | return size; |
| 1369 | } |
| 1370 | |
| 1371 | inline DWORD MethodTable::() |
| 1372 | { |
| 1373 | WRAPPER_NO_CONTRACT; |
| 1374 | |
| 1375 | return GetEndOffsetOfOptionalMembers() - GetStartOffsetOfOptionalMembers(); |
| 1376 | } |
| 1377 | |
| 1378 | #ifndef DACCESS_COMPILE |
| 1379 | |
| 1380 | //========================================================================================== |
| 1381 | inline PTR_BYTE MethodTable::GetNonGCStaticsBasePointer() |
| 1382 | { |
| 1383 | WRAPPER_NO_CONTRACT; |
| 1384 | return GetDomainLocalModule()->GetNonGCStaticsBasePointer(this); |
| 1385 | } |
| 1386 | |
| 1387 | //========================================================================================== |
| 1388 | inline PTR_BYTE MethodTable::GetGCStaticsBasePointer() |
| 1389 | { |
| 1390 | WRAPPER_NO_CONTRACT; |
| 1391 | return GetDomainLocalModule()->GetGCStaticsBasePointer(this); |
| 1392 | } |
| 1393 | |
| 1394 | //========================================================================================== |
| 1395 | inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer() |
| 1396 | { |
| 1397 | CONTRACTL |
| 1398 | { |
| 1399 | NOTHROW; |
| 1400 | GC_NOTRIGGER; |
| 1401 | MODE_ANY; |
| 1402 | } |
| 1403 | CONTRACTL_END; |
| 1404 | |
| 1405 | // Get the current thread |
| 1406 | PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread()); |
| 1407 | |
| 1408 | // Get the current module's ModuleIndex |
| 1409 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
| 1410 | |
| 1411 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
| 1412 | |
| 1413 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
| 1414 | if (pTLM == NULL) |
| 1415 | return NULL; |
| 1416 | |
| 1417 | return pTLM->GetNonGCStaticsBasePointer(this); |
| 1418 | } |
| 1419 | |
| 1420 | //========================================================================================== |
| 1421 | inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer() |
| 1422 | { |
| 1423 | CONTRACTL |
| 1424 | { |
| 1425 | NOTHROW; |
| 1426 | GC_NOTRIGGER; |
| 1427 | MODE_COOPERATIVE; |
| 1428 | } |
| 1429 | CONTRACTL_END; |
| 1430 | |
| 1431 | // Get the current thread |
| 1432 | PTR_Thread pThread = dac_cast<PTR_Thread>(GetThread()); |
| 1433 | |
| 1434 | // Get the current module's ModuleIndex |
| 1435 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
| 1436 | |
| 1437 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
| 1438 | |
| 1439 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
| 1440 | if (pTLM == NULL) |
| 1441 | return NULL; |
| 1442 | |
| 1443 | return pTLM->GetGCStaticsBasePointer(this); |
| 1444 | } |
| 1445 | |
| 1446 | #endif //!DACCESS_COMPILE |
| 1447 | |
| 1448 | //========================================================================================== |
| 1449 | inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread) |
| 1450 | { |
| 1451 | LIMITED_METHOD_DAC_CONTRACT; |
| 1452 | |
| 1453 | // Get the current module's ModuleIndex |
| 1454 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
| 1455 | |
| 1456 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
| 1457 | |
| 1458 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
| 1459 | if (pTLM == NULL) |
| 1460 | return NULL; |
| 1461 | |
| 1462 | return pTLM->GetNonGCStaticsBasePointer(this); |
| 1463 | } |
| 1464 | |
| 1465 | //========================================================================================== |
| 1466 | inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer(PTR_Thread pThread) |
| 1467 | { |
| 1468 | LIMITED_METHOD_DAC_CONTRACT; |
| 1469 | |
| 1470 | // Get the current module's ModuleIndex |
| 1471 | ModuleIndex index = GetModuleForStatics()->GetModuleIndex(); |
| 1472 | |
| 1473 | PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread); |
| 1474 | |
| 1475 | PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index); |
| 1476 | if (pTLM == NULL) |
| 1477 | return NULL; |
| 1478 | |
| 1479 | return pTLM->GetGCStaticsBasePointer(this); |
| 1480 | } |
| 1481 | |
| 1482 | //========================================================================================== |
| 1483 | inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule(AppDomain * pAppDomain) |
| 1484 | { |
| 1485 | WRAPPER_NO_CONTRACT; |
| 1486 | return GetModuleForStatics()->GetDomainLocalModule(pAppDomain); |
| 1487 | } |
| 1488 | |
| 1489 | #ifndef DACCESS_COMPILE |
| 1490 | //========================================================================================== |
| 1491 | inline PTR_DomainLocalModule MethodTable::GetDomainLocalModule() |
| 1492 | { |
| 1493 | WRAPPER_NO_CONTRACT; |
| 1494 | return GetModuleForStatics()->GetDomainLocalModule(); |
| 1495 | } |
| 1496 | #endif //!DACCESS_COMPILE |
| 1497 | |
| 1498 | //========================================================================================== |
| 1499 | inline OBJECTREF MethodTable::AllocateNoChecks() |
| 1500 | { |
| 1501 | CONTRACTL |
| 1502 | { |
| 1503 | MODE_COOPERATIVE; |
| 1504 | GC_TRIGGERS; |
| 1505 | THROWS; |
| 1506 | } |
| 1507 | CONTRACTL_END; |
| 1508 | |
| 1509 | // we know an instance of this class already exists in the same appdomain |
| 1510 | // therefore, some checks become redundant. |
| 1511 | // this currently only happens for Delegate.Combine |
| 1512 | CONSISTENCY_CHECK(IsRestored_NoLogging()); |
| 1513 | |
| 1514 | CONSISTENCY_CHECK(CheckInstanceActivated()); |
| 1515 | |
| 1516 | return AllocateObject(this); |
| 1517 | } |
| 1518 | |
| 1519 | |
| 1520 | //========================================================================================== |
| 1521 | inline DWORD MethodTable::GetClassIndex() |
| 1522 | { |
| 1523 | WRAPPER_NO_CONTRACT; |
| 1524 | return GetClassIndexFromToken(GetCl()); |
| 1525 | } |
| 1526 | |
| 1527 | #ifndef DACCESS_COMPILE |
| 1528 | //========================================================================================== |
| 1529 | // unbox src into dest, making sure src is of the correct type. |
| 1530 | |
| 1531 | inline BOOL MethodTable::UnBoxInto(void *dest, OBJECTREF src) |
| 1532 | { |
| 1533 | CONTRACTL |
| 1534 | { |
| 1535 | NOTHROW; |
| 1536 | GC_NOTRIGGER; |
| 1537 | SO_TOLERANT; |
| 1538 | MODE_COOPERATIVE; |
| 1539 | } |
| 1540 | CONTRACTL_END; |
| 1541 | |
| 1542 | if (Nullable::IsNullableType(TypeHandle(this))) |
| 1543 | return Nullable::UnBoxNoGC(dest, src, this); |
| 1544 | else |
| 1545 | { |
| 1546 | if (src == NULL || src->GetMethodTable() != this) |
| 1547 | return FALSE; |
| 1548 | |
| 1549 | CopyValueClass(dest, src->UnBox(), this, src->GetAppDomain()); |
| 1550 | } |
| 1551 | return TRUE; |
| 1552 | } |
| 1553 | |
| 1554 | //========================================================================================== |
| 1555 | // unbox src into argument, making sure src is of the correct type. |
| 1556 | |
| 1557 | inline BOOL MethodTable::UnBoxIntoArg(ArgDestination *argDest, OBJECTREF src) |
| 1558 | { |
| 1559 | CONTRACTL |
| 1560 | { |
| 1561 | NOTHROW; |
| 1562 | GC_NOTRIGGER; |
| 1563 | SO_TOLERANT; |
| 1564 | MODE_COOPERATIVE; |
| 1565 | } |
| 1566 | CONTRACTL_END; |
| 1567 | |
| 1568 | if (Nullable::IsNullableType(TypeHandle(this))) |
| 1569 | return Nullable::UnBoxIntoArgNoGC(argDest, src, this); |
| 1570 | else |
| 1571 | { |
| 1572 | if (src == NULL || src->GetMethodTable() != this) |
| 1573 | return FALSE; |
| 1574 | |
| 1575 | CopyValueClassArg(argDest, src->UnBox(), this, src->GetAppDomain(), 0); |
| 1576 | } |
| 1577 | return TRUE; |
| 1578 | } |
| 1579 | |
| 1580 | //========================================================================================== |
| 1581 | // unbox src into dest, No checks are done |
| 1582 | |
| 1583 | inline void MethodTable::UnBoxIntoUnchecked(void *dest, OBJECTREF src) |
| 1584 | { |
| 1585 | CONTRACTL |
| 1586 | { |
| 1587 | NOTHROW; |
| 1588 | GC_NOTRIGGER; |
| 1589 | SO_TOLERANT; |
| 1590 | MODE_COOPERATIVE; |
| 1591 | } |
| 1592 | CONTRACTL_END; |
| 1593 | |
| 1594 | if (Nullable::IsNullableType(TypeHandle(this))) { |
| 1595 | BOOL ret; |
| 1596 | ret = Nullable::UnBoxNoGC(dest, src, this); |
| 1597 | _ASSERTE(ret); |
| 1598 | } |
| 1599 | else |
| 1600 | { |
| 1601 | _ASSERTE(src->GetMethodTable()->GetNumInstanceFieldBytes() == GetNumInstanceFieldBytes()); |
| 1602 | |
| 1603 | CopyValueClass(dest, src->UnBox(), this, src->GetAppDomain()); |
| 1604 | } |
| 1605 | } |
| 1606 | #endif |
| 1607 | //========================================================================================== |
| 1608 | __forceinline TypeHandle::CastResult MethodTable::CanCastToClassOrInterfaceNoGC(MethodTable *pTargetMT) |
| 1609 | { |
| 1610 | CONTRACTL |
| 1611 | { |
| 1612 | NOTHROW; |
| 1613 | GC_NOTRIGGER; |
| 1614 | MODE_ANY; |
| 1615 | INSTANCE_CHECK; |
| 1616 | SO_TOLERANT; |
| 1617 | PRECONDITION(CheckPointer(pTargetMT)); |
| 1618 | PRECONDITION(!pTargetMT->IsArray()); |
| 1619 | } |
| 1620 | CONTRACTL_END |
| 1621 | |
| 1622 | if (pTargetMT->IsInterface()) |
| 1623 | return CanCastToInterfaceNoGC(pTargetMT); |
| 1624 | else |
| 1625 | return CanCastToClassNoGC(pTargetMT); |
| 1626 | } |
| 1627 | |
| 1628 | //========================================================================================== |
| 1629 | inline BOOL MethodTable::CanCastToClassOrInterface(MethodTable *pTargetMT, TypeHandlePairList *pVisited) |
| 1630 | { |
| 1631 | CONTRACTL |
| 1632 | { |
| 1633 | THROWS; |
| 1634 | GC_TRIGGERS; |
| 1635 | MODE_ANY; |
| 1636 | INSTANCE_CHECK; |
| 1637 | PRECONDITION(CheckPointer(pTargetMT)); |
| 1638 | PRECONDITION(!pTargetMT->IsArray()); |
| 1639 | PRECONDITION(IsRestored_NoLogging()); |
| 1640 | } |
| 1641 | CONTRACTL_END |
| 1642 | |
| 1643 | if (pTargetMT->IsInterface()) |
| 1644 | return CanCastToInterface(pTargetMT, pVisited); |
| 1645 | else |
| 1646 | return CanCastToClass(pTargetMT, pVisited); |
| 1647 | } |
| 1648 | |
| 1649 | //========================================================================================== |
| 1650 | FORCEINLINE PTR_Module MethodTable::GetGenericsStaticsModuleAndID(DWORD * pID) |
| 1651 | { |
| 1652 | CONTRACTL |
| 1653 | { |
| 1654 | NOTHROW; |
| 1655 | GC_NOTRIGGER; |
| 1656 | MODE_ANY; |
| 1657 | SO_TOLERANT; |
| 1658 | SUPPORTS_DAC; |
| 1659 | } |
| 1660 | CONTRACTL_END |
| 1661 | |
| 1662 | _ASSERTE(HasGenericsStaticsInfo()); |
| 1663 | |
| 1664 | #ifdef FEATURE_PREJIT |
| 1665 | // This is performance sensitive codepath inlined into JIT helpers. Test the flag directly without |
| 1666 | // checking IsStringOrArray() first. IsStringOrArray() will always be false here. |
| 1667 | _ASSERTE(!IsStringOrArray()); |
| 1668 | if (m_dwFlags & enum_flag_StaticsMask_IfGenericsThenCrossModule) |
| 1669 | { |
| 1670 | CrossModuleGenericsStaticsInfo *pInfo = ReadPointer(this, &MethodTable::m_pWriteableData)->GetCrossModuleGenericsStaticsInfo(); |
| 1671 | _ASSERTE(FitsIn<DWORD>(pInfo->m_DynamicTypeID) || pInfo->m_DynamicTypeID == (SIZE_T)-1); |
| 1672 | *pID = static_cast<DWORD>(pInfo->m_DynamicTypeID); |
| 1673 | return pInfo->m_pModuleForStatics; |
| 1674 | } |
| 1675 | #endif // FEATURE_PREJIT |
| 1676 | |
| 1677 | _ASSERTE(FitsIn<DWORD>(GetGenericsStaticsInfo()->m_DynamicTypeID) || GetGenericsStaticsInfo()->m_DynamicTypeID == (SIZE_T)-1); |
| 1678 | *pID = static_cast<DWORD>(GetGenericsStaticsInfo()->m_DynamicTypeID); |
| 1679 | return GetLoaderModule(); |
| 1680 | } |
| 1681 | |
| 1682 | //========================================================================================== |
| 1683 | inline OBJECTHANDLE MethodTable::GetLoaderAllocatorObjectHandle() |
| 1684 | { |
| 1685 | LIMITED_METHOD_CONTRACT; |
| 1686 | return GetLoaderAllocator()->GetLoaderAllocatorObjectHandle(); |
| 1687 | } |
| 1688 | |
| 1689 | //========================================================================================== |
| 1690 | FORCEINLINE OBJECTREF MethodTable::GetManagedClassObjectIfExists() |
| 1691 | { |
| 1692 | LIMITED_METHOD_CONTRACT; |
| 1693 | |
| 1694 | // Logging will be done by the slow path |
| 1695 | LOADERHANDLE handle = GetWriteableData_NoLogging()->GetExposedClassObjectHandle(); |
| 1696 | |
| 1697 | OBJECTREF retVal; |
| 1698 | |
| 1699 | // GET_LOADERHANDLE_VALUE_FAST macro is inlined here to let us give hint to the compiler |
| 1700 | // when the return value is not null. |
| 1701 | if (!LoaderAllocator::GetHandleValueFast(handle, &retVal) && |
| 1702 | !GetLoaderAllocator()->GetHandleValueFastPhase2(handle, &retVal)) |
| 1703 | { |
| 1704 | return NULL; |
| 1705 | } |
| 1706 | |
| 1707 | COMPILER_ASSUME(retVal != NULL); |
| 1708 | return retVal; |
| 1709 | } |
| 1710 | |
| 1711 | //========================================================================================== |
| 1712 | inline void MethodTable::SetIsArray(CorElementType arrayType, CorElementType elementType) |
| 1713 | { |
| 1714 | STANDARD_VM_CONTRACT; |
| 1715 | |
| 1716 | DWORD category = enum_flag_Category_Array; |
| 1717 | if (arrayType == ELEMENT_TYPE_SZARRAY) |
| 1718 | category |= enum_flag_Category_IfArrayThenSzArray; |
| 1719 | |
| 1720 | _ASSERTE((m_dwFlags & enum_flag_Category_Mask) == 0); |
| 1721 | m_dwFlags |= category; |
| 1722 | |
| 1723 | _ASSERTE(GetInternalCorElementType() == arrayType); |
| 1724 | } |
| 1725 | |
| 1726 | //========================================================================================== |
| 1727 | FORCEINLINE BOOL MethodTable::ImplementsInterfaceInline(MethodTable *pInterface) |
| 1728 | { |
| 1729 | CONTRACTL |
| 1730 | { |
| 1731 | NOTHROW; |
| 1732 | GC_NOTRIGGER; |
| 1733 | SO_TOLERANT; |
| 1734 | PRECONDITION(pInterface->IsInterface()); // class we are looking up should be an interface |
| 1735 | } |
| 1736 | CONTRACTL_END; |
| 1737 | |
| 1738 | // |
| 1739 | // Inline InterfaceMapIterator here for performance reasons |
| 1740 | // |
| 1741 | |
| 1742 | DWORD numInterfaces = GetNumInterfaces(); |
| 1743 | if (numInterfaces == 0) |
| 1744 | return FALSE; |
| 1745 | |
| 1746 | InterfaceInfo_t *pInfo = GetInterfaceMap(); |
| 1747 | |
| 1748 | do |
| 1749 | { |
| 1750 | if (pInfo->GetMethodTable() == pInterface) |
| 1751 | { |
| 1752 | // Extensible RCW's need to be handled specially because they can have interfaces |
| 1753 | // in their map that are added at runtime. These interfaces will have a start offset |
| 1754 | // of -1 to indicate this. We cannot take for granted that every instance of this |
| 1755 | // COM object has this interface so FindInterface on these interfaces is made to fail. |
| 1756 | // |
| 1757 | // However, we are only considering the statically available slots here |
| 1758 | // (m_wNumInterface doesn't contain the dynamic slots), so we can safely |
| 1759 | // ignore this detail. |
| 1760 | return TRUE; |
| 1761 | } |
| 1762 | pInfo++; |
| 1763 | } |
| 1764 | while (--numInterfaces); |
| 1765 | |
| 1766 | return FALSE; |
| 1767 | } |
| 1768 | |
| 1769 | #endif // !_METHODTABLE_INL_ |
| 1770 | |