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 | |