Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Commit

Permalink
Fix module override for recursive generic signatures (#24707)
Browse files Browse the repository at this point in the history
* Fix module override for recursive generic signatures

When crossgen-ing with large version bubble enabled, generic signatures
that got copied from the source IL were missing module overrides at
deeper levels of the generic signature.
For example, in case of X<Y<A,B>,Z>, the override was applied only to Y
and Z, but not to A and B.

This change fixes that by inserting module override zapsig at all
levels.
  • Loading branch information
janvorli committed May 27, 2019
1 parent 580152a commit 419b46f
Show file tree
Hide file tree
Showing 3 changed files with 143 additions and 25 deletions.
2 changes: 1 addition & 1 deletion src/vm/siginfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
#include "util.hpp"
#include "vars.hpp"
#include "clsload.hpp"
#include "sigparser.h"
#include "zapsig.h"
#include "threads.h"

#include "eecontract.h"
#include "typectxt.h"
#include "sigparser.h"

//---------------------------------------------------------------------------------------
// These macros define how arguments are mapped to the stack in the managed calling convention.
Expand Down
159 changes: 135 additions & 24 deletions src/vm/zapsig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1106,6 +1106,119 @@ FieldDesc * ZapSig::DecodeField(Module *pReferencingModule,
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_ARRAY_TEMPLATE_ZAPSIG || 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,
Expand Down Expand Up @@ -1333,14 +1446,14 @@ BOOL ZapSig::EncodeMethod(
{
_ASSERTE(pResolvedToken->cbTypeSpec > 0);

if (IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != (Module *) pResolvedToken->tokenScope)
DWORD moduleIndex = MODULE_INDEX_NONE;
if ((IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != (Module *) pResolvedToken->tokenScope))
{
pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_MODULE_ZAPSIG);
DWORD index = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) pResolvedToken->tokenScope);
pSigBuilder->AppendData(index);
moduleIndex = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) pResolvedToken->tokenScope);
}

pSigBuilder->AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
SigParser sigParser(pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);
CopyTypeSignature(&sigParser, pSigBuilder, moduleIndex);
}
else
{
Expand All @@ -1367,7 +1480,7 @@ BOOL ZapSig::EncodeMethod(
_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);
SigParser sigParser(pResolvedToken->pMethodSpec, pResolvedToken->cbMethodSpec);
BYTE callingConvention;
IfFailThrow(sigParser.GetByte(&callingConvention));
if (callingConvention != (BYTE)IMAGE_CEE_CS_CALLCONV_GENERICINST)
Expand All @@ -1379,25 +1492,15 @@ BOOL ZapSig::EncodeMethod(
IfFailThrow(sigParser.GetData(&numGenArgs));
pSigBuilder->AppendData(numGenArgs);

DWORD moduleIndex;
bool addModuleZapSig = (IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != (Module *) pResolvedToken->tokenScope);
if (addModuleZapSig)
DWORD moduleIndex = MODULE_INDEX_NONE;
if ((IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != (Module *) pResolvedToken->tokenScope))
{
moduleIndex = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) pResolvedToken->tokenScope);
}

while (numGenArgs != 0)
{
if (addModuleZapSig)
{
pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_MODULE_ZAPSIG);
pSigBuilder->AppendData(moduleIndex);
}

PCCOR_SIGNATURE typeSigStart = sigParser.GetPtr();
IfFailThrow(sigParser.SkipExactlyOne());
PCCOR_SIGNATURE typeSigEnd = sigParser.GetPtr();
pSigBuilder->AppendBlob((PVOID)typeSigStart, typeSigEnd - typeSigStart);
CopyTypeSignature(&sigParser, pSigBuilder, moduleIndex);
numGenArgs--;
}
}
Expand Down Expand Up @@ -1427,14 +1530,14 @@ BOOL ZapSig::EncodeMethod(
{
_ASSERTE(pConstrainedResolvedToken->cbTypeSpec > 0);

DWORD moduleIndex = (DWORD)-1;
if (IsReadyToRunCompilation() && pMethod->GetModule()->IsInCurrentVersionBubble() && pInfoModule != (Module *) pConstrainedResolvedToken->tokenScope)
{
pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_MODULE_ZAPSIG);
DWORD index = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) pConstrainedResolvedToken->tokenScope);
pSigBuilder->AppendData(index);
moduleIndex = (*((EncodeModuleCallback)pfnEncodeModule))(pEncodeModuleContext, (Module *) pConstrainedResolvedToken->tokenScope);
}

pSigBuilder->AppendBlob((PVOID)pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
SigParser sigParser(pConstrainedResolvedToken->pTypeSpec, pConstrainedResolvedToken->cbTypeSpec);
CopyTypeSignature(&sigParser, pSigBuilder, moduleIndex);
}
else
{
Expand Down Expand Up @@ -1538,7 +1641,15 @@ void ZapSig::EncodeField(
if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pTypeSpec != NULL)
{
_ASSERTE(pResolvedToken->cbTypeSpec > 0);
pSigBuilder->AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec);

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
{
Expand Down
7 changes: 7 additions & 0 deletions src/vm/zapsig.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ typedef DWORD (*EncodeModuleCallback)(void* pModuleContext, Module *pReferencedM
enum {
// return value when EncodeModule fails
ENCODE_MODULE_FAILED = 0xffffffff,
// no module index override is needed
MODULE_INDEX_NONE = 0xfffffffe
};

typedef void(*DEFINETOKEN_CALLBACK)(LPVOID pModuleContext, CORINFO_MODULE_HANDLE moduleHandle, DWORD index, mdTypeRef* token);
Expand Down Expand Up @@ -127,6 +129,11 @@ class ZapSig
//
static CorElementType TryEncodeUsingShortcut(/* in */ MethodTable * pMT);

// Copy single type signature, adding ELEMENT_TYPE_MODULE_ZAPSIG to types that are encoded using tokens.
// 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.
//
static void CopyTypeSignature(SigParser* pSigParser, SigBuilder* pSigBuilder, DWORD moduleIndex);

private:

Expand Down

0 comments on commit 419b46f

Please sign in to comment.