Skip to content

Commit

Permalink
Add two helpers for OSR related optimizations
Browse files Browse the repository at this point in the history
- Add a helper named osrFearPointHelper to mark an OSR fear point, a
  place that has been optimized with runtime assumptions and requires
  protection of OSR points. This helper helps to locate actual fear
  points, which as part of the program can be optimized, and allows the
  separation of OSR dependant optimization and OSR guard insertion.

- Add a helper named potentialOSRPointHelper to serve as a marker of OSR
  points. Currently, OSR points consist of calls, asyncchecks and
  monitor enters. As part of the program, they can be optimized and no
  longer be identified as OSR points. However, places where they reside
  may still be OSR possible. This helper works as a bookkeeping tool to
  track place that are OSR possible.

- Fix some node APIs such that doNotProfile is set only for nodes
  created during ilgen. doNotProfile on a bytecode info is looked at by
  OSR APIs to determine if a node is created in ilgen. Only nodes
  created in ilgen will have the OSR bookkeeping  and are able to
  support OSR transition. Thus, nodes created after ILGen supposed to
  have doNotProfile set and cannot be OSR points.

Signed-off-by: Liqun Liu <liqunl@ca.ibm.com>
  • Loading branch information
Liqun Liu committed Nov 6, 2018
1 parent 3bb131c commit dce02fc
Show file tree
Hide file tree
Showing 9 changed files with 275 additions and 3 deletions.
13 changes: 12 additions & 1 deletion compiler/compile/OMRCompilation.cpp
Expand Up @@ -648,9 +648,15 @@ bool OMR::Compilation::isPotentialOSRPoint(TR::Node *node, TR::Node **osrPointNo
else if (node->getOpCode().isCall())
{
TR::SymbolReference *callSymRef = node->getSymbolReference();
if (callSymRef->getReferenceNumber() >=
if (node->isPotentialOSRPointHelperCall())
{
potentialOSRPoint = true;
}
else if (callSymRef->getReferenceNumber() >=
self()->getSymRefTab()->getNonhelperIndex(self()->getSymRefTab()->getLastCommonNonhelperSymbol()))
{
potentialOSRPoint = (disableGuardedCallOSR == NULL);
}
}
else if (node->getOpCodeValue() == TR::monent)
potentialOSRPoint = (disableMonentOSR == NULL);
Expand Down Expand Up @@ -776,6 +782,11 @@ OMR::Compilation::getOSRInductionOffset(TR::Node *node)
TR_ASSERT(0, "getOSRInductionOffset should only be called on OSR points");
}

if (osrNode->isPotentialOSRPointHelperCall())
{
return osrNode->getOSRInductionOffset();
}

if (osrNode->getOpCode().isCall())
return 3;

Expand Down
26 changes: 26 additions & 0 deletions compiler/compile/OMRSymbolReferenceTable.cpp
Expand Up @@ -1927,3 +1927,29 @@ TR_BitVector *OMR::SymbolReferenceTable::getSharedAliases(TR::SymbolReference *s

return NULL;
}

TR::SymbolReference *
OMR::SymbolReferenceTable::findOrCreatePotentialOSRPointHelperSymbolRef()
{
if (!element(potentialOSRPointHelperSymbol))
{
TR::MethodSymbol * sym = TR::MethodSymbol::create(trHeapMemory(), TR_None);
sym->setHelper();
TR::SymbolReference* symRef = new (trHeapMemory()) TR::SymbolReference(self(), potentialOSRPointHelperSymbol, sym);
element(potentialOSRPointHelperSymbol) = symRef;
}
return element(potentialOSRPointHelperSymbol);
}

TR::SymbolReference *
OMR::SymbolReferenceTable::findOrCreateOSRFearPointHelperSymbolRef()
{
if (!element(osrFearPointHelperSymbol))
{
TR::MethodSymbol * sym = TR::MethodSymbol::create(trHeapMemory(), TR_None);
sym->setHelper();
TR::SymbolReference* symRef = new (trHeapMemory()) TR::SymbolReference(self(), osrFearPointHelperSymbol, sym);
element(osrFearPointHelperSymbol) = symRef;
}
return element(osrFearPointHelperSymbol);
}
31 changes: 31 additions & 0 deletions compiler/compile/OMRSymbolReferenceTable.hpp
Expand Up @@ -146,6 +146,35 @@ class SymbolReferenceTable
osrScratchBufferSymbol, //osrScratchBuffer slot on j9vmthread
osrFrameIndexSymbol, // osrFrameIndex slot on j9vmthread
osrReturnAddressSymbol, // osrFrameIndex slot on j9vmthread

/** \brief
*
* A call with this symbol marks a place in the jitted code where OSR transition to the VM interpreter is supported.
* The transition target bytecode is the bytecode index on the call plus an induction offset which is stored on the
* call node.
*
* \code
* call <potentialOSRPointHelperSymbol>
* \endcode
*
* \note
* The call is not to be codegen evaluated, it should be cleaned up before codegen.
*/
potentialOSRPointHelperSymbol,
/** \brief
*
* A call with this symbol marks a place that has been optimized with runtime assumptions. Such place needs protection of OSR
* points. When the assumption becomes wrong, the execution of jitted code with the assumption has to be transition to the VM
* interpreter before running the invalid code.
*
* \code
* call <osrFearPointHelperSymbol>
* \endcode
*
* \note
* The call is not to be codegen evaluated, it should be cleaned up before codegen.
*/
osrFearPointHelperSymbol,
lowTenureAddressSymbol, // on j9vmthread
highTenureAddressSymbol, // on j9vmthread
fragmentParentSymbol,
Expand Down Expand Up @@ -329,6 +358,8 @@ class SymbolReferenceTable
TR::SymbolReference * findOrCreateRuntimeHelper(TR_RuntimeHelper index, bool canGCandReturn, bool canGCandExcept, bool preservesAllRegisters);

TR::SymbolReference * findOrCreateCodeGenInlinedHelper(CommonNonhelperSymbol index);
TR::SymbolReference * findOrCreatePotentialOSRPointHelperSymbolRef();
TR::SymbolReference * findOrCreateOSRFearPointHelperSymbolRef();

TR::ParameterSymbol * createParameterSymbol(TR::ResolvedMethodSymbol * owningMethodSymbol, int32_t slot, TR::DataType);
TR::SymbolReference * findOrCreateAutoSymbol(TR::ResolvedMethodSymbol * owningMethodSymbol, int32_t slot, TR::DataType, bool isReference = true,
Expand Down
33 changes: 32 additions & 1 deletion compiler/il/Aliases.cpp
Expand Up @@ -105,6 +105,33 @@ OMR::SymbolReference::getUseonlyAliasesBV(TR::SymbolReferenceTable * symRefTab)
case TR::Symbol::IsMethod:
{
TR::MethodSymbol * methodSymbol = _symbol->castToMethodSymbol();

// Aliasing for potentialOSRPointHelper
// A potentialOSRPointHelper call is an exception point that may go to OSR catch block ( see
// Node API exceptionsRaised), the control flow constraint imposed by the exception edge will
// apply to all the global optimizations that may move things around. Local optimizations also
// ask exceptionsRaised to determine if a code motion across certain point is safe. So aliasing
// is not necessary. However, we'd like to add aliasing here to cause the compiler to be more
// conservative about reordering this helper with other operations. The aliasing can always be
// relaxed when necessary.
//
if (symRefTab->isNonHelper(self(), TR::SymbolReferenceTable::potentialOSRPointHelperSymbol))
{
return &symRefTab->aliasBuilder.defaultMethodUseAliases();
}

// Aliasing for osrFearPointHelper
// Preventing the reordering of fear point helper w.r.t. OSR points and yield/invalidation points is
// the minimum requirement of aliasing for OSR fear point helper. These reorderings would in almost
// all cases be naturally disallowed simply due to the fact that the fear point is represented as a
// call, which even without aliasing could e.g. perform I/O. Thus the following is a highly conservative
// aliasing and can be relaxed later when necessary
//
if (symRefTab->isNonHelper(self(), TR::SymbolReferenceTable::osrFearPointHelperSymbol))
{
return &symRefTab->aliasBuilder.defaultMethodUseAliases();
}

if (!methodSymbol->isHelper())
{
return &symRefTab->aliasBuilder.defaultMethodUseAliases();
Expand Down Expand Up @@ -285,8 +312,12 @@ OMR::SymbolReference::getUseDefAliasesBV(bool isDirectCall, bool includeGCSafePo
if (!methodSymbol->isHelper())
return symRefTab->aliasBuilder.methodAliases(self());

if (symRefTab->isNonHelper(self(), TR::SymbolReferenceTable::arraySetSymbol))
if (symRefTab->isNonHelper(self(), TR::SymbolReferenceTable::arraySetSymbol) ||
symRefTab->isNonHelper(self(), TR::SymbolReferenceTable::osrFearPointHelperSymbol) ||
symRefTab->isNonHelper(self(), TR::SymbolReferenceTable::potentialOSRPointHelperSymbol))
{
return &symRefTab->aliasBuilder.defaultMethodDefAliases();
}

if (symRefTab->isNonHelper(self(), TR::SymbolReferenceTable::arrayCmpSymbol))
return 0;
Expand Down
93 changes: 92 additions & 1 deletion compiler/il/OMRNode.cpp
Expand Up @@ -200,6 +200,8 @@ OMR::Node::Node(TR::Node *originatingByteCodeNode, TR::ILOpCodes op, uint16_t nu
// estimate code size to be able to propagate frequencies
//else
// TR_ASSERT(0, "no byte code info");

_byteCodeInfo.setDoNotProfile(1);
}
if(comp->getDebug())
comp->getDebug()->newNode(self());
Expand Down Expand Up @@ -267,6 +269,16 @@ OMR::Node::Node(TR::Node * from, uint16_t numChildren)
if(comp->getDebug())
comp->getDebug()->newNode(self());

TR_IlGenerator * ilGen = comp->getCurrentIlGenerator();
if (ilGen)
{
_byteCodeInfo.setDoNotProfile(0);
}
else
{
_byteCodeInfo.setDoNotProfile(1);
}

if (from->getOpCode().isBranch() || from->getOpCode().isSwitch())
_byteCodeInfo.setDoNotProfile(1);

Expand Down Expand Up @@ -528,6 +540,9 @@ OMR::Node::recreateAndCopyValidPropertiesImpl(TR::Node *originalNode, TR::ILOpCo
TR_ASSERT(originalNode != NULL, "trying to recreate node from a NULL originalNode.");
if (originalNode->getOpCodeValue() == op)
{
if (!originalNode->hasSymbolReference() || newSymRef != originalNode->getSymbolReference())
originalNode->_byteCodeInfo.setDoNotProfile(1);

// need to at least set the new symbol reference on the node before returning
if (newSymRef)
originalNode->setSymbolReference(newSymRef);
Expand Down Expand Up @@ -575,6 +590,7 @@ OMR::Node::recreateAndCopyValidPropertiesImpl(TR::Node *originalNode, TR::ILOpCo

// TODO: copyValidProperties is incomplete
TR::Node::copyValidProperties(originalNodeCopy, node);
originalNode->_byteCodeInfo.setDoNotProfile(1);

// add originalNodeCopy back to the node pool
comp->getNodePool().deallocate(originalNodeCopy);
Expand Down Expand Up @@ -1192,6 +1208,38 @@ OMR::Node::createArraycopy(TR::Node *first, TR::Node *second, TR::Node * third,
}


TR::Node *
OMR::Node::createPotentialOSRPointHelperCallInILGen(TR::Node* originatingByteCodeNode, int32_t osrInductionOffset)
{
TR::Compilation* comp = TR::comp();
// The following are assertions to prevent misuses of this helper
//
TR_ASSERT(comp->getCurrentIlGenerator(), "This API must be called during ILGen");
TR_ASSERT(!comp->isPeekingMethod(), "Can not generate the helper call during peeking");
TR_ASSERT(comp->supportsInduceOSR(), "Can not create the helper without OSR support");

TR::Node* callNode = TR::Node::createWithSymRef(originatingByteCodeNode, TR::call, 0, TR::comp()->getSymRefTab()->findOrCreatePotentialOSRPointHelperSymbolRef());
callNode->setOSRInductionOffset(osrInductionOffset);

// Node created outside of ilgen will have doNotProfile set, this results in OSR infrastructure believing it
// can not OSR at this node. Reset this flag since a potentialOSRPointHelper is a safe OSR transition point
//
callNode->getByteCodeInfo().setDoNotProfile(0);
return callNode;
}

TR::Node *
OMR::Node::createOSRFearPointHelperCall(TR::Node* originatingByteCodeNode)
{
TR::Compilation* comp = TR::comp();

TR_ASSERT(!comp->isPeekingMethod(), "Can not generate the helper call during peeking");
TR_ASSERT(comp->supportsInduceOSR(), "Can not create the helper without OSR support");

TR::Node* callNode = TR::Node::createWithSymRef(originatingByteCodeNode, TR::call, 0, TR::comp()->getSymRefTab()->findOrCreateOSRFearPointHelperSymbolRef());
return callNode;
}


TR::Node *
OMR::Node::createLoad(TR::SymbolReference * symRef)
Expand Down Expand Up @@ -3599,7 +3647,7 @@ OMR::Node::exceptionsRaised()
break;
#endif
default:
if (node->getOpCode().isCall())
if (node->getOpCode().isCall() && !node->isOSRFearPointHelperCall())
{
possibleExceptions |= TR::Block::CanCatchOSR;
if (node->getSymbolReference()->canGCandExcept()
Expand Down Expand Up @@ -4042,12 +4090,16 @@ void
OMR::Node::setByteCodeInfo(const TR_ByteCodeInfo &bcInfo)
{
_byteCodeInfo = bcInfo;
if (!TR::comp()->getCurrentIlGenerator())
_byteCodeInfo.setDoNotProfile(1);
}

void
OMR::Node::copyByteCodeInfo(TR::Node * from)
{
_byteCodeInfo = from->_byteCodeInfo;
if (!TR::comp()->getCurrentIlGenerator())
_byteCodeInfo.setDoNotProfile(1);
}

uint32_t
Expand Down Expand Up @@ -8642,3 +8694,42 @@ OMR::Node::resetFlagsForCodeMotion()
/**
* Node flags functions end
*/

bool
OMR::Node::isLoadOfStaticFinalField()
{
if (self()->hasSymbolReference())
{
TR::Symbol *sym = self()->getSymbol();
if (sym->isFinal() &&
sym->isStaticField())
return true;
}
return false;
}

bool
OMR::Node::isOSRFearPointHelperCall()
{
TR::Compilation *c = TR::comp();

if (self()->getOpCode().isCall()
&& self()->getSymbol()->isMethod()
&& c->getSymRefTab()->isNonHelper(self()->getSymbolReference(), TR::SymbolReferenceTable::osrFearPointHelperSymbol))
return true;

return false;
}

bool
OMR::Node::isPotentialOSRPointHelperCall()
{
TR::Compilation *c = TR::comp();

if (self()->getOpCode().isCall()
&& self()->getSymbol()->isMethod()
&& c->getSymRefTab()->isNonHelper(self()->getSymbolReference(), TR::SymbolReferenceTable::potentialOSRPointHelperSymbol))
return true;

return false;
}
60 changes: 60 additions & 0 deletions compiler/il/OMRNode.hpp
Expand Up @@ -267,6 +267,37 @@ class OMR_EXTENSIBLE Node
static TR::Node *createArraycopy(TR::Node *first, TR::Node *second, TR::Node *third);
static TR::Node *createArraycopy(TR::Node *first, TR::Node *second, TR::Node *third, TR::Node *fourth, TR::Node *fifth);

/**
* \brief
* Create a call to potentialOSRPointHelperSymbol, only to be used during ILGen
*
* \parm originatingByteCodeNode
* The node whose bytecode info is used to create the call.
*
* \parm osrInductionOffset
* The offset to be added to the originatingByteCodeNode's bytecode index to get the
* target bytecode index. This is to be stored in _unionBase._osrInductionOffset
*
* \note
* One can not create a potentialOSRPointHelper call and stick it to anywhere in the trees
* without the right exception setup and without the right bookkeeping being in place for
* the call. Preventative checks are required to avoid potential misuses. Due the fact that
* during ILGen the OSR infrastructure may be incomplete, the checks can be done in ILGen are
* different than checks needed after ILGen.
*
* This API does checks required to create the helper in ILGen, thus it is only to be used in
* ILGen.
*/
static TR::Node *createPotentialOSRPointHelperCallInILGen(TR::Node* originatingByteCodeNode, int32_t offset);
/**
* \brief
* Create a call to osrFearPointHelperSymbol
*
* \parm originatingByteCodeNode The node whose bytecode info is used to create the call
*
*/
static TR::Node *createOSRFearPointHelperCall(TR::Node* originatingByteCodeNode);

static TR::Node *createLoad(TR::SymbolReference * symRef);
static TR::Node *createLoad(TR::Node *originatingByteCodeNode, TR::SymbolReference *);

Expand Down Expand Up @@ -499,6 +530,22 @@ class OMR_EXTENSIBLE Node

bool isClassUnloadingConst();

/**
* \brief
* Return true if the node is a load of static final field
*/
bool isLoadOfStaticFinalField();
/**
* \brief
* Return true if the node is a call with osrFearPointHelperSymbol
*/
bool isOSRFearPointHelperCall();
/**
* \brief
* Return true if the node is a call with potentialOSRPointHelperSymbol
*/
bool isPotentialOSRPointHelperCall();

// A common query used by the optimizer
inline bool isSingleRef();

Expand Down Expand Up @@ -779,6 +826,9 @@ class OMR_EXTENSIBLE Node
*/

// These three methods should be used only if you're sure you can't use one of the other ones.
inline int32_t getOSRInductionOffset();
inline int32_t setOSRInductionOffset(int32_t offset);

inline int64_t getConstValue();
inline uint64_t getUnsignedConstValue();
inline void setConstValue(int64_t val);
Expand Down Expand Up @@ -1665,6 +1715,16 @@ class OMR_EXTENSIBLE Node
float _fpConstValue;
double _dpConstValue;

// Used only on potentialOSRPointHelper call, which has no children.
//
// In post-execution OSR, transition occurs after the OSR point has
// been evaluated. The intepreter will resume the execution at a bytecode
// index after the bytecode index of the OSR point. The target bytecode
// index can be calculated by offsetting the OSR point's bytecode index
// by the size of the bytecode. This size is stored in _osrInductionOffset.
//
int32_t _osrInductionOffset;

//intToFloat returns a bag of bits in a uint32_t
int32_t _fpConstValueBits;

Expand Down

0 comments on commit dce02fc

Please sign in to comment.