Skip to content

Commit

Permalink
Update documentation for Unsafe.get()/put() to reflect changes
Browse files Browse the repository at this point in the history
made to accommodate cases where offheap allocation is enabled.

Signed-off-by: midronij <[email protected]>
  • Loading branch information
midronij committed Jul 9, 2024
1 parent cf73c72 commit 8ecd372
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 28 deletions.
50 changes: 24 additions & 26 deletions runtime/compiler/optimizer/InlinerTempForJ9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ TR_J9InlinerPolicy::genCodeForUnsafeGetPut(TR::Node* unsafeAddress,

// If low-order bit of offset is set, perform indirect access. In both cases where
// a runtime lowtag check is needed (CASES 1 and 2), the direct access code is placed
// on the fallthrough path, so it will ALWAYS need to take the branch to the indirect
// on the fallthrough path, so it will ALWAYS need to take the branch to the indirect
// access block if the bit is set.

TR::TreeTop *lowTagCmpTree = checksNeeded ? // CASES (1) and (2)
Expand Down Expand Up @@ -938,7 +938,7 @@ TR_J9InlinerPolicy::genCodeForUnsafeGetPut(TR::Node* unsafeAddress,


TR::Block *joinBlock = NULL;

if (checksNeeded || arrayBlockNeeded) // CASES (1), (2), (3)
{
joinBlock = createUnsafeGetPutCallDiamond(callNodeTreeTop, firstComparisonTree, branchTargetTree, fallThroughTree);
Expand All @@ -952,7 +952,7 @@ TR_J9InlinerPolicy::genCodeForUnsafeGetPut(TR::Node* unsafeAddress,
callNodeTreeTop->getNode()->removeAllChildren();
callNodeTreeTop->getPrevTreeTop()->join(callNodeTreeTop->getNextTreeTop());
}

TR::Block *beforeCallBlock = prevTreeTop->getEnclosingBlock();

TR::Block *arrayDirectAccessBlock = NULL;
Expand Down Expand Up @@ -1011,7 +1011,7 @@ TR_J9InlinerPolicy::genCodeForUnsafeGetPut(TR::Node* unsafeAddress,
}

debugTrace(tracer(), "\t In genCodeForUnsafeGetPut, directAccessBlock is %d\n", directAccessBlock->getNumber());
if (indirectAccessBlock)
if (indirectAccessBlock)
debugTrace(tracer(), "\t In genCodeForUnsafeGetPut, indirectAccessBlock is %d\n", indirectAccessBlock->getNumber());

createAnchorNodesForUnsafeGetPut(directAccessTreeTop, type, isUnsafeGet);
Expand Down Expand Up @@ -1049,7 +1049,7 @@ TR_J9InlinerPolicy::genCodeForUnsafeGetPut(TR::Node* unsafeAddress,
isArrayBlock->append(isArrayTreeTop);
cfg->addNode(isArrayBlock);
isArrayNode->setBranchDestination(arrayDirectAccessBlock->getEntry());

directAccessBlock->getEntry()->insertTreeTopsBeforeMe(lowTagCmpBlock->getEntry(), lowTagCmpBlock->getExit());
lowTagCmpTree->getNode()->setBranchDestination(indirectAccessBlock->getEntry());

Expand Down Expand Up @@ -1119,7 +1119,7 @@ TR_J9InlinerPolicy::genCodeForUnsafeGetPut(TR::Node* unsafeAddress,

if (arrayCheckNeeded && arrayBlockNeeded)
cfg->removeEdge(nullComparisonBlock, arrayDirectAccessBlock);

if (needNullCheck)
{
TR::TreeTop *treeBeforeCmp = firstComparisonTree ? firstComparisonTree->getPrevTreeTop() : beforeCallBlock->getExit()->getPrevTreeTop();
Expand Down Expand Up @@ -1156,6 +1156,9 @@ b) whether the object is array
c) whether the object is of type java.lang.Class (which might involve testing the
low-order bit of the offset or comparing the <vft-symbol> of the object)
When the type of the object is unknown at compile time, several runtime checks will be
generated to determine which type of read/write should be used.
The pseudocode of the generated inline code for case (1) under normal compilation is :
if (offset is low-tagged)
Expand All @@ -1167,7 +1170,8 @@ The pseudocode of the generated inline code for case (1) under normal compilatio
else
use indirect access
If we cannot get the J9Class of java/lang/Class, we generate following sequence of tests:
If we cannot get the J9Class of java/lang/Class OR if offheap allocation and balanced GC policy is
in use, we generate following sequence of tests:
if (object == NULL)
use direct access
Expand Down Expand Up @@ -1242,7 +1246,7 @@ TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSy


bool conversionNeeded = comp()->fe()->dataTypeForLoadOrStore(type) != type;

// If we are not able to get javaLangClass it is still inefficient to put direct Access far
// So in that case we will generate lowTagCmpTest to branch to indirect access if true
TR_OpaqueClassBlock *javaLangClass = comp()->getClassClassPointer(/* isVettedForAOT = */ true);
Expand Down Expand Up @@ -1373,7 +1377,7 @@ TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSy
}

// We need to generate an arrayDirectAccessBlock AND a directAccessBlock in the following cases:
// 1.) arrayCheckNeeded == true: arrayDirectAccessBlock used for array access,
// 1.) arrayCheckNeeded == true: arrayDirectAccessBlock used for array access,
// directAccessBlock used for non-array/non-class object access
// 2.) !arrayCheckNeeded && arrayBlockNeeded: arrayDirectAccessBlock used for array access,
// directAccessBlock used if object is NULL
Expand Down Expand Up @@ -1429,8 +1433,6 @@ TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSy

if (TR::Compiler->om.isOffHeapAllocationEnabled() && arrayBlockNeeded)
{
J9JavaVM *vm = comp()->fej9()->getJ9JITConfig()->javaVM;

TR::Node *addrToAccessNode = arrayDirectAccessTreeTop->getNode()->getChild(0);

//change object base address to dataAddr
Expand All @@ -1442,8 +1444,8 @@ TR_J9InlinerPolicy::createUnsafePutWithOffset(TR::ResolvedMethodSymbol *calleeSy
objBaseAddrNode->decReferenceCount();
dataAddrNode->incReferenceCount();
}
#endif /* TR_TARGET_64BIT */
#endif /* J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION */

genCodeForUnsafeGetPut(unsafeAddress, offset, type, callNodeTreeTop,
prevTreeTop, newSymbolReferenceForAddress,
directAccessTreeTop, arrayDirectAccessTreeTop,
Expand Down Expand Up @@ -1551,11 +1553,11 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
// (A low tagged offset value means the object being passed in is a java/lang/Class object, and we want a static field)

// Regarding which checks/diamonds get generated, there are three possible cases:
// 1.) Only the low tagged check is generated. This will occur either when gencon GC policy is being used, or under
// balanced GC policy with offheap allocation enabled if the object being operated on is known NOT to be an array
// 1.) Only the low tagged check is generated. This will occur either when gencon GC policy is being used, or under
// balanced GC policy with offheap allocation enabled if the object being operated on is known NOT to be an array
// at compile time.
// 2.) No checks are generated. This will occur under balanced GC policy with offheap allocation enabled if the object
// being operated on is known to be an array at compile time (since if the object is an array, it can't also be a
// being operated on is known to be an array at compile time (since if the object is an array, it can't also be a
// java/lang/Class object).
// 3.) Both the array and low tagged checks are generated. This will occur under balanced GC policy with offheap allocation
// enabled if the type of the object being operated on is unknown at compile time.
Expand Down Expand Up @@ -1587,15 +1589,15 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
bool arrayCheckNeeded = TR::Compiler->om.isOffHeapAllocationEnabled() && comp()->target().is64Bit() && objTypeUnknown;

//only generate separate array access block in cases (2) or (3)
bool arrayBlockNeeded = TR::Compiler->om.isOffHeapAllocationEnabled() && comp()->target().is64Bit() &&
bool arrayBlockNeeded = TR::Compiler->om.isOffHeapAllocationEnabled() && comp()->target().is64Bit() &&
(arrayCheckNeeded || objTypeSig[0] == '[');

createTempsForUnsafeCall(callNodeTreeTop, callNode);

TR::Node *offsetNode = callNode->getChild(2);

TR::TreeTop *compareTree;

//do not generate low tagged check in case (2)
if (!arrayCheckNeeded && arrayBlockNeeded)
compareTree = NULL;
Expand Down Expand Up @@ -1644,8 +1646,6 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
// lload -> offset
// lload -> value to compare against
// lload -> value to swap in

J9JavaVM *vm = comp()->fej9()->getJ9JITConfig()->javaVM;

arrayAccessTreeTop = TR::TreeTop::create(comp(),callNodeTreeTop->getNode()->duplicateTree());
TR::Node *CASicallNode = arrayAccessTreeTop->getNode()->getChild(0);
Expand Down Expand Up @@ -1709,14 +1709,14 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
callBlock->createConditionalBlocksBeforeTree(callNodeTreeTop, isArrayTreeTop, arrayAccessTreeTop, nonArrayAccessTreeTop, comp()->getFlowGraph(), false, false);
nonArrayAccessTreeTop->getEnclosingBlock()->createConditionalBlocksBeforeTree(nonArrayAccessTreeTop, compareTree, branchTargetTree, fallThroughTree, comp()->getFlowGraph(), false, false);
}
else if (arrayBlockNeeded) //in case (2), no branching is needed: we simply need to replace the original CAS call with the modified array access block
else if (arrayBlockNeeded) //in case (2), no branching is needed: we simply need to replace the original CAS call with the modified array access block
{
callNodeTreeTop->insertAfter(arrayAccessTreeTop);
callNodeTreeTop->getPrevTreeTop()->join(callNodeTreeTop->getNextTreeTop());
callBlock->split(arrayAccessTreeTop->getNextTreeTop(), comp()->getFlowGraph(), true);
callBlock->split(arrayAccessTreeTop, comp()->getFlowGraph(), true);
}
else if (compareTree != NULL) //in case (1), we only generate the low tagged check diamond
else if (compareTree != NULL) //in case (1), we only generate the low tagged check diamond
callBlock->createConditionalBlocksBeforeTree(callNodeTreeTop, compareTree, branchTargetTree, fallThroughTree, comp()->getFlowGraph(), false, false);


Expand Down Expand Up @@ -1904,7 +1904,7 @@ TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSy
genDirectAccessCodeForUnsafeGetPut(callNodeTreeTop->getNode(), false, true);

// We need to generate an arrayDirectAccessBlock AND a directAccessBlock in the following cases:
// 1.) arrayCheckNeeded == true: arrayDirectAccessBlock used for array access,
// 1.) arrayCheckNeeded == true: arrayDirectAccessBlock used for array access,
// directAccessBlock used for non-array/non-class object access
// 2.) !arrayCheckNeeded && arrayBlockNeeded: arrayDirectAccessBlock used for array access,
// directAccessBlock used if object is NULL
Expand Down Expand Up @@ -1942,8 +1942,6 @@ TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSy

if (TR::Compiler->om.isOffHeapAllocationEnabled() && arrayBlockNeeded)
{
J9JavaVM *vm = comp()->fej9()->getJ9JITConfig()->javaVM;

TR::Node *addrToAccessNode;

if (conversionNeeded) //CASE 1
Expand All @@ -1955,7 +1953,7 @@ TR_J9InlinerPolicy::createUnsafeGetWithOffset(TR::ResolvedMethodSymbol *calleeSy
TR::Node *objBaseAddrNode = addrToAccessNode->getChild(0);
TR::Node *dataAddrNode = TR::TransformUtil::generateDataAddrLoadTrees(comp(), objBaseAddrNode);
addrToAccessNode->setChild(0, dataAddrNode);

//correct refcounts
objBaseAddrNode->decReferenceCount();
dataAddrNode->incReferenceCount();
Expand Down
4 changes: 2 additions & 2 deletions runtime/compiler/optimizer/J9Inliner.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -310,12 +310,12 @@ class TR_J9InlinerPolicy : public OMR_InlinerPolicy
* \param isUnsafeGet A \bool value indicating whether the call represents an
* \c Unsafe.get* operation &mdash; \c true &mdash; or an
* \c Unsafe.put* operation &mdash; \c false.
* \param conversionNeeded Indicates whether the call reprents an \c Unsafe
* \param conversionNeeded Indicates whether the call represents an \c Unsafe
* method call involving any of Java \c char, \c short, \c byte or
* \c boolean.
* \param arrayCheckNeeded Indicates whether an array check needs to be generated
* for the type of the \c Object
* \param arrayBlockNeeded Indicates whether a separate access block needs to be
* \param arrayBlockNeeded Indicates whether a separate access block needs to be
* generated to handle the case where the \c Object is an array
* \param checksNeeded Indicates whether any type checks for \c Object need to
* be generated (i.e.: if the type of the \c Object is unknown)
Expand Down

0 comments on commit 8ecd372

Please sign in to comment.