Skip to content

Commit

Permalink
Stop looking for initializations at any GC point
Browse files Browse the repository at this point in the history
All null initializations of autos that might hold references to
heapified objects must happen in the entry block to the method before
any potential GC point or point at which an exception might be thrown.
The code that finds autos that have already been initialized in the
entry block and adds them to _initializedHeapifiedTemps would stop when
it encountered the first point in the entry block that might raise an
exception.  However, it failed to take into account potential GC points
in the entry block.  This change halts adding entries to
_initializedHeapifiedTemps when it encounters a GC point in the entry
block.

This change further restricts the set of autos that are added to
_initializedHeapifiedTemps to those that actually have a null reference
- that is, an aconst of zero - stored to them in the entry block.  Other
values would likely be acceptable, but just out of a sense of caution,
we'll restrict this to just those that are explicitly zero initialized.

Finally, this change includes some additional comments describing the
logic around how _initializedHeapifiedTemps is set up.

Signed-off-by:  Henry Zongaro <[email protected]>
  • Loading branch information
hzongaro committed Apr 28, 2023
1 parent 353b298 commit 5eee94c
Showing 1 changed file with 22 additions and 7 deletions.
29 changes: 22 additions & 7 deletions runtime/compiler/optimizer/EscapeAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,16 @@ int32_t TR_EscapeAnalysis::performAnalysisOnce()

if (candidate->escapesInColdBlocks())
{
// _initializedHeapifiedTemps will contain any autos that are initialized in the entry block of
// the method. When the first candidate that escapes in a cold block is encountered, sweep
// through the entry block looking for autos that are null initialized up until any potential
// GC point or point at which an exception might be thrown, and record their sym refs in
// _initializedHeapifiedTemps. Then any autos that are associated with candidates that need to
// be heapified will be explicitly null initialized in the entry block by heapifyForColdBlocks
// if they have not already been found to be initialized there (i.e., not already listed in
// _initializedHeapifiedTemps). heapifyForColdBlocks will also add a new entry to
// _initializedHeapifiedTemps for each sym ref it is obliged to explicitly null initialize.
//
if (_initializedHeapifiedTemps == NULL)
{
_initializedHeapifiedTemps = new(trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable);
Expand All @@ -1354,26 +1364,31 @@ int32_t TR_EscapeAnalysis::performAnalysisOnce()
const bool entryHasExceptionSuccessors = entryBlock->hasExceptionSuccessors();

// Anything that might hold a reference to a potentially heapified object must be initialized
// on method entry. Keep track of what is initialized in the first block on method entry to
// avoid redundant initializations that might occur in a large method that has many points at
// which heapification might occur.
// on method entry. Keep track of what is already null initialized in the first block on
// method entry to avoid redundant initializations that might occur in a large method that
// has many points at which heapification might occur.
//
for (TR::TreeTop *tt = comp()->getStartTree();
tt != NULL && tt->getNode()->getOpCodeValue() != TR::BBEnd;
tt = tt->getNextTreeTop())
{
TR::Node *node = tt->getNode();

// If the entry block has exception successors, any local initializations that follow
// If the entry block has exception successors, any null initializations that follow
// a node that might raise an exception is not guaranteed to be executed, so stop
// recording entries in _initializedHeapifiedTemps
// recording entries in _initializedHeapifiedTemps. Similarly, we need to ensure that
// all local initializations of autos that might hold a reference to a potentially
// heapified object are initialized before any GC might happen, so stop considering
// local initializations that follow a potential GC point.
//
if (entryHasExceptionSuccessors && node->exceptionsRaised())
if (node->canCauseGC() || entryHasExceptionSuccessors && node->exceptionsRaised())
{
break;
}

if (node->getOpCode().isStore() && !node->getOpCode().isIndirect())
if (node->getOpCode().isStoreDirect()
&& (node->getFirstChild()->getOpCodeValue() == TR::aconst)
&& (node->getFirstChild()->getConstValue() == 0))
{
TR::SymbolReference *storeSymRef = node->getSymbolReference();

Expand Down

0 comments on commit 5eee94c

Please sign in to comment.