From 9fe3286e3810298934315e999580edd78c3322c2 Mon Sep 17 00:00:00 2001 From: Andon Andonov Date: Mon, 14 Jan 2019 19:59:12 -0800 Subject: [PATCH] Large version bubble Support (#21727) * Preliminary Changes * Module Index Resolution * Change infoModule encoding * Change referencing module in R2R * Pre-condition Check * Virtual Method Module Resolution * Remove Workarounds and add conditional import loading * Add signature kind module override * Add ELEMENT_TYPE_MODULE_ZAPSIG * Add switch to enable large version bubble * Cleanup * Change Native header check * Add large version bubble test * Add Large Version Bubble Checks * Cleanup * Revert unnecessary check * Change EncodeMethod Version Bubble Condition * Add Large Version Bubble asserts * Cleanup * Add default argument to runtests.py * Change test PreCommands * Revert whitespace changes * Change breaking conditional check * Streamline Version Bubble test * Address PR Feedback * Address PR Feedback #2 * Remove dead code * Add crossgen-time ifdef --- src/inc/corcompile.h | 8 ++ src/inc/coregen.h | 1 + src/inc/pedecoder.h | 3 +- src/inc/readytorun.h | 3 +- src/tools/crossgen/crossgen.cpp | 9 +++ src/utilcode/pedecoder.cpp | 24 +++++- src/vm/ceeload.cpp | 23 ++++-- src/vm/ceeload.h | 1 + src/vm/genericdict.cpp | 16 +++- src/vm/jitinterface.cpp | 2 +- src/vm/peimage.cpp | 4 +- src/vm/readytoruninfo.cpp | 4 +- src/vm/readytoruninfo.h | 1 + src/vm/vars.hpp | 1 + src/vm/zapsig.cpp | 25 ++++-- src/zap/zapimage.cpp | 6 +- src/zap/zapimage.h | 2 + src/zap/zapimport.cpp | 13 ++-- src/zap/zapper.cpp | 2 + src/zap/zapreadytorun.cpp | 20 ++++- src/zap/zapreadytorun.h | 2 + tests/runtest.cmd | 88 ++++++++++++---------- tests/runtest.py | 7 ++ tests/src/CLRTest.CrossGen.targets | 5 +- .../src/readytorun/tests/versionbubbles/helper.cs | 13 ++++ .../readytorun/tests/versionbubbles/helper.csproj | 33 ++++++++ .../tests/versionbubbles/versionbubbles.cs | 41 ++++++++++ .../tests/versionbubbles/versionbubbles.csproj | 58 ++++++++++++++ 28 files changed, 341 insertions(+), 74 deletions(-) create mode 100644 tests/src/readytorun/tests/versionbubbles/helper.cs create mode 100644 tests/src/readytorun/tests/versionbubbles/helper.csproj create mode 100644 tests/src/readytorun/tests/versionbubbles/versionbubbles.cs create mode 100644 tests/src/readytorun/tests/versionbubbles/versionbubbles.csproj diff --git a/src/inc/corcompile.h b/src/inc/corcompile.h index a644dd8..f8f522c 100644 --- a/src/inc/corcompile.h +++ b/src/inc/corcompile.h @@ -1812,6 +1812,7 @@ extern bool g_fNGenWinMDResilient; #ifdef FEATURE_READYTORUN_COMPILER extern bool g_fReadyToRunCompilation; +extern bool g_fLargeVersionBubble; #endif inline bool IsReadyToRunCompilation() @@ -1823,4 +1824,11 @@ inline bool IsReadyToRunCompilation() #endif } +#ifdef FEATURE_READYTORUN_COMPILER +inline bool IsLargeVersionBubbleEnabled() +{ + return g_fLargeVersionBubble; +} +#endif + #endif /* COR_COMPILE_H_ */ diff --git a/src/inc/coregen.h b/src/inc/coregen.h index f8d07a5..8ef075a 100644 --- a/src/inc/coregen.h +++ b/src/inc/coregen.h @@ -13,6 +13,7 @@ #define NGENWORKER_FLAGS_TUNING 0x0001 #define NGENWORKER_FLAGS_MISSINGDEPENDENCIESOK 0x0004 +#define NGENWORKER_FLAGS_LARGEVERSIONBUBBLE 0x0008 #define NGENWORKER_FLAGS_WINMD_RESILIENT 0x1000 #define NGENWORKER_FLAGS_READYTORUN 0x2000 diff --git a/src/inc/pedecoder.h b/src/inc/pedecoder.h index 2d6c5f5..4fdbee5 100644 --- a/src/inc/pedecoder.h +++ b/src/inc/pedecoder.h @@ -49,6 +49,7 @@ typedef DPTR(struct CORCOMPILE_HEADER) PTR_CORCOMPILE_HEADER; #include "readytorun.h" typedef DPTR(struct READYTORUN_HEADER) PTR_READYTORUN_HEADER; +typedef DPTR(struct READYTORUN_SECTION) PTR_READYTORUN_SECTION; typedef DPTR(IMAGE_COR20_HEADER) PTR_IMAGE_COR20_HEADER; @@ -400,7 +401,7 @@ class PEDecoder IMAGE_NT_HEADERS *FindNTHeaders() const; IMAGE_COR20_HEADER *FindCorHeader() const; CORCOMPILE_HEADER *FindNativeHeader() const; - READYTORUN_HEADER *FindReadyToRunHeader() const; + READYTORUN_HEADER *FindReadyToRunHeader() const; // Flat mapping utilities RVA InternalAddressToRva(SIZE_T address) const; diff --git a/src/inc/readytorun.h b/src/inc/readytorun.h index 0f5183f..faccfd0 100644 --- a/src/inc/readytorun.h +++ b/src/inc/readytorun.h @@ -60,7 +60,8 @@ enum ReadyToRunSectionType READYTORUN_SECTION_AVAILABLE_TYPES = 108, READYTORUN_SECTION_INSTANCE_METHOD_ENTRYPOINTS = 109, READYTORUN_SECTION_INLINING_INFO = 110, // Added in V2.1 - READYTORUN_SECTION_PROFILEDATA_INFO = 111 // Added in V2.2 + READYTORUN_SECTION_PROFILEDATA_INFO = 111, // Added in V2.2 + READYTORUN_SECTION_MANIFEST_METADATA = 112 // Added in V2.3 // If you add a new section consider whether it is a breaking or non-breaking change. // Usually it is non-breaking, but if it is preferable to have older runtimes fail diff --git a/src/tools/crossgen/crossgen.cpp b/src/tools/crossgen/crossgen.cpp index e208bc3..2643583 100644 --- a/src/tools/crossgen/crossgen.cpp +++ b/src/tools/crossgen/crossgen.cpp @@ -152,6 +152,9 @@ void PrintUsageHelper() #ifdef FEATURE_READYTORUN_COMPILER W(" /ReadyToRun - Generate images resilient to the runtime and\n") W(" dependency versions\n") + W(" /LargeVersionBubble - Generate image with a version bubble including all\n") + W(" input assemblies\n") + #endif #ifdef FEATURE_WINMD_RESILIENT W(" WinMD Parameters\n") @@ -422,6 +425,7 @@ int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv) LPWSTR pwzSearchPathForManagedPDB = NULL; LPCWSTR pwzOutputFilename = NULL; LPCWSTR pwzPublicKeys = nullptr; + bool fLargeVersionBubbleSwitch = false; #if !defined(FEATURE_MERGE_JIT_AND_ENGINE) LPCWSTR pwszCLRJITPath = nullptr; @@ -518,6 +522,11 @@ int _cdecl wmain(int argc, __in_ecount(argc) WCHAR **argv) { dwFlags &= ~NGENWORKER_FLAGS_READYTORUN; } + else if (MatchParameter(*argv, W("LargeVersionBubble"))) + { + dwFlags |= NGENWORKER_FLAGS_LARGEVERSIONBUBBLE; + fLargeVersionBubbleSwitch = true; + } #endif else if (MatchParameter(*argv, W("NoMetaData"))) { diff --git a/src/utilcode/pedecoder.cpp b/src/utilcode/pedecoder.cpp index bd0451d..d442d34 100644 --- a/src/utilcode/pedecoder.cpp +++ b/src/utilcode/pedecoder.cpp @@ -2481,14 +2481,34 @@ PTR_CVOID PEDecoder::GetNativeManifestMetadata(COUNT_T *pSize) const CONTRACT(PTR_CVOID) { INSTANCE_CHECK; - PRECONDITION(CheckNativeHeader()); + PRECONDITION(HasReadyToRunHeader() || CheckNativeHeader()); POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); // TBD - may not store metadata for IJW NOTHROW; GC_NOTRIGGER; } CONTRACT_END; + + IMAGE_DATA_DIRECTORY *pDir; + if (HasReadyToRunHeader()) + { + READYTORUN_HEADER * pHeader = GetReadyToRunHeader(); - IMAGE_DATA_DIRECTORY *pDir = GetMetaDataHelper(METADATA_SECTION_MANIFEST); + PTR_READYTORUN_SECTION pSections = dac_cast(dac_cast(pHeader) + sizeof(READYTORUN_HEADER)); + for (DWORD i = 0; i < pHeader->NumberOfSections; i++) + { + // Verify that section types are sorted + _ASSERTE(i == 0 || (pSections[i - 1].Type < pSections[i].Type)); + + READYTORUN_SECTION * pSection = pSections + i; + if (pSection->Type == READYTORUN_SECTION_MANIFEST_METADATA) + // Set pDir to the address of the manifest metadata section + pDir = &pSection->Section; + } + } + else + { + pDir = GetMetaDataHelper(METADATA_SECTION_MANIFEST); + } if (pSize != NULL) *pSize = VAL32(pDir->Size); diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp index 0399e87..3502b2d 100644 --- a/src/vm/ceeload.cpp +++ b/src/vm/ceeload.cpp @@ -3537,7 +3537,7 @@ BOOL Module::IsInCurrentVersionBubble() return TRUE; if (IsReadyToRunCompilation()) - return FALSE; + return IsLargeVersionBubbleEnabled(); #ifdef FEATURE_COMINTEROP if (g_fNGenWinMDResilient) @@ -9978,7 +9978,7 @@ Module *Module::GetModuleFromIndex(DWORD ix) } CONTRACT_END; - if (HasNativeImage()) + if (HasNativeOrReadyToRunImage()) { RETURN ZapSig::DecodeModuleFromIndex(this, ix); } @@ -10011,7 +10011,7 @@ Module *Module::GetModuleFromIndexIfLoaded(DWORD ix) NOTHROW; GC_NOTRIGGER; MODE_ANY; - PRECONDITION(HasNativeImage()); + PRECONDITION(HasNativeOrReadyToRunImage()); POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); } CONTRACT_END; @@ -10051,15 +10051,24 @@ IMDInternalImport *Module::GetNativeAssemblyImport(BOOL loadAllowed) if (loadAllowed) THROWS; else NOTHROW; if (loadAllowed) INJECT_FAULT(COMPlusThrowOM()); else FORBID_FAULT; MODE_ANY; - PRECONDITION(HasNativeImage()); - POSTCONDITION(CheckPointer(RETVAL)); + PRECONDITION(HasNativeOrReadyToRunImage()); + POSTCONDITION(loadAllowed ? + CheckPointer(RETVAL): + CheckPointer(RETVAL, NULL_OK)); } CONTRACT_END; - RETURN GetFile()->GetPersistentNativeImage()->GetNativeMDImport(loadAllowed); + // Check if image is R2R + if (GetFile()->IsILImageReadyToRun()) + { + RETURN GetFile()->GetOpenedILimage()->GetNativeMDImport(loadAllowed); + } + else + { + RETURN GetFile()->GetPersistentNativeImage()->GetNativeMDImport(loadAllowed); + } } - /*static*/ void Module::RestoreMethodTablePointerRaw(MethodTable ** ppMT, Module *pContainingModule, diff --git a/src/vm/ceeload.h b/src/vm/ceeload.h index 81f7acd..497c79e 100644 --- a/src/vm/ceeload.h +++ b/src/vm/ceeload.h @@ -2739,6 +2739,7 @@ public: BYTE *GetNativeFixupBlobData(RVA fixup); IMDInternalImport *GetNativeAssemblyImport(BOOL loadAllowed = TRUE); + IMDInternalImport *GetNativeAssemblyImportIfLoaded(); BOOL FixupNativeEntry(CORCOMPILE_IMPORT_SECTION * pSection, SIZE_T fixupIndex, SIZE_T *fixup); diff --git a/src/vm/genericdict.cpp b/src/vm/genericdict.cpp index 5fad30f..906f5c5 100644 --- a/src/vm/genericdict.cpp +++ b/src/vm/genericdict.cpp @@ -686,8 +686,20 @@ Dictionary::PopulateEntry( pBlob = p.GetPtr(); } - CORCOMPILE_FIXUP_BLOB_KIND signatureKind = (CORCOMPILE_FIXUP_BLOB_KIND)CorSigUncompressData(pBlob); - switch (signatureKind) + BYTE signatureKind = *pBlob++; + if (signatureKind & ENCODE_MODULE_OVERRIDE) + { + DWORD moduleIndex = CorSigUncompressData(pBlob); + Module * pSignatureModule = pModule->GetModuleFromIndex(moduleIndex); + if (pInfoModule == pModule) + { + pInfoModule = pSignatureModule; + } + _ASSERTE(pInfoModule == pSignatureModule); + signatureKind &= ~ENCODE_MODULE_OVERRIDE; + } + + switch ((CORCOMPILE_FIXUP_BLOB_KIND) signatureKind) { case ENCODE_DECLARINGTYPE_HANDLE: kind = DeclaringTypeHandleSlot; break; case ENCODE_TYPE_HANDLE: kind = TypeHandleSlot; break; diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp index 37046ef..ef214f6 100644 --- a/src/vm/jitinterface.cpp +++ b/src/vm/jitinterface.cpp @@ -686,7 +686,7 @@ bool IsInSameVersionBubble(Assembly * current, Assembly * target) if (current == target) return true; - return false; + return IsLargeVersionBubbleEnabled(); } // Returns true if the assemblies defining current and target are in the same version bubble diff --git a/src/vm/peimage.cpp b/src/vm/peimage.cpp index f058159..8385408 100644 --- a/src/vm/peimage.cpp +++ b/src/vm/peimage.cpp @@ -460,7 +460,7 @@ IMDInternalImport* PEImage::GetNativeMDImport(BOOL loadAllowed) CONTRACTL { INSTANCE_CHECK; - PRECONDITION(HasNativeHeader()); + PRECONDITION(HasNativeHeader() || HasReadyToRunHeader()); if (loadAllowed) GC_TRIGGERS; else GC_NOTRIGGER; if (loadAllowed) THROWS; else NOTHROW; if (loadAllowed) INJECT_FAULT(COMPlusThrowOM()); else FORBID_FAULT; @@ -485,7 +485,7 @@ void PEImage::OpenNativeMDImport() CONTRACTL { INSTANCE_CHECK; - PRECONDITION(HasNativeHeader()); + PRECONDITION(HasNativeHeader() || HasReadyToRunHeader()); GC_TRIGGERS; THROWS; MODE_ANY; diff --git a/src/vm/readytoruninfo.cpp b/src/vm/readytoruninfo.cpp index baac710..7c110c6 100644 --- a/src/vm/readytoruninfo.cpp +++ b/src/vm/readytoruninfo.cpp @@ -607,7 +607,8 @@ ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYT pamTracker, &m_pPersistentInlineTrackingMap); } } - // Fpr format version 2.2 and later, there is an optional profile-data section + + // For format version 2.2 and later, there is an optional profile-data section if (IsImageVersionAtLeast(2, 2)) { IMAGE_DATA_DIRECTORY * pProfileDataInfoDir = FindSection(READYTORUN_SECTION_PROFILEDATA_INFO); @@ -619,6 +620,7 @@ ReadyToRunInfo::ReadyToRunInfo(Module * pModule, PEImageLayout * pLayout, READYT pModule->SetMethodProfileList(pMethodProfileList); } } + } static bool SigMatchesMethodDesc(MethodDesc* pMD, SigPointer &sig, Module * pModule) diff --git a/src/vm/readytoruninfo.h b/src/vm/readytoruninfo.h index fea5b33..93bed74 100644 --- a/src/vm/readytoruninfo.h +++ b/src/vm/readytoruninfo.h @@ -43,6 +43,7 @@ class ReadyToRunInfo NativeFormat::NativeArray m_methodDefEntryPoints; NativeFormat::NativeHashtable m_instMethodEntryPoints; NativeFormat::NativeHashtable m_availableTypesHashtable; + NativeFormat::NativeHashtable m_pMetaDataHashtable; Crst m_Crst; PtrHashMap m_entryPointToMethodDescMap; diff --git a/src/vm/vars.hpp b/src/vm/vars.hpp index 931bf3a..91ad42a 100644 --- a/src/vm/vars.hpp +++ b/src/vm/vars.hpp @@ -812,6 +812,7 @@ extern CEECompileInfo *g_pCEECompileInfo; #ifdef FEATURE_READYTORUN_COMPILER extern bool g_fReadyToRunCompilation; +extern bool g_fLargeVersionBubble; #endif // Returns true if this is NGen compilation process. diff --git a/src/vm/zapsig.cpp b/src/vm/zapsig.cpp index b883eaf..734491e 100644 --- a/src/vm/zapsig.cpp +++ b/src/vm/zapsig.cpp @@ -760,7 +760,7 @@ Module *ZapSig::DecodeModuleFromIndexIfLoaded(Module *fromModule, fValidAssemblyRef = FALSE; } } - + if (fValidAssemblyRef) { pAssembly = fromModule->GetAssemblyIfLoaded( @@ -803,11 +803,11 @@ TypeHandle ZapSig::DecodeType(Module *pEncodeModuleContext, TypeHandle th = p.GetTypeHandleThrowing(pInfoModule, &typeContext, ClassLoader::LoadTypes, - level, + level, level < CLASS_LOADED, // For non-full loads, drop a level when loading generic arguments NULL, pZapSigContext); - + return th; } @@ -1127,7 +1127,11 @@ BOOL ZapSig::EncodeMethod( TypeHandle ownerType; #ifdef FEATURE_READYTORUN_COMPILER - if (IsReadyToRunCompilation()) + + // 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 + // FUTURE: This condition should likely be changed or reevaluated once support for smaller version bubbles is implemented. + if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pMethod->GetModule()->IsInCurrentVersionBubble())) { if (pResolvedToken == NULL) { @@ -1186,7 +1190,9 @@ BOOL ZapSig::EncodeMethod( } #ifdef FEATURE_READYTORUN_COMPILER - if (IsReadyToRunCompilation()) + + // FUTURE: This condition should likely be changed or reevaluated once support for smaller version bubbles is implemented. + if (IsReadyToRunCompilation() && (!IsLargeVersionBubbleEnabled() || !pMethod->GetModule()->IsInCurrentVersionBubble())) { if (pConstrainedResolvedToken != NULL) { @@ -1202,7 +1208,6 @@ BOOL ZapSig::EncodeMethod( // GetSvcLogger()->Printf(W("ReadyToRun: Method reference outside of current version bubble cannot be encoded\n")); ThrowHR(E_FAIL); } - _ASSERTE(pReferencingModule == GetAppDomain()->ToCompilationDomain()->GetTargetModule()); methodToken = pResolvedToken->token; @@ -1312,6 +1317,14 @@ BOOL ZapSig::EncodeMethod( if (fEncodeUsingResolvedTokenSpecStreams && pResolvedToken != NULL && pResolvedToken->pTypeSpec != NULL) { _ASSERTE(pResolvedToken->cbTypeSpec > 0); + + 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); + } + pSigBuilder->AppendBlob((PVOID)pResolvedToken->pTypeSpec, pResolvedToken->cbTypeSpec); } else diff --git a/src/zap/zapimage.cpp b/src/zap/zapimage.cpp index 7dce3af..3fa6073 100644 --- a/src/zap/zapimage.cpp +++ b/src/zap/zapimage.cpp @@ -1082,7 +1082,7 @@ HANDLE ZapImage::GenerateFile(LPCWSTR wszOutputFileName, CORCOMPILE_NGEN_SIGNATU HANDLE ZapImage::SaveImage(LPCWSTR wszOutputFileName, LPCWSTR wszDllPath, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig) { - if (!IsReadyToRunCompilation()) + if(!IsReadyToRunCompilation() || IsLargeVersionBubbleEnabled()) { OutputManifestMetadata(); } @@ -1835,6 +1835,10 @@ void ZapImage::Compile() OutputTypesTableForReadyToRun(m_pMDImport); OutputInliningTableForReadyToRun(); OutputProfileDataForReadyToRun(); + if (IsLargeVersionBubbleEnabled()) + { + OutputManifestMetadataForReadyToRun(); + } } else #endif diff --git a/src/zap/zapimage.h b/src/zap/zapimage.h index 36266d3..832f2b1 100644 --- a/src/zap/zapimage.h +++ b/src/zap/zapimage.h @@ -596,6 +596,7 @@ private: void OutputTypesTableForReadyToRun(IMDInternalImport * pMDImport); void OutputInliningTableForReadyToRun(); void OutputProfileDataForReadyToRun(); + void OutputManifestMetadataForReadyToRun(); void CopyDebugDirEntry(); void CopyWin32VersionResource(); @@ -691,6 +692,7 @@ public: } static void __stdcall TryCompileMethodStub(LPVOID pContext, CORINFO_METHOD_HANDLE hStub, CORJIT_FLAGS jitFlags); + static DWORD EncodeModuleHelper(LPVOID compileContext, CORINFO_MODULE_HANDLE referencedModule); BOOL IsVTableGapMethod(mdMethodDef md); diff --git a/src/zap/zapimport.cpp b/src/zap/zapimport.cpp index d3010af..9d8eec1 100644 --- a/src/zap/zapimport.cpp +++ b/src/zap/zapimport.cpp @@ -329,6 +329,7 @@ ZapGenericSignature * ZapImportTable::GetGenericSignature(PVOID signature, BOOL /*static*/ DWORD ZapImportTable::EncodeModuleHelper( LPVOID compileContext, CORINFO_MODULE_HANDLE referencedModule) { + _ASSERTE(!IsReadyToRunCompilation() || IsLargeVersionBubbleEnabled()); ZapImportTable * pTable = (ZapImportTable *)compileContext; return pTable->GetIndexOfModule(referencedModule); } @@ -952,6 +953,7 @@ void ZapImportTable::EncodeModule(CORCOMPILE_FIXUP_BLOB_KIND kind, CORINFO_MODUL { if (module != GetImage()->GetModuleHandle()) { + _ASSERTE(!IsReadyToRunCompilation() || IsLargeVersionBubbleEnabled()); pSigBuilder->AppendByte(kind | ENCODE_MODULE_OVERRIDE); pSigBuilder->AppendData(GetIndexOfModule(module)); } @@ -1635,7 +1637,7 @@ ZapImport * ZapImportTable::GetExternalMethodCell(CORINFO_METHOD_HANDLE handle, } else { - EncodeMethod(ENCODE_METHOD_ENTRY, handle, &sigBuilder, pResolvedToken, pConstrainedResolvedToken); + EncodeMethod(ENCODE_METHOD_ENTRY, handle, &sigBuilder, pResolvedToken, pConstrainedResolvedToken, false); } return GetImportForSignature((PVOID)handle, &sigBuilder); @@ -1777,7 +1779,7 @@ ZapImport * ZapImportTable::GetDictionaryLookupCell(CORCOMPILE_FIXUP_BLOB_KIND k if ((kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE) == ENCODE_DICTIONARY_LOOKUP_THISOBJ) { CORINFO_CLASS_HANDLE hClassContext = GetJitInfo()->getMethodClass(pResolvedToken->tokenContext); - GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), hClassContext, &sigBuilder, NULL, NULL); + GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), hClassContext, &sigBuilder, this, EncodeModuleHelper); } switch (pLookup->runtimeLookupFlags) @@ -1795,7 +1797,7 @@ ZapImport * ZapImportTable::GetDictionaryLookupCell(CORCOMPILE_FIXUP_BLOB_KIND k { _ASSERTE(pLookup->runtimeLookupArgs != NULL); sigBuilder.AppendData(ENCODE_DECLARINGTYPE_HANDLE); - GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), (CORINFO_CLASS_HANDLE)pLookup->runtimeLookupArgs, &sigBuilder, NULL, NULL); + GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), (CORINFO_CLASS_HANDLE)pLookup->runtimeLookupArgs, &sigBuilder, this, EncodeModuleHelper); } else { @@ -1844,8 +1846,7 @@ ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind sigBuilder.AppendData(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE); - GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), handle, &sigBuilder, NULL, NULL); - + GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), handle, &sigBuilder, this, EncodeModuleHelper); pImport->SetBlob(GetBlob(&sigBuilder)); } @@ -1863,7 +1864,7 @@ ZapImport * ZapImportTable::GetDynamicHelperCell(CORCOMPILE_FIXUP_BLOB_KIND kind if (delegateType != NULL) { _ASSERTE((CORCOMPILE_FIXUP_BLOB_KIND)(kind & ~CORINFO_HELP_READYTORUN_ATYPICAL_CALLSITE) == ENCODE_DELEGATE_CTOR); - GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), delegateType, &sigBuilder, NULL, NULL); + GetCompileInfo()->EncodeClass(m_pImage->GetModuleHandle(), delegateType, &sigBuilder, this, EncodeModuleHelper); } return GetImportForSignature((void *)(uintptr_t)((kind << 1) | 1), &sigBuilder); diff --git a/src/zap/zapper.cpp b/src/zap/zapper.cpp index 6d1cbd9..f4ddb92 100644 --- a/src/zap/zapper.cpp +++ b/src/zap/zapper.cpp @@ -21,6 +21,7 @@ bool g_fNGenWinMDResilient; #ifdef FEATURE_READYTORUN_COMPILER bool g_fReadyToRunCompilation; +bool g_fLargeVersionBubble; #endif static bool s_fNGenNoMetaData; @@ -110,6 +111,7 @@ STDAPI NGenWorker(LPCWSTR pwzFilename, DWORD dwFlags, LPCWSTR pwzPlatformAssembl #ifdef FEATURE_READYTORUN_COMPILER g_fReadyToRunCompilation = !!(dwFlags & NGENWORKER_FLAGS_READYTORUN); + g_fLargeVersionBubble = !!(dwFlags & NGENWORKER_FLAGS_LARGEVERSIONBUBBLE); #endif if (pLogger != NULL) diff --git a/src/zap/zapreadytorun.cpp b/src/zap/zapreadytorun.cpp index 099ef41..7e26411 100644 --- a/src/zap/zapreadytorun.cpp +++ b/src/zap/zapreadytorun.cpp @@ -254,7 +254,7 @@ void ZapImage::OutputEntrypointsTableForReadyToRun() resolvedToken.token = token; resolvedToken.hClass = pMethod->GetClassHandle(); resolvedToken.hMethod = pMethod->GetHandle(); - GetCompileInfo()->EncodeMethod(module, pMethod->GetHandle(), &sigBuilder, NULL, NULL, &resolvedToken); + GetCompileInfo()->EncodeMethod(module, pMethod->GetHandle(), &sigBuilder, m_pImportTable, EncodeModuleHelper, &resolvedToken); DWORD cbBlob; PVOID pBlob = sigBuilder.GetSignature(&cbBlob); @@ -326,6 +326,16 @@ public: } } }; +// At ngen time Zapper::CompileModule PlaceFixups called from +// code:ZapSig.GetSignatureForTypeHandle +// +/*static*/ DWORD ZapImage::EncodeModuleHelper(LPVOID compileContext, + CORINFO_MODULE_HANDLE referencedModule) +{ + _ASSERTE(!IsReadyToRunCompilation() || IsLargeVersionBubbleEnabled()); + ZapImportTable * pTable = (ZapImportTable *)compileContext; + return pTable->GetIndexOfModule(referencedModule); +} void ZapImage::OutputDebugInfoForReadyToRun() { @@ -397,6 +407,14 @@ void ZapImage::OutputProfileDataForReadyToRun() } } +void ZapImage::OutputManifestMetadataForReadyToRun() +{ + if (m_pMetaDataSection != nullptr) + { + GetReadyToRunHeader()->RegisterSection(READYTORUN_SECTION_MANIFEST_METADATA, m_pMetaDataSection); + } +} + void ZapImage::OutputTypesTableForReadyToRun(IMDInternalImport * pMDImport) { NativeWriter writer; diff --git a/src/zap/zapreadytorun.h b/src/zap/zapreadytorun.h index cf7ad06..d9409e9 100644 --- a/src/zap/zapreadytorun.h +++ b/src/zap/zapreadytorun.h @@ -59,6 +59,8 @@ public: } virtual void Save(ZapWriter * pZapWriter); + + DWORD EncodeModuleHelper(LPVOID compileContext, CORINFO_MODULE_HANDLE referencedModule); }; #endif // __ZAPREADYTORUN_H__ diff --git a/tests/runtest.cmd b/tests/runtest.cmd index ba7f6b5..37c5341 100644 --- a/tests/runtest.cmd +++ b/tests/runtest.cmd @@ -62,50 +62,52 @@ if /i "%1" == "-h" goto Usage if /i "%1" == "/help" goto Usage if /i "%1" == "-help" goto Usage -if /i "%1" == "x64" (set __BuildArch=x64&shift&goto Arg_Loop) -if /i "%1" == "x86" (set __BuildArch=x86&shift&goto Arg_Loop) -if /i "%1" == "arm" (set __BuildArch=arm&shift&goto Arg_Loop) -if /i "%1" == "arm64" (set __BuildArch=arm64&shift&goto Arg_Loop) - -if /i "%1" == "debug" (set __BuildType=Debug&shift&goto Arg_Loop) -if /i "%1" == "release" (set __BuildType=Release&shift&goto Arg_Loop) -if /i "%1" == "checked" (set __BuildType=Checked&shift&goto Arg_Loop) - -if /i "%1" == "vs2015" (set __VSVersion=%1&shift&goto Arg_Loop) -if /i "%1" == "vs2017" (set __VSVersion=%1&shift&goto Arg_Loop) - -if /i "%1" == "TestEnv" (set __TestEnv=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "AgainstPackages" (set __AgainstPackages=1&shift&goto Arg_Loop) -if /i "%1" == "sequential" (set __Sequential=1&shift&goto Arg_Loop) -if /i "%1" == "crossgen" (set __DoCrossgen=1&shift&goto Arg_Loop) -if /i "%1" == "crossgenaltjit" (set __DoCrossgen=1&set __CrossgenAltJit=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "longgc" (set __LongGCTests=1&shift&goto Arg_Loop) -if /i "%1" == "gcsimulator" (set __GCSimulatorTests=1&shift&goto Arg_Loop) -if /i "%1" == "jitstress" (set COMPlus_JitStress=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "jitstressregs" (set COMPlus_JitStressRegs=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "jitminopts" (set COMPlus_JITMinOpts=1&shift&goto Arg_Loop) -if /i "%1" == "jitforcerelocs" (set COMPlus_ForceRelocs=1&shift&goto Arg_Loop) -if /i "%1" == "jitdisasm" (set __JitDisasm=1&shift&goto Arg_Loop) -if /i "%1" == "ilasmroundtrip" (set __IlasmRoundTrip=1&shift&goto Arg_Loop) -if /i "%1" == "GenerateLayoutOnly" (set __GenerateLayoutOnly=1&shift&goto Arg_Loop) -if /i "%1" == "skipgeneratelayout" (set __SkipGenerateLayout=1&shift&goto Arg_Loop) -if /i "%1" == "buildxunitwrappers" (set __BuildXunitWrappers=1&shift&goto Arg_Loop) -if /i "%1" == "printlastresultsonly" (set __PrintLastResultsOnly=1&shift&goto Arg_Loop) -if /i "%1" == "PerfTests" (set __PerfTests=true&shift&goto Arg_Loop) -if /i "%1" == "CoreFXTests" (set __CoreFXTests=true&shift&goto Arg_Loop) -if /i "%1" == "CoreFXTestsAll" (set __CoreFXTests=true&set __CoreFXTestsRunAllAvailable=true&shift&goto Arg_Loop) -if /i "%1" == "CoreFXTestList" (set __CoreFXTests=true&set __CoreFXTestList=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "runcrossgentests" (set RunCrossGen=true&shift&goto Arg_Loop) -if /i "%1" == "link" (set DoLink=true&set ILLINK=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "x64" (set __BuildArch=x64&shift&goto Arg_Loop) +if /i "%1" == "x86" (set __BuildArch=x86&shift&goto Arg_Loop) +if /i "%1" == "arm" (set __BuildArch=arm&shift&goto Arg_Loop) +if /i "%1" == "arm64" (set __BuildArch=arm64&shift&goto Arg_Loop) + +if /i "%1" == "debug" (set __BuildType=Debug&shift&goto Arg_Loop) +if /i "%1" == "release" (set __BuildType=Release&shift&goto Arg_Loop) +if /i "%1" == "checked" (set __BuildType=Checked&shift&goto Arg_Loop) + +if /i "%1" == "vs2015" (set __VSVersion=%1&shift&goto Arg_Loop) +if /i "%1" == "vs2017" (set __VSVersion=%1&shift&goto Arg_Loop) + +if /i "%1" == "TestEnv" (set __TestEnv=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "AgainstPackages" (set __AgainstPackages=1&shift&goto Arg_Loop) +if /i "%1" == "sequential" (set __Sequential=1&shift&goto Arg_Loop) +if /i "%1" == "crossgen" (set __DoCrossgen=1&shift&goto Arg_Loop) +if /i "%1" == "crossgenaltjit" (set __DoCrossgen=1&set __CrossgenAltJit=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "longgc" (set __LongGCTests=1&shift&goto Arg_Loop) +if /i "%1" == "gcsimulator" (set __GCSimulatorTests=1&shift&goto Arg_Loop) +if /i "%1" == "jitstress" (set COMPlus_JitStress=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "jitstressregs" (set COMPlus_JitStressRegs=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "jitminopts" (set COMPlus_JITMinOpts=1&shift&goto Arg_Loop) +if /i "%1" == "jitforcerelocs" (set COMPlus_ForceRelocs=1&shift&goto Arg_Loop) +if /i "%1" == "jitdisasm" (set __JitDisasm=1&shift&goto Arg_Loop) +if /i "%1" == "ilasmroundtrip" (set __IlasmRoundTrip=1&shift&goto Arg_Loop) +if /i "%1" == "GenerateLayoutOnly" (set __GenerateLayoutOnly=1&shift&goto Arg_Loop) +if /i "%1" == "skipgeneratelayout" (set __SkipGenerateLayout=1&shift&goto Arg_Loop) +if /i "%1" == "buildxunitwrappers" (set __BuildXunitWrappers=1&shift&goto Arg_Loop) +if /i "%1" == "printlastresultsonly" (set __PrintLastResultsOnly=1&shift&goto Arg_Loop) +if /i "%1" == "PerfTests" (set __PerfTests=true&shift&goto Arg_Loop) +if /i "%1" == "CoreFXTests" (set __CoreFXTests=true&shift&goto Arg_Loop) +if /i "%1" == "CoreFXTestsAll" (set __CoreFXTests=true&set __CoreFXTestsRunAllAvailable=true&shift&goto Arg_Loop) +if /i "%1" == "CoreFXTestList" (set __CoreFXTests=true&set __CoreFXTestList=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "runcrossgentests" (set RunCrossGen=true&shift&goto Arg_Loop) +REM This test feature is currently intentionally undocumented +if /i "%1" == "runlargeversionbubblecrossgentests" (set RunCrossGen=true&set CrossgenLargeVersionBubble=true&shift&goto Arg_Loop) +if /i "%1" == "link" (set DoLink=true&set ILLINK=%2&shift&shift&goto Arg_Loop) REM tieredcompilation is on by default now, but setting this environment variable is harmless and I didn't want to break any automation that might be using it just yet -if /i "%1" == "tieredcompilation" (set COMPLUS_TieredCompilation=1&shift&goto Arg_Loop) -if /i "%1" == "gcname" (set COMPlus_GCName=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "timeout" (set __TestTimeout=%2&shift&shift&goto Arg_Loop) -if /i "%1" == "altjitarch" (set __AltJitArch=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "tieredcompilation" (set COMPLUS_TieredCompilation=1&shift&goto Arg_Loop) +if /i "%1" == "gcname" (set COMPlus_GCName=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "timeout" (set __TestTimeout=%2&shift&shift&goto Arg_Loop) +if /i "%1" == "altjitarch" (set __AltJitArch=%2&shift&shift&goto Arg_Loop) REM change it to COMPlus_GCStress when we stop using xunit harness -if /i "%1" == "gcstresslevel" (set COMPlus_GCStress=%2&set __TestTimeout=1800000&shift&shift&goto Arg_Loop) -if /i "%1" == "collectdumps" (set __CollectDumps=true&shift&goto Arg_Loop) +if /i "%1" == "gcstresslevel" (set COMPlus_GCStress=%2&set __TestTimeout=1800000&shift&shift&goto Arg_Loop) +if /i "%1" == "collectdumps" (set __CollectDumps=true&shift&goto Arg_Loop) if /i not "%1" == "msbuildargs" goto SkipMsbuildArgs :: All the rest of the args will be collected and passed directly to msbuild. @@ -208,6 +210,10 @@ if defined __DoCrossgen ( set __RuntestPyArgs=%__RuntestPyArgs% --precompile_core_root ) +if defined CrossgenLargeVersionBubble ( + set __RuntestPyArgs=%__RuntestPyArgs% --large_version_bubble +) + if defined __PrintLastResultsOnly ( set __RuntestPyArgs=%__RuntestPyArgs% --analyze_results_only ) diff --git a/tests/runtest.py b/tests/runtest.py index 5f38b8d..df51557 100755 --- a/tests/runtest.py +++ b/tests/runtest.py @@ -122,6 +122,7 @@ parser.add_argument("--gcsimulator", dest="gcsimulator", action="store_true", de parser.add_argument("--jitdisasm", dest="jitdisasm", action="store_true", default=False) parser.add_argument("--ilasmroundtrip", dest="ilasmroundtrip", action="store_true", default=False) parser.add_argument("--run_crossgen_tests", dest="run_crossgen_tests", action="store_true", default=False) +parser.add_argument("--large_version_bubble", dest="large_version_bubble", action="store_true", default=False) parser.add_argument("--precompile_core_root", dest="precompile_core_root", action="store_true", default=False) parser.add_argument("--sequential", dest="sequential", action="store_true", default=False) @@ -968,6 +969,7 @@ def run_tests(host_os, is_ilasm=False, is_illink=False, run_crossgen_tests=False, + large_version_bubble=False, run_sequential=False, limited_core_dumps=False): """ Run the coreclr tests @@ -1028,6 +1030,10 @@ def run_tests(host_os, print("Setting RunCrossGen=true") os.environ["RunCrossGen"] = "true" + if large_version_bubble: + print("Large Version Bubble enabled") + os.environ["LargeVersionBubble"] = "true" + if gc_stress: print("Running GCStress, extending timeout to 120 minutes.") print("Setting __TestTimeout=%s" % str(120*60*1000)) @@ -2243,6 +2249,7 @@ def do_setup(host_os, is_ilasm=unprocessed_args.ilasmroundtrip, is_illink=unprocessed_args.il_link, run_crossgen_tests=unprocessed_args.run_crossgen_tests, + large_version_bubble=unprocessed_args.large_version_bubble, run_sequential=unprocessed_args.sequential, limited_core_dumps=unprocessed_args.limited_core_dumps) diff --git a/tests/src/CLRTest.CrossGen.targets b/tests/src/CLRTest.CrossGen.targets index 7dddfa2..9dc441f 100644 --- a/tests/src/CLRTest.CrossGen.targets +++ b/tests/src/CLRTest.CrossGen.targets @@ -75,6 +75,7 @@ fi REM CrossGen Script if defined RunCrossGen ( + if defined LargeVersionBubble ( set OptionalArguments=!OptionalArguments! /largeversionbubble) set COMPlus_ZapRequire=$(ZapRequire) set COMPlus_ZapRequireList=$(MSBuildProjectName) if not exist "$(MSBuildProjectName).org" ( @@ -84,8 +85,8 @@ if defined RunCrossGen ( mkdir IL copy $(MSBuildProjectName).exe IL\$(MSBuildProjectName).exe ren $(MSBuildProjectName).exe $(MSBuildProjectName).org - echo "%_DebuggerFullPath% %CORE_ROOT%\crossgen.exe" /Platform_Assemblies_Paths %CORE_ROOT%%3B%25cd%25\IL%3B%25cd%25 /in $(MSBuildProjectName).org /out $(MSBuildProjectName).exe - %_DebuggerFullPath% "%CORE_ROOT%\crossgen.exe" /Platform_Assemblies_Paths %CORE_ROOT%%3B%25cd%25\IL%3B%25cd%25 /in $(MSBuildProjectName).org /out $(MSBuildProjectName).exe + echo "%_DebuggerFullPath% %CORE_ROOT%\crossgen.exe" !OptionalArguments! /Platform_Assemblies_Paths %CORE_ROOT%%3B%25cd%25\IL%3B%25cd%25 /in $(MSBuildProjectName).org /out $(MSBuildProjectName).exe + %_DebuggerFullPath% "%CORE_ROOT%\crossgen.exe" !OptionalArguments! /Platform_Assemblies_Paths %CORE_ROOT%%3B%25cd%25\IL%3B%25cd%25 /in $(MSBuildProjectName).org /out $(MSBuildProjectName).exe set CrossGenStatus=!ERRORLEVEL! ) call :ReleaseLock diff --git a/tests/src/readytorun/tests/versionbubbles/helper.cs b/tests/src/readytorun/tests/versionbubbles/helper.cs new file mode 100644 index 0000000..0fc5aa6 --- /dev/null +++ b/tests/src/readytorun/tests/versionbubbles/helper.cs @@ -0,0 +1,13 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; + +public class Helper +{ + [MethodImplAttribute(MethodImplOptions.AggressiveInlining)] + public string GetLastMethodName() + { + StackTrace st = new StackTrace(); + return st.GetFrame(0).GetMethod().Name; + } +} diff --git a/tests/src/readytorun/tests/versionbubbles/helper.csproj b/tests/src/readytorun/tests/versionbubbles/helper.csproj new file mode 100644 index 0000000..a11d2b0 --- /dev/null +++ b/tests/src/readytorun/tests/versionbubbles/helper.csproj @@ -0,0 +1,33 @@ + + + + + Debug + AnyCPU + 2.0 + {F74F55A1-DFCF-4C7C-B462-E96E1D0BB667} + library + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\..\ + $(DefineConstants);STATIC;CORECLR + SharedLibrary + True + + + + + + + + + False + + + + + + + + + + diff --git a/tests/src/readytorun/tests/versionbubbles/versionbubbles.cs b/tests/src/readytorun/tests/versionbubbles/versionbubbles.cs new file mode 100644 index 0000000..fd1f596 --- /dev/null +++ b/tests/src/readytorun/tests/versionbubbles/versionbubbles.cs @@ -0,0 +1,41 @@ +using System; + +public class Program +{ + public static int Main() + { + return RunTest(); + } + + public static int RunTest() + { + + Helper helper = new Helper(); + string lastMethodName = String.Empty; + + lastMethodName = helper.GetLastMethodName(); + + if((System.Environment.GetEnvironmentVariable("LargeVersionBubble") == null)) + { + // Cross-Assembly inlining is only allowed in multi-module version bubbles + Console.WriteLine("Large Version Bubble is disabled."); + Console.WriteLine("PASS"); + return 100; + } + + Console.WriteLine("Large Version Bubble is enabled."); + // Helper returns the name of the method in the last stack frame + // Check to see if the method has been inlined cross-module + if (lastMethodName != "GetLastMethodName") + { + // method in helper.cs has been inlined + Console.WriteLine("PASS"); + return 100; + } + else + { + Console.WriteLine("FAIL"); + return 101; + } + } +} diff --git a/tests/src/readytorun/tests/versionbubbles/versionbubbles.csproj b/tests/src/readytorun/tests/versionbubbles/versionbubbles.csproj new file mode 100644 index 0000000..2a6b749 --- /dev/null +++ b/tests/src/readytorun/tests/versionbubbles/versionbubbles.csproj @@ -0,0 +1,58 @@ + + + + + Debug + AnyCPU + 2.0 + {7DECC55A-B584-4456-83BA-6C42A5B3B3CB} + exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + BuildAndRun + $(DefineConstants);STATIC;CORECLR + 1 + 1 + PdbOnly + True + + + + + + + + + False + + + + + {F74F55A1-DFCF-4C7C-B462-E96E1D0BB667} + + + + + + + + + + + + + -- 2.7.4