Remove constrainedexecutionregion.cpp
authordanmosemsft <danmose@microsoft.com>
Mon, 13 Feb 2017 04:42:42 +0000 (20:42 -0800)
committerdanmosemsft <danmose@microsoft.com>
Mon, 13 Feb 2017 05:56:43 +0000 (21:56 -0800)
Commit migrated from https://github.com/dotnet/coreclr/commit/6f05c7c8d283345b811cfe7abe1c2ad416301a12

src/coreclr/src/inc/clrconfigvalues.h
src/coreclr/src/mscorlib/src/System/Runtime/Reliability/ReliabilityContractAttribute.cs
src/coreclr/src/vm/constrainedexecutionregion.cpp [deleted file]

index 347cdd0..6a30af1 100644 (file)
@@ -1058,7 +1058,6 @@ CONFIG_DWORD_INFO_DIRECT_ACCESS(INTERNAL_AlwaysUseMetadataInterfaceMapLayout, W(
 CONFIG_DWORD_INFO(INTERNAL_AssertOnUnneededThis, W("AssertOnUnneededThis"), 0, "While the ConfigDWORD is unnecessary, the contained ASSERT should be kept. This may result in some work tracking down violating MethodDescCallSites.")
 CONFIG_DWORD_INFO_EX(INTERNAL_AssertStacktrace, W("AssertStacktrace"), 1, "", CLRConfig::REGUTIL_default)
 RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(UNSUPPORTED_BuildFlavor, W("BuildFlavor"), "Choice of build flavor (wks or svr) of CLR")
-CONFIG_DWORD_INFO(INTERNAL_CerLogging, W("CerLogging"), 0, "In vm\\ConstrainedExecutionRegion.cpp.  Debug-only logging when we prepare methods, find reliability contract problems, restore stuff from ngen images, etc.")
 CONFIG_DWORD_INFO_EX(INTERNAL_clearNativeImageStress, W("clearNativeImageStress"), 0, "", CLRConfig::REGUTIL_default)
 RETAIL_CONFIG_STRING_INFO_DIRECT_ACCESS(INTERNAL_CLRLoadLogDir, W("CLRLoadLogDir"), "Enable logging of CLR selection")
 RETAIL_CONFIG_STRING_INFO_EX(EXTERNAL_CONFIG, W("CONFIG"), "Used to specify an XML config file for EEConfig", CLRConfig::REGUTIL_default)
index 4a14e57..a889f15 100644 (file)
@@ -20,13 +20,6 @@ namespace System.Runtime.ConstrainedExecution {
     using System.Runtime.InteropServices;
     using System;
 
-    // **************************************************************************************************************************
-    //
-    // Note that if you change either of the enums below or the constructors, fields or properties of the custom attribute itself
-    // you must also change the logic and definitions in vm\ConstrainedExecutionRegion.cpp to match.
-    //
-    // **************************************************************************************************************************
-
     [Serializable]
     public enum Consistency : int
     {
diff --git a/src/coreclr/src/vm/constrainedexecutionregion.cpp b/src/coreclr/src/vm/constrainedexecutionregion.cpp
deleted file mode 100644 (file)
index 0745bd5..0000000
+++ /dev/null
@@ -1,2264 +0,0 @@
-// 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).
-//
-
-//
-
-
-#include "common.h"
-#include <openum.h>
-#include <mdaassistants.h>
-#include <ecmakey.h>
-#include <typestring.h>
-#include <jitinterface.h>
-
-#ifdef FEATURE_PREJIT
-#include <compile.h>
-#endif
-
-
-// Internal debugging support. Would be nice to use the common logging code but we've run out of unique facility codes and the debug
-// info we spew out is of interest to a limited audience anyhow.
-#ifdef _DEBUG
-
-#define CER_NOISY_PREPARE       0x00000001
-#define CER_NOISY_RESTORE       0x00000002
-#define CER_NOISY_CONTRACTS     0x00000004
-#define CER_NOISY_WARNINGS      0x00000008
-#define CER_NOISY_NGEN_STATS    0x00000010
-
-DWORD g_dwCerLogActions = 0xffffffff;
-DWORD GetCerLoggingOptions()
-{
-    WRAPPER_NO_CONTRACT;
-    if (g_dwCerLogActions != 0xffffffff)
-        return g_dwCerLogActions;
-    return g_dwCerLogActions = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_CerLogging);
-}
-
-#define CER_LOG(_reason, _msg) do { if (GetCerLoggingOptions() & CER_NOISY_##_reason) printf _msg; } while (false)
-#else
-#define CER_LOG(_reason, _msg)
-#endif
-
-
-// Enumeration used to determine the number of inline data bytes included inside a given IL instruction (except for the case of a
-// SWITCH instruction, where a dynamic calculation is required).
-enum
-{
-        ArgBytes_InlineNone             = 0,    // no inline args       
-        ArgBytes_InlineVar              = 2,    // local variable       (U2 (U1 if Short on))
-        ArgBytes_InlineI                = 4,    // an signed integer    (I4 (I1 if Short on))
-        ArgBytes_InlineR                = 8,    // a real number        (R8 (R4 if Short on))
-        ArgBytes_InlineBrTarget         = 4,    // branch target        (I4 (I1 if Short on))
-        ArgBytes_InlineI8               = 8,
-        ArgBytes_InlineMethod           = 4,    // method token (U4)
-        ArgBytes_InlineField            = 4,    // field token  (U4)
-        ArgBytes_InlineType             = 4,    // type token   (U4)
-        ArgBytes_InlineString           = 4,    // string TOKEN (U4)
-        ArgBytes_InlineSig              = 4,    // signature tok (U4)
-        ArgBytes_InlineRVA              = 4,    // ldptr token  (U4)
-        ArgBytes_InlineTok              = 4,    // a meta-data token of unknown type (U4)
-        ArgBytes_InlineSwitch           = 4,    // count (U4), pcrel1 (U4) .... pcrelN (U4)
-        ArgBytes_ShortInlineVar         = 1,
-        ArgBytes_ShortInlineI           = 1,
-        ArgBytes_ShortInlineR           = 4,
-        ArgBytes_ShortInlineBrTarget    = 1
-};
-
-// Build an array of argument byte counts as described above by extracting the 'args' field of each entry in opcode.def.
-#define OPDEF(c, s, pop, push, args, type, l, s1, s2, ctrl) ArgBytes_##args,
-const BYTE g_rOpArgs[] = {
-#include <opcode.def>
-};
-#undef OPDEF
-
-
-// Global cache of methods and their reliability contract state.
-PtrHashCache *g_pMethodContractCache = NULL;
-
-
-// Private method forward references.
-bool IsPcrReference(Module *pModule, mdToken tkMethod);
-MethodContext *TokenToMethodDesc(Module *pModule, mdToken tokMethod, SigTypeContext *pTypeContext);
-TypeHandle GetTypeFromMemberDefOrRefOrSpecThrowing(Module         *pModule,
-                                                   mdToken         tokMethod,
-                                                   SigTypeContext *pTypeContext);
-
-bool MethodCallGraphPreparer::ShouldGatherExplicitCERCallInfo()
-{
-    LIMITED_METHOD_CONTRACT;
-
-    // If we're partially processing a method body (at the top of the call graph), we need to fetch exception handling
-    // information to determine possible ranges of interesting IL (potentially each finally and catch clause).
-    // 
-    // And if we are probing for stack overflow, we need to know if the explicit CER region contains any calls out, in 
-    // which case we want to probe in the call to PrepareConstrainedExecutionRegions.  This will ensure that we don't
-    // take an SO in boundary code and not be able to call the CER.  When stack probing is disabled, we rip the process
-    // if we take an SO anywhere but managed, or if we take an SO with a CER on the stack.  For NGEN images, we need 
-    // to always probe because stack probing may be enabled in the runtime, but if we haven't probed in the NGEN image
-    // then we could take an SO in boundary code and not be able to crawl the stack to know that we've skipped a CER and
-    // need to tear the process.
-    //
-    // Additionally, if the MDA for illegal PrepareConstrainedRegions call positioning is enabled we gather this information for
-    // all methods in the graph.
-    return !m_fEntireMethod 
-#ifdef MDA_SUPPORTED
-        || MDA_GET_ASSISTANT(IllegalPrepareConstrainedRegion)
-#endif
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-        || m_fNgen
-#endif
-        || g_pConfig->ProbeForStackOverflow();
-}
-
-MethodCallGraphPreparer::MethodCallGraphPreparer(MethodDesc *pRootMD, SigTypeContext *pRootTypeContext, bool fEntireMethod, bool fExactTypeContext, bool fIgnoreVirtualCERCallMDA)
-{
-    CONTRACTL {
-        STANDARD_VM_CHECK;
-        PRECONDITION(CheckPointer(pRootMD));
-        PRECONDITION(CheckPointer(pRootTypeContext));
-    } CONTRACTL_END;
-
-    // Canonicalize value type unboxing stubs into their underlying method desc.
-    if (pRootMD->IsUnboxingStub())
-        pRootMD = pRootMD->GetWrappedMethodDesc();
-
-    m_pRootMD = pRootMD;
-    m_pRootTypeContext = pRootTypeContext;
-    m_fEntireMethod = fEntireMethod;
-    m_fExactTypeContext = fExactTypeContext;
-    m_fIgnoreVirtualCERCallMDA = fIgnoreVirtualCERCallMDA;
-    
-    m_pEHClauses = NULL;
-    m_cEHClauses = 0;
-    m_pCerPrepInfo = NULL;  
-    m_pMethodDecoder = NULL;
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-    m_fNgen = false; 
-#endif
-
-    m_pThread = GetThread(); 
-    m_fPartialPreparation = false;
-    m_fMethodHasCallsWithinExplicitCer = false;
-}
-
-// Walk the call graph of the method given by pRootMD (and type context in 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).
-bool MethodCallGraphPreparer::Run()
-{
-    STANDARD_VM_CONTRACT;
-
-    // Avoid recursion while jitting methods for another preparation.
-    if (!m_pThread->GetCerPreparationState()->CanPreparationProceed(m_pRootMD, m_pRootTypeContext))
-        return TRUE;   // Assume the worst
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-    // Determine if we're being called in order to provide an ngen image. This impacts whether we actually prepare methods and the
-    // type of tracking data we produce. Ideally we'd call GetAppDomain()->IsCompilationDomain() here, but we have to deal with the
-    // problem of ngen'ing mscorlib. Mscorlib code is always shared and some of it is run before the compilation domain is fully
-    // created (so we'd end up with some methods being prepared without saving any ngen metadata to that effect). So instead we
-    // check to see whether this is an ngen process. This will catch those first few mscorlib methods.
-    m_fNgen = IsCompilationProcess() != FALSE;
-
-    // We keep a hash table of CERs we've processed on the module object of the root method. See if any work has been done on this
-    // CER before. We store different data for ngen and non-ngen cases.
-    if (m_fNgen) {
-
-        // Pretty simple in ngen case -- if we've stored a context record for this method at all then we've already processed it.
-        if (m_pRootMD->GetModule()->IsNgenCerRootMethod(m_pRootMD)) {
-            m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD);
-
-            // We always store CerPrepInfo if the method has calls, so if we haven't stored
-            // anything then we know it doesn't have any calls
-            return (m_pCerPrepInfo && m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer);
-        }
-    } else 
-#endif
-    {
-        // The non-ngen case (normal jit, call to PrepareMethod etc).
-        m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD);
-        if (m_pCerPrepInfo) {
-
-            // Check for the "everything's done" case.
-            if (m_pCerPrepInfo->m_fFullyPrepared)
-                return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer;
-
-            // Check for the "we can't do anything" case (see below for descriptions of that).
-            if (m_pCerPrepInfo->m_fRequiresInstantiation && !m_fExactTypeContext)
-                return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer;
-
-            // Check for the "need to prepare per-instantiation, but we've already done this one" case.
-            if (m_pCerPrepInfo->m_fRequiresInstantiation) {
-                HashDatum sDatum;
-                if (m_pCerPrepInfo->m_sIsInitAtInstHash.GetValue(m_pRootTypeContext, &sDatum))
-                    return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer;
-            }
-        }
-    }
-
-    // We can't deal with generic methods or methods on generic types that may have some representative type parameters in their
-    // instantiation (i.e. some reference types indicated by Object rather than the exact type). The jit will tend to pass us these
-    // since it shares code between instantiations over reference types. We can't prepare methods like these completely -- even
-    // though we can jit all the method bodies the code might require generic dictionary information at the class or method level
-    // that is populated at runtime and can introduce failure points. So we reject such methods immediately (they will need to be
-    // prepared at non-jit time by an explicit call to PrepareMethod with a fully instantiated method).
-    //
-    // In the case where the type context is marked as suspect (m_fExactTypeContext == false) there are a number of possibilites for
-    // bad methods the jit will pass us:
-    //  1) We're passed a MethodDesc that shared between instantiations (bogus because exact method descs are never shared).
-    //  2) We're passed a MethodDesc that's an instantiating stub (bogus because non-shared methods don't need this).
-    //  3) We're passed a MethodDesc that has generic variables in its instantiations (I've seen this during ngen).
-    //
-    // Technically we could do a little better than this -- we could determine whether any of the representative type parameters are
-    // actually used within the CER call graph itself. But this would require us to understand the IL at a much deeper level (i.e.
-    // parse every instruction that could take a type or member spec and pull apart those specs to see if a type var is used). Plus
-    // we couldn't make this determination until we've prepared the entire region and the result is rather brittle from the code
-    // author's point of view (i.e. we might prepare a CER automatically one day but stop doing after some relatively subtle changes
-    // in the source code).
-    m_fPartialPreparation = m_pRootMD->IsSharedByGenericInstantiations() || m_pRootMD->IsInstantiatingStub() || m_pRootMD->ContainsGenericVariables();
-    if (!m_fExactTypeContext && m_fPartialPreparation) {
-#ifdef MDA_SUPPORTED
-        MDA_TRIGGER_ASSISTANT(OpenGenericCERCall, ReportViolation(m_pRootMD));
-#endif
-        CER_LOG(WARNINGS, ("CER: %s has open type parameters and can't be pre-prepared\n", m_pRootMD->m_pszDebugMethodName));
-
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-        if (!m_fNgen) 
-#endif
-        {
-            // Set up a prep info structure for this method if it's not there already (the create method takes care of races).
-            if (m_pCerPrepInfo == NULL)
-                m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD);
-
-            // We may be racing to update the structure at this point but that's OK since the flag we're setting is never cleared once
-            // it's set and is always guaranteed to be set before we rely on its value (setting it here is just a performance thing,
-            // letting us early-out on multiple attempts to prepare this CER from the jit).
-            m_pCerPrepInfo->m_fRequiresInstantiation = true;
-        }
-
-        if (! g_pConfig->ProbeForStackOverflow())
-        {
-            return FALSE;
-        }
-        m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD);
-
-        // We always store CerPrepInfo if the method has calls, so if we haven't stored
-        // anything then we know it doesn't have any calls
-        return (m_pCerPrepInfo && m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer);
-        
-    }
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-    // If we've been called for a shared generic root method and the exact instantiation (this can happen because ngen lets code
-    // execute under some circumstances) we don't currently support saving this information in the ngen image (we don't have a
-    // format for the instantiation info). We just ignore the preparation in this case (it will be prepared at runtime).
-    if (m_fNgen && m_fPartialPreparation)
-        return TRUE;
-#endif
-
-    // Prevent inlining of the root method (otherwise it's hard to tell where ThreadAbort exceptions should be delayed). Note that
-    // MethodDesc::SetNotInline is thread safe.
-    m_pRootMD->SetNotInline(true);
-
-    // Remember the checkpoint for all of our allocations. Keep it in a holder so they'll be unwound if we throw an exception past
-    // here.
-    CheckPointHolder sCheckpoint(m_pThread->m_MarshalAlloc.GetCheckpoint());
-
-    // Push the current method as the one and only method to process so far.
-    m_sLeftToProcess.Push(MethodContext::PerThreadAllocate(m_pRootMD, m_pRootTypeContext));
-
-    MethodContext      *pContext = NULL;               // The current MethodContext we're processing
-    
-    // Iterate until we run out of methods to process.
-    while ((pContext = m_sLeftToProcess.Pop()) != NULL) {
-
-        // Restore the MD if necessary. In particular, if this is an instantiating stub and the wrapped MethodDesc could
-        // not be hard bound, then we'll need to restore that pointer before getting it.
-        pContext->m_pMethodDesc->CheckRestore();
-
-        // Transfer the method to the already seen stack immediately (we don't want to loop infinitely in the case of method
-        // recursion).
-        m_sAlreadySeen.Push(pContext);
-
-        // Check if the enclosing class requires a static class constructor to be run. If so, we need to prepare that method as
-        // though it were any other call.
-        if (pContext->m_pMethodDesc->GetMethodTable()->HasClassConstructor()) {
-
-            // Decode target method into MethodDesc and new SigTypeContext.
-            // The type context is easy to derive here : .cctors never have any method type parameters and the class instantiations
-            // are those of the method we're currently parsing, so can be simply copied down.
-            MethodDesc *pCctor = pContext->m_pMethodDesc->GetCanonicalMethodTable()->GetClassConstructor();
-            SigTypeContext sCctorTypeContext(pCctor, pContext->m_sTypeContext.m_classInst, Instantiation());
-            MethodContext *pCctorContext = MethodContext::PerThreadAllocate(pCctor, &sCctorTypeContext);
-
-            // Only process this cctor the first time we find it in this call graph.
-            if (!m_sAlreadySeen.IsInStack(pCctorContext) && !m_sLeftToProcess.IsInStack(pCctorContext))
-                m_sLeftToProcess.Push(pCctorContext);
-        }
-
-        // Skip further processing if this method doesn't have an IL body (note that we assume the method we entered with was IL, so
-        // we don't need to bother with partial method processing).
-        if (!pContext->m_pMethodDesc->IsIL()) {
-            _ASSERTE(m_fEntireMethod);
-            continue;
-        }
-
-        // Locate the IL body of the current method. May have to account for the fact that the current method desc is an
-        // instantiating stub and burrow down for the real method desc.
-        MethodDesc *pRealMethod = pContext->m_pMethodDesc;
-        if (pRealMethod->IsInstantiatingStub()) {
-            _ASSERTE(!pRealMethod->ContainsGenericVariables());
-            pRealMethod = pRealMethod->GetWrappedMethodDesc();
-        }
-
-        COR_ILMETHOD* pILHeader = pRealMethod->GetILHeader();
-
-        // Skip malformed methods. (We should always have method with IL for well-formed images here.)
-        if (pILHeader == NULL) {
-            continue;
-        }
-
-        COR_ILMETHOD_DECODER method(pILHeader);
-        m_pMethodDecoder = &method;
-
-        // We want to reget the EH clauses for the current method so that we can scan its handlers
-        GetEHClauses();
-
-        LookForInterestingCallsites(pContext);
-
-        // Whatever we've done, we're definitely not processing the top-level method at this point (so we'll be processing full
-        // method bodies from now on).
-        m_fEntireMethod = true;
-    }
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-    if (!m_fNgen) 
-#endif
-    {
-        // Set up a prep info structure for this method if it's not there already (the create method takes care of races).
-        // This needs to happen before we start JITing the methods as part of preparation. The JIT needs to know
-        // about the CER root in CEEInfo::canTailCall.
-        if (m_pCerPrepInfo == NULL)
-            m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD);
-    }
-
-    // Prevent infinite recursion by recording on the thread which roots we're currently preparing.
-    ThreadPreparingCerHolder sCerHolder(this);
-
-    // Once we get here we've run out of methods to process and have recorded each method we visited in the m_sAlreadySeen stack. Now
-    // it's time to prepare each of these methods (jit, prepopulate generic dictionaries etc.).
-    PrepareMethods();
-
-    return RecordResults();
-}
-
-
-// Determine whether a CER preparation for the given root method (with type context for generic instantiation
-// if necessary) can go ahead given any current preparation already being performed on the current thread.
-BOOL MethodCallGraphPreparer::CanPreparationProceed(MethodDesc * pMD, SigTypeContext * pTypeContext)
-{
-    WRAPPER_NO_CONTRACT;
-    MethodCallGraphPreparer * pCurrPrep = this;
-    while (pCurrPrep)
-    {
-        // Is the prepartion request for the root method of the current preparer?
-        if (pMD == pCurrPrep->m_pRootMD && SigTypeContext::Equal(pTypeContext, pCurrPrep->m_pRootTypeContext))
-        {
-            // We're already preparing this root, return FALSE to turn the request into a no-op and avoid
-            // infinite recursion.
-            return FALSE;
-        }
-
-        pCurrPrep = pCurrPrep->m_pNext;
-    }
-
-    // We found no previous preparation for the same root, so the request can proceed.
-    return TRUE;
-}
-
-// Methods that push and pop thread local state used to determine if a re-entrant preparation request should
-// complete immediately as a no-op (because it would lead to an infinite recursion) or should proceed
-// recursively.
-
-//static
-void MethodCallGraphPreparer::BeginPrepareCerForHolder(MethodCallGraphPreparer * pPrepState)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    Thread * pThread = pPrepState->m_pThread;
-    pPrepState->m_pNext = pThread->GetCerPreparationState();
-    pThread->SetCerPreparationState(pPrepState);
-}
-
-//static
-void MethodCallGraphPreparer::EndPrepareCerForHolder(MethodCallGraphPreparer * pPrepState)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    Thread * pThread = pPrepState->m_pThread;
-    _ASSERTE(pThread && pThread->GetCerPreparationState() == pPrepState);
-    pThread->SetCerPreparationState(pPrepState->m_pNext);
-}
-
-
-void MethodCallGraphPreparer::GetEHClauses()
-{
-    STANDARD_VM_CONTRACT;
-
-    if (! ShouldGatherExplicitCERCallInfo())
-    {
-        return;
-    }
-
-    m_cEHClauses = 0;
-    m_pEHClauses = NULL;    // we use the StackingAllocator, so don't have to delete the previous storage
-    
-    COR_ILMETHOD_SECT_EH const * pEH = m_pMethodDecoder->EH;
-    if (pEH == NULL ||pEH->EHCount() == 0) 
-    {
-        return;
-    }
-
-    m_cEHClauses = pEH->EHCount();
-    m_pEHClauses = new (&m_pThread->m_MarshalAlloc) EHClauseRange[m_cEHClauses];
-
-    for (DWORD i = 0; i < m_cEHClauses; i++) 
-    {
-        COR_ILMETHOD_SECT_EH_CLAUSE_FAT         sEHClauseBuffer;
-        const COR_ILMETHOD_SECT_EH_CLAUSE_FAT   *pEHClause;
-
-        pEHClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pEH->EHClause(i, &sEHClauseBuffer);
-
-        // The algorithm below assumes handlers are located after their associated try blocks. If this turns out to be a
-        // false assumption we need to move to a two pass technique (or defer callsite handling in some other fashion until
-        // we've scanned the IL for all calls to our preparation marker method).
-        if (!(pEHClause->GetTryOffset() < pEHClause->GetHandlerOffset()))
-        {
-            COMPlusThrowHR(COR_E_NOTSUPPORTED, IDS_EE_NOTSUPPORTED_CATCHBEFORETRY);
-        }
-
-        m_pEHClauses[i].m_dwTryOffset = pEHClause->GetTryOffset();
-        m_pEHClauses[i].m_dwHandlerOffset = pEHClause->GetHandlerOffset();
-        m_pEHClauses[i].m_dwHandlerLength = pEHClause->GetHandlerLength();
-        m_pEHClauses[i].m_fActive = false;
-
-        //printf("Try: %u Handler: %u -> %u\n", pEHClause->GetTryOffset(), pEHClause->GetHandlerOffset(), pEHClause->GetHandlerOffset() + pEHClause->GetHandlerLength() - 1);
-    }
-}
-
-void MethodCallGraphPreparer::MarkEHClauseActivatedByCERCall(MethodContext *pContext, BYTE *pbIL, DWORD cbIL)
-{
-    STANDARD_VM_CONTRACT;
-
-    DWORD   dwOffset = (DWORD)(SIZE_T)((pbIL + ArgBytes_InlineTok) - (BYTE*)m_pMethodDecoder->Code);
-
-    // Additionally we need to cope with the fact that VB and C# (for debug builds) can generate NOP instructions
-    // between the PCR call and the beginning of the try block. So we're potentially looking for the
-    // intersection of the try with a range of instructions. Count the number of consecutive NOP instructions
-    // which follow the call.
-    DWORD   dwLength = 0;
-    BYTE   *pbTmpIL = pbIL + ArgBytes_InlineTok;
-    while (pbTmpIL < (pbIL + cbIL) && *pbTmpIL++ == CEE_NOP)
-    {
-        dwLength++;
-    }
-
-    bool    fMatched = false;
-    for (DWORD i = 0; i < m_cEHClauses; i++)
-    {
-        if (m_pEHClauses[i].m_dwTryOffset >= dwOffset &&
-            m_pEHClauses[i].m_dwTryOffset <= (dwOffset + dwLength)) 
-        {
-            fMatched = true;
-            m_pEHClauses[i].m_fActive = true;
-        }
-    }
-    if (!fMatched) 
-    {
-#if defined(_DEBUG) || defined(MDA_SUPPORTED)
-        DWORD dwPCROffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code);
-#endif // defined(_DEBUG) || defined(MDA_SUPPORTED)
-#ifdef MDA_SUPPORTED
-        MDA_TRIGGER_ASSISTANT(IllegalPrepareConstrainedRegion, ReportViolation(pContext->m_pMethodDesc, dwPCROffset));
-#endif
-        CER_LOG(WARNINGS, ("CER: %s: Invalid call to PrepareConstrainedRegions() at IL +%04X\n",
-                           pContext->m_pMethodDesc->m_pszDebugMethodName, dwPCROffset));
-    }
-}
-
-bool MethodCallGraphPreparer::CheckIfCallsiteWithinCER(DWORD dwOffset)
-{
-    STANDARD_VM_CONTRACT;
-
-    //printf("Found: %s at %u\n", pCallTarget->m_pMethodDesc->m_pszDebugMethodName, dwOffset);
-
-    // Search all the EH regions we know about.
-    for (DWORD i = 0; i < m_cEHClauses; i++) 
-    {
-        bool fCallsiteWithinCER = false;
-        if (! m_pEHClauses[i].m_fActive) 
-        {
-            // clause not CER-active so skip it
-            continue;
-        }
-        if (dwOffset >= (m_pEHClauses[i].m_dwHandlerOffset + m_pEHClauses[i].m_dwHandlerLength)) 
-        {
-            // offset beyond clause, so skip it
-            continue;
-        }
-        if (dwOffset >= m_pEHClauses[i].m_dwTryOffset)
-        {   
-            // For stack probing optimization, we care if either the try or the handler has a call.  If neither
-            // does, then we can optimize the probe out.
-            m_fMethodHasCallsWithinExplicitCer = true;
-            if (dwOffset >= m_pEHClauses[i].m_dwHandlerOffset)
-            {
-                fCallsiteWithinCER = true;
-            }
-        }
-        // Only terminate if we got a positive result (i.e. the calliste is within a hardened clause).
-        // We can't terminate early in the negative case because the callsite could be nested
-        // in another EH region which may be hardened.
-        if (fCallsiteWithinCER == true)
-        {
-            return true;
-        }
-    }
-    
-    return false;
-}
-
-
-// Iterate through the body of the method looking for interesting call sites.
-void MethodCallGraphPreparer::LookForInterestingCallsites(MethodContext *pContext)
-{
-    STANDARD_VM_CONTRACT;
-
-    BYTE *pbIL = (BYTE*)m_pMethodDecoder->Code;
-    DWORD cbIL = m_pMethodDecoder->GetCodeSize();
-
-    while (cbIL) {
-
-        // Read the IL op.
-        DWORD dwOp = *pbIL++; cbIL--;
-
-        // Handle prefix codes (only CEE_PREFIX1 is legal so far).
-        if (dwOp == CEE_PREFIX1) {
-            if (!cbIL)
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            dwOp = 256 + *pbIL++; cbIL--;
-        } else if (dwOp >= CEE_PREFIX7)
-            COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
-        // We're interested in NEWOBJ, JMP, CALL and CALLVIRT (can't trace through CALLI). We include CALLVIRT becase C#
-        // routinely calls non-virtual instance methods this way in order to get this pointer null checking. We prepare NEWOBJ
-        // because that covers the corner case of value types which can be constructed with no failure path.
-        if (dwOp == CEE_CALL || dwOp == CEE_CALLVIRT || dwOp == CEE_NEWOBJ || dwOp == CEE_JMP) {
-
-            if (cbIL < sizeof(DWORD))
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
-            // Decode target method into MethodDesc and new SigTypeContext.
-            mdToken tkCallTarget = (mdToken)GET_UNALIGNED_VAL32(pbIL);
-            MethodContext *pCallTarget = TokenToMethodDesc(pContext->m_pMethodDesc->GetModule(), tkCallTarget, &pContext->m_sTypeContext);
-
-            // Check whether we've found a call to our own preparation marker method.
-            if (pCallTarget->m_pMethodDesc == g_pPrepareConstrainedRegionsMethod) {
-
-                if (ShouldGatherExplicitCERCallInfo()) {
-                    // If we're preparing a partial method these callsites are significant (we mark which EH clauses are now
-                    // 'activated' by proximity to this marker method call). Look for EH regions that are 'activated' by the call to
-                    // PrepareConstrainedRegions by comparing the IL offset of the start of the try to the offset immediately after
-                    // the callsite (remember to account for the rest of the CALLVIRT instruction we haven't skipped yet).
-                    MarkEHClauseActivatedByCERCall(pContext, pbIL, cbIL);
-                }
-
-                // Record the fact that we found a method in the CER which is the root of a sub-CER. This is important since the
-                // rude thread abort protection algorithm relies on root CER methods being marked as such.
-                pContext->m_fRoot = true;
-            }
-
-            // Determine if this was really a virtual call (we discard those since we can't reliably determine the call target).
-            bool fNonVirtualCall = dwOp == CEE_CALL || !pCallTarget->m_pMethodDesc->IsVirtual() || pCallTarget->m_pMethodDesc->IsFinal();
-
-            // When we're only processing qualified catch / finally handlers then we need to compute whether this call site
-            // lands in one of them.  The callsite is always within a cer if we are processing the full method.
-            // If we have stackoverflow probing on, also call to determine if the CER try or finally makes any calls
-            bool fCallsiteWithinCerInThisFunction = false;
-            if (!m_fEntireMethod || g_pConfig->ProbeForStackOverflow()) {
-                DWORD dwOffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code);
-                fCallsiteWithinCerInThisFunction = CheckIfCallsiteWithinCER(dwOffset);
-            }
-            bool fCallsiteWithinCer = m_fEntireMethod || fCallsiteWithinCerInThisFunction;
-
-            // Check for the presence of some sort of reliability contract (on the method, class or assembly). This will
-            // determine whether we log an error, ignore the method or treat it as part of the prepared call graph.
-            ReliabilityContractLevel eLevel = RCL_UNKNOWN;
-            if (fNonVirtualCall &&                          // Ignore virtual calls
-                fCallsiteWithinCer &&                       // And calls outside CERs
-                !m_sAlreadySeen.IsInStack(pCallTarget) &&     // And methods we've seen before
-                !m_sLeftToProcess.IsInStack(pCallTarget) &&   // And methods we've already queued for processing
-                (eLevel = CheckForReliabilityContract(pCallTarget->m_pMethodDesc)) >= RCL_PREPARE_CONTRACT) // And unreliable methods
-                m_sLeftToProcess.Push(pCallTarget);           // Otherwise add this method to the list to process
-            else if (fCallsiteWithinCer) { 
-#if defined(_DEBUG) || defined(MDA_SUPPORTED)
-                DWORD dwOffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code);
-#endif // defined(_DEBUG) || defined(MDA_SUPPORTED)
-                if (eLevel == RCL_NO_CONTRACT) {
-                    // Method was sufficiently unreliable for us to warn interested users that something may be amiss. Do this
-                    // through MDA logging.
-#ifdef MDA_SUPPORTED
-                    MDA_TRIGGER_ASSISTANT(InvalidCERCall, ReportViolation(pContext->m_pMethodDesc, pCallTarget->m_pMethodDesc, dwOffset));
-#endif
-                    CER_LOG(WARNINGS, ("CER: %s +%04X -> %s: weak contract\n", pContext->ToString(), dwOffset, pCallTarget->ToString()));
-                } else if (!fNonVirtualCall && !m_fIgnoreVirtualCERCallMDA) {
-                    // Warn users about virtual calls in CERs (so they can go back and consider which target methods need to be
-                    // prepared ahead of time).
-#ifdef MDA_SUPPORTED
-                    MDA_TRIGGER_ASSISTANT(VirtualCERCall, ReportViolation(pContext->m_pMethodDesc, pCallTarget->m_pMethodDesc, dwOffset));
-#endif
-                    CER_LOG(WARNINGS, ("CER: %s +%04X -> %s: virtual call\n", pContext->ToString(), dwOffset, pCallTarget->ToString()));
-                }
-            }
-        }
-
-        // Skip the rest of the current IL instruction. Look up the table built statically at the top of this module for most
-        // instructions, but CEE_SWITCH requires special processing (the length of that instruction depends on a count DWORD
-        // embedded right after the opcode).
-        if (dwOp == CEE_SWITCH) {
-            DWORD dwTargets = GET_UNALIGNED_VAL32(pbIL);
-            if (dwTargets >= (MAXDWORD / sizeof(DWORD)))
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT); // multiplication below would overflow
-            DWORD cbSwitch = (1 + dwTargets) * sizeof(DWORD);
-            if (cbIL < cbSwitch)
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            pbIL += cbSwitch;
-            cbIL -= cbSwitch;
-        } else {
-            if (dwOp >= _countof(g_rOpArgs))
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            DWORD cbOp = g_rOpArgs[dwOp];
-            if (cbIL < cbOp)
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            pbIL += cbOp;
-            cbIL -= cbOp;
-        }
-
-    } // End of IL parsing loop
-}
-
-void MethodCallGraphPreparer::PrepareMethods()
-{
-    STANDARD_VM_CONTRACT;
-
-#ifdef _DEBUG
-    DWORD dwCount = 0;
-    if (GetCerLoggingOptions())
-    {
-        CER_LOG(PREPARE, ("---------------------------------------------------------------\n"));
-        SString ssMethod;
-        TypeString::AppendMethodInternal(ssMethod, m_pRootMD, TypeString::FormatNamespace | TypeString::FormatStubInfo);
-        CER_LOG(PREPARE, ("Preparing from %S\n", ssMethod.GetUnicode()));
-    }
-#endif
-
-    MethodContext      *pContext;               // The current MethodContext we're processing
-
-    while ((pContext = m_sAlreadySeen.Pop()) != NULL) {
-        MethodDesc *pMD = pContext->m_pMethodDesc;
-
-#ifndef CROSSGEN_COMPILE
-        // Jitting. Don't need to do this for the ngen case.
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-        if (!m_fNgen)
-#endif
-        {
-            // Also skip the jit for the root method in the activated from jit case (where this would result in a recursive
-            // jit). We'd cope with this just fine, the main reason for this logic is to avoid unbalancing some profiler event
-            // counts that upset some of our test cases. This is safe in the face of multiple instantiations of the same method
-            // because in the jit activated case (where we're told the root type context is not exact) we early exit if the root
-            // method desc isn't 'unique' (i.e. independent of the type context).
-            if (m_fExactTypeContext || pMD != m_pRootMD) {
-
-                // Jit the method we traced.
-                if (pMD->IsPointingToPrestub())
-                {
-                    pMD->EnsureActive();
-                    pMD->DoPrestub(NULL);
-                }
-
-                // If we traced an instantiating stub we need to jit the wrapped (real) method as well.
-                if (pMD->IsInstantiatingStub()) {
-                    _ASSERTE(!pMD->ContainsGenericVariables());
-                    MethodDesc *pRealMD = pMD->GetWrappedMethodDesc();
-                    if (pRealMD->IsPointingToPrestub())
-                    {
-                        pMD->EnsureActive();
-                        pRealMD->DoPrestub(NULL);
-                    }
-                }
-            }
-
-            // Remember sub-CER root methods for further processing in RecordResults. We need to build CerPrepInfo structures for
-            // these just the same as top-level CERs since we may wander in to them by a route that doesn't include the top-level CER
-            // and the thread abort deflection algorithm relies on each CER root method being marked by a CerPrepInfo. Defer this
-            // processing to RecordResults since we aren't guaranteed to have prepared all the methods of the sub-graph at this
-            // point.
-            if (pContext->m_fRoot && pMD != m_pRootMD)
-                m_sPersist.Push(pContext);
-        }
-#endif // CROSSGEN_COMPILE
-
-        // Prepare generic dictionaries (both class and method as needed). We do this even in the ngen scenario, trying to get
-        // as many slots filled as possible. By the looks of it, it's possible that not all of these entries will make it across
-        // to runtime (the fixup code seems to give up on some of the more complex entries, not sure of the details). But we'll
-        // do as best we can here to hopefully minimize any real work on the other side.
-
-        // Don't use the direct PrepopulateDictionary method on MethodTable here, it takes binding considerations into account
-        // (which we don't care about).
-        DictionaryLayout *pClassDictLayout = pMD->GetClass()->GetDictionaryLayout();
-        if (pClassDictLayout) {
-            // Translate the representative method table we can find from our method desc into an exact instantiation using the
-            // type context we have.
-            MethodTable *pMT = TypeHandle(pMD->GetMethodTable()).Instantiate(pContext->m_sTypeContext.m_classInst).AsMethodTable();
-
-            pMT->GetDictionary()->PrepopulateDictionary(NULL, pMT, false);
-
-            // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
-            PrepopulateGenericHandleCache(pClassDictLayout, NULL, pMT);
-        }
-
-        // Don't use the direct PrepopulateDictionary method on MethodDesc here, it appears to use a representative class
-        // instantiation (and we have the exact one handy).
-        DictionaryLayout *pMethDictLayout = pMD->GetDictionaryLayout();
-        if (pMethDictLayout) {
-            pMD->GetMethodDictionary()->PrepopulateDictionary(pMD, NULL, false);
-
-            // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
-            PrepopulateGenericHandleCache(pMethDictLayout, pMD, NULL);
-        }
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-        // Keep some of the method contexts around for the ngen case (the ones that might still need fixup at runtime). We'll
-        // write them into a persisted data structure in the next step.
-        // @todo: We use a horrible workaround here to get round the fact that while ngen'ing mscorlib we may prepare some of its
-        // methods before we've had a chance to start up the compilation domain (mscorlib code is shared and used by the ngen
-        // process itself). So we can't blindly call NeedsRestore() on an mscorlib method since that code asserts we're in the
-        // compilation domain. Instead, if we're in the ngen process and we're outside the compilation domain we're going to
-        // assume that the method doesn't need restoration. This only affects a handful of methods (six at last count, all to do
-        // with security safe handles or some CERs in remoting).
-        if (m_fNgen) {
-            if (GetAppDomain() == NULL ||
-                !GetAppDomain()->IsCompilationDomain() ||
-                !(GetAppDomain()->ToCompilationDomain()->canCallNeedsRestore()) ||
-                !(GetAppDomain()->ToCompilationDomain()->GetTargetImage()->CanPrerestoreEagerBindToMethodDesc(pMD, NULL))||
-                pMD->HasClassOrMethodInstantiation() ||
-                pMD->IsNDirect() ||
-                pMD->IsComPlusCall() ||
-                pMD->IsFCall() ||
-                pContext->m_fRoot)
-                m_sPersist.Push(pContext);
-        }
-#endif
-
-#ifdef _DEBUG
-        CER_LOG(PREPARE, ("  %s\n", pContext->ToString()));
-        dwCount++;
-#endif
-    }
-
-#ifdef _DEBUG
-    CER_LOG(PREPARE, ("Prepared a total of %u methods\n", dwCount));
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-    if (m_fNgen)
-        CER_LOG(PREPARE, ("Saved data for %u of them in the ngen image\n", m_sPersist.GetCount()));
-#endif
-    CER_LOG(PREPARE, ("---------------------------------------------------------------\n"));
-#endif
-}
-
-// Common code used in creating/looking up a CerPrepInfo and initializing/updating it.
-void InitPrepInfo(MethodDesc *pMD, SigTypeContext *pTypeContext, bool fMethodHasCallsWithinExplicitCer)
-{
-    CONTRACTL {
-        STANDARD_VM_CHECK;
-        PRECONDITION(CheckPointer(pMD));
-    } CONTRACTL_END;
-
-    // Lookup or allocate the CerPrepInfo.
-    CerPrepInfo *pInfo = pMD->GetModule()->CreateCerPrepInfo(pMD);
-
-    pInfo->m_fMethodHasCallsWithinExplicitCer = fMethodHasCallsWithinExplicitCer;
-
-    // Work out if this was a partial preparation.
-    bool fPartialPreparation = pMD->IsSharedByGenericInstantiations() ||
-                               pMD->IsInstantiatingStub() ||
-                               pMD->ContainsGenericVariables();
-
-    // Simple case first: if this isn't a partial preparation (no pesky unbound type vars to worry about), then the method is
-    // now fully prepared.
-    if (!fPartialPreparation) {
-        pInfo->m_fFullyPrepared = true;
-        return;
-    }
-
-    // Else we know we require per-instantiation initialization. We need to update a hash table to record the preparation we did
-    // in this case, and that requires taking a mutex. We could check that nobody beat us to it first, but that will hardly ever
-    // happen, so it's not really worth it. So just acquire the mutex right away.
-    CrstHolder sHolder(pMD->GetModule()->GetCerCrst());
-
-    pInfo->m_fRequiresInstantiation = true;
-
-    // Add an entry to a hash that records which instantiations we've prep'd for (again, only if someone hasn't beaten us).
-    HashDatum sDatum;
-    if (!pInfo->m_sIsInitAtInstHash.GetValue(pTypeContext, &sDatum))
-    {
-        pInfo->m_sIsInitAtInstHash.InsertKeyAsValue(pTypeContext);
-    }
-}
-
-bool  MethodCallGraphPreparer::RecordResults()
-{
-    STANDARD_VM_CONTRACT;
-
-    // Preparation has been successful, record what we've done in a manner consistent with whether we're ngen'ing or running for
-    // real.
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-    // If we're ngen'ing an image we save our progess as a list of method contexts that might need restoration at runtime (since
-    // even with prejitting there are some things that need to be prepared at runtime). This list goes into a per module table (the
-    // module in question being that of the root method in the CER).
-    if (m_fNgen) {
-
-        // We have the list of MethodContexts ready, but they're in cheap storage that will go away once we exit this method.
-        // Not only do we have to copy them to heap memory, but we also know exactly how many there are. So we can allocate a
-        // single array with a more compact form of MethodContext for each element. We allocate an extra sentinel value for the end
-        // of the list. This means we can store just a pointer to the list without a count (the code that accesses this list cares
-        // about keeping the list heads compact and densely packed and doesn't care about counting the elements in the list).
-        DWORD cContexts = m_sPersist.GetCount();
-        LoaderHeap *pHeap = m_pRootMD->GetAssembly()->GetLowFrequencyHeap();
-        MethodContextElement *pContexts = (MethodContextElement*)(void*)pHeap->AllocMem(S_SIZE_T(sizeof(MethodContextElement)) * (S_SIZE_T(cContexts) + S_SIZE_T(1)));
-        DWORD i = 0;
-
-        MethodContext      *pContext;               // The current MethodContext we're processing
-        while ((pContext = m_sPersist.Pop()) != NULL) {
-            pContexts[i].m_pMethodDesc.SetValue(pContext->m_pMethodDesc);
-
-            MethodTable * pExactMT = NULL;
-            if (!pContext->m_sTypeContext.m_classInst.IsEmpty())
-            {
-                pExactMT = TypeHandle(pContext->m_pMethodDesc->GetMethodTable()).Instantiate(pContext->m_sTypeContext.m_classInst).AsMethodTable();
-                _ASSERTE(pExactMT->HasInstantiation());
-            }
-            else
-            {
-                _ASSERTE(!pContext->m_pMethodDesc->GetMethodTable()->HasInstantiation());
-            }
-            pContexts[i].m_pExactMT.SetValue(pExactMT);
-
-            i++;
-
-            // Keep the context round for a little longer if the method in question was the root of a sub-CER.
-            if (pContext->m_fRoot)
-                m_sRootMethods.Push(pContext);
-        }
-
-        // Write sentinel entry terminating list.
-        _ASSERTE(i == cContexts);
-
-        // Add list representing this CER to the per-module table (keyed by root method desc).
-        m_pRootMD->GetModule()->AddCerListToRootTable(m_pRootMD, pContexts);
-
-        // If this did have an call from an explicit PCER range, create a PrepInfo for it so that we can
-        // quickly grab that information later when we jit that method.  This allows us to optimize the probe
-        // away if there are no calls from the PCER range.  This is an issue when we've prepared a method
-        // as part of a CER call from another method, but haven't ngened that method yet.  When we get
-        // around to finally ngening that method, we want to be able to optimize the CER probe out if
-        // we can, but don't want to reprepare the method.
-        if (g_pConfig->ProbeForStackOverflow() && m_fMethodHasCallsWithinExplicitCer)
-        {
-            if (m_pCerPrepInfo == NULL)
-                m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD);
-            m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer = TRUE;
-        }
-
-
-        // We need to be careful with sub-CERs in the ngen case. In the jit case they're dealt with automatically (preparing a
-        // super-CER always completely prepares a sub-CER). But in the ngen case we potentially need to run further preparation
-        // steps at the point that a CER root is executed for the first time. If the sub-root is encountered before the super-root
-        // then the sub-CER won't have been prepared correctly.
-        // We solve this simply by recursively running this routine over the methods we noted were sub-roots earlier (this list
-        // doesn't include the main root). We could potentially do a little better than this given that we've calculated the
-        // super-graph, but this is complicated somewhat by the fact that we don't retain the graph structure (i.e. we can't extract
-        // sub-graphs easily) and the effort seems wasted just to avoid a little CPU time and stack space just for the ngen creation
-        // scenario.
-        while ((pContext = m_sRootMethods.Pop()) != NULL)
-        {
-            MethodCallGraphPreparer mgcp(pContext->m_pMethodDesc, &pContext->m_sTypeContext, false, false);
-            mgcp.Run();
-        }
-
-        return m_fMethodHasCallsWithinExplicitCer;
-    }
-#endif // FEATURE_NATIVE_IMAGE_GENERATION
-
-    // This is the runtime (non-ngen case). Record our progress in an info structure placed in a hash table hung off the module
-    // which owns the root method desc in the CER. The methods which create this info structure handle race conditions (to
-    // ensure we don't leak memory or data), but the updates to the info structure itself might not require any serialization
-    // (the values are 'latched' -- recomputation should yield the same result). The exception is any update to a more complex
-    // data fields (lists and hash tables) that require serialization to prevent corruption of the basic data structure.
-
-    // Process sub-CER roots first. We need to build CerPrepInfo structures for these just as same as top-level CERs since we may
-    // wander in to them by a route that doesn't include the top-level CER and the thread abort deflection algorithm relies on each
-    // CER root method being marked by a CerPrepInfo.
-    MethodContext *pContext;
-    while ((pContext = m_sPersist.Pop()) != NULL) {
-        _ASSERTE(pContext->m_fRoot);
-
-        // @todo: need to flow fMethodHasCallsWithinExplicitCer information through method contexts. For now just make a
-        // conservative, safe choice.
-        InitPrepInfo(pContext->m_pMethodDesc, &pContext->m_sTypeContext, true);
-    }
-
-    // Now process the top-level CER.
-    InitPrepInfo(m_pRootMD, m_pRootTypeContext, m_fMethodHasCallsWithinExplicitCer);
-
-    return m_fMethodHasCallsWithinExplicitCer;
-}
-
-// Determines whether the given method contains a CER root that can be pre-prepared (i.e. prepared at jit time).
-bool ContainsPrePreparableCerRoot(MethodDesc *pMD)
-{
-    CONTRACTL {
-        STANDARD_VM_CHECK;
-        PRECONDITION(CheckPointer(pMD));
-    } CONTRACTL_END;
-
-    // Deal with exotic cases (non-IL methods and the like).
-    if (!pMD->IsIL() || pMD->IsAbstract())
-        return false;
-
-    // And cases where we can't jit prepare (because the code is shared between instantiations).
-    if (pMD->IsSharedByGenericInstantiations() || pMD->IsInstantiatingStub() || pMD->ContainsGenericVariables())
-        return false;
-
-    // Otherwise we have a trickier calculation. We don't want to force the jit of the method at this point (may cause infinite
-    // recursion problems when we're called from the jit in the presence of call cycles). Instead we walk the top-level of the
-    // method IL using the same algorithm as PrepareMethodCallGraph.
-
-    // Locate the IL body of the current method. May have to account for the fact that the current method desc is an
-    // instantiating stub and burrow down for the real method desc.
-    MethodDesc *pRealMethod = pMD;
-    if (pRealMethod->IsInstantiatingStub()) {
-        _ASSERTE(!pRealMethod->ContainsGenericVariables());
-        pRealMethod = pRealMethod->GetWrappedMethodDesc();
-    }
-    COR_ILMETHOD_DECODER method(pRealMethod->GetILHeader());
-    BYTE *pbIL = (BYTE*)method.Code;
-    DWORD cbIL = method.GetCodeSize();
-
-    // Look for exception handling information for the method. If there isn't any then we know there can't be a CER rooted here.
-    COR_ILMETHOD_SECT_EH const * pEH = method.EH;
-    if (pEH == NULL || pEH->EHCount() == 0)
-        return false;
-
-    // Iterate through the body of the method looking for interesting call sites.
-    while (cbIL) {
-
-        // Read the IL op.
-        DWORD dwOp = *pbIL++; cbIL--;
-
-        // Handle prefix codes (only CEE_PREFIX1 is legal so far).
-        if (dwOp == CEE_PREFIX1) {
-            if (!cbIL)
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            dwOp = 256 + *pbIL++; cbIL--;
-            if (dwOp >= CEE_ILLEGAL)
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-        } else if (dwOp >= CEE_PREFIX7)
-            COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
-        // We'll only ever see CALL instructions targeting PrepareConstrainedRegions (well those are the ones we're interested in
-        // anyway).
-        if (dwOp == CEE_CALL)
-        {
-            if (cbIL < sizeof(DWORD))
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            if (IsPcrReference(pMD->GetModule(), (mdToken)GET_UNALIGNED_VAL32(pbIL)))
-                return true;
-        }
-
-        // Skip the rest of the current IL instruction. Look up the table built statically at the top of this module for most
-        // instructions, but CEE_SWITCH requires special processing (the length of that instruction depends on a count DWORD
-        // embedded right after the opcode).
-        if (dwOp == CEE_SWITCH) {
-            if (cbIL < sizeof(DWORD))
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            DWORD dwTargets = GET_UNALIGNED_VAL32(pbIL);
-            if (dwTargets >= (MAXDWORD / sizeof(DWORD)))
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT); // multiplication below would overflow
-            DWORD cbSwitch = (1 + dwTargets) * sizeof(DWORD);
-            if (cbIL < cbSwitch)
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            pbIL += cbSwitch;
-            cbIL -= cbSwitch;
-        } else {
-            if (dwOp >= _countof(g_rOpArgs))
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            DWORD cbOp = g_rOpArgs[dwOp];
-            if (cbIL < cbOp)
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-            pbIL += cbOp;
-            cbIL -= cbOp;
-        }
-
-    } // End of IL parsing loop
-
-    // If we get here then there was no CER-root.
-    return false;
-}
-
-// The name of the PrepareConstrainedRegions method, broken down into its components (the code below scans for these directly in the
-// metadata).
-#define PCR_METHOD      "PrepareConstrainedRegions"
-#define PCR_TYPE        "RuntimeHelpers"
-#define PCR_NAMESPACE   "System.Runtime.CompilerServices"
-
-// Given a token and a module scoping it, determine if that token is a reference to PrepareConstrainedRegions. We want to do this
-// without loading any random types since we're called in a context where type loading is prohibited.
-bool IsPcrReference(Module *pModule, mdToken tkMethod)
-{
-    CONTRACTL {
-        STANDARD_VM_CHECK;
-        PRECONDITION(CheckPointer(pModule));
-    } CONTRACTL_END;
-
-    IMDInternalImport *pImport = pModule->GetMDImport();
-
-    // Validate that the token is one that we can handle.
-    if (!pImport->IsValidToken(tkMethod) || (TypeFromToken(tkMethod) != mdtMethodDef &&
-                                             TypeFromToken(tkMethod) != mdtMethodSpec &&
-                                             TypeFromToken(tkMethod) != mdtMemberRef))
-        COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
-
-    // No reason to see a method spec for a call to something as simple as PrepareConstrainedRegions.
-    if (TypeFromToken(tkMethod) == mdtMethodSpec)
-        return false;
-
-    // If it's a method def then the module had better be mscorlib.
-    if (TypeFromToken(tkMethod) == mdtMethodDef) {
-        if (pModule->GetAssembly()->GetManifestModule() == SystemDomain::SystemAssembly()->GetManifestModule())
-            return tkMethod == g_pPrepareConstrainedRegionsMethod->GetMemberDef();
-        else
-            return false;
-    }
-
-    // That leaves the cross module reference case.
-    _ASSERTE(TypeFromToken(tkMethod) == mdtMemberRef);
-
-    // First get the method name and signature and validate it.
-    PCCOR_SIGNATURE pSig;
-    DWORD cbSig;
-    LPCSTR szMethod;
-    IfFailThrow(pImport->GetNameAndSigOfMemberRef(tkMethod, &pSig, &cbSig, &szMethod));
-    
-    {
-        SigParser sig(pSig, cbSig);
-        ULONG nCallingConvention;
-        ULONG nArgumentsCount;
-        BYTE  bReturnType;
-        
-        // Signature is easy: void PCR().
-        // Must be a static method signature.
-        if (FAILED(sig.GetCallingConvInfo(&nCallingConvention)))
-            return false;
-        if (nCallingConvention != IMAGE_CEE_CS_CALLCONV_DEFAULT)
-            return false;
-        // With no arguments.
-        if (FAILED(sig.GetData(&nArgumentsCount)))
-            return false;
-        if (nArgumentsCount != 0)
-            return false;
-        // And a void return type.
-        if (FAILED(sig.GetByte(&bReturnType)))
-            return false;
-        if (bReturnType != (BYTE)ELEMENT_TYPE_VOID)
-            return false;
-    }
-
-    // Validate the name.
-    if (strcmp(szMethod, PCR_METHOD) != 0)
-        return false;
-
-    // The method looks OK, move up to the type and validate that.
-    mdToken tkType;
-    IfFailThrow(pImport->GetParentOfMemberRef(tkMethod, &tkType));
-    
-    if (!pImport->IsValidToken(tkType))
-        COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
-    
-    // If the parent is not a type ref then this isn't our target (we assume that mscorlib never uses a member ref to target
-    // PrepareConstrainedRegions, check that with the assert below, if it ever fails we need to add some additional logic below).
-    _ASSERTE(TypeFromToken(tkType) != mdtTypeDef ||
-             pModule->GetAssembly()->GetManifestModule() != SystemDomain::SystemAssembly()->GetManifestModule());
-    if (TypeFromToken(tkType) != mdtTypeRef)
-        return false;
-
-    // Get the type name and validate it.
-    LPCSTR szNamespace;
-    LPCSTR szType;
-    IfFailThrow(pImport->GetNameOfTypeRef(tkType, &szNamespace, &szType));
-    
-    if (strcmp(szType, PCR_TYPE) != 0)
-        return false;
-    if (strcmp(szNamespace, PCR_NAMESPACE) != 0)
-        return false;
-    
-    // Type is OK as well. Check the assembly reference.
-    mdToken tkScope;
-    IfFailThrow(pImport->GetResolutionScopeOfTypeRef(tkType, &tkScope));
-    
-    if (TypeFromToken(tkScope) != mdtAssemblyRef)
-        return false;
-    if (!pImport->IsValidToken(tkScope))
-    {
-        COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
-    }
-    
-    // Fetch the name and public key or public key token.
-    BYTE *pbPublicKeyOrToken;
-    DWORD cbPublicKeyOrToken;
-    LPCSTR szAssembly;
-    DWORD dwAssemblyFlags;
-    IfFailThrow(pImport->GetAssemblyRefProps(
-        tkScope, 
-        (const void**)&pbPublicKeyOrToken, 
-        &cbPublicKeyOrToken, 
-        &szAssembly, 
-        NULL,   // AssemblyMetaDataInternal: we don't care about version, culture etc.
-        NULL,   // Hash value pointer, obsolete information
-        NULL,   // Byte count for above
-        &dwAssemblyFlags));
-    
-    // Validate the name.
-    if (stricmpUTF8(szAssembly, g_psBaseLibraryName) != 0)
-        return false;
-    
-    // And the public key or token, which ever was burned into the reference by the compiler. For mscorlib this is the ECMA key or
-    // token.
-    if (IsAfPublicKeyToken(dwAssemblyFlags)) {
-        if (cbPublicKeyOrToken != sizeof(g_rbNeutralPublicKeyToken) ||
-            memcmp(pbPublicKeyOrToken, g_rbNeutralPublicKeyToken, cbPublicKeyOrToken) != 0)
-            return false;
-    } else {
-        if (cbPublicKeyOrToken != sizeof(g_rbNeutralPublicKey) ||
-            memcmp(pbPublicKeyOrToken, g_rbNeutralPublicKey, cbPublicKeyOrToken) != 0)
-            return false;
-    }
-
-    // If we get here we've finally proved the call target was indeed PrepareConstrainedRegions. Whew.
-    return true;
-}
-
-// Prepares a method as a CER root. In some scenarios we set
-// fIgnoreVirtualCERCallMDA=TRUE, this happens when we want to ignore firing a
-// VirtualCERCall MDA because we know for sure that the virtual methods are
-// already prepared. A good example of this case is preparing
-// g_pExecuteBackoutCodeHelperMethod method. 
-void PrepareMethodDesc(MethodDesc* pMD, Instantiation classInst, Instantiation methodInst, BOOL onlyContractedMethod, BOOL fIgnoreVirtualCERCallMDA)
-{
-     CONTRACTL 
-     {
-        THROWS;
-        DISABLED(GC_TRIGGERS);
-        MODE_ANY;
-    }
-    CONTRACTL_END;
-
-    GCX_PREEMP();
-
-#ifdef FEATURE_PREJIT
-    // This method may have some ngen fixup information provided, in which case we just check that it's been restored and can
-    // dispense with the preparation altogether.
-    Module *pModule = pMD->GetModule();
-    if (pModule->IsNgenCerRootMethod(pMD))
-    {
-        pMD->CheckRestore();
-        pModule->RestoreCer(pMD);
-        return;
-    }
-#endif
-
-    // If we are only going to prepare contracted methods and this method does
-    // not have a contract then we just return.
-    if (onlyContractedMethod && CheckForReliabilityContract(pMD) < RCL_BASIC_CONTRACT)
-    {
-        return;
-    }
-
-    SigTypeContext sTypeContext(pMD, classInst, methodInst);
-    MethodCallGraphPreparer mcgp(pMD, &sTypeContext, true, true, fIgnoreVirtualCERCallMDA == TRUE);
-    mcgp.Run();
-}
-
-// 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)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-        PRECONDITION(CheckPointer(pMT));
-    } CONTRACTL_END;
-
-    // Have we prepared this type before?
-    if (pMT->CriticalTypeHasBeenPrepared())
-        return;
-
-    GCX_PREEMP();
-
-    // Restore the method table if necessary.
-    pMT->CheckRestore();
-
-    // Determine the interesting parent class (either SafeHandle, CriticalHandle or CriticalFinalizerObject).
-    MethodTable *pSafeHandleClass = MscorlibBinder::GetClass(CLASS__SAFE_HANDLE);
-    MethodTable *pCriticalHandleClass = MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE);
-    MethodTable *pParent = pMT;
-    while (pParent) {
-        if (pParent == g_pCriticalFinalizerObjectClass ||
-            pParent == pSafeHandleClass ||
-            pParent == pCriticalHandleClass) {
-            break;
-        }
-        pParent = pParent->GetParentMethodTable();
-    }
-    _ASSERTE(pParent != NULL);
-
-    BinderMethodID rgMethods[5];
-    int nMethods;
-
-    // Prepare the method or methods based on the parent class.
-    if (pParent == pSafeHandleClass) {
-        rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE;
-        rgMethods[1] = METHOD__SAFE_HANDLE__RELEASE_HANDLE;
-        rgMethods[2] = METHOD__SAFE_HANDLE__GET_IS_INVALID;
-        rgMethods[3] = METHOD__SAFE_HANDLE__DISPOSE;
-        rgMethods[4] = METHOD__SAFE_HANDLE__DISPOSE_BOOL;
-        nMethods = 5;
-    } else if (pParent == pCriticalHandleClass) {
-        rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE;
-        rgMethods[1] = METHOD__CRITICAL_HANDLE__RELEASE_HANDLE;
-        rgMethods[2] = METHOD__CRITICAL_HANDLE__GET_IS_INVALID;
-        rgMethods[3] = METHOD__CRITICAL_HANDLE__DISPOSE;
-        rgMethods[4] = METHOD__CRITICAL_HANDLE__DISPOSE_BOOL;
-        nMethods = 5;
-    } else {
-        _ASSERTE(pParent == g_pCriticalFinalizerObjectClass);
-        rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE;
-        nMethods = 1;
-    }
-
-    for (int iMethod = 0; iMethod < nMethods; iMethod++)
-    {
-        // Prepare a (possibly virtual) method on an instance. The method is identified via a binder ID, so the initial
-        // declaration of the method must reside within mscorlib. We might have ngen fixup information for the method and can avoid direct
-        // preparation as well.
-
-        MethodDesc *pPrepMethod = pMT->GetMethodDescForSlot(MscorlibBinder::GetMethod(rgMethods[iMethod])->GetSlot());
-#ifdef FEATURE_PREJIT
-        if (pPrepMethod->GetModule()->IsNgenCerRootMethod(pPrepMethod)) {
-            pPrepMethod->GetModule()->RestoreCer(pPrepMethod);
-        }
-        else
-        if (IsCompilationProcess() && pPrepMethod->IsAbstract()) {
-            // Skip abstract methods during NGen (we should not ever get abstract methods here at runtime)
-        }
-        else
-#endif
-        {
-            if (pModule == NULL || pPrepMethod->GetModule() == pModule) {
-                SigTypeContext _sTypeContext(pPrepMethod, TypeHandle(pMT));
-                MethodCallGraphPreparer mcgp(pPrepMethod, &_sTypeContext, true, true);
-                mcgp.Run();
-            }
-        }
-    }
-
-    // Note the fact that we've prepared this type before to prevent repetition of the work above. (Though repetition is harmless in
-    // all other respects, so there's no need to worry about the race setting this flag).
-    pMT->SetCriticalTypeHasBeenPrepared();
-}
-
-#ifdef _DEBUG
-
-static const char * const g_rszContractNames[] = { "RCL_NO_CONTRACT", "RCL_BASIC_CONTRACT", "RCL_PREPARE_CONTRACT" };
-static DWORD g_dwContractChecks = 0;
-
-#define ReturnContractLevel(_level) do {                                                        \
-    g_dwContractChecks++;                                                                       \
-    if ((g_dwContractChecks % 100) == 0 && g_pMethodContractCache)                              \
-        g_pMethodContractCache->DbgDumpStats();                                                 \
-    ReliabilityContractLevel __level = (_level);                                                \
-    CER_LOG(CONTRACTS, ("%s -- %s\n", pMD->m_pszDebugMethodName, g_rszContractNames[__level])); \
-    return __level;                                                                             \
-} while (false)
-#else
-#define ReturnContractLevel(_level) return (_level)
-#endif
-
-// 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)
-{
-    CONTRACTL {
-        NOTHROW;
-        GC_NOTRIGGER;
-        MODE_ANY;
-        PRECONDITION(CheckPointer(pMD));
-    } CONTRACTL_END;
-
-    // We are attempting to abstract reliability contracts for the given method into three different buckets: those methods that
-    // will cause an error (or a MDA report at least) during preparation (RCL_NO_CONTRACT), those we allow but don't prepare
-    // (RCL_BASIC_CONTRACT) and those we allow and prepare (RCL_PREPARE_CONTRACT).
-    //
-    // We place methods into the first bucket below that matches:
-    //  RCL_NO_CONTRACT      --  Methods with no consistency or whose consistency states they may corrupt the appdomain or process.
-    //  RCL_BASIC_CONTRACT   --  Methods that state CER.None (or don't specify a CER attribute)
-    //  RCL_PREPARE_CONTRACT --  Methods that state CER.MayFail or CER.Success
-    //
-    // We look for reliability contracts at three levels: method, class and assembly. Definitions found at the method level override
-    // those at the class and assembly level and those at the class level override assembly settings.
-    //
-    // In the interests of efficiency we cache contract information in a number of ways. Firstly we look at a hash of recently
-    // queried MethodDescs. This contains authoritative answers (assembly/class/method information has already been composed so on a
-    // hit we don't need to look anywhere else). This cache is allocated lazily, never grows (newer items eventually displace older
-    // ones), is global, requires no locks and is never freed. The idea is to limit the amount of working set we ever occupy while
-    // keeping the CPU usage as low as possible. Typical usages of this method involve querying a small number of methods in a stack
-    // walk, possibly multiple times, so a small hash cache should work reasonably well here.
-    //
-    // On a miss we're going to have to bite the bullet and look at the assembly, class and method. The assembly and class cache
-    // this information at load (ngen) time though, so they're not so expensive (class level data is cached on the EEClass, so it's
-    // cold data, but the most performance sensitive scenario in which we're called here, ThreadAbort, isn't all that hot).
-
-    // Check the cache first, it contains a raw contract level.
-    ReliabilityContractLevel eLevel;
-    if (g_pMethodContractCache && g_pMethodContractCache->Lookup(pMD, (DWORD*)&eLevel))
-        ReturnContractLevel(eLevel);
-
-    // Start at the method level and work up until we've found enough information to make a decision. The contract level is composed
-    // in an encoded DWORD form that lets us track both parts of the state (consistency and cer) and whether each has been supplied
-    // yet. See the RC_* macros for encoding details.
-    DWORD dwMethodContractInfo = GetReliabilityContract(pMD->GetMDImport(), pMD->GetMemberDef());
-    if (RC_INCOMPLETE(dwMethodContractInfo)) {
-        DWORD dwClassContractInfo = pMD->GetClass()->GetReliabilityContract();
-        dwMethodContractInfo = RC_MERGE(dwMethodContractInfo, dwClassContractInfo);
-        if (RC_INCOMPLETE(dwMethodContractInfo)) {
-            DWORD dwAssemblyContractInfo = pMD->GetModule()->GetReliabilityContract();
-            dwMethodContractInfo = RC_MERGE(dwMethodContractInfo, dwAssemblyContractInfo);
-        }
-    }
-
-    // We've got an answer, so attempt to cache it for the next time.
-
-    // First check we have a cache (we allocate it lazily).
-    if (g_pMethodContractCache == NULL) {
-        PtrHashCache *pCache = new (nothrow) PtrHashCache();
-        if (pCache)
-            if (FastInterlockCompareExchangePointer(&g_pMethodContractCache, pCache, NULL) != NULL)
-                delete pCache;
-    }
-
-    // We still might not have a cache in low memory situations. That's OK.
-    if (g_pMethodContractCache)
-        g_pMethodContractCache->Add(pMD, RC_ENCODED_TO_LEVEL(dwMethodContractInfo));
-
-    ReturnContractLevel(RC_ENCODED_TO_LEVEL(dwMethodContractInfo));
-}
-
-
-// Macro used to handle failures in the routine below.
-#define IfFailRetRcNull(_hr) do { if (FAILED(_hr)) return RC_NULL; } while (false)
-
-// Look for a reliability contract attached to the given metadata token in the given scope. Return the result as an encoded DWORD
-// (see the RC_ENCODE macro).
-DWORD GetReliabilityContract(IMDInternalImport *pImport, mdToken tkParent)
-{
-    CONTRACTL {
-        NOTHROW;
-        GC_NOTRIGGER;
-        MODE_ANY;
-        PRECONDITION(CheckPointer(pImport));
-    } CONTRACTL_END;
-
-    HRESULT hr;
-    DWORD   dwResult = RC_NULL;
-
-    // Sadly we only have two unmanaged APIs available to us for looking at custom attributes. One looks up attributes by name but
-    // only returns the byte blob, not the attribute ctor information (which we need to parse the blob) while the other returns
-    // everything but requires us to enumerate all attributes on a given token looking for the one we're interested in. To keep the
-    // cost down we probe for the existence of the attribute using the first API and then use the enumeration method if we get a
-    // hit.
-    hr = pImport->GetCustomAttributeByName(tkParent, RELIABILITY_CONTRACT_NAME, NULL, NULL);
-    if (hr == S_FALSE)
-        return RC_NULL;
-
-    IfFailRetRcNull(hr);
-
-    // Got at least one contract against this parent. Enumerate them all (filtering by name).
-    MDEnumHolder hEnum(pImport);
-    hr = pImport->SafeAndSlowEnumCustomAttributeByNameInit(tkParent, RELIABILITY_CONTRACT_NAME, &hEnum);
-    _ASSERTE(hr != S_FALSE);
-    IfFailRetRcNull(hr);
-
-    // Enumerate over all the contracts.
-    mdToken tkContract;
-    while (S_OK == pImport->SafeAndSlowEnumCustomAttributeByNameNext(tkParent, RELIABILITY_CONTRACT_NAME, &hEnum, &tkContract)) {
-
-        // Get the attribute type (token of the ctor used) since we need this information in order to parse the blob we'll find
-        // next.
-        mdToken tkAttrType;
-        IfFailRetRcNull(pImport->GetCustomAttributeProps(tkContract, &tkAttrType));
-        if (!pImport->IsValidToken(tkAttrType))
-            continue;
-
-        // The token should be a member ref or method def.
-        // Get the signature of the ctor so we know which version has been called.
-        PCCOR_SIGNATURE pSig;
-        DWORD           cbSig;
-        LPCSTR          szName_Ignore;
-        if (TypeFromToken(tkAttrType) == mdtMemberRef)
-        {
-            IfFailRetRcNull(pImport->GetNameAndSigOfMemberRef(tkAttrType, &pSig, &cbSig, &szName_Ignore));
-        }
-        else
-        {
-            if (TypeFromToken(tkAttrType) != mdtMethodDef)
-                continue;
-            IfFailRetRcNull(pImport->GetNameAndSigOfMethodDef(tkAttrType, &pSig, &cbSig, &szName_Ignore));
-        }
-
-        // Only two signatures are supported: the null sig '()' and the full sig '(Consistency, CER)'.
-        // Set a boolean based on which one was provided.
-        bool                    fNullCtor;
-        ULONG                   eCallConv;
-
-        SigPointer sig(pSig, cbSig);
-
-        // Check the calling convention is what we expect (default convention on an instance method).
-        IfFailRetRcNull(sig.GetCallingConvInfo(&eCallConv));
-        _ASSERTE(eCallConv == (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS));
-        if (eCallConv != (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS))
-            IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
-        // If so, the next datum is the count of arguments, and this is all we need to determine which ctor has been used.
-        ULONG dwArgs;
-        IfFailRetRcNull(sig.GetData(&dwArgs));
-        _ASSERTE(dwArgs == 0 || dwArgs == 2);
-        if (dwArgs != 0 && dwArgs != 2)
-            IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
-        fNullCtor = dwArgs == 0;
-
-        // Now we know how to parse the blob, let's fetch a pointer to it.
-        BYTE const *pbData;
-        DWORD       cbData;
-        IfFailRetRcNull(pImport->GetCustomAttributeAsBlob(tkContract, (const void **)&pbData, &cbData));
-        
-        // Check serialization format (we support version 1 only).
-        if (cbData < sizeof(WORD) || GET_UNALIGNED_VAL16(pbData) != 1)
-            IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-        pbData += sizeof(WORD);
-        cbData -= sizeof(WORD);
-
-        // Parse ctor arguments if we have any.
-        if (!fNullCtor) {
-
-            // We assume the enums are based on DWORDS.
-            if (cbData < (sizeof(DWORD) * 2))
-                IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
-            // Consistency first.
-            DWORD dwConsistency = GET_UNALIGNED_VAL32(pbData);
-            pbData += sizeof(DWORD);
-            cbData -= sizeof(DWORD);
-            if (dwConsistency > RC_CONSISTENCY_CORRUPT_NOTHING)
-                IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
-            // Followed by Cer.
-            DWORD dwCer = GET_UNALIGNED_VAL32(pbData);
-            pbData += sizeof(DWORD);
-            cbData -= sizeof(DWORD);
-            if (dwCer > RC_CER_SUCCESS)
-                IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
-            dwResult = RC_MERGE(dwResult, RC_ENCODE(dwConsistency, dwCer));
-        }
-
-        // Get the count of field/property, value pairs.
-        if (cbData < sizeof(WORD))
-            IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-        WORD cPairs = GET_UNALIGNED_VAL16(pbData);
-        pbData += sizeof(WORD);
-        cbData -= sizeof(WORD);
-
-        // Iterate over any such pairs, looking for values we haven't picked up yet.
-        for (DWORD i = 0 ; i < cPairs; i++) {
-
-            // First is a field vs property selector. We expect only properties.
-            if (cbData < sizeof(BYTE) || *(BYTE*)pbData != SERIALIZATION_TYPE_PROPERTY)
-                IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-            pbData += sizeof(BYTE);
-            cbData -= sizeof(BYTE);
-
-            // Next is the type of the property. It had better be an enum.
-            if (cbData < sizeof(BYTE) || *(BYTE*)pbData != SERIALIZATION_TYPE_ENUM)
-                IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-            pbData += sizeof(BYTE);
-            cbData -= sizeof(BYTE);
-
-            // Next we have the assembly qualified enum type name. This is preceded by a metadata style packed byte length (the
-            // string itself is 8-bit and not null terminated). Ignore it (just skip across) and we'll key off the property name
-            // (coming up) instead.
-            DWORD cbName;
-            BYTE const * pbPostEncodedLength;
-            IfFailRetRcNull(CPackedLen::SafeGetData(pbData, cbData, &cbName, &pbPostEncodedLength));
-            DWORD cbEncodedLength = static_cast<DWORD>(pbPostEncodedLength - pbData);
-            pbData += cbEncodedLength + cbName;
-            cbData -= cbEncodedLength + cbName;
-
-            // Now we have the name of the property (in a similar format to above).
-            IfFailRetRcNull(CPackedLen::SafeGetData(pbData, cbData, &cbName, &pbPostEncodedLength));
-            cbEncodedLength = static_cast<DWORD>(pbPostEncodedLength - pbData);
-            pbData += cbEncodedLength;
-            cbData -= cbEncodedLength;
-
-            bool fConsistencyProp = false;
-            if (cbName == strlen(RC_CONSISTENCY_PROP_NAME) && strncmp((const char*)pbData, RC_CONSISTENCY_PROP_NAME, cbName) == 0)
-                fConsistencyProp = true;
-            else if (cbName == strlen(RC_CER_PROP_NAME) && strncmp((const char*)pbData, RC_CER_PROP_NAME, cbName) == 0)
-                fConsistencyProp = false;
-            else
-                IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-            pbData += cbName;
-            cbData -= cbName;
-
-            // And finally the actual enum value (again, we assume the underlying type is a DWORD).
-            if (cbData < sizeof(DWORD))
-                IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-            DWORD dwValue = GET_UNALIGNED_VAL32(pbData);
-            pbData += sizeof(DWORD);
-            cbData -= sizeof(DWORD);
-
-            if (fConsistencyProp) {
-                if (dwValue > RC_CONSISTENCY_CORRUPT_NOTHING)
-                    IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-                dwResult = RC_MERGE(dwResult, RC_ENCODE(dwValue, RC_CER_UNDEFINED));
-            } else {
-                if (dwValue > RC_CER_SUCCESS)
-                    IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-                dwResult = RC_MERGE(dwResult, RC_ENCODE(RC_CONSISTENCY_UNDEFINED, dwValue));
-            }
-        }
-
-        // Shouldn't have any bytes left in the blob at this stage.
-        _ASSERTE(cbData == 0);
-    }
-
-    // Return the result encoded and packed into the 2 low order bits of a DWORD.
-    return dwResult;
-}
-
-// Given a metadata token, a scoping module and a type context, look up the appropriate MethodDesc (and recomputed accompanying type
-// context).
-MethodContext *TokenToMethodDesc(Module *pModule, mdToken tokMethod, SigTypeContext *pTypeContext)
-{
-    STANDARD_VM_CONTRACT;
-
-    // Validate that the token is one that we can handle.
-    if (!pModule->GetMDImport()->IsValidToken(tokMethod) || (TypeFromToken(tokMethod) != mdtMethodDef &&
-                                                             TypeFromToken(tokMethod) != mdtMethodSpec &&
-                                                             TypeFromToken(tokMethod) != mdtMemberRef)) {
-        COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
-    }
-
-    // Look up the MethodDesc based on the token and type context.
-    MethodDesc *pMD = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule,
-                                                                          tokMethod,
-                                                                          pTypeContext,
-                                                                          TRUE,
-                                                                          FALSE);
-
-    // The MethodDesc we get might be shared between several types. If so we'll need to do extra work to locate the exact
-    // class instantiation instead of the default representative one.
-    SigTypeContext sNewTypeContext;
-    if (pMD->IsSharedByGenericInstantiations()) {
-        TypeHandle th = GetTypeFromMemberDefOrRefOrSpecThrowing(pModule,
-                                                                tokMethod,
-                                                                pTypeContext);
-        SigTypeContext::InitTypeContext(pMD, th,&sNewTypeContext);
-    } else
-        SigTypeContext::InitTypeContext(pMD, pMD->GetClassInstantiation(), pMD->GetMethodInstantiation(),&sNewTypeContext);
-
-    return MethodContext::PerThreadAllocate(pMD, &sNewTypeContext);
-}
-
-// Locate an exact type definition given a method token and the type context in which it can be resolved.
-TypeHandle GetTypeFromMemberDefOrRefOrSpecThrowing(Module         *pModule,
-                                                   mdToken         tokMethod,
-                                                   SigTypeContext *pTypeContext)
-{
-    STANDARD_VM_CONTRACT;
-
-    IMDInternalImport *pImport = pModule->GetMDImport();
-
-    // Convert method specs into the underlying member ref.
-    if (TypeFromToken(tokMethod) == mdtMethodSpec)
-    {
-        PCCOR_SIGNATURE   pSig;
-        ULONG             cSig;
-        mdMemberRef       tkGenericMemberRef;
-        
-        IfFailThrow(pImport->GetMethodSpecProps(tokMethod, &tkGenericMemberRef, &pSig, &cSig));
-        
-        if (!pImport->IsValidToken(tkGenericMemberRef) || 
-            (TypeFromToken(tkGenericMemberRef) != mdtMethodDef &&
-             TypeFromToken(tkGenericMemberRef) != mdtMemberRef))
-        {
-            COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
-        }
-        
-        tokMethod = tkGenericMemberRef;
-    }
-    
-    // Follow the member ref/def back up to the type def/ref/spec or module (for global methods).
-    if (TypeFromToken(tokMethod) == mdtMemberRef)
-    {
-        IfFailThrow(pImport->GetParentOfMemberRef(tokMethod, &tokMethod));
-        
-        // For varargs, a memberref can point to a methodDef
-        if (TypeFromToken(tokMethod) == mdtMethodDef)
-        {
-            if (!pImport->IsValidToken(tokMethod))
-            {
-                COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
-            }
-            IfFailThrow(pImport->GetParentToken(tokMethod, &tokMethod));
-        }
-    }
-    else if (TypeFromToken(tokMethod) == mdtMethodDef)
-    {
-        IfFailThrow(pImport->GetParentToken(tokMethod, &tokMethod));
-    }
-    
-    if (!pImport->IsValidToken(tokMethod) || (TypeFromToken(tokMethod) != mdtTypeDef  &&
-                                              TypeFromToken(tokMethod) != mdtTypeRef  &&
-                                              TypeFromToken(tokMethod) != mdtTypeSpec &&
-                                              TypeFromToken(tokMethod) != mdtModuleRef))
-    {
-        COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
-    }
-    
-    // Load the type in question, using a type context if necessary to get an exact representation.
-    TypeHandle th;
-    if (TypeFromToken(tokMethod) == mdtModuleRef) {
-        DomainFile *pNewModule = pModule->LoadModule(GetAppDomain(), tokMethod, FALSE);
-        if (pNewModule != NULL)
-            th = TypeHandle(pNewModule->GetModule()->GetGlobalMethodTable());
-    } else {
-        th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule,
-                                                         tokMethod,
-                                                         pTypeContext);
-    }
-
-    if (th.IsNull())
-        COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
-    return th;
-}
-
-// 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)
-{
-    CONTRACTL {
-        NOTHROW;
-        GC_NOTRIGGER;
-        MODE_ANY;
-        PRECONDITION(CheckPointer(pMD));
-        SO_TOLERANT;
-    } CONTRACTL_END;
-
-    // Treat IL stubs as CER roots (marshaling code needs to string together operations without being interruped by thread aborts).
-    if (pMD->IsILStub())
-        return true;
-
-    // There are some well defined root methods defined by the system.
-    if (pMD == g_pExecuteBackoutCodeHelperMethod)
-        return true;
-
-    // For now we just look to see whether there is some prep or fixup info stored for this method.
-    Module *pModule = pMD->GetModule();
-
-    if (pModule->GetCerPrepInfo(pMD) != NULL)
-        return true;
-
-#ifdef FEATURE_PREJIT
-    if (pModule->IsNgenCerRootMethod(pMD))
-        return true;
-#endif
-
-    return false;
-}
-
-// 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)
-{
-    CONTRACTL {
-        THROWS;
-        GC_TRIGGERS;
-        MODE_ANY;
-    } CONTRACTL_END;
-
-    // Dictionary overflow entries are recorded starting in the second bucket of the dictionary layout.
-    DictionaryLayout *pOverflows = pDictionaryLayout->GetNextLayout();
-
-    while (pOverflows) {
-        for (DWORD i = 0; i < pOverflows->GetMaxSlots(); i++) {
-            DictionaryEntryLayout *pEntry = pOverflows->GetEntryLayout(i);
-
-            // We've finished as soon as we find the first unused slot.
-            if (!pEntry->m_signature)
-                return;
-
-            // We have a valid overflow entry. Determine the handle value given the type context we have and push it into the JIT's
-            // cache.
-            JIT_GenericHandleWorker(pMD, pMT, pEntry->m_signature);
-        }
-        pOverflows = pOverflows->GetNextLayout();
-    }
-}
-
-#ifdef FEATURE_PREJIT
-
-// 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 CerNgenRootTable::Restore(MethodDesc *pRootMD)
-{
-#ifndef CROSSGEN_COMPILE
-    STANDARD_VM_CONTRACT;
-
-    // We don't have a restoration bitmap at ngen time. No matter, we just always claim everything is restored.
-    if (m_pRestoreBitmap == NULL)
-        return;
-
-    // Locate the root index from the table. Failure indicates there's no work to do.
-    DWORD dwIndex = FindIndex(pRootMD);
-    if (dwIndex == NoSuchRoot)
-        return;
-
-    _ASSERTE(m_pRoots[dwIndex].m_pRootMD == pRootMD);
-
-    // Check then mark the fact that we're preparing (to prevent potential recursion).
-    SigTypeContext typeContext;
-    if (!GetThread()->GetCerPreparationState()->CanPreparationProceed(pRootMD, &typeContext))
-        return;
-
-    MethodCallGraphPreparer sPrep(pRootMD, &typeContext, true, true);
-    MethodCallGraphPreparer::ThreadPreparingCerHolder sCerHolder(&sPrep);
-
-#ifdef _DEBUG
-    if (GetCerLoggingOptions())
-    {
-        CER_LOG(RESTORE, ("---------------------------------------------------------------\n"));
-        SString ssRootMethod;
-        TypeString::AppendMethodInternal(ssRootMethod, pRootMD, TypeString::FormatNamespace | TypeString::FormatStubInfo);
-        CER_LOG(RESTORE, ("Restoring CER graph from %S\n", ssRootMethod.GetUnicode()));
-    }
-#endif
-
-    g_IBCLogger.LogCerMethodListReadAccess(pRootMD);
-
-    // Retrieve the CerRoot structure.
-    CerRoot *pRoot = &m_pRoots[dwIndex];
-    _ASSERTE(pRoot->m_pRootMD == pRootMD);
-
-    // Scan the list of methods in the CER (the last one is a sentinel with a NULL MethodDesc*). Restore each method as we go.
-    MethodContextElement *pEntry = pRoot->m_pList;
-    while (pEntry->GetMethodDesc())
-    {
-        // Method desc and type handle pointers may still be tokenized at this point.
-        Module::RestoreMethodDescPointer(&pEntry->m_pMethodDesc);
-        Module::RestoreMethodTablePointer(&pEntry->m_pExactMT);
-
-        g_IBCLogger.LogCerMethodListReadAccess(pEntry->GetMethodDesc());
-
-        MethodDesc * pMD = pEntry->GetMethodDesc();
-
-        // Check whether there are generic dictionaries that need to be pre-populated.
-
-        // Don't use the direct PrepopulateDictionary method here for MethodTable/MethodDesc
-        //  - MethodTable: Takes binding considerations into account (which we don't care about)
-        //  - MethodDesc: Appears to use a representative class instantiation (and we have the exact one handy)
-        //
-        // Additionally, avoid touching EE Class if we don't need to
-        MethodTable * pMT = pEntry->GetExactMT();
-        if (pMT != NULL)
-        {
-            // MethodTable
-            DictionaryLayout *pClassDictLayout = pMT->GetClass()->GetDictionaryLayout();
-            if (pClassDictLayout)
-            {
-                pMT->GetDictionary()->PrepopulateDictionary(NULL, pMT, false);
-
-                // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
-                PrepopulateGenericHandleCache(pClassDictLayout, NULL, pMT);
-            }
-
-            // MethodDesc
-            DictionaryLayout *pMethDictLayout = pMD->GetDictionaryLayout();
-            if (pMethDictLayout)
-            {
-                pMD->GetMethodDictionary()->PrepopulateDictionary(pMD, NULL, false);
-
-                // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
-                PrepopulateGenericHandleCache(pMethDictLayout, pMD, NULL);
-            }
-        }
-
-        // Recreate stubs used by P/Invoke, COM calls, or FCalls by exercising the prestub.
-        if (pMD->IsPointingToPrestub() && (pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsFCall()))
-        {
-            pMD->EnsureActive();
-            pMD->DoPrestub(NULL);
-        }
-
-#ifdef _DEBUG
-        if (GetCerLoggingOptions())
-        {
-            SString ssMethod;
-            TypeString::AppendMethodInternal(ssMethod, pMD, TypeString::FormatNamespace | TypeString::FormatStubInfo);
-            CER_LOG(RESTORE, ("  %S\n", ssMethod.GetUnicode()));
-        }
-#endif
-
-        // Move to next entry.
-        pEntry++;
-    }
-
-    CER_LOG(RESTORE, ("---------------------------------------------------------------\n"));
-
-    // Mark this whole CER region as fixed up by setting a flag in the restore bitmap (kept separate so we can cluster all our page
-    // writes).
-    // Compute the DWORD offset into the flag array and then the mask for the specific bit in that DWORD.
-    DWORD dwOffset = dwIndex / (sizeof(DWORD) * 8);
-    DWORD dwMask = 1 << (dwIndex % (sizeof(DWORD) * 8));
-    EnsureWritablePages(m_pRestoreBitmap, sizeof(DWORD) * SizeOfRestoreBitmap());
-    FastInterlockOr(&m_pRestoreBitmap[dwOffset], dwMask);
-
-    // If we fixed up any methods with their own CERs then we will have implicitly fixed up those too. Mark their fixup records as
-    // completed as well to avoid further unecessary work.
-    pEntry = pRoot->m_pList;
-    while (pEntry->GetMethodDesc()) {
-        dwIndex = FindIndex(pEntry->GetMethodDesc());
-        if (dwIndex != NoSuchRoot) {
-            dwOffset = dwIndex / (sizeof(DWORD) * 8);
-            dwMask = 1 << (dwIndex % (sizeof(DWORD) * 8));
-            FastInterlockOr(&m_pRestoreBitmap[dwOffset], dwMask);
-        }
-        pEntry++;
-    }
-#endif // CROSSGEN_COMPILE
-}
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-// Add a new root to the table, expanding it as necessary. Note that this method must be called with the CerCrst already held.
-void CerNgenRootTable::AddRoot(MethodDesc *pRootMD, MethodContextElement *pList)
-{
-    CONTRACTL {
-        STANDARD_VM_CHECK;
-        PRECONDITION(IsOwnerOfCrst(pRootMD->GetModule()->GetCerCrst()));
-    } CONTRACTL_END;
-
-    // Ensure we have enough space first.
-    if (m_cRoots == m_cSlots) {
-        DWORD cNewSize = m_cSlots + 16;
-        CerRoot *pNewArray = new CerRoot[cNewSize];
-        memcpyNoGCRefs(pNewArray, m_pRoots, m_cRoots * sizeof(CerRoot));
-        MethodContextElement **pNewRootsInCompilationOrder = new MethodContextElement*[cNewSize];
-        memcpyNoGCRefs(pNewRootsInCompilationOrder, m_pRootsInCompilationOrder, m_cRoots * sizeof(MethodContextElement*) );
-        m_cSlots = cNewSize;
-        delete m_pRoots;
-        m_pRoots = pNewArray;
-        delete m_pRootsInCompilationOrder;
-        m_pRootsInCompilationOrder = pNewRootsInCompilationOrder;
-    }
-
-    // Fill in the new entry in sorted order.
-    DWORD i;
-    for (i = 0; i < m_cRoots; i++)
-        if ((UPTR) m_pRoots[i].m_pRootMD > (UPTR) pRootMD)
-            break;
-    if (i < m_cRoots)
-        memmove(&m_pRoots[i + 1], &m_pRoots[i], (m_cRoots - i) * sizeof(CerRoot));
-    m_pRoots[i].m_pRootMD = pRootMD;
-    m_pRoots[i].m_pList = pList;
-
-    m_pRootsInCompilationOrder[m_cRoots] = pList;
-
-    m_cRoots++;
-}
-
-// Ngen callouts to help serialize this structure and its children to storage.
-void CerNgenRootTable::Save(DataImage *image, CorProfileData *profileData)
-{
-    STANDARD_VM_CONTRACT;
-
-#ifdef _DEBUG
-    DWORD dwMaxEntries = 0;
-    DWORD dwTotalEntries = 0;
-#endif
-
-    image->StoreStructure(this, sizeof(CerNgenRootTable), DataImage::ITEM_CER_ROOT_TABLE);
-    image->StoreStructure(m_pRoots, m_cRoots * sizeof(CerRoot), DataImage::ITEM_CER_ROOT_TABLE);
-
-    // Create a bitmap of boolean flags (1 bit per flag) indicating whether the CER at a given index in the array has been restored.
-    // This is initially all zero and only filled in at runtime (keep all the flags together this way because they're the only
-    // things we have to write at runtime and we want to keep them as dense as possible).
-    _ASSERTE((SizeOfRestoreBitmap() % sizeof(DWORD)) == 0);
-    m_pRestoreBitmap = new DWORD[SizeOfRestoreBitmap() / sizeof(DWORD)];
-    memset(m_pRestoreBitmap, 0xff, SizeOfRestoreBitmap());
-
-    image->StoreStructure(m_pRestoreBitmap,
-                          SizeOfRestoreBitmap(),
-                          DataImage::ITEM_CER_RESTORE_FLAGS);
-
-    // Next save off the list of MethodContextElements associated with each root.
-    for (DWORD i = 0; i < m_cRoots; i++) {
-        MethodContextElement *pEntry = m_pRootsInCompilationOrder[i];
-        
-        // Count entries in list.
-        DWORD cEntries = 0;
-        while (pEntry->GetMethodDesc()) {
-            cEntries++;
-            pEntry++;
-        }
-
-        // Plus one for the sentinel value.
-        cEntries++;
-
-#ifdef _DEBUG
-        dwTotalEntries += cEntries;
-        if (cEntries > dwMaxEntries)
-            dwMaxEntries = cEntries;
-#endif
-
-        // Store this list.
-        image->StoreStructure(m_pRootsInCompilationOrder[i],
-                              cEntries * sizeof(MethodContextElement),
-                              DataImage::ITEM_CER_METHOD_LIST);
-    }
-
-#ifdef _DEBUG
-    if (m_cRoots > 0) {
-        CER_LOG(NGEN_STATS, ("Saving %u CER roots in ngen image\n", m_cRoots));
-        CER_LOG(NGEN_STATS, ("  Max methods in CER: %u\n", dwMaxEntries));
-        CER_LOG(NGEN_STATS, ("  Avg methods in CER: %.1f\n", (float)((float)dwTotalEntries / (float)m_cRoots)));
-    } else
-        CER_LOG(NGEN_STATS, ("No CER roots in ngen image\n"));
-#endif
-}
-
-void CerNgenRootTable::Fixup(DataImage *image)
-{
-    STANDARD_VM_CONTRACT;
-
-    DWORD i;
-
-    // We still use the point to the root array even though at runtime the two structures will be adjacent.
-    image->FixupPointerField(this, offsetof(CerNgenRootTable, m_pRoots));
-
-    // Restoration flags are used only at runtime and must start off zeroed.
-    image->FixupPointerField(this, offsetof(CerNgenRootTable, m_pRestoreBitmap));
-    image->ZeroField(m_pRestoreBitmap, 0, SizeOfRestoreBitmap());
-
-    // The root list in compilation order is only used at ngen time, and is not written into native image.
-    image->ZeroPointerField(this, offsetof(CerNgenRootTable, m_pRootsInCompilationOrder));
-
-    // Fixup all the pointers in the individual CERs.
-    for (i = 0; i < m_cRoots; i++) {
-
-        // For each MethodContextElement in the list we need to fixup a pointer to a MethodDesc and two array pointers (one for any
-        // class instantiation and one for any method instantiation). The actual MethodDescs and TypeHandles themselves are already
-        // fixed up as are the instantiation arrays we point to (they're the ones inside the generic dictionaries of the class/method
-        // concerned).
-        MethodContextElement *pList = m_pRootsInCompilationOrder[i];
-        MethodContextElement *pEntry = pList;
-        while (pEntry->GetMethodDesc()) {
-            image->FixupMethodDescPointer(pList, &pEntry->m_pMethodDesc);
-            image->FixupMethodTablePointer(pList, &pEntry->m_pExactMT);
-            pEntry++;
-        }
-    }
-}
-
-void CerNgenRootTable::FixupRVAs(DataImage *image)
-{
-    STANDARD_VM_CONTRACT;
-
-    DWORD i, j;
-
-    // Now we go back through the root table and sort the entries based on the locations of the root method descs in the new image
-    // (they may be rearranged due to IBC profiling).
-    CerRoot *pNewRoots = (CerRoot*)image->GetImagePointer(m_pRoots);
-    PREFIX_ASSUME(pNewRoots != NULL);
-
-    // Simple insertion sort. Starting at the second element insert a candidate into its correct location in the sub-list
-    // preceding it (which by definition will already be sorted).
-    for (i = 1; i < m_cRoots; i++)
-    {
-        // Look at all of the preceding elements for the first that is larger than the candidate (i.e. should succeed the
-        // candidate in sorted order). If we don't find one then the candidate is already in place and we can proceed to the
-        // next candidate.
-        for (j = 0; j < i; j++)
-            if (image->GetRVA(pNewRoots[j].m_pRootMD) > image->GetRVA(pNewRoots[i].m_pRootMD)) {
-
-                // Need to move candidate element up. Cache its value because we're about to overwrite it.
-                MethodDesc *pTmpRootMD = pNewRoots[i].m_pRootMD;
-                MethodContextElement *pTmpList = pNewRoots[i].m_pList;
-
-                // Shuffle the sorted list one up to make room for the candidate.
-                memmove(&pNewRoots[j + 1], &pNewRoots[j], (i - j) * sizeof(CerRoot));
-
-                // Insert the candidate into position.
-                pNewRoots[j].m_pRootMD = pTmpRootMD;
-                pNewRoots[j].m_pList = pTmpList;
-
-                // Sorted the candidate, move onto the next.
-                break;
-            }
-    }
-
-    // Fixup all the pointers in the individual CERs.
-    for (i = 0; i < m_cRoots; i++) {
-        // Fix up the pointer to the root method and the list of methods in the CER.
-        image->FixupField(m_pRoots, sizeof(CerRoot) * i + offsetof(CerRoot, m_pRootMD),
-            pNewRoots[i].m_pRootMD);
-        image->FixupField(m_pRoots, sizeof(CerRoot) * i + offsetof(CerRoot, m_pList),
-            pNewRoots[i].m_pList);
-    }
-}
-#endif // FEATURE_NATIVE_IMAGE_GENERATION
-
-// 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 CerNgenRootTable::FindIndex(MethodDesc *pRootMD)
-{
-    CONTRACTL {
-        NOTHROW;
-        MODE_ANY;
-        GC_NOTRIGGER;
-        PRECONDITION(CheckPointer(pRootMD));
-        SO_TOLERANT;
-    } CONTRACTL_END;
-
-    // The table is guaranteed to be sorted, so we can lookup our target with a binary search.
-    DWORD dwLow = 0;
-    DWORD dwHigh = m_cRoots - 1;
-    while (true) {
-
-        // Take out the simple cases first.
-
-        // The range has only one entry.
-        if (dwLow == dwHigh) {
-            if (m_pRoots[dwLow].m_pRootMD == pRootMD)
-                return dwLow;
-#ifdef _DEBUG
-            for (DWORD i = 0; i < m_cRoots; i++)
-                _ASSERTE(m_pRoots[i].m_pRootMD != pRootMD);
-#endif
-            return NoSuchRoot;
-        }
-
-        // The range has only two entries.
-        if (dwLow == dwHigh - 1) {
-            if (m_pRoots[dwLow].m_pRootMD == pRootMD)
-                return dwLow;
-            if (m_pRoots[dwHigh].m_pRootMD == pRootMD)
-                return dwHigh;
-#ifdef _DEBUG
-            for (DWORD i = 0; i < m_cRoots; i++)
-                _ASSERTE(m_pRoots[i].m_pRootMD != pRootMD);
-#endif
-            return NoSuchRoot;
-        }
-
-        // Now we can compute a midpoint that is definitely distinct and in-between the endpoints.
-        DWORD dwMid = dwLow + ((dwHigh - dwLow) / 2);
-
-        // Did we nail it?
-        if (m_pRoots[dwMid].m_pRootMD == pRootMD)
-            return dwMid;
-
-        // Otherwise adjust our range to be the bit we haven't looked at and iterate.
-        if ((UPTR)m_pRoots[dwMid].m_pRootMD < (UPTR)pRootMD)
-            dwLow = dwMid + 1;
-        else
-            dwHigh = dwMid - 1;
-    }
-}
-
-// 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)
-{
-    STANDARD_VM_CONTRACT;
-
-    // Prepare any class that satisfies the criteria. Pass a pointer to this module so that we'll only prepare any overrides of
-    // the critical methods that were actually introduced here.
-    if (pMT->HasCriticalFinalizer())
-        PrepareCriticalFinalizerObject(pMT, pMT->GetLoaderModule());
-}
-
-// 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)
-{
-    STANDARD_VM_CONTRACT;
-
-    EX_TRY {
-
-        // Translate jit-style method handle into method desc.
-        MethodDesc *pMD = GetMethod(hMethod);
-
-        // Check for the existance of the attribute.
-        IMDInternalImport  *pImport = pMD->GetMDImport();
-        mdToken             tkMethod = pMD->GetMemberDef();
-        HRESULT             hr = pImport->GetCustomAttributeByName(tkMethod,
-                                                                   "System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute",
-                                                                   NULL, NULL);
-
-        // TODO: We should add IBC probes which indicate that methods need to be preprepared
-        //                which can then be reflected in the IBC data, we can add an additional check
-        //                here to cover that case, then we can get around this problem with profiling
-        //                instead of manual programmer effort.
-
-        // Only prepare if we definitely saw the attribute.
-        if (hr == S_OK) {
-            // Prepare the method and its graph. There should never be any open type parameters (we can't do much at ngen time with these),
-            // so we can pass a null type context.
-            SigTypeContext sTypeContext;
-            MethodCallGraphPreparer mcgp(pMD, &sTypeContext, true, true);
-            mcgp.Run();
-        }
-
-    } EX_CATCH {
-    } EX_END_CATCH(SwallowAllExceptions);
-}
-
-#endif // FEATURE_PREJIT
-
-PtrHashCache::PtrHashCache()
-{
-    LIMITED_METHOD_CONTRACT;
-    ZeroMemory(this, sizeof(*this));
-
-    // First entry in each bucket is a chain index used to evenly distribute inserts within a bucket.
-    _ASSERTE(PHC_CHAIN > 1);
-}
-
-bool PtrHashCache::Lookup(void *pKey, DWORD *pdwValue)
-{
-    LIMITED_METHOD_CONTRACT;
-    _ASSERTE(((UINT_PTR)pKey & PHC_DATA_MASK) == 0);
-
-    DWORD dwBucket = GetHash(pKey);
-
-    // Skip first entry in bucket, it's a sequence number used for insertions.
-    for (DWORD i = 1; i < PHC_CHAIN; i++) {
-        UINT_PTR uipEntry = VolatileLoad<UINT_PTR>(&m_rEntries[(dwBucket * PHC_CHAIN) + i]);
-        if ((uipEntry & ~PHC_DATA_MASK) == (UINT_PTR)pKey) {
-#ifdef _DEBUG
-            FastInterlockIncrement((LONG*)&m_dwHits);
-#endif
-            *pdwValue = uipEntry & PHC_DATA_MASK;
-            return true;
-        }
-    }
-
-#ifdef _DEBUG
-    FastInterlockIncrement((LONG*)&m_dwMisses);
-#endif
-    return false;
-}
-
-void PtrHashCache::Add(void *pKey, DWORD dwValue)
-{
-    LIMITED_METHOD_CONTRACT;
-    _ASSERTE(((UINT_PTR)pKey & PHC_DATA_MASK) == 0);
-    _ASSERTE((dwValue & ~PHC_DATA_MASK) == 0);
-
-    DWORD dwBucket = GetHash(pKey);
-
-    // We keep a sequence number in the first entry of the bucket so that we distribute insertions within the bucket evenly. We're
-    // racing when we update this value, but it doesn't matter if we lose an update (we're a cache after all). We don't bother being
-    // careful to avoid overflowing the value here (we just keep incrementing); we'll do the modulo logic when we insert our value
-    // instead.
-    DWORD dwIndex = static_cast<DWORD>(m_rEntries[dwBucket * PHC_CHAIN]++);
-    dwIndex = (dwIndex % (PHC_CHAIN - 1)) + 1;
-    m_rEntries[(dwBucket * PHC_CHAIN) + dwIndex] = ((UINT_PTR)pKey & ~PHC_DATA_MASK) | dwValue;
-}
-
-DWORD PtrHashCache::GetHash(void *pKey)
-{
-    LIMITED_METHOD_CONTRACT;
-
-    return (DWORD)(((UINT_PTR)pKey >> 4) % PHC_BUCKETS);
-}
-
-#ifdef _DEBUG
-void PtrHashCache::DbgDumpStats()
-{
-#if 0
-    if ((m_dwHits + m_dwMisses) == 0)
-        return;
-
-    printf("Dumping stats for PtrHashCache %08X\n", this);
-    printf("  %u hits, %u misses (%u%% hit rate)\n", m_dwHits, m_dwMisses, (m_dwHits * 100) / (m_dwHits + m_dwMisses));
-    for (DWORD i = 0; i < PHC_BUCKETS; i++)
-        printf("    [%2u] : %u insertions\n", i, m_rEntries[i * PHC_CHAIN]);
-    printf("\n");
-#endif
-}
-#endif