@@ -1710,15 +1710,19 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
1710
1710
// Codegens have a fast path for the compare and swaps, but cannot deal with the case where the offset value passed in to a the CAS is low tagged
1711
1711
// (A low tagged offset value means the object being passed in is a java/lang/Class object, and we want a static field)
1712
1712
1713
- // Regarding which checks/diamonds get generated, there are three possible cases:
1713
+ // Regarding which type checks/diamonds get generated, there are three possible cases:
1714
1714
// 1.) Only the low tagged check is generated. This will occur either when gencon GC policy is being used, or under
1715
1715
// balanced GC policy with offheap allocation enabled if the object being operated on is known NOT to be an array
1716
1716
// at compile time.
1717
- // 2.) No checks are generated. This will occur under balanced GC policy with offheap allocation enabled if the object
1717
+ // 2.) No type checks are generated. This will occur under balanced GC policy with offheap allocation enabled if the object
1718
1718
// 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
1719
1719
// java/lang/Class object).
1720
1720
// 3.) Both the array and low tagged checks are generated. This will occur under balanced GC policy with offheap allocation
1721
1721
// enabled if the type of the object being operated on is unknown at compile time.
1722
+ //
1723
+ // In addition to type checks, a NULL check on the object address is needed to ensure that we do not try to load dataAddr
1724
+ // from a NULL reference. This is only a concern when offheap is enabled AND there is a possibility that the object is an array.
1725
+ // so the NULL check will only be generated in cases (2) and (3).
1722
1726
1723
1727
// This method assumes the offset node is of type long, and is the second child of the unsafe call.
1724
1728
TR_InlinerDelimiter delimiter (tracer ()," createUnsafeCASCallDiamond" );
@@ -1759,14 +1763,25 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
1759
1763
1760
1764
TR::Node *offsetNode = callNode->getChild (2 );
1761
1765
1762
- TR::TreeTop *compareTree;
1766
+ TR::TreeTop *compareTree = NULL ;
1767
+ TR::TreeTop *lowTagAccessTreeTop = NULL ;
1763
1768
1764
- // do not generate low tagged test in case (2 )
1765
- if (! arrayTestNeeded && arrayBlockNeeded)
1766
- compareTree = NULL ;
1767
- else
1769
+ // generate low tagged test/access block in cases (1) and (3 )
1770
+ if (arrayTestNeeded || ! arrayBlockNeeded)
1771
+ {
1772
+ // create lowtag test treetop
1768
1773
compareTree = genClassCheckForUnsafeGetPut (offsetNode, /* branchIfLowTagged */ false );
1769
1774
1775
+ // create lowtag access treetop
1776
+ lowTagAccessTreeTop = TR::TreeTop::create (comp (),callNodeTreeTop->getNode ()->duplicateTree ());
1777
+ lowTagAccessTreeTop->getNode ()->getFirstChild ()->setVisitCount (_inliner->getVisitCount ());
1778
+
1779
+ debugTrace (tracer ()," lowTagAccessTreeTop = %p" ,lowTagAccessTreeTop->getNode ());
1780
+ }
1781
+
1782
+
1783
+ TR::TreeTop *isNullTreeTop = NULL ;
1784
+ TR::TreeTop *nonNullAccessTreeTop = NULL ;
1770
1785
TR::TreeTop *isArrayTreeTop = NULL ;
1771
1786
TR::TreeTop *arrayAccessTreeTop = NULL ;
1772
1787
TR::TreeTop *nonArrayAccessTreeTop = NULL ;
@@ -1824,31 +1839,19 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
1824
1839
1825
1840
CASicallNode->setIsSafeForCGToFastPathUnsafeCall (true );
1826
1841
1827
- // if array test is being generated, need to create non-array access treetop (same as default)
1828
- if (isArrayTreeTop)
1829
- nonArrayAccessTreeTop = TR::TreeTop::create (comp (),callNodeTreeTop->getNode ()->duplicateTree ());
1842
+ // create NULL test treetop
1843
+ TR::Node *objAddr = callNodeTreeTop->getNode ()->getChild (0 )->getChild (1 );
1844
+ TR::Node *isNullNode = TR::Node::createif (TR::ifacmpeq, objAddr, TR::Node::create (objAddr, TR::aconst, 0 , 0 ), NULL );
1845
+ isNullTreeTop = TR::TreeTop::create (comp (), isNullNode);
1830
1846
}
1831
1847
#endif /* J9VM_GC_ENABLE_SPARSE_HEAP_ALLOCATION */
1832
1848
1833
- TR::TreeTop *branchTargetTree;
1834
- TR::TreeTop *fallThroughTree;
1835
-
1836
- // only generate if and else trees for low tagged test in cases (1) and (3)
1837
- if (compareTree != NULL )
1838
- {
1839
- // genClassCheck generates a ifcmpne offset&mask 1, meaning if it is NOT
1840
- // lowtagged (ie offset&mask == 0), the branch will be taken
1841
- branchTargetTree = TR::TreeTop::create (comp (),callNodeTreeTop->getNode ()->duplicateTree ());
1842
- branchTargetTree->getNode ()->getFirstChild ()->setIsSafeForCGToFastPathUnsafeCall (true );
1843
-
1844
- fallThroughTree = TR::TreeTop::create (comp (),callNodeTreeTop->getNode ()->duplicateTree ());
1845
-
1849
+ // default access tree (non-array, non-lowtagged)
1850
+ TR::TreeTop *defaultAccessTreeTop = TR::TreeTop::create (comp (),callNodeTreeTop->getNode ()->duplicateTree ());
1851
+ defaultAccessTreeTop->getNode ()->getFirstChild ()->setIsSafeForCGToFastPathUnsafeCall (true );
1852
+ defaultAccessTreeTop->getNode ()->getFirstChild ()->setVisitCount (_inliner->getVisitCount ());
1846
1853
1847
- branchTargetTree->getNode ()->getFirstChild ()->setVisitCount (_inliner->getVisitCount ());
1848
- fallThroughTree->getNode ()->getFirstChild ()->setVisitCount (_inliner->getVisitCount ());
1849
-
1850
- debugTrace (tracer ()," branchTargetTree = %p fallThroughTree = %p" ,branchTargetTree->getNode (),fallThroughTree->getNode ());
1851
- }
1854
+ debugTrace (tracer ()," defaultAccessTreeTop = %p" , defaultAccessTreeTop->getNode ());
1852
1855
1853
1856
1854
1857
// the call itself may be commoned, so we need to create a temp for the callnode itself
@@ -1867,43 +1870,65 @@ TR_J9InlinerPolicy::createUnsafeCASCallDiamond( TR::TreeTop *callNodeTreeTop, TR
1867
1870
1868
1871
TR::Block *callBlock = callNodeTreeTop->getEnclosingBlock ();
1869
1872
1870
- if (arrayTestNeeded) // in case (3), we generate the array test diamond, followed by the low tagged check test
1873
+ if (arrayTestNeeded) // in case (3), we generate the null test diamond, then the array test diamond, and then the low tagged test diamond
1871
1874
{
1872
- callBlock->createConditionalBlocksBeforeTree (callNodeTreeTop, isArrayTreeTop, arrayAccessTreeTop, nonArrayAccessTreeTop, comp ()->getFlowGraph (), false , false );
1873
- nonArrayAccessTreeTop->getEnclosingBlock ()->createConditionalBlocksBeforeTree (nonArrayAccessTreeTop, compareTree, branchTargetTree, fallThroughTree, comp ()->getFlowGraph (), false , false );
1875
+ TR::TreeTop *nonNullAccessTreeTop = TR::TreeTop::create (comp (),callNodeTreeTop->getNode ()->duplicateTree ());
1876
+
1877
+ // add null test and array test
1878
+ callBlock->createConditionalBlocksBeforeTree (callNodeTreeTop, isNullTreeTop, defaultAccessTreeTop, nonNullAccessTreeTop, comp ()->getFlowGraph (), false , false );
1879
+ TR::Block *joinBlock = nonNullAccessTreeTop->getEnclosingBlock ()->createConditionalBlocksBeforeTree (nonNullAccessTreeTop, isArrayTreeTop, arrayAccessTreeTop, compareTree, comp ()->getFlowGraph (), false , false );
1880
+
1881
+ TR::CFG *cfg = comp ()->getFlowGraph ();
1882
+
1883
+ // add lowtag test
1884
+ TR::Block *isLowTaggedBlock = compareTree->getEnclosingBlock ();
1885
+ cfg->removeEdge (isLowTaggedBlock, joinBlock);
1886
+
1887
+ // add branch path (default access)
1888
+ // note that genClassCheck generates a ifcmpne offset&mask 1, meaning if it is NOT
1889
+ // lowtagged (ie offset&mask == 0), the branch will be taken
1890
+ TR::Block *defaultAccessBlock = defaultAccessTreeTop->getEnclosingBlock ();
1891
+ compareTree->getNode ()->setBranchDestination (defaultAccessBlock->getEntry ());
1892
+ cfg->addEdge (TR::CFGEdge::createEdge (isLowTaggedBlock, defaultAccessBlock, trMemory ()));
1893
+
1894
+ // add fallthrough path (lowtag access)
1895
+ TR::Block *lowTagAccessBlock = TR::Block::createEmptyBlock (compareTree->getNode (), comp (), isLowTaggedBlock->getFrequency (), isLowTaggedBlock);
1896
+ lowTagAccessBlock->append (lowTagAccessTreeTop);
1897
+ isLowTaggedBlock->getExit ()->insertTreeTopsAfterMe (lowTagAccessBlock->getEntry (), lowTagAccessBlock->getExit ());
1898
+ cfg->addNode (lowTagAccessBlock);
1899
+ cfg->addEdge (TR::CFGEdge::createEdge (isLowTaggedBlock, lowTagAccessBlock, trMemory ()));
1900
+ cfg->addEdge (TR::CFGEdge::createEdge (lowTagAccessBlock, joinBlock, trMemory ()));
1874
1901
}
1875
- 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
1902
+ else if (arrayBlockNeeded) // in case (2), we generate only the null test diamond
1876
1903
{
1877
- callNodeTreeTop->insertAfter (arrayAccessTreeTop);
1878
- callNodeTreeTop->getPrevTreeTop ()->join (callNodeTreeTop->getNextTreeTop ());
1879
- callBlock->split (arrayAccessTreeTop->getNextTreeTop (), comp ()->getFlowGraph (), true );
1880
- callBlock->split (arrayAccessTreeTop, comp ()->getFlowGraph (), true );
1904
+ callBlock->createConditionalBlocksBeforeTree (callNodeTreeTop, isNullTreeTop, defaultAccessTreeTop, arrayAccessTreeTop, comp ()->getFlowGraph (), false , false );
1881
1905
}
1882
1906
else if (compareTree != NULL ) // in case (1), we only generate the low tagged test diamond
1883
- callBlock->createConditionalBlocksBeforeTree (callNodeTreeTop, compareTree, branchTargetTree, fallThroughTree, comp ()->getFlowGraph (), false , false );
1884
-
1907
+ {
1908
+ callBlock->createConditionalBlocksBeforeTree (callNodeTreeTop, compareTree, defaultAccessTreeTop, lowTagAccessTreeTop, comp ()->getFlowGraph (), false , false );
1909
+ }
1885
1910
1886
1911
// the original call will be deleted by createConditionalBlocksBeforeTree, but if the refcount was > 1, we need to insert stores.
1887
1912
if (newSymbolReference)
1888
1913
{
1889
- if (compareTree != NULL ) // case (1) and (3) only
1890
- {
1891
- TR::Node *branchTargetStoreNode = TR::Node::createWithSymRef (comp ()->il .opCodeForDirectStore (dataType), 1 , 1 , branchTargetTree->getNode ()->getFirstChild (), newSymbolReference);
1892
- TR::TreeTop *branchTargetStoreTree = TR::TreeTop::create (comp (), branchTargetStoreNode);
1914
+ TR::Node *defaultAccessStoreNode = TR::Node::createWithSymRef (comp ()->il .opCodeForDirectStore (dataType), 1 , 1 , defaultAccessTreeTop->getNode ()->getFirstChild (), newSymbolReference);
1915
+ TR::TreeTop *defaultAccessStoreTree = TR::TreeTop::create (comp (), defaultAccessStoreNode);
1893
1916
1894
- branchTargetTree ->insertAfter (branchTargetStoreTree );
1917
+ defaultAccessTreeTop ->insertAfter (defaultAccessStoreTree );
1895
1918
1896
- debugTrace (tracer ()," Inserted store tree %p for branch target (taken) side of the diamond" , branchTargetStoreNode );
1919
+ debugTrace (tracer ()," Inserted store tree %p for branch target (taken) side of the diamond" , defaultAccessStoreNode );
1897
1920
1898
- TR::Node *fallThroughStoreNode = TR::Node::createWithSymRef (comp ()->il .opCodeForDirectStore (dataType), 1 , 1 , fallThroughTree->getNode ()->getFirstChild (), newSymbolReference);
1899
- TR::TreeTop *fallThroughStoreTree = TR::TreeTop::create (comp (), fallThroughStoreNode);
1921
+ if (compareTree != NULL ) // cases (1) and (3) only
1922
+ {
1923
+ TR::Node *lowTagAccessStoreNode = TR::Node::createWithSymRef (comp ()->il .opCodeForDirectStore (dataType), 1 , 1 , lowTagAccessTreeTop->getNode ()->getFirstChild (), newSymbolReference);
1924
+ TR::TreeTop *lowTagAccessStoreTree = TR::TreeTop::create (comp (), lowTagAccessStoreNode);
1900
1925
1901
- fallThroughTree ->insertAfter (fallThroughStoreTree );
1926
+ lowTagAccessTreeTop ->insertAfter (lowTagAccessStoreTree );
1902
1927
1903
- debugTrace (tracer ()," Inserted store tree %p for fall-through side of the diamond" , fallThroughStoreNode );
1928
+ debugTrace (tracer ()," Inserted store tree %p for fall-through side of the diamond" , lowTagAccessStoreNode );
1904
1929
}
1905
1930
1906
- if (arrayAccessTreeTop != NULL ) // case (1 ) only
1931
+ if (arrayAccessTreeTop != NULL ) // cases (2) and (3 ) only
1907
1932
{
1908
1933
TR::Node *arrayAccessStoreNode = TR::Node::createWithSymRef (comp ()->il .opCodeForDirectStore (dataType), 1 , 1 , arrayAccessTreeTop->getNode ()->getFirstChild (), newSymbolReference);
1909
1934
TR::TreeTop *arrayAccessStoreTree = TR::TreeTop::create (comp (), arrayAccessStoreNode);
0 commit comments