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;
}