Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(0.49) Track method dependencies during AOT store compilations #20703

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 35 additions & 17 deletions runtime/compiler/codegen/J9AheadOfTimeCompile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -502,8 +502,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal
fieldRecord->setInlinedSiteIndex(reloTarget, inlinedSiteIndex);
fieldRecord->setConstantPool(reloTarget, reinterpret_cast<uintptr_t>(aotCI->_constantPool));
fieldRecord->setCpIndex(reloTarget, static_cast<uintptr_t>(aotCI->_cpIndex));
fieldRecord->setClassChainOffsetInSharedCache(reloTarget, aotCI->_classChainOffset,
self(), aotCI->getAOTCacheClassChainRecord());
fieldRecord->setClassChainOffsetInSharedCache(reloTarget, aotCI, self());
}
break;

Expand Down Expand Up @@ -601,8 +600,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal
vsfRecord->setInlinedSiteIndex(reloTarget, inlinedSiteIndex);
vsfRecord->setConstantPool(reloTarget, reinterpret_cast<uintptr_t>(aotCI->_constantPool));
vsfRecord->setCpIndex(reloTarget, aotCI->_cpIndex);
vsfRecord->setRomClassOffsetInSharedCache(reloTarget, romClassOffsetInSharedCache,
self(), aotCI->getAOTCacheClassChainRecord());
vsfRecord->setRomClassOffsetInSharedCache(reloTarget, romClassOffsetInSharedCache, self(), aotCI);
}
break;

Expand All @@ -616,8 +614,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal
vcRecord->setInlinedSiteIndex(reloTarget, inlinedSiteIndex);
vcRecord->setConstantPool(reloTarget, reinterpret_cast<uintptr_t>(aotCI->_constantPool));
vcRecord->setCpIndex(reloTarget, aotCI->_cpIndex);
vcRecord->setClassChainOffsetInSharedCache(reloTarget, aotCI->_classChainOffset,
self(), aotCI->getAOTCacheClassChainRecord());
vcRecord->setClassChainOffsetInSharedCache(reloTarget, aotCI, self());
}
break;

Expand Down Expand Up @@ -671,7 +668,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal
pRecord->setInlinedSiteIndex(reloTarget, inlinedSiteIndex);
pRecord->setConstantPool(reloTarget, reinterpret_cast<uintptr_t>(owningMethod->constantPool()));
pRecord->setCpIndex(reloTarget, cpIndexOrData);
pRecord->setRomClassOffsetInSharedCache(reloTarget, romClassOffsetInSharedCache, self(), classChainRecord);
pRecord->setRomClassOffsetInSharedCache(reloTarget, romClassOffsetInSharedCache, self(), inlinedCodeClass, classChainRecord);
pRecord->setClassChainIdentifyingLoaderOffsetInSharedCache(reloTarget, classChainIdentifyingLoaderOffsetInSharedCache,
self(), classChainRecord);
pRecord->setClassChainForInlinedMethod(reloTarget, classChainOffsetInSharedCache, self(), classChainRecord);
Expand Down Expand Up @@ -758,8 +755,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal

vacRecord->setClassChainIdentifyingLoaderOffset(reloTarget, classChainOffsetInSharedCacheForCL,
self(), aotCI->getAOTCacheClassChainRecord());
vacRecord->setClassChainOffsetForClassBeingValidated(reloTarget, aotCI->_classChainOffset,
self(), aotCI->getAOTCacheClassChainRecord());
vacRecord->setClassChainOffsetForClassBeingValidated(reloTarget, aotCI, self());
}
break;

Expand All @@ -783,8 +779,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal

cbnRecord->setClassID(reloTarget, symValManager->getSymbolIDFromValue(svmRecord->_class));
cbnRecord->setBeholderID(reloTarget, symValManager->getSymbolIDFromValue(svmRecord->_beholder));
cbnRecord->setClassChainOffset(reloTarget, svmRecord->_classChainOffset,
self(), svmRecord->getAOTCacheClassChainRecord());
cbnRecord->setClassChainOffset(reloTarget, svmRecord, self());
}
break;

