From 5facf9e3b7d1aa93fc906dce6cf90070fd91d74a Mon Sep 17 00:00:00 2001 From: Irwin D'Souza Date: Mon, 22 Jan 2024 11:27:50 -0500 Subject: [PATCH] Delay AOT validation until restore under -XX:+DebugOnRestore Under -XX:+DebugOnRestore, the JIT generates FSD code. This is problematic for AOT as either: 1. An existing SCC will fail validation, since the AOT code therein will not have been generated with FSD, or 2. An unpopulated SCC will contain FSD code, which will be useless for any JVM that does not have FSD enabled This commit delays AOT validation until after restore; this ensures that AOT code from the SCC can be loaded post-restore, and that any code added to the SCC is maximally sharable. Signed-off-by: Irwin D'Souza --- .../compiler/control/OptionsPostRestore.cpp | 39 +++++++++++++-- runtime/compiler/control/rossa.cpp | 49 +++++++------------ runtime/compiler/env/J9SharedCache.cpp | 36 ++++++++++++++ runtime/compiler/env/J9SharedCache.hpp | 14 +++++- runtime/compiler/env/VMJ9.cpp | 6 +++ 5 files changed, 110 insertions(+), 34 deletions(-) diff --git a/runtime/compiler/control/OptionsPostRestore.cpp b/runtime/compiler/control/OptionsPostRestore.cpp index 46b40a94767..3cc098e4472 100644 --- a/runtime/compiler/control/OptionsPostRestore.cpp +++ b/runtime/compiler/control/OptionsPostRestore.cpp @@ -537,6 +537,10 @@ J9::OptionsPostRestore::invalidateCompiledMethodsIfNeeded(bool invalidateAll) void J9::OptionsPostRestore::disableAOTCompilation() { + static bool aotDisabled = false; + if (aotDisabled) + return; + // Ideally when disabling AOT, the vmThread->aotVMwithThreadInfo->_sharedCache // would also be freed and set to NULL. However, it isn't obvious whether non // compilation and java threads that could be running at the moment could make @@ -555,6 +559,9 @@ J9::OptionsPostRestore::disableAOTCompilation() TR::Options::setSharedClassCache(false); TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::AOT_DISABLED); + aotDisabled = true; + _disableAOTPostRestore = true; + j9nls_printf(PORTLIB, (UDATA) J9NLS_WARNING, J9NLS_JIT_CHECKPOINT_RESTORE_AOT_DISABLED); } @@ -736,7 +743,28 @@ J9::OptionsPostRestore::postProcessInternalCompilerOptions() // Disable AOT compilation if needed if (disableAOT) + { disableAOTCompilation(); + } + // If at this point AOT is not disabled, then reset all the options and + // validate the AOT Header if the validation was delayed pre-checkpoint + else if (TR_J9SharedCache::aotHeaderValidationDelayed()) + { + _jitConfig->javaVM->sharedClassConfig->runtimeFlags |= J9SHR_RUNTIMEFLAG_ENABLE_AOT; + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoLoadAOT, false); + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT, false); + TR::Options::setSharedClassCache(true); + TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::NOT_DISABLED); + TR_J9SharedCache::resetAOTHeaderValidationDelayed(); + + TR_J9SharedCache::validateAOTHeader(_jitConfig, _vmThread, _compInfo); + + if (TR::Options::getAOTCmdLineOptions()->getOption(TR_NoStoreAOT)) + { + _jitConfig->javaVM->sharedClassConfig->runtimeFlags &= ~J9SHR_RUNTIMEFLAG_ENABLE_AOT; + TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::AOT_DISABLED); + } + } // Set option to print code cache if necessary if (_argIndexPrintCodeCache > _argIndexDisablePrintCodeCache) @@ -791,7 +819,7 @@ J9::OptionsPostRestore::processCompilerOptions() PORT_ACCESS_FROM_JAVAVM(vm); bool jitEnabled = TR::Options::canJITCompile(); - bool aotEnabled = TR::Options::sharedClassCache(); + bool aotEnabled = TR_J9SharedCache::aotHeaderValidationDelayed() ? true : TR::Options::sharedClassCache(); _argIndexXjit = FIND_AND_CONSUME_RESTORE_ARG(OPTIONAL_LIST_MATCH, J9::Options::_externalOptionStrings[J9::ExternalOptions::Xjit], 0); _argIndexXnojit = FIND_AND_CONSUME_RESTORE_ARG(OPTIONAL_LIST_MATCH, J9::Options::_externalOptionStrings[J9::ExternalOptions::Xnojit], 0); @@ -802,14 +830,19 @@ J9::OptionsPostRestore::processCompilerOptions() jitEnabled = (_argIndexXjit > _argIndexXnojit); // If -Xnoaot was specified pre-checkpoint, there is a lot of infrastructure - // that needs to be set up, including validating the existing SCC. For now, - // Ignore -Xaot post-restore if -Xnoaot was specified pre-checkpoint. + // that needs to be set up. For now, ignore -Xaot post-restore if -Xnoaot + // was specified pre-checkpoint. if (aotEnabled) aotEnabled = (_argIndexXaot >= _argIndexXnoaot); if (!aotEnabled) { _disableAOTPostRestore = true; + } + + if (_disableAOTPostRestore) + { + aotEnabled = false; disableAOTCompilation(); } diff --git a/runtime/compiler/control/rossa.cpp b/runtime/compiler/control/rossa.cpp index 776505e112a..8b79459050e 100644 --- a/runtime/compiler/control/rossa.cpp +++ b/runtime/compiler/control/rossa.cpp @@ -2025,6 +2025,8 @@ aboutToBootstrap(J9JavaVM * javaVM, J9JITConfig * jitConfig) #endif #if defined(J9VM_OPT_CRIU_SUPPORT) + bool debugOnRestoreEnabled = javaVM->internalVMFunctions->isDebugOnRestoreEnabled(curThread); + /* If the JVM is in CRIU mode and checkpointing is allowed, then the JIT should be * limited to the same processor features as those used in Portable AOT mode. This * is because, the restore run may not be on the same machine as the one that created @@ -2049,38 +2051,14 @@ aboutToBootstrap(J9JavaVM * javaVM, J9JITConfig * jitConfig) validateSCC = false; #endif /* defined(J9VM_OPT_JITSERVER) */ +#if defined(J9VM_OPT_CRIU_SUPPORT) + if (debugOnRestoreEnabled) + validateSCC = false; +#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ + if (validateSCC) { - /* If AOT Shared Classes is turned ON, perform compatibility checks for AOT Shared Classes - * - * This check has to be done after latePostProcessJIT so that all the necessary JIT options - * can be set - */ - TR_J9VMBase *fe = TR_J9VMBase::get(jitConfig, curThread); - if (!compInfo->reloRuntime()->validateAOTHeader(fe, curThread)) - { - TR_ASSERT_FATAL(static_cast(jitConfig->privateConfig)->aotValidHeader != TR_yes, - "aotValidHeader is TR_yes after failing to validate AOT header\n"); - - /* If this is the second run, then failing to validate AOT header will cause aotValidHeader - * to be TR_no, in which case the SCC is not valid for use. However, if this is the first - * run, then aotValidHeader will be TR_maybe; try to store the AOT Header in this case. - */ - if (static_cast(jitConfig->privateConfig)->aotValidHeader == TR_no - || !compInfo->reloRuntime()->storeAOTHeader(fe, curThread)) - { - static_cast(jitConfig->privateConfig)->aotValidHeader = TR_no; - TR::Options::getAOTCmdLineOptions()->setOption(TR_NoLoadAOT); - TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT); - TR::Options::setSharedClassCache(false); - TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::AOT_DISABLED); - } - } - else - { - TR::Compiler->relocatableTarget.cpu = TR::CPU::customize(compInfo->reloRuntime()->getProcessorDescriptionFromSCC(curThread)); - jitConfig->relocatableTargetProcessor = TR::Compiler->relocatableTarget.cpu.getProcessorDescription(); - } + TR_J9SharedCache::validateAOTHeader(jitConfig, curThread, compInfo); } if (TR::Options::getAOTCmdLineOptions()->getOption(TR_NoStoreAOT)) @@ -2107,6 +2085,17 @@ aboutToBootstrap(J9JavaVM * javaVM, J9JITConfig * jitConfig) } #endif /* defined(J9VM_OPT_JITSERVER) */ } +#if defined(J9VM_OPT_CRIU_SUPPORT) + else if (debugOnRestoreEnabled) + { + javaVM->sharedClassConfig->runtimeFlags &= ~J9SHR_RUNTIMEFLAG_ENABLE_AOT; + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoLoadAOT); + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT); + TR::Options::setSharedClassCache(false); + TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::AOT_HEADER_VALIDATION_DELAYED); + TR_J9SharedCache::setAOTHeaderValidationDelayed(); + } +#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ if (javaVM->sharedClassConfig->runtimeFlags & J9SHR_RUNTIMEFLAG_ENABLE_READONLY) { diff --git a/runtime/compiler/env/J9SharedCache.cpp b/runtime/compiler/env/J9SharedCache.cpp index 01fc380ff71..b6a8f18347b 100644 --- a/runtime/compiler/env/J9SharedCache.cpp +++ b/runtime/compiler/env/J9SharedCache.cpp @@ -65,6 +65,42 @@ static_assert(TR_SharedCache::INVALID_CLASS_CHAIN_OFFSET != COULD_CREATE_CLASS_C TR_J9SharedCache::TR_J9SharedCacheDisabledReason TR_J9SharedCache::_sharedCacheState = TR_J9SharedCache::UNINITIALIZED; TR_YesNoMaybe TR_J9SharedCache::_sharedCacheDisabledBecauseFull = TR_maybe; UDATA TR_J9SharedCache::_storeSharedDataFailedLength = 0; +bool TR_J9SharedCache::_aotHeaderValidationDelayed = false; + +void +TR_J9SharedCache::validateAOTHeader(J9JITConfig *jitConfig, J9VMThread *vmThread, TR::CompilationInfo *compInfo) + { + /* If AOT Shared Classes is turned ON, perform compatibility checks for AOT Shared Classes + * + * This check has to be done after latePostProcessJIT so that all the necessary JIT options + * can be set + */ + TR_J9VMBase *fe = TR_J9VMBase::get(jitConfig, vmThread); + if (!compInfo->reloRuntime()->validateAOTHeader(fe, vmThread)) + { + TR_ASSERT_FATAL(static_cast(jitConfig->privateConfig)->aotValidHeader != TR_yes, + "aotValidHeader is TR_yes after failing to validate AOT header\n"); + + /* If this is the second run, then failing to validate AOT header will cause aotValidHeader + * to be TR_no, in which case the SCC is not valid for use. However, if this is the first + * run, then aotValidHeader will be TR_maybe; try to store the AOT Header in this case. + */ + if (static_cast(jitConfig->privateConfig)->aotValidHeader == TR_no + || !compInfo->reloRuntime()->storeAOTHeader(fe, vmThread)) + { + static_cast(jitConfig->privateConfig)->aotValidHeader = TR_no; + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoLoadAOT); + TR::Options::getAOTCmdLineOptions()->setOption(TR_NoStoreAOT); + TR::Options::setSharedClassCache(false); + TR_J9SharedCache::setSharedCacheDisabledReason(TR_J9SharedCache::AOT_DISABLED); + } + } + else + { + TR::Compiler->relocatableTarget.cpu = TR::CPU::customize(compInfo->reloRuntime()->getProcessorDescriptionFromSCC(vmThread)); + jitConfig->relocatableTargetProcessor = TR::Compiler->relocatableTarget.cpu.getProcessorDescription(); + } + } TR_YesNoMaybe TR_J9SharedCache::isSharedCacheDisabledBecauseFull(TR::CompilationInfo *compInfo) { diff --git a/runtime/compiler/env/J9SharedCache.hpp b/runtime/compiler/env/J9SharedCache.hpp index 3343d52f933..7b244d7da80 100644 --- a/runtime/compiler/env/J9SharedCache.hpp +++ b/runtime/compiler/env/J9SharedCache.hpp @@ -103,6 +103,8 @@ class TR_J9SharedCache : public TR_SharedCache virtual void addHint(TR_ResolvedMethod *, TR_SharedCacheHint); virtual bool isMostlyFull(); + static void validateAOTHeader(J9JITConfig *jitConfig, J9VMThread *vmThread, TR::CompilationInfo *compInfo); + /** * \brief Converts a shared cache offset, calculated from the end of the SCC, into the * metadata section of the SCC into a pointer. @@ -400,7 +402,8 @@ class TR_J9SharedCache : public TR_SharedCache // The following are probably equivalent to SHARED_CACHE_FULL - // they could have failed because of no space but no error code is returned. SHARED_CACHE_CLASS_CHAIN_STORE_FAILED, - AOT_HEADER_STORE_FAILED + AOT_HEADER_STORE_FAILED, + AOT_HEADER_VALIDATION_DELAYED }; static void setSharedCacheDisabledReason(TR_J9SharedCacheDisabledReason state) { _sharedCacheState = state; } @@ -408,6 +411,12 @@ class TR_J9SharedCache : public TR_SharedCache static TR_YesNoMaybe isSharedCacheDisabledBecauseFull(TR::CompilationInfo *compInfo); static void setStoreSharedDataFailedLength(UDATA length) {_storeSharedDataFailedLength = length; } +#if defined(J9VM_OPT_CRIU_SUPPORT) + static void setAOTHeaderValidationDelayed() { _aotHeaderValidationDelayed = true; } + static void resetAOTHeaderValidationDelayed() { _aotHeaderValidationDelayed = false; } + static bool aotHeaderValidationDelayed() { return _aotHeaderValidationDelayed; } +#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ + virtual J9SharedClassCacheDescriptor *getCacheDescriptorList(); protected: @@ -613,6 +622,9 @@ class TR_J9SharedCache : public TR_SharedCache static TR_J9SharedCacheDisabledReason _sharedCacheState; static TR_YesNoMaybe _sharedCacheDisabledBecauseFull; static UDATA _storeSharedDataFailedLength; +#if defined(J9VM_OPT_CRIU_SUPPORT) + static bool _aotHeaderValidationDelayed; +#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ }; diff --git a/runtime/compiler/env/VMJ9.cpp b/runtime/compiler/env/VMJ9.cpp index 97ef26d35da..abc179bd168 100644 --- a/runtime/compiler/env/VMJ9.cpp +++ b/runtime/compiler/env/VMJ9.cpp @@ -814,6 +814,12 @@ TR_J9VMBase::TR_J9VMBase( #if defined(J9VM_OPT_JITSERVER) || (compInfo->getPersistentInfo()->getRemoteCompilationMode() == JITServer::SERVER) #endif /* defined(J9VM_OPT_JITSERVER) */ +#if defined(J9VM_OPT_CRIU_SUPPORT) + || (vmThread + && jitConfig->javaVM->sharedClassConfig + && jitConfig->javaVM->internalVMFunctions->isDebugOnRestoreEnabled(vmThread) + && jitConfig->javaVM->internalVMFunctions->isCheckpointAllowed(vmThread)) +#endif /* defined(J9VM_OPT_CRIU_SUPPORT) */ ) // shared classes and AOT must be enabled, or we should be on the JITServer with remote AOT enabled {