diff options
Diffstat (limited to 'src/vm/genericdict.h')
-rw-r--r-- | src/vm/genericdict.h | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/src/vm/genericdict.h b/src/vm/genericdict.h new file mode 100644 index 0000000000..1cb172a174 --- /dev/null +++ b/src/vm/genericdict.h @@ -0,0 +1,331 @@ +// 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: genericdict.h +// + +// +// Definitions for "dictionaries" used to encapsulate generic instantiations +// and instantiation-specific information for shared-code generics +// + +// +// ============================================================================ + +#ifndef _GENERICDICT_H +#define _GENERICDICT_H + +#ifdef FEATURE_PREJIT +#include "dataimage.h" +#endif + +// DICTIONARIES +// +// A dictionary is a cache of handles associated with particular +// instantiations of generic classes and generic methods, containing +// - the instantiation itself (a list of TypeHandles) +// - handles created on demand at runtime when code shared between +// multiple instantiations needs to lookup an instantiation-specific +// handle (for example, in newobj C<!0> and castclass !!0[]) +// +// DICTIONARY ENTRIES +// +// Dictionary entries (abstracted as the type DictionaryEntry) can be: +// a TypeHandle (for type arguments and entries associated with a TypeSpec token) +// a MethodDesc* (for entries associated with a method MemberRef or MethodSpec token) +// a FieldDesc* (for entries associated with a field MemberRef token) +// a code pointer (e.g. for entries associated with an EntryPointAnnotation annotated token) +// a dispatch stub address (for entries associated with an StubAddrAnnotation annotated token) +// +// DICTIONARY LAYOUTS +// +// A dictionary layout describes the layout of all dictionaries that can be +// accessed from the same shared code. For example, Hashtable<string,int> and +// Hashtable<object,int> share one layout, and Hashtable<int,string> and Hashtable<int,object> +// share another layout. For generic types, the dictionary layout is stored in the EEClass +// that is shared across compatible instantiations. For generic methods, the layout +// is stored in the InstantiatedMethodDesc associated with the shared generic code itself. +// + +class TypeHandleList; +class Module; +class BaseDomain; +class SigTypeContext; +class SigBuilder; + +enum DictionaryEntryKind +{ + EmptySlot = 0, + TypeHandleSlot = 1, + MethodDescSlot = 2, + MethodEntrySlot = 3, + ConstrainedMethodEntrySlot = 4, + DispatchStubAddrSlot = 5, + FieldDescSlot = 6, + DeclaringTypeHandleSlot = 7, +}; + +enum DictionaryEntrySignatureSource : BYTE +{ + FromZapImage = 0, + FromReadyToRunImage = 1, + FromJIT = 2, +}; + +class DictionaryEntryLayout +{ +public: + DictionaryEntryLayout(PTR_VOID signature) + { LIMITED_METHOD_CONTRACT; m_signature = signature; } + + DictionaryEntryKind GetKind(); + + PTR_VOID m_signature; + + DictionaryEntrySignatureSource m_signatureSource; +}; + +typedef DPTR(DictionaryEntryLayout) PTR_DictionaryEntryLayout; + + +class DictionaryLayout; +typedef DPTR(DictionaryLayout) PTR_DictionaryLayout; + +// The type of dictionary layouts. We don't include the number of type +// arguments as this is obtained elsewhere +class DictionaryLayout +{ + friend class Dictionary; +#ifdef DACCESS_COMPILE + friend class NativeImageDumper; +#endif +private: + // Next bucket of slots (only used to track entries that won't fit in the dictionary) + DictionaryLayout* m_pNext; + + // Number of non-type-argument slots in this bucket + WORD m_numSlots; + + // m_numSlots of these + DictionaryEntryLayout m_slots[1]; + + static BOOL FindTokenWorker(LoaderAllocator *pAllocator, + DWORD numGenericArgs, + DictionaryLayout *pDictLayout, + CORINFO_RUNTIME_LOOKUP *pResult, + SigBuilder * pSigBuilder, + BYTE * pSig, + DWORD cbSig, + int nFirstOffset, + DictionaryEntrySignatureSource signatureSource, + WORD * pSlotOut); + + +public: + // Create an initial dictionary layout with a single bucket containing numSlots slots + static DictionaryLayout* Allocate(WORD numSlots, LoaderAllocator *pAllocator, AllocMemTracker *pamTracker); + + // Bytes used for the first bucket of this dictionary, which might be stored inline in + // another structure (e.g. MethodTable) + static DWORD GetFirstDictionaryBucketSize(DWORD numGenericArgs, PTR_DictionaryLayout pDictLayout); + + static BOOL FindToken(LoaderAllocator *pAllocator, + DWORD numGenericArgs, + DictionaryLayout *pDictLayout, + CORINFO_RUNTIME_LOOKUP *pResult, + SigBuilder * pSigBuilder, + int nFirstOffset, + DictionaryEntrySignatureSource signatureSource); + + static BOOL FindToken(LoaderAllocator * pAllocator, + DWORD numGenericArgs, + DictionaryLayout * pDictLayout, + CORINFO_RUNTIME_LOOKUP * pResult, + BYTE * signature, + int nFirstOffset, + DictionaryEntrySignatureSource signatureSource, + WORD * pSlotOut); + + DWORD GetMaxSlots(); + DWORD GetNumUsedSlots(); + + PTR_DictionaryEntryLayout GetEntryLayout(DWORD i) + { + LIMITED_METHOD_CONTRACT; + _ASSERTE(i >= 0 && i < GetMaxSlots()); + return dac_cast<PTR_DictionaryEntryLayout>( + dac_cast<TADDR>(this) + offsetof(DictionaryLayout, m_slots) + sizeof(DictionaryEntryLayout) * i); + } + + DictionaryLayout* GetNextLayout() { LIMITED_METHOD_CONTRACT; return m_pNext; } + +#ifdef FEATURE_PREJIT + DWORD GetObjectSize(); + + // Trim the canonical dictionary layout to include only those used slots actually used. + // WARNING!!! + // You should only call this if + // (a) you're actually saving this shared instantiation into it's PreferredZapModule, + // i.e. you must be both saving the shared instantiation and the module + // you're ngen'ing MUST be that the PreferredZapModule. + // (b) you're sure you've compiled all the shared code for this type + // within the context of this NGEN session. + // This is currently the same as saying we can hardbind to the EEClass - if it's in another + // module then we will have already trimmed the layout, and if it's being saved into the + // current module then we can only hardbind to it if the current module is the PreferredZapModule. + // + // Note after calling this both GetObjectSize for this layout and the + // computed dictionary size for all dictionaries based on this layout may + // be reduced. This may in turn affect the size of all non-canonical + // method tables, potentially trimming some dictionary words off the end + // of the method table. + void Trim(); + void Save(DataImage *image); + void Fixup(DataImage *image, BOOL fMethod); +#endif // FEATURE_PREJIT + +}; + + +// The type of dictionaries. This is just an abstraction around an open-ended array +class Dictionary +{ +#ifdef DACCESS_COMPILE + friend class NativeImageDumper; +#endif + private: + // First N entries are generic instantiations arguments. They are stored as FixupPointers + // in NGen images. It means that the lowest bit is used to mark optional indirection (see code:FixupPointer). + // The rest of the open array are normal pointers (no optional indirection). + DictionaryEntry m_pEntries[1]; + + TADDR EntryAddr(ULONG32 idx) + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return PTR_HOST_MEMBER_TADDR(Dictionary, this, m_pEntries) + + idx * sizeof(m_pEntries[0]); + } + + public: + inline DPTR(FixupPointer<TypeHandle>) GetInstantiation() + { + LIMITED_METHOD_CONTRACT; + SUPPORTS_DAC; + return dac_cast<DPTR(FixupPointer<TypeHandle>)>(EntryAddr(0)); + } + +#ifndef DACCESS_COMPILE + inline void* AsPtr() + { + LIMITED_METHOD_CONTRACT; + return (void*) m_pEntries; + } +#endif // #ifndef DACCESS_COMPILE + + private: + +#ifndef DACCESS_COMPILE + + inline TypeHandle GetTypeHandleSlot(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return *GetTypeHandleSlotAddr(numGenericArgs, i); + } + inline MethodDesc *GetMethodDescSlot(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return *GetMethodDescSlotAddr(numGenericArgs,i); + } + inline FieldDesc *GetFieldDescSlot(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return *GetFieldDescSlotAddr(numGenericArgs,i); + } + inline TypeHandle *GetTypeHandleSlotAddr(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return ((TypeHandle *) &m_pEntries[numGenericArgs + i]); + } + inline MethodDesc **GetMethodDescSlotAddr(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return ((MethodDesc **) &m_pEntries[numGenericArgs + i]); + } + inline FieldDesc **GetFieldDescSlotAddr(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return ((FieldDesc **) &m_pEntries[numGenericArgs + i]); + } + inline DictionaryEntry *GetSlotAddr(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return ((void **) &m_pEntries[numGenericArgs + i]); + } + inline DictionaryEntry GetSlot(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return *GetSlotAddr(numGenericArgs,i); + } + inline BOOL IsSlotEmpty(DWORD numGenericArgs, DWORD i) + { + LIMITED_METHOD_CONTRACT; + return GetSlot(numGenericArgs,i) == NULL; + } + +#endif // #ifndef DACCESS_COMPILE + + public: + +#ifndef DACCESS_COMPILE + + static DictionaryEntry PopulateEntry(MethodDesc * pMD, + MethodTable * pMT, + LPVOID signature, + BOOL nonExpansive, + DictionaryEntry ** ppSlot, + DWORD dictionaryIndexAndSlot = -1, + Module * pModule = NULL); + + void PrepopulateDictionary(MethodDesc * pMD, + MethodTable * pMT, + BOOL nonExpansive); + +#endif // #ifndef DACCESS_COMPILE + + public: + +#ifdef FEATURE_PREJIT + + // Fixup the dictionary entries, including the type arguments + // + // WARNING!!! + // You should only pass "canSaveSlots=TRUE" if you are certain the dictionary layout + // matches that which will be used at runtime. This means you must either + // be able to hard-bind to the EEClass of the canonical instantiation, or else + // you are saving a copy of the canonical instantiation itself. + // + // If we can't save slots, then we will zero all entries in the dictionary (apart from the + // instantiation itself) and load at runtime. + void Fixup(DataImage *image, + BOOL canSaveInstantiation, + BOOL canSaveSlots, + DWORD numGenericArgs, // Must be non-zero + Module *pModule, // module of the generic code + DictionaryLayout *pDictLayout); // If NULL, then only type arguments are present + + BOOL IsWriteable(DataImage *image, + BOOL canSaveSlots, + DWORD numGenericArgs, // Must be non-zero + Module *pModule, // module of the generic code + DictionaryLayout *pDictLayout); // If NULL, then only type arguments are present + + BOOL ComputeNeedsRestore(DataImage *image, + TypeHandleList *pVisited, + DWORD numGenericArgs); + void Restore(DWORD numGenericArgs, ClassLoadLevel level); +#endif // FEATURE_PREJIT +}; + +#endif |