Expand All @@ -801,8 +796,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal

pcRecord->setClassID(reloTarget, symValManager->getSymbolIDFromValue(classToValidate));
//store the classchain's offset for the class that needs to be validated in the second run
pcRecord->setClassChainOffset(reloTarget, svmRecord->_classChainOffset,
self(), svmRecord->getAOTCacheClassChainRecord());
pcRecord->setClassChainOffset(reloTarget, svmRecord, self());
pcRecord->setClassChainOffsetForClassLoader(reloTarget, classChainOffsetInSharedCacheForCL,
self(), svmRecord->getAOTCacheClassChainRecord());
}
Expand Down Expand Up @@ -892,8 +886,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal
scmRecord->setSystemClassID(reloTarget, symValManager->getSymbolIDFromValue(classToValidate));
// Store class chain to get name of class. Checking the class chain for
// this record eliminates the need for a separate class chain validation.
scmRecord->setClassChainOffset(reloTarget, svmRecord->_classChainOffset,
self(), svmRecord->getAOTCacheClassChainRecord());
scmRecord->setClassChainOffset(reloTarget, svmRecord, self());
}
break;

Expand Down Expand Up @@ -943,8 +936,7 @@ J9::AheadOfTimeCompile::initializeCommonAOTRelocationHeader(TR::IteratedExternal
ccRecord->setClassID(reloTarget, symValManager->getSymbolIDFromValue(classToValidate));
// Store class chain to get name of class. Checking the class chain for
// this record eliminates the need for a separate class chain validation.
ccRecord->setClassChainOffset(reloTarget, svmRecord->_classChainOffset,
self(), svmRecord->getAOTCacheClassChainRecord());
ccRecord->setClassChainOffset(reloTarget, svmRecord, self());
}
break;

Expand Down Expand Up @@ -2626,4 +2618,30 @@ void J9::AheadOfTimeCompile::processRelocations()
relocationDataCursor += s->getSizeOfRelocationData();
}
}
#if !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED)
if (!comp->getOption(TR_DisableDependencyTracking))
{
auto method = comp->getMethodBeingCompiled()->getPersistentIdentifier();
auto definingClass = comp->fe()->getClassOfMethod(method);

Vector<uintptr_t> dependencies(comp->trMemory()->currentStackRegion());
uintptr_t totalDependencies = comp->populateAOTMethodDependencies(definingClass, dependencies);

if (totalDependencies == 0)
{
// If there are zero dependencies, we skip storing the chain. This
// flag must still be set to distinguish methods with zero
// dependencies from methods with untracked dependencies.
comp->getAotMethodHeaderEntry()->flags |= TR_AOTMethodHeader_TracksDependencies;
}
else
{
auto sharedCache = fej9->sharedCache();
auto vmThread = fej9->getCurrentVMThread();
auto dependencyChain = sharedCache->storeAOTMethodDependencies(vmThread, method, definingClass, dependencies.data(), dependencies.size());
if (dependencyChain)
comp->getAotMethodHeaderEntry()->flags |= TR_AOTMethodHeader_TracksDependencies;
}
}
#endif /* !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED) */
}
4 changes: 2 additions & 2 deletions runtime/compiler/compile/AOTClassInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,9 @@ class AOTClassInfo
}

#if defined(J9VM_OPT_JITSERVER)
const AOTCacheClassChainRecord *getAOTCacheClassChainRecord() { return _aotCacheClassChainRecord; }
const AOTCacheClassChainRecord *getAOTCacheClassChainRecord() const { return _aotCacheClassChainRecord; }
#else /* defined(J9VM_OPT_JITSERVER) */
const AOTCacheClassChainRecord *getAOTCacheClassChainRecord() { return NULL; }
const AOTCacheClassChainRecord *getAOTCacheClassChainRecord() const { return NULL; }
#endif /* defined(J9VM_OPT_JITSERVER) */

