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.h
6//
7// Keeps track of contract implementations, used primarily in stub dispatch.
8//
9
10
11//
12
13//
14// ============================================================================
15
16#ifndef CONTRACTIMPL_H_
17#define CONTRACTIMPL_H_
18
19#include "hash.h"
20#include "decodemd.h"
21
22class Module;
23class MethodDesc;
24class StackingAllocator;
25
26// ===========================================================================
27struct DispatchSlot
28{
29protected:
30 PCODE m_slot;
31
32public:
33 //------------------------------------------------------------------------
34 inline DispatchSlot(PCODE slot) : m_slot(slot)
35 { LIMITED_METHOD_CONTRACT; }
36
37 //------------------------------------------------------------------------
38 inline DispatchSlot(const DispatchSlot &slot) : m_slot(slot.m_slot)
39 { LIMITED_METHOD_CONTRACT; }
40
41 //------------------------------------------------------------------------
42 inline DispatchSlot& operator=(PCODE slot)
43 { LIMITED_METHOD_CONTRACT; m_slot = slot; return *this; }
44
45 //------------------------------------------------------------------------
46 inline DispatchSlot& operator=(const DispatchSlot &slot)
47 { LIMITED_METHOD_CONTRACT; m_slot = slot.m_slot; return *this; }
48
49 //------------------------------------------------------------------------
50 inline BOOL IsNull()
51 { LIMITED_METHOD_CONTRACT; return (m_slot == NULL); }
52
53 //------------------------------------------------------------------------
54 inline void SetNull()
55 { LIMITED_METHOD_CONTRACT; m_slot = NULL; }
56
57 //------------------------------------------------------------------------
58 inline PCODE GetTarget()
59 { LIMITED_METHOD_CONTRACT; return m_slot; }
60
61 //------------------------------------------------------------------------
62 MethodDesc *GetMethodDesc();
63}; // struct DispatchSlot
64
65// ===========================================================================
66// This value indicates that a slot number is in reference to the
67// current class. Thus, no TypeID can have a value of 0. This is stored
68// inside a DispatchToken as the TypeID for such cases.
69static const UINT32 TYPE_ID_THIS_CLASS = 0;
70
71
72// ===========================================================================
73// The type IDs used in the dispatch map are relative to the implementing
74// type, and are a discriminated union between:
75// - a special value to indicate "this" class
76// - a special value to indicate that an interface is not implemented by the type
77// - an index into the InterfaceMap
78class DispatchMapTypeID
79{
80private:
81 static const UINT32 const_nFirstInterfaceIndex = 1;
82
83 UINT32 m_typeIDVal;
84 DispatchMapTypeID(UINT32 id) { LIMITED_METHOD_DAC_CONTRACT; m_typeIDVal = id; }
85public:
86 // Constructors
87 static DispatchMapTypeID ThisClassID() { LIMITED_METHOD_CONTRACT; return DispatchMapTypeID(TYPE_ID_THIS_CLASS); }
88 static DispatchMapTypeID InterfaceClassID(UINT32 inum)
89 {
90 LIMITED_METHOD_CONTRACT;
91 _ASSERTE(inum + const_nFirstInterfaceIndex > inum);
92 return DispatchMapTypeID(inum + const_nFirstInterfaceIndex);
93 }
94 DispatchMapTypeID() { LIMITED_METHOD_DAC_CONTRACT; m_typeIDVal = TYPE_ID_THIS_CLASS; }
95
96 // Accessors
97 BOOL IsThisClass() const { LIMITED_METHOD_DAC_CONTRACT; return (m_typeIDVal == TYPE_ID_THIS_CLASS); }
98 BOOL IsImplementedInterface() const { LIMITED_METHOD_CONTRACT; return (m_typeIDVal >= const_nFirstInterfaceIndex); }
99 UINT32 GetInterfaceNum() const
100 {
101 LIMITED_METHOD_CONTRACT;
102 _ASSERTE(IsImplementedInterface());
103 return (m_typeIDVal - const_nFirstInterfaceIndex);
104 }
105
106 // Ordering/equality
107 BOOL operator ==(const DispatchMapTypeID &that) const { LIMITED_METHOD_CONTRACT; return m_typeIDVal == that.m_typeIDVal; }
108 BOOL operator !=(const DispatchMapTypeID &that) const { LIMITED_METHOD_CONTRACT; return m_typeIDVal != that.m_typeIDVal; }
109 BOOL operator <(const DispatchMapTypeID &that) const { LIMITED_METHOD_CONTRACT; return m_typeIDVal < that.m_typeIDVal; }
110
111 // To/from UINT32, for encoding/decoding etc.
112 UINT32 ToUINT32() const { LIMITED_METHOD_DAC_CONTRACT; return m_typeIDVal; }
113 static DispatchMapTypeID FromUINT32(UINT32 x) { LIMITED_METHOD_DAC_CONTRACT; return DispatchMapTypeID(x); }
114}; // class DispatchMapTypeID
115
116#ifdef FAT_DISPATCH_TOKENS
117// ===========================================================================
118// This is the structure that is used when typeId becomes too be to be
119// contained in a regular DispatchToken. DispatchToken is able to encapsulate
120// a DispatchTokenFat*, somewhat like TypeHandle may encapsulate a TypeDesc*.
121struct DispatchTokenFat
122{
123 friend struct DispatchToken;
124 friend class BaseDomain;
125
126 private:
127 UINT32 m_typeId;
128 UINT32 m_slotNum;
129
130 public:
131 DispatchTokenFat(UINT32 typeID, UINT32 slotNumber)
132 : m_typeId(typeID), m_slotNum(slotNumber)
133 {}
134
135 // Equality comparison, used in SHash set.
136 bool operator==(const DispatchTokenFat &other) const
137 { return m_typeId == other.m_typeId && m_slotNum == other.m_slotNum; }
138
139 // Hashing operator, using in SHash set.
140 operator size_t() const
141 { return (size_t)m_typeId ^ (size_t)m_slotNum; }
142}; // struct DispatchTokenFat
143
144typedef DPTR(DispatchTokenFat) PTR_DispatchTokenFat;
145#endif
146
147// ===========================================================================
148// This represents the contract used for code lookups throughout the
149// virtual stub dispatch mechanism. It is important to know that
150// sizeof(DispatchToken) is UINT_PTR, which means it can be thrown around
151// by value without a problem.
152
153struct DispatchToken
154{
155private:
156 // IMPORTANT: This is the ONLY member of this class.
157 UINT_PTR m_token;
158
159#ifndef _WIN64
160 // NOTE: On 32-bit, we use the uppermost bit to indicate that the
161 // token is really a DispatchTokenFat*, and to recover the pointer
162 // we just shift left by 1; correspondingly, when storing a
163 // DispatchTokenFat* in a DispatchToken, we shift right by 1.
164 static const UINT_PTR MASK_TYPE_ID = 0x00007FFF;
165 static const UINT_PTR MASK_SLOT_NUMBER = 0x0000FFFF;
166
167 static const UINT_PTR SHIFT_TYPE_ID = 0x10;
168 static const UINT_PTR SHIFT_SLOT_NUMBER = 0x0;
169
170#ifdef FAT_DISPATCH_TOKENS
171 static const UINT_PTR FAT_TOKEN_FLAG = 0x80000000;
172#endif // FAT_DISPATCH_TOKENS
173
174 static const UINT_PTR INVALID_TOKEN = 0x7FFFFFFF;
175#else //_WIN64
176 static const UINT_PTR MASK_TYPE_ID = UI64(0x000000007FFFFFFF);
177 static const UINT_PTR MASK_SLOT_NUMBER = UI64(0x000000000000FFFF);
178
179 static const UINT_PTR SHIFT_TYPE_ID = 0x20;
180 static const UINT_PTR SHIFT_SLOT_NUMBER = 0x0;
181
182#ifdef FAT_DISPATCH_TOKENS
183 static const UINT_PTR FAT_TOKEN_FLAG = UI64(0x8000000000000000);
184#endif // FAT_DISPATCH_TOKENS
185
186 static const UINT_PTR INVALID_TOKEN = 0x7FFFFFFFFFFFFFFF;
187#endif //_WIN64
188
189#ifdef FAT_DISPATCH_TOKENS
190 //------------------------------------------------------------------------
191 static inline BOOL IsFat(UINT_PTR token)
192 {
193 return (token & FAT_TOKEN_FLAG) != 0;
194 }
195
196 //------------------------------------------------------------------------
197 static inline DispatchTokenFat* ToFat(UINT_PTR token)
198 {
199 return PTR_DispatchTokenFat(token << 1);
200 }
201#endif
202
203 //------------------------------------------------------------------------
204 // Combines the two values into a single 32-bit number.
205 static UINT_PTR CreateToken(UINT32 typeID, UINT32 slotNumber)
206 {
207 LIMITED_METHOD_CONTRACT;
208 CONSISTENCY_CHECK(((UINT_PTR)typeID & MASK_TYPE_ID) == (UINT_PTR)typeID);
209 CONSISTENCY_CHECK(((UINT_PTR)slotNumber & MASK_SLOT_NUMBER) == (UINT_PTR)slotNumber);
210 return ((((UINT_PTR)typeID & MASK_TYPE_ID) << SHIFT_TYPE_ID) |
211 (((UINT_PTR)slotNumber & MASK_SLOT_NUMBER) << SHIFT_SLOT_NUMBER));
212 }
213
214 //------------------------------------------------------------------------
215 // Extracts the type ID from a token created by CreateToken
216 static UINT32 DecodeTypeID(UINT_PTR token)
217 {
218 LIMITED_METHOD_CONTRACT;
219 CONSISTENCY_CHECK(token != INVALID_TOKEN);
220#ifdef FAT_DISPATCH_TOKENS
221 if (IsFat(token))
222 return ToFat(token)->m_typeId;
223 else
224#endif
225 return ((token >> SHIFT_TYPE_ID) & MASK_TYPE_ID);
226 }
227
228 //------------------------------------------------------------------------
229 // Extracts the slot number from a token created by CreateToken
230 static UINT32 DecodeSlotNumber(UINT_PTR token)
231 {
232 LIMITED_METHOD_CONTRACT;
233 CONSISTENCY_CHECK(token != INVALID_TOKEN);
234#ifdef FAT_DISPATCH_TOKENS
235 if (IsFat(token))
236 return ToFat(token)->m_slotNum;
237 else
238#endif
239 return ((token >> SHIFT_SLOT_NUMBER) & MASK_SLOT_NUMBER);
240 }
241
242public:
243
244#ifdef FAT_DISPATCH_TOKENS
245#if !defined(_WIN64)
246 static const UINT32 MAX_TYPE_ID_SMALL = 0x00007FFF;
247#else
248 static const UINT32 MAX_TYPE_ID_SMALL = 0x7FFFFFFF;
249#endif
250#endif // FAT_DISPATCH_TOKENS
251
252 //------------------------------------------------------------------------
253 DispatchToken()
254 {
255 LIMITED_METHOD_CONTRACT;
256 m_token = INVALID_TOKEN;
257 }
258
259 DispatchToken(UINT_PTR token)
260 {
261 CONSISTENCY_CHECK(token != INVALID_TOKEN);
262 m_token = token;
263 }
264
265#ifdef FAT_DISPATCH_TOKENS
266 //------------------------------------------------------------------------
267 DispatchToken(DispatchTokenFat *pFat)
268 {
269 LIMITED_METHOD_CONTRACT;
270 CONSISTENCY_CHECK((((UINT_PTR)pFat) & 0x1) == 0);
271 m_token = (UINT_PTR(pFat) >> 1) | FAT_TOKEN_FLAG;
272 }
273
274 //------------------------------------------------------------------------
275 static bool RequiresDispatchTokenFat(UINT32 typeID, UINT32 slotNumber)
276 {
277 LIMITED_METHOD_CONTRACT;
278 return typeID > MAX_TYPE_ID_SMALL
279#ifdef _DEBUG
280 // Stress the overflow mechanism in debug builds.
281 || ((typeID != TYPE_ID_THIS_CLASS) && ((typeID % 7) < 4))
282#endif
283 ;
284 }
285#endif //FAT_DISPATCH_TOKENS
286
287 //------------------------------------------------------------------------
288 inline bool operator==(const DispatchToken &tok) const
289 {
290 LIMITED_METHOD_CONTRACT;
291 return m_token == tok.m_token;
292 }
293
294 //------------------------------------------------------------------------
295 // Creates a "this" type dispatch token. This means that the type for the
296 // token is implied by the type on which one wishes to invoke. In other
297 // words, the value returned by GetTypeID is TYPE_ID_THIS_CLASS.
298 static DispatchToken CreateDispatchToken(UINT32 slotNumber)
299 {
300 WRAPPER_NO_CONTRACT;
301 return DispatchToken(CreateToken(TYPE_ID_THIS_CLASS, slotNumber));
302 }
303
304 //------------------------------------------------------------------------
305 // Creates a fully qualified type dispatch token. This means that the ID
306 // for the type is encoded directly in the token.
307 static DispatchToken CreateDispatchToken(UINT32 typeID, UINT32 slotNumber)
308 {
309 WRAPPER_NO_CONTRACT;
310 return DispatchToken(CreateToken(typeID, slotNumber));
311 }
312
313 //------------------------------------------------------------------------
314 // Returns the type ID for this dispatch contract
315 inline UINT32 GetTypeID() const
316 {
317 WRAPPER_NO_CONTRACT;
318 return DecodeTypeID(m_token);
319 }
320
321 //------------------------------------------------------------------------
322 // Returns the slot number for this dispatch contract
323 inline UINT32 GetSlotNumber() const
324 {
325 WRAPPER_NO_CONTRACT;
326 return DecodeSlotNumber(m_token);
327 }
328
329 //------------------------------------------------------------------------
330 inline bool IsThisToken() const
331 {
332 WRAPPER_NO_CONTRACT;
333 return (GetTypeID() == TYPE_ID_THIS_CLASS);
334 }
335
336 //------------------------------------------------------------------------
337 inline bool IsTypedToken() const
338 {
339 WRAPPER_NO_CONTRACT;
340 return (!IsThisToken());
341 }
342
343 //------------------------------------------------------------------------
344 static DispatchToken From_SIZE_T(SIZE_T token)
345 {
346 WRAPPER_NO_CONTRACT;
347 return DispatchToken((UINT_PTR)token);
348 }
349
350 //------------------------------------------------------------------------
351 SIZE_T To_SIZE_T() const
352 {
353 WRAPPER_NO_CONTRACT;
354 static_assert_no_msg(sizeof(SIZE_T) == sizeof(UINT_PTR));
355 return (SIZE_T) m_token;
356 }
357
358 //------------------------------------------------------------------------
359 inline BOOL IsValid() const
360 {
361 LIMITED_METHOD_CONTRACT;
362 return !(m_token == INVALID_TOKEN);
363 }
364}; // struct DispatchToken
365
366// DispatchToken.m_token should be the only field of DispatchToken.
367static_assert_no_msg(sizeof(DispatchToken) == sizeof(UINT_PTR));
368
369// ===========================================================================
370class TypeIDProvider
371{
372protected:
373 UINT32 m_nextID;
374 UINT32 m_incSize;
375 UINT32 m_nextFatID;
376
377public:
378 // This is used for an invalid type ID.
379 static const UINT32 INVALID_TYPE_ID = ~0;
380
381 // If we can have more than 2^32-1 types, we'll need to revisit this.
382 static const UINT32 MAX_TYPE_ID = INVALID_TYPE_ID - 1;
383
384 //------------------------------------------------------------------------
385 // Ctor
386 TypeIDProvider()
387 : m_nextID(0), m_incSize(0), m_nextFatID(0)
388 { LIMITED_METHOD_CONTRACT; }
389
390
391 //------------------------------------------------------------------------
392 void Init(UINT32 idStartValue, UINT32 idIncrementValue)
393 {
394 LIMITED_METHOD_CONTRACT;
395 m_nextID = idStartValue;
396 m_incSize = idIncrementValue;
397 m_nextFatID = DispatchToken::MAX_TYPE_ID_SMALL + 1;
398 if (m_incSize != 0)
399 {
400 while (!OwnsID(m_nextFatID))
401 {
402 m_nextFatID++;
403 }
404 }
405 }
406
407 //------------------------------------------------------------------------
408 // Returns the next available ID
409 inline UINT32 GetNextID()
410 {
411 CONTRACTL {
412 THROWS;
413 GC_NOTRIGGER;
414 MODE_ANY;
415 SO_TOLERANT;
416 INJECT_FAULT(COMPlusThrowOM());
417 PRECONDITION(m_nextID != 0);
418 PRECONDITION(m_incSize != 0);
419 } CONTRACTL_END;
420 UINT32 id = m_nextID;
421
422 if (id > DispatchToken::MAX_TYPE_ID_SMALL)
423 {
424 return GetNextFatID();
425 }
426
427 if (!ClrSafeInt<UINT32>::addition(m_nextID, m_incSize, m_nextID) ||
428 m_nextID == INVALID_TYPE_ID)
429 {
430 ThrowOutOfMemory();
431 }
432 return id;
433 }
434
435 //------------------------------------------------------------------------
436 // Returns the next available ID
437 inline UINT32 GetNextFatID()
438 {
439 CONTRACTL {
440 THROWS;
441 GC_NOTRIGGER;
442 MODE_ANY;
443 SO_TOLERANT;
444 INJECT_FAULT(COMPlusThrowOM());
445 PRECONDITION(m_nextFatID != 0);
446 PRECONDITION(m_incSize != 0);
447 } CONTRACTL_END;
448 UINT32 id = m_nextFatID;
449 if (!ClrSafeInt<UINT32>::addition(m_nextFatID, m_incSize, m_nextFatID) ||
450 m_nextID == INVALID_TYPE_ID)
451 {
452 ThrowOutOfMemory();
453 }
454 return id;
455 }
456
457 //------------------------------------------------------------------------
458 inline BOOL OwnsID(UINT32 id)
459 {
460 LIMITED_METHOD_CONTRACT;
461 return ((id % m_incSize) == (m_nextID % m_incSize));
462 }
463}; // class TypeIDProvider
464
465// ===========================================================================
466class TypeIDMap
467{
468protected:
469 HashMap m_idMap;
470 HashMap m_mtMap;
471 Crst m_lock;
472 TypeIDProvider m_idProvider;
473 BOOL m_fUseFatIdsForUniqueness;
474 UINT32 m_entryCount;
475
476 //------------------------------------------------------------------------
477 // Returns the next available ID
478 inline UINT32 GetNextID()
479 {
480 WRAPPER_NO_CONTRACT;
481 CONSISTENCY_CHECK(m_lock.OwnedByCurrentThread());
482 UINT32 id = m_idProvider.GetNextID();
483 CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
484 return id;
485 }
486
487 //------------------------------------------------------------------------
488 // Returns the next available FAT ID
489 inline UINT32 GetNextFatID()
490 {
491 WRAPPER_NO_CONTRACT;
492 CONSISTENCY_CHECK(m_lock.OwnedByCurrentThread());
493 UINT32 id = m_idProvider.GetNextFatID();
494 CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS);
495 return id;
496 }
497
498public:
499 // Starting values for shared and unshared domains
500 enum
501 {
502 STARTING_SHARED_DOMAIN_ID = 0x2,
503 STARTING_UNSHARED_DOMAIN_ID = 0x3,
504 };
505
506 //------------------------------------------------------------------------
507 void Init(UINT32 idStartValue, UINT32 idIncrementValue, BOOL fUseFatTokensForUniqueness);
508
509 //------------------------------------------------------------------------
510 // Ctor
511 TypeIDMap()
512 : m_lock(CrstTypeIDMap, CrstFlags(CRST_REENTRANCY))
513 {
514 WRAPPER_NO_CONTRACT;
515 static_assert_no_msg(TypeIDProvider::INVALID_TYPE_ID == static_cast<UINT32>(INVALIDENTRY));
516 }
517
518 //------------------------------------------------------------------------
519 // Dtor
520 ~TypeIDMap()
521 { WRAPPER_NO_CONTRACT; }
522
523 //------------------------------------------------------------------------
524 // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID
525 UINT32 LookupTypeID(PTR_MethodTable pMT);
526
527 //------------------------------------------------------------------------
528 // Returns the ID of the type if found. If not found, returns NULL.
529 PTR_MethodTable LookupType(UINT32 id);
530
531 //------------------------------------------------------------------------
532 // Returns the ID of the type if found. If not found, assigns the ID and
533 // returns the new ID.
534 UINT32 GetTypeID(PTR_MethodTable pMT);
535
536 //------------------------------------------------------------------------
537 inline UINT32 GetCount()
538 { LIMITED_METHOD_CONTRACT; return m_entryCount; }
539
540 //------------------------------------------------------------------------
541 void Clear()
542 {
543 CONTRACTL {
544 NOTHROW;
545 GC_NOTRIGGER;
546 } CONTRACTL_END;
547 m_idMap.Clear();
548 m_mtMap.Clear();
549 m_idProvider.Init(0, 0);
550 }
551
552 //------------------------------------------------------------------------
553 class Iterator
554 {
555 HashMap::Iterator m_it;
556
557 public:
558 //--------------------------------------------------------------------
559 inline Iterator(TypeIDMap *map)
560 : m_it(map->m_mtMap.begin())
561 {
562 WRAPPER_NO_CONTRACT;
563 }
564
565 //--------------------------------------------------------------------
566 inline BOOL IsValid()
567 {
568 WRAPPER_NO_CONTRACT;
569 return !m_it.end();
570 }
571
572 //--------------------------------------------------------------------
573 inline BOOL Next()
574 {
575 // We want to skip the entries that are ID->Type, and just
576 // enumerate the Type->ID entries to avoid duplicates.
577 ++m_it;
578 return IsValid();
579 }
580
581 //--------------------------------------------------------------------
582 inline MethodTable *GetType()
583 {
584 WRAPPER_NO_CONTRACT;
585 return (MethodTable *) m_it.GetKey();
586 }
587
588 //--------------------------------------------------------------------
589 inline UINT32 GetID()
590 {
591 WRAPPER_NO_CONTRACT;
592 return (UINT32) m_it.GetValue();
593 }
594 };
595}; // class TypeIDMap
596
597
598// ===========================================================================
599struct DispatchMapEntry
600{
601private:
602 DispatchMapTypeID m_typeID;
603 UINT16 m_slotNumber;
604 UINT16 m_targetSlotNumber;
605
606 enum
607 {
608 e_IS_VALID = 0x1
609 };
610 UINT16 m_flags;
611
612public:
613 //------------------------------------------------------------------------
614 // Initializes this structure.
615 void InitVirtualMapping(
616 DispatchMapTypeID typeID,
617 UINT32 slotNumber,
618 UINT32 targetSlotNumber)
619 {
620 LIMITED_METHOD_DAC_CONTRACT;
621
622 m_typeID = typeID;
623 m_slotNumber = (UINT16)slotNumber;
624 m_targetSlotNumber = (UINT16)targetSlotNumber;
625
626 // Set the flags
627 m_flags = e_IS_VALID;
628 }
629
630 //------------------------------------------------------------------------
631 inline DispatchMapTypeID GetTypeID()
632 { LIMITED_METHOD_CONTRACT; return m_typeID; }
633
634 //------------------------------------------------------------------------
635 inline UINT32 GetSlotNumber()
636 { LIMITED_METHOD_CONTRACT; return (UINT32) m_slotNumber; }
637
638 //------------------------------------------------------------------------
639 inline UINT32 GetTargetSlotNumber()
640 {
641 LIMITED_METHOD_DAC_CONTRACT;
642 CONSISTENCY_CHECK(IsValid());
643 return (UINT32)m_targetSlotNumber;
644 }
645 inline void SetTargetSlotNumber(UINT32 targetSlotNumber)
646 {
647 LIMITED_METHOD_CONTRACT;
648 CONSISTENCY_CHECK(IsValid());
649 m_targetSlotNumber = (UINT16)targetSlotNumber;
650 }
651
652 //------------------------------------------------------------------------
653 // Ctor - just blanks everything out - need to call Init*Mapping function.
654 inline DispatchMapEntry() : m_flags(0)
655 { LIMITED_METHOD_DAC_CONTRACT; }
656
657 inline BOOL IsValid()
658 { LIMITED_METHOD_CONTRACT; return (m_flags & e_IS_VALID); }
659}; // struct DispatchMapEntry
660
661// ===========================================================================
662// This represents an entry in the dispatch mapping. Conceptually, there is a
663// source to target mapping. There are additional housekeeping flags.
664struct DispatchMapBuilderNode
665{
666 // This represents the type and slot for this mapping
667 DispatchMapTypeID m_typeID;
668 UINT32 m_slotNumber;
669
670 // These represent the target, and type of mapping
671 MethodDesc * m_pMDTarget;
672
673 // Flags
674 UINT32 m_flags;
675
676 enum {
677 e_ENTRY_IS_METHODIMPL = 1
678 };
679
680 // Next entry in the list
681 DispatchMapBuilderNode *m_next;
682
683 //------------------------------------------------------------------------
684 void Init(
685 DispatchMapTypeID typeID,
686 UINT32 slotNumber,
687 MethodDesc * pMDTarget)
688 {
689 WRAPPER_NO_CONTRACT;
690 CONSISTENCY_CHECK(CheckPointer(pMDTarget, NULL_OK));
691 // Remember type and slot
692 m_typeID = typeID;
693 m_slotNumber = slotNumber;
694 // Set the target MD
695 m_pMDTarget = pMDTarget;
696 // Initialize the flags
697 m_flags = 0;
698 // Default to null link
699 m_next = NULL;
700 }
701
702 //------------------------------------------------------------------------
703 inline BOOL IsMethodImpl()
704 {
705 WRAPPER_NO_CONTRACT;
706 return (m_flags & e_ENTRY_IS_METHODIMPL);
707 }
708
709 //------------------------------------------------------------------------
710 inline void SetIsMethodImpl()
711 {
712 WRAPPER_NO_CONTRACT;
713 m_flags |= e_ENTRY_IS_METHODIMPL;
714 }
715}; // struct DispatchMapBuilderNode
716
717// ===========================================================================
718class DispatchMapBuilder
719{
720public:
721 class Iterator;
722
723 //------------------------------------------------------------------------
724 DispatchMapBuilder(StackingAllocator *allocator)
725 : m_pHead(NULL), m_cEntries(0), m_pAllocator(allocator)
726 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(CheckPointer(m_pAllocator)); }
727
728 //------------------------------------------------------------------------
729 inline StackingAllocator *GetAllocator()
730 { LIMITED_METHOD_CONTRACT; return m_pAllocator; }
731
732 //------------------------------------------------------------------------
733 // If TRUE, it points to a matching entry.
734 // If FALSE, it is at the insertion point.
735 BOOL Find(DispatchMapTypeID typeID, UINT32 slotNumber, Iterator &it);
736
737 //------------------------------------------------------------------------
738 // If TRUE, contains such an entry.
739 // If FALSE, no such entry exists.
740 BOOL Contains(DispatchMapTypeID typeID, UINT32 slotNumber);
741
742 //------------------------------------------------------------------------
743 // This is used when building a MT, and things such as implementation
744 // table index and chain delta can't be calculated until later on. That's
745 // why we use an MD to get the information later.
746 void InsertMDMapping(
747 DispatchMapTypeID typeID,
748 UINT32 slotNumber,
749 MethodDesc * pMDTarget,
750 BOOL fIsMethodImpl);
751
752 //------------------------------------------------------------------------
753 inline UINT32 Count()
754 { LIMITED_METHOD_CONTRACT; return m_cEntries; }
755
756 //------------------------------------------------------------------------
757 class Iterator
758 {
759 friend class DispatchMapBuilder;
760
761 protected:
762 DispatchMapBuilderNode **m_cur;
763
764 //--------------------------------------------------------------------
765 inline DispatchMapBuilderNode **EntryNodePtr()
766 { LIMITED_METHOD_CONTRACT; return m_cur; }
767
768 //--------------------------------------------------------------------
769 inline DispatchMapBuilderNode *EntryNode()
770 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsValid()); return *m_cur; }
771
772public:
773 //--------------------------------------------------------------------
774 // Creates an iterator that is pointing to the first entry of the map.
775 inline Iterator(DispatchMapBuilder *pMap)
776 : m_cur(&pMap->m_pHead)
777 { LIMITED_METHOD_CONTRACT; }
778
779 //--------------------------------------------------------------------
780 // Creates an iterator this is pointing to the same location as 'it'.
781 inline Iterator(Iterator &it)
782 : m_cur(it.m_cur)
783 { LIMITED_METHOD_CONTRACT; }
784
785 //--------------------------------------------------------------------
786 inline BOOL IsValid()
787 { LIMITED_METHOD_CONTRACT; return (*m_cur != NULL); }
788
789 //--------------------------------------------------------------------
790 inline BOOL Next()
791 {
792 WRAPPER_NO_CONTRACT;
793 if (!IsValid()) {
794 return FALSE;
795 }
796 m_cur = &((*m_cur)->m_next);
797 return (IsValid());
798 }
799
800 //--------------------------------------------------------------------
801 inline DispatchMapTypeID GetTypeID()
802 {
803 WRAPPER_NO_CONTRACT;
804 CONSISTENCY_CHECK(IsValid());
805 return EntryNode()->m_typeID;
806 }
807
808 //--------------------------------------------------------------------
809 inline UINT32 GetSlotNumber()
810 {
811 WRAPPER_NO_CONTRACT;
812 CONSISTENCY_CHECK(IsValid());
813 return EntryNode()->m_slotNumber;
814 }
815
816 //--------------------------------------------------------------------
817 inline MethodDesc *GetTargetMD()
818 {
819 WRAPPER_NO_CONTRACT;
820 CONSISTENCY_CHECK(IsValid());
821 return EntryNode()->m_pMDTarget;
822 }
823
824 //--------------------------------------------------------------------
825 UINT32 GetTargetSlot();
826
827 //--------------------------------------------------------------------
828 inline void SetTarget(MethodDesc *pMDTarget)
829 {
830 WRAPPER_NO_CONTRACT;
831 CONSISTENCY_CHECK(IsValid());
832 CONSISTENCY_CHECK(CheckPointer(pMDTarget));
833 EntryNode()->m_pMDTarget = pMDTarget;
834 }
835
836 //--------------------------------------------------------------------
837 inline BOOL IsMethodImpl()
838 {
839 WRAPPER_NO_CONTRACT;
840 CONSISTENCY_CHECK(IsValid());
841 return EntryNode()->IsMethodImpl();
842 }
843
844 //--------------------------------------------------------------------
845 inline void SetIsMethodImpl()
846 {
847 WRAPPER_NO_CONTRACT;
848 CONSISTENCY_CHECK(IsValid());
849 EntryNode()->SetIsMethodImpl();
850 }
851
852 inline void SkipThisTypeEntries()
853 {
854 LIMITED_METHOD_CONTRACT;
855 while (IsValid() && GetTypeID() == DispatchMapTypeID::ThisClassID())
856 {
857 Next();
858 }
859 }
860 }; // class Iterator
861
862protected:
863 DispatchMapBuilderNode * m_pHead;
864 UINT32 m_cEntries;
865 StackingAllocator * m_pAllocator;
866
867 //------------------------------------------------------------------------
868 DispatchMapBuilderNode * NewEntry();
869
870}; // class DispatchMapBuilder
871
872typedef DPTR(class DispatchMap) PTR_DispatchMap;
873// ===========================================================================
874class DispatchMap
875{
876protected:
877 BYTE m_rgMap[0];
878
879 static const INT32 ENCODING_TYPE_DELTA = 1;
880 static const INT32 ENCODING_SLOT_DELTA = 1;
881 static const INT32 ENCODING_TARGET_SLOT_DELTA = 1;
882
883public:
884 //------------------------------------------------------------------------
885 // Need to make sure that you allocate GetObjectSize(pMap) bytes for any
886 // instance of DispatchMap, as this constructor assumes that m_rgMap is
887 // large enough to store cbMap bytes, which GetObjectSize ensures.
888 DispatchMap(
889 BYTE * pMap,
890 UINT32 cbMap);
891
892 //------------------------------------------------------------------------
893 static void CreateEncodedMapping(
894 MethodTable * pMT,
895 DispatchMapBuilder * pMapBuilder,
896 StackingAllocator * pAllocator,
897 BYTE ** ppbMap,
898 UINT32 * pcbMap);
899
900 //------------------------------------------------------------------------
901 static UINT32 GetObjectSize(UINT32 cbMap)
902 {
903 LIMITED_METHOD_CONTRACT;
904 return (UINT32)(sizeof(DispatchMap) + cbMap);
905 }
906
907 //------------------------------------------------------------------------
908 UINT32 GetMapSize();
909
910#ifdef DACCESS_COMPILE
911 void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
912#endif
913
914#ifdef FEATURE_PREJIT
915 //------------------------------------------------------------------------
916 void Save(DataImage *image);
917
918 //------------------------------------------------------------------------
919 void Fixup(DataImage *image);
920#endif //FEATURE_PREJIT
921
922 //------------------------------------------------------------------------
923 class EncodedMapIterator
924 {
925 friend class DispatchMap;
926 protected:
927 DispatchMapEntry m_e;
928
929 // These fields are for decoding the implementation map
930 Decoder m_d;
931 // Keep count of the number of types in the list
932 INT32 m_numTypes;
933 INT32 m_curType;
934 DispatchMapTypeID m_curTypeId;
935 BOOL m_fCurTypeHasNegativeEntries;
936
937 // Keep count of the number of entries for the current type
938 INT32 m_numEntries;
939 INT32 m_curEntry;
940 UINT32 m_curSlot;
941
942 UINT32 m_curTargetSlot;
943
944 //--------------------------------------------------------------------
945 void Invalidate();
946
947 //--------------------------------------------------------------------
948 void Init(PTR_BYTE pbMap);
949
950public:
951 //--------------------------------------------------------------------
952 EncodedMapIterator(MethodTable *pMT);
953
954 //--------------------------------------------------------------------
955 // This should be used only when a dispatch map needs to be used
956 // separately from its MethodTable.
957 EncodedMapIterator(DispatchMap *pMap);
958
959 //--------------------------------------------------------------------
960 EncodedMapIterator(PTR_BYTE pbMap);
961
962 //--------------------------------------------------------------------
963 inline BOOL IsValid()
964 { LIMITED_METHOD_DAC_CONTRACT; return (m_curType < m_numTypes); }
965
966 //--------------------------------------------------------------------
967 BOOL Next();
968
969 //--------------------------------------------------------------------
970 inline DispatchMapEntry *Entry()
971 { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsValid()); return &m_e; }
972 }; // class EncodedMapIterator
973
974public:
975 //------------------------------------------------------------------------
976 class Iterator
977 {
978 protected:
979 // This is for generating entries from the encoded map
980 EncodedMapIterator m_mapIt;
981
982 public:
983 //--------------------------------------------------------------------
984 Iterator(MethodTable *pMT);
985
986 //--------------------------------------------------------------------
987 BOOL IsValid();
988
989 //--------------------------------------------------------------------
990 BOOL Next();
991
992 //--------------------------------------------------------------------
993 DispatchMapEntry *Entry();
994 }; // class Iterator
995}; // class DispatchMap
996
997#ifdef LOGGING
998struct StubDispatchStats
999{
1000 // DispatchMap stats
1001 UINT32 m_cDispatchMap; // Number of DispatchMaps created
1002 UINT32 m_cbDispatchMap; // Total size of created maps
1003 UINT32 m_cNGENDispatchMap;
1004 UINT32 m_cbNGENDispatchMap;
1005
1006 // Some comparative stats with the old world (simulated)
1007 UINT32 m_cVTables; // Number of vtables out there
1008 UINT32 m_cVTableSlots; // Total number of slots.
1009 UINT32 m_cVTableDuplicateSlots; // Total number of duplicated slots
1010
1011 UINT32 m_cCacheLookups;
1012 UINT32 m_cCacheMisses;
1013
1014 UINT32 m_cbComInteropData;
1015}; // struct StubDispatchStats
1016
1017extern StubDispatchStats g_sdStats;
1018#endif // LOGGING
1019
1020#endif // !CONTRACTIMPL_H_
1021