Skip to content

Commit e3451a2

Browse files
authored
Merge pull request #21216 from jdmpapin/retained-method-set
Prevent JIT bodies from strictly outliving methods inlined into them
2 parents 37e96b4 + 90bbfe8 commit e3451a2

30 files changed

+1785
-31
lines changed

runtime/compiler/build/files/common.mk.ftl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ JIT_PRODUCT_BACKEND_SOURCES+=\
125125
omr/compiler/env/OMRDebugEnv.cpp \
126126
omr/compiler/env/OMRObjectModel.cpp \
127127
omr/compiler/env/OMRPersistentInfo.cpp \
128+
omr/compiler/env/OMRRetainedMethodSet.cpp \
128129
omr/compiler/env/OMRVMEnv.cpp \
129130
omr/compiler/env/Region.cpp \
130131
omr/compiler/env/SegmentAllocator.cpp \
@@ -306,6 +307,7 @@ JIT_PRODUCT_SOURCE_FILES+=\
306307
compiler/env/J9KnownObjectTable.cpp \
307308
compiler/env/J9ObjectModel.cpp \
308309
compiler/env/J9PersistentInfo.cpp \
310+
compiler/env/J9RetainedMethodSet.cpp \
309311
compiler/env/J9SegmentAllocator.cpp \
310312
compiler/env/J9SegmentCache.cpp \
311313
compiler/env/J9SegmentProvider.cpp \

runtime/compiler/codegen/J9CodeGenerator.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include "env/VMJ9.h"
4646
#include "env/jittypes.h"
4747
#include "env/j9method.h"
48+
#include "env/OMRRetainedMethodSet.hpp"
4849
#include "il/AutomaticSymbol.hpp"
4950
#include "il/Block.hpp"
5051
#include "il/LabelSymbol.hpp"
@@ -4807,11 +4808,13 @@ bool
48074808
J9::CodeGenerator::mustGenerateSwitchToInterpreterPrePrologue()
48084809
{
48094810
TR::Compilation *comp = self()->comp();
4811+
TR_ResolvedMethod *bondMethod = NULL;
48104812

48114813
return comp->usesPreexistence() ||
48124814
comp->getOption(TR_EnableHCR) ||
48134815
!comp->fej9()->isAsyncCompilation() ||
4814-
comp->getOption(TR_FullSpeedDebug);
4816+
comp->getOption(TR_FullSpeedDebug) ||
4817+
comp->retainedMethods()->bondMethods().next(&bondMethod);
48154818
}
48164819

48174820
extern void VMgenerateCatchBlockBBStartPrologue(TR::Node *node, TR::Instruction *fenceInstruction, TR::CodeGenerator *cg);

