TypeHandle SigPointer::GetTypeHandleThrowing()

in src/coreclr/vm/siginfo.cpp [999:1844]


TypeHandle SigPointer::GetTypeHandleThrowing(
                 ModuleBase *                pModule,
                 const SigTypeContext *      pTypeContext,
                 ClassLoader::LoadTypesFlag  fLoadTypes/*=LoadTypes*/,
                 ClassLoadLevel              level/*=CLASS_LOADED*/,
                 BOOL                        dropGenericArgumentLevel/*=FALSE*/,
                 const Substitution *        pSubst/*=NULL*/,
                 // ZapSigContext is only set when decoding zapsigs
                 const ZapSig::Context *     pZapSigContext,
                 MethodTable *               pMTInterfaceMapOwner,
                 HandleRecursiveGenericsForFieldLayoutLoad *pRecursiveFieldGenericHandling) const
{
    CONTRACT(TypeHandle)
    {
        INSTANCE_CHECK;
        if (FORBIDGC_LOADER_USE_ENABLED()) NOTHROW; else THROWS;
        MODE_ANY;
        if (FORBIDGC_LOADER_USE_ENABLED()) GC_NOTRIGGER; else GC_TRIGGERS;
        if (FORBIDGC_LOADER_USE_ENABLED()) FORBID_FAULT; else { INJECT_FAULT(COMPlusThrowOM()); }
        if (FORBIDGC_LOADER_USE_ENABLED() || fLoadTypes != ClassLoader::LoadTypes) { LOADS_TYPE(CLASS_LOAD_BEGIN); } else { LOADS_TYPE(level); }
        PRECONDITION(CheckPointer(pModule));
        PRECONDITION(level > CLASS_LOAD_BEGIN && level <= CLASS_LOADED);
        POSTCONDITION(CheckPointer(RETVAL, ((fLoadTypes == ClassLoader::LoadTypes) ? NULL_NOT_OK : NULL_OK)));
        SUPPORTS_DAC;
    }
    CONTRACT_END

    _ASSERTE(!pRecursiveFieldGenericHandling || dropGenericArgumentLevel); // pRecursiveFieldGenericHandling can only be set if dropGenericArgumentLevel is set
    if (pRecursiveFieldGenericHandling != NULL)
    {
        // if pRecursiveFieldGenericHandling is set, we must allow loading types
        _ASSERTE(fLoadTypes == ClassLoader::LoadTypes);
        // if pRecursiveFieldGenericHandling is set, then substitutions must not be enabled.
        _ASSERTE(pSubst == NULL);
        // FORBIDGC_LOADER_USE_ENABLED must not be enabled
        _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
        // Zap sig context must be NULL, as this can only happen in the type loader itself
        _ASSERTE(pZapSigContext == NULL);
        // Similarly with the pMTInterfaceMapOwner logic
        _ASSERTE(pMTInterfaceMapOwner == NULL);

        // This may throw an exception using the FullModule
        _ASSERTE(pModule->IsFullModule());
    }

    // We have an invariant that before we call a method, we must have loaded all of the valuetype parameters of that
    // method visible from the signature of the method. Normally we do this via type loading before the method is called
    // by walking the signature of the callee method at jit time, and loading all of the valuetype arguments at that time.
    // For NGEN, we record which valuetypes need to be loaded, and force load those types when the caller method is first executed.
    // However, in certain circumstances involving generics the jit does not have the opportunity to observe the complete method
    // signature that may be used a signature walk time. See example below.
    //
    //
//using System;
//
//struct A<T> { }
//struct B<T> { }
//
//interface Interface<T>
//{ A<T> InterfaceFunc(); }
//
//class Base<T>
//{ public virtual B<T> Func() { return default(B<T>); }  }
//
//class C<U,T> where U:Base<T>, Interface<T>
//{
//  public static void CallFunc(U u) { u.Func(); }
//  public static void CallInterfaceFunc(U u) { u.InterfaceFunc(); }
//}
//
//class Problem : Base<object>, Interface<object>
//{
//    public A<object> InterfaceFunc() { return new A<object>(); }
//    public override B<object> Func() { return new B<object>(); }
//}
//
//class Test
//{
//    static void Main()
//    {
//        C<Problem, object>.CallFunc(new Problem());
//        C<Problem, object>.CallInterfaceFunc(new Problem());
//    }
//}
//
    // In this example, when CallFunc and CallInterfaceFunc are jitted, the types that will
    // be loaded during JIT time are A<__Canon> and <__Canon>. Thus we need to be able to only
    // search for canonical type arguments during these restricted time periods. IsGCThread() || IsStackWalkerThread() is the current
    // predicate for determining this.

#ifdef _DEBUG
    if ((IsGCThread() || IsStackWalkerThread()) && (fLoadTypes == ClassLoader::LoadTypes))
    {
        // The callers are expected to pass the right arguments in
        _ASSERTE(level == CLASS_LOAD_APPROXPARENTS);
        _ASSERTE(dropGenericArgumentLevel == TRUE);
    }
#endif

    TypeHandle thRet;
    SigPointer     psig = *this;
    CorElementType typ = ELEMENT_TYPE_END;
    IfFailThrowBF(psig.GetElemType(&typ), BFA_BAD_SIGNATURE, pModule);

    if ((typ < ELEMENT_TYPE_MAX) &&
        (CorTypeInfo::IsPrimitiveType_NoThrow(typ) || (typ == ELEMENT_TYPE_STRING) || (typ == ELEMENT_TYPE_OBJECT)))
    {
        // case ELEMENT_TYPE_VOID     = 0x01,
        // case ELEMENT_TYPE_BOOLEAN  = 0x02,
        // case ELEMENT_TYPE_CHAR     = 0x03,
        // case ELEMENT_TYPE_I1       = 0x04,
        // case ELEMENT_TYPE_U1       = 0x05,
        // case ELEMENT_TYPE_I2       = 0x06,
        // case ELEMENT_TYPE_U2       = 0x07,
        // case ELEMENT_TYPE_I4       = 0x08,
        // case ELEMENT_TYPE_U4       = 0x09,
        // case ELEMENT_TYPE_I8       = 0x0a,
        // case ELEMENT_TYPE_U8       = 0x0b,
        // case ELEMENT_TYPE_R4       = 0x0c,
        // case ELEMENT_TYPE_R8       = 0x0d,
        // case ELEMENT_TYPE_I        = 0x18,
        // case ELEMENT_TYPE_U        = 0x19,
        //
        // case ELEMENT_TYPE_STRING   = 0x0e,
        // case ELEMENT_TYPE_OBJECT   = 0x1c,
        //
        thRet = TypeHandle(CoreLibBinder::GetElementType(typ));
    }
    else
    {
#ifdef _DEBUG_IMPL
        // This verifies that we won't try and load a type
        // if FORBIDGC_LOADER_USE_ENABLED is true.
        //
        // The FORBIDGC_LOADER_USE is limited to very specific scenarios that need to retrieve
        // GC_OTHER typehandles for size and gcroot information. This assert attempts to prevent
        // this abuse from proliferating.
        //
        if (FORBIDGC_LOADER_USE_ENABLED() && (fLoadTypes == ClassLoader::LoadTypes))
        {
            TypeHandle th = GetTypeHandleThrowing(pModule,
                                                  pTypeContext,
                                                  ClassLoader::DontLoadTypes,
                                                  level,
                                                  dropGenericArgumentLevel,
                                                  pSubst,
                                                  pZapSigContext);
            _ASSERTE(!th.IsNull());
        }
#endif
        //
        // pOrigModule is the original module that contained this ZapSig
        //
        ModuleBase * pOrigModule = (pZapSigContext != NULL) ? pZapSigContext->pInfoModule : pModule;

        ClassLoader::NotFoundAction  notFoundAction;
        CorInternalStates            tdTypes;

        switch((DWORD)typ) {
        case ELEMENT_TYPE_TYPEDBYREF:
        {
            thRet = TypeHandle(g_TypedReferenceMT);
            break;
        }

        case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG:
        {
#ifndef DACCESS_COMPILE
            TypeHandle baseType = psig.GetTypeHandleThrowing(pModule,
                                                             pTypeContext,
                                                             fLoadTypes,
                                                             level,
                                                             dropGenericArgumentLevel,
                                                             pSubst,
                                                             pZapSigContext);
            if (baseType.IsNull())
            {
                thRet = baseType;
            }
            else
            {
                thRet = ClassLoader::LoadNativeValueTypeThrowing(baseType, fLoadTypes, level);
            }
#else
            DacNotImpl();
            thRet = TypeHandle();
#endif
            break;
        }

        case ELEMENT_TYPE_CANON_ZAPSIG:
        {
#ifndef DACCESS_COMPILE
            assert(g_pCanonMethodTableClass != NULL);
            thRet = TypeHandle(g_pCanonMethodTableClass);
#else
            DacNotImpl();
            thRet = TypeHandle();
#endif
            break;
        }

        case ELEMENT_TYPE_MODULE_ZAPSIG:
        {
#ifndef DACCESS_COMPILE
            uint32_t ix;
            IfFailThrowBF(psig.GetData(&ix), BFA_BAD_SIGNATURE, pModule);
#ifdef FEATURE_MULTICOREJIT
            if (pZapSigContext->externalTokens == ZapSig::MulticoreJitTokens)
            {
                pModule = MulticoreJitManager::DecodeModuleFromIndex(pZapSigContext->pModuleContext, ix);
            }
            else
#endif
            {
                pModule = pZapSigContext->GetZapSigModule()->GetModuleFromIndex(ix);
            }

            if (pModule != NULL)
            {
                thRet = psig.GetTypeHandleThrowing(pModule,
                                                   pTypeContext,
                                                   fLoadTypes,
                                                   level,
                                                   dropGenericArgumentLevel,
                                                   pSubst,
                                                   pZapSigContext);
            }
            else
            {
                // For ReadyToRunCompilation we return a null TypeHandle when we reference a non-local module
                //
                thRet = TypeHandle();
            }
#else
            DacNotImpl();
            thRet = TypeHandle();
#endif
            break;
        }

        case ELEMENT_TYPE_VAR_ZAPSIG:
        {
#ifndef DACCESS_COMPILE
            RID rid;
            IfFailThrowBF(psig.GetData(&rid), BFA_BAD_SIGNATURE, pModule);

            mdGenericParam tkTyPar = TokenFromRid(rid, mdtGenericParam);

            if (!pModule->IsFullModule())
                THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pOrigModule);

            Module *pNormalModule = static_cast<Module*>(pModule);

            TypeVarTypeDesc *pTypeVarTypeDesc = pNormalModule->LookupGenericParam(tkTyPar);
            if (pTypeVarTypeDesc == NULL && (fLoadTypes == ClassLoader::LoadTypes))
            {
                mdToken tkOwner;
                IfFailThrow(pNormalModule->GetMDImport()->GetGenericParamProps(tkTyPar, NULL, NULL, &tkOwner, NULL, NULL));

                if (TypeFromToken(tkOwner) == mdtMethodDef)
                {
                    MemberLoader::GetMethodDescFromMethodDef(pNormalModule, tkOwner, FALSE);
                }
                else
                {
                    ClassLoader::LoadTypeDefThrowing(pNormalModule, tkOwner,
                        ClassLoader::ThrowIfNotFound,
                        ClassLoader::PermitUninstDefOrRef);
                }

                pTypeVarTypeDesc = pNormalModule->LookupGenericParam(tkTyPar);
                if (pTypeVarTypeDesc == NULL)
                {
                    THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pOrigModule);
                }
            }
            thRet = TypeHandle(pTypeVarTypeDesc);
#else
            DacNotImpl();
            thRet = TypeHandle();
#endif
            break;
        }

        case ELEMENT_TYPE_VAR:
        {
            if ((pSubst != NULL) && !pSubst->GetInst().IsNull())
            {
#ifdef _DEBUG_IMPL
                _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
#endif
                uint32_t index;
                IfFailThrow(psig.GetData(&index));

                SigPointer inst = pSubst->GetInst();
                for (uint32_t i = 0; i < index; i++)
                {
                    IfFailThrowBF(inst.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
                }

                thRet =  inst.GetTypeHandleThrowing(
                    pSubst->GetModule(),
                    pTypeContext,
                    fLoadTypes,
                    level,
                    dropGenericArgumentLevel,
                    pSubst->GetNext(),
                    pZapSigContext);
            }
            else
            {
                thRet = (psig.GetTypeVariableThrowing(pModule, typ, fLoadTypes, pTypeContext));
                if (fLoadTypes == ClassLoader::LoadTypes)
                    ClassLoader::EnsureLoaded(thRet, level);
            }
            break;
        }

        case ELEMENT_TYPE_MVAR:
        {
            thRet = (psig.GetTypeVariableThrowing(pModule, typ, fLoadTypes, pTypeContext));
            if (fLoadTypes == ClassLoader::LoadTypes)
                ClassLoader::EnsureLoaded(thRet, level);
            break;
        }

        case ELEMENT_TYPE_GENERICINST:
        {
            mdTypeDef tkGenericType = mdTypeDefNil;
            Module *pGenericTypeModule = NULL;

            // Before parsing the generic instantiation, determine if the signature tells us its module and token.
            // This is the common case, and when true we can avoid dereferencing the resulting TypeHandle to ask for them.
            bool typeAndModuleKnown = false;
            if (pZapSigContext && pZapSigContext->externalTokens == ZapSig::NormalTokens && psig.IsTypeDef(&tkGenericType))
            {
                typeAndModuleKnown = true;
                pGenericTypeModule = static_cast<Module*>(pModule);
            }

            TypeHandle genericType = psig.GetGenericInstType(pModule, fLoadTypes, level < CLASS_LOAD_APPROXPARENTS ? level : CLASS_LOAD_APPROXPARENTS, pZapSigContext);

            if (genericType.IsNull())
            {
                thRet = genericType;
                break;
            }

            if (!typeAndModuleKnown)
            {
                tkGenericType = genericType.GetCl();
                pGenericTypeModule = genericType.GetModule();
            }
            else
            {
                _ASSERTE(tkGenericType == genericType.GetCl());
                _ASSERTE(pGenericTypeModule == genericType.GetModule());
            }

            if (level == CLASS_LOAD_APPROXPARENTS && dropGenericArgumentLevel && genericType.IsInterface())
            {
                thRet = genericType;
                break;
            }

            // The number of type parameters follows
            uint32_t ntypars = 0;
            IfFailThrowBF(psig.GetData(&ntypars), BFA_BAD_SIGNATURE, pOrigModule);

            DWORD dwAllocaSize = 0;
            if (!ClrSafeInt<DWORD>::multiply(ntypars, sizeof(TypeHandle), dwAllocaSize))
                ThrowHR(COR_E_OVERFLOW);

            TypeHandle *thisinst = (TypeHandle*) _alloca(dwAllocaSize);

            bool handlingRecursiveGenericFieldScenario = false;
            SigPointer     psigCopy = psig;

            // For the recursive field handling system, we instantiate over __Canon first, then over Byte and if the
            // types end up with the same GC layout, we can use the __Canon variant to replace instantiations over the specified type
            for (int iRecursiveGenericFieldHandlingPass = 0; handlingRecursiveGenericFieldScenario || iRecursiveGenericFieldHandlingPass == 0 ; iRecursiveGenericFieldHandlingPass++)
            {
                // Finally we gather up the type arguments themselves, loading at the level specified for generic arguments
                for (unsigned i = 0; i < ntypars; i++)
                {
                    ClassLoadLevel argLevel = level;
                    TypeHandle typeHnd = TypeHandle();
                    BOOL argDrop = FALSE;

                    if (dropGenericArgumentLevel)
                    {
                        if (level == CLASS_LOAD_APPROXPARENTS)
                        {
                            SigPointer tempsig = psig;
                            bool checkTokenForRecursion = false;

                            CorElementType elemType = ELEMENT_TYPE_END;
                            IfFailThrowBF(tempsig.GetElemType(&elemType), BFA_BAD_SIGNATURE, pOrigModule);

                            if (elemType == (CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG)
                            {
                                // Skip over the module index
                                IfFailThrowBF(tempsig.GetData(NULL), BFA_BAD_SIGNATURE, pModule);
                                // Read the next elemType
                                IfFailThrowBF(tempsig.GetElemType(&elemType), BFA_BAD_SIGNATURE, pModule);
                            }

                            if (elemType == ELEMENT_TYPE_GENERICINST)
                            {
                                CorElementType tmpEType = ELEMENT_TYPE_END;
                                IfFailThrowBF(tempsig.GetElemType(&tmpEType), BFA_BAD_SIGNATURE, pOrigModule);

                                if (tmpEType == ELEMENT_TYPE_CLASS)
                                    typeHnd = TypeHandle(g_pCanonMethodTableClass);
                                else if ((pRecursiveFieldGenericHandling != NULL) && (tmpEType == ELEMENT_TYPE_VALUETYPE))
                                    checkTokenForRecursion = true;
                            }
                            else if ((elemType == (CorElementType)ELEMENT_TYPE_CANON_ZAPSIG) ||
                                    (CorTypeInfo::GetGCType_NoThrow(elemType) == TYPE_GC_REF))
                            {
                                typeHnd = TypeHandle(g_pCanonMethodTableClass);
                            }
                            else if ((elemType == ELEMENT_TYPE_VALUETYPE) && (pRecursiveFieldGenericHandling != NULL))
                            {
                                checkTokenForRecursion = true;
                            }

                            if (checkTokenForRecursion)
                            {
                                mdToken valueTypeToken = mdTypeDefNil;
                                IfFailThrowBF(tempsig.GetToken(&valueTypeToken), BFA_BAD_SIGNATURE, pOrigModule);
                                if (valueTypeToken == pRecursiveFieldGenericHandling->tkTypeDefToAvoidIfPossible && pOrigModule == pRecursiveFieldGenericHandling->pModuleWithTokenToAvoidIfPossible)
                                {
                                    bool exactSelfRecursionDetected = true;

                                    if (elemType == ELEMENT_TYPE_GENERICINST)
                                    {
                                        // Check to ensure that the type variables in use are for an exact self-referential generic.
                                        // Other cases are possible, but this logic is scoped to exactly self-referential generics.
                                        uint32_t instantiationCount;
                                        IfFailThrowBF(tempsig.GetData(&instantiationCount), BFA_BAD_SIGNATURE, pModule);
                                        for (uint32_t iInstantiation = 0; iInstantiation < instantiationCount; iInstantiation++)
                                        {
                                            IfFailThrowBF(tempsig.GetElemType(&elemType), BFA_BAD_SIGNATURE, pOrigModule);
                                            if (elemType != ELEMENT_TYPE_VAR)
                                            {
                                                exactSelfRecursionDetected = false;
                                                break;
                                            }

                                            uint32_t varIndex;
                                            IfFailThrowBF(tempsig.GetData(&varIndex), BFA_BAD_SIGNATURE, pModule);
                                            if (varIndex != iInstantiation)
                                            {
                                                exactSelfRecursionDetected = false;
                                                break;
                                            }
                                        }
                                    }
                                    if (exactSelfRecursionDetected)
                                    {
                                        handlingRecursiveGenericFieldScenario = true;
                                        if (iRecursiveGenericFieldHandlingPass == 0)
                                        {
                                            typeHnd = TypeHandle(g_pCanonMethodTableClass);
                                        }
                                        else
                                        {
                                            typeHnd = TypeHandle(CoreLibBinder::GetClass(CLASS__BYTE));
                                        }
                                    }
                                }
                            }
                            argDrop = TRUE;
                        }
                        else
                        // We need to make sure that typekey is always restored. Otherwise, we may run into unrestored typehandles while using
                        // the typekey for lookups. It is safe to not drop the levels for initial NGen-specific loading levels since there cannot
                        // be cycles in typekeys.
                        if (level > CLASS_LOAD_APPROXPARENTS)
                        {
                            argLevel = (ClassLoadLevel) (level-1);
                        }
                    }

                    if (typeHnd.IsNull())
                    {
                        typeHnd = psig.GetTypeHandleThrowing(pOrigModule,
                                                            pTypeContext,
                                                            fLoadTypes,
                                                            argLevel,
                                                            argDrop,
                                                            pSubst,
                                                            pZapSigContext,
                                                            NULL,
                                                            pRecursiveFieldGenericHandling);
                        if (typeHnd.IsNull())
                        {
                            // Indicate failure by setting thisinst to NULL
                            thisinst = NULL;
                            break;
                        }

                        if (dropGenericArgumentLevel && level == CLASS_LOAD_APPROXPARENTS)
                        {
                            typeHnd = ClassLoader::CanonicalizeGenericArg(typeHnd);
                        }
                    }
                    thisinst[i] = typeHnd;
                    IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
                }

                // If we failed to get all of the instantiation type arguments then we return the null type handle
                if (thisinst == NULL)
                {
                    thRet = TypeHandle();
                    break;
                }

                Instantiation genericLoadInst(thisinst, ntypars);

                if (pMTInterfaceMapOwner != NULL && genericLoadInst.ContainsAllOneType(pMTInterfaceMapOwner))
                {
                    thRet = ClassLoader::LoadTypeDefThrowing(pGenericTypeModule, tkGenericType, ClassLoader::ThrowIfNotFound, ClassLoader::PermitUninstDefOrRef, 0, level);
                }
                else
                {
                    // Group together the current signature type context and substitution chain, which
                    // we may later use to instantiate constraints of type arguments that turn out to be
                    // typespecs, i.e. generic types.
                    InstantiationContext instContext(pTypeContext, pSubst);

                    // Now make the instantiated type
                    // The class loader will check the arity
                    // When we know it was correctly computed at NGen time, we ask the class loader to skip that check.
                    TypeHandle thFound = (ClassLoader::LoadGenericInstantiationThrowing(pGenericTypeModule,
                                                                        tkGenericType,
                                                                        genericLoadInst,
                                                                        fLoadTypes, level,
                                                                        &instContext,
                                                                        pZapSigContext && pZapSigContext->externalTokens == ZapSig::NormalTokens));

                    if (!handlingRecursiveGenericFieldScenario)
                    {
                        thRet = thFound;
                        break;
                    }
                    else
                    {
                        if (iRecursiveGenericFieldHandlingPass == 0)
                        {
                            // This is the instantiation over __Canon if we succeed with finding out if the recursion does not affect type layout, we will return this type.
                            thRet = thFound;
                            // Restart with the same sig as we had for the first pass
                            psig = psigCopy;

                        }
                        else
                        {
                            // At this point thFound is the instantiation over Byte and thRet is set to the instantiation over __Canon.
                            // If the two have the same GC layout, then the field layout is not affected by the type parameters, and the type load can continue
                            // with just using the __Canon variant.
                            // To simplify the calculation, all we really need to compute is the number of GC pointers in the representation and the Base size.
                            // For if the type parameter is used in field layout, there will be at least 1 more pointer in the __Canon instantiation as compared to the Byte instantiation.

                            SIZE_T objectSizeCanonInstantiation = thRet.AsMethodTable()->GetBaseSize();
                            SIZE_T objectSizeByteInstantion = thFound.AsMethodTable()->GetBaseSize();

                            bool failedLayoutCompare = objectSizeCanonInstantiation != objectSizeByteInstantion;
                            if (!failedLayoutCompare)
                            {
#ifndef DACCESS_COMPILE
                                failedLayoutCompare = CGCDesc::GetNumPointers(thRet.AsMethodTable(), objectSizeCanonInstantiation, 0) !=
                                                      CGCDesc::GetNumPointers(thFound.AsMethodTable(), objectSizeCanonInstantiation, 0);
#else
                                DacNotImpl();
#endif
                            }

                            if (failedLayoutCompare)
                            {
#ifndef DACCESS_COMPILE
                                static_cast<Module*>(pOrigModule)->ThrowTypeLoadException(pOrigModule->GetMDImport(), pRecursiveFieldGenericHandling->tkTypeDefToAvoidIfPossible, IDS_INVALID_RECURSIVE_GENERIC_FIELD_LOAD);
#else
                                DacNotImpl();
#endif
                            }

                            // Runtime successfully found a type with the desired layout, return
                            break;
                        }
                    }
                }
            }
            break;
        }

        case ELEMENT_TYPE_CLASS:
            // intentional fallthru to ELEMENT_TYPE_VALUETYPE
        case ELEMENT_TYPE_VALUETYPE:
        {
            mdTypeRef typeToken = 0;

            IfFailThrowBF(psig.GetToken(&typeToken), BFA_BAD_SIGNATURE, pOrigModule);

            if ((TypeFromToken(typeToken) != mdtTypeRef) && (TypeFromToken(typeToken) != mdtTypeDef))
                THROW_BAD_FORMAT(BFA_UNEXPECTED_TOKEN_AFTER_CLASSVALTYPE, pOrigModule);

            if (IsNilToken(typeToken))
                THROW_BAD_FORMAT(BFA_UNEXPECTED_TOKEN_AFTER_CLASSVALTYPE, pOrigModule);

            if (fLoadTypes == ClassLoader::LoadTypes)
            {
                notFoundAction = ClassLoader::ThrowButNullV11McppWorkaround;
                tdTypes = tdNoTypes;
            }
            else
            {
                notFoundAction = ClassLoader::ReturnNullIfNotFound;
                tdTypes = tdAllTypes;
            }

            TypeHandle loadedType =
                ClassLoader::LoadTypeDefOrRefThrowing(pModule,
                                                      typeToken,
                                                      notFoundAction,
                                                      // pZapSigContext is only set when decoding zapsigs
                                                      // ZapSigs use uninstantiated tokens to represent the GenericTypeDefinition
                                                      (pZapSigContext ? ClassLoader::PermitUninstDefOrRef : ClassLoader::FailIfUninstDefOrRef),
                                                      tdTypes,
                                                      level);

            // Everett C++ compiler can generate a TypeRef with RS=0 without respective TypeDef for unmanaged valuetypes,
            // referenced only by pointers to them. For this case we treat this as an ELEMENT_TYPE_VOID, and perform the
            // same operations as the appropriate case block above.
            if (loadedType.IsNull())
            {
                if (TypeFromToken(typeToken) == mdtTypeRef)
                {
                    loadedType = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_VOID));
                    thRet = loadedType;
                    break;
                }
            }

#ifndef DACCESS_COMPILE
            //
            // Check that the type that we loaded matches the signature
            //   with regards to ET_CLASS and ET_VALUETYPE
            //
            if (fLoadTypes == ClassLoader::LoadTypes)
            {
                // Skip this check when using zap sigs; it should have been correctly computed at NGen time
                // and a change from one to the other would have invalidated the image.
                if (pZapSigContext == NULL || pZapSigContext->externalTokens != ZapSig::NormalTokens)
                {
                    bool typFromSigIsClass = (typ == ELEMENT_TYPE_CLASS);
                    bool typLoadedIsClass  = (loadedType.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS);

                    if (typFromSigIsClass != typLoadedIsClass)
                    {
                        if (pModule->GetMDImport()->GetMetadataStreamVersion() != MD_STREAM_VER_1X)
                        {
                            pOrigModule->ThrowTypeLoadException(pModule->GetMDImport(),
                                                                typeToken,
                                                                BFA_CLASSLOAD_VALUETYPEMISMATCH);
                        }
                    }
                }

                // Assert that our reasoning above was valid (that there is never a zapsig that gets this wrong)
                _ASSERTE(((typ == ELEMENT_TYPE_CLASS) == (loadedType.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS)) ||
                          pZapSigContext == NULL || pZapSigContext->externalTokens != ZapSig::NormalTokens);

            }
#endif // #ifndef DACCESS_COMPILE

            thRet = loadedType;
            break;
        }

        case ELEMENT_TYPE_ARRAY:
        case ELEMENT_TYPE_SZARRAY:
        {
            TypeHandle elemType = psig.GetTypeHandleThrowing(pModule,
                                                             pTypeContext,
                                                             fLoadTypes,
                                                             level,
                                                             dropGenericArgumentLevel,
                                                             pSubst,
                                                             pZapSigContext);
            if (elemType.IsNull())
            {
                thRet = elemType;
                break;
            }

            uint32_t rank = 0;
            if (typ == ELEMENT_TYPE_ARRAY) {
                IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
                IfFailThrowBF(psig.GetData(&rank), BFA_BAD_SIGNATURE, pOrigModule);

                _ASSERTE(0 < rank);
            }
            thRet = ClassLoader::LoadArrayTypeThrowing(elemType, typ, rank, fLoadTypes, level);
            break;
        }

        case ELEMENT_TYPE_PINNED:
            // Return what follows
            thRet = psig.GetTypeHandleThrowing(pModule,
                                               pTypeContext,
                                               fLoadTypes,
                                               level,
                                               dropGenericArgumentLevel,
                                               pSubst,
                                               pZapSigContext);
            break;

        case ELEMENT_TYPE_BYREF:
        case ELEMENT_TYPE_PTR:
        {
            TypeHandle baseType = psig.GetTypeHandleThrowing(pModule,
                                                             pTypeContext,
                                                             fLoadTypes,
                                                             level,
                                                             dropGenericArgumentLevel,
                                                             pSubst,
                                                             pZapSigContext);
            if (baseType.IsNull())
            {
                thRet = baseType;
            }
            else
            {
                thRet = ClassLoader::LoadPointerOrByrefTypeThrowing(typ, baseType, fLoadTypes, level);
            }
            break;
        }

        case ELEMENT_TYPE_FNPTR:
        {
#ifndef DACCESS_COMPILE
            uint32_t uCallConv = 0;
            IfFailThrowBF(psig.GetData(&uCallConv), BFA_BAD_SIGNATURE, pOrigModule);

            if ((uCallConv & IMAGE_CEE_CS_CALLCONV_MASK) == IMAGE_CEE_CS_CALLCONV_FIELD)
                THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_A_FIELD, pOrigModule);

            if ((uCallConv & IMAGE_CEE_CS_CALLCONV_GENERIC) > 0)
                THROW_BAD_FORMAT(BFA_FNPTR_CANNOT_BE_GENERIC, pOrigModule);

            // Get the arg count.
            uint32_t cArgs = 0;
            IfFailThrowBF(psig.GetData(&cArgs), BFA_BAD_SIGNATURE, pOrigModule);

            uint32_t cAllocaSize;
            if (!ClrSafeInt<uint32_t>::addition(cArgs, 1, cAllocaSize) ||
                !ClrSafeInt<uint32_t>::multiply(cAllocaSize, sizeof(TypeHandle), cAllocaSize))
            {
                ThrowHR(COR_E_OVERFLOW);
            }

            TypeHandle *retAndArgTypes = (TypeHandle*) _alloca(cAllocaSize);
            bool fReturnTypeOrParameterNotLoaded = false;

            for (uint32_t i = 0; i <= cArgs; i++)
            {
                // Lookup type handle.
                retAndArgTypes[i] = psig.GetTypeHandleThrowing(pOrigModule,
                                                               pTypeContext,
                                                               fLoadTypes,
                                                               level,
                                                               dropGenericArgumentLevel,
                                                               pSubst,
                                                               pZapSigContext);

                if (retAndArgTypes[i].IsNull())
                {
                    thRet = TypeHandle();
                    fReturnTypeOrParameterNotLoaded = true;
                    break;
                }

                IfFailThrowBF(psig.SkipExactlyOne(), BFA_BAD_SIGNATURE, pOrigModule);
            }

            if (fReturnTypeOrParameterNotLoaded)
            {
                break;
            }

            uCallConv = NormalizeFnPtrCallingConvention(uCallConv);

            // Find an existing function pointer or make a new one
            thRet = ClassLoader::LoadFnptrTypeThrowing((BYTE) uCallConv, cArgs, retAndArgTypes, fLoadTypes, level);
#else
            // Function pointers are interpreted as IntPtr to the debugger.
            thRet = TypeHandle(CoreLibBinder::GetElementType(ELEMENT_TYPE_I));
#endif
            break;
        }

        case ELEMENT_TYPE_INTERNAL :
            {
                TypeHandle hType;
                // this check is not functional in DAC and provides no security against a malicious dump
                // the DAC is prepared to receive an invalid type handle
#ifndef DACCESS_COMPILE
                if (pModule->IsSigInIL(m_ptr))
                    THROW_BAD_FORMAT(BFA_BAD_SIGNATURE, pModule);
#endif
                CorSigUncompressPointer(psig.GetPtr(), (void**)&hType);
                thRet = hType;
                break;
            }

        case ELEMENT_TYPE_SENTINEL:
            {
#ifndef DACCESS_COMPILE

                mdToken token = 0;

                IfFailThrowBF(psig.GetToken(&token), BFA_BAD_SIGNATURE, pOrigModule);

                pOrigModule->ThrowTypeLoadException(pModule->GetMDImport(),
                                                    token,
                                                    IDS_CLASSLOAD_GENERAL);
#else
                DacNotImpl();
                break;
#endif // #ifndef DACCESS_COMPILE
            }

            default:
#ifdef _DEBUG_IMPL
                _ASSERTE(!FORBIDGC_LOADER_USE_ENABLED());
#endif
                THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pOrigModule);
    }

    }

    RETURN thRet;
}