Merge pull request #14619 from briansull/emitter-cleanup
[platform/upstream/coreclr.git] / src / vm / contractimpl.h
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
22 class Module;
23 class MethodDesc;
24 class StackingAllocator;
25
26 // ===========================================================================
27 struct DispatchSlot
28 {
29 protected:
30     PCODE m_slot;
31
32 public:
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.
69 static 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
78 class DispatchMapTypeID
79 {
80 private:
81     static const UINT32 const_nFirstInterfaceIndex = 1;
82
83     UINT32 m_typeIDVal;
84     DispatchMapTypeID(UINT32 id) { LIMITED_METHOD_DAC_CONTRACT; m_typeIDVal = id; }
85 public:
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*.
121 struct 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
144 typedef 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
153 struct DispatchToken
154 {
155 private:
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
242 public:
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.
367 static_assert_no_msg(sizeof(DispatchToken) == sizeof(UINT_PTR));
368
369 // ===========================================================================
370 class TypeIDProvider
371 {
372 protected:
373     UINT32 m_nextID;
374     UINT32 m_incSize;
375     UINT32 m_nextFatID;
376
377 public:
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 // ===========================================================================
466 class TypeIDMap
467 {
468 protected:
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
498 public:
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 // ===========================================================================
599 struct DispatchMapEntry
600 {
601 private:
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
612 public:
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.
664 struct 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 // ===========================================================================
718 class DispatchMapBuilder
719 {
720 public:
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
772 public:
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
862 protected:
863     DispatchMapBuilderNode * m_pHead;
864     UINT32                   m_cEntries;
865     StackingAllocator *      m_pAllocator;
866
867     //------------------------------------------------------------------------
868     DispatchMapBuilderNode * NewEntry();
869
870 };  // class DispatchMapBuilder
871
872 typedef DPTR(class DispatchMap) PTR_DispatchMap;
873 // ===========================================================================
874 class DispatchMap
875 {
876 protected:
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
883 public:
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
950 public:
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
974 public:
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 
998 struct 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
1017 extern StubDispatchStats g_sdStats;
1018 #endif // LOGGING
1019
1020 #endif // !CONTRACTIMPL_H_