diff options
Diffstat (limited to 'src/vm/contractimpl.h')
-rw-r--r-- | src/vm/contractimpl.h | 1020 |
1 files changed, 1020 insertions, 0 deletions
diff --git a/src/vm/contractimpl.h b/src/vm/contractimpl.h new file mode 100644 index 0000000000..d7aefaf12c --- /dev/null +++ b/src/vm/contractimpl.h @@ -0,0 +1,1020 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: contractimpl.h +// +// Keeps track of contract implementations, used primarily in stub dispatch. +// + + +// + +// +// ============================================================================ + +#ifndef CONTRACTIMPL_H_ +#define CONTRACTIMPL_H_ + +#include "hash.h" +#include "decodemd.h" + +class Module; +class MethodDesc; +class StackingAllocator; + +// =========================================================================== +struct DispatchSlot +{ +protected: + PCODE m_slot; + +public: + //------------------------------------------------------------------------ + inline DispatchSlot(PCODE slot) : m_slot(slot) + { LIMITED_METHOD_CONTRACT; } + + //------------------------------------------------------------------------ + inline DispatchSlot(const DispatchSlot &slot) : m_slot(slot.m_slot) + { LIMITED_METHOD_CONTRACT; } + + //------------------------------------------------------------------------ + inline DispatchSlot& operator=(PCODE slot) + { LIMITED_METHOD_CONTRACT; m_slot = slot; return *this; } + + //------------------------------------------------------------------------ + inline DispatchSlot& operator=(const DispatchSlot &slot) + { LIMITED_METHOD_CONTRACT; m_slot = slot.m_slot; return *this; } + + //------------------------------------------------------------------------ + inline BOOL IsNull() + { LIMITED_METHOD_CONTRACT; return (m_slot == NULL); } + + //------------------------------------------------------------------------ + inline void SetNull() + { LIMITED_METHOD_CONTRACT; m_slot = NULL; } + + //------------------------------------------------------------------------ + inline PCODE GetTarget() + { LIMITED_METHOD_CONTRACT; return m_slot; } + + //------------------------------------------------------------------------ + MethodDesc *GetMethodDesc(); +}; // struct DispatchSlot + +// =========================================================================== +// This value indicates that a slot number is in reference to the +// current class. Thus, no TypeID can have a value of 0. This is stored +// inside a DispatchToken as the TypeID for such cases. +static const UINT32 TYPE_ID_THIS_CLASS = 0; + + +// =========================================================================== +// The type IDs used in the dispatch map are relative to the implementing +// type, and are a discriminated union between: +// - a special value to indicate "this" class +// - a special value to indicate that an interface is not implemented by the type +// - an index into the InterfaceMap +class DispatchMapTypeID +{ +private: + static const UINT32 const_nFirstInterfaceIndex = 1; + + UINT32 m_typeIDVal; + DispatchMapTypeID(UINT32 id) { LIMITED_METHOD_DAC_CONTRACT; m_typeIDVal = id; } +public: + // Constructors + static DispatchMapTypeID ThisClassID() { LIMITED_METHOD_CONTRACT; return DispatchMapTypeID(TYPE_ID_THIS_CLASS); } + static DispatchMapTypeID InterfaceClassID(UINT32 inum) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(inum + const_nFirstInterfaceIndex > inum); + return DispatchMapTypeID(inum + const_nFirstInterfaceIndex); + } + DispatchMapTypeID() { LIMITED_METHOD_DAC_CONTRACT; m_typeIDVal = TYPE_ID_THIS_CLASS; } + + // Accessors + BOOL IsThisClass() const { LIMITED_METHOD_DAC_CONTRACT; return (m_typeIDVal == TYPE_ID_THIS_CLASS); } + BOOL IsImplementedInterface() const { LIMITED_METHOD_CONTRACT; return (m_typeIDVal >= const_nFirstInterfaceIndex); } + UINT32 GetInterfaceNum() const + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(IsImplementedInterface()); + return (m_typeIDVal - const_nFirstInterfaceIndex); + } + + // Ordering/equality + BOOL operator ==(const DispatchMapTypeID &that) const { LIMITED_METHOD_CONTRACT; return m_typeIDVal == that.m_typeIDVal; } + BOOL operator !=(const DispatchMapTypeID &that) const { LIMITED_METHOD_CONTRACT; return m_typeIDVal != that.m_typeIDVal; } + BOOL operator <(const DispatchMapTypeID &that) const { LIMITED_METHOD_CONTRACT; return m_typeIDVal < that.m_typeIDVal; } + + // To/from UINT32, for encoding/decoding etc. + UINT32 ToUINT32() const { LIMITED_METHOD_DAC_CONTRACT; return m_typeIDVal; } + static DispatchMapTypeID FromUINT32(UINT32 x) { LIMITED_METHOD_DAC_CONTRACT; return DispatchMapTypeID(x); } +}; // class DispatchMapTypeID + +#ifdef FAT_DISPATCH_TOKENS +// =========================================================================== +// This is the structure that is used when typeId becomes too be to be +// contained in a regular DispatchToken. DispatchToken is able to encapsulate +// a DispatchTokenFat*, somewhat like TypeHandle may encapsulate a TypeDesc*. +struct DispatchTokenFat +{ + friend struct DispatchToken; + friend class BaseDomain; + + private: + UINT32 m_typeId; + UINT32 m_slotNum; + + public: + DispatchTokenFat(UINT32 typeID, UINT32 slotNumber) + : m_typeId(typeID), m_slotNum(slotNumber) + {} + + // Equality comparison, used in SHash set. + bool operator==(const DispatchTokenFat &other) const + { return m_typeId == other.m_typeId && m_slotNum == other.m_slotNum; } + + // Hashing operator, using in SHash set. + operator size_t() const + { return (size_t)m_typeId ^ (size_t)m_slotNum; } +}; // struct DispatchTokenFat + +typedef DPTR(DispatchTokenFat) PTR_DispatchTokenFat; +#endif + +// =========================================================================== +// This represents the contract used for code lookups throughout the +// virtual stub dispatch mechanism. It is important to know that +// sizeof(DispatchToken) is UINT_PTR, which means it can be thrown around +// by value without a problem. + +struct DispatchToken +{ +private: + // IMPORTANT: This is the ONLY member of this class. + UINT_PTR m_token; + +#ifndef _WIN64 + // NOTE: On 32-bit, we use the uppermost bit to indicate that the + // token is really a DispatchTokenFat*, and to recover the pointer + // we just shift left by 1; correspondingly, when storing a + // DispatchTokenFat* in a DispatchToken, we shift right by 1. + static const UINT_PTR MASK_TYPE_ID = 0x00007FFF; + static const UINT_PTR MASK_SLOT_NUMBER = 0x0000FFFF; + + static const UINT_PTR SHIFT_TYPE_ID = 0x10; + static const UINT_PTR SHIFT_SLOT_NUMBER = 0x0; + +#ifdef FAT_DISPATCH_TOKENS + static const UINT_PTR FAT_TOKEN_FLAG = 0x80000000; +#endif // FAT_DISPATCH_TOKENS + + static const UINT_PTR INVALID_TOKEN = 0x7FFFFFFF; +#else //_WIN64 + static const UINT_PTR MASK_TYPE_ID = UI64(0x000000007FFFFFFF); + static const UINT_PTR MASK_SLOT_NUMBER = UI64(0x000000000000FFFF); + + static const UINT_PTR SHIFT_TYPE_ID = 0x20; + static const UINT_PTR SHIFT_SLOT_NUMBER = 0x0; + +#ifdef FAT_DISPATCH_TOKENS + static const UINT_PTR FAT_TOKEN_FLAG = UI64(0x8000000000000000); +#endif // FAT_DISPATCH_TOKENS + + static const UINT_PTR INVALID_TOKEN = 0x7FFFFFFFFFFFFFFF; +#endif //_WIN64 + +#ifdef FAT_DISPATCH_TOKENS + //------------------------------------------------------------------------ + static inline BOOL IsFat(UINT_PTR token) + { + return (token & FAT_TOKEN_FLAG) != 0; + } + + //------------------------------------------------------------------------ + static inline DispatchTokenFat* ToFat(UINT_PTR token) + { + return PTR_DispatchTokenFat(token << 1); + } +#endif + + //------------------------------------------------------------------------ + // Combines the two values into a single 32-bit number. + static UINT_PTR CreateToken(UINT32 typeID, UINT32 slotNumber) + { + LIMITED_METHOD_CONTRACT; + CONSISTENCY_CHECK(((UINT_PTR)typeID & MASK_TYPE_ID) == (UINT_PTR)typeID); + CONSISTENCY_CHECK(((UINT_PTR)slotNumber & MASK_SLOT_NUMBER) == (UINT_PTR)slotNumber); + return ((((UINT_PTR)typeID & MASK_TYPE_ID) << SHIFT_TYPE_ID) | + (((UINT_PTR)slotNumber & MASK_SLOT_NUMBER) << SHIFT_SLOT_NUMBER)); + } + + //------------------------------------------------------------------------ + // Extracts the type ID from a token created by CreateToken + static UINT32 DecodeTypeID(UINT_PTR token) + { + LIMITED_METHOD_CONTRACT; + CONSISTENCY_CHECK(token != INVALID_TOKEN); +#ifdef FAT_DISPATCH_TOKENS + if (IsFat(token)) + return ToFat(token)->m_typeId; + else +#endif + return ((token >> SHIFT_TYPE_ID) & MASK_TYPE_ID); + } + + //------------------------------------------------------------------------ + // Extracts the slot number from a token created by CreateToken + static UINT32 DecodeSlotNumber(UINT_PTR token) + { + LIMITED_METHOD_CONTRACT; + CONSISTENCY_CHECK(token != INVALID_TOKEN); +#ifdef FAT_DISPATCH_TOKENS + if (IsFat(token)) + return ToFat(token)->m_slotNum; + else +#endif + return ((token >> SHIFT_SLOT_NUMBER) & MASK_SLOT_NUMBER); + } + +public: + +#ifdef FAT_DISPATCH_TOKENS +#if !defined(_WIN64) + static const UINT32 MAX_TYPE_ID_SMALL = 0x00007FFF; +#else + static const UINT32 MAX_TYPE_ID_SMALL = 0x7FFFFFFF; +#endif +#endif // FAT_DISPATCH_TOKENS + + //------------------------------------------------------------------------ + DispatchToken() + { + LIMITED_METHOD_CONTRACT; + m_token = INVALID_TOKEN; + } + + DispatchToken(UINT_PTR token) + { + CONSISTENCY_CHECK(token != INVALID_TOKEN); + m_token = token; + } + +#ifdef FAT_DISPATCH_TOKENS + //------------------------------------------------------------------------ + DispatchToken(DispatchTokenFat *pFat) + { + LIMITED_METHOD_CONTRACT; + CONSISTENCY_CHECK((((UINT_PTR)pFat) & 0x1) == 0); + m_token = (UINT_PTR(pFat) >> 1) | FAT_TOKEN_FLAG; + } + + //------------------------------------------------------------------------ + static bool RequiresDispatchTokenFat(UINT32 typeID, UINT32 slotNumber) + { + LIMITED_METHOD_CONTRACT; + return typeID > MAX_TYPE_ID_SMALL +#ifdef _DEBUG + // Stress the overflow mechanism in debug builds. + || ((typeID != TYPE_ID_THIS_CLASS) && ((typeID % 7) < 4)) +#endif + ; + } +#endif //FAT_DISPATCH_TOKENS + + //------------------------------------------------------------------------ + inline bool operator==(const DispatchToken &tok) const + { + LIMITED_METHOD_CONTRACT; + return m_token == tok.m_token; + } + + //------------------------------------------------------------------------ + // Creates a "this" type dispatch token. This means that the type for the + // token is implied by the type on which one wishes to invoke. In other + // words, the value returned by GetTypeID is TYPE_ID_THIS_CLASS. + static DispatchToken CreateDispatchToken(UINT32 slotNumber) + { + WRAPPER_NO_CONTRACT; + return DispatchToken(CreateToken(TYPE_ID_THIS_CLASS, slotNumber)); + } + + //------------------------------------------------------------------------ + // Creates a fully qualified type dispatch token. This means that the ID + // for the type is encoded directly in the token. + static DispatchToken CreateDispatchToken(UINT32 typeID, UINT32 slotNumber) + { + WRAPPER_NO_CONTRACT; + return DispatchToken(CreateToken(typeID, slotNumber)); + } + + //------------------------------------------------------------------------ + // Returns the type ID for this dispatch contract + inline UINT32 GetTypeID() const + { + WRAPPER_NO_CONTRACT; + return DecodeTypeID(m_token); + } + + //------------------------------------------------------------------------ + // Returns the slot number for this dispatch contract + inline UINT32 GetSlotNumber() const + { + WRAPPER_NO_CONTRACT; + return DecodeSlotNumber(m_token); + } + + //------------------------------------------------------------------------ + inline bool IsThisToken() const + { + WRAPPER_NO_CONTRACT; + return (GetTypeID() == TYPE_ID_THIS_CLASS); + } + + //------------------------------------------------------------------------ + inline bool IsTypedToken() const + { + WRAPPER_NO_CONTRACT; + return (!IsThisToken()); + } + + //------------------------------------------------------------------------ + static DispatchToken From_SIZE_T(SIZE_T token) + { + WRAPPER_NO_CONTRACT; + return DispatchToken((UINT_PTR)token); + } + + //------------------------------------------------------------------------ + SIZE_T To_SIZE_T() const + { + WRAPPER_NO_CONTRACT; + static_assert_no_msg(sizeof(SIZE_T) == sizeof(UINT_PTR)); + return (SIZE_T) m_token; + } + + //------------------------------------------------------------------------ + inline BOOL IsValid() const + { + LIMITED_METHOD_CONTRACT; + return !(m_token == INVALID_TOKEN); + } +}; // struct DispatchToken + +// DispatchToken.m_token should be the only field of DispatchToken. +static_assert_no_msg(sizeof(DispatchToken) == sizeof(UINT_PTR)); + +// =========================================================================== +class TypeIDProvider +{ +protected: + UINT32 m_nextID; + UINT32 m_incSize; + UINT32 m_nextFatID; + +public: + // This is used for an invalid type ID. + static const UINT32 INVALID_TYPE_ID = ~0; + + // If we can have more than 2^32-1 types, we'll need to revisit this. + static const UINT32 MAX_TYPE_ID = INVALID_TYPE_ID - 1; + + //------------------------------------------------------------------------ + // Ctor + TypeIDProvider() + : m_nextID(0), m_incSize(0), m_nextFatID(0) + { LIMITED_METHOD_CONTRACT; } + + + //------------------------------------------------------------------------ + void Init(UINT32 idStartValue, UINT32 idIncrementValue) + { + LIMITED_METHOD_CONTRACT; + m_nextID = idStartValue; + m_incSize = idIncrementValue; + m_nextFatID = DispatchToken::MAX_TYPE_ID_SMALL + 1; + if (m_incSize != 0) + { + while (!OwnsID(m_nextFatID)) + { + m_nextFatID++; + } + } + } + + //------------------------------------------------------------------------ + // Returns the next available ID + inline UINT32 GetNextID() + { + CONTRACTL { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + INJECT_FAULT(COMPlusThrowOM()); + PRECONDITION(m_nextID != 0); + PRECONDITION(m_incSize != 0); + } CONTRACTL_END; + UINT32 id = m_nextID; + + if (id > DispatchToken::MAX_TYPE_ID_SMALL) + { + return GetNextFatID(); + } + + if (!ClrSafeInt<UINT32>::addition(m_nextID, m_incSize, m_nextID) || + m_nextID == INVALID_TYPE_ID) + { + ThrowOutOfMemory(); + } + return id; + } + + //------------------------------------------------------------------------ + // Returns the next available ID + inline UINT32 GetNextFatID() + { + CONTRACTL { + THROWS; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + INJECT_FAULT(COMPlusThrowOM()); + PRECONDITION(m_nextFatID != 0); + PRECONDITION(m_incSize != 0); + } CONTRACTL_END; + UINT32 id = m_nextFatID; + if (!ClrSafeInt<UINT32>::addition(m_nextFatID, m_incSize, m_nextFatID) || + m_nextID == INVALID_TYPE_ID) + { + ThrowOutOfMemory(); + } + return id; + } + + //------------------------------------------------------------------------ + inline BOOL OwnsID(UINT32 id) + { + LIMITED_METHOD_CONTRACT; + return ((id % m_incSize) == (m_nextID % m_incSize)); + } +}; // class TypeIDProvider + +// =========================================================================== +class TypeIDMap +{ +protected: + HashMap m_idMap; + HashMap m_mtMap; + Crst m_lock; + TypeIDProvider m_idProvider; + BOOL m_fUseFatIdsForUniqueness; + UINT32 m_entryCount; + + //------------------------------------------------------------------------ + // Returns the next available ID + inline UINT32 GetNextID() + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(m_lock.OwnedByCurrentThread()); + UINT32 id = m_idProvider.GetNextID(); + CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); + return id; + } + + //------------------------------------------------------------------------ + // Returns the next available FAT ID + inline UINT32 GetNextFatID() + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(m_lock.OwnedByCurrentThread()); + UINT32 id = m_idProvider.GetNextFatID(); + CONSISTENCY_CHECK(id != TYPE_ID_THIS_CLASS); + return id; + } + +public: + // Starting values for shared and unshared domains + enum + { + STARTING_SHARED_DOMAIN_ID = 0x2, + STARTING_UNSHARED_DOMAIN_ID = 0x3, + }; + + //------------------------------------------------------------------------ + void Init(UINT32 idStartValue, UINT32 idIncrementValue, BOOL fUseFatTokensForUniqueness); + + //------------------------------------------------------------------------ + // Ctor + TypeIDMap() + : m_lock(CrstTypeIDMap, CrstFlags(CRST_REENTRANCY)) + { + WRAPPER_NO_CONTRACT; + static_assert_no_msg(TypeIDProvider::INVALID_TYPE_ID == static_cast<UINT32>(INVALIDENTRY)); + } + + //------------------------------------------------------------------------ + // Dtor + ~TypeIDMap() + { WRAPPER_NO_CONTRACT; } + + //------------------------------------------------------------------------ + // Returns the ID of the type if found. If not found, returns INVALID_TYPE_ID + UINT32 LookupTypeID(PTR_MethodTable pMT); + + //------------------------------------------------------------------------ + // Returns the ID of the type if found. If not found, returns NULL. + PTR_MethodTable LookupType(UINT32 id); + + //------------------------------------------------------------------------ + // Returns the ID of the type if found. If not found, assigns the ID and + // returns the new ID. + UINT32 GetTypeID(PTR_MethodTable pMT); + + //------------------------------------------------------------------------ + inline UINT32 GetCount() + { LIMITED_METHOD_CONTRACT; return m_entryCount; } + + //------------------------------------------------------------------------ + void Clear() + { + CONTRACTL { + NOTHROW; + GC_NOTRIGGER; + } CONTRACTL_END; + m_idMap.Clear(); + m_mtMap.Clear(); + m_idProvider.Init(0, 0); + } + + //------------------------------------------------------------------------ + class Iterator + { + HashMap::Iterator m_it; + + public: + //-------------------------------------------------------------------- + inline Iterator(TypeIDMap *map) + : m_it(map->m_mtMap.begin()) + { + WRAPPER_NO_CONTRACT; + } + + //-------------------------------------------------------------------- + inline BOOL IsValid() + { + WRAPPER_NO_CONTRACT; + return !m_it.end(); + } + + //-------------------------------------------------------------------- + inline BOOL Next() + { + // We want to skip the entries that are ID->Type, and just + // enumerate the Type->ID entries to avoid duplicates. + ++m_it; + return IsValid(); + } + + //-------------------------------------------------------------------- + inline MethodTable *GetType() + { + WRAPPER_NO_CONTRACT; + return (MethodTable *) m_it.GetKey(); + } + + //-------------------------------------------------------------------- + inline UINT32 GetID() + { + WRAPPER_NO_CONTRACT; + return (UINT32) m_it.GetValue(); + } + }; +}; // class TypeIDMap + + +// =========================================================================== +struct DispatchMapEntry +{ +private: + DispatchMapTypeID m_typeID; + UINT16 m_slotNumber; + UINT16 m_targetSlotNumber; + + enum + { + e_IS_VALID = 0x1 + }; + UINT16 m_flags; + +public: + //------------------------------------------------------------------------ + // Initializes this structure. + void InitVirtualMapping( + DispatchMapTypeID typeID, + UINT32 slotNumber, + UINT32 targetSlotNumber) + { + LIMITED_METHOD_DAC_CONTRACT; + + m_typeID = typeID; + m_slotNumber = (UINT16)slotNumber; + m_targetSlotNumber = (UINT16)targetSlotNumber; + + // Set the flags + m_flags = e_IS_VALID; + } + + //------------------------------------------------------------------------ + inline DispatchMapTypeID GetTypeID() + { LIMITED_METHOD_CONTRACT; return m_typeID; } + + //------------------------------------------------------------------------ + inline UINT32 GetSlotNumber() + { LIMITED_METHOD_CONTRACT; return (UINT32) m_slotNumber; } + + //------------------------------------------------------------------------ + inline UINT32 GetTargetSlotNumber() + { + LIMITED_METHOD_DAC_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + return (UINT32)m_targetSlotNumber; + } + inline void SetTargetSlotNumber(UINT32 targetSlotNumber) + { + LIMITED_METHOD_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + m_targetSlotNumber = (UINT16)targetSlotNumber; + } + + //------------------------------------------------------------------------ + // Ctor - just blanks everything out - need to call Init*Mapping function. + inline DispatchMapEntry() : m_flags(0) + { LIMITED_METHOD_DAC_CONTRACT; } + + inline BOOL IsValid() + { LIMITED_METHOD_CONTRACT; return (m_flags & e_IS_VALID); } +}; // struct DispatchMapEntry + +// =========================================================================== +// This represents an entry in the dispatch mapping. Conceptually, there is a +// source to target mapping. There are additional housekeeping flags. +struct DispatchMapBuilderNode +{ + // This represents the type and slot for this mapping + DispatchMapTypeID m_typeID; + UINT32 m_slotNumber; + + // These represent the target, and type of mapping + MethodDesc * m_pMDTarget; + + // Flags + UINT32 m_flags; + + enum { + e_ENTRY_IS_METHODIMPL = 1 + }; + + // Next entry in the list + DispatchMapBuilderNode *m_next; + + //------------------------------------------------------------------------ + void Init( + DispatchMapTypeID typeID, + UINT32 slotNumber, + MethodDesc * pMDTarget) + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(CheckPointer(pMDTarget, NULL_OK)); + // Remember type and slot + m_typeID = typeID; + m_slotNumber = slotNumber; + // Set the target MD + m_pMDTarget = pMDTarget; + // Initialize the flags + m_flags = 0; + // Default to null link + m_next = NULL; + } + + //------------------------------------------------------------------------ + inline BOOL IsMethodImpl() + { + WRAPPER_NO_CONTRACT; + return (m_flags & e_ENTRY_IS_METHODIMPL); + } + + //------------------------------------------------------------------------ + inline void SetIsMethodImpl() + { + WRAPPER_NO_CONTRACT; + m_flags |= e_ENTRY_IS_METHODIMPL; + } +}; // struct DispatchMapBuilderNode + +// =========================================================================== +class DispatchMapBuilder +{ +public: + class Iterator; + + //------------------------------------------------------------------------ + DispatchMapBuilder(StackingAllocator *allocator) + : m_pHead(NULL), m_cEntries(0), m_pAllocator(allocator) + { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(CheckPointer(m_pAllocator)); } + + //------------------------------------------------------------------------ + inline StackingAllocator *GetAllocator() + { LIMITED_METHOD_CONTRACT; return m_pAllocator; } + + //------------------------------------------------------------------------ + // If TRUE, it points to a matching entry. + // If FALSE, it is at the insertion point. + BOOL Find(DispatchMapTypeID typeID, UINT32 slotNumber, Iterator &it); + + //------------------------------------------------------------------------ + // If TRUE, contains such an entry. + // If FALSE, no such entry exists. + BOOL Contains(DispatchMapTypeID typeID, UINT32 slotNumber); + + //------------------------------------------------------------------------ + // This is used when building a MT, and things such as implementation + // table index and chain delta can't be calculated until later on. That's + // why we use an MD to get the information later. + void InsertMDMapping( + DispatchMapTypeID typeID, + UINT32 slotNumber, + MethodDesc * pMDTarget, + BOOL fIsMethodImpl); + + //------------------------------------------------------------------------ + inline UINT32 Count() + { LIMITED_METHOD_CONTRACT; return m_cEntries; } + + //------------------------------------------------------------------------ + class Iterator + { + friend class DispatchMapBuilder; + + protected: + DispatchMapBuilderNode **m_cur; + + //-------------------------------------------------------------------- + inline DispatchMapBuilderNode **EntryNodePtr() + { LIMITED_METHOD_CONTRACT; return m_cur; } + + //-------------------------------------------------------------------- + inline DispatchMapBuilderNode *EntryNode() + { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsValid()); return *m_cur; } + +public: + //-------------------------------------------------------------------- + // Creates an iterator that is pointing to the first entry of the map. + inline Iterator(DispatchMapBuilder *pMap) + : m_cur(&pMap->m_pHead) + { LIMITED_METHOD_CONTRACT; } + + //-------------------------------------------------------------------- + // Creates an iterator this is pointing to the same location as 'it'. + inline Iterator(Iterator &it) + : m_cur(it.m_cur) + { LIMITED_METHOD_CONTRACT; } + + //-------------------------------------------------------------------- + inline BOOL IsValid() + { LIMITED_METHOD_CONTRACT; return (*m_cur != NULL); } + + //-------------------------------------------------------------------- + inline BOOL Next() + { + WRAPPER_NO_CONTRACT; + if (!IsValid()) { + return FALSE; + } + m_cur = &((*m_cur)->m_next); + return (IsValid()); + } + + //-------------------------------------------------------------------- + inline DispatchMapTypeID GetTypeID() + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + return EntryNode()->m_typeID; + } + + //-------------------------------------------------------------------- + inline UINT32 GetSlotNumber() + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + return EntryNode()->m_slotNumber; + } + + //-------------------------------------------------------------------- + inline MethodDesc *GetTargetMD() + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + return EntryNode()->m_pMDTarget; + } + + //-------------------------------------------------------------------- + UINT32 GetTargetSlot(); + + //-------------------------------------------------------------------- + inline void SetTarget(MethodDesc *pMDTarget) + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + CONSISTENCY_CHECK(CheckPointer(pMDTarget)); + EntryNode()->m_pMDTarget = pMDTarget; + } + + //-------------------------------------------------------------------- + inline BOOL IsMethodImpl() + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + return EntryNode()->IsMethodImpl(); + } + + //-------------------------------------------------------------------- + inline void SetIsMethodImpl() + { + WRAPPER_NO_CONTRACT; + CONSISTENCY_CHECK(IsValid()); + EntryNode()->SetIsMethodImpl(); + } + + inline void SkipThisTypeEntries() + { + LIMITED_METHOD_CONTRACT; + while (IsValid() && GetTypeID() == DispatchMapTypeID::ThisClassID()) + { + Next(); + } + } + }; // class Iterator + +protected: + DispatchMapBuilderNode * m_pHead; + UINT32 m_cEntries; + StackingAllocator * m_pAllocator; + + //------------------------------------------------------------------------ + DispatchMapBuilderNode * NewEntry(); + +}; // class DispatchMapBuilder + +typedef DPTR(class DispatchMap) PTR_DispatchMap; +// =========================================================================== +class DispatchMap +{ +protected: + BYTE m_rgMap[0]; + + static const INT32 ENCODING_TYPE_DELTA = 1; + static const INT32 ENCODING_SLOT_DELTA = 1; + static const INT32 ENCODING_TARGET_SLOT_DELTA = 1; + +public: + //------------------------------------------------------------------------ + // Need to make sure that you allocate GetObjectSize(pMap) bytes for any + // instance of DispatchMap, as this constructor assumes that m_rgMap is + // large enough to store cbMap bytes, which GetObjectSize ensures. + DispatchMap( + BYTE * pMap, + UINT32 cbMap); + + //------------------------------------------------------------------------ + static void CreateEncodedMapping( + MethodTable * pMT, + DispatchMapBuilder * pMapBuilder, + StackingAllocator * pAllocator, + BYTE ** ppbMap, + UINT32 * pcbMap); + + //------------------------------------------------------------------------ + static UINT32 GetObjectSize(UINT32 cbMap) + { + LIMITED_METHOD_CONTRACT; + return (UINT32)(sizeof(DispatchMap) + cbMap); + } + + //------------------------------------------------------------------------ + UINT32 GetMapSize(); + +#ifdef DACCESS_COMPILE + void EnumMemoryRegions(CLRDataEnumMemoryFlags flags); +#endif + +#ifdef FEATURE_PREJIT + //------------------------------------------------------------------------ + void Save(DataImage *image); + + //------------------------------------------------------------------------ + void Fixup(DataImage *image); +#endif //FEATURE_PREJIT + + //------------------------------------------------------------------------ + class EncodedMapIterator + { + friend class DispatchMap; + protected: + DispatchMapEntry m_e; + + // These fields are for decoding the implementation map + Decoder m_d; + // Keep count of the number of types in the list + INT32 m_numTypes; + INT32 m_curType; + DispatchMapTypeID m_curTypeId; + BOOL m_fCurTypeHasNegativeEntries; + + // Keep count of the number of entries for the current type + INT32 m_numEntries; + INT32 m_curEntry; + UINT32 m_curSlot; + + UINT32 m_curTargetSlot; + + //-------------------------------------------------------------------- + void Invalidate(); + + //-------------------------------------------------------------------- + void Init(PTR_BYTE pbMap); + +public: + //-------------------------------------------------------------------- + EncodedMapIterator(MethodTable *pMT); + + //-------------------------------------------------------------------- + // This should be used only when a dispatch map needs to be used + // separately from its MethodTable. + EncodedMapIterator(DispatchMap *pMap); + + //-------------------------------------------------------------------- + EncodedMapIterator(PTR_BYTE pbMap); + + //-------------------------------------------------------------------- + inline BOOL IsValid() + { LIMITED_METHOD_DAC_CONTRACT; return (m_curType < m_numTypes); } + + //-------------------------------------------------------------------- + BOOL Next(); + + //-------------------------------------------------------------------- + inline DispatchMapEntry *Entry() + { LIMITED_METHOD_CONTRACT; CONSISTENCY_CHECK(IsValid()); return &m_e; } + }; // class EncodedMapIterator + +public: + //------------------------------------------------------------------------ + class Iterator + { + protected: + // This is for generating entries from the encoded map + EncodedMapIterator m_mapIt; + + public: + //-------------------------------------------------------------------- + Iterator(MethodTable *pMT); + + //-------------------------------------------------------------------- + BOOL IsValid(); + + //-------------------------------------------------------------------- + BOOL Next(); + + //-------------------------------------------------------------------- + DispatchMapEntry *Entry(); + }; // class Iterator +}; // class DispatchMap + +#ifdef LOGGING +struct StubDispatchStats +{ + // DispatchMap stats + UINT32 m_cDispatchMap; // Number of DispatchMaps created + UINT32 m_cbDispatchMap; // Total size of created maps + UINT32 m_cNGENDispatchMap; + UINT32 m_cbNGENDispatchMap; + + // Some comparative stats with the old world (simulated) + UINT32 m_cVTables; // Number of vtables out there + UINT32 m_cVTableSlots; // Total number of slots. + UINT32 m_cVTableDuplicateSlots; // Total number of duplicated slots + + UINT32 m_cCacheLookups; + UINT32 m_cCacheMisses; + + UINT32 m_cbComInteropData; +}; // struct StubDispatchStats + +extern StubDispatchStats g_sdStats; +#endif // LOGGING + +#endif // !CONTRACTIMPL_H_ |