1
0
Fork 0
mirror of https://github.com/VSadov/Satori.git synced 2025-06-09 17:44:48 +09:00
Satori/src/coreclr/src/vm/zapsig.cpp
Tomáš Rylek 0c610c5de7
Runtime composite support, 2nd attempt (fixing DAC) (#33304)
[2nd attempt after the initial version was rolled back]

This change changes CoreCLR runtime to support running
composite R2R apps with standalone MSIL produced by
Crossgen2. It introduces the new concept of a NativeImage
representing the composite R2R with native executable header
and adds basic support for loading these native images
upon loading the original MSIL assemblies and for using
the R2R code information therein as the native code cache
for the component MSIL assemblies.

Thanks

Tomas
2020-03-07 01:59:23 +01:00

1753 lines
60 KiB
C++

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
// File: zapsig.cpp
//
// Signature encoding for zapper (ngen)
//
// ===========================================================================
#include "common.h"
#include "zapsig.h"
#include "typedesc.h"
#include "compile.h"
#include "sigbuilder.h"
#include "nativeimage.h"
#ifndef DACCESS_COMPILE
BOOL ZapSig::GetSignatureForTypeDesc(TypeDesc * desc, SigBuilder * pSigBuilder)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
}
CONTRACTL_END
CorElementType elemType = desc->GetInternalCorElementType();
if (elemType == ELEMENT_TYPE_VALUETYPE)
{
// convert to ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG so that the right
// thing will happen in code:SigPointer.GetTypeHandleThrowing
elemType = (CorElementType) ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG;
}
else if (elemType == ELEMENT_TYPE_VAR || elemType == ELEMENT_TYPE_MVAR)
{
// Enable encoding of type variables for NGen signature only. IBC toolchain is not aware of them yet.
if (context.externalTokens == ZapSig::NormalTokens)
elemType = (CorElementType) ELEMENT_TYPE_VAR_ZAPSIG;
}
pSigBuilder->AppendElementType(elemType);
if (desc->HasTypeParam())
{
if (!this->GetSignatureForTypeHandle(desc->GetTypeParam(), pSigBuilder))
return FALSE;
}
else
{
switch ((DWORD)elemType)
{
case ELEMENT_TYPE_FNPTR:
{
FnPtrTypeDesc *pTD = dac_cast<PTR_FnPtrTypeDesc>(desc);
// Emit calling convention
pSigBuilder->AppendByte(pTD->GetCallConv());
// number of args
unsigned numArgs = pTD->GetNumArgs();
pSigBuilder->AppendData(numArgs);
// return type and args
TypeHandle *retAndArgTypes = pTD->GetRetAndArgTypesPointer();
for (DWORD i = 0; i <= numArgs; i++)
{
TypeHandle th = retAndArgTypes[i];
// This should be a consequence of the type key being restored
CONSISTENCY_CHECK(!th.IsNull() && !th.IsEncodedFixup());
if (!this->GetSignatureForTypeHandle(th, pSigBuilder))
return FALSE;
}
}
break;
case ELEMENT_TYPE_MVAR:
// _ASSERTE(!"Cannot encode ET_MVAR in a ZapSig");
return FALSE;
case ELEMENT_TYPE_VAR:
// _ASSERTE(!"Cannot encode ET_VAR in a ZapSig");
return FALSE;
case ELEMENT_TYPE_VAR_ZAPSIG:
{
TypeVarTypeDesc * pTypeVarDesc = dac_cast<PTR_TypeVarTypeDesc>(desc);
Module * pVarTypeModule = pTypeVarDesc->GetModule();
if (pVarTypeModule != this->context.pInfoModule)
{
DWORD index = (*this->pfnEncodeModule)(this->context.pModuleContext, pVarTypeModule);
if (index == ENCODE_MODULE_FAILED)
return FALSE;
// emit the ET_MODULE_ZAPSIG escape
pSigBuilder->AppendElementType((CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG);
// emit the module index
pSigBuilder->AppendData(index);
}
pSigBuilder->AppendData(RidFromToken(pTypeVarDesc->GetToken()));
break;
}
default:
_ASSERTE(!"Bad type");
return FALSE;
}
}
return TRUE;
}
// Create a signature for a typeHandle
// It can be decoded using MetaSig::GetTypeHandleThrowing
// The tokens are espressed relative to this->pInfoModule
// When handle.GetModule() != this->pInfoModule), we escape the signature
// with an ELEMENT_TYPE_MODULE_ZAPSIG <id-num> <token> to encode
// a temporary change of module
//
// Returns the number of characters written into the buffer.
// If buffer and bufferMax are NULL, it returns the number of
// characters that would have been written.
// If the buffer isn't big enough it doesn't write past bufferMax
// A return value of 0 indidates a failure to encode the signature
//
BOOL ZapSig::GetSignatureForTypeHandle(TypeHandle handle,
SigBuilder * pSigBuilder)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
PRECONDITION(CheckPointer(handle));
PRECONDITION(CheckPointer(this->context.pInfoModule));
PRECONDITION(!handle.HasUnrestoredTypeKey());
MODE_ANY;
}
CONTRACTL_END
if (handle.IsTypeDesc())
return GetSignatureForTypeDesc(handle.AsTypeDesc(), pSigBuilder);
MethodTable *pMT = handle.AsMethodTable();
// Can we encode the type using a short ET encoding?
//
CorElementType elemType = TryEncodeUsingShortcut(pMT);
if (elemType != ELEMENT_TYPE_END)
{
_ASSERTE(pMT->IsTypicalTypeDefinition());
// Check for an array type and encode that we are dealing with a MethodTable representation
if (elemType == ELEMENT_TYPE_SZARRAY || elemType == ELEMENT_TYPE_ARRAY)
{
pSigBuilder->AppendElementType(elemType);
TypeHandle elementType = pMT->GetArrayElementTypeHandle();
if (!this->GetSignatureForTypeHandle(elementType, pSigBuilder))
return FALSE;
if (elemType == ELEMENT_TYPE_ARRAY)
{
pSigBuilder->AppendData(pMT->GetRank());
pSigBuilder->AppendData(0);
pSigBuilder->AppendData(0);
}
}
else
{
pSigBuilder->AppendElementType(elemType);
}
return TRUE;
}
// We could not encode the type using a short encoding
// and we have a handle that represents a Class or ValueType
// We may need to emit an out-of-module escape sequence
//
Module *pTypeHandleModule = pMT->GetModule_NoLogging();
// If the type handle's module is different that the this->pInfoModule
// we will need to add an out-of-module escape for the type
//
DWORD index = 0;
mdToken token = pMT->GetCl_NoLogging();
#ifdef FEATURE_NATIVE_IMAGE_GENERATION
if (pTypeHandleModule != this->context.pInfoModule && !pTypeHandleModule->IsInCurrentVersionBubble())
{
pTypeHandleModule = GetAppDomain()->ToCompilationDomain()->GetTargetModule();
token = pTypeHandleModule->LookupTypeRefByMethodTable(pMT);
}
#endif
if (pTypeHandleModule != this->context.pInfoModule)
{
// During IBC profiling this calls
// code:Module.EncodeModuleHelper
// During ngen this calls
// code:ZapImportTable.EncodeModuleHelper)
//
index = (*this->pfnEncodeModule)(this->context.pModuleContext, pTypeHandleModule);
if (index == ENCODE_MODULE_FAILED)
return FALSE;
// emit the ET_MODULE_ZAPSIG escape
pSigBuilder->AppendElementType((CorElementType) ELEMENT_TYPE_MODULE_ZAPSIG);
// emit the module index
pSigBuilder->AppendData(index);
}
// Remember if we have an instantiated generic type
bool fNeedsInstantiation = pMT->HasInstantiation() && !pMT->IsGenericTypeDefinition();
// We possibly have an instantiated generic type
if (fNeedsInstantiation)
{
pSigBuilder->AppendElementType(ELEMENT_TYPE_GENERICINST);
}
// Beware of enums! Can't use GetInternalCorElementType() here.
pSigBuilder->AppendElementType(pMT->IsValueType() ? ELEMENT_TYPE_VALUETYPE : ELEMENT_TYPE_CLASS);
_ASSERTE(!IsNilToken(token));
if (IsNilToken(token))
return FALSE;
if ((index != 0) && (this->pfnTokenDefinition != NULL))
{
//
// We do not want to log the metadata lookups that we perform here
//
IBCLoggingDisabler disableLogging;
// During IBC profiling this calls
// code:Module::TokenDefinitionHelper
(*this->pfnTokenDefinition)(this->context.pModuleContext, pTypeHandleModule, index, &token);
// ibcExternalType tokens are actually encoded as mdtTypeDef tokens in the signature
_ASSERT(TypeFromToken(token) == ibcExternalType);
token = TokenFromRid(RidFromToken(token), mdtTypeDef);
}
pSigBuilder->AppendToken(token);
if (fNeedsInstantiation)
{
pSigBuilder->AppendData(pMT->GetNumGenericArgs());
Instantiation inst = pMT->GetInstantiation();
for (DWORD i = 0; i < inst.GetNumArgs(); i++)
{
TypeHandle t = inst[i];
CONSISTENCY_CHECK(!t.IsNull() && !t.IsEncodedFixup());
if (!this->GetSignatureForTypeHandle(t, pSigBuilder))
return FALSE;
}
}
return TRUE;
}
#endif // #ifndef DACCESS_COMPILE
//
// Returns element type when the typeHandle can be encoded using
// using a single CorElementType value
// This includes using ELEMENT_TYPE_CANON_ZAPSIG for the System.__Canon type
//
/*static */ CorElementType ZapSig::TryEncodeUsingShortcut(/* in */ MethodTable * pMT)
{
LIMITED_METHOD_CONTRACT;
CorElementType elemType = ELEMENT_TYPE_END; // An illegal value that we check for later
// Set elemType to a shortcut encoding whenever possible
//
if (pMT->IsTruePrimitive())
elemType = pMT->GetInternalCorElementType();
else if (pMT == g_pObjectClass)
elemType = ELEMENT_TYPE_OBJECT;
else if (pMT == g_pStringClass)
elemType = ELEMENT_TYPE_STRING;
else if (pMT == g_pCanonMethodTableClass)
elemType = (CorElementType) ELEMENT_TYPE_CANON_ZAPSIG;
else if (pMT->IsArray())
elemType = pMT->GetInternalCorElementType(); // either ELEMENT_TYPE_SZARRAY or ELEMENT_TYPE_ARRAY
return elemType;
}
//
// Compare a metadata signature element with a type handle
// The type handle must have a fully restored type key, which in turn means that modules for all of its
// components are loaded (e.g. type arguments to an instantiated type).
//
// Hence we can do the signature comparison without incurring any loads or restores.
//
/*static*/ BOOL ZapSig::CompareSignatureToTypeHandle(PCCOR_SIGNATURE pSig,
Module* pModule,
TypeHandle handle,
const ZapSig::Context * pZapSigContext)
{
CONTRACT(BOOL)
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
FORBID_FAULT;
PRECONDITION(CheckPointer(pModule));
PRECONDITION(CheckPointer(pZapSigContext));
PRECONDITION(CheckPointer(pZapSigContext->pModuleContext));
PRECONDITION(CheckPointer(pZapSigContext->pInfoModule));
PRECONDITION(CheckPointer(handle));
PRECONDITION(CheckPointer(pSig));
PRECONDITION(!handle.HasUnrestoredTypeKey());
}
CONTRACT_END
mdToken tk;
//
// pOrigModule is the original module that contained this ZapSig
//
Module * pOrigModule = pZapSigContext->pInfoModule;
CorElementType sigType = CorSigUncompressElementType(pSig);
CorElementType handleType = handle.GetSignatureCorElementType();
switch ((DWORD)sigType)
{
default:
{
// Unknown type!
_ASSERTE(!"Unknown type in ZapSig::CompareSignatureToTypeHandle");
RETURN(FALSE);
}
case ELEMENT_TYPE_MODULE_ZAPSIG:
{
DWORD ix = CorSigUncompressData(pSig);
CONTRACT_VIOLATION(ThrowsViolation|GCViolation);
pModule = pZapSigContext->GetZapSigModule()->GetModuleFromIndexIfLoaded(ix);
if (pModule == NULL)
RETURN FALSE;
else
RETURN(CompareSignatureToTypeHandle(pSig, pModule, handle, pZapSigContext));
}
case ELEMENT_TYPE_U:
case ELEMENT_TYPE_I:
case ELEMENT_TYPE_VOID:
case ELEMENT_TYPE_I1:
case ELEMENT_TYPE_U1:
case ELEMENT_TYPE_I2:
case ELEMENT_TYPE_U2:
case ELEMENT_TYPE_I4:
case ELEMENT_TYPE_U4:
case ELEMENT_TYPE_I8:
case ELEMENT_TYPE_U8:
case ELEMENT_TYPE_R4:
case ELEMENT_TYPE_R8:
case ELEMENT_TYPE_BOOLEAN:
case ELEMENT_TYPE_CHAR:
case ELEMENT_TYPE_TYPEDBYREF:
RETURN(sigType == handleType);
case ELEMENT_TYPE_STRING:
RETURN(handle == TypeHandle(g_pStringClass));
case ELEMENT_TYPE_OBJECT:
RETURN(handle == TypeHandle(g_pObjectClass));
case ELEMENT_TYPE_CANON_ZAPSIG:
RETURN(handle == TypeHandle(g_pCanonMethodTableClass));
case ELEMENT_TYPE_VAR:
case ELEMENT_TYPE_MVAR:
{
if (sigType != handleType)
RETURN(FALSE);
unsigned varNum = CorSigUncompressData(pSig);
RETURN(varNum == (dac_cast<PTR_TypeVarTypeDesc>(handle.AsTypeDesc())->GetIndex()));
}
case ELEMENT_TYPE_VAR_ZAPSIG:
{
if (!handle.IsGenericVariable())
RETURN(FALSE);
TypeVarTypeDesc *pTypeVarTypeDesc = handle.AsGenericVariable();
unsigned rid = CorSigUncompressData(pSig);
RETURN(TokenFromRid(rid, mdtGenericParam) == pTypeVarTypeDesc->GetToken() && pModule == pTypeVarTypeDesc->GetModule());
}
// These take an additional argument, which is the element type
case ELEMENT_TYPE_SZARRAY:
case ELEMENT_TYPE_PTR:
case ELEMENT_TYPE_BYREF:
{
if (sigType != handleType)
RETURN(FALSE);
RETURN (CompareSignatureToTypeHandle(pSig, pModule, handle.GetTypeParam(), pZapSigContext));
}
case ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG:
{
sigType = CorSigUncompressElementType(pSig);
_ASSERTE(sigType == ELEMENT_TYPE_VALUETYPE);
if (!handle.IsNativeValueType()) RETURN(FALSE);
} // fall-through
case ELEMENT_TYPE_VALUETYPE:
case ELEMENT_TYPE_CLASS:
{
CorSigUncompressToken(pSig, &tk);
if (TypeFromToken(tk) == mdtTypeRef)
{
BOOL resolved = FALSE;
EX_TRY
{
ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
resolved = ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pModule, &tk, Loader::DontLoad);
}
EX_CATCH
{
}
EX_END_CATCH(SwallowAllExceptions);
if (!resolved)
RETURN(FALSE);
}
_ASSERTE(TypeFromToken(tk) == mdtTypeDef);
RETURN (sigType == handleType && !handle.HasInstantiation() && pModule == handle.GetModule() && handle.GetCl() == tk);
}
case ELEMENT_TYPE_FNPTR:
{
if (sigType != handleType)
RETURN(FALSE);
FnPtrTypeDesc *pTD = handle.AsFnPtrType();
DWORD callConv = CorSigUncompressData(pSig);
if (callConv != pTD->GetCallConv())
RETURN(FALSE);
DWORD numArgs = CorSigUncompressData(pSig);
if (numArgs != pTD->GetNumArgs())
RETURN(FALSE);
{
CONTRACT_VIOLATION(ThrowsViolation|GCViolation);
for (DWORD i = 0; i <= numArgs; i++)
{
SigPointer sp(pSig);
if (!CompareSignatureToTypeHandle(pSig, pOrigModule, pTD->GetRetAndArgTypes()[i], pZapSigContext))
RETURN(FALSE);
if (FAILED(sp.SkipExactlyOne()))
{
RETURN(FALSE);
}
pSig = sp.GetPtr();
}
}
break;
}
case ELEMENT_TYPE_GENERICINST:
{
if (!handle.HasInstantiation())
RETURN(FALSE);
sigType = CorSigUncompressElementType(pSig);
if (sigType != handleType)
RETURN(FALSE);
pSig += CorSigUncompressToken(pSig, &tk);
if (TypeFromToken(tk) == mdtTypeRef)
{
BOOL resolved = FALSE;
EX_TRY
{
ENABLE_FORBID_GC_LOADER_USE_IN_THIS_SCOPE();
resolved = ClassLoader::ResolveTokenToTypeDefThrowing(pModule, tk, &pModule, &tk, Loader::DontLoad);
}
EX_CATCH
{
}
EX_END_CATCH(SwallowAllExceptions);
if (!resolved)
RETURN(FALSE);
}
_ASSERTE(TypeFromToken(tk) == mdtTypeDef);
if (pModule != handle.GetModule() || tk != handle.GetCl())
RETURN(FALSE);
DWORD numGenericArgs = CorSigUncompressData(pSig);
if (numGenericArgs != handle.GetNumGenericArgs())
RETURN(FALSE);
Instantiation inst = handle.GetInstantiation();
for (DWORD i = 0; i < inst.GetNumArgs(); i++)
{
SigPointer sp(pSig);
if (!CompareSignatureToTypeHandle(pSig, pOrigModule, inst[i], pZapSigContext))
RETURN(FALSE);
if (FAILED(sp.SkipExactlyOne()))
{
RETURN(FALSE);
}
pSig = sp.GetPtr();
}
break;
}
case ELEMENT_TYPE_ARRAY:
{
if (sigType != handleType)
RETURN(FALSE);
if (!CompareSignatureToTypeHandle(pSig, pModule, handle.GetArrayElementTypeHandle(), pZapSigContext))
RETURN(FALSE);
SigPointer sp(pSig);
if (FAILED(sp.SkipExactlyOne()))
RETURN(FALSE);
DWORD rank;
if (FAILED(sp.GetData(&rank)))
RETURN(FALSE);
if (rank != handle.GetRank())
RETURN(FALSE);
break;
}
}
RETURN(TRUE);
}
#ifdef FEATURE_PREJIT
/*static*/
BOOL ZapSig::CompareFixupToTypeHandle(Module * pModule, TADDR fixup, TypeHandle handle)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
FORBID_FAULT;
PRECONDITION(CORCOMPILE_IS_POINTER_TAGGED(fixup));
PRECONDITION(CheckPointer(pModule));
}
CONTRACTL_END
Module *pDefiningModule;
PCCOR_SIGNATURE pSig = pModule->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
if (pDefiningModule == NULL)
return FALSE;
ZapSig::Context zapSigContext(pDefiningModule, pModule);
return ZapSig::CompareSignatureToTypeHandle(pSig, pDefiningModule, handle, &zapSigContext);
}
#endif // FEATURE_PREJIT
/*static*/
BOOL ZapSig::CompareTypeHandleFieldToTypeHandle(TypeHandle *pTypeHnd, TypeHandle typeHnd2)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
MODE_ANY;
FORBID_FAULT;
PRECONDITION(CheckPointer(pTypeHnd));
PRECONDITION(CheckPointer(typeHnd2));
PRECONDITION(!CORCOMPILE_IS_POINTER_TAGGED((SIZE_T) typeHnd2.AsPtr()));
}
CONTRACTL_END
// Ensure that the compiler won't fetch the value twice
SIZE_T fixup = VolatileLoadWithoutBarrier((SIZE_T *)pTypeHnd);
#ifdef FEATURE_PREJIT
if (CORCOMPILE_IS_POINTER_TAGGED(fixup))
{
Module *pContainingModule = ExecutionManager::FindZapModule(dac_cast<TADDR>(pTypeHnd));
CONSISTENCY_CHECK(pContainingModule != NULL);
Module *pDefiningModule;
PCCOR_SIGNATURE pSig = pContainingModule->GetEncodedSigIfLoaded(CORCOMPILE_UNTAG_TOKEN(fixup), &pDefiningModule);
if (pDefiningModule == NULL)
return FALSE;
else
{
ZapSig::Context zapSigContext(pDefiningModule, pContainingModule);
ZapSig::Context * pZapSigContext = &zapSigContext;
return CompareSignatureToTypeHandle(pSig, pDefiningModule, typeHnd2, pZapSigContext);
}
}
else
#endif // FEATURE_PREJIT
return TypeHandle::FromTAddr(fixup) == typeHnd2;
}
#ifndef DACCESS_COMPILE
Module *ZapSig::DecodeModuleFromIndex(Module *fromModule,
DWORD index)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
Assembly *pAssembly = NULL;
NativeImage *nativeImage = fromModule->GetCompositeNativeImage();
uint32_t assemblyRefMax = (nativeImage != NULL ? 0 : fromModule->GetAssemblyRefMax());
if (index < assemblyRefMax)
{
if (index == 0)
{
pAssembly = fromModule->GetAssembly();
}
else
{
pAssembly = fromModule->LoadAssembly(RidToToken(index, mdtAssemblyRef))->GetAssembly();
}
}
else
{
index -= assemblyRefMax;
pAssembly = fromModule->GetNativeMetadataAssemblyRefFromCache(index);
if(pAssembly == NULL)
{
if (nativeImage != NULL)
{
pAssembly = nativeImage->LoadComponentAssembly(index);
}
else
{
AssemblySpec spec;
spec.InitializeSpec(TokenFromRid(index, mdtAssemblyRef),
fromModule->GetNativeAssemblyImport(),
NULL);
pAssembly = spec.LoadAssembly(FILE_LOADED);
}
fromModule->SetNativeMetadataAssemblyRefInCache(index, pAssembly);
}
}
return pAssembly->GetManifestModule();
}
Module *ZapSig::DecodeModuleFromIndexIfLoaded(Module *fromModule,
DWORD index)
{
CONTRACTL
{
NOTHROW;
GC_NOTRIGGER;
FORBID_FAULT;
}
CONTRACTL_END;
Assembly *pAssembly = NULL;
mdAssemblyRef tkAssemblyRef;
NativeImage *nativeImage = fromModule->GetCompositeNativeImage();
uint32_t assemblyRefMax = (nativeImage != NULL ? 0 : fromModule->GetAssemblyRefMax());
if (index < assemblyRefMax)
{
if (index == 0)
{
pAssembly = fromModule->GetAssembly();
}
else
{
pAssembly = fromModule->GetAssemblyIfLoaded(RidToToken(index, mdtAssemblyRef));
}
}
else
{
index -= assemblyRefMax;
tkAssemblyRef = RidToToken(index, mdtAssemblyRef);
IMDInternalImport * pMDImportOverride = (nativeImage != NULL
? nativeImage->GetManifestMetadata() : fromModule->GetNativeAssemblyImport(FALSE));
if (pMDImportOverride != NULL)
{
CHAR szFullName[MAX_CLASS_NAME + 1];
LPCSTR szWinRtNamespace = NULL;
LPCSTR szWinRtClassName = NULL;
BOOL fValidAssemblyRef = TRUE;
LPCSTR pAssemblyName;
DWORD dwFlags;
if (FAILED(pMDImportOverride->GetAssemblyRefProps(tkAssemblyRef,
NULL,
NULL,
&pAssemblyName,
NULL,
NULL,
NULL,
&dwFlags)))
{ // Unexpected failure reading MetaData
fValidAssemblyRef = FALSE;
}
if (fValidAssemblyRef && IsAfContentType_WindowsRuntime(dwFlags))
{
// Find the encoded type name
LPCSTR pTypeName = NULL;
if (pAssemblyName != NULL)
pTypeName = strchr(pAssemblyName, '!');
if (pTypeName != NULL)
{
pTypeName++;
// pTypeName now contains the full type name (namespace + name)
strcpy_s(szFullName, _countof(szFullName), pTypeName);
LPSTR pszName = strrchr(szFullName, '.');
// WinRT types must have a namespace
if (pszName != NULL)
{
// Replace . between namespace and name with null terminator.
// This breaks the string into a namespace and name pair.
*pszName = '\0';
pszName++;
szWinRtNamespace = szFullName;
szWinRtClassName = pszName;
}
else
{ // Namespace '.' separator not found - invalid type name (namespace has to be always present)
fValidAssemblyRef = FALSE;
}
}
else
{ // Type name separator in assembly name '!' not found
fValidAssemblyRef = FALSE;
}
}
if (fValidAssemblyRef)
{
pAssembly = fromModule->GetAssemblyIfLoaded(
tkAssemblyRef,
szWinRtNamespace,
szWinRtClassName,
pMDImportOverride);
}
}
}
if (pAssembly == NULL)
return NULL;
return pAssembly->GetManifestModule();
}
TypeHandle ZapSig::DecodeType(Module *pEncodeModuleContext,
Module *pInfoModule,
PCCOR_SIGNATURE pBuffer,
ClassLoadLevel level)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
SigPointer p(pBuffer);
ZapSig::Context zapSigContext(pInfoModule, pEncodeModuleContext);
ZapSig::Context * pZapSigContext = &zapSigContext;
SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
TypeHandle th = p.GetTypeHandleThrowing(pInfoModule,
&typeContext,
ClassLoader::LoadTypes,
level,
level < CLASS_LOADED, // For non-full loads, drop a level when loading generic arguments
NULL,
pZapSigContext);
return th;
}
MethodDesc *ZapSig::DecodeMethod(Module *pReferencingModule,
Module *pInfoModule,
PCCOR_SIGNATURE pBuffer,
TypeHandle * ppTH /*=NULL*/)
{
STANDARD_VM_CONTRACT;
SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
return DecodeMethod(pReferencingModule, pInfoModule, pBuffer, &typeContext, ppTH);
}
MethodDesc *ZapSig::DecodeMethod(Module *pReferencingModule,
Module *pInfoModule,
PCCOR_SIGNATURE pBuffer,
SigTypeContext *pContext,
TypeHandle *ppTH, /*=NULL*/
PCCOR_SIGNATURE *ppOwnerTypeSpecWithVars, /*=NULL*/
PCCOR_SIGNATURE *ppMethodSpecWithVars /*=NULL*/)
{
STANDARD_VM_CONTRACT;
MethodDesc *pMethod = NULL;
SigPointer sig(pBuffer);
ZapSig::Context zapSigContext(pInfoModule, (void *)pReferencingModule, ZapSig::NormalTokens);
ZapSig::Context * pZapSigContext = &zapSigContext;
// decode flags
DWORD methodFlags;
IfFailThrow(sig.GetData(&methodFlags));
TypeHandle thOwner = NULL;
if ( methodFlags & ENCODE_METHOD_SIG_OwnerType )
{
if (ppOwnerTypeSpecWithVars != NULL)
*ppOwnerTypeSpecWithVars = sig.GetPtr();
thOwner = sig.GetTypeHandleThrowing(pInfoModule,
pContext,
ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
IfFailThrow(sig.SkipExactlyOne());
}
if ( methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken )
{
// get the method desc using slot number
DWORD slot;
IfFailThrow(sig.GetData(&slot));
_ASSERTE(!thOwner.IsNull());
pMethod = thOwner.GetMethodTable()->GetMethodDescForSlot(slot);
}
else
{
//
// decode method token
//
RID rid;
IfFailThrow(sig.GetData(&rid));
if (methodFlags & ENCODE_METHOD_SIG_MemberRefToken)
{
if (thOwner.IsNull())
{
TypeHandle th;
MethodDesc * pMD = NULL;
FieldDesc * pFD = NULL;
MemberLoader::GetDescFromMemberRef(pInfoModule, TokenFromRid(rid, mdtMemberRef), &pMD, &pFD, NULL, FALSE, &th);
_ASSERTE(pMD != NULL);
thOwner = th;
pMethod = pMD;
}
else
{
pMethod = MemberLoader::GetMethodDescFromMemberRefAndType(pInfoModule, TokenFromRid(rid, mdtMemberRef), thOwner.GetMethodTable());
}
}
else
{
pMethod = MemberLoader::GetMethodDescFromMethodDef(pInfoModule, TokenFromRid(rid, mdtMethodDef), FALSE);
}
}
if (thOwner.IsNull())
thOwner = pMethod->GetMethodTable();
if (ppTH != NULL)
*ppTH = thOwner;
#ifndef CROSSGEN_COMPILE
// Ensure that the methoddescs dependencies have been walked sufficiently for type forwarders to be resolved.
// This method is actually basically a nop for dependencies which are ngen'd, but is real work for jitted
// dependencies. (However, this shouldn't be meaningful work that wouldn't happen in any case very soon.)
pMethod->PrepareForUseAsADependencyOfANativeImage();
#endif // CROSSGEN_COMPILE
Instantiation inst;
// Instantiate the method if needed, or create a stub to a static method in a generic class.
if (methodFlags & ENCODE_METHOD_SIG_MethodInstantiation)
{
if (ppMethodSpecWithVars != NULL)
*ppMethodSpecWithVars = sig.GetPtr();
DWORD nargs;
IfFailThrow(sig.GetData(&nargs));
_ASSERTE(nargs > 0);
SIZE_T cbMem;
if (!ClrSafeInt<SIZE_T>::multiply(nargs, sizeof(TypeHandle), cbMem/* passed by ref */))
ThrowHR(COR_E_OVERFLOW);
TypeHandle * pInst = (TypeHandle*) _alloca(cbMem);
for (DWORD i = 0; i < nargs; i++)
{
pInst[i] = sig.GetTypeHandleThrowing(pInfoModule,
pContext,
ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
IfFailThrow(sig.SkipExactlyOne());
}
inst = Instantiation(pInst, nargs);
}
else
{
inst = pMethod->GetMethodInstantiation();
}
// This must be called even if nargs == 0, in order to create an instantiating
// stub for static methods in generic classees if needed, also for BoxedEntryPointStubs
// in non-generic structs.
BOOL isInstantiatingStub = (methodFlags & ENCODE_METHOD_SIG_InstantiatingStub);
BOOL isUnboxingStub = (methodFlags & ENCODE_METHOD_SIG_UnboxingStub);
pMethod = MethodDesc::FindOrCreateAssociatedMethodDesc(pMethod, thOwner.GetMethodTable(),
isUnboxingStub,
inst,
!(isInstantiatingStub || isUnboxingStub));
g_IBCLogger.LogMethodDescAccess(pMethod);
if (methodFlags & ENCODE_METHOD_SIG_Constrained)
{
TypeHandle constrainedType = sig.GetTypeHandleThrowing(pInfoModule,
pContext,
ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext);
MethodDesc * directMethod = constrainedType.GetMethodTable()->TryResolveConstraintMethodApprox(thOwner.GetMethodTable(), pMethod);
if (directMethod == NULL)
{
// Method on value type was removed. Boxing stub would need to be generated to handle this case.
_ASSERTE(!"Constrained method resolution failed");
MemberLoader::ThrowMissingMethodException(constrainedType.GetMethodTable(), NULL, NULL, NULL, 0, NULL);
}
// Strip the instantiating stub if the signature did not ask for one
if (directMethod->IsInstantiatingStub() && !isInstantiatingStub)
{
pMethod = directMethod->GetWrappedMethodDesc();
}
else
{
pMethod = directMethod;
}
}
return pMethod;
}
FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
Module *pInfoModule,
PCCOR_SIGNATURE pBuffer,
TypeHandle *ppTH /*=NULL*/)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
SigTypeContext typeContext; // empty context is OK: encoding should not contain type variables.
return DecodeField(pReferencingModule, pInfoModule, pBuffer, &typeContext, ppTH);
}
FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
Module *pInfoModule,
PCCOR_SIGNATURE pBuffer,
SigTypeContext *pContext,
TypeHandle *ppTH /*=NULL*/)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
FieldDesc *pField = NULL;
SigPointer sig(pBuffer);
DWORD fieldFlags;
IfFailThrow(sig.GetData(&fieldFlags));
MethodTable *pOwnerMT = NULL;
if (fieldFlags & ENCODE_FIELD_SIG_OwnerType)
{
ZapSig::Context zapSigContext(pInfoModule, pReferencingModule);
ZapSig::Context * pZapSigContext = &zapSigContext;
pOwnerMT = sig.GetTypeHandleThrowing(pInfoModule,
pContext,
ClassLoader::LoadTypes,
CLASS_LOADED,
FALSE,
NULL,
pZapSigContext).GetMethodTable();
IfFailThrow(sig.SkipExactlyOne());
}
if (fieldFlags & ENCODE_FIELD_SIG_IndexInsteadOfToken)
{
// get the field desc using index
DWORD fieldIndex;
IfFailThrow(sig.GetData(&fieldIndex));
_ASSERTE(pOwnerMT != NULL);
pField = pOwnerMT->GetFieldDescByIndex(fieldIndex);
_ASSERTE(pOwnerMT == pField->GetApproxEnclosingMethodTable());
}
else
{
RID rid;
IfFailThrow(sig.GetData(&rid));
if (fieldFlags & ENCODE_FIELD_SIG_MemberRefToken)
{
if (pOwnerMT == NULL)
{
TypeHandle th;
MethodDesc * pMD = NULL;
FieldDesc * pFD = NULL;
MemberLoader::GetDescFromMemberRef(pInfoModule, TokenFromRid(rid, mdtMemberRef), &pMD, &pFD, NULL, FALSE, &th);
_ASSERTE(pFD != NULL);
pField = pFD;
}
else
{
pField = MemberLoader::GetFieldDescFromMemberRefAndType(pInfoModule, TokenFromRid(rid, mdtMemberRef), pOwnerMT);
}
}
else
{
pField = MemberLoader::GetFieldDescFromFieldDef(pInfoModule, TokenFromRid(rid, mdtFieldDef), FALSE);
}
}
if (ppTH != NULL)
*ppTH = (pOwnerMT != NULL) ? pOwnerMT : pField->GetApproxEnclosingMethodTable();
return pField;
}
// Copy single type signature, adding ELEMENT_TYPE_MODULE_ZAPSIG to types that are encoded using tokens.
// The check for types that use token is conservative in the sense that it adds the override for types
// it doesn't explicitly recognize.
// The source signature originates from the module with index specified by the parameter moduleIndex.
// Passing moduleIndex set to MODULE_INDEX_NONE results in pure copy of the signature.
//
// NOTE: This function is meant to process only generic signatures that occur as owner type,
// constraint types and method instantiation in the EncodeMethod and EncodeField methods below.
//
void ZapSig::CopyTypeSignature(SigParser* pSigParser, SigBuilder* pSigBuilder, DWORD moduleIndex)
{
if (moduleIndex != MODULE_INDEX_NONE)
{
BYTE type;
IfFailThrow(pSigParser->PeekByte(&type));
// Handle single and multidimensional arrays
if (type == ELEMENT_TYPE_SZARRAY || type == ELEMENT_TYPE_ARRAY)
{
IfFailThrow(pSigParser->GetByte(&type));
pSigBuilder->AppendElementType((CorElementType)type);
// Copy the element type signature
CopyTypeSignature(pSigParser, pSigBuilder, moduleIndex);
if (type == ELEMENT_TYPE_ARRAY)
{
// Copy rank
ULONG rank;
IfFailThrow(pSigParser->GetData(&rank));
pSigBuilder->AppendData(rank);
if (rank)
{
// Copy # of sizes
ULONG nsizes;
IfFailThrow(pSigParser->GetData(&nsizes));
pSigBuilder->AppendData(nsizes);
while (nsizes--)
{
// Copy size
ULONG size;
IfFailThrow(pSigParser->GetData(&size));
pSigBuilder->AppendData(size);
}
// Copy # of lower bounds
ULONG nlbounds;
IfFailThrow(pSigParser->GetData(&nlbounds));
pSigBuilder->AppendData(nlbounds);
while (nlbounds--)
{
// Copy lower bound
ULONG lbound;
IfFailThrow(pSigParser->GetData(&lbound));
pSigBuilder->AppendData(lbound);
}
}
}
return;
}
// The following elements are not expected in the signatures this function processes. They are followed by
if (type == ELEMENT_TYPE_BYREF || type == ELEMENT_TYPE_PTR || type == ELEMENT_TYPE_PINNED ||
type == ELEMENT_TYPE_NATIVE_VALUETYPE_ZAPSIG)
{
_ASSERTE(FALSE);
}
// Add the module zapsig only for types that use tokens.
if (type >= ELEMENT_TYPE_PTR && type != ELEMENT_TYPE_I && type != ELEMENT_TYPE_U && type != ELEMENT_TYPE_OBJECT &&
type != ELEMENT_TYPE_VAR && type != ELEMENT_TYPE_MVAR && type != ELEMENT_TYPE_TYPEDBYREF)
{
pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_MODULE_ZAPSIG);
pSigBuilder->AppendData(moduleIndex);
}
// Generic instantiation requires processing each nesting level separately
if (type == ELEMENT_TYPE_GENERICINST)
{
IfFailThrow(pSigParser->GetByte(&type));
_ASSERTE(type == ELEMENT_TYPE_GENERICINST);
pSigBuilder->AppendElementType((CorElementType)type);
IfFailThrow(pSigParser->GetByte(&type));
_ASSERTE((type == ELEMENT_TYPE_CLASS) || (type == ELEMENT_TYPE_VALUETYPE));
pSigBuilder->AppendElementType((CorElementType)type);
mdToken token;
IfFailThrow(pSigParser->GetToken(&token));
pSigBuilder->AppendToken(token);
ULONG argCnt; // Get number of generic parameters
IfFailThrow(pSigParser->GetData(&argCnt));
pSigBuilder->AppendData(argCnt);
while (argCnt--)
{
CopyTypeSignature(pSigParser, pSigBuilder, moduleIndex);
}
return;
}
}
PCCOR_SIGNATURE typeSigStart = pSigParser->GetPtr();
IfFailThrow(pSigParser->SkipExactlyOne());
PCCOR_SIGNATURE typeSigEnd = pSigParser->GetPtr();
pSigBuilder->AppendBlob((PVOID)typeSigStart, typeSigEnd - typeSigStart);
}
/* static */
BOOL ZapSig::EncodeMethod(
MethodDesc * pMethod,
Module * pInfoModule,
SigBuilder * pSigBuilder,
LPVOID pEncodeModuleContext,
ENCODEMODULE_CALLBACK pfnEncodeModule,
DEFINETOKEN_CALLBACK pfnDefineToken,
CORINFO_RESOLVED_TOKEN * pResolvedToken,
CORINFO_RESOLVED_TOKEN * pConstrainedResolvedToken,
BOOL fEncodeUsingResolvedTokenSpecStreams)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
TypeHandle ownerType;
#ifdef FEATURE_READYTORUN_COMPILER
// For methods encoded outside of the version bubble, we use pResolvedToken which describes the metadata token from which the method originated
// For tokens inside the version bubble we are not constrained by the contents of pResolvedToken and as such we skip this codepath
// Generic interfaces in canonical form are an exception, we need to get the real type from the pResolvedToken so that the lookup at runtime
// can find the type in interface map.
// FUTURE: This condition should likely be changed or reevaluated once support for smaller version bubbles is implemented.
if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pMethod->GetModule()->IsInCurrentVersionBubble() || (pMethod->IsSharedByGenericInstantiations() && pMethod->IsInterface())))
{
if (pMethod->IsNDirect())
{
ownerType = pMethod->GetMethodTable_NoLogging();
}
else
{
if (pResolvedToken == NULL)
{
_ASSERTE(!"CORINFO_RESOLVED_TOKEN required to encode method!");
ThrowHR(E_FAIL);
}
// Encode the referencing method type
ownerType = TypeHandle(pResolvedToken->hClass);
}
}
else
#endif
{
ownerType = pMethod->GetMethodTable_NoLogging();
}
ZapSig::ExternalTokens externalTokens = ZapSig::NormalTokens;
if (pfnDefineToken != NULL)
{
externalTokens = ZapSig::IbcTokens;
}
ZapSig zapSig(pInfoModule, pEncodeModuleContext, externalTokens,
(EncodeModuleCallback) pfnEncodeModule,
(TokenDefinitionCallback) pfnDefineToken);
//
// output the sequence that represents the token for the method
//
mdMethodDef methodToken = pMethod->GetMemberDef_NoLogging();
DWORD methodFlags = 0;
BOOL fMethodNeedsInstantiation = pMethod->HasMethodInstantiation() && !pMethod->IsGenericMethodDefinition();
if (pMethod->IsUnboxingStub())
methodFlags |= ENCODE_METHOD_SIG_UnboxingStub;
if (pMethod->IsInstantiatingStub())
methodFlags |= ENCODE_METHOD_SIG_InstantiatingStub;
if (fMethodNeedsInstantiation)
methodFlags |= ENCODE_METHOD_SIG_MethodInstantiation;
//
// For backward compatibility, IBC tokens use slightly different encoding:
// - Owning type is uncoditionally encoded
// - Number of method instantiation arguments is not encoded
//
if (externalTokens == ZapSig::IbcTokens)
{
// The type is always encoded before flags for IBC
if (!zapSig.GetSignatureForTypeHandle(ownerType, pSigBuilder))
return FALSE;
}
else
{
// Assume that the owner type is going to be needed
methodFlags |= ENCODE_METHOD_SIG_OwnerType;
}
#ifdef FEATURE_READYTORUN_COMPILER
if (IsReadyToRunCompilation() && (pConstrainedResolvedToken != NULL))
{
methodFlags |= ENCODE_METHOD_SIG_Constrained;
}
// FUTURE: This condition should likely be changed or reevaluated once support for smaller version bubbles is implemented.
if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pMethod->GetModule()->IsInCurrentVersionBubble()))
{
Module * pReferencingModule = pMethod->IsNDirect() ?
pMethod->GetModule() :
IsDynamicScope(pResolvedToken->tokenScope) ? NULL: GetModule(pResolvedToken->tokenScope);
// pReferencingModule may be NULL if the method is a dynamic method.
if (pReferencingModule != NULL && !pReferencingModule->IsInCurrentVersionBubble())
{
// FUTURE: Encoding of new cross-module references for ReadyToRun
// This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
// GetSvcLogger()->Printf(W("ReadyToRun: Method reference outside of current version bubble cannot be encoded\n"));
ThrowHR(E_FAIL);
}
if (pMethod->IsNDirect())
{
methodToken = pMethod->GetMemberDef_NoLogging();
}
else if (!IsDynamicScope(pResolvedToken->tokenScope))
{
// Normal case for IL code
methodToken = pResolvedToken->token;
}
else
{
// Dynamic scope case. IL Stubs only
if (!pMethod->GetModule()->IsSystem())
{
_ASSERTE(FALSE); // IL stubs are expected to only have references to System.
ThrowHR(E_FAIL);
}
if (pInfoModule == pMethod->GetModule())
{
// This is assuming that the current module being compiled is the same as the module
// associated with the method being called. If so, we can identify the method by a MethodDef
// token. Otherwise, a more complex operation would be necessary.
methodToken = pMethod->GetMemberDef_NoLogging();
}
else
{
// Attempt to compile IL stub with use of helper function outside of CoreLib
_ASSERTE(FALSE);
ThrowHR(E_FAIL);
}
if (!ownerType.IsTypicalTypeDefinition() || pMethod->HasMethodInstantiation())
{
_ASSERTE(FALSE); // IL Stubs are not expected to have use of generic functions
ThrowHR(E_FAIL); // Attempt to compile IL stub with use of generic function. This encoding does not support that.
}
}
if (TypeFromToken(methodToken) != mdtMethodDef)
{
if (pReferencingModule == NULL)
{
// Invalid situation. Null pReferencingModule can only happen with a dynamic scope,
// and in that case the reference can only be a methoddef.
ThrowHR(E_FAIL);
}
}
if (TypeFromToken(methodToken) == mdtMethodSpec)
{
IfFailThrow(pReferencingModule->GetMDImport()->GetMethodSpecProps(methodToken, &methodToken, NULL, NULL));
}
switch (TypeFromToken(methodToken))
{
case mdtMethodDef:
_ASSERTE(pMethod->IsNDirect() || pResolvedToken->pTypeSpec == NULL);
if (!ownerType.HasInstantiation() || ownerType.IsTypicalTypeDefinition())
{
methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
}
break;
case mdtMemberRef:
_ASSERTE(pResolvedToken != NULL);
methodFlags |= ENCODE_METHOD_SIG_MemberRefToken;
if (pResolvedToken->pTypeSpec == NULL)
{
methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
}
else
if (!(methodFlags & ENCODE_METHOD_SIG_InstantiatingStub))
{
if (SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec).IsPolyType(NULL) == hasNoVars)
methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
}
break;
default:
_ASSERTE(!"Unexpected method token type!");
ThrowHR(E_NOTIMPL);
}
}
else
#endif
if (IsNilToken(methodToken))
{
methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
}
else
if (!pMethod->GetModule()->IsInCurrentVersionBubble())
{
// Using a method defined in another version bubble. We can assume the slot number is stable only for real interface methods.
if (!ownerType.IsInterface() || pMethod->IsStatic() || pMethod->HasMethodInstantiation())
{
// FUTURE TODO: Version resilience
_ASSERTE(!"References to non-interface methods not yet supported in version resilient images");
IfFailThrow(E_FAIL);
}
methodFlags |= ENCODE_METHOD_SIG_SlotInsteadOfToken;
}
else
{
Module * pTypeHandleModule = pMethod->GetModule();
if (pTypeHandleModule != pInfoModule)
{
// During IBC profiling this calls
// code:Module.EncodeModuleHelper
// During ngen this calls
// code:ZapImportTable.EncodeModuleHelper)
//
DWORD index = (*((EncodeModuleCallback) pfnEncodeModule))(pEncodeModuleContext, pTypeHandleModule);
if (index == ENCODE_MODULE_FAILED)
{
return FALSE;
}
// If the method handle's module is different that the pInfoModule
// we need to call the TokenDefinitionCallback function
// to record the names for the external module tokens
//
if ((index != 0) && (pfnDefineToken != NULL))
{
//
// We do not want to log the metadata lookups that we perform here
//
IBCLoggingDisabler disableLogging;
// During IBC profiling this calls
// code:Module::TokenDefinitionHelper()
(*((TokenDefinitionCallback) pfnDefineToken))(pEncodeModuleContext, pTypeHandleModule, index, &methodToken);
}
}
else
{
_ASSERTE(pInfoModule == pMethod->GetModule());
}
if (!ownerType.HasInstantiation())
methodFlags &= ~ENCODE_METHOD_SIG_OwnerType;
}
//
// output the flags
//
pSigBuilder->AppendData(methodFlags);
if (methodFlags & ENCODE_METHOD_SIG_OwnerType)
{
if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pTypeSpec != NULL)
{
_ASSERTE(pResolvedToken->cbTypeSpec > 0);
DWORD moduleIndex = MODULE_INDEX_NONE;
if ((IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != GetModule(pResolvedToken->tokenScope)))
{
if (IsDynamicScope(pResolvedToken->tokenScope))
{
_ASSERTE(FALSE); // IL stubs aren't expected to call methods which need this
ThrowHR(E_FAIL);
}
moduleIndex = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) GetModule(pResolvedToken->tokenScope));
}
SigParser sigParser(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
CopyTypeSignature(&sigParser, pSigBuilder, moduleIndex);
}
else
{
if (!zapSig.GetSignatureForTypeHandle(ownerType, pSigBuilder))
return FALSE;
}
}
if ((methodFlags & ENCODE_METHOD_SIG_SlotInsteadOfToken) == 0)
{
// emit the rid
pSigBuilder->AppendData(RidFromToken(methodToken));
}
else
{
// have no token (e.g. it could be an array), encode slot number
pSigBuilder->AppendData(pMethod->GetSlot());
}
if ((methodFlags & ENCODE_METHOD_SIG_MethodInstantiation) != 0)
{
if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pMethodSpec != NULL)
{
_ASSERTE(pResolvedToken->cbMethodSpec > 1);
// Copy the pResolvedToken->pMethodSpec, inserting ELEMENT_TYPE_MODULE_ZAPSIG in front of each type parameter in needed
SigParser sigParser(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
BYTE callingConvention;
IfFailThrow(sigParser.GetByte(&callingConvention));
if (callingConvention != (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST)
{
ThrowHR(COR_E_BADIMAGEFORMAT);
}
ULONG numGenArgs;
IfFailThrow(sigParser.GetData(&numGenArgs));
pSigBuilder->AppendData(numGenArgs);
if (IsDynamicScope(pResolvedToken->tokenScope))
{
_ASSERTE(FALSE); // IL stubs aren't expected to call methods which need this
ThrowHR(E_FAIL);
}
DWORD moduleIndex = MODULE_INDEX_NONE;
if (IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != GetModule(pResolvedToken->tokenScope))
{
moduleIndex = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, GetModule(pResolvedToken->tokenScope));
}
while (numGenArgs != 0)
{
CopyTypeSignature(&sigParser, pSigBuilder, moduleIndex);
numGenArgs--;
}
}
else
{
Instantiation inst = pMethod->GetMethodInstantiation();
// Number of method instantiation arguments is not encoded in IBC tokens - see comment above
if (externalTokens != ZapSig::IbcTokens)
pSigBuilder->AppendData(inst.GetNumArgs());
for (DWORD i = 0; i < inst.GetNumArgs(); i++)
{
TypeHandle t = inst[i];
_ASSERTE(!t.IsNull());
if (!zapSig.GetSignatureForTypeHandle(t, pSigBuilder))
return FALSE;
}
}
}
#ifdef FEATURE_READYTORUN_COMPILER
if ((methodFlags & ENCODE_METHOD_SIG_Constrained) != 0)
{
if (fEncodeUsingResolvedTokenSpecStreams && pConstrainedResolvedToken->pTypeSpec != NULL)
{
_ASSERTE(pConstrainedResolvedToken->cbTypeSpec > 0);
DWORD moduleIndex = MODULE_INDEX_NONE;
if (IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != GetModule(pConstrainedResolvedToken->tokenScope))
{
if (IsDynamicScope(pConstrainedResolvedToken->tokenScope))
{
_ASSERTE(FALSE); // IL stubs aren't expected to call methods which need this
ThrowHR(E_FAIL);
}
moduleIndex = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, GetModule(pConstrainedResolvedToken->tokenScope));
}
SigParser sigParser(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
CopyTypeSignature(&sigParser, pSigBuilder, moduleIndex);
}
else
{
if (!zapSig.GetSignatureForTypeHandle(TypeHandle(pConstrainedResolvedToken->hClass), pSigBuilder))
return FALSE;
}
}
#endif
return TRUE;
}
void ZapSig::EncodeField(
FieldDesc *pField,
Module *pInfoModule,
SigBuilder *pSigBuilder,
LPVOID pEncodeModuleContext,
ENCODEMODULE_CALLBACK pfnEncodeModule,
CORINFO_RESOLVED_TOKEN *pResolvedToken,
BOOL fEncodeUsingResolvedTokenSpecStreams)
{
CONTRACTL
{
THROWS;
GC_TRIGGERS;
MODE_ANY;
}
CONTRACTL_END;
MethodTable * pMT;
mdMethodDef fieldToken = pField->GetMemberDef();
DWORD fieldFlags = ENCODE_FIELD_SIG_OwnerType;
#ifdef FEATURE_READYTORUN_COMPILER
if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pField->GetModule()->IsInCurrentVersionBubble()))
{
if (pResolvedToken == NULL)
{
_ASSERTE(!"CORINFO_RESOLVED_TOKEN required to encode field!");
ThrowHR(E_FAIL);
}
// Encode the referencing field type
pMT = (MethodTable *)(pResolvedToken->hClass);
if (IsDynamicScope(pResolvedToken->tokenScope))
{
_ASSERTE(FALSE); // IL stubs aren't expected to need to access this sort of field
ThrowHR(E_FAIL);
}
Module * pReferencingModule = GetModule(pResolvedToken->tokenScope);
if (!pReferencingModule->IsInCurrentVersionBubble())
{
// FUTURE: Encoding of new cross-module references for ReadyToRun
// This warning is hit for recursive cross-module inlining. It is commented out to avoid noise.
// GetSvcLogger()->Printf(W("ReadyToRun: Field reference outside of current version bubble cannot be encoded\n"));
ThrowHR(E_FAIL);
}
_ASSERTE(pReferencingModule == GetAppDomain()->ToCompilationDomain()->GetTargetModule());
fieldToken = pResolvedToken->token;
switch (TypeFromToken(fieldToken))
{
case mdtFieldDef:
_ASSERTE(pResolvedToken->pTypeSpec == NULL);
fieldFlags &= ~ENCODE_FIELD_SIG_OwnerType;
break;
case mdtMemberRef:
fieldFlags |= ENCODE_FIELD_SIG_MemberRefToken;
if (pResolvedToken->pTypeSpec == NULL)
{
fieldFlags &= ~ENCODE_METHOD_SIG_OwnerType;
}
else
{
if (SigPointer(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec).IsPolyType(NULL) == hasNoVars)
fieldFlags &= ~ENCODE_METHOD_SIG_OwnerType;
}
break;
default:
_ASSERTE(!"Unexpected field token type!");
ThrowHR(E_NOTIMPL);
}
}
else
#endif
{
pMT = pField->GetApproxEnclosingMethodTable();
fieldFlags |= ENCODE_FIELD_SIG_IndexInsteadOfToken;
}
//
// output the flags
//
pSigBuilder->AppendData(fieldFlags);
if (fieldFlags & ENCODE_FIELD_SIG_OwnerType)
{
if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pTypeSpec != NULL)
{
_ASSERTE(pResolvedToken->cbTypeSpec > 0);
DWORD moduleIndex = MODULE_INDEX_NONE;
if ((IsReadyToRunCompilation() && pField->GetModule()->IsInCurrentVersionBubble() && pInfoModule != (Module *) pResolvedToken->tokenScope))
{
moduleIndex = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) pResolvedToken->tokenScope);
}
SigParser sigParser(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
CopyTypeSignature(&sigParser, pSigBuilder, moduleIndex);
}
else
{
ZapSig zapSig(pInfoModule, pEncodeModuleContext, ZapSig::NormalTokens,
(EncodeModuleCallback)pfnEncodeModule, NULL);
//
// Write class
//
BOOL fSuccess;
fSuccess = zapSig.GetSignatureForTypeHandle(pMT, pSigBuilder);
_ASSERTE(fSuccess);
}
}
if ((fieldFlags & ENCODE_FIELD_SIG_IndexInsteadOfToken) == 0)
{
// emit the rid
pSigBuilder->AppendData(RidFromToken(fieldToken));
}
else
{
//
// Write field index
//
DWORD fieldIndex = pMT->GetIndexForFieldDesc(pField);
_ASSERTE(fieldIndex < DWORD(pMT->GetNumStaticFields() + pMT->GetNumIntroducedInstanceFields()));
// have no token (e.g. it could be an array), encode slot number
pSigBuilder->AppendData(fieldIndex);
}
}
#endif // DACCESS_COMPILE