TR_ExternalRelocationTargetKind _reloKind; // identifies validation needed (instance field, static field, class, arbitrary class)
Expand Down
71 changes: 71 additions & 0 deletions runtime/compiler/compile/J9Compilation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "compile/Compilation.hpp"
#include "compile/Compilation_inlines.hpp"
#include "compile/CompilationTypes.hpp"
#include "env/DependencyTable.hpp"
#include "compile/ResolvedMethod.hpp"
#include "control/OptimizationPlan.hpp"
#include "control/Options.hpp"
Expand Down Expand Up @@ -205,6 +206,9 @@ J9::Compilation::Compilation(int32_t id,
_serializationRecords(decltype(_serializationRecords)::allocator_type(heapMemoryRegion)),
_thunkRecords(decltype(_thunkRecords)::allocator_type(heapMemoryRegion)),
#endif /* defined(J9VM_OPT_JITSERVER) */
#if !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED)
_aotMethodDependencies(decltype(_aotMethodDependencies)::allocator_type(heapMemoryRegion)),
#endif /* !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED) */
_osrProhibitedOverRangeOfTrees(false),
_wasFearPointAnalysisDone(false)
{
Expand Down Expand Up @@ -1583,6 +1587,73 @@ J9::Compilation::canAddOSRAssumptions()
&& !self()->wasFearPointAnalysisDone();
}

#if !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED)
void
J9::Compilation::addAOTMethodDependency(TR_OpaqueClassBlock *clazz)
{
if (getOption(TR_DisableDependencyTracking))
return;

auto chainOffset = self()->fej9()->sharedCache()->rememberClass(clazz);

if (TR_SharedCache::INVALID_CLASS_CHAIN_OFFSET == chainOffset)
self()->failCompilation<J9::ClassChainPersistenceFailure>("classChainOffset == INVALID_CLASS_CHAIN_OFFSET");

addAOTMethodDependency(chainOffset, self()->fej9()->isClassInitialized(clazz));
}

void
J9::Compilation::addAOTMethodDependency(TR_OpaqueClassBlock *clazz, uintptr_t chainOffset)
{
if (getOption(TR_DisableDependencyTracking))
return;

addAOTMethodDependency(chainOffset, self()->fej9()->isClassInitialized(clazz));
}

void
J9::Compilation::addAOTMethodDependency(uintptr_t chainOffset, bool ensureClassIsInitialized)
{
TR_ASSERT(TR_SharedCache::INVALID_CLASS_CHAIN_OFFSET != chainOffset, "Attempted to remember invalid chain offset");
TR_ASSERT(self()->compileRelocatableCode(), "Must be generating AOT code");

auto it = _aotMethodDependencies.find(chainOffset);
if (it != _aotMethodDependencies.end())
it->second = it->second || ensureClassIsInitialized;
else
_aotMethodDependencies.insert(it, {chainOffset, ensureClassIsInitialized});
}

// Populate the given dependencyBuffer with dependencies of this method, in the
// format needed by TR_J9SharedCache::storeAOTMethodDependencies(). Returns the
// total number of dependencies.
uintptr_t
J9::Compilation::populateAOTMethodDependencies(TR_OpaqueClassBlock *definingClass, Vector<uintptr_t> &dependencyBuffer)
{
// TODO: Methods may be able to run before their defining class is
// initialized. Adding this back in will save a fair amount of space in the
// SCC once that's figured out.
//
// uintptr_t definingClassChainOffset = self()->fej9()->sharedCache()->rememberClass(definingClass);
// TR_ASSERT_FATAL(TR_SharedCache::INVALID_CLASS_CHAIN_OFFSET != definingClassChainOffset, "Defining class %p of an AOT-compiled method must be remembered");
// _aotMethodDependencies.erase(definingClassChainOffset);

uintptr_t totalDependencies = _aotMethodDependencies.size();
if (totalDependencies == 0)
return totalDependencies;

dependencyBuffer.reserve(totalDependencies + 1);
dependencyBuffer.push_back(totalDependencies);
for (auto &entry : _aotMethodDependencies)
{
uintptr_t encodedOffset = TR_AOTDependencyTable::encodeDependencyOffset(entry.first, entry.second);
dependencyBuffer.push_back(encodedOffset);
}

return totalDependencies;
}
#endif /* !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED) */

#if defined(J9VM_OPT_JITSERVER)
void
J9::Compilation::addSerializationRecord(const AOTCacheRecord *record, uintptr_t reloDataOffset)
Expand Down
23 changes: 21 additions & 2 deletions runtime/compiler/compile/J9Compilation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ namespace J9 { typedef J9::Compilation CompilationConnector; }
#include "env/OMRMemory.hpp"
#include "compile/AOTClassInfo.hpp"
#include "runtime/SymbolValidationManager.hpp"
#if defined(J9VM_OPT_JITSERVER)
#include "env/PersistentCollections.hpp"
#endif /* defined(J9VM_OPT_JITSERVER) */


class TR_AOTGuardSite;
Expand Down Expand Up @@ -432,6 +430,15 @@ class OMR_EXTENSIBLE Compilation : public OMR::CompilationConnector
void setOSRProhibitedOverRangeOfTrees() { _osrProhibitedOverRangeOfTrees = true; }
bool isOSRProhibitedOverRangeOfTrees() { return _osrProhibitedOverRangeOfTrees; }

#if defined(PERSISTENT_COLLECTIONS_UNSUPPORTED)
void addAOTMethodDependency(TR_OpaqueClassBlock *ramClass) {}
void addAOTMethodDependency(TR_OpaqueClassBlock *ramClass, uintptr_t chainOffset) {}
#else
void addAOTMethodDependency(TR_OpaqueClassBlock *ramClass);
void addAOTMethodDependency(TR_OpaqueClassBlock *ramClass, uintptr_t chainOffset);
uintptr_t populateAOTMethodDependencies(TR_OpaqueClassBlock *definingClass, Vector<uintptr_t> &chainBuffer);
#endif

private:
enum CachedClassPointerId
{
Expand All @@ -446,6 +453,10 @@ class OMR_EXTENSIBLE Compilation : public OMR::CompilationConnector

TR_OpaqueClassBlock *getCachedClassPointer(CachedClassPointerId which);

#if !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED)
void addAOTMethodDependency(uintptr_t offset, bool classIsInitialized);
#endif /* !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED) */

J9VMThread *_j9VMThread;

bool _doneHWProfile;
Expand Down Expand Up @@ -561,6 +572,14 @@ class OMR_EXTENSIBLE Compilation : public OMR::CompilationConnector
UnorderedSet<const AOTCacheThunkRecord *> _thunkRecords;
#endif /* defined(J9VM_OPT_JITSERVER) */

#if !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED)
// A map recording the dependencies of an AOT method. The keys are the class
// chain offsets of classes this method depends on, and the values record
// whether the class needs to be initialized before method loading, or only
// loaded.
UnorderedMap<uintptr_t, bool> _aotMethodDependencies;
#endif /* defined(PERSISTENT_COLLECTIONS_UNSUPPORTED) */

TR::SymbolValidationManager *_symbolValidationManager;
bool _osrProhibitedOverRangeOfTrees;
bool _wasFearPointAnalysisDone;
Expand Down
3 changes: 3 additions & 0 deletions runtime/compiler/control/CompilationThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8632,6 +8632,9 @@ TR::CompilationInfoPerThreadBase::wrappedCompile(J9PortLibrary *portLib, void *
options->setOption(TR_UseSymbolValidationManager, false);
}

if (!vm->canTrackAOTDependencies() || !that->_compInfo.getPersistentInfo()->getTrackAOTDependencies())
options->setOption(TR_DisableDependencyTracking);

// Adjust Options for AOT compilation
if (vm->isAOT_DEPRECATED_DO_NOT_USE())
{
Expand Down
9 changes: 9 additions & 0 deletions runtime/compiler/control/JITClientCompilationThread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3322,6 +3322,15 @@ remoteCompile(J9VMThread *vmThread, TR::Compilation *compiler, TR_ResolvedMethod
}
compiler->setIgnoringLocalSCC(aotCacheStore && compiler->getPersistentInfo()->getJITServerAOTCacheIgnoreLocalSCC());

// TODO: To support dependency tracking with the JITServer AOT cache while
// ignoring the local SCC, we would have to store the dependencies at the
// server and detect (with the help of the server's serialization records)
// when they were satisfied. More limited support also makes sense when not
// ignoring the local SCC - the dependencies would just have to be saved at
// the server so they could be sent to and stored by the client.
if (aotCacheLoad || aotCacheStore)
compiler->setOption(TR_DisableDependencyTracking);

// This thread may have been notified at some point in the past that the deserializer was reset.
// Since this is the start of a new compilation, we must clear the reset flag in order to detect
// a concurrent deserializer reset during the course of this compilation. This clearing must
Expand Down
4 changes: 2 additions & 2 deletions runtime/compiler/env/J9SharedCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1636,11 +1636,11 @@ TR_J9JITServerSharedCache::TR_J9JITServerSharedCache(TR_J9VMBase *fe)
uintptr_t
TR_J9JITServerSharedCache::rememberClass(J9Class *clazz, const AOTCacheClassChainRecord **classChainRecord, bool create)
{
TR_ASSERT_FATAL(classChainRecord || !create, "Must pass classChainRecord if creating class chain at JITServer");
TR::Compilation *comp = _compInfoPT->getCompilation();
TR_ASSERT_FATAL(classChainRecord || !create || !comp->isAOTCacheStore(), "Must pass classChainRecord if creating class chain at JITServer");
TR_ASSERT(_stream, "stream must be initialized by now");

uintptr_t clientClassChainOffset = TR_SharedCache::INVALID_CLASS_CHAIN_OFFSET;
TR::Compilation *comp = _compInfoPT->getCompilation();
ClientSessionData *clientData = comp->getClientData();
bool needClassChainRecord = comp->isAOTCacheStore();
bool useServerOffsets = clientData->useServerOffsets(_stream) && needClassChainRecord;
Expand Down
2 changes: 2 additions & 0 deletions runtime/compiler/env/VMJ9.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ class TR_J9VMBase : public TR_FrontEnd
virtual bool needsContiguousCodeAndDataCacheAllocation() { return false; }
virtual bool supportsJitMethodEntryAlignment() { return true; }
virtual bool canUseSymbolValidationManager() { return false; }
virtual bool canTrackAOTDependencies() { return false; }

/////
// Inlining optimization
Expand Down Expand Up @@ -1632,6 +1633,7 @@ class TR_J9SharedCacheVM : public TR_J9VM

// replacing calls to isAOT
virtual bool canUseSymbolValidationManager() { return true; }
virtual bool canTrackAOTDependencies() { return true; }
virtual bool supportsCodeCacheSnippets() { return false; }
virtual bool needClassAndMethodPointerRelocations() { return true; }
virtual bool inlinedAllocationsMustBeVerified() { return true; }
Expand Down
1 change: 1 addition & 0 deletions runtime/compiler/env/VMJ9Server.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ class TR_J9SharedCacheServerVM: public TR_J9ServerVM

// replacing calls to isAOT
virtual bool canUseSymbolValidationManager() override { return true; }
virtual bool canTrackAOTDependencies() override { return true; }
virtual bool supportsCodeCacheSnippets() override { return false; }
virtual bool needClassAndMethodPointerRelocations() override { return true; }
virtual bool inlinedAllocationsMustBeVerified() override { return true; }
Expand Down
Loading