summaryrefslogtreecommitdiff
path: root/src/vm/genericdict.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/genericdict.h')
-rw-r--r--src/vm/genericdict.h331
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