| 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: contractimpl.cpp |
| 6 | // |
| 7 | // Keeps track of contract implementations, used primarily in stub dispatch. |
| 8 | // |
| 9 | |
| 10 | |
| 11 | // |
| 12 | |
| 13 | // |
| 14 | // ============================================================================ |
| 15 | |
| 16 | #include "common.h" // Precompiled header |
| 17 | |
| 18 | #include "contractimpl.h" |
| 19 | #include "virtualcallstub.h" |
| 20 | #include "decodemd.h" |
| 21 | |
| 22 | #ifdef FEATURE_PREJIT |
| 23 | #include "compile.h" |
| 24 | #endif |
| 25 | |
| 26 | #if defined(_DEBUG) |
| 27 | DummyGlobalContract ___contract; |
| 28 | #endif |
| 29 | |
| 30 | #ifdef LOGGING |
| 31 | //---------------------------------------------------------------------------- |
| 32 | StubDispatchStats g_sdStats = {0}; |
| 33 | #endif // LOGGING |
| 34 | |
| 35 | #ifndef DACCESS_COMPILE |
| 36 | |
| 37 | //---------------------------------------------------------------------------- |
| 38 | MethodDesc * DispatchSlot::GetMethodDesc() |
| 39 | { |
| 40 | WRAPPER_NO_CONTRACT; |
| 41 | if (IsNull()) |
| 42 | return NULL; |
| 43 | else |
| 44 | return MethodTable::GetMethodDescForSlotAddress(GetTarget()); |
| 45 | } |
| 46 | |
| 47 | //------------------------------------------------------------------------ |
| 48 | void TypeIDMap::Init(UINT32 idStartValue, UINT32 idIncrementValue, BOOL fUseFatTokensForUniqueness) |
| 49 | { |
| 50 | STANDARD_VM_CONTRACT; |
| 51 | |
| 52 | LockOwner lock = {&m_lock, IsOwnerOfCrst}; |
| 53 | m_idMap.Init(11, TRUE, &lock); |
| 54 | m_mtMap.Init(11, TRUE, &lock); |
| 55 | m_idProvider.Init(idStartValue, idIncrementValue); |
| 56 | m_entryCount = 0; |
| 57 | m_fUseFatIdsForUniqueness = fUseFatTokensForUniqueness; |
| 58 | } |
| 59 | |
| 60 | #endif // !DACCESS_COMPILE |
| 61 | |
| 62 | //------------------------------------------------------------------------ |
| 63 | // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID |
| 64 | UINT32 TypeIDMap::LookupTypeID(PTR_MethodTable pMT) |
| 65 | { |
| 66 | CONTRACTL { |
| 67 | NOTHROW; |
| 68 | SO_TOLERANT; |
| 69 | PRECONDITION(CheckPointer(GetThread())); |
| 70 | if (GetThread()->PreemptiveGCDisabled()) { GC_NOTRIGGER; } else { GC_TRIGGERS; } |
| 71 | } CONTRACTL_END; |
| 72 | |
| 73 | UINT32 id = (UINT32) m_mtMap.LookupValue((UPTR)dac_cast<TADDR>(pMT), 0); |
| 74 | _ASSERTE(!m_fUseFatIdsForUniqueness || !pMT->RequiresFatDispatchTokens() || (DispatchToken::RequiresDispatchTokenFat(id, 0))); |
| 75 | |
| 76 | return id; |
| 77 | } |
| 78 | |
| 79 | //------------------------------------------------------------------------ |
| 80 | // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID |
| 81 | PTR_MethodTable TypeIDMap::LookupType(UINT32 id) |
| 82 | { |
| 83 | CONTRACTL { |
| 84 | NOTHROW; |
| 85 | SO_TOLERANT; |
| 86 | PRECONDITION(CheckPointer(GetThread())); |
| 87 | if (GetThread()->PreemptiveGCDisabled()) { GC_NOTRIGGER; } else { GC_TRIGGERS; } |
| 88 | PRECONDITION(id <= TypeIDProvider::MAX_TYPE_ID); |
| 89 | } CONTRACTL_END; |
| 90 | |
| 91 | if (!m_idProvider.OwnsID(id)) |
| 92 | return NULL; |
| 93 | |
| 94 | UPTR ret = m_idMap.LookupValue((UPTR)id, 0); |
| 95 | if (ret == static_cast<UPTR>(INVALIDENTRY)) |
| 96 | return NULL; |
| 97 | |
| 98 | ret <<= 1; |
| 99 | |
| 100 | return PTR_MethodTable(ret); |
| 101 | } |
| 102 | |
| 103 | //------------------------------------------------------------------------ |
| 104 | // Returns the ID of the type if found. If not found, assigns the ID and |
| 105 | // returns the new ID. |
| 106 | UINT32 TypeIDMap::GetTypeID(PTR_MethodTable pMT) |
| 107 | { |
| 108 | CONTRACTL { |
| 109 | THROWS; |
| 110 | GC_TRIGGERS; |
| 111 | } CONTRACTL_END; |
| 112 | |
| 113 | // Lookup the value. |
| 114 | UINT32 id = LookupTypeID(pMT); |
| 115 | #ifndef DACCESS_COMPILE |
| 116 | // If the value is not in the table, take the lock, get a new ID, and |
| 117 | // insert the new pair. |
| 118 | if (id == TypeIDProvider::INVALID_TYPE_ID) |
| 119 | { |
| 120 | // Take the lock |
| 121 | CrstHolder lh(&m_lock); |
| 122 | // Check to see if someone beat us to the punch |
| 123 | id = LookupTypeID(pMT); |
| 124 | if (id != TypeIDProvider::INVALID_TYPE_ID) |
| 125 | { |
| 126 | return id; |
| 127 | } |
| 128 | // Get the next ID |
| 129 | if (m_fUseFatIdsForUniqueness && pMT->RequiresFatDispatchTokens()) |
| 130 | { |
| 131 | id = GetNextFatID(); |
| 132 | } |
| 133 | else |
| 134 | { |
| 135 | id = GetNextID(); |
| 136 | } |
| 137 | |
| 138 | CONSISTENCY_CHECK(id <= TypeIDProvider::MAX_TYPE_ID); |
| 139 | // Insert the pair, with lookups in both directions |
| 140 | CONSISTENCY_CHECK((((UPTR)pMT) & 0x1) == 0); |
| 141 | m_idMap.InsertValue((UPTR)id, (UPTR)pMT >> 1); |
| 142 | m_mtMap.InsertValue((UPTR)pMT, (UPTR)id); |
| 143 | m_entryCount++; |
| 144 | CONSISTENCY_CHECK(GetThread()->GetDomain()->IsCompilationDomain() || |
| 145 | (LookupType(id) == pMT)); |
| 146 | } |
| 147 | #else // DACCESS_COMPILE |
| 148 | if (id == TypeIDProvider::INVALID_TYPE_ID) |
| 149 | DacError(E_FAIL); |
| 150 | #endif // DACCESS_COMPILE |
| 151 | // Return the ID for this type. |
| 152 | return id; |
| 153 | } // TypeIDMap::GetTypeID |
| 154 | |
| 155 | #ifndef DACCESS_COMPILE |
| 156 | |
| 157 | //------------------------------------------------------------------------ |
| 158 | // If TRUE, it points to a matching entry. |
| 159 | // If FALSE, it is at the insertion point. |
| 160 | BOOL |
| 161 | DispatchMapBuilder::Find( |
| 162 | DispatchMapTypeID typeID, |
| 163 | UINT32 slotNumber, |
| 164 | Iterator & it) |
| 165 | { |
| 166 | WRAPPER_NO_CONTRACT; |
| 167 | for (; it.IsValid(); it.Next()) |
| 168 | { |
| 169 | if (typeID == it.GetTypeID()) |
| 170 | { |
| 171 | if (slotNumber == it.GetSlotNumber()) |
| 172 | { |
| 173 | return TRUE; |
| 174 | } |
| 175 | if (slotNumber < it.GetSlotNumber()) |
| 176 | { |
| 177 | return FALSE; |
| 178 | } |
| 179 | } |
| 180 | else if (typeID < it.GetTypeID()) |
| 181 | { |
| 182 | return FALSE; |
| 183 | } |
| 184 | } |
| 185 | |
| 186 | return FALSE; |
| 187 | } // DispatchMapBuilder::Find |
| 188 | |
| 189 | //------------------------------------------------------------------------ |
| 190 | // If TRUE, contains such an entry. |
| 191 | // If FALSE, no such entry exists. |
| 192 | BOOL DispatchMapBuilder::Contains(DispatchMapTypeID typeID, UINT32 slotNumber) |
| 193 | { |
| 194 | WRAPPER_NO_CONTRACT; |
| 195 | Iterator it(this); |
| 196 | return Find(typeID, slotNumber, it); |
| 197 | } |
| 198 | |
| 199 | //------------------------------------------------------------------------ |
| 200 | void |
| 201 | DispatchMapBuilder::InsertMDMapping( |
| 202 | DispatchMapTypeID typeID, |
| 203 | UINT32 slotNumber, |
| 204 | MethodDesc * pMDTarget, |
| 205 | BOOL fIsMethodImpl) |
| 206 | { |
| 207 | CONTRACTL { |
| 208 | THROWS; |
| 209 | GC_NOTRIGGER; |
| 210 | } CONTRACTL_END; |
| 211 | |
| 212 | // Find a matching entry, or move the iterator to insertion point. |
| 213 | Iterator it(this); |
| 214 | BOOL fFound = Find(typeID, slotNumber, it); |
| 215 | |
| 216 | // If we find an existing matching entry, fail. |
| 217 | if (fFound) |
| 218 | { |
| 219 | _ASSERTE(false); |
| 220 | COMPlusThrowHR(COR_E_TYPELOAD); |
| 221 | } |
| 222 | |
| 223 | // Create and initialize a new entry |
| 224 | DispatchMapBuilderNode * pNew = NewEntry(); |
| 225 | pNew->Init(typeID, slotNumber, pMDTarget); |
| 226 | if (fIsMethodImpl) |
| 227 | pNew->SetIsMethodImpl(); |
| 228 | |
| 229 | // Insert at the point of the iterator |
| 230 | pNew->m_next = NULL; |
| 231 | if (it.IsValid()) |
| 232 | { |
| 233 | pNew->m_next = it.EntryNode(); |
| 234 | } |
| 235 | *(it.EntryNodePtr()) = pNew; |
| 236 | m_cEntries++; |
| 237 | |
| 238 | } // DispatchMapBuilder::InsertMDMapping |
| 239 | |
| 240 | //-------------------------------------------------------------------- |
| 241 | UINT32 DispatchMapBuilder::Iterator::GetTargetSlot() |
| 242 | { |
| 243 | WRAPPER_NO_CONTRACT; |
| 244 | CONSISTENCY_CHECK(IsValid()); |
| 245 | if (GetTargetMD() != NULL) |
| 246 | { |
| 247 | return EntryNode()->m_pMDTarget->GetSlot(); |
| 248 | } |
| 249 | else |
| 250 | { |
| 251 | return 0; |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | //------------------------------------------------------------------------ |
| 256 | DispatchMapBuilderNode * DispatchMapBuilder::NewEntry() |
| 257 | { |
| 258 | CONTRACTL { |
| 259 | THROWS; |
| 260 | GC_NOTRIGGER; |
| 261 | INJECT_FAULT(COMPlusThrowOM()); |
| 262 | } CONTRACTL_END; |
| 263 | |
| 264 | return new (m_pAllocator) DispatchMapBuilderNode(); |
| 265 | } |
| 266 | |
| 267 | //---------------------------------------------------------------------------- |
| 268 | DispatchMap::DispatchMap( |
| 269 | BYTE * pMap, |
| 270 | UINT32 cbMap) |
| 271 | { |
| 272 | LIMITED_METHOD_CONTRACT; |
| 273 | CONSISTENCY_CHECK(CheckPointer(pMap)); |
| 274 | memcpyNoGCRefs(m_rgMap, pMap, cbMap); |
| 275 | } |
| 276 | |
| 277 | //---------------------------------------------------------------------------- |
| 278 | // This mapping consists of a list of the following entries. |
| 279 | // <type, [<slot, (index | slot)>]>. This is implemented as |
| 280 | // |
| 281 | // flag: 0 if the map is a part of a JIT'd module |
| 282 | // 1 if the map is a part of an NGEN'd module. |
| 283 | // count: number of types that have entries |
| 284 | // { |
| 285 | // type: The ID current type being mapped |
| 286 | // count: Number of subentries for the current type |
| 287 | // bool: Whether or not the target slot/index values can be negative. |
| 288 | // { |
| 289 | // slot: The slot of type that is being mapped |
| 290 | // index/slot: This is a slot mapping for the current type. The implementation search is |
| 291 | // modified to <this, slot> and the search is restarted from the initial type. |
| 292 | // } |
| 293 | // } |
| 294 | void |
| 295 | DispatchMap::CreateEncodedMapping( |
| 296 | MethodTable * pMT, |
| 297 | DispatchMapBuilder * pMapBuilder, |
| 298 | StackingAllocator * pAllocator, |
| 299 | BYTE ** ppbMap, |
| 300 | UINT32 * pcbMap) |
| 301 | { |
| 302 | CONTRACTL { |
| 303 | THROWS; |
| 304 | GC_TRIGGERS; |
| 305 | INJECT_FAULT(COMPlusThrowOM()); |
| 306 | PRECONDITION(CheckPointer(pMT)); |
| 307 | PRECONDITION(CheckPointer(pMapBuilder)); |
| 308 | PRECONDITION(CheckPointer(pAllocator)); |
| 309 | PRECONDITION(CheckPointer(ppbMap)); |
| 310 | PRECONDITION(CheckPointer(pcbMap)); |
| 311 | } CONTRACTL_END; |
| 312 | |
| 313 | ///////////////////////////////// |
| 314 | // Phase 1 - gather entry counts |
| 315 | |
| 316 | UINT32 cNumTypes = 0; |
| 317 | UINT32 cNumEntries = 0; |
| 318 | |
| 319 | { |
| 320 | DispatchMapBuilder::Iterator it(pMapBuilder); |
| 321 | // We don't want to record overrides or methodImpls in the dispatch map since |
| 322 | // we have vtables to track this information. |
| 323 | it.SkipThisTypeEntries(); |
| 324 | if (it.IsValid()) |
| 325 | { |
| 326 | DispatchMapTypeID curType = DispatchMapTypeID::FromUINT32(INVALIDENTRY); |
| 327 | do |
| 328 | { |
| 329 | cNumEntries++; |
| 330 | if (curType != it.GetTypeID()) |
| 331 | { |
| 332 | cNumTypes++; |
| 333 | curType = it.GetTypeID(); |
| 334 | } |
| 335 | } |
| 336 | while (it.Next()); |
| 337 | } |
| 338 | } |
| 339 | |
| 340 | ///////////////////////////////// |
| 341 | // Phase 2 - allocate space |
| 342 | |
| 343 | // Now that we have stats about the overall absolute maximum map size, we can allocate |
| 344 | // some working space for createing the encoded map in. |
| 345 | // Sizes: flag==UINT32, typeID==UINT32, slot==UINT32, index/slot==UINT32 |
| 346 | |
| 347 | S_UINT32 scbMap = S_UINT32(sizeof(UINT32)) + |
| 348 | S_UINT32(cNumTypes) * S_UINT32(sizeof(UINT32)) + |
| 349 | S_UINT32(cNumEntries) * S_UINT32((sizeof(UINT32) + sizeof(UINT32))); |
| 350 | |
| 351 | BYTE * pbMap = (BYTE *)pAllocator->Alloc(scbMap); |
| 352 | |
| 353 | ///////////////////////////////// |
| 354 | // Phase 3 - encode the map |
| 355 | |
| 356 | { |
| 357 | // Create the encoder over the newly allocated memory |
| 358 | Encoder e(pbMap); |
| 359 | // Encode the count of type entries |
| 360 | e.Encode((unsigned)cNumTypes); |
| 361 | // Start encoding the map |
| 362 | DispatchMapBuilder::Iterator it(pMapBuilder); |
| 363 | it.SkipThisTypeEntries(); |
| 364 | |
| 365 | INT32 curType = -1; |
| 366 | INT32 prevType; |
| 367 | INT32 deltaType; |
| 368 | while (it.IsValid()) |
| 369 | { |
| 370 | // Encode the type ID |
| 371 | prevType = curType; |
| 372 | curType = (INT32)it.GetTypeID().ToUINT32(); |
| 373 | deltaType = curType - prevType - ENCODING_TYPE_DELTA; |
| 374 | CONSISTENCY_CHECK(0 <= deltaType); |
| 375 | e.Encode((unsigned)deltaType); |
| 376 | // Variables for slot delta calculations |
| 377 | BOOL fHasNegatives = FALSE; |
| 378 | // Source slot |
| 379 | INT32 curSlot = -1; |
| 380 | INT32 prevSlot = -1; |
| 381 | // Target slot for virtual mappings |
| 382 | INT32 curTargetSlot = -1; |
| 383 | INT32 prevTargetSlot = -1; |
| 384 | // Count and encode the number of sub entries for this type |
| 385 | UINT32 cSubEntries = 0; |
| 386 | DispatchMapBuilder::Iterator subIt(it); |
| 387 | do |
| 388 | { |
| 389 | prevTargetSlot = curTargetSlot; |
| 390 | curTargetSlot = (INT32)subIt.GetTargetSlot(); |
| 391 | INT32 deltaTargetSlot = curTargetSlot - prevTargetSlot - ENCODING_TARGET_SLOT_DELTA; |
| 392 | if (deltaTargetSlot < 0) |
| 393 | { |
| 394 | fHasNegatives = TRUE; |
| 395 | } |
| 396 | cSubEntries++; |
| 397 | } |
| 398 | while (subIt.Next() && (subIt.GetTypeID().ToUINT32() == (UINT32)curType)); |
| 399 | |
| 400 | e.Encode((unsigned)cSubEntries); |
| 401 | e.Encode((unsigned)fHasNegatives); |
| 402 | e.ContainsNegatives(fHasNegatives); |
| 403 | // Iterate each subentry and encode it |
| 404 | curTargetSlot = -1; |
| 405 | do |
| 406 | { |
| 407 | // Only virtual targets can be mapped virtually. |
| 408 | CONSISTENCY_CHECK((it.GetTargetMD() == NULL) || |
| 409 | it.GetTargetMD()->IsVirtual()); |
| 410 | // Encode the slot |
| 411 | prevSlot = curSlot; |
| 412 | curSlot = it.GetSlotNumber(); |
| 413 | INT32 deltaSlot = curSlot - prevSlot - ENCODING_SLOT_DELTA; |
| 414 | CONSISTENCY_CHECK(0 <= deltaSlot); |
| 415 | e.Encode((unsigned)deltaSlot); |
| 416 | |
| 417 | // Calculate and encode the target slot delta |
| 418 | prevTargetSlot = curTargetSlot; |
| 419 | curTargetSlot = (INT32)it.GetTargetSlot(); |
| 420 | INT32 delta = curTargetSlot - prevTargetSlot - ENCODING_TARGET_SLOT_DELTA; |
| 421 | |
| 422 | if (fHasNegatives) |
| 423 | { |
| 424 | e.EncodeSigned((signed)delta); |
| 425 | } |
| 426 | else |
| 427 | { |
| 428 | CONSISTENCY_CHECK(0 <= delta); |
| 429 | e.Encode((unsigned)delta); |
| 430 | } |
| 431 | } |
| 432 | while (it.Next() && it.GetTypeID().ToUINT32() == (UINT32)curType); |
| 433 | } // while (it.IsValid()) |
| 434 | |
| 435 | // Finish and finalize the map, and set the out params. |
| 436 | e.Done(); |
| 437 | *pcbMap = e.Contents(ppbMap); |
| 438 | } |
| 439 | |
| 440 | #ifdef _DEBUG |
| 441 | // Let's verify the mapping |
| 442 | { |
| 443 | EncodedMapIterator itMap(*ppbMap); |
| 444 | DispatchMapBuilder::Iterator itBuilder(pMapBuilder); |
| 445 | itBuilder.SkipThisTypeEntries(); |
| 446 | |
| 447 | while (itMap.IsValid()) |
| 448 | { |
| 449 | CONSISTENCY_CHECK(itBuilder.IsValid()); |
| 450 | DispatchMapEntry * pEntryMap = itMap.Entry(); |
| 451 | CONSISTENCY_CHECK(pEntryMap->GetTypeID() == itBuilder.GetTypeID()); |
| 452 | CONSISTENCY_CHECK(pEntryMap->GetTargetSlotNumber() == itBuilder.GetTargetSlot()); |
| 453 | itMap.Next(); |
| 454 | itBuilder.Next(); |
| 455 | } |
| 456 | |
| 457 | CONSISTENCY_CHECK(!itBuilder.IsValid()); |
| 458 | } |
| 459 | #endif //_DEBUG |
| 460 | } // DispatchMap::CreateEncodedMapping |
| 461 | |
| 462 | #ifdef FEATURE_NATIVE_IMAGE_GENERATION |
| 463 | //------------------------------------------------------------------------ |
| 464 | void DispatchMap::Save(DataImage * image) |
| 465 | { |
| 466 | STANDARD_VM_CONTRACT; |
| 467 | |
| 468 | CONSISTENCY_CHECK(!image->IsStored(this)); |
| 469 | |
| 470 | UINT32 cbMap = GetMapSize(); |
| 471 | UINT32 cbObj = GetObjectSize(cbMap); |
| 472 | |
| 473 | image->StoreInternedStructure( |
| 474 | this, |
| 475 | cbObj, |
| 476 | DataImage::ITEM_DISPATCH_MAP, |
| 477 | sizeof(void *)); |
| 478 | |
| 479 | #ifdef LOGGING |
| 480 | g_sdStats.m_cNGENDispatchMap++; |
| 481 | g_sdStats.m_cbNGENDispatchMap += cbObj; |
| 482 | #endif //LOGGING |
| 483 | } |
| 484 | |
| 485 | //------------------------------------------------------------------------ |
| 486 | void DispatchMap::Fixup(DataImage *image) |
| 487 | { |
| 488 | STANDARD_VM_CONTRACT; |
| 489 | } |
| 490 | |
| 491 | #endif //FEATURE_NATIVE_IMAGE_GENERATION |
| 492 | |
| 493 | #endif //!DACCESS_COMPILE |
| 494 | |
| 495 | //------------------------------------------------------------------------ |
| 496 | UINT32 DispatchMap::GetMapSize() |
| 497 | { |
| 498 | WRAPPER_NO_CONTRACT; |
| 499 | SUPPORTS_DAC; |
| 500 | EncodedMapIterator it(this); |
| 501 | for (; it.IsValid(); it.Next()) |
| 502 | { |
| 503 | } |
| 504 | CONSISTENCY_CHECK(dac_cast<TADDR>(it.m_d.End()) > PTR_HOST_MEMBER_TADDR(DispatchMap, this, m_rgMap)); |
| 505 | return (UINT32)(dac_cast<TADDR>(it.m_d.End()) - PTR_HOST_MEMBER_TADDR(DispatchMap, this, m_rgMap)); |
| 506 | } |
| 507 | |
| 508 | #ifdef DACCESS_COMPILE |
| 509 | |
| 510 | //------------------------------------------------------------------------ |
| 511 | void DispatchMap::EnumMemoryRegions(CLRDataEnumMemoryFlags flags) |
| 512 | { |
| 513 | WRAPPER_NO_CONTRACT; |
| 514 | SUPPORTS_DAC; |
| 515 | |
| 516 | DAC_ENUM_DTHIS(); |
| 517 | |
| 518 | EMEM_OUT(("MEM: %p DispatchMap\n" , dac_cast<TADDR>(this))); |
| 519 | |
| 520 | DacEnumMemoryRegion(PTR_HOST_MEMBER_TADDR(DispatchMap,this,m_rgMap), GetMapSize()); |
| 521 | } |
| 522 | |
| 523 | #endif // DACCESS_COMPILE |
| 524 | |
| 525 | //-------------------------------------------------------------------- |
| 526 | void DispatchMap::EncodedMapIterator::Invalidate() |
| 527 | { |
| 528 | LIMITED_METHOD_DAC_CONTRACT; |
| 529 | m_numTypes = 0; |
| 530 | m_curType = 0; |
| 531 | m_numEntries = 0; |
| 532 | m_curEntry = 0; |
| 533 | } |
| 534 | |
| 535 | //-------------------------------------------------------------------- |
| 536 | void DispatchMap::EncodedMapIterator::Init(PTR_BYTE pbMap) |
| 537 | { |
| 538 | CONTRACTL { |
| 539 | GC_NOTRIGGER; |
| 540 | NOTHROW; |
| 541 | INSTANCE_CHECK; |
| 542 | PRECONDITION(CheckPointer(pbMap, NULL_OK)); |
| 543 | SUPPORTS_DAC; |
| 544 | } CONTRACTL_END; |
| 545 | |
| 546 | if (pbMap != NULL) |
| 547 | { |
| 548 | // Initialize the map decoder |
| 549 | m_d.Init(pbMap); |
| 550 | m_numTypes = m_d.Next(); |
| 551 | m_curType = -1; |
| 552 | m_curTypeId = DispatchMapTypeID::FromUINT32(static_cast<UINT32>(-1)); |
| 553 | m_numEntries = 0; |
| 554 | m_curEntry = -1; |
| 555 | m_curTargetSlot = static_cast<UINT32>(-1); |
| 556 | } |
| 557 | else |
| 558 | { |
| 559 | Invalidate(); |
| 560 | } |
| 561 | |
| 562 | Next(); |
| 563 | } |
| 564 | |
| 565 | //-------------------------------------------------------------------- |
| 566 | DispatchMap::EncodedMapIterator::EncodedMapIterator(MethodTable * pMT) |
| 567 | { |
| 568 | CONTRACTL { |
| 569 | GC_NOTRIGGER; |
| 570 | NOTHROW; |
| 571 | INSTANCE_CHECK; |
| 572 | SUPPORTS_DAC; |
| 573 | } CONTRACTL_END; |
| 574 | |
| 575 | if (pMT->HasDispatchMap()) |
| 576 | { |
| 577 | DispatchMap * pMap = pMT->GetDispatchMap(); |
| 578 | Init(PTR_BYTE(PTR_HOST_MEMBER_TADDR(DispatchMap, pMap, m_rgMap))); |
| 579 | } |
| 580 | else |
| 581 | { |
| 582 | Init(NULL); |
| 583 | } |
| 584 | } |
| 585 | |
| 586 | //-------------------------------------------------------------------- |
| 587 | // This should be used only when a dispatch map needs to be used |
| 588 | // separately from its MethodTable. |
| 589 | DispatchMap::EncodedMapIterator::EncodedMapIterator(DispatchMap * pMap) |
| 590 | { |
| 591 | LIMITED_METHOD_CONTRACT; |
| 592 | SUPPORTS_DAC; |
| 593 | PTR_BYTE pBytes = NULL; |
| 594 | if (pMap != NULL) |
| 595 | { |
| 596 | pBytes = PTR_BYTE(PTR_HOST_MEMBER_TADDR(DispatchMap, pMap,m_rgMap)); |
| 597 | } |
| 598 | Init(pBytes); |
| 599 | } |
| 600 | |
| 601 | //-------------------------------------------------------------------- |
| 602 | DispatchMap::EncodedMapIterator::EncodedMapIterator(PTR_BYTE pbMap) |
| 603 | { |
| 604 | LIMITED_METHOD_CONTRACT; |
| 605 | |
| 606 | Init(pbMap); |
| 607 | } |
| 608 | |
| 609 | //-------------------------------------------------------------------- |
| 610 | BOOL DispatchMap::EncodedMapIterator::Next() |
| 611 | { |
| 612 | CONTRACTL { |
| 613 | GC_NOTRIGGER; |
| 614 | NOTHROW; |
| 615 | INSTANCE_CHECK; |
| 616 | SUPPORTS_DAC; |
| 617 | } CONTRACTL_END; |
| 618 | |
| 619 | if (!IsValid()) |
| 620 | { |
| 621 | return FALSE; |
| 622 | } |
| 623 | |
| 624 | m_curEntry++; |
| 625 | if (m_curEntry == m_numEntries) |
| 626 | { |
| 627 | m_curType++; |
| 628 | if (m_curType == m_numTypes) |
| 629 | { |
| 630 | return FALSE; |
| 631 | } |
| 632 | m_curTypeId = |
| 633 | DispatchMapTypeID::FromUINT32( |
| 634 | (UINT32)((INT32)m_curTypeId.ToUINT32() + |
| 635 | (INT32)m_d.Next() + |
| 636 | ENCODING_TYPE_DELTA)); |
| 637 | _ASSERTE(!m_curTypeId.IsThisClass()); |
| 638 | m_curEntry = 0; |
| 639 | m_numEntries = m_d.Next(); |
| 640 | m_fCurTypeHasNegativeEntries = (BOOL)m_d.Next(); |
| 641 | m_curSlot = static_cast<UINT32>(-1); |
| 642 | m_curTargetSlot = static_cast<UINT32>(-1); |
| 643 | CONSISTENCY_CHECK(m_numEntries != 0); |
| 644 | } |
| 645 | |
| 646 | // Now gather enough info to initialize the dispatch entry |
| 647 | |
| 648 | // Get the source slot |
| 649 | m_curSlot = (UINT32)((INT32)m_curSlot + (INT32)m_d.Next() + ENCODING_SLOT_DELTA); |
| 650 | |
| 651 | // If virtual, get the target virtual slot number |
| 652 | m_curTargetSlot = |
| 653 | (UINT32)((INT32)m_curTargetSlot + |
| 654 | ENCODING_TARGET_SLOT_DELTA + |
| 655 | (INT32)(m_fCurTypeHasNegativeEntries ? m_d.NextSigned() : m_d.Next())); |
| 656 | m_e.InitVirtualMapping(m_curTypeId, m_curSlot, m_curTargetSlot); |
| 657 | |
| 658 | CONSISTENCY_CHECK(IsValid()); |
| 659 | return TRUE; |
| 660 | } // DispatchMap::EncodedMapIterator::Next |
| 661 | |
| 662 | //-------------------------------------------------------------------- |
| 663 | DispatchMap::Iterator::Iterator(MethodTable * pMT) |
| 664 | : m_mapIt(pMT) |
| 665 | { |
| 666 | CONTRACTL { |
| 667 | THROWS; |
| 668 | GC_TRIGGERS; |
| 669 | } CONTRACTL_END; |
| 670 | } |
| 671 | |
| 672 | //-------------------------------------------------------------------- |
| 673 | BOOL DispatchMap::Iterator::IsValid() |
| 674 | { |
| 675 | WRAPPER_NO_CONTRACT; |
| 676 | return m_mapIt.IsValid(); |
| 677 | } |
| 678 | |
| 679 | //-------------------------------------------------------------------- |
| 680 | BOOL DispatchMap::Iterator::Next() |
| 681 | { |
| 682 | WRAPPER_NO_CONTRACT; |
| 683 | CONSISTENCY_CHECK(!m_mapIt.Entry()->GetTypeID().IsThisClass()); |
| 684 | if (m_mapIt.IsValid()) |
| 685 | { |
| 686 | m_mapIt.Next(); |
| 687 | CONSISTENCY_CHECK(!m_mapIt.IsValid() || !m_mapIt.Entry()->GetTypeID().IsThisClass()); |
| 688 | } |
| 689 | return IsValid(); |
| 690 | } |
| 691 | |
| 692 | //-------------------------------------------------------------------- |
| 693 | DispatchMapEntry * DispatchMap::Iterator::Entry() |
| 694 | { |
| 695 | /* |
| 696 | CONTRACTL { |
| 697 | INSTANCE_CHECK; |
| 698 | MODE_ANY; |
| 699 | if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS; |
| 700 | if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS; |
| 701 | if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); } |
| 702 | PRECONDITION(IsValid()); |
| 703 | } CONTRACTL_END; |
| 704 | */ |
| 705 | WRAPPER_NO_CONTRACT; |
| 706 | CONSISTENCY_CHECK(IsValid()); |
| 707 | |
| 708 | DispatchMapEntry * pEntry = NULL; |
| 709 | if (m_mapIt.IsValid()) |
| 710 | { |
| 711 | pEntry = m_mapIt.Entry(); |
| 712 | } |
| 713 | CONSISTENCY_CHECK(CheckPointer(pEntry)); |
| 714 | return pEntry; |
| 715 | } |
| 716 | |