summaryrefslogtreecommitdiff
path: root/src/vm/constrainedexecutionregion.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/constrainedexecutionregion.h')
-rw-r--r--src/vm/constrainedexecutionregion.h563
1 files changed, 563 insertions, 0 deletions
diff --git a/src/vm/constrainedexecutionregion.h b/src/vm/constrainedexecutionregion.h
new file mode 100644
index 0000000000..93ceb63010
--- /dev/null
+++ b/src/vm/constrainedexecutionregion.h
@@ -0,0 +1,563 @@
+// 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.
+//
+// Methods to support the implementation of Constrained Execution Regions (CERs). This includes logic to walk the IL of methods to
+// determine the statically determinable call graph and prepare each submethod (jit, prepopulate generic dictionaries etc.,
+// everything needed to ensure that the runtime won't generate implicit failure points during the execution of said call graph).
+//
+
+//
+
+
+#ifndef __CONSTRAINED_EXECUTION_REGION_H
+#define __CONSTRAINED_EXECUTION_REGION_H
+
+
+#include <corhlpr.h>
+#include <typestring.h>
+
+
+// An enumeration that abstracts the interesting information (from our point of view) present in a reliability contract decorating a
+// method.
+enum ReliabilityContractLevel
+{
+ RCL_UNKNOWN = -1, // The contract attribute hasn't been read yet
+ RCL_NO_CONTRACT = 0, // No contract (or a fairly useless one) was specified
+ RCL_BASIC_CONTRACT = 1, // The contract promises enough for the method to be a legal member of a CER call graph
+ RCL_PREPARE_CONTRACT = 2, // The contract promises enough to be worth preparing the method as part of a CER call graph
+};
+
+// Various definitions used to parse reliability contracts. These must be kept synchronized with the managed version in
+// BCL\System\Runtime\Reliability\ReliabilityContractAttribute.cs
+
+#define RELIABILITY_CONTRACT_NAME "System.Runtime.ConstrainedExecution.ReliabilityContractAttribute"
+#define RC_CONSISTENCY_PROP_NAME "ConsistencyGuarantee"
+#define RC_CER_PROP_NAME "Cer"
+
+enum {
+ RC_CONSISTENCY_CORRUPT_PROCESS = 0,
+ RC_CONSISTENCY_CORRUPT_APPDOMAIN = 1,
+ RC_CONSISTENCY_CORRUPT_INSTANCE = 2,
+ RC_CONSISTENCY_CORRUPT_NOTHING = 3,
+ RC_CONSISTENCY_UNDEFINED = 4,
+ RC_CER_NONE = 0,
+ RC_CER_MAYFAIL = 1,
+ RC_CER_SUCCESS = 2,
+ RC_CER_UNDEFINED = 3
+};
+
+
+// We compact the reliability contract states above into a single DWORD format easy to cache at the assembly and class level
+// opaquely. We also encode in this DWORD whether a given part of the state has been defined yet (an assembly might set a
+// consistency level without specifying a cer level, for instance, and this information is vital when merging states between
+// assembly, class and method levels).
+// The macros below handle the encoding so nobody else needs to know the details.
+
+// The base state for an encoded DWORD: neither consistency or cer defined.
+#define RC_NULL RC_ENCODE(RC_CONSISTENCY_UNDEFINED, RC_CER_UNDEFINED)
+
+// Extract the raw consistency value from an encoded DWORD.
+#define RC_CONSISTENCY(_encoded) ((_encoded) >> 2)
+
+// Extract the raw cer value from an encoded DWORD.
+#define RC_CER(_encoded) ((_encoded) & 3)
+
+// Produce an encoded DWORD from a pair of raw consistency and cer values. Values must have been range validated first.
+#define RC_ENCODE(_consistency, _cer) (DWORD)(((_consistency) << 2) | (_cer))
+
+// Produce an abstracted ReliabilityContractLevel from an encoded DWORD, see CheckForReliabilityContract for details of the rules.
+#define RC_ENCODED_TO_LEVEL(_encoded) \
+ ((RC_CONSISTENCY(_encoded) == RC_CONSISTENCY_UNDEFINED || \
+ RC_CONSISTENCY(_encoded) < RC_CONSISTENCY_CORRUPT_INSTANCE) ? RCL_NO_CONTRACT : \
+ (RC_CER(_encoded) == RC_CER_UNDEFINED || \
+ RC_CER(_encoded) == RC_CER_NONE) ? RCL_BASIC_CONTRACT : \
+ RCL_PREPARE_CONTRACT)
+
+// Given two DWORD encodings presumed to come from different scopes (e.g. method and class) merge them to find the effective
+// contract state. It's presumed the first encoding is the most tightly scoped (i.e. method would go first in the example above) and
+// therefore takes precedence.
+#define RC_MERGE(_old, _new) RC_ENCODE((RC_CONSISTENCY(_old) == RC_CONSISTENCY_UNDEFINED) ? \
+ RC_CONSISTENCY(_new) : RC_CONSISTENCY(_old), \
+ (RC_CER(_old) == RC_CER_UNDEFINED) ? \
+ RC_CER(_new) : RC_CER(_old)) \
+
+// Return true if either consistency or cer has not been specified in the encoded DWORD given.
+#define RC_INCOMPLETE(_encoded) (RC_CONSISTENCY(_encoded) == RC_CONSISTENCY_UNDEFINED || RC_CER(_encoded) == RC_CER_UNDEFINED)
+
+// Look for reliability contracts at the method, class and assembly level and parse them to extract the information we're interested
+// in from a runtime preparation viewpoint. This information is abstracted in the form of the ReliabilityContractLevel enumeration.
+ReliabilityContractLevel CheckForReliabilityContract(MethodDesc *pMD);
+
+
+// Structure used to track enough information to identify a method (possibly generic or belonging to a generic class). Includes a
+// MethodDesc pointer and a SigTypeContext (values of class and method type parameters to narrow down the exact method being refered
+// to). Similar to MethodContext (see ConstrainedExecutionRegion.cpp), but without the unneeded list link field (we expect to embed
+// these in arrays, hence the name).
+struct MethodContextElement
+{
+ FixupPointer<PTR_MethodDesc> m_pMethodDesc; // Pointer to a MethodDesc
+ FixupPointer<PTR_MethodTable> m_pExactMT; // Exact type to disambiguate code shared by instantiations
+
+ MethodDesc * GetMethodDesc()
+ {
+ return m_pMethodDesc.GetValue();
+ }
+
+ MethodTable * GetExactMT()
+ {
+ return m_pExactMT.GetValue();
+ }
+};
+
+
+// Base structure used to track which CERs have been prepared so far.
+// These structures are looked up via a per-assembly hash table using the root method desc as a key.
+// Used to avoid extra work in both the jit and PrepareMethod calls. The latter case is more involved because we support preparing a
+// CER with generic type parameters (the instantiation is passed in along with the method in the PrepareMethod call). In that case
+// we need to track exactly which instantiations we've prepared for a given method.
+struct CerPrepInfo
+{
+ CerPrepInfo() :
+ m_fFullyPrepared(false),
+ m_fRequiresInstantiation(false),
+ m_fMethodHasCallsWithinExplicitCer(false)
+ {
+ CONTRACTL {
+ THROWS;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+ if (!m_sIsInitAtInstHash.Init(17, NULL, NULL, FALSE))
+ COMPlusThrowOM();
+ }
+
+ bool m_fFullyPrepared; // True implies we've prep'd this once and there are no shared instantiations
+ bool m_fRequiresInstantiation; // True implies that this method is shared amongst multiple instantiations
+ bool m_fMethodHasCallsWithinExplicitCer; // True if method contains calls out from within an explicit PCER range
+ EEInstantiationHashTable m_sIsInitAtInstHash; // Hash of instantiations we've prepared this CER for
+};
+
+
+#ifdef FEATURE_PREJIT
+
+// Structure used to represent a CER by a root method and a list of MethodContextElements that indicate all the methods contained.
+// The MethodContextElement list is terminated with a sentinel entry (m_pMethodDesc set to NULL).
+// Keep this structure small since we'll access the whole array of them randomly at runtime; density is our best friend.
+struct CerRoot
+{
+ MethodDesc *m_pRootMD; // Root method (no type context since it never has type params)
+ MethodContextElement *m_pList; // List of methods in this CER
+};
+
+// Class used to track all the CERs rooted at methods defined within a given module that are discovered at ngen time. This data is
+// then used at runtime to determine when and how to perform necessary restoration work so that the CERs don't encounter any
+// unexpected failure points during execution.
+// During ngen this class keeps a dynamically expanded array of CER roots (both the class and the array are allocated from a win32
+// heap). When we save the image to storage (and thus know the final size of the table) we combine the two so that at runtime
+// they're adjacent and exactly the right size.
+class CerNgenRootTable
+{
+#ifdef DACCESS_COMPILE
+ friend class NativeImageDumper;
+#endif
+
+ DWORD *m_pRestoreBitmap; // Pointer to array of restored flag bits
+ DWORD m_cRoots; // Count of root methods represented
+ DWORD m_cSlots; // Extra empty slots at the tail of the array below (ngen time only)
+ CerRoot *m_pRoots; // Pointer to array of CER roots (sorted by RootMD address)
+ MethodContextElement **m_pRootsInCompilationOrder; // Pointer to array of CerRoot::m_pList (in the order AddRoot is called)
+
+public:
+
+ CerNgenRootTable() :
+ m_pRestoreBitmap(NULL),
+ m_cRoots(0),
+ m_cSlots(0),
+ m_pRoots(NULL),
+ m_pRootsInCompilationOrder(NULL)
+ {
+ }
+
+ ~CerNgenRootTable()
+ {
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ SO_TOLERANT;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+ delete m_pRestoreBitmap;
+ delete m_pRoots;
+ delete m_pRootsInCompilationOrder;
+ }
+
+ // Add a new root to the table, expanding it as necessary. Note that this method must be called with the CerCrst already held.
+ void AddRoot(MethodDesc *pRootMD, MethodContextElement *pList);
+
+ // Retrieve the address of the list of methods for the CER rooted at the given index.
+ inline MethodContextElement *GetList(DWORD dwIndex) { LIMITED_METHOD_CONTRACT; _ASSERTE(dwIndex < m_cRoots); return m_pRoots[dwIndex].m_pList; }
+
+ // Retrieve the address of the list of methods for the CER rooted at the given method. (The root must exist).
+ inline MethodContextElement *GetList(MethodDesc *pRootMD) { WRAPPER_NO_CONTRACT; return GetList(FindIndex(pRootMD)); }
+
+ // Indicate whether the given method has ngen restoration information associated with it.
+ inline bool IsNgenRootMethod(MethodDesc *pRootMD) { WRAPPER_NO_CONTRACT; return FindIndex(pRootMD) != NoSuchRoot; }
+
+ // Prepare the CER rooted at the given method (it's OK to pass a MethodDesc* that doesn't root a CER, in which case the method
+ // is a no-op).
+ void Restore(MethodDesc *pRootMD);
+
+ // Ngen callouts to help serialize this structure and its children to storage.
+ void Save(DataImage *image, CorProfileData *profileData);
+ void Fixup(DataImage *image);
+ void FixupRVAs(DataImage *image);
+
+ // Calculate (in bytes) the size of bitmap to allocate to record whether each CER has been restored at runtime. Size is
+ // rounded up to DWORD alignment.
+ inline DWORD SizeOfRestoreBitmap()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return ((m_cRoots + 31) / 32) * sizeof(DWORD);
+ }
+
+ inline DWORD GetRootCount() { LIMITED_METHOD_CONTRACT; return m_cRoots; }
+ inline CerRoot *GetRoots() { LIMITED_METHOD_CONTRACT; return m_pRoots; }
+ inline DWORD *GetRestoreBitmap() { LIMITED_METHOD_CONTRACT; return m_pRestoreBitmap; }
+
+private:
+ enum { NoSuchRoot = 0xffffffff };
+
+ // Locate the index of a given CerRoot record in the array given the root method. This is used to access the array and to locate
+ // the restored flag for the entry in the restored bitmap. NoSuchRoot is returned if the root cannot be found.
+ DWORD FindIndex(MethodDesc *pRootMD);
+};
+
+#endif
+
+
+// Default initial size for hash table used to track CerPrepInfo structures on a per-module basis.
+#define CER_DEFAULT_HASH_SIZE 17
+
+
+// Structure used to track a single exception handling range (catch, finally etc.). We build an array of these and then track which
+// ones have become 'activated' by virtue of having their try clause immediately preceded by a call to our preparation marker
+// method. This allows us to determine which call sites in the method body should be followed during method preparation.
+struct EHClauseRange
+{
+ DWORD m_dwTryOffset;
+ DWORD m_dwHandlerOffset;
+ DWORD m_dwHandlerLength;
+ bool m_fActive;
+};
+
+
+// Structure used to track enough information to identify a method (possibly generic or belonging to a generic class). Includes a
+// MethodDesc pointer and a SigTypeContext (values of class and method type parameters to narrow down the exact method being refered
+// to). The structure also contains a next pointer so that it can be placed in a singly linked list (see MethodContextStack below).
+struct MethodContext
+{
+ MethodContext *m_pNext; // Next MethodContext in a MethodContextStack list
+ MethodDesc *m_pMethodDesc; // Pointer to a MethodDesc
+ SigTypeContext m_sTypeContext; // Additional type parameter information to qualify the exact method targetted
+ bool m_fRoot; // Does this method contain a CER root of its own?
+
+ // Allocate and initialize a MethodContext from the per-thread stacking allocator (we assume the checkpoint has already been
+ // taken).
+ static MethodContext* PerThreadAllocate(MethodDesc *pMD, SigTypeContext *pTypeContext)
+ {
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ } CONTRACTL_END;
+
+
+ MethodContext *pContext = new (&GetThread()->m_MarshalAlloc) MethodContext();
+ pContext->m_pMethodDesc = pMD;
+ pContext->m_sTypeContext = *pTypeContext;
+ pContext->m_fRoot = false;
+
+ return pContext;
+ }
+
+ // Determine if two MethodContexts are equivalent (same MethodDesc pointer and identical arrays of TypeHandles in the
+ // TypeContext).
+ bool Equals(MethodContext *pOther)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ if (pOther->m_pMethodDesc != m_pMethodDesc)
+ return false;
+
+ if (pOther->m_sTypeContext.m_classInst.GetNumArgs() != m_sTypeContext.m_classInst.GetNumArgs())
+ return false;
+
+ if (pOther->m_sTypeContext.m_methodInst.GetNumArgs() != m_sTypeContext.m_methodInst.GetNumArgs())
+ return false;
+
+ DWORD i;
+
+ for (i = 0; i < m_sTypeContext.m_classInst.GetNumArgs(); i++)
+ if (pOther->m_sTypeContext.m_classInst[i] != m_sTypeContext.m_classInst[i])
+ return false;
+
+ for (i = 0; i < m_sTypeContext.m_methodInst.GetNumArgs(); i++)
+ if (pOther->m_sTypeContext.m_methodInst[i] != m_sTypeContext.m_methodInst[i])
+ return false;
+
+ return true;
+ }
+
+#ifdef _DEBUG
+#define CER_DBG_MAX_OUT 4096
+ char *ToString()
+ {
+ STATIC_CONTRACT_THROWS;
+ STATIC_CONTRACT_GC_TRIGGERS;
+ STATIC_CONTRACT_MODE_ANY;
+
+ // Support up to two ToString calls before we re-use a buffer and overwrite previous output.
+ static char szOut1[CER_DBG_MAX_OUT];
+ static char szOut2[CER_DBG_MAX_OUT];
+ static char *pszOut = szOut1;
+
+ StackSString ssBuffer;
+ StackScratchBuffer ssScratch;
+
+ TypeString::AppendMethod(ssBuffer, m_pMethodDesc, m_sTypeContext.m_classInst, TypeString::FormatNamespace | TypeString::FormatAngleBrackets);
+ sprintf_s(&pszOut[0], CER_DBG_MAX_OUT, "%s", ssBuffer.GetUTF8(ssScratch));
+
+ char *pszReturn = pszOut;
+ pszOut = pszOut == szOut1 ? szOut2 : szOut1;
+ return pszReturn;
+ }
+#endif
+};
+
+// Maintains a stack of MethodContexts (implemented as a singly linked list with insert and remove operations only at the head).
+class MethodContextStack
+{
+ MethodContext *m_pFirst; // The head of the linked list
+ DWORD m_cElements; // Count of elements in the stack
+
+public:
+
+ // Initialize to an empty list.
+ MethodContextStack()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ m_pFirst = NULL;
+ m_cElements = 0;
+ }
+
+ // Push a MethodContext pointer on the head of the list.
+ void Push(MethodContext *pContext)
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ pContext->m_pNext = m_pFirst;
+ m_pFirst = pContext;
+ m_cElements++;
+ }
+
+ // Remove and retrieve the most recently pushed MethodContext. Return NULL if no more entries exist.
+ MethodContext *Pop()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ MethodContext* pContext = m_pFirst;
+ if (pContext == NULL)
+ return NULL;
+
+ m_pFirst = pContext->m_pNext;
+ m_cElements--;
+
+ return pContext;
+ }
+
+ // Return true if an MethodContext equivalent to the argument exists in the stack.
+ bool IsInStack(MethodContext *pMatchContext)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ MethodContext* pContext = m_pFirst;
+ while (pContext) {
+ if (pContext->Equals(pMatchContext))
+ return true;
+ pContext = pContext->m_pNext;
+ }
+
+ return false;
+ }
+
+ // Get count of elements in the stack.
+ DWORD GetCount()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+ return m_cElements;
+ }
+};
+
+
+class MethodCallGraphPreparer
+{
+ MethodDesc *m_pRootMD;
+ SigTypeContext *m_pRootTypeContext;
+
+ COR_ILMETHOD_DECODER *m_pMethodDecoder;
+
+ MethodContextStack m_sLeftToProcess; // MethodContexts we have yet to look at in this call graph
+ MethodContextStack m_sAlreadySeen; // MethodContexts we've already processed at least once
+
+ EHClauseRange *m_pEHClauses; // Array of exception handling clauses in current method (only if !fEntireMethod)
+ DWORD m_cEHClauses; // Number of elements in above array
+ CerPrepInfo *m_pCerPrepInfo; // Context recording how much preparation this region has had
+ MethodContextStack m_sPersist; // MethodContexts we need to keep around past the 'prepare' phase of preparation
+#ifdef FEATURE_NATIVE_IMAGE_GENERATION
+ bool m_fNgen; // True when being called as part of an ngen
+ MethodContextStack m_sRootMethods; // Methods containing a sub-CER (excludes the real root)
+#endif // FEATURE_NATIVE_IMAGE_GENERATION
+ Thread *m_pThread; // Cached managed thread pointer (for allocations and the like)
+ bool m_fPartialPreparation; // True if we have unbound type vars at the CER root and can only prep one instantiation at a time
+
+ bool m_fEntireMethod; // True if are preparing for the entire method
+ bool m_fExactTypeContext;
+ bool m_fMethodHasCallsWithinExplicitCer; // True if method contains calls out from within an explicit PCER range
+
+ bool m_fIgnoreVirtualCERCallMDA; // True if VirtualCER MDA is not desirable to be fired
+
+ MethodCallGraphPreparer * m_pNext; // Links this instance on a per-thread stack used to detect
+ // and defeat recursive preparations
+
+ public:
+ MethodCallGraphPreparer(MethodDesc *pRootMD, SigTypeContext *pRootTypeContext, bool fEntireMethod, bool fExactTypeContext, bool fIgnoreVirtualCERCallMDA = false);
+
+ // Walk the call graph of the method given by m_pRootMD (and type context in m_pRootTypeContext which provides instantiation information
+ // for generic methods/classes).
+ //
+ // If fEntireMethod is true then the entire body of pRootMD is scanned for callsites, otherwise we assume that one or more CER
+ // exception handlers exist in the method and only the finally and catch blocks of such handlers are scanned for graph roots.
+ //
+ // Each method we come across in the call graph (excluding late bound invocation destinations precipitated by virtual or interface
+ // calls) is jitted and has any generic dictionary information we can determine at jit time prepopulated. This includes implicit
+ // cctor invocations. If this method is called at ngen time we will attach extra fixup information to the affected method to ensure
+ // that fixing up the root method of the graph will cause all methods in the graph to be fixed up at that point also.
+ //
+ // Some generic dictionary entries may not be prepopulated if unbound type variables exist at the root of the call tree. Such cases
+ // will be ignored (as for the virtual/interface dispatch case we assume the caller will use an out-of-band mechanism to pre-prepare
+ // these entries explicitly).
+ //
+ // Returns true if the m_pRootMD contains a CER that calls outside the method.
+ //
+ bool Run();
+
+ // Methods used to control re-entrancy on the same thread. Essentially we'd like to avoid all re-entrancy
+ // (since it can lead to unbounded recursion easily) but unfortunately jitting methods during the
+ // preparation phase can cause this both directly (if we spot a sub-root) or indirectly (where implicit
+ // jit execution of a cctor causes a possibly unrelated CER graph to be prepared). The algorithm we use to
+ // avoid this records a stack of preparations attempts on the current thread (implemented via a singly
+ // linked list of the MethodCallGraphPreparer instances). Re-entrant prepare requests become noops if
+ // they're for a root method we're already processing (anywhere in the stack) and run to completion
+ // otherwise. This prevents infinite recursion since it removes at least one method from the intersection
+ // of the CER call graphs on each iteration. Theoretically it might not be the most efficient solution
+ // since there might still be a lot of overlap between graphs, but in practice the number of sub-CER roots
+ // is likely to be small and we won't recurse very far. This will still allow a re-entrant preparation
+ // that is the result of running a cctor to potentially early-out (and thus allow code to run before its
+ // CERs have been fully prepped). But this should only happen when a CER causes (directly or indirectly) a
+ // cctor to run that depends on that CER having been prepared already, which we really can't do much
+ // about.
+ //
+ BOOL CanPreparationProceed(MethodDesc * pMD, SigTypeContext * pTypeContext);
+
+ static void BeginPrepareCerForHolder(MethodCallGraphPreparer *pPrepState);
+ static void EndPrepareCerForHolder(MethodCallGraphPreparer *pPrepState);
+
+ typedef Holder<MethodCallGraphPreparer*, BeginPrepareCerForHolder, EndPrepareCerForHolder> ThreadPreparingCerHolder;
+
+ private:
+ void GetEHClauses();
+ void MarkEHClauseActivatedByCERCall(MethodContext *pContext, BYTE *pbIL, DWORD cbIL);
+ bool CheckIfCallsiteWithinCER(DWORD dwOffset);
+ bool ShouldGatherExplicitCERCallInfo();
+ void LookForInterestingCallsites(MethodContext *pContext);
+ void PrepareMethods();
+ bool RecordResults();
+};
+
+// Determines whether the given method contains a CER root that can be pre-prepared (i.e. prepared at jit time).
+bool ContainsPrePreparableCerRoot(MethodDesc *pMD);
+
+// Prepares the critical finalizer call graph for the given object type (which must derive from CriticalFinalizerObject). This
+// involves preparing at least the finalizer method and possibly some others (for SafeHandle and CriticalHandle derivations). If a
+// module pointer is supplied then only the critical methods introduced in that module are prepared (this is used at ngen time to
+// ensure that we're only generating ngen preparation info for the targetted module).
+void PrepareCriticalFinalizerObject(MethodTable *pMT, Module *pModule = NULL);
+
+void PrepareMethodDesc(MethodDesc* pMD, Instantiation classInst = Instantiation(), Instantiation methodInst = Instantiation(), BOOL onlyContractedMethod = FALSE, BOOL fIgnoreVirtualCERCallMDA = FALSE);
+// Determine whether the method given as a parameter is the root of a CER.
+// @todo: Need an x86 offset as well and logic to determine whether we're actually in a root-CER portion of the method (if the whole
+// thing isn't the root).
+bool IsCerRootMethod(MethodDesc *pMD);
+
+// Fill the cache of overflowed generic dictionary entries that the jit maintains with all the overflow slots stored so far in the
+// dictionary layout.
+void PrepopulateGenericHandleCache(DictionaryLayout *pDictionaryLayout,
+ MethodDesc *pMD,
+ MethodTable *pMT);
+
+DWORD GetReliabilityContract(IMDInternalImport *pImport, mdToken tkParent);
+
+#ifdef FEATURE_PREJIT
+
+// Prepare the class if it is derived from CriticalFinalizerObject. This is used at ngen time since such classes are normally
+// prepared at runtime (at instantiation) and would therefore miss the ngen image.
+void PrepareCriticalType(MethodTable *pMT);
+
+// Prepare a method and its statically determinable call graph if a hint attribute has been applied. This is only called at ngen
+// time to save additional preparation information into the ngen image that wouldn't normally be there (and thus lower runtime
+// overheads).
+void PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod);
+
+#endif
+
+
+// A fixed sized hash table keyed by pointers and storing two bits worth of value for every entry. The value is stored in the low
+// order bits of the keys, so the pointers must be at least DWORD aligned. No hash table expansion occurs so new entries will sooner
+// or later overwrite old. The implementation uses no locks (all accesses are single aligned pointer sized operations and therefore
+// inherently atomic).
+// The purpose of this table is to store a smallish number of reliability contract levels for the most recently queried methods,
+// mainly for the purpose of speeding up thread abort processing (where we will walk the stack probing methods for contracts,
+// sometimes repeatedly). So we use a small fixed sized hash to speed up lookups on average but avoid impacting working set.
+#define PHC_BUCKETS 29
+#define PHC_CHAIN 5
+#define PHC_DATA_MASK 3
+
+class PtrHashCache
+{
+public:
+ PtrHashCache();
+ bool Lookup(void *pKey, DWORD *pdwValue);
+ void Add(void *pKey, DWORD dwValue);
+
+#ifdef _DEBUG
+ void DbgDumpStats();
+#endif
+
+private:
+ DWORD GetHash(void *pKey);
+
+ UINT_PTR m_rEntries[PHC_BUCKETS * PHC_CHAIN];
+
+#ifdef _DEBUG
+ DWORD m_dwHits;
+ DWORD m_dwMisses;
+#endif
+};
+
+#endif