runtime/compiler/compile/J9Compilation.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "control/RecompilationInfo.hpp"
4444
#include "env/ClassLoaderTable.hpp"
4545
#include "env/j9method.h"
46+
#include "env/J9RetainedMethodSet.hpp"
4647
#include "env/TRMemory.hpp"
4748
#include "env/VMJ9.h"
4849
#include "env/VMAccessCriticalSection.hpp"
@@ -186,6 +187,7 @@ J9::Compilation::Compilation(int32_t id,
186187
_j9VMThread(j9vmThread),
187188
_monitorAutos(m),
188189
_monitorAutoSymRefsInCompiledMethod(getTypedAllocator<TR::SymbolReference*>(self()->allocator())),
190+
_keepaliveClasses(heapMemoryRegion),
189191
_classForOSRRedefinition(m),
190192
_classForStaticFinalFieldModification(m),
191193
_profileInfo(NULL),
@@ -232,6 +234,10 @@ J9::Compilation::Compilation(int32_t id,
232234
for (int i = 0; i < CACHED_CLASS_POINTER_COUNT; i++)
233235
_cachedClassPointers[i] = NULL;
234236

237+
if (!self()->ilGenRequest().details().supportsInvalidation())
238+
{
239+
self()->getOptions()->setOption(TR_DontInlineUnloadableMethods);
240+
}
235241

236242
// Add known object index to parm 0 so that other optmizations can be unlocked.
237243
// It is safe to do so because method and method symbols of a archetype specimen
@@ -1707,6 +1713,75 @@ J9::Compilation::populateAOTMethodDependencies(TR_OpaqueClassBlock *definingClas
17071713
}
17081714
#endif /* !defined(PERSISTENT_COLLECTIONS_UNSUPPORTED) */
17091715

1716+
OMR::RetainedMethodSet *
1717+
J9::Compilation::createRetainedMethods(TR_ResolvedMethod *method)
1718+
{
1719+
#if defined(J9VM_OPT_JITSERVER)
1720+
if (self()->isRemoteCompilation())
1721+
{
1722+
TR_ASSERT_FATAL(false, "client must not use Compilation::retainedMethods()");
1723+
}
1724+
#endif
1725+
1726+
if (self()->mustTrackRetainedMethods())
1727+
{
1728+
return J9::RetainedMethodSet::create(self(), method);
1729+
}
1730+
else
1731+
{
1732+
return OMR::Compilation::createRetainedMethods(method);
1733+
}
1734+
}
1735+
1736+
bool
1737+
J9::Compilation::mustTrackRetainedMethods()
1738+
{
1739+
if (self()->compileRelocatableCode())
1740+
{
1741+
// AOT: Relationships between class loaders seen at compile time won't
1742+
// necessarily still hold at load time, so there's no point in tracking
1743+
// retained method sets. At load, the inlining table will be available,
1744+
// and bonds will be created as needed.
1745+
return false;
1746+
}
1747+
1748+
if (self()->getOption(TR_NoClassGC))
1749+
{
1750+
return false;
1751+
}
1752+
1753+
return !self()->getOption(TR_AllowJitBodyToOutliveInlinedCode)
1754+
|| self()->getOption(TR_DontInlineUnloadableMethods);
1755+
}
1756+
1757+
const char *
1758+
J9::Compilation::bondMethodsTraceNote()
1759+
{
1760+
#if defined(J9VM_OPT_JITSERVER)
1761+
TR_ResolvedMethod *m = NULL;
1762+
if (self()->isOutOfProcessCompilation()
1763+
&& self()->mustTrackRetainedMethods()
1764+
&& self()->retainedMethods()->bondMethods().next(&m))
1765+
{
1766+
return "approximate; client may find a more precise (smaller) set";
1767+
}
1768+
#endif
1769+
1770+
return NULL;
1771+
}
1772+
1773+
void
1774+
J9::Compilation::addKeepaliveClass(TR_OpaqueClassBlock *c)
1775+
{
1776+
_keepaliveClasses.insert(c);
1777+
if (self()->getOption(TR_TraceRetainedMethods))
1778+
{
1779+
int32_t len;
1780+
const char *name = TR::Compiler->cls.classNameChars(self(), c, len);
1781+
traceMsg(self(), "Added global keepalive class %p %.*s\n", c, len, name);
1782+
}
1783+
}
1784+
17101785
#if defined(J9VM_OPT_JITSERVER)
17111786
void
17121787
J9::Compilation::addSerializationRecord(const AOTCacheRecord *record, uintptr_t reloDataOffset)

runtime/compiler/compile/J9Compilation.hpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ namespace J9 { typedef J9::Compilation CompilationConnector; }
3737
#include "compile/CompilationTypes.hpp"
3838
#include "control/Options.hpp"
3939
#include "control/Options_inlines.hpp"
40+
#include "infra/set.hpp"
4041
#include "infra/Statistics.hpp"
4142
#include "infra/vector.hpp"
4243
#include "env/CompilerEnv.hpp"
@@ -45,7 +46,7 @@ namespace J9 { typedef J9::Compilation CompilationConnector; }
4546
#include "runtime/SymbolValidationManager.hpp"
4647
#include "env/PersistentCollections.hpp"
4748

48-
49+
namespace J9 { class RetainedMethodSet; }
4950
class TR_AOTGuardSite;
5051
class TR_FrontEnd;
5152
class TR_ResolvedMethod;
@@ -397,6 +398,52 @@ class OMR_EXTENSIBLE Compilation : public OMR::CompilationConnector
397398

398399
TR::SymbolValidationManager *getSymbolValidationManager() { return _symbolValidationManager; }
399400

401+
// overrides OMR::Compilation::createRetainedMethods(TR_ResolvedMethod*)
402+
OMR::RetainedMethodSet *createRetainedMethods(TR_ResolvedMethod *method);
403+
404+
/**
405+
* \brief Determine whether retained methods need to be tracked.
406+
*
407+
* If they do, then J9::RetainedMethodSet will be used. Otherwise, the base
408+
* OMR::RetainedMethodSet will be used instead, which does no tracking.
409+
*
410+
* \return true if tracking is needed, false otherwise
411+
*/
412+
bool mustTrackRetainedMethods();
413+
414+
// overrides OMR::Compilation::bondMethodsTraceNote().
415+
const char *bondMethodsTraceNote();
416+
417+
/**
418+
* \brief Get the set of classes to keep alive.
419+
*
420+
* During optimization, these are classes that should be kept alive due to
421+
* IL transformations, as opposed to the keepalives in retainedMethods(),
422+
* which are due to inlining. They are kept separately because the API of
423+
* OMR::RetainedMethodSet is designed to avoid assuming that unloading
424+
* proceeds at any granularity coarser than per-method.
425+
*
426+
* \return the set of classes to keep alive
427+
*/
428+
const TR::set<TR_OpaqueClassBlock*> &keepaliveClasses() { return _keepaliveClasses; }
429+
430+
/**
431+
* \brief Add a keepalive class.
432+
*
433+
* This is only for cases where an IL transformation based on known objects
434+
* causes the IL to directly use a class (i.e. with loadaddr) or one of
435+
* its members, when it didn't previously. After such a transformation, the
436+
* known objects could end up being unused, in which case they wouldn't
437+
* guarantee on their own that the class remains loaded at the point of use.
438+
*
439+
* If the IL is modified to use a member that will necessarily remain loaded
440+
* at the point of use anyway, e.g. an instance method, then no keepalive is
441+
* needed.
442+
*
443+
* \param c the class to keep alive
444+
*/
445+
void addKeepaliveClass(TR_OpaqueClassBlock *c);
446+
400447
/**
401448
* \brief Determine whether it's currently expected to be possible to add
402449
* OSR assumptions and corresponding fear points somewhere in the method.
@@ -525,6 +572,8 @@ class OMR_EXTENSIBLE Compilation : public OMR::CompilationConnector
525572
TR_Array<List<TR::RegisterMappedSymbol> *> _monitorAutos;
526573
TR::list<TR::SymbolReference*> _monitorAutoSymRefsInCompiledMethod;
527574

575+
TR::set<TR_OpaqueClassBlock*> _keepaliveClasses;
576+
528577
TR_Array<TR_OpaqueClassBlock*> _classForOSRRedefinition;
529578
// Classes that have their static final fields folded and need assumptions
530579
TR_Array<TR_OpaqueClassBlock*> _classForStaticFinalFieldModification;

runtime/compiler/control/CompilationThread.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8919,6 +8919,15 @@ TR::CompilationInfoPerThreadBase::wrappedCompile(J9PortLibrary *portLib, void *
89198919
methodInfo->incrementNumberOfInlinedMethodRedefinition();
89208920
if (methodInfo->getNumberOfInlinedMethodRedefinition() >= 2)
89218921
options->setOption(TR_DisableNextGenHCR);
8922+
8923+
// If this method has been invalidated due to unloading of
8924+
// inlined code, then from now on we should only inline
8925+
// methods that will not be unloaded before this one.
8926+
auto invReasons = methodInfo->invalidationReasons();
8927+
if (invReasons.contains(TR_JitBodyInvalidations::Unloading))
8928+
{
8929+
options->setOption(TR_DontInlineUnloadableMethods);
8930+
}
89228931
}
89238932
}
89248933

runtime/compiler/control/J9Recompilation.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "compile/Compilation.hpp"
3131
#include "control/Options.hpp"
3232
#include "compile/SymbolReferenceTable.hpp"
33+
#include "env/OMRRetainedMethodSet.hpp"
3334
#include "env/VMJ9.h"
3435
#include "env/VerboseLog.hpp"
3536
#include "runtime/J9Profiler.hpp"
@@ -456,10 +457,12 @@ J9::Recompilation::createProfilers()
456457
bool
457458
J9::Recompilation::couldBeCompiledAgain()
458459
{
460+
TR_ResolvedMethod *bondMethod = NULL;
459461
return
460462
self()->shouldBeCompiledAgain() ||
461463
_compilation->usesPreexistence() ||
462-
_compilation->getOption(TR_EnableHCR);
464+
_compilation->getOption(TR_EnableHCR) ||
465+
_compilation->retainedMethods()->bondMethods().next(&bondMethod);
463466
}
464467

465468

runtime/compiler/control/JITClientCompilationThread.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "env/j9methodServer.hpp"
3636
#include "env/JITServerPersistentCHTable.hpp"
3737
#include "env/JSR292Methods.h"
38+
#include "env/J9RetainedMethodSet.hpp"
3839
#include "env/StackMemoryRegion.hpp"
3940
#include "env/TypeLayout.hpp"
4041
#include "env/ut_j9jit.h"
@@ -3944,7 +3945,7 @@ remoteCompile(J9VMThread *vmThread, TR::Compilation *compiler, TR_ResolvedMethod
39443945
}
39453946
}
39463947

3947-
if (!compiler->getOption(TR_DisableCHOpts) && !useAotCompilation && (compiler->isDeserializedAOTMethodStore() || !compiler->isDeserializedAOTMethod()))
3948+
if (!useAotCompilation && (compiler->isDeserializedAOTMethodStore() || !compiler->isDeserializedAOTMethod()))
39483949
{
39493950
TR::ClassTableCriticalSection commit(compiler->fe());
39503951

runtime/compiler/control/JITServerCompilationThread.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,8 +138,11 @@ outOfProcessCompilationEnd(TR_MethodToBeCompiled *entry, TR::Compilation *comp)
138138
std::string codeCacheStr((const char *)codeCacheHeader, codeSize);
139139
std::string dataCacheStr((const char *)dataCacheHeader, dataSize);
140140

141+
// The CH table commit data may be needed even if TR_DisableCHOpts is set,
142+
// because if there were bonds, it may be necessary for the client's CH
143+
// table commit to create unload assumptions.
141144
CHTableCommitData chTableData;
142-
if (!comp->getOption(TR_DisableCHOpts) && !entry->_useAotCompilation)
145+
if (!entry->_useAotCompilation)
143146
{
144147
TR_CHTable *chTable = comp->getCHTable();
145148
chTableData = chTable->computeDataForCHTableCommit(comp);

runtime/compiler/control/RecompilationInfo.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ class TR_JitBodyInvalidations
7878
HCR, // outermost method has been obsoleted by HCR
7979
Preexistence, // preexistence assumption has been invalidated
8080
PostRestoreExclude, // method is excluded post-restore, should be interpreted
81+
Unloading, // an inlined method has been unloaded
8182
};
8283

8384
bool isEmpty() const { return _flags.getValue() == 0; }

0 commit comments

Comments
 (0)