Path: blob/master/runtime/compiler/codegen/J9CodeGenerator.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2021 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#if defined(J9ZOS390)23#pragma csect(CODE,"TRJ9CGBase#C")24#pragma csect(STATIC,"TRJ9CGBase#S")25#pragma csect(TEST,"TRJ9CGBase#T")26#endif2728#include <algorithm>29#include "codegen/AheadOfTimeCompile.hpp"30#include "codegen/CodeGenerator.hpp"31#include "codegen/CodeGenerator_inlines.hpp"32#include "codegen/PicHelpers.hpp"33#include "codegen/Relocation.hpp"34#include "codegen/Instruction.hpp"35#include "codegen/MonitorState.hpp"36#include "compile/AOTClassInfo.hpp"37#include "compile/Compilation.hpp"38#include "compile/OSRData.hpp"39#include "compile/VirtualGuard.hpp"40#include "control/Recompilation.hpp"41#include "control/RecompilationInfo.hpp"42#include "env/CompilerEnv.hpp"43#include "env/VMAccessCriticalSection.hpp"44#include "env/VMJ9.h"45#include "env/jittypes.h"46#include "env/j9method.h"47#include "il/AutomaticSymbol.hpp"48#include "il/Block.hpp"49#include "il/LabelSymbol.hpp"50#include "il/Node.hpp"51#include "il/Node_inlines.hpp"52#include "il/NodePool.hpp"53#include "il/ParameterSymbol.hpp"54#include "il/StaticSymbol.hpp"55#include "il/Symbol.hpp"56#include "infra/Assert.hpp"57#include "infra/BitVector.hpp"58#include "infra/ILWalk.hpp"59#include "infra/List.hpp"60#include "optimizer/Structure.hpp"61#include "optimizer/TransformUtil.hpp"62#include "ras/Delimiter.hpp"63#include "ras/DebugCounter.hpp"64#include "runtime/CodeCache.hpp"65#include "runtime/CodeCacheExceptions.hpp"66#include "runtime/CodeCacheManager.hpp"67#include "env/CHTable.hpp"68#include "env/PersistentCHTable.hpp"6970#define OPT_DETAILS "O^O CODE GENERATION: "717273J9::CodeGenerator::CodeGenerator(TR::Compilation *comp) :74OMR::CodeGeneratorConnector(comp),75_gpuSymbolMap(comp->allocator()),76_stackLimitOffsetInMetaData(comp->fej9()->thisThreadGetStackLimitOffset()),77_uncommonedNodes(comp->trMemory(), stackAlloc),78_liveMonitors(NULL),79_nodesSpineCheckedList(getTypedAllocator<TR::Node*>(comp->allocator())),80_jniCallSites(getTypedAllocator<TR_Pair<TR_ResolvedMethod,TR::Instruction> *>(comp->allocator())),81_monitorMapping(std::less<ncount_t>(), MonitorMapAllocator(comp->trMemory()->heapMemoryRegion())),82_dummyTempStorageRefNode(NULL)83{84/**85* Do not add CodeGenerator initialization logic here.86* Use the \c initialize() method instead.87*/88}8990void91J9::CodeGenerator::initialize()92{93self()->OMR::CodeGeneratorConnector::initialize();94}9596TR_J9VMBase *97J9::CodeGenerator::fej9()98{99return (TR_J9VMBase *)self()->fe();100}101102// J9103static TR::Node *lowerCASValues(104TR::Node *parent,105int32_t childNum,106TR::Node *address,107TR::Compilation *comp,108TR::Node *shftOffset,109bool isLowMem,110TR::Node *heapBase)111{112TR::Node *l2iNode = NULL;113114if ((address->getOpCodeValue() == TR::aconst) &&115(address->getAddress() == 0))116{117l2iNode = TR::Node::create(address, TR::iconst, 0, 0);118}119else120{121// -J9JIT_COMPRESSED_POINTER-122// if the value is known to be null or if using lowMemHeap, do not123// generate a compression sequence124//125TR::Node *a2lNode = TR::Node::create(TR::a2l, 1, address);126bool isNonNull = false;127if (address->isNonNull())128isNonNull = true;129130TR::Node *addNode = NULL;131132if (address->isNull() || isLowMem)133{134addNode = a2lNode;135}136else137{138if (isNonNull)139a2lNode->setIsNonZero(true);140addNode = TR::Node::create(TR::lsub, 2, a2lNode, heapBase);141addNode->setContainsCompressionSequence(true);142if (isNonNull)143addNode->setIsNonZero(true);144}145146if (shftOffset)147{148addNode = TR::Node::create(TR::lushr, 2, addNode, shftOffset);149addNode->setContainsCompressionSequence(true);150}151152if (isNonNull)153addNode->setIsNonZero(true);154155l2iNode = TR::Node::create(TR::l2i, 1, addNode);156if (isNonNull)157l2iNode->setIsNonZero(true);158159if (address->isNull())160l2iNode->setIsNull(true);161}162163parent->setAndIncChild(childNum, l2iNode);164address->recursivelyDecReferenceCount();165return l2iNode;166}167168169// J9170//171// convert dual operators from DAG representation to cyclic representation by cloning172// eg173// luaddh174// xh175// yh176// ladd177// xl178// yl179// ==> luaddh <=== replace dummy node with this third child to complete cycle180//181void182J9::CodeGenerator::lowerDualOperator(183TR::Node *parent,184int32_t childNumber,185TR::TreeTop *treeTop)186{187if (parent == NULL)188{189// should never need to process treetops190return;191}192193// any parent may have an adjunct194TR::Node *child = parent->getChild(childNumber);195if (child->isAdjunct())196{197TR_ASSERT(!child->isDualCyclic(), "Visitcount problem: trying to clone node %p when it has already been cloned.\n", child);198199// create clone with space for third child, but still with two children200TR::Node *clone = self()->createOrFindClonedNode(child, 3);201if (1 && performTransformation(self()->comp(), "%sCreating Cyclic Dual Representation, replacing %p (%s) by %p under %p (childNumber %d).\n",202OPT_DETAILS, child, child->getOpCode().getName(), clone, parent, childNumber))203{204child = clone;205parent->setChild(childNumber, child);206if (parent->isDualHigh() && (childNumber == 2))207{208// build cycle209TR_ASSERT(!parent->isDualCyclic(), "Attempting to lower a dual operator node %p that has already been lowered.\n", parent);210child->setNumChildren(3);211child->setAndIncChild(2, parent);212}213}214}215}216217218// J9219void220J9::CodeGenerator::lowerCompressedRefs(221TR::TreeTop *treeTop,222TR::Node *node,223vcount_t visitCount,224TR_BitVector *childrenToBeLowered)225{226if (node->getOpCode().isCall() && childrenToBeLowered)227{228TR_BitVectorIterator bvi(*childrenToBeLowered);229while (bvi.hasMoreElements())230{231int32_t nextChild = bvi.getNextElement();232TR::Node *valueChild = node->getChild(nextChild);233if (valueChild->getOpCode().is8Byte())234{235TR::Node *shftOffset = NULL;236if (TR::Compiler->om.compressedReferenceShiftOffset() > 0)237{238shftOffset = TR::Node::create(node, TR::iconst, 0, TR::Compiler->om.compressedReferenceShiftOffset());239}240241TR::Node *heapBase = TR::Node::create(node, TR::lconst, 0, 0);242lowerCASValues(node, nextChild, valueChild, self()->comp(), shftOffset, true, heapBase);243}244}245246return;247}248249250TR::Node *loadOrStoreNode = node->getFirstChild();251252/*253decompression:254actual = compress + heap_base255256and compression:257compress = actual - heap_base258259iaload f l2a260aload O ladd261lshl262i2l263iiload f264aload O265iconst shftKonst266lconst HB267268-or- if the field is known to be null269l2a270i2l271iiload f272aload O273274275iastore f iistore f276aload O aload O277value l2i278lshr279lsub280a2l281aload O282lconst HB283iconst shftKonst284285-or- if the field is known to be null286iistore f287aload O288l2i289a2l <- nop on most platforms290aload O291292- J9JIT_COMPRESS_POINTER 32-bit -293294DEPRECATED - do *not* use, kept here for historical reasons295296compress = actual - heapBase + shadowBase = actual + disp297actual = compress - disp298299iaload f i2a300aload O isub301iiload f302aload O303iconst HB304305iastore f iistore f306aload O aload O307iushr // iushr only there to distinguish between308iadd // real iistores with iadds as the value309a2i310value311iconst HB312iconst 0313314*/315316// dont process loads/stores twice317// cannot use visitCounts because compressedRefs318// trees may appear after checks (in which case the node319// would have already been visited, preventing lowering)320//321TR::ILOpCodes convertOp = self()->comp()->target().is64Bit() ? TR::l2a : TR::i2a;322if (loadOrStoreNode->getOpCodeValue() == convertOp)323return;324else if (loadOrStoreNode->getOpCode().isStoreIndirect())325{326convertOp = self()->comp()->target().is64Bit() ? TR::l2i : TR::iushr;327if (loadOrStoreNode->getSecondChild()->getOpCodeValue() == convertOp)328return;329}330331TR::Node *heapBase = node->getSecondChild();332333TR::SymbolReference *symRef = loadOrStoreNode->getSymbolReference();334TR::ILOpCodes loadOrStoreOp;335bool isLoad = true;336337TR::Node *address = NULL;338339bool shouldBeCompressed = false;340if (loadOrStoreNode->getOpCode().isLoadIndirect() ||341loadOrStoreNode->getOpCode().isStoreIndirect() ||342loadOrStoreNode->getOpCodeValue() == TR::arrayset)343{344shouldBeCompressed = TR::TransformUtil::fieldShouldBeCompressed(loadOrStoreNode, self()->comp());345if (!shouldBeCompressed)346{347// catch cases when a compressedRefs anchor is created for specific348// unsafe loads by inliner349//350if (loadOrStoreNode->getSymbol()->isUnsafeShadowSymbol())351shouldBeCompressed = true;352}353// Don't de-compress loads created by dynamicLitPool354if (loadOrStoreNode->getOpCode().isLoadIndirect() &&355loadOrStoreNode->getSymbolReference()->isFromLiteralPool())356shouldBeCompressed = false;357}358359if (loadOrStoreNode->getOpCode().isLoadIndirect() && shouldBeCompressed)360{361if (self()->comp()->target().cpu.isZ() && TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)362{363dumpOptDetails(self()->comp(), "converting to ardbari %p under concurrent scavenge on Z.\n", node);364self()->createReferenceReadBarrier(treeTop, loadOrStoreNode);365return;366}367368// base object369address = loadOrStoreNode->getFirstChild();370loadOrStoreOp = TR::Compiler->om.readBarrierType() != gc_modron_readbar_none || loadOrStoreNode->getOpCode().isReadBar() ? self()->comp()->il.opCodeForIndirectReadBarrier(TR::Int32) :371self()->comp()->il.opCodeForIndirectLoad(TR::Int32);372}373else if ((loadOrStoreNode->getOpCode().isStoreIndirect() ||374loadOrStoreNode->getOpCodeValue() == TR::arrayset) &&375shouldBeCompressed)376{377// store value378address = loadOrStoreNode->getSecondChild();379380loadOrStoreOp = self()->comp()->il.opCodeForIndirectStore(TR::Int32);381isLoad = false;382}383else384{385dumpOptDetails(self()->comp(), "compression sequence %p is not in required form\n", node);386return;387}388389// in future if shifted offsets are used, this value will be390// a positive non-zero constant391//392TR::Node *shftOffset = NULL;393if (TR::Compiler->om.compressedReferenceShiftOffset() > 0)394shftOffset = TR::Node::create(loadOrStoreNode, TR::iconst, 0, TR::Compiler->om.compressedReferenceShiftOffset());395396if (isLoad)397{398TR::Node *newLoad = TR::Node::createWithSymRef(loadOrStoreOp, 1, 1, address, symRef);399newLoad->setByteCodeInfo(loadOrStoreNode->getByteCodeInfo());400401if (loadOrStoreNode->isNonNull())402newLoad->setIsNonZero(true);403404// FIXME: this breaks commoning of address (which could be a regLoad)405// it would be nice to get the node flags on the original406//TR::Node *newLoad = loadOrStoreNode->duplicateTree();407//TR::Node::recreate(newLoad, loadOrStoreOp);408409// -J9JIT_COMPRESSED_POINTER-410//411TR::Node *iu2lNode = TR::Node::create(TR::iu2l, 1, newLoad);412413TR::Node *addNode = iu2lNode;414if (loadOrStoreNode->isNonNull())415addNode->setIsNonZero(true);416417// if the load is known to be null or if using lowMemHeap, do not418// generate a compression sequence419addNode = iu2lNode;420if (shftOffset)421{422addNode = TR::Node::create(TR::lshl, 2, iu2lNode, shftOffset);423addNode->setContainsCompressionSequence(true);424}425426TR::Node::recreate(loadOrStoreNode, TR::l2a);427address->decReferenceCount();428loadOrStoreNode->setAndIncChild(0, addNode);429loadOrStoreNode->setNumChildren(1);430}431else432{433// All evaluators makes an assumption that if we are loading or storing434// object references they will have decompression or compression sequence for435// the child being loaded or stored respectively. In case of storing436// object reference, in some cases it might need actual object decompressed437// address.438// Due to above assumptions made by the codegen we should not do any439// optimization here on compression/decompression sequence which could440// break this assumption and lead to undefined behaviour.441// See openj9#12597 for more details442443// -J9JIT_COMPRESSED_POINTER-444// if the value is known to be null or if using lowMemHeap, do not445// generate a compression sequence446//447TR::Node *a2lNode = TR::Node::create(TR::a2l, 1, address);448bool isNonNull = false;449if (address->isNonNull())450isNonNull = true;451452TR::Node *addNode = NULL;453addNode = a2lNode;454455if (shftOffset)456{457addNode = TR::Node::create(TR::lushr, 2, addNode, shftOffset);458addNode->setContainsCompressionSequence(true);459}460461if (isNonNull)462addNode->setIsNonZero(true);463464TR::Node *l2iNode = TR::Node::create(TR::l2i, 1, addNode);465if (isNonNull)466l2iNode->setIsNonZero(true);467468if (address->isNull())469l2iNode->setIsNull(true);470471// recreating an arrayset node will replace the TR::arrayset with an istorei, which is undesired472// as arrayset nodes can set indirect references473if (!loadOrStoreNode->getOpCode().isWrtBar() && loadOrStoreNode->getOpCodeValue() != TR::arrayset)474{475TR::Node::recreate(loadOrStoreNode, loadOrStoreOp);476}477478loadOrStoreNode->setAndIncChild(1, l2iNode);479address->recursivelyDecReferenceCount();480}481}482483bool484J9::CodeGenerator::supportVMInternalNatives()485{486return !self()->comp()->compileRelocatableCode();487}488489// J9490//491static bool scanForNativeMethodsUntilMonitorNode(TR::TreeTop *firstTree, TR::Compilation *comp)492{493TR::TreeTop *currTree = firstTree;494while (currTree)495{496TR::Node *currNode = currTree->getNode();497//traceMsg(comp(), "-> Looking at node %p\n", currNode);498499if ((currNode->getOpCodeValue() == TR::monexit) ||500(currNode->getOpCodeValue() == TR::monent))501{502return false;503}504else if (currNode->getNumChildren() > 0 &&505currNode->getFirstChild()->getNumChildren() > 0 &&506((currNode->getFirstChild()->getOpCodeValue() == TR::monexit) ||507(currNode->getFirstChild()->getOpCodeValue() == TR::monent))508)509{510return false;511}512513514TR::Node *callTestNode = NULL;515516if (currNode->getOpCode().isCall() &&517!currNode->getSymbolReference()->isUnresolved() &&518currNode->getSymbol()->castToMethodSymbol()->isNative())519{520callTestNode = currNode;521}522else if (currNode->getNumChildren() > 0 &&523currNode->getFirstChild()->getOpCode().isCall() &&524!currNode->getFirstChild()->getSymbolReference()->isUnresolved() &&525currNode->getFirstChild()->getSymbol()->castToMethodSymbol()->isNative())526{527callTestNode = currNode->getFirstChild();528}529530if (callTestNode)531{532TR::ResolvedMethodSymbol *symbol = callTestNode->getSymbol()->castToResolvedMethodSymbol();533if (strstr(symbol->signature(comp->trMemory()), "java/lang/Object.notify") ||534strstr(symbol->signature(comp->trMemory()), "java/lang/Object.wait"))535return true;536}537538currTree = currTree->getNextTreeTop();539}540541return false;542}543544545void546J9::CodeGenerator::preLowerTrees()547{548549OMR::CodeGeneratorConnector::preLowerTrees();550551/*552* These initializations should move from OMR to J9553554int32_t symRefCount = comp()->getSymRefCount();555_localsThatAreStored = new (comp()->trHeapMemory()) TR_BitVector(symRefCount, comp()->trMemory(), heapAlloc);556_numLocalsWhenStoreAnalysisWasDone = symRefCount;557*/558559// For dual operator lowering560_uncommonedNodes.reset();561_uncommonedNodes.init(64, true);562}563564565void566J9::CodeGenerator::lowerTreesPreTreeTopVisit(TR::TreeTop *tt, vcount_t visitCount)567{568OMR::CodeGeneratorConnector::lowerTreesPreTreeTopVisit(tt, visitCount);569570TR::Node *node = tt->getNode();571572if (self()->getSupportsBDLLHardwareOverflowCheck() && node->getNumChildren() > 0 &&573node->getFirstChild() && node->getFirstChild()->getOpCodeValue() == TR::icall &&574node->getFirstChild()->getSymbol() &&575(node->getFirstChild()->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_noLLOverflowAdd))576{577node->getFirstChild()->getChild(2)->setNodeRequiresConditionCodes(true);578}579580}581582583void584J9::CodeGenerator::lowerTreesPreChildrenVisit(TR::Node *parent, TR::TreeTop *treeTop, vcount_t visitCount)585{586OMR::CodeGeneratorConnector::lowerTreesPreChildrenVisit(parent, treeTop, visitCount);587588/*589rip out a SpineCHK under two conditions.5901. If the first child has been the first child of another SpineCHK5912. If the first child is not an array access. This can happens when592an array access node is changed by common sub expression593*/594595bool doIt = false;596597if ( (parent->getOpCodeValue() == TR::BNDCHKwithSpineCHK) || (parent->getOpCodeValue() == TR::SpineCHK) )598{599TR::Node *firstChild = parent->getFirstChild();600TR::ILOpCode opcode = firstChild->getOpCode();601602if( ( (opcode.isLoad() || opcode.isStore() ) && opcode.hasSymbolReference() && firstChild->getSymbolReference() != NULL &&603firstChild->getSymbolReference()->getSymbol()->isArrayShadowSymbol()) || opcode.isArrayRef())604{605//first child of SpineCHK is an array load or store, check if this is the first time we evaluate this node606bool found = (std::find(_nodesSpineCheckedList.begin(), _nodesSpineCheckedList.end(), firstChild) != _nodesSpineCheckedList.end());607if ( (firstChild->getVisitCount() == visitCount) && found )608{609// we have check this array access before, rip out SpineCHK610doIt = true;611}612else613{614_nodesSpineCheckedList.push_front(firstChild);615}616}617else618{619// the first child is not an array access, rip out SpineCHK620doIt = true;621}622623if( doIt )624{625int32_t i = 0;626int32_t numChildren = parent->getNumChildren();627TR::TreeTop *prevTreeTop = treeTop;628TR::TreeTop *nextTreeTop = treeTop->getNextTreeTop();629while (i < numChildren)630{631TR::Node *childToBeAnchored = parent->getChild(i);632TR::TreeTop *anchorTree = TR::TreeTop::create(self()->comp(), TR::Node::create(TR::treetop, 1, childToBeAnchored), NULL, NULL);633prevTreeTop->join(anchorTree);634anchorTree->join(nextTreeTop);635prevTreeTop = anchorTree;636i++;637}638TR::TransformUtil::removeTree(self()->comp(), treeTop);639return;640}641}642643if (parent->getOpCode().isFunctionCall())644{645// J9646//647// Hiding compressedref logic from CodeGen doesn't seem a good practise, the evaluator always need the uncompressedref node for write barrier,648// therefore, this part is deprecated. It'll be removed once P and Z update their corresponding evaluators.649static bool UseOldCompareAndSwapObject = (bool)feGetEnv("TR_UseOldCompareAndSwapObject");650if (self()->comp()->useCompressedPointers() && (UseOldCompareAndSwapObject || !(self()->comp()->target().cpu.isX86() || self()->comp()->target().cpu.isARM64())))651{652TR::MethodSymbol *methodSymbol = parent->getSymbol()->castToMethodSymbol();653// In Java9 Unsafe could be the jdk.internal JNI method or the sun.misc ordinary method wrapper,654// while in Java8 it can only be the sun.misc package which will itself contain the JNI method.655// Test for isNative to distinguish between them.656if ((methodSymbol->getRecognizedMethod() == TR::sun_misc_Unsafe_compareAndSwapObject_jlObjectJjlObjectjlObject_Z) &&657methodSymbol->isNative() &&658(!TR::Compiler->om.canGenerateArraylets() || parent->isUnsafeGetPutCASCallOnNonArray()) && parent->isSafeForCGToFastPathUnsafeCall())659{660TR_BitVector childrenToBeLowered(parent->getNumChildren(), self()->comp()->trMemory(), stackAlloc);661childrenToBeLowered.set(3);662childrenToBeLowered.set(4);663self()->lowerCompressedRefs(treeTop, parent, visitCount, &childrenToBeLowered);664}665}666}667668// J9669//670if (parent->getOpCode().hasSymbolReference() &&671(parent->getSymbolReference() == self()->comp()->getSymRefTab()->findThisRangeExtensionSymRef()))672TR::Node::recreate(parent, TR::treetop);673674675// J9676//677if (parent->getOpCode().isCall() &&678!parent->getSymbolReference()->isUnresolved() &&679parent->getSymbolReference()->getSymbol()->getMethodSymbol() &&680!parent->getSymbolReference()->getSymbol()->castToMethodSymbol()->isHelper() &&681!parent->getSymbolReference()->getSymbol()->castToMethodSymbol()->isSystemLinkageDispatch() &&682parent->getSymbolReference()->getSymbol()->getResolvedMethodSymbol())683{684//this code should match the one in genInvoke (Walker.cpp)685if (parent->getSymbolReference()->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive32 ||686parent->getSymbolReference()->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive64687)688parent->removeChild(0);689690if (parent->getSymbolReference()->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive32)691TR::Node::recreate(parent, TR::a2i);692else if (parent->getSymbolReference()->getSymbol()->castToResolvedMethodSymbol()->getRecognizedMethod() == TR::com_ibm_jit_JITHelpers_getAddressAsPrimitive64)693TR::Node::recreate(parent, TR::a2l);694}695696// J9697//698if (self()->comp()->useCompressedPointers())699{700if (parent->getOpCodeValue() == TR::compressedRefs)701self()->lowerCompressedRefs(treeTop, parent, visitCount, NULL);702}703else if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)704{705self()->createReferenceReadBarrier(treeTop, parent);706}707708// J9709//710// Prepare to lower dual operators711//712for (int32_t childCount = 0; childCount < parent->getNumChildren(); childCount++)713{714self()->lowerDualOperator(parent, childCount, treeTop);715}716717}718719void720J9::CodeGenerator::createReferenceReadBarrier(TR::TreeTop* treeTop, TR::Node* parent)721{722if (parent->getOpCodeValue() != TR::aloadi)723return;724725TR::Symbol* symbol = parent->getSymbolReference()->getSymbol();726// isCollectedReference() responds false to generic int shadows because their type727// is int. However, address type generic int shadows refer to collected slots.728729if (symbol == TR::comp()->getSymRefTab()->findGenericIntShadowSymbol() || symbol->isCollectedReference())730{731TR::Node::recreate(parent, TR::ardbari);732if (treeTop->getNode()->getOpCodeValue() == TR::NULLCHK &&733treeTop->getNode()->getChild(0)->getOpCodeValue() != TR::PassThrough &&734treeTop->getNode()->getChild(0)->getChild(0) == parent)735{736treeTop->insertBefore(TR::TreeTop::create(self()->comp(),737TR::Node::createWithSymRef(TR::NULLCHK, 1, 1,738TR::Node::create(TR::PassThrough, 1, parent),739treeTop->getNode()->getSymbolReference())));740treeTop->getNode()->setSymbolReference(NULL);741TR::Node::recreate(treeTop->getNode(), TR::treetop);742}743else if (treeTop->getNode()->getOpCodeValue() == TR::NULLCHK &&744treeTop->getNode()->getChild(0) == parent)745{746treeTop->insertBefore(TR::TreeTop::create(self()->comp(),747TR::Node::createWithSymRef(TR::NULLCHK, 1, 1,748TR::Node::create(TR::PassThrough, 1, parent->getChild(0)),749treeTop->getNode()->getSymbolReference())));750treeTop->getNode()->setSymbolReference(NULL);751TR::Node::recreate(treeTop->getNode(), TR::treetop);752}753else754{755treeTop->insertBefore(TR::TreeTop::create(self()->comp(), TR::Node::create(parent, TR::treetop, 1, parent)));756}757}758759}760761void762J9::CodeGenerator::lowerTreeIfNeeded(763TR::Node *node,764int32_t childNumberOfNode,765TR::Node *parent,766TR::TreeTop *tt)767{768TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->comp()->fe());769OMR::CodeGeneratorConnector::lowerTreeIfNeeded(node, childNumberOfNode, parent, tt);770771if (node->getOpCode().isCall() &&772!node->getSymbol()->castToMethodSymbol()->isHelper())773{774TR::RecognizedMethod rm = node->getSymbol()->castToMethodSymbol()->getRecognizedMethod();775776if(rm == TR::java_lang_invoke_MethodHandle_invokeBasic ||777rm == TR::java_lang_invoke_MethodHandle_linkToStatic ||778rm == TR::java_lang_invoke_MethodHandle_linkToSpecial ||779rm == TR::java_lang_invoke_MethodHandle_linkToVirtual ||780rm == TR::java_lang_invoke_MethodHandle_linkToInterface)781{782// invokeBasic and linkTo* are signature-polymorphic, so the VM needs to know the number of argument slots783// for the INL call in order to locate the start of the arguments on the stack. The arg slot count is stored784// in vmThread.tempSlot.785//786// Furthermore, for unresolved invokedynamic and invokehandle bytecodes, we create a dummy TR_ResolvedMethod call to787// linkToStatic. The appendix object in the invoke cache array entry could be NULL, which we cannot determine at compile788// time when the callSite/invokeCache table entries are unresolved. The VM would have to remove the appendix789// object, which would require knowing the number of stack slots of the ROM method signature plus the slots occupied790// by the receiver object (for invokehandle only) and appendix object. This would be equivalent to the number of791// parameter slots of the linkToStatic call - 1.792// To pass that information, we store to vmThread.floatTemp1 field. The name of the field is793// misleading, as it is an lconst/iconst being stored. If the linkToStatic call is not for an unresolved794// invokedynamic/invokehandle, then the JIT would not create a push of a null appendix object, so the VM would not795// need to do any stack adjustments. In those cases, -1 is stored in floatTemp1. This is also done for linkToSpecial,796// as it shares the same handling mechanism in the VM. No stack adjustments are necessary for linkToSpecial, so the value797// stored in floatTemp1 will always be -1.798TR::Node * numArgsNode = NULL;799TR::Node * numArgSlotsNode = NULL;800TR::Node * tempSlotStoreNode = NULL;801TR::Node * floatTemp1StoreNode = NULL;802bool is64Bit = self()->comp()->target().is64Bit();803TR::ILOpCodes storeOpCode;804int32_t numParameterStackSlots = node->getSymbol()->castToResolvedMethodSymbol()->getNumParameterSlots();805if (is64Bit)806{807storeOpCode = TR::lstore;808numArgSlotsNode = TR::Node::lconst(node, numParameterStackSlots);809}810else811{812storeOpCode = TR::istore;813numArgSlotsNode = TR::Node::iconst(node, numParameterStackSlots);814}815tempSlotStoreNode = TR::Node::createStore(self()->comp()->getSymRefTab()->findOrCreateVMThreadTempSlotFieldSymbolRef(),816numArgSlotsNode,817storeOpCode);818tempSlotStoreNode->setByteCodeIndex(node->getByteCodeIndex());819TR::TreeTop::create(self()->comp(), tt->getPrevTreeTop(), tempSlotStoreNode);820821if (rm == TR::java_lang_invoke_MethodHandle_linkToStatic || rm == TR::java_lang_invoke_MethodHandle_linkToSpecial)822{823int32_t numArgs;824if (node->getSymbolReference()->getSymbol()->isDummyResolvedMethod())825numArgs = numParameterStackSlots - 1 ;826else827numArgs = -1;828829numArgsNode = is64Bit ? TR::Node::lconst(node, numArgs) :830TR::Node::iconst(node, numArgs);831832floatTemp1StoreNode = TR::Node::createStore(self()->comp()->getSymRefTab()->findOrCreateVMThreadFloatTemp1SymbolRef(),833numArgsNode,834storeOpCode);835floatTemp1StoreNode->setByteCodeIndex(node->getByteCodeIndex());836TR::TreeTop::create(self()->comp(), tt->getPrevTreeTop(), floatTemp1StoreNode);837}838}839}840841// J9842//843// if we found this iterator method inlined in a scorching method844// we should attempt to prefetch where it's used for performance845// structure is needed to determine the loop size to use proper prefetch stride846if (!self()->shouldBuildStructure() &&847(self()->comp()->getMethodHotness() >= scorching) &&848!tt->getEnclosingBlock()->isCold() &&849strstr(fej9->sampleSignature(node->getOwningMethod(), 0, 0, self()->trMemory()),"java/util/TreeMap$UnboundedValueIterator.next()"))850{851self()->setShouldBuildStructure();852}853854// J9855if (node->getOpCode().isCall() &&856node->isUnsafePutOrderedCall() &&857node->isDontInlinePutOrderedCall())858{859// Remove this treetop860tt->getPrevTreeTop()->setNextTreeTop(tt->getNextTreeTop());861tt->getNextTreeTop()->setPrevTreeTop(tt->getPrevTreeTop());862tt->getNode()->recursivelyDecReferenceCount();863return;864}865866// J9867if (!self()->comp()->getOption(TR_DisableUnsafe) &&868node->getOpCode().isCall() &&869node->getOpCodeValue() == TR::call &&870!TR::Compiler->om.canGenerateArraylets() &&871((node->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_nio_Bits_copyToByteArray) ||872(node->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_nio_Bits_copyFromByteArray)) &&873!fej9->isAnyMethodTracingEnabled(node->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->getPersistentIdentifier()) &&874performTransformation(self()->comp(), "%s Change recognized nio call to arraycopy [%p] \n", OPT_DETAILS, node))875{876bool from = false;877if (node->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_nio_Bits_copyFromByteArray)878from = true;879880TR::Node *nativeSrc;881TR::Node *javaTarget;882TR::Node *nativeOffset;883884if (from)885{886nativeSrc = node->getChild(2);887javaTarget = node->getFirstChild();888nativeOffset = node->getSecondChild();889}890else891{892nativeSrc = node->getFirstChild();893javaTarget = node->getSecondChild();894nativeOffset = node->getChild(2);895}896897TR::Node *javaOffset;898if (self()->comp()->target().is64Bit())899javaOffset = TR::Node::lconst(node, (int64_t) TR::Compiler->om.contiguousArrayHeaderSizeInBytes());900else901javaOffset = TR::Node::iconst(node, TR::Compiler->om.contiguousArrayHeaderSizeInBytes());902903TR::Node *len = node->getChild(3);904905TR::Node *oldNativeSrc = nativeSrc;906TR::Node *oldNativeOffset = nativeOffset;907TR::Node *oldLen = len;908909if (self()->comp()->target().is32Bit())910{911nativeSrc = TR::Node::create(TR::l2i, 1, nativeSrc);912nativeOffset = TR::Node::create(TR::l2i, 1, nativeOffset);913len = TR::Node::create(TR::l2i, 1, len);914}915916TR::Node::recreate(node, TR::arraycopy);917918TR::Node *nativeAddr;919TR::Node *javaAddr;920921if (self()->comp()->target().is32Bit())922{923nativeAddr = nativeSrc;924javaOffset = TR::Node::create(TR::iadd, 2, javaOffset, nativeOffset);925javaAddr = TR::Node::create(TR::aiadd, 2, javaTarget, javaOffset);926}927else928{929nativeAddr = nativeSrc;930javaOffset = TR::Node::create(TR::ladd, 2, javaOffset, nativeOffset);931javaAddr = TR::Node::create(TR::aladd, 2, javaTarget, javaOffset);932}933934node->setNumChildren(3);935936if (from)937{938node->setAndIncChild(0, javaAddr);939node->setAndIncChild(1, nativeAddr);940node->setAndIncChild(2, len);941}942else943{944node->setAndIncChild(0, nativeAddr);945node->setAndIncChild(1, javaAddr);946node->setAndIncChild(2, len);947}948949javaTarget->recursivelyDecReferenceCount();950oldNativeSrc->recursivelyDecReferenceCount();951oldNativeOffset->recursivelyDecReferenceCount();952oldLen->recursivelyDecReferenceCount();953954node->setArrayCopyElementType(TR::Int8);955node->setForwardArrayCopy(true);956}957958// J9959if (self()->comp()->compileRelocatableCode() && (node->getOpCodeValue() == TR::loadaddr) && parent && ((parent->getOpCodeValue() == TR::instanceof) || (parent->getOpCodeValue() == TR::checkcast)))960{961TR::TreeTop::create(self()->comp(), tt->getPrevTreeTop(), TR::Node::create(TR::treetop, 1, node));962}963964// J9965if (node->getOpCode().hasSymbolReference() &&966(node->getOpCode().isLoad() ||967node->getOpCode().isStore()))968{969TR::SymbolReference *symRef = node->getSymbolReference();970TR::Symbol *symbol = symRef->getSymbol();971if (symbol->isVolatile() && node->getDataType() == TR::Int64 && !symRef->isUnresolved() && self()->comp()->target().is32Bit() &&972!self()->getSupportsInlinedAtomicLongVolatiles())973{974bool isLoad = false;975TR::SymbolReference * volatileLongSymRef = NULL;976if (node->getOpCode().isLoadVar())977{978volatileLongSymRef = self()->comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_volatileReadLong, false, false, true);979isLoad = true;980}981else982volatileLongSymRef = self()->comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_volatileWriteLong, false, false, true);983984node->setSymbolReference(volatileLongSymRef);985986TR::Node * address = NULL;987if (node->getOpCode().isIndirect())988address = node->getFirstChild();989990TR::Node * addrNode = NULL;991if (address)992{993if (symRef->getOffset() == 0)994addrNode = address;995else996{997addrNode = TR::Node::create(TR::aiadd, 2, address,998TR::Node::create(node, TR::iconst, 0, symRef->getOffset()));999addrNode->setIsInternalPointer(true);1000}1001}10021003if (isLoad)1004{1005if (node->getOpCode().isIndirect())1006{1007if (tt->getNode()->getOpCodeValue() == TR::NULLCHK)1008{1009TR::Node * nullchkNode =1010TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, TR::Node::create(TR::PassThrough, 1, address), tt->getNode()->getSymbolReference());1011tt->getPrevTreeTop()->insertAfter(TR::TreeTop::create(self()->comp(), nullchkNode));1012TR::Node::recreate(tt->getNode(), TR::treetop);1013}1014node->setNumChildren(1);1015node->setAndIncChild(0, addrNode);1016}1017else1018{1019TR::Node * statics = TR::Node::createWithSymRef(node, TR::loadaddr, 0, symRef);1020node->setNumChildren(1);1021node->setAndIncChild(0, statics);1022}10231024if ((tt->getNode()->getOpCodeValue() != TR::treetop) ||1025(tt->getNode()->getFirstChild() != node))1026{1027TR::Node * ttNode = TR::Node::create(TR::treetop, 1, node);1028tt->getPrevTreeTop()->insertAfter(TR::TreeTop::create(self()->comp(), ttNode));1029}1030}1031else1032{1033if (node->getOpCode().isIndirect())1034{1035if (tt->getNode()->getOpCodeValue() == TR::NULLCHK)1036{1037TR::Node * nullchkNode =1038TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, TR::Node::create(TR::PassThrough, 1, address), tt->getNode()->getSymbolReference());1039tt->getPrevTreeTop()->insertAfter(TR::TreeTop::create(self()->comp(), nullchkNode));1040TR::Node::recreate(tt->getNode(), TR::treetop);1041}10421043node->setNumChildren(2);1044node->setChild(0, node->getSecondChild());1045node->setAndIncChild(1, addrNode);1046}1047else1048{1049TR::Node * statics = TR::Node::createWithSymRef(node, TR::loadaddr, 0, symRef);1050node->setNumChildren(2);1051node->setAndIncChild(1, statics);1052}10531054TR::Node * ttNode = tt->getNode();1055if (ttNode == node)1056{1057TR::Node * newTTNode = TR::Node::create(TR::treetop, 1, ttNode);1058tt->setNode(newTTNode);1059}1060}10611062if (isLoad)1063TR::Node::recreate(node, TR::lcall);1064else1065TR::Node::recreate(node, TR::call);10661067if (address)1068address->recursivelyDecReferenceCount();1069}1070}10711072// J9 (currentTimeMillis & OSR)1073if (node->getOpCode().isStore())1074{1075if ((node->getType().isInt64() &&1076node->isNOPLongStore()) ||1077(node->getSymbol()->isAutoOrParm() &&1078node->storedValueIsIrrelevant()))1079{1080TR_ASSERT(node == tt->getNode(), "A store is expected to be the root of its treetop");10811082// Remove this treetop1083tt->getPrevTreeTop()->setNextTreeTop(tt->getNextTreeTop());1084tt->getNextTreeTop()->setPrevTreeTop(tt->getPrevTreeTop());1085node->recursivelyDecReferenceCount();1086}1087else1088{1089// Needed for OSR1090//1091_localsThatAreStored->set(node->getSymbolReference()->getReferenceNumber());1092}1093}1094// J91095else if (node->getOpCodeValue() == TR::monent ||1096node->getOpCodeValue() == TR::monexit ||1097node->getOpCodeValue() == TR::tstart )1098{1099TR_OpaqueClassBlock * monClass = node->getMonitorClass(self()->comp()->getCurrentMethod());1100if (monClass)1101self()->addMonClass(node, monClass);1102//Clear the hidden second child that may be used by code generation1103node->setMonitorClassInNode(NULL);1104}110511061107// J91108if (self()->comp()->getOption(TR_ReservingLocks) &&1109node->getOpCodeValue() == TR::monent)1110{1111TR_OpaqueMethodBlock *owningMethod = node->getOwningMethod();1112TR_OpaqueClassBlock *classPointer = fej9->getClassOfMethod(owningMethod);1113TR_PersistentClassInfo * persistentClassInfo =1114self()->comp()->getPersistentInfo()->getPersistentCHTable()->findClassInfoAfterLocking(classPointer, self()->comp());11151116if (persistentClassInfo && persistentClassInfo->isReservable())1117{1118bool allowedToReserve = !scanForNativeMethodsUntilMonitorNode(tt->getNextTreeTop(), self()->comp());1119if (!allowedToReserve)1120{1121persistentClassInfo->setReservable(false);1122#if defined(J9VM_OPT_JITSERVER)1123// This is currently the only place where this flag gets cleared. For JITServer, we should propagate it to the client,1124// to avoid having to call scanForNativeMethodsUntilMonitorNode again.1125if (auto stream = TR::CompilationInfo::getStream())1126{1127stream->write(JITServer::MessageType::CHTable_clearReservable, classPointer);1128stream->read<JITServer::Void>();1129}1130#endif /* defined(J9VM_OPT_JITSERVER) */1131}1132}1133}11341135// J91136if ( self()->comp()->getOptions()->enableDebugCounters()1137&& node->getOpCode().isCall()1138&& node->getSymbol()->getMethodSymbol() // compjazz 45988: zEmulator arrayset currently isCall and uses a generic int shadow. Can't assume it's a method.1139&& !node->getSymbol()->castToMethodSymbol()->isHelper())1140{1141bool insertByteCode = TR::Options::_debugCounterInsertByteCode;1142bool insertJittedBody = TR::Options::_debugCounterInsertJittedBody;1143bool insertMethod = TR::Options::_debugCounterInsertMethod;11441145const char *caller = self()->comp()->signature();1146const char *callee = node->getSymbol()->castToMethodSymbol()->getMethod()->signature(self()->trMemory(), stackAlloc);1147TR_ByteCodeInfo &bcInfo = node->getByteCodeInfo();1148if (insertByteCode)1149{1150TR::DebugCounter::prependDebugCounter(self()->comp(), TR::DebugCounter::debugCounterName(self()->comp(),1151"compilationReport.instructions:byByteCode.numInvocations.(%s)=%d", caller, node->getByteCodeInfo().getByteCodeIndex()), tt);1152}1153if (insertJittedBody)1154{1155TR::DebugCounter::prependDebugCounter(self()->comp(), TR::DebugCounter::debugCounterName(self()->comp(),1156"compilationReport.instructions:byJittedBody.numInvocations.(%s).%s", caller, self()->comp()->getHotnessName()), tt);1157}1158if (insertMethod)1159{1160TR::DebugCounter::prependDebugCounter(self()->comp(), TR::DebugCounter::debugCounterName(self()->comp(),1161"compilationReport.instructions:byMethod.numInvocations.(%s)", caller), tt);1162}1163TR::DebugCounter::prependDebugCounter(self()->comp(), TR::DebugCounter::debugCounterName(self()->comp(), "callers/(%s)/%d=%d", caller, bcInfo.getCallerIndex(), bcInfo.getByteCodeIndex()), tt);1164TR::DebugCounter::prependDebugCounter(self()->comp(), TR::DebugCounter::debugCounterName(self()->comp(), "callees/(%s)/(%s)/%d=%d", callee, caller, bcInfo.getCallerIndex(), bcInfo.getByteCodeIndex()), tt);1165}11661167// J91168//1169// We uncommon all the address children of a direct to JNI call1170// because if the loadaddr is commoned across a GC point, we cannot mark the register1171// as collected (since it is not a Java object) and we can have a problem if we do not1172// mark in some other way if the stack grows (and is moved) at the GC point. The problem1173// will be that the register will continue to point at the old stack.1174//1175if (node->getOpCode().isCall() &&1176node->getSymbol()->getMethodSymbol() &&1177node->isPreparedForDirectJNI())1178{1179int32_t i;1180for (i = 0; i < node->getNumChildren(); ++i)1181{1182TR::Node * n = node->getChild(i);1183if (n->getDataType() == TR::Address)1184{1185//TR_ASSERT((n->getOpCodeValue() == TR::loadaddr), "Address child of JNI call is not a loadaddr\n");1186if ((n->getOpCodeValue() == TR::loadaddr) &&1187(n->getReferenceCount() > 1) &&1188n->getSymbol()->isAutoOrParm())1189{1190//printf("Uncommoned address child of JNI call in %s\n", comp()->signature());1191TR::Node *dupChild = n->duplicateTree();1192node->setAndIncChild(i, dupChild);1193n->recursivelyDecReferenceCount();1194}1195}1196}1197}11981199// J91200// code to push recompilation of methods whose caller is scorching1201if (self()->comp()->getOption(TR_EnableRecompilationPushing) &&1202!self()->getCurrentBlock()->isCold() &&1203self()->comp()->allowRecompilation() &&1204self()->comp()->getMethodHotness()>=veryHot &&1205node->getOpCode().isCall() &&1206self()->comp()->getPersistentInfo()->getNumLoadedClasses() < TR::Options::_bigAppThreshold &&1207node->getSymbol()->getMethodSymbol() &&1208!node->isPreparedForDirectJNI())1209{1210bool pushCall = true;1211TR::MethodSymbol *methodSymbol = node->getSymbol()->getMethodSymbol();1212TR::SymbolReference *methodSymRef = node->getSymbolReference();12131214if (methodSymRef->isUnresolved())1215{1216pushCall = false;1217}1218else if (!node->getOpCode().isCallDirect() || methodSymbol->isVirtual())1219{1220TR_ResolvedMethod *resolvedMethod = node->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod();1221if (!resolvedMethod || node->isTheVirtualCallNodeForAGuardedInlinedCall() ||1222resolvedMethod->virtualMethodIsOverridden() ||1223resolvedMethod->isAbstract() ||1224(resolvedMethod == self()->comp()->getCurrentMethod()))1225{1226pushCall = false;1227}1228}12291230if (pushCall)1231{1232if (!((methodSymbol && methodSymbol->getResolvedMethodSymbol() &&1233methodSymbol->getResolvedMethodSymbol()->getResolvedMethod() &&1234methodSymbol->getResolvedMethodSymbol()->getResolvedMethod()->isInterpretedForHeuristics()) ||1235methodSymbol->isVMInternalNative() ||1236methodSymbol->isHelper() ||1237methodSymbol->isNative() ||1238methodSymbol->isSystemLinkageDispatch() ||1239methodSymbol->isJITInternalNative()) &&1240methodSymbol->getResolvedMethodSymbol() &&1241methodSymbol->getResolvedMethodSymbol()->getResolvedMethod())1242{1243TR_PersistentJittedBodyInfo * bodyInfo = ((TR_ResolvedJ9Method*) methodSymbol->getResolvedMethodSymbol()->getResolvedMethod())->getExistingJittedBodyInfo();1244//printf("Pushing node %p\n", node);1245//fflush(stdout);1246if (bodyInfo &&1247bodyInfo->getHotness() <= warm && !bodyInfo->getIsProfilingBody())1248{1249TR_ResolvedMethod *method = methodSymbol->castToResolvedMethodSymbol()->getResolvedMethod();1250int isInLoop = -1;1251TR::Block * block = self()->getCurrentBlock();12521253TR_BlockStructure * blockStructure = block->getStructureOf();1254if (blockStructure)1255{1256TR_Structure *parentStructure = blockStructure->getParent();1257while (parentStructure)1258{1259TR_RegionStructure *region = parentStructure->asRegion();1260if (region->isNaturalLoop() ||1261region->containsInternalCycles())1262{1263isInLoop = region->getNumber();1264break;1265}1266parentStructure = parentStructure->getParent();1267}1268}12691270//printf ("Scorching method %s is calling warm (or called method) %s, in block_%d with frequency %d, is in loop %d\n", comp()->getMethodSymbol()->signature(), fej9->sampleSignature(method->getPersistentIdentifier(), 0, 0, trMemory()), getCurrentBlock()->getNumber(), getCurrentBlock()->getFrequency(), isInLoop);1271if ((self()->getCurrentBlock()->getFrequency() > MAX_COLD_BLOCK_COUNT) || (isInLoop && self()->getCurrentBlock()->getFrequency()==0))1272{1273bodyInfo->setCounter(1);1274bodyInfo->setIsPushedForRecompilation();1275}1276}1277}1278}1279}12801281// J91282if (node->getOpCodeValue() == TR::instanceof)1283{1284TR::Node * topNode = tt->getNode();1285if (topNode->getNumChildren() > 0)1286topNode = topNode->getFirstChild();12871288if (topNode->getOpCode().isCall() &&1289topNode->getSymbol()->getMethodSymbol() &&1290(topNode->getSymbol()->getMethodSymbol()->isSystemLinkageDispatch() ||1291topNode->isPreparedForDirectJNI()))1292{1293TR::Node * ttNode = TR::Node::create(TR::treetop, 1, node);1294tt->getPrevTreeTop()->insertAfter(TR::TreeTop::create(self()->comp(), ttNode));1295}1296}12971298// J91299if (node->getOpCodeValue() == TR::NULLCHK)1300{1301if ((node->getFirstChild()->getReferenceCount() == 1) &&1302node->getFirstChild()->getOpCode().isLoadVar() &&1303!node->getFirstChild()->getSymbolReference()->getSymbol()->isVolatile())1304{1305TR::Node::recreate(node->getFirstChild(), TR::PassThrough);1306}1307}13081309// J91310//1311//Anchoring node to either extract register pressure(performance)1312//or ensure instanceof doesn't have a parent node of CALL (correctness)1313//1314char *anchoringReason = "register hog";1315switch (node->getOpCodeValue())1316{1317// Extract heavy register pressure trees when dictated at the start of the walk1318// (typically IA32 on system linkage calls when there is one fewer register).1319case TR::ldiv:1320case TR::lrem:1321case TR::lcmp:1322{13231324if (!self()->removeRegisterHogsInLowerTreesWalk())1325break;1326}1327// Instanceof might requires this transformation for the reason of either register pressure1328// or ensure no parent node of CALL1329case TR::instanceof:1330{1331// For correctness, all we really need here is to ensure instanceof1332// doesn't have a parent of native call. But even java call would1333// create control flow to setup linkage, which might cause conflict1334// with the instanceof control flow.1335if(parent->getOpCode().isCall())1336{1337anchoringReason = "call-like";1338}13391340else if (!self()->removeRegisterHogsInLowerTreesWalk())1341break;13421343TR::Node *ttNode = TR::Node::create(TR::treetop, 1, node);1344tt->getPrevTreeTop()->insertAfter(TR::TreeTop::create(self()->comp(), ttNode));1345if (self()->comp()->getOption(TR_TraceCG))1346traceMsg(self()->comp(), "Anchoring %s node %s [%p] under treetop [%p]\n", anchoringReason, node->getOpCode().getName(), node, ttNode);1347break;1348}1349default:1350break;13511352}13531354}135513561357static bool isArraySizeSymbolRef(TR::SymbolReference *s, TR::SymbolReferenceTable *symRefTab)1358{1359// TODO: Move to compile/SymbolReferenceTable.hpp1360return (s!=NULL) && (s == symRefTab->findContiguousArraySizeSymbolRef() || s == symRefTab->findDiscontiguousArraySizeSymbolRef());1361}136213631364void1365J9::CodeGenerator::moveUpArrayLengthStores(TR::TreeTop *insertionPoint)1366{1367// 174954: Until TR::arraylength has a symref with proper aliasing, we have to1368// make sure that stores to the array length field occur before all arraylength1369// trees. Good news is that all such stores are inserted by escape1370// analysis, so they always have a loadaddr as one child and a constant as1371// the other, so they can be trivially moved to the top of the block.1372//1373for (TR::TreeTop *tt = insertionPoint->getNextTreeTop(); tt; tt = tt->getNextTreeTop())1374{1375if (tt->getNode()->getOpCodeValue() == TR::BBStart && !tt->getNode()->getBlock()->isExtensionOfPreviousBlock())1376break;1377TR::Node *store = tt->getNode()->getStoreNode();1378if (store && store->getOpCode().isStoreIndirect() && isArraySizeSymbolRef(store->getSymbolReference(), self()->symRefTab()))1379{1380if (store->getFirstChild()->getOpCodeValue() != TR::loadaddr)1381{1382dumpOptDetails(self()->comp(), "MOVE UP ARRAY LENGTH STORES: WARNING! First child of %p is %s; expected loadaddr\n", store, store->getFirstChild()->getOpCode().getName());1383}1384else if (!store->getSecondChild()->getOpCode().isLoadConst())1385{1386dumpOptDetails(self()->comp(), "MOVE UP ARRAY LENGTH STORES: WARNING! Second child of %p is %s; expected const\n", store, store->getSecondChild()->getOpCode().getName());1387}1388else1389{1390dumpOptDetails(self()->comp(), "MOVE UP ARRAY LENGTH STORES: Moving %s %p up after %p\n", tt->getNode()->getOpCode().getName(), tt->getNode(), insertionPoint->getNode());1391tt->unlink(false);1392insertionPoint->insertAfter(tt);1393insertionPoint = tt;1394}1395}1396}1397}139813991400void1401J9::CodeGenerator::zeroOutAutoOnEdge(1402TR::SymbolReference *liveAutoSymRef,1403TR::Block *block,1404TR::Block *succBlock,1405TR::list<TR::Block*> *newBlocks,1406TR_ScratchList<TR::Node> *fsdStores)1407{1408TR::Block *storeBlock = NULL;1409if ((succBlock->getPredecessors().size() == 1))1410storeBlock = succBlock;1411else1412{1413for (auto blocksIt = newBlocks->begin(); blocksIt != newBlocks->end(); ++blocksIt)1414{1415if ((*blocksIt)->getSuccessors().front()->getTo()->asBlock() == succBlock)1416{1417storeBlock = *blocksIt;1418break;1419}1420}1421}14221423if (!storeBlock)1424{1425TR::TreeTop * startTT = succBlock->getEntry();1426TR::Node * startNode = startTT->getNode();1427TR::Node * glRegDeps = NULL;1428if (startNode->getNumChildren() > 0)1429glRegDeps = startNode->getFirstChild();14301431TR::Block * newBlock = block->splitEdge(block, succBlock, self()->comp(), NULL, false);14321433if (debug("traceFSDSplit"))1434diagnostic("\nSplitting edge, create new intermediate block_%d", newBlock->getNumber());14351436if (glRegDeps)1437{1438TR::Node *duplicateGlRegDeps = glRegDeps->duplicateTree();1439TR::Node *origDuplicateGlRegDeps = duplicateGlRegDeps;1440duplicateGlRegDeps = TR::Node::copy(duplicateGlRegDeps);1441newBlock->getEntry()->getNode()->setNumChildren(1);1442newBlock->getEntry()->getNode()->setAndIncChild(0, origDuplicateGlRegDeps);1443for (int32_t i = origDuplicateGlRegDeps->getNumChildren() - 1; i >= 0; --i)1444{1445TR::Node * dep = origDuplicateGlRegDeps->getChild(i);1446if(self()->comp()->getOption(TR_MimicInterpreterFrameShape) || self()->comp()->getOption(TR_PoisonDeadSlots))1447dep->setRegister(NULL); // basically need to do prepareNodeForInstructionSelection1448duplicateGlRegDeps->setAndIncChild(i, dep);1449}1450if(self()->comp()->getOption(TR_MimicInterpreterFrameShape) || self()->comp()->getOption(TR_PoisonDeadSlots))1451{1452TR::Node *glRegDepsParent;1453if ( (newBlock->getSuccessors().size() == 1)1454&& newBlock->getSuccessors().front()->getTo()->asBlock()->getEntry() == newBlock->getExit()->getNextTreeTop())1455{1456glRegDepsParent = newBlock->getExit()->getNode();1457}1458else1459{1460glRegDepsParent = newBlock->getExit()->getPrevTreeTop()->getNode();1461TR_ASSERT(glRegDepsParent->getOpCodeValue() == TR::Goto, "Expected block to fall through or end in goto; it ends with %s %s\n",1462self()->getDebug()->getName(glRegDepsParent->getOpCodeValue()), self()->getDebug()->getName(glRegDepsParent));1463}1464if (self()->comp()->getOption(TR_TraceCG))1465traceMsg(self()->comp(), "zeroOutAutoOnEdge: glRegDepsParent is %s\n", self()->getDebug()->getName(glRegDepsParent));1466glRegDepsParent->setNumChildren(1);1467glRegDepsParent->setAndIncChild(0, duplicateGlRegDeps);1468}1469else //original path1470{1471newBlock->getExit()->getNode()->setNumChildren(1);1472newBlock->getExit()->getNode()->setAndIncChild(0, duplicateGlRegDeps);1473}1474}14751476newBlock->setLiveLocals(new (self()->trHeapMemory()) TR_BitVector(*succBlock->getLiveLocals()));1477newBlock->getEntry()->getNode()->setLabel(generateLabelSymbol(self()));147814791480if (self()->comp()->getOption(TR_PoisonDeadSlots))1481{1482if (self()->comp()->getOption(TR_TraceCG))1483traceMsg(self()->comp(), "POISON DEAD SLOTS --- New Block Created %d\n", newBlock->getNumber());1484newBlock->setIsCreatedAtCodeGen();1485}14861487newBlocks->push_front(newBlock);1488storeBlock = newBlock;1489}1490TR::Node *storeNode;14911492if (self()->comp()->getOption(TR_PoisonDeadSlots))1493storeNode = self()->generatePoisonNode(block, liveAutoSymRef);1494else1495storeNode = TR::Node::createStore(liveAutoSymRef, TR::Node::aconst(block->getEntry()->getNode(), 0));14961497if (storeNode)1498{1499TR::TreeTop *storeTree = TR::TreeTop::create(self()->comp(), storeNode);1500storeBlock->prepend(storeTree);1501fsdStores->add(storeNode);1502}1503}150415051506void1507J9::CodeGenerator::doInstructionSelection()1508{1509J9::SetMonitorStateOnBlockEntry::LiveMonitorStacks liveMonitorStacks(1510(J9::SetMonitorStateOnBlockEntry::LiveMonitorStacksComparator()),1511J9::SetMonitorStateOnBlockEntry::LiveMonitorStacksAllocator(self()->comp()->trMemory()->heapMemoryRegion()));1512151315141515// Set default value for pre-prologue size1516//1517TR::ResolvedMethodSymbol * methodSymbol = self()->comp()->getJittedMethodSymbol();1518self()->setPrePrologueSize(4 + (methodSymbol->isJNI() ? 4 : 0));15191520if (self()->comp()->getOption(TR_TraceCG))1521diagnostic("\n<selection>");15221523if (self()->comp()->getOption(TR_TraceCG) || debug("traceGRA"))1524self()->comp()->getDebug()->setupToDumpTreesAndInstructions("Performing Instruction Selection");15251526self()->beginInstructionSelection();15271528{1529TR::StackMemoryRegion stackMemoryRegion(*self()->trMemory());15301531TR_BitVector * liveLocals = self()->getLiveLocals();1532TR_BitVector nodeChecklistBeforeDump(self()->comp()->getNodeCount(), self()->trMemory(), stackAlloc, growable);15331534/*1535To enable instruction scheduling (both in the compiler and in out-of-order hardware),1536we would prefer not to reuse the same memory to represent multiple temps inside1537a tight loop. At higher opt levels, therefore, we only free variable size symrefs at1538back edges. To prevent pathological cases from consuming too much stack space, we set a1539cap on the number of extended basic blocks before we stop waiting for a back edge and free1540our temps anyway.1541*/1542const uint32_t MAX_EBBS_BEFORE_FREEING_VARIABLE_SIZED_SYMREFS = 10;1543uint32_t numEBBsSinceFreeingVariableSizeSymRefs = 0;15441545TR_BitVector * liveMonitors = 0;1546TR_Stack<TR::SymbolReference *> * liveMonitorStack = 0;1547int32_t numMonitorLocals = 0;1548static bool traceLiveMonEnv = feGetEnv("TR_traceLiveMonitors") ? true : false;1549bool traceLiveMon = self()->comp()->getOption(TR_TraceLiveMonitorMetadata) || traceLiveMonEnv;15501551_lmmdFailed = false;1552if (self()->comp()->getMethodSymbol()->mayContainMonitors())1553{1554if(traceLiveMon)1555traceMsg(self()->comp(),"In doInstructionSelection: Method may contain monitors\n");15561557if (!liveLocals)1558self()->comp()->getMethodSymbol()->resetLiveLocalIndices();15591560ListIterator<TR::AutomaticSymbol> locals(&self()->comp()->getMethodSymbol()->getAutomaticList());1561for (TR::AutomaticSymbol * a = locals.getFirst(); a; a = locals.getNext())1562if (a->holdsMonitoredObject())1563{1564if(traceLiveMon)1565traceMsg(self()->comp(),"\tSymbol %p contains monitored object\n",a);1566if (!liveLocals)1567{1568if(traceLiveMon)1569traceMsg(self()->comp(),"\tsetting LiveLocalIndex to %d on symbol %p\n",numMonitorLocals+1,a);1570a->setLiveLocalIndex(numMonitorLocals++, self()->fe());1571}1572else if (a->getLiveLocalIndex() + 1 > numMonitorLocals)1573{1574if(traceLiveMon)1575traceMsg(self()->comp(),"\tsetting numMonitorLocals to %d while considering symbol %p\n",a->getLiveLocalIndex()+1,a);1576numMonitorLocals = a->getLiveLocalIndex() + 1;1577}1578}15791580if (numMonitorLocals)1581{1582J9::SetMonitorStateOnBlockEntry monitorState(self()->comp(), &liveMonitorStacks);15831584if(traceLiveMon)1585traceMsg(self()->comp(),"\tCreated monitorState %p\n",&monitorState);15861587monitorState.set(_lmmdFailed, traceLiveMon);1588if (traceLiveMon)1589traceMsg(self()->comp(), "found numMonitorLocals %d\n", numMonitorLocals);1590}1591else if(traceLiveMon)1592traceMsg(self()->comp(),"\tnumMonitorLocals = %d\n",numMonitorLocals);1593}15941595TR::SymbolReference **liveLocalSyms = NULL;1596TR_BitVector *unsharedSymsBitVector = NULL;1597int32_t maxLiveLocalIndex = -1;1598TR::list<TR::Block*> newBlocks(getTypedAllocator<TR::Block*>(self()->comp()->allocator()));1599TR_ScratchList<TR::Node> fsdStores(self()->trMemory());1600if (self()->comp()->getOption(TR_MimicInterpreterFrameShape) || self()->comp()->getOption(TR_PoisonDeadSlots))1601{1602if (self()->comp()->areSlotsSharedByRefAndNonRef() || self()->comp()->getOption(TR_PoisonDeadSlots))1603{1604TR_ScratchList<TR::SymbolReference> participatingLocals(self()->trMemory());16051606TR::SymbolReference *autoSymRef = NULL;1607int32_t symRefNumber;1608int32_t symRefCount = self()->comp()->getSymRefCount();1609TR::SymbolReferenceTable *symRefTab = self()->comp()->getSymRefTab();1610for (symRefNumber = symRefTab->getIndexOfFirstSymRef(); symRefNumber < symRefCount; symRefNumber++)1611{1612autoSymRef = symRefTab->getSymRef(symRefNumber);1613if (autoSymRef &&1614autoSymRef->getSymbol() &&1615autoSymRef->getSymbol()->isAuto() &&1616(autoSymRef->getSymbol()->castToAutoSymbol()->getLiveLocalIndex() != (uint16_t)-1))1617{1618TR::AutomaticSymbol * autoSym = autoSymRef->getSymbol()->castToAutoSymbol();1619if (methodSymbol->getAutomaticList().find(autoSym))1620{1621participatingLocals.add(autoSymRef);16221623if (autoSym->getLiveLocalIndex() > maxLiveLocalIndex)1624maxLiveLocalIndex = autoSym->getLiveLocalIndex();1625}1626}1627}16281629liveLocalSyms = (TR::SymbolReference **)self()->trMemory()->allocateStackMemory((maxLiveLocalIndex+1)*sizeof(TR::SymbolReference *));1630memset(liveLocalSyms, 0, (maxLiveLocalIndex+1)*sizeof(TR::SymbolReference *));1631unsharedSymsBitVector = new (self()->trStackMemory()) TR_BitVector(maxLiveLocalIndex+1, self()->trMemory(), stackAlloc);16321633ListIterator<TR::SymbolReference> participatingLocalsIt(&participatingLocals);1634for (autoSymRef = participatingLocalsIt.getFirst(); autoSymRef; autoSymRef = participatingLocalsIt.getNext())1635{1636TR::AutomaticSymbol * autoSym = autoSymRef->getSymbol()->castToAutoSymbol();1637liveLocalSyms[autoSym->getLiveLocalIndex()] = autoSymRef;1638if (!autoSym->isSlotSharedByRefAndNonRef())1639{1640//dumpOptDetails("Unshared symRef %d live local index %d\n", autoSymRef->getReferenceNumber(), autoSym->getLiveLocalIndex());1641unsharedSymsBitVector->set(autoSym->getLiveLocalIndex());1642}1643}1644}1645else1646liveLocals = NULL;1647}16481649bool fixedUpBlock = false;16501651for (TR::TreeTop *tt = self()->comp()->getStartTree(); tt; tt = self()->getCurrentEvaluationTreeTop()->getNextTreeTop())1652{1653if(traceLiveMon)1654traceMsg(self()->comp(),"\tWalking TreeTops at tt %p with node %p\n",tt,tt->getNode());16551656TR::Instruction *prevInstr = self()->getAppendInstruction();1657TR::Node * node = tt->getNode();1658TR::ILOpCodes opCode = node->getOpCodeValue();16591660TR::Node * firstChild = node->getNumChildren() > 0 ? node->getFirstChild() : 0;16611662if (opCode == TR::BBStart)1663{1664fixedUpBlock = false;1665TR::Block *block = node->getBlock();1666self()->setCurrentEvaluationBlock(block);1667self()->resetMethodModifiedByRA();16681669liveMonitorStack = (liveMonitorStacks.find(block->getNumber()) != liveMonitorStacks.end()) ?1670liveMonitorStacks[block->getNumber()] :1671NULL;16721673if (!block->isExtensionOfPreviousBlock())1674{1675// If we are keeping track of live locals, set up the live locals for1676// this block1677//1678if (liveLocals)1679{1680if (block->getLiveLocals())1681liveLocals = new (self()->trHeapMemory()) TR_BitVector(*block->getLiveLocals());1682else1683{1684liveLocals = new (self()->trHeapMemory()) TR_BitVector(*liveLocals);1685liveLocals->empty();1686}16871688if (self()->comp()->areSlotsSharedByRefAndNonRef() && unsharedSymsBitVector)1689{1690*liveLocals |= *unsharedSymsBitVector;1691}1692}169316941695if (liveMonitorStack)1696{1697liveMonitors = new (self()->trHeapMemory()) TR_BitVector(numMonitorLocals, self()->trMemory());1698if (traceLiveMon)1699traceMsg(self()->comp(), "created liveMonitors bitvector at block_%d for stack %p size %d\n",1700block->getNumber(), liveMonitorStack,1701liveMonitorStack->size());1702for (int32_t i = liveMonitorStack->size() - 1; i >= 0; --i)1703{1704if (traceLiveMon)1705traceMsg(self()->comp(), "about to set liveMonitors for symbol %p\n",(*liveMonitorStack)[i]->getSymbol());1706liveMonitors->set((*liveMonitorStack)[i]->getSymbol()->castToRegisterMappedSymbol()->getLiveLocalIndex());1707if (traceLiveMon)1708traceMsg(self()->comp(), "setting livemonitor %d at block_%d\n",1709(*liveMonitorStack)[i]->getSymbol()->castToRegisterMappedSymbol()->getLiveLocalIndex(),1710block->getNumber());1711}1712}1713else1714{1715liveMonitors = 0;1716if (traceLiveMon)1717traceMsg(self()->comp(), "no liveMonitorStack for block_%d\n", block->getNumber());1718}1719numEBBsSinceFreeingVariableSizeSymRefs++;1720}17211722if (self()->getDebug())1723self()->getDebug()->roundAddressEnumerationCounters();17241725#if DEBUG1726// Verify that we are only being more conservative by inheriting the live1727// local information from the previous block.1728//1729else if (liveLocals && debug("checkBlockEntryLiveLocals"))1730{1731TR_BitVector *extendedBlockLocals = new (self()->trStackMemory()) TR_BitVector(*(block->getLiveLocals()));1732*extendedBlockLocals -= *(liveLocals);17331734TR_ASSERT(extendedBlockLocals->isEmpty(),1735"Live local information is *less* pessimistic!\n");1736}1737#endif1738}1739else if (opCode == TR::BBEnd)1740{1741TR::Block *b = self()->getCurrentEvaluationBlock();17421743// checks for consistent monitorStack1744//1745for (auto e = b->getSuccessors().begin(); e != b->getSuccessors().end(); ++e)1746if ((*e)->getTo() == self()->comp()->getFlowGraph()->getEnd())1747{1748// block could end in a throw,1749//1750TR::TreeTop *lastRealTT = b->getLastRealTreeTop();1751// last warm blocks could end in a goto1752//1753if (lastRealTT->getNode()->getOpCode().isGoto())1754lastRealTT = lastRealTT->getPrevTreeTop();17551756TR::Node *n = lastRealTT->getNode();1757if (n->getOpCodeValue() == TR::treetop ||1758n->getOpCode().isCheck())1759n = n->getFirstChild();17601761bool endsInThrow = false;1762if (n->getOpCode().isCall() &&1763(n->getSymbolReference()->getReferenceNumber() == TR_aThrow))1764endsInThrow = true;1765else if (n->getOpCodeValue() == TR::Return)1766{1767// a check that is going to fail1768//1769TR::TreeTop *prev = lastRealTT->getPrevTreeTop();1770if ((prev->getNode()->getOpCodeValue() == TR::asynccheck) ||1771(prev->getNode()->getOpCodeValue() == TR::treetop))1772prev = prev->getPrevTreeTop();1773if (prev->getNode()->getOpCode().isCheck())1774endsInThrow = true;1775}17761777if (liveMonitorStack &&1778liveMonitorStack->size() != 0 &&1779!endsInThrow)1780dumpOptDetails(self()->comp(), "liveMonitorStack must be empty, unbalanced monitors found! %d\n",1781liveMonitorStack->size());17821783if (traceLiveMon)1784{1785traceMsg(self()->comp(), "liveMonitorStack %p at CFG end (syncMethod %d)", liveMonitorStack,1786self()->comp()->getMethodSymbol()->isSynchronised());1787if (liveMonitorStack)1788traceMsg(self()->comp(), " size %d\n", liveMonitorStack->size());1789else1790traceMsg(self()->comp(), " size empty\n");1791}1792break;1793}17941795bool endOfEBB = !(b->getNextBlock() && b->getNextBlock()->isExtensionOfPreviousBlock());1796if (endOfEBB &&1797(b->branchesBackwards() ||1798numEBBsSinceFreeingVariableSizeSymRefs > MAX_EBBS_BEFORE_FREEING_VARIABLE_SIZED_SYMREFS))1799{1800if (self()->traceBCDCodeGen())1801traceMsg(self()->comp(),"\tblock_%d branches backwards, so free all symbols in the _variableSizeSymRefPendingFreeList\n",b->getNumber());1802self()->freeAllVariableSizeSymRefs();1803numEBBsSinceFreeingVariableSizeSymRefs = 0;1804}1805}18061807if (((opCode == TR::BBEnd) && !fixedUpBlock) ||1808node->getOpCode().isBranch() ||1809node->getOpCode().isSwitch())1810{1811fixedUpBlock = true;1812//GCMAP1813if ( (self()->comp()->getOption(TR_MimicInterpreterFrameShape) && self()->comp()->areSlotsSharedByRefAndNonRef() ) || self()->comp()->getOption(TR_PoisonDeadSlots))1814{1815// TODO : look at last warm block code above1816//1817if ((!self()->comp()->getOption(TR_PoisonDeadSlots)&& liveLocals) || (self()->comp()->getOption(TR_PoisonDeadSlots) && self()->getCurrentEvaluationBlock()->getLiveLocals()))1818{1819newBlocks.clear();1820TR::Block *block = self()->getCurrentEvaluationBlock();18211822TR_BitVectorIterator bvi(self()->comp()->getOption(TR_PoisonDeadSlots) ? *block->getLiveLocals(): *liveLocals);18231824if (self()->comp()->getOption(TR_TraceCG) && self()->comp()->getOption(TR_PoisonDeadSlots))1825traceMsg(self()->comp(), "POISON DEAD SLOTS --- Parent Block Number: %d\n", block->getNumber());182618271828while (bvi.hasMoreElements())1829{1830int32_t liveLocalIndex = bvi.getNextElement();1831TR_ASSERT((liveLocalIndex <= maxLiveLocalIndex), "Symbol has live local index higher than computed max\n");1832TR::SymbolReference * liveAutoSymRef = liveLocalSyms[liveLocalIndex];18331834if (self()->comp()->getOption(TR_TraceCG) && self()->comp()->getOption(TR_PoisonDeadSlots))1835traceMsg(self()->comp(), "POISON DEAD SLOTS --- Parent Block: %d, Maintained Live Local: %d\n", block->getNumber(), liveAutoSymRef->getReferenceNumber());18361837if(self()->comp()->getOption(TR_PoisonDeadSlots) && (!liveAutoSymRef || block->isCreatedAtCodeGen()))1838{1839//Don't process a block we created to poison a dead slot.1840continue;1841}18421843if(!liveAutoSymRef)1844{1845continue;1846}1847TR::AutomaticSymbol * liveAutoSym = liveAutoSymRef->getSymbol()->castToAutoSymbol();18481849//For slot poisoning, a monitored object is still in the GCMaps even if its liveness has ended.1850//1851if ((liveAutoSym->getType().isAddress() && liveAutoSym->isSlotSharedByRefAndNonRef()) || (self()->comp()->getOption(TR_PoisonDeadSlots) && !liveAutoSymRef->getSymbol()->holdsMonitoredObject()))1852{1853for (auto succ = block->getSuccessors().begin(); succ != block->getSuccessors().end();)1854{1855auto next = succ;1856++next;1857if ((*succ)->getTo() == self()->comp()->getFlowGraph()->getEnd())1858{1859succ = next;1860continue;1861}1862TR::Block *succBlock = (*succ)->getTo()->asBlock();18631864if (self()->comp()->getOption(TR_PoisonDeadSlots) && succBlock->isExtensionOfPreviousBlock())1865{1866if (self()->comp()->getOption(TR_TraceCG) && self()->comp()->getOption(TR_PoisonDeadSlots))1867traceMsg(self()->comp(), "POISON DEAD SLOTS --- Successor Block Number %d is extension of Parent Block %d ... skipping \n", succBlock->getNumber(), block->getNumber());1868succ = next;1869continue; //We cannot poison in an extended block as gcmaps are still live for maintained live locals !!!! if target of jump, ignore, could be extension1870}18711872if (self()->comp()->getOption(TR_TraceCG) && self()->comp()->getOption(TR_PoisonDeadSlots))1873traceMsg(self()->comp(), "POISON DEAD SLOTS --- Successor Block Number %d, of Parent Block %d \n", succBlock->getNumber(), block->getNumber());18741875TR_BitVector *succLiveLocals = succBlock->getLiveLocals();1876if (succLiveLocals && !succLiveLocals->get(liveLocalIndex)) //added1877{1878bool zeroOut = true;1879TR_BitVectorIterator sbvi(*succLiveLocals);1880while (sbvi.hasMoreElements())1881{1882int32_t succLiveLocalIndex = sbvi.getNextElement();1883TR_ASSERT((succLiveLocalIndex <= maxLiveLocalIndex), "Symbol has live local index higher than computed max\n");1884TR::SymbolReference * succLiveAutoSymRef = liveLocalSyms[succLiveLocalIndex];1885if (self()->comp()->getOption(TR_TraceCG) && self()->comp()->getOption(TR_PoisonDeadSlots))1886traceMsg(self()->comp(), "POISON DEAD SLOTS --- Successor Block %d contains live local %d\n", succBlock->getNumber(), succLiveAutoSymRef->getReferenceNumber());18871888TR::AutomaticSymbol * succLiveAutoSym = succLiveAutoSymRef->getSymbol()->castToAutoSymbol();1889if ( (succLiveAutoSym->getType().isAddress() && succLiveAutoSym->isSlotSharedByRefAndNonRef()) || self()->comp()->getOption(TR_PoisonDeadSlots))1890{1891if ((succLiveAutoSym->getGCMapIndex() == liveAutoSym->getGCMapIndex()) ||1892((TR::Symbol::convertTypeToNumberOfSlots(succLiveAutoSym->getDataType()) == 2) &&1893((succLiveAutoSym->getGCMapIndex()+1) == liveAutoSym->getGCMapIndex())))1894{1895zeroOut = false;1896break;1897}1898}1899}19001901if (zeroOut)1902{1903self()->comp()->getFlowGraph()->setStructure(0);1904self()->zeroOutAutoOnEdge(liveAutoSymRef, block, succBlock, &newBlocks, &fsdStores);1905}1906}1907succ = next;1908}19091910// TODO : Think about exc edges case below1911//1912for (auto esucc = block->getExceptionSuccessors().begin(); esucc != block->getExceptionSuccessors().end(); ++esucc)1913{1914TR::Block *esuccBlock = (*esucc)->getTo()->asBlock();1915//since we have asked the liveness analysis to assume that uses in the OSR block don't exist1916//in certain cases, this code thinks that some locals are dead in the OSR block so it tries1917//to zero them out. But we don't want that to happen1918if (esuccBlock->isOSRCodeBlock() || esuccBlock->isOSRCatchBlock())1919continue;1920TR_BitVector *esuccLiveLocals = esuccBlock->getLiveLocals();1921TR_ASSERT(esuccLiveLocals, "No live locals for successor block\n");1922if (!esuccLiveLocals->get(liveLocalIndex))1923{1924bool zeroOut = true;1925TR_BitVectorIterator sbvi(*esuccLiveLocals);1926while (sbvi.hasMoreElements())1927{1928int32_t succLiveLocalIndex = sbvi.getNextElement();1929TR_ASSERT((succLiveLocalIndex <= maxLiveLocalIndex), "Symbol has live local index higher than computed max\n");1930TR::SymbolReference * succLiveAutoSymRef = liveLocalSyms[succLiveLocalIndex];1931TR::AutomaticSymbol * succLiveAutoSym = succLiveAutoSymRef->getSymbol()->castToAutoSymbol();1932if ( succLiveAutoSym->getType().isAddress() && ( succLiveAutoSym->isSlotSharedByRefAndNonRef() || self()->comp()->getOption(TR_PoisonDeadSlots)))1933{1934if ((succLiveAutoSym->getGCMapIndex() == liveAutoSym->getGCMapIndex()) ||1935((TR::Symbol::convertTypeToNumberOfSlots(succLiveAutoSym->getDataType()) == 2) &&1936((succLiveAutoSym->getGCMapIndex()+1) == liveAutoSym->getGCMapIndex())))1937{1938zeroOut = false;1939break;1940}1941}1942}19431944if (zeroOut)1945{1946TR::TreeTop *cursorTree = esuccBlock->getEntry()->getNextTreeTop();1947TR::TreeTop *endTree = esuccBlock->getExit();1948bool storeExists = false;1949while (cursorTree != endTree)1950{1951TR::Node *cursorNode = cursorTree->getNode();1952if (cursorNode->getOpCode().isStore())1953{1954if ((cursorNode->getSymbolReference() == liveAutoSymRef) &&1955(cursorNode->getFirstChild()->getOpCodeValue() == TR::aconst) &&1956(cursorNode->getFirstChild()->getAddress() == 0 || cursorNode->getFirstChild()->getAddress() == 0xdeadf00d ))1957{1958storeExists = true;1959break;1960}1961}1962else1963break;19641965cursorTree = cursorTree->getNextTreeTop();1966}19671968if (!storeExists)1969{1970TR::Node *storeNode;1971if (self()->comp()->getOption(TR_PoisonDeadSlots))1972storeNode = self()->generatePoisonNode(block, liveAutoSymRef);1973else1974storeNode = TR::Node::createStore(liveAutoSymRef, TR::Node::aconst(block->getEntry()->getNode(), 0));1975if (storeNode)1976{1977TR::TreeTop *storeTree = TR::TreeTop::create(self()->comp(), storeNode);1978esuccBlock->prepend(storeTree);1979fsdStores.add(storeNode);1980}1981}1982}1983}1984}1985}1986}1987}1988}1989}19901991self()->setLiveLocals(liveLocals);1992self()->setLiveMonitors(liveMonitors);19931994if (self()->comp()->getOption(TR_TraceCG) || debug("traceGRA"))1995{1996// any evaluator that handles multiple trees will need to dump1997// the others1998self()->comp()->getDebug()->saveNodeChecklist(nodeChecklistBeforeDump);1999self()->comp()->getDebug()->dumpSingleTreeWithInstrs(tt, NULL, true, false, true, true);2000trfprintf(self()->comp()->getOutFile(),"\n------------------------------\n");2001trfflush(self()->comp()->getOutFile());2002}20032004self()->setLastInstructionBeforeCurrentEvaluationTreeTop(self()->getAppendInstruction());2005self()->setCurrentEvaluationTreeTop(tt);2006self()->setImplicitExceptionPoint(NULL);20072008bool doEvaluation = true;2009if ((node->getOpCode().isStore() &&2010node->getSymbol()->holdsMonitoredObject() &&2011!node->isLiveMonitorInitStore()) || node->getOpCode().getOpCodeValue() == TR::monexitfence)2012{2013if (traceLiveMon)2014{2015traceMsg(self()->comp(), "liveMonitorStack %p ", liveMonitorStack);2016if (liveMonitorStack)2017traceMsg(self()->comp(), " size %d\n", liveMonitorStack->size());2018else2019traceMsg(self()->comp(), " size empty\n");2020traceMsg(self()->comp(), "Looking at Node %p with symbol %p",node,node->getSymbol());2021}2022bool isMonent = node->getOpCode().getOpCodeValue() != TR::monexitfence;2023if (isMonent)2024{2025// monent2026if (liveMonitors)2027liveMonitors = new (self()->trHeapMemory()) TR_BitVector(*liveMonitors);2028else2029liveMonitors = new (self()->trHeapMemory()) TR_BitVector(numMonitorLocals, self()->trMemory());20302031// add this monent to the block's stack2032//2033if (liveMonitorStack)2034{2035liveMonitorStack->push(node->getSymbolReference());2036if (traceLiveMon)2037traceMsg(self()->comp(), "pushing symref %p (#%u) onto monitor stack\n", node->getSymbolReference(), node->getSymbolReference()->getReferenceNumber());2038}20392040liveMonitors->set(node->getSymbol()->castToRegisterMappedSymbol()->getLiveLocalIndex());20412042if (traceLiveMon)2043traceMsg(self()->comp(), "monitor %p went live at node %p\n", node->getSymbol(), node);2044}2045else if (!isMonent)2046{2047if (liveMonitorStack)2048{2049// monexit2050TR_ASSERT(liveMonitors, "inconsistent live monitor state");20512052// pop this monexit from the block's stack2053//2054if (!liveMonitorStack->isEmpty())2055{2056liveMonitors = new (self()->trHeapMemory()) TR_BitVector(*liveMonitors);20572058if (self()->comp()->getOption(TR_PoisonDeadSlots))2059{2060TR::SymbolReference *symRef = liveMonitorStack->pop();2061liveMonitors->reset(symRef->getSymbol()->castToRegisterMappedSymbol()->getLiveLocalIndex());2062TR::Node *storeNode = NULL;20632064if (self()->comp()->getOption(TR_TraceCG) && self()->comp()->getOption(TR_PoisonDeadSlots))2065traceMsg(self()->comp(), "POISON DEAD SLOTS --- MonExit Block Number: %d\n", self()->getCurrentEvaluationBlock()->getNumber());20662067storeNode = self()->generatePoisonNode(self()->getCurrentEvaluationBlock(), symRef);2068if (storeNode)2069{2070TR::TreeTop *storeTree = TR::TreeTop::create(self()->comp(), storeNode);2071self()->getCurrentEvaluationBlock()->prepend(storeTree);2072fsdStores.add(storeNode);2073}2074}2075else2076{2077TR::SymbolReference *symref = liveMonitorStack->pop();20782079if (traceLiveMon)2080traceMsg(self()->comp(), "popping symref %p (#%u) off monitor stack\n", symref, symref->getReferenceNumber());2081liveMonitors->reset(symref->getSymbol()->castToRegisterMappedSymbol()->getLiveLocalIndex());2082}20832084}2085else2086{2087dumpOptDetails(self()->comp(), "liveMonitorStack %p is inconsistently empty at node %p!\n", liveMonitorStack, node);2088if (liveMonitors)2089liveMonitors->empty();2090}20912092if (traceLiveMon)2093traceMsg(self()->comp(), "monitor %p went dead at node %p\n", node->getSymbol(), node);2094}2095// no need to generate code for this store2096//2097doEvaluation = false;2098}2099}21002101#ifdef TR_TARGET_S3902102if (self()->getAddStorageReferenceHints())2103self()->addStorageReferenceHints(node);2104#endif210521062107if (doEvaluation)2108self()->evaluate(node);210921102111if (self()->comp()->getOption(TR_TraceCG) || debug("traceGRA"))2112{2113TR::Instruction *lastInstr = self()->getAppendInstruction();2114tt->setLastInstruction(lastInstr == prevInstr ? 0 : lastInstr);2115}21162117if (liveLocals)2118{2119TR::AutomaticSymbol * liveSym = 0;2120if (debug("checkBlockEntryLiveLocals"))2121{2122// Check for a store into a local.2123// If so, this local becomes live at this point.2124//2125if (node->getOpCode().isStore())2126{2127liveSym = node->getSymbol()->getAutoSymbol();2128}21292130// Check for a loadaddr of a local object.2131// If so, this local object becomes live at this point.2132//2133else if (opCode == TR::treetop)2134{2135if (firstChild->getOpCodeValue() == TR::loadaddr)2136liveSym = firstChild->getSymbol()->getLocalObjectSymbol();2137}2138if (liveSym && liveSym->getLiveLocalIndex() == (uint16_t)-1)2139liveSym = NULL;2140}2141else2142{2143// Check for a store into a collected local reference.2144// If so, this local becomes live at this point.2145//2146if ((opCode == TR::astore) &&2147((!self()->comp()->getOption(TR_MimicInterpreterFrameShape)) ||2148(!self()->comp()->areSlotsSharedByRefAndNonRef()) ||2149(!fsdStores.find(node))))2150{2151liveSym = node->getSymbol()->getAutoSymbol();2152}21532154// Check for a loadaddr of a local object containing collected references.2155// If so, this local object becomes live at this point.2156//2157else if (opCode == TR::treetop)2158{2159if (firstChild->getOpCodeValue() == TR::loadaddr)2160liveSym = firstChild->getSymbol()->getLocalObjectSymbol();2161}2162if (liveSym && !liveSym->isCollectedReference())2163liveSym = NULL;2164}21652166bool newLiveLocals = false;2167if (liveSym)2168{2169liveLocals = new (self()->trHeapMemory()) TR_BitVector(*liveLocals);2170newLiveLocals = true;2171if (liveSym)2172liveLocals->set(liveSym->getLiveLocalIndex());2173}21742175// In interpreter-frame mode a reference can share a slot with a nonreference so when we see a store to a nonreference2176// we need to make sure that any reference that it shares a slot with is marked as dead2177//2178if (self()->comp()->getOption(TR_MimicInterpreterFrameShape) && node->getOpCode().isStore() && opCode != TR::astore)2179{2180TR::AutomaticSymbol * nonRefStoreSym = node->getSymbol()->getAutoSymbol();2181if (nonRefStoreSym && (nonRefStoreSym->getGCMapIndex() != -1)) //defect 147894: don't check this for GCMapIndex = -12182{2183bool isTwoSlots = ( TR::Symbol::convertTypeToNumberOfSlots(nonRefStoreSym->getDataType()) == 2);2184if (isTwoSlots || nonRefStoreSym->isSlotSharedByRefAndNonRef())2185{2186ListIterator<TR::AutomaticSymbol> autoIterator(&methodSymbol->getAutomaticList());2187if (!newLiveLocals)2188liveLocals = new (self()->trHeapMemory()) TR_BitVector(*liveLocals);2189for (TR::AutomaticSymbol * autoSym = autoIterator.getFirst(); autoSym; autoSym = autoIterator.getNext())2190if (autoSym->getType().isAddress() && autoSym->getLiveLocalIndex() != (uint16_t)-1)2191{2192if (autoSym->getGCMapIndex() == nonRefStoreSym->getGCMapIndex())2193liveLocals->reset(autoSym->getLiveLocalIndex());2194else if (isTwoSlots && autoSym->getGCMapIndex() == nonRefStoreSym->getGCMapIndex() + 1)2195liveLocals->reset(autoSym->getLiveLocalIndex());2196}2197}2198}2199}2200}22012202bool compactVSSStack = false;2203if (!self()->comp()->getOption(TR_DisableVSSStackCompaction))2204{2205if (self()->comp()->getMethodHotness() < hot)2206compactVSSStack = true;2207else if (self()->comp()->getOption(TR_ForceVSSStackCompaction))2208compactVSSStack = true;2209}22102211if (compactVSSStack && !_variableSizeSymRefPendingFreeList.empty())2212{2213TR::Node *ttNode = (node->getOpCodeValue() == TR::treetop) ? node->getFirstChild() : node;2214auto it = _variableSizeSymRefPendingFreeList.begin();2215TR::SymbolReference *symRef;2216while (it != _variableSizeSymRefPendingFreeList.end())2217{2218//Element is removed within freeVariableSizeSymRef. Need a reference to next element2219auto next = it;2220++next;2221TR_ASSERT((*it)->getSymbol()->isVariableSizeSymbol(),"symRef #%d must contain a variable size symbol\n",(*it)->getReferenceNumber());2222auto *sym = (*it)->getSymbol()->getVariableSizeSymbol();2223bool found = (std::find(_variableSizeSymRefFreeList.begin(), _variableSizeSymRefFreeList.end(), (*it)) != _variableSizeSymRefFreeList.end());2224if (self()->traceBCDCodeGen())2225{2226if (sym->getNodeToFreeAfter())2227traceMsg(self()->comp(),"pending free temps : looking at symRef #%d (%s) refCount %d sym->getNodeToFreeAfter() %p ttNode %p (find sym in list %d)\n",2228(*it)->getReferenceNumber(),self()->getDebug()->getName(sym),sym->getReferenceCount(),2229sym->getNodeToFreeAfter(),ttNode,found);2230else2231traceMsg(self()->comp(),"pending free temps : looking at symRef #%d (%s) refCount %d (find sym in list %d)\n",2232(*it)->getReferenceNumber(),self()->getDebug()->getName(sym),sym->getReferenceCount(),found);2233}2234if (!sym->isAddressTaken() && !found)2235{2236TR::Node *nodeToFreeAfter = sym->getNodeToFreeAfter();2237bool nodeToFreeAfterIsCurrentNode = nodeToFreeAfter && (ttNode==nodeToFreeAfter);2238if (sym->getReferenceCount() == 0 &&2239(!nodeToFreeAfter || nodeToFreeAfterIsCurrentNode))2240{2241self()->freeVariableSizeSymRef(*it); // will also remove sym from the pending free list2242}2243else if (sym->getReferenceCount() > 0 && nodeToFreeAfterIsCurrentNode)2244{2245if (self()->traceBCDCodeGen())2246traceMsg(self()->comp(),"\treset nodeToFreeAfter %p->NULL for sym %p with refCount %d > 0\n",nodeToFreeAfter,sym,sym->getReferenceCount());2247sym->setNodeToFreeAfter(NULL);2248}2249else2250{2251// We'd like to assert the following, but refcounts are unsigned, so we can't2252//TR_ASSERT(sym->getReferenceCount() >= 0,"sym %p refCount %d should be >= 0\n",sym,sym->getReferenceCount());2253}2254}2255it = next;2256}2257}22582259if (self()->comp()->getOption(TR_TraceCG) || debug("traceGRA"))2260{2261self()->comp()->getDebug()->restoreNodeChecklist(nodeChecklistBeforeDump);2262if (tt == self()->getCurrentEvaluationTreeTop())2263{2264trfprintf(self()->comp()->getOutFile(),"------------------------------\n");2265self()->comp()->getDebug()->dumpSingleTreeWithInstrs(tt, prevInstr->getNext(), true, true, true, false);2266}2267else2268{2269// dump all the trees that the evaluator handled2270trfprintf(self()->comp()->getOutFile(),"------------------------------");2271for (TR::TreeTop *dumptt = tt; dumptt != self()->getCurrentEvaluationTreeTop()->getNextTreeTop(); dumptt = dumptt->getNextTreeTop())2272{2273trfprintf(self()->comp()->getOutFile(),"\n");2274self()->comp()->getDebug()->dumpSingleTreeWithInstrs(dumptt, NULL, true, false, true, false);2275}2276// all instructions are on the tt tree2277self()->comp()->getDebug()->dumpSingleTreeWithInstrs(tt, prevInstr->getNext(), false, true, false, false);2278}2279trfflush(self()->comp()->getOutFile());2280}2281}22822283if (self()->traceBCDCodeGen())2284traceMsg(self()->comp(),"\tinstruction selection is complete so free all symbols in the _variableSizeSymRefPendingFreeList\n");22852286self()->freeAllVariableSizeSymRefs();22872288#if defined(TR_TARGET_S390)2289// Virtual function insertInstructionPrefetches is implemented only for s390 platform,2290// for all other platforms the function is empty2291//2292self()->insertInstructionPrefetches();2293#endif2294} // Stack memory region ends22952296if (self()->comp()->getOption(TR_TraceCG) || debug("traceGRA"))2297self()->comp()->incVisitCount();22982299if (self()->getDebug())2300self()->getDebug()->roundAddressEnumerationCounters();23012302self()->endInstructionSelection();23032304if (self()->comp()->getOption(TR_TraceCG))2305diagnostic("</selection>\n");2306}23072308bool2309J9::CodeGenerator::allowGuardMerging()2310{2311return self()->fej9()->supportsGuardMerging();2312}23132314void2315J9::CodeGenerator::populateOSRBuffer()2316{23172318if (!self()->comp()->getOption(TR_EnableOSR))2319return;23202321//The following struct definitions are coming from VM include files and are intended as2322//a legend for OSR buffer23232324// typedef struct J9OSRBuffer {2325// U_32 numberOfFrames;2326// // frames here - reachable by "(J9OSRFrame*)(buffer + 1)"2327// } J9OSRBuffer;2328// typedef struct J9OSRFrame {2329// J9Method *method;2330// U_8 *bytecodePC;2331// U_32 maxStack;2332// U_32 pendingStackHeight;2333// // stack slots here - reachable by "(UDATA*)(frame + 1)"2334// } J9OSRFrame;23352336self()->comp()->getOSRCompilationData()->buildSymRefOrderMap();2337const TR_Array<TR_OSRMethodData *>& methodDataArray = self()->comp()->getOSRCompilationData()->getOSRMethodDataArray();2338bool traceOSR = self()->comp()->getOption(TR_TraceOSR);2339uint32_t maxScratchBufferSize = 0;2340const int firstSymChildIndex = 2;23412342/*2343for (int32_t i = 0; i < methodDataArray.size(); ++i)2344for (int32_t j = i+1; j < methodDataArray.size(); ++j)2345TR_ASSERT((methodDataArray[i] == NULL && methodDataArray[j] == NULL) || (methodDataArray[i] != methodDataArray[j]),2346"methodDataArray elements %d and %d are equal\n", i, j);2347*/23482349TR::Block * block = NULL;2350for(TR::TreeTop * tt = self()->comp()->getStartTree(); tt; tt = tt->getNextTreeTop())2351{2352// Write pending pushes, parms, and locals to vmthread's OSR buffer23532354TR::Node* n = tt->getNode();2355if (n->getOpCodeValue() == TR::BBStart)2356{2357block = n->getBlock();2358continue;2359}2360if (n->getOpCodeValue() == TR::treetop && n->getNumChildren() == 1)2361n = n->getFirstChild();2362else2363continue;2364if (n->getOpCodeValue() != TR::call ||2365n->getSymbolReference()->getReferenceNumber() != TR_prepareForOSR)2366continue;23672368TR::Node *callNode = n;2369TR_OSRMethodData* osrMethodData = methodDataArray[callNode->getChild(1)->getInt()+1];2370TR_ASSERT(osrMethodData != NULL && osrMethodData->getOSRCodeBlock() != NULL,2371"osr method data or its block is NULL\n");23722373if (traceOSR)2374traceMsg(self()->comp(), "Lowering trees in OSR block_%d...\n", block->getNumber());23752376//osrFrameIndex is a field in the vmThread that is initialized by the VM to the offset2377//of the start of the first (deepest) frame in the OSR buffer2378//Once we are done with generating code that populates the current frame, we generate code2379//that advances this field to the point to the next frame at the end of the OSR code block2380//of each frame2381TR::ResolvedMethodSymbol *methSym = osrMethodData->getMethodSymbol();2382TR::Node *osrBufferNode = TR::Node::createLoad(callNode, self()->symRefTab()->findOrCreateOSRBufferSymbolRef());2383TR::Node *osrFrameIndex = TR::Node::createLoad(callNode, self()->symRefTab()->findOrCreateOSRFrameIndexSymbolRef());2384TR::Node *osrScratchBufferNode = TR::Node::createLoad(callNode, self()->symRefTab()->findOrCreateOSRScratchBufferSymbolRef());23852386TR::TreeTop* insertionPoint = tt->getPrevRealTreeTop();2387bool inlinesAnyMethod = osrMethodData->inlinesAnyMethod();23882389if (traceOSR)2390traceMsg(self()->comp(), "callerIndex %d: max pending push slots=%d, # of auto slots=%d, # of arg slots=%d\n",2391osrMethodData->getInlinedSiteIndex(), methSym->getNumPPSlots(),2392methSym->getResolvedMethod()->numberOfTemps(), methSym->getNumParameterSlots());23932394uint32_t numOfSymsThatShareSlot = 0;2395int32_t scratchBufferOffset = 0;2396for (int32_t child = firstSymChildIndex; child+2 < callNode->getNumChildren(); child += 3)2397{2398TR::Node* loadNode = callNode->getChild(child);2399int32_t symRefNumber = callNode->getChild(child+1)->getInt();2400int32_t symRefOrder = callNode->getChild(child+2)->getInt();2401TR::SymbolReference* symRef = self()->symRefTab()->getSymRef(symRefNumber);24022403int32_t specialCasedSlotIndex = -1;2404//if (methSym->getSyncObjectTemp() == symRef)2405if (symRef->getSymbol()->holdsMonitoredObject())2406specialCasedSlotIndex = methSym->getSyncObjectTempIndex();2407//else if (methSym->getThisTempForObjectCtor() == symRef)2408else if (symRef->getSymbol()->isThisTempForObjectCtor())2409specialCasedSlotIndex = methSym->getThisTempForObjectCtorIndex();2410//else if (methSym->getATCDeferredCountTemp() == symRef)24112412int32_t slotIndex = symRef->getCPIndex() >= methSym->getFirstJitTempIndex()2413? methSym->getFirstJitTempIndex()2414: symRef->getCPIndex();24152416if (symRef->getCPIndex() >= methSym->getFirstJitTempIndex())2417{2418TR_ASSERT(((slotIndex == methSym->getSyncObjectTempIndex()) ||2419(slotIndex == methSym->getThisTempForObjectCtorIndex())), "Unknown temp sym ref being written to the OSR buffer; probably needs special casing\n");2420}24212422if (specialCasedSlotIndex != -1)2423slotIndex = specialCasedSlotIndex;24242425int32_t symSize = symRef->getSymbol()->getSize();2426bool sharedSlot = (symRefOrder != -1);2427if (sharedSlot)2428{2429insertionPoint = self()->genSymRefStoreToArray(callNode, osrScratchBufferNode, NULL, loadNode, scratchBufferOffset, insertionPoint);2430osrMethodData->addScratchBufferOffset(slotIndex, symRefOrder, scratchBufferOffset);2431scratchBufferOffset += symSize;2432numOfSymsThatShareSlot++;2433}2434else2435{2436TR::DataType dt = symRef->getSymbol()->getDataType();2437bool takesTwoSlots = dt == TR::Int64 || dt == TR::Double;2438int32_t offset = osrMethodData->slotIndex2OSRBufferIndex(slotIndex, symSize, takesTwoSlots);2439insertionPoint = self()->genSymRefStoreToArray(callNode, osrBufferNode, osrFrameIndex, loadNode, offset, insertionPoint);2440}2441}24422443/*2444* dead slots are bookkept together with shared slots under involuntary OSR2445* increase this number to indicate the existence of entries for dead slots2446*/2447if (osrMethodData->hasSlotSharingOrDeadSlotsInfo() && numOfSymsThatShareSlot == 0)2448numOfSymsThatShareSlot++;24492450osrMethodData->setNumOfSymsThatShareSlot(numOfSymsThatShareSlot);2451maxScratchBufferSize = (maxScratchBufferSize > scratchBufferOffset) ? maxScratchBufferSize : scratchBufferOffset;24522453if (traceOSR)2454{2455traceMsg(self()->comp(), "%s %s %s: written out bytes in OSR buffer\n",2456osrMethodData->getInlinedSiteIndex() == -1 ? "Method," : "Inlined method,",2457inlinesAnyMethod? "inlines another method,": "doesn't inline any method,",2458methSym->signature(self()->trMemory()));2459}2460int32_t totalNumOfSlots = osrMethodData->getTotalNumOfSlots();2461//The OSR helper call will print the contents of the OSR buffer (if trace option is on)2462//and populate the OSR buffer with the correct values of the shared slots (if there is any)2463bool emitCall = false;24642465if ((numOfSymsThatShareSlot > 0) ||2466self()->comp()->getOption(TR_EnablePrepareForOSREvenIfThatDoesNothing))2467emitCall = true;24682469int32_t startIndex = 0;2470if (emitCall)2471startIndex = firstSymChildIndex;24722473for (int32_t i = startIndex; i < callNode->getNumChildren(); i++)2474callNode->getChild(i)->recursivelyDecReferenceCount();24752476if (emitCall)2477{2478callNode->setNumChildren(firstSymChildIndex+1);2479TR_ASSERT(totalNumOfSlots < (1 << 16) - 1, "only 16 bits are reserved for number of slots");2480TR_ASSERT(numOfSymsThatShareSlot < (1 << 16) -1, "only 16 bits are reserved for number of syms that share slots");2481callNode->setAndIncChild(firstSymChildIndex,2482TR::Node::create(callNode, TR::iconst, 0, totalNumOfSlots | (numOfSymsThatShareSlot << 16)));2483insertionPoint = tt;2484}2485else2486{2487TR::TreeTop *prev = tt->getPrevTreeTop();2488TR::TreeTop *next = tt->getNextTreeTop();2489prev->join(next);2490insertionPoint = prev;2491}24922493//at the end of each OSR code block, we need to advance osrFrameIndex such that2494//it points to the beginning of the next osr frame2495//osrFrameIndex += osrMethodData->getTotalDataSize();2496TR::TreeTop* osrFrameIndexAdvanceTreeTop = TR::TreeTop::create(self()->comp(),2497TR::Node::createStore(self()->symRefTab()->findOrCreateOSRFrameIndexSymbolRef(),2498TR::Node::create(TR::iadd, 2, osrFrameIndex,2499TR::Node::create(callNode, TR::iconst, 0, osrMethodData->getTotalDataSize())2500)2501)2502);2503insertionPoint->insertTreeTopsAfterMe(osrFrameIndexAdvanceTreeTop);2504}250525062507for (int32_t i = 0; i < methodDataArray.size(); i++)2508{2509TR_OSRMethodData* osrMethodData = methodDataArray[i];2510//osrMethodData can be NULL when the inlined method didn't cause a call to ILGen (e.g., a jni method)2511if (methodDataArray[i] == NULL)2512continue;2513//Initialize the number of syms that share slots to zero if it's hasn't been already initialized.2514if (osrMethodData->getNumOfSymsThatShareSlot() == -1)2515{2516osrMethodData->setNumOfSymsThatShareSlot(0);2517}2518}25192520self()->comp()->getOSRCompilationData()->setMaxScratchBufferSize(maxScratchBufferSize);2521}25222523static void addValidationRecords(TR::CodeGenerator *cg)2524{2525TR_J9VMBase *fej9 = (TR_J9VMBase *)(cg->comp()->fe());25262527TR::list<TR::AOTClassInfo*>* classInfo = cg->comp()->_aotClassInfo;2528if (!classInfo->empty())2529{2530for (auto info = classInfo->begin(); info != classInfo->end(); ++info)2531{2532traceMsg(cg->comp(), "processing AOT class info: %p in %s\n", *info, cg->comp()->signature());2533traceMsg(cg->comp(), "ramMethod: %p cp: %p cpIndex: %x relo %d\n", (*info)->_method, (*info)->_constantPool, (*info)->_cpIndex, (*info)->_reloKind);2534traceMsg(cg->comp(), "clazz: %p classChain: %p\n", (*info)->_clazz, (*info)->_classChain);25352536TR_OpaqueMethodBlock *ramMethod = (*info)->_method;25372538int32_t siteIndex = -1;25392540if (ramMethod != cg->comp()->getCurrentMethod()->getPersistentIdentifier()) // && info->_reloKind != TR_ValidateArbitraryClass)2541{2542int32_t i;2543for (i = 0; i < cg->comp()->getNumInlinedCallSites(); i++)2544{2545TR_InlinedCallSite &ics = cg->comp()->getInlinedCallSite(i);2546TR_OpaqueMethodBlock *inlinedMethod = fej9->getInlinedCallSiteMethod(&ics);25472548traceMsg(cg->comp(), "\tinline site %d inlined method %p\n", i, inlinedMethod);2549if (ramMethod == inlinedMethod)2550{2551traceMsg(cg->comp(), "\t\tmatch!\n");2552siteIndex = i;2553break;2554}2555}25562557if (i >= (int32_t) cg->comp()->getNumInlinedCallSites())2558{2559// this assumption isn't associated with a method directly in the compilation2560// so we can't use a constant pool approach to validate: transform into TR_ValidateArbitraryClass2561// kind of overkill for TR_ValidateStaticField, but still correct2562(*info)->_reloKind = TR_ValidateArbitraryClass;2563siteIndex = -1; // invalidate main compiled method2564traceMsg(cg->comp(), "\ttransformed into TR_ValidateArbitraryClass\n");2565}2566}25672568traceMsg(cg->comp(), "Found inlined site %d\n", siteIndex);25692570TR_ASSERT(siteIndex < (int32_t) cg->comp()->getNumInlinedCallSites(), "did not find AOTClassInfo %p method in inlined site table", *info);25712572cg->addExternalRelocation(new (cg->trHeapMemory()) TR::ExternalRelocation(NULL,2573(uint8_t *)(intptr_t)siteIndex,2574(uint8_t *)(*info),2575(*info)->_reloKind, cg),2576__FILE__, __LINE__, NULL);2577}2578}2579}25802581static void addSVMValidationRecords(TR::CodeGenerator *cg)2582{2583TR::SymbolValidationManager::SymbolValidationRecordList &validationRecords = cg->comp()->getSymbolValidationManager()->getValidationRecordList();2584if (cg->comp()->getOption(TR_UseSymbolValidationManager))2585{2586// Add the flags in TR_AOTMethodHeader on the compile run2587TR_AOTMethodHeader *aotMethodHeaderEntry = cg->comp()->getAotMethodHeaderEntry();2588aotMethodHeaderEntry->flags |= TR_AOTMethodHeader_UsesSymbolValidationManager;25892590for (auto it = validationRecords.begin(); it != validationRecords.end(); it++)2591{2592cg->addExternalRelocation(new (cg->trHeapMemory()) TR::ExternalRelocation(NULL,2593(uint8_t *)(*it),2594(*it)->_kind, cg),2595__FILE__, __LINE__, NULL);2596}2597}2598}25992600static TR_ExternalRelocationTargetKind getReloKindFromGuardSite(TR::CodeGenerator *cg, TR_AOTGuardSite *site)2601{2602TR_ExternalRelocationTargetKind type;26032604switch (site->getType())2605{2606case TR_DirectMethodGuard:2607if (site->getGuard()->getSymbolReference()->getSymbol()->getMethodSymbol()->isStatic())2608type = TR_InlinedStaticMethodWithNopGuard;2609else if (site->getGuard()->getSymbolReference()->getSymbol()->getMethodSymbol()->isSpecial())2610type = TR_InlinedSpecialMethodWithNopGuard;2611else if (site->getGuard()->getSymbolReference()->getSymbol()->getMethodSymbol()->isVirtual())2612type = TR_InlinedVirtualMethodWithNopGuard;2613else2614TR_ASSERT(0, "unexpected AOTDirectMethodGuard method symbol");2615break;26162617case TR_NonoverriddenGuard:2618type = TR_InlinedVirtualMethodWithNopGuard;2619break;2620case TR_RemovedNonoverriddenGuard:2621type = TR_InlinedVirtualMethod;2622break;26232624case TR_InterfaceGuard:2625type = TR_InlinedInterfaceMethodWithNopGuard;2626break;2627case TR_RemovedInterfaceGuard:2628traceMsg(cg->comp(), "TR_RemovedInterfaceMethod\n");2629type = TR_InlinedInterfaceMethod;2630break;26312632case TR_AbstractGuard:2633type = TR_InlinedAbstractMethodWithNopGuard;2634break;26352636case TR_HCRGuard:2637// devinmp: TODO/FIXME this should arrange to create an AOT2638// relocation which, when loaded, creates a2639// TR_PatchNOPedGuardSiteOnClassRedefinition or similar.2640// Here we would previously create a TR_HCR relocation,2641// which is for replacing J9Class or J9Method pointers.2642// These would be the 'unresolved' variant2643// (TR_RedefinedClassUPicSite), which would (hopefully) never2644// get patched. If it were patched, it seems like it would2645// replace code with a J9Method pointer.2646if (!cg->comp()->getOption(TR_UseOldHCRGuardAOTRelocations))2647type = TR_NoRelocation;2648else2649type = TR_HCR;2650break;26512652case TR_MethodEnterExitGuard:2653if (site->getGuard()->getCallNode()->getOpCodeValue() == TR::MethodEnterHook)2654type = TR_CheckMethodEnter;2655else if (site->getGuard()->getCallNode()->getOpCodeValue() == TR::MethodExitHook)2656type = TR_CheckMethodExit;2657else2658TR_ASSERT(0,"Unexpected TR_MethodEnterExitGuard at site %p guard %p node %p\n",2659site, site->getGuard(), site->getGuard()->getCallNode());2660break;26612662case TR_RemovedProfiledGuard:2663traceMsg(cg->comp(), "TR_ProfiledInlinedMethodRelocation\n");2664type = TR_ProfiledInlinedMethodRelocation;2665break;26662667case TR_ProfiledGuard:2668if (site->getGuard()->getTestType() == TR_MethodTest)2669{2670type = TR_ProfiledMethodGuardRelocation;2671traceMsg(cg->comp(), "TR_ProfiledMethodGuardRelocation\n");2672}2673else if (site->getGuard()->getTestType() == TR_VftTest)2674{2675type = TR_ProfiledClassGuardRelocation;2676traceMsg(cg->comp(), "TR_ProfiledClassGuardRelocation\n");2677}2678else2679TR_ASSERT(false, "unexpected profiled guard test type");2680break;26812682case TR_BreakpointGuard:2683traceMsg(cg->comp(), "TR_Breakpoint\n");2684type = TR_Breakpoint;2685break;26862687default:2688TR_ASSERT(false, "got a unknown/non-AOT guard at AOT site");2689cg->comp()->failCompilation<J9::AOTRelocationRecordGenerationFailure>("Unknown/non-AOT guard at AOT site");2690break;2691}26922693return type;2694}26952696static void processAOTGuardSites(TR::CodeGenerator *cg, uint32_t inlinedCallSize, TR_InlinedSiteHastTableEntry *orderedInlinedSiteListTable)2697{2698TR::list<TR_AOTGuardSite*> *aotGuardSites = cg->comp()->getAOTGuardPatchSites();2699for(auto it = aotGuardSites->begin(); it != aotGuardSites->end(); ++it)2700{2701// first, figure out the appropriate relocation record type from the guard type and symbol2702TR_ExternalRelocationTargetKind type = getReloKindFromGuardSite(cg, (*it));27032704switch (type) // relocation record type2705{2706case TR_InlinedStaticMethodWithNopGuard:2707case TR_InlinedSpecialMethodWithNopGuard:2708case TR_InlinedVirtualMethodWithNopGuard:2709case TR_InlinedInterfaceMethodWithNopGuard:2710case TR_InlinedAbstractMethodWithNopGuard:2711case TR_ProfiledClassGuardRelocation:2712case TR_ProfiledMethodGuardRelocation:2713case TR_ProfiledInlinedMethodRelocation:2714case TR_InlinedVirtualMethod:2715case TR_InlinedInterfaceMethod:2716{2717TR_ASSERT(inlinedCallSize, "TR_AOT expect inlinedCallSize to be larger than 0\n");2718intptr_t inlinedSiteIndex = (intptr_t)(*it)->getGuard()->getCurrentInlinedSiteIndex();2719TR_InlinedSiteLinkedListEntry *entry = (TR_InlinedSiteLinkedListEntry *)cg->comp()->trMemory()->allocateMemory(sizeof(TR_InlinedSiteLinkedListEntry), heapAlloc);27202721entry->reloType = type;2722entry->location = (uint8_t *)(*it)->getLocation();2723entry->destination = (uint8_t *)(*it)->getDestination();2724entry->guard = (uint8_t *)(*it)->getGuard();2725entry->next = NULL;27262727if (orderedInlinedSiteListTable[inlinedSiteIndex].first)2728{2729orderedInlinedSiteListTable[inlinedSiteIndex].last->next = entry;2730orderedInlinedSiteListTable[inlinedSiteIndex].last = entry;2731}2732else2733{2734orderedInlinedSiteListTable[inlinedSiteIndex].first = entry;2735orderedInlinedSiteListTable[inlinedSiteIndex].last = entry;2736}2737}2738break;27392740case TR_CheckMethodEnter:2741case TR_CheckMethodExit:2742case TR_HCR:2743cg->addExternalRelocation(new (cg->trHeapMemory()) TR::ExternalRelocation((uint8_t *)(*it)->getLocation(),2744(uint8_t *)(*it)->getDestination(),2745type, cg),2746__FILE__, __LINE__, NULL);2747break;27482749case TR_Breakpoint:2750cg->addExternalRelocation(new (cg->trHeapMemory()) TR::ExternalRelocation((uint8_t *)(*it)->getLocation(),2751(uint8_t *)(intptr_t)(*it)->getGuard()->getCurrentInlinedSiteIndex(),2752(uint8_t *)(*it)->getDestination(),2753type, cg),2754__FILE__, __LINE__, NULL);2755break;27562757case TR_NoRelocation:2758break;27592760default:2761TR_ASSERT(false, "got a unknown/non-AOT guard at AOT site");2762cg->comp()->failCompilation<J9::AOTRelocationRecordGenerationFailure>("Unknown/non-AOT guard at AOT site");2763break;2764}2765}2766}27672768static void addInlinedSiteRelocation(TR::CodeGenerator *cg,2769TR_ExternalRelocationTargetKind reloType,2770uint8_t *reloLocation,2771int32_t inlinedSiteIndex,2772TR::SymbolReference *callSymref,2773TR_OpaqueClassBlock *receiver,2774uint8_t *destinationAddress)2775{2776TR_ASSERT_FATAL(reloType != TR_NoRelocation, "TR_NoRelocation specified as reloType for inlinedSiteIndex=%d, reloLocation=%p, callSymref=%p, receiver=%p",2777inlinedSiteIndex, reloLocation, callSymref, receiver);27782779TR_RelocationRecordInformation *info = new (cg->comp()->trHeapMemory()) TR_RelocationRecordInformation();2780info->data1 = static_cast<uintptr_t>(inlinedSiteIndex);2781info->data2 = reinterpret_cast<uintptr_t>(callSymref);2782info->data3 = reinterpret_cast<uintptr_t>(receiver);2783info->data4 = reinterpret_cast<uintptr_t>(destinationAddress);27842785cg->addExternalRelocation(new (cg->trHeapMemory()) TR::ExternalRelocation(reloLocation, (uint8_t *)info, reloType, cg),2786__FILE__,__LINE__, NULL);2787}27882789static void addInliningTableRelocations(TR::CodeGenerator *cg, uint32_t inlinedCallSize, TR_InlinedSiteHastTableEntry *orderedInlinedSiteListTable)2790{2791// If have inlined calls, now add the relocation records in descending order2792// of inlined site index (at relocation time, the order is reverse)2793if (inlinedCallSize > 0)2794{2795for (int32_t counter = inlinedCallSize - 1; counter >= 0 ; counter--)2796{2797TR_InlinedSiteLinkedListEntry *currentSite = orderedInlinedSiteListTable[counter].first;27982799if (currentSite)2800{2801do2802{2803TR_VirtualGuard *guard = reinterpret_cast<TR_VirtualGuard *>(currentSite->guard);28042805addInlinedSiteRelocation(cg, currentSite->reloType, currentSite->location, counter, guard->getSymbolReference(), guard->getThisClass(), currentSite->destination);28062807currentSite = currentSite->next;2808}2809while(currentSite);2810}2811else2812{2813TR_AOTMethodInfo *methodInfo = cg->comp()->getInlinedAOTMethodInfo(counter);28142815addInlinedSiteRelocation(cg, methodInfo->reloKind, NULL, counter, methodInfo->callSymRef, methodInfo->receiver, NULL);2816}2817}2818}2819}28202821void2822J9::CodeGenerator::processRelocations()2823{2824// Project neutral non-AOT processRelocation2825// This should be done first to ensure that the2826// external relocations are generated after the2827// code is in its final form.2828OMR::CodeGeneratorConnector::processRelocations();28292830if (self()->comp()->compileRelocatableCode())2831{2832uint32_t inlinedCallSize = self()->comp()->getNumInlinedCallSites();28332834// Create temporary hashtable for ordering AOT guard relocations2835TR_InlinedSiteHastTableEntry *orderedInlinedSiteListTable = NULL;2836if (inlinedCallSize > 0)2837{2838orderedInlinedSiteListTable= (TR_InlinedSiteHastTableEntry*)self()->comp()->trMemory()->allocateMemory(sizeof(TR_InlinedSiteHastTableEntry) * inlinedCallSize, heapAlloc);2839memset(orderedInlinedSiteListTable, 0, sizeof(TR_InlinedSiteHastTableEntry)*inlinedCallSize);2840}28412842// Traverse list of AOT-specific guards and create relocation records2843processAOTGuardSites(self(), inlinedCallSize, orderedInlinedSiteListTable);28442845// Add non-SVM validation records2846addValidationRecords(self());28472848// If have inlined calls, now add the relocation records in descending order of inlined site index (at relocation time, the order is reverse)2849addInliningTableRelocations(self(), inlinedCallSize, orderedInlinedSiteListTable);2850}28512852#if defined(J9VM_OPT_JITSERVER)2853if (self()->comp()->compileRelocatableCode() || self()->comp()->isOutOfProcessCompilation())2854#else2855if (self()->comp()->compileRelocatableCode())2856#endif /* defined(J9VM_OPT_JITSERVER) */2857{2858// Add SVM validation records2859addSVMValidationRecords(self());28602861// Now call the platform specific processing of relocations2862self()->getAheadOfTimeCompile()->processRelocations();2863}28642865// Traverse the AOT/external labels2866for (auto aotIterator = self()->getExternalRelocationList().begin(); aotIterator != self()->getExternalRelocationList().end(); ++aotIterator)2867{2868(*aotIterator)->apply(self());2869}2870}28712872#if defined(J9VM_OPT_JITSERVER)2873void J9::CodeGenerator::addExternalRelocation(TR::Relocation *r, const char *generatingFileName, uintptr_t generatingLineNumber, TR::Node *node, TR::ExternalRelocationPositionRequest where)2874{2875TR_ASSERT(generatingFileName, "External relocation location has improper NULL filename specified");2876if (self()->comp()->compileRelocatableCode() || self()->comp()->isOutOfProcessCompilation())2877{2878TR::RelocationDebugInfo *genData = new(self()->trHeapMemory()) TR::RelocationDebugInfo;2879genData->file = generatingFileName;2880genData->line = generatingLineNumber;2881genData->node = node;2882self()->addExternalRelocation(r, genData, where);2883}2884}28852886void J9::CodeGenerator::addExternalRelocation(TR::Relocation *r, TR::RelocationDebugInfo* info, TR::ExternalRelocationPositionRequest where)2887{2888if (self()->comp()->compileRelocatableCode() || self()->comp()->isOutOfProcessCompilation())2889{2890TR_ASSERT(info, "External relocation location does not have associated debug information");2891r->setDebugInfo(info);2892switch (where)2893{2894case TR::ExternalRelocationAtFront:2895_externalRelocationList.push_front(r);2896break;28972898case TR::ExternalRelocationAtBack:2899_externalRelocationList.push_back(r);2900break;29012902default:2903TR_ASSERT_FATAL(2904false,2905"invalid TR::ExternalRelocationPositionRequest %d",2906where);2907break;2908}2909}2910}2911#endif /* defined(J9VM_OPT_JITSERVER) */29122913void J9::CodeGenerator::addProjectSpecializedRelocation(uint8_t *location, uint8_t *target, uint8_t *target2,2914TR_ExternalRelocationTargetKind kind, char *generatingFileName, uintptr_t generatingLineNumber, TR::Node *node)2915{2916(target2 == NULL) ?2917self()->addExternalRelocation(new (self()->trHeapMemory()) TR::ExternalRelocation(location, target, kind, self()),2918generatingFileName, generatingLineNumber, node) :2919self()->addExternalRelocation(new (self()->trHeapMemory()) TR::ExternalRelocation(location, target, target2, kind, self()),2920generatingFileName, generatingLineNumber, node);2921}29222923void J9::CodeGenerator::addProjectSpecializedRelocation(TR::Instruction *instr, uint8_t *target, uint8_t *target2,2924TR_ExternalRelocationTargetKind kind, char *generatingFileName, uintptr_t generatingLineNumber, TR::Node *node)2925{2926(target2 == NULL) ?2927self()->addExternalRelocation(new (self()->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(instr, target, kind, self()),2928generatingFileName, generatingLineNumber, node) :2929self()->addExternalRelocation(new (self()->trHeapMemory()) TR::BeforeBinaryEncodingExternalRelocation(instr, target, target2, kind, self()),2930generatingFileName, generatingLineNumber, node);2931}29322933void J9::CodeGenerator::addProjectSpecializedPairRelocation(uint8_t *location, uint8_t *location2, uint8_t *target,2934TR_ExternalRelocationTargetKind kind, char *generatingFileName, uintptr_t generatingLineNumber, TR::Node *node)2935{2936self()->addExternalRelocation(new (self()->trHeapMemory()) TR::ExternalOrderedPair32BitRelocation(location, location2, target, kind, self()),2937generatingFileName, generatingLineNumber, node);2938}293929402941TR::Node *2942J9::CodeGenerator::createOrFindClonedNode(TR::Node *node, int32_t numChildren)2943{2944TR_HashId index;2945if (!_uncommonedNodes.locate(node->getGlobalIndex(), index))2946{2947// has not been uncommoned already, clone and store for later2948TR::Node *clone = TR::Node::copy(node, numChildren);2949_uncommonedNodes.add(node->getGlobalIndex(), index, clone);2950node = clone;2951}2952else2953{2954// found previously cloned node2955node = (TR::Node *) _uncommonedNodes.getData(index);2956}2957return node;2958}295929602961void2962J9::CodeGenerator::jitAddUnresolvedAddressMaterializationToPatchOnClassRedefinition(void *firstInstruction)2963{2964TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());2965#if defined(J9VM_OPT_JITSERVER)2966if (self()->comp()->compileRelocatableCode() || self()->comp()->isOutOfProcessCompilation())2967#else2968if (self()->comp()->compileRelocatableCode())2969#endif /* defined(J9VM_OPT_JITSERVER) */2970{2971self()->addExternalRelocation(new (self()->trHeapMemory()) TR::ExternalRelocation((uint8_t *)firstInstruction, 0, TR_HCR, self()),2972__FILE__,__LINE__, NULL);2973}2974else2975{2976createClassRedefinitionPicSite((void*)-1, firstInstruction, 1 /* see OMR::RuntimeAssumption::isForAddressMaterializationSequence */, true, self()->comp()->getMetadataAssumptionList());2977self()->comp()->setHasClassRedefinitionAssumptions();2978}2979}298029812982// J92983//2984void2985J9::CodeGenerator::compressedReferenceRematerialization()2986{2987TR::TreeTop * tt;2988TR::Node *node;2989TR_J9VMBase *fej9 = (TR_J9VMBase *)(self()->fe());29902991static bool disableRematforCP = feGetEnv("TR_DisableWrtBarOpt") != NULL;29922993// The compressedrefs remat opt removes decompression/compression sequences from2994// loads/stores where there doesn't exist a gc point between the load and the store,2995// and the load doesn't need to be dereferenced.2996// The opt needs to be disabled for the following cases:2997// 1. In Guarded Storage, we can't not do a guarded load because the object that is loaded may2998// not be in the root set, and as a consequence, may get moved.2999// 2. For read barriers in field watch, the vmhelpers are GC points and therefore the object might be moved3000if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none || self()->comp()->getOption(TR_EnableFieldWatch))3001{3002if (TR::Compiler->om.readBarrierType() != gc_modron_readbar_none)3003traceMsg(self()->comp(), "The compressedrefs remat opt is disabled because Concurrent Scavenger is enabled\n");3004if (self()->comp()->getOption(TR_EnableFieldWatch))3005traceMsg(self()->comp(), "The compressedrefs remat opt is disabled because field watch is enabled\n");3006disableRematforCP = true;3007}30083009// no need to rematerialize for lowMemHeap3010if (self()->comp()->useCompressedPointers() &&3011(TR::Compiler->om.compressedReferenceShift() != 0) &&3012!disableRematforCP)3013{3014if (self()->comp()->getOption(TR_TraceCG))3015self()->comp()->dumpMethodTrees("Trees before this remat phase", self()->comp()->getMethodSymbol());30163017List<TR::Node> rematerializedNodes(self()->trMemory());3018vcount_t visitCount = self()->comp()->incVisitCount();3019TR::SymbolReference *autoSymRef = NULL;3020for (tt = self()->comp()->getStartTree(); tt; tt = tt->getNextTreeTop())3021{3022node = tt->getNode();3023if (node->getOpCodeValue() == TR::BBStart && !node->getBlock()->isExtensionOfPreviousBlock())3024{30253026ListIterator<TR::Node> nodesIt(&rematerializedNodes);3027for (TR::Node * rematNode = nodesIt.getFirst(); rematNode != NULL; rematNode = nodesIt.getNext())3028{3029if (rematNode->getReferenceCount() == 0)3030rematNode->getFirstChild()->recursivelyDecReferenceCount();3031}30323033rematerializedNodes.deleteAll();3034}30353036bool alreadyVisitedFirstChild = false;3037if ((node->getOpCodeValue() == TR::compressedRefs) &&3038(node->getFirstChild()->getOpCodeValue() == TR::l2a))3039{3040if (node->getFirstChild()->getVisitCount() == visitCount)3041alreadyVisitedFirstChild = true;3042}30433044self()->rematerializeCompressedRefs(autoSymRef, tt, NULL, -1, node, visitCount, &rematerializedNodes);30453046if ((node->getOpCodeValue() == TR::compressedRefs) &&3047(node->getFirstChild()->getOpCodeValue() == TR::l2a))3048{3049TR::TreeTop *prevTree = tt->getPrevTreeTop();3050TR::TreeTop *nextTree = tt->getNextTreeTop();3051if (node->getFirstChild()->getReferenceCount() > 1)3052{3053if (!alreadyVisitedFirstChild)3054{3055if (!rematerializedNodes.find(node->getFirstChild()))3056{3057////traceMsg(comp(), "Adding %p\n", node->getFirstChild());3058rematerializedNodes.add(node->getFirstChild());3059}3060node->getFirstChild()->setVisitCount(visitCount-1);3061}306230633064if (rematerializedNodes.find(node->getFirstChild()))3065{3066TR::Node *cursorNode = node->getFirstChild()->getFirstChild();3067while (cursorNode &&3068(cursorNode->getOpCodeValue() != TR::iu2l))3069cursorNode = cursorNode->getFirstChild();30703071TR::Node *ttNode = TR::Node::create(TR::treetop, 1, cursorNode);30723073///traceMsg(comp(), "5 ttNode %p\n", ttNode);3074TR::TreeTop *treeTop = TR::TreeTop::create(self()->comp(), ttNode);3075TR::TreeTop *prevTreeTop = tt->getPrevTreeTop();3076prevTreeTop->join(treeTop);3077treeTop->join(tt);3078prevTree = treeTop;3079}3080}30813082node->getFirstChild()->recursivelyDecReferenceCount();3083node->getSecondChild()->recursivelyDecReferenceCount();3084prevTree->join(nextTree);3085}30863087if (node->canGCandReturn())3088{3089ListIterator<TR::Node> nodesIt(&rematerializedNodes);3090for (TR::Node * rematNode = nodesIt.getFirst(); rematNode != NULL; rematNode = nodesIt.getNext())3091{3092if (rematNode->getVisitCount() != visitCount)3093{3094rematNode->setVisitCount(visitCount);3095TR::Node *ttNode = TR::Node::create(TR::treetop, 1, rematNode);30963097///traceMsg(comp(), "5 ttNode %p\n", ttNode);3098TR::TreeTop *treeTop = TR::TreeTop::create(self()->comp(), ttNode);3099TR::TreeTop *prevTree = tt->getPrevTreeTop();3100prevTree->join(treeTop);3101treeTop->join(tt);3102}3103}3104rematerializedNodes.deleteAll();3105}3106}3107if (self()->comp()->getOption(TR_TraceCG))3108self()->comp()->dumpMethodTrees("Trees after this remat phase", self()->comp()->getMethodSymbol());31093110if (self()->shouldYankCompressedRefs())3111{3112visitCount = self()->comp()->incVisitCount();3113vcount_t secondVisitCount = self()->comp()->incVisitCount();3114TR::TreeTop *nextTree = NULL;3115for (tt = self()->comp()->getStartTree(); tt; tt = nextTree)3116{3117node = tt->getNode();3118nextTree = tt->getNextTreeTop();3119self()->yankCompressedRefs(tt, NULL, -1, node, visitCount, secondVisitCount);3120}31213122if (self()->comp()->getOption(TR_TraceCG))3123self()->comp()->dumpMethodTrees("Trees after this yank phase", self()->comp()->getMethodSymbol());3124}3125}31263127if (self()->comp()->useCompressedPointers() &&3128!disableRematforCP)3129{3130for (tt = self()->comp()->getStartTree(); tt; tt = tt->getNextTreeTop())3131{3132node = tt->getNode();31333134if ((node->getOpCodeValue() == TR::compressedRefs) &&3135(node->getFirstChild()->getOpCodeValue() == TR::l2a))3136{3137TR::TreeTop *prevTree = tt->getPrevTreeTop();3138TR::TreeTop *nextTree = tt->getNextTreeTop();31393140if (nextTree->getNode()->getOpCode().isNullCheck())3141{3142TR::Node *firstChild = nextTree->getNode()->getFirstChild();3143TR::Node *reference = NULL;3144if (firstChild->getOpCodeValue() == TR::l2a)3145{3146TR::ILOpCodes loadOp = self()->comp()->il.opCodeForIndirectLoad(TR::Int32);3147while (firstChild->getOpCodeValue() != loadOp)3148firstChild = firstChild->getFirstChild();3149reference = firstChild->getFirstChild();3150}3151else3152reference = nextTree->getNode()->getNullCheckReference();31533154if (reference == node->getFirstChild())3155{3156node->getFirstChild()->recursivelyDecReferenceCount();3157node->getSecondChild()->recursivelyDecReferenceCount();3158prevTree->join(nextTree);3159}3160}3161}3162}3163}31643165}3166316731683169void3170J9::CodeGenerator::rematerializeCompressedRefs(3171TR::SymbolReference * & autoSymRef,3172TR::TreeTop *tt,3173TR::Node *parent,3174int32_t childNum,3175TR::Node *node,3176vcount_t visitCount,3177List<TR::Node> *rematerializedNodes)3178{3179if (node->getVisitCount() == visitCount)3180return;31813182node->setVisitCount(visitCount);31833184bool alreadyVisitedNullCheckReference = false;3185bool alreadyVisitedReferenceInNullTest = false;3186bool alreadyVisitedReferenceInStore = false;31873188TR::Node *reference = NULL;3189TR::Node *address = NULL;31903191if (node->getOpCode().isNullCheck())3192{3193// check for either3194// a) HB!=03195// l2a3196// ladd (compressionSequence)3197// b) HB=0, shifted offsets3198// l2a3199// lshl3200//3201if ((node->getFirstChild()->getOpCodeValue() == TR::l2a) &&3202(((node->getFirstChild()->getFirstChild()->getOpCodeValue() == TR::ladd) &&3203node->getFirstChild()->getFirstChild()->containsCompressionSequence()) ||3204(node->getFirstChild()->getFirstChild()->getOpCodeValue() == TR::lshl)))3205{3206TR::ILOpCodes loadOp = self()->comp()->il.opCodeForIndirectLoad(TR::Int32);3207TR::Node *n = node->getFirstChild();3208while (n->getOpCodeValue() != loadOp)3209n = n->getFirstChild();3210reference = n->getFirstChild();3211}3212else3213{3214reference = node->getNullCheckReference();3215}32163217if (reference->getVisitCount() == visitCount)3218alreadyVisitedNullCheckReference = true;3219}32203221if ((node->getOpCodeValue() == TR::ifacmpeq) ||3222(node->getOpCodeValue() == TR::ifacmpne))3223{3224TR::Node *cmpValue = node->getFirstChild();3225if (cmpValue->getVisitCount() == visitCount)3226alreadyVisitedReferenceInNullTest = true;3227}32283229if (node->getOpCode().isStoreIndirect())3230{3231// check for either3232// a) HB!=03233// l2a3234// lsub (compressionSequence)3235// b) HB=0, shifted offsets3236// l2a3237// lshr3238//3239bool isCompressed = false;3240if ((node->getSecondChild()->getOpCodeValue() == TR::l2i) &&3241(((node->getSecondChild()->getFirstChild()->getOpCodeValue() == TR::lsub) ||3242(node->getSecondChild()->getFirstChild()->getOpCodeValue() == TR::lushr)) &&3243node->getSecondChild()->getFirstChild()->containsCompressionSequence()))3244{3245TR::Node *n = node->getSecondChild()->getFirstChild();3246while (n->getOpCodeValue() != TR::a2l)3247n = n->getFirstChild();3248address = n->getFirstChild();3249isCompressed = true;3250}32513252if (address && (address->getVisitCount() == visitCount))3253alreadyVisitedReferenceInStore = true;32543255// check for loads that have occurred before this store3256// if so, anchor the load right before the store3257//3258self()->anchorRematNodesIfNeeded(node, tt, rematerializedNodes);3259}3260else if ((node->getOpCodeValue() == TR::arraycopy) || (node->getOpCodeValue() == TR::arrayset))3261{3262self()->anchorRematNodesIfNeeded(node, tt, rematerializedNodes);3263}32643265if (node->getOpCodeValue() == TR::l2a)3266{3267rematerializedNodes->remove(node);3268}32693270if ((node->getOpCodeValue() == TR::l2a) &&3271((node->getFirstChild()->getOpCodeValue() == TR::ladd &&3272node->getFirstChild()->containsCompressionSequence()) ||3273((node->getFirstChild()->getOpCodeValue() == TR::lshl) &&3274self()->isAddressScaleIndexSupported((1 << TR::Compiler->om.compressedReferenceShiftOffset())))))3275{3276if (parent &&3277(node->getReferenceCount() > 1) &&3278((parent->getOpCode().isStoreIndirect() && (childNum == 0)) ||3279parent->getOpCode().isLoadVar() ||3280(self()->getSupportsConstantOffsetInAddressing() && parent->getOpCode().isArrayRef() &&3281(self()->canFoldLargeOffsetInAddressing() || parent->getSecondChild()->getOpCode().isLoadConst()))) &&3282performTransformation(self()->comp(), "%sRematerializing node %p(%s) in decompression sequence\n", OPT_DETAILS, node, node->getOpCode().getName()))3283{3284if ((node->getReferenceCount() > 1) &&3285!rematerializedNodes->find(node))3286{3287rematerializedNodes->add(node);3288}32893290TR::Node *dupNode= NULL;//3291TR::Node *cursorNode = node;3292TR::Node *cursorParent = parent;3293int32_t cursorChildNum = childNum;3294while (cursorNode &&3295((cursorNode->getOpCodeValue() != TR::iu2l) ||3296(cursorNode->getFirstChild()->getOpCodeValue() != TR::iloadi)))3297{3298TR::Node *copyCursorNode = TR::Node::copy(cursorNode);3299copyCursorNode->setReferenceCount(0);3300if (cursorNode == node)3301dupNode = copyCursorNode;33023303for (int32_t j = 0; j < cursorNode->getNumChildren(); ++j)3304{3305TR::Node *cursorChild = cursorNode->getChild(j);3306copyCursorNode->setAndIncChild(j, cursorChild);3307}33083309cursorParent->setAndIncChild(cursorChildNum, copyCursorNode);3310cursorNode->decReferenceCount();33113312cursorParent = cursorNode;3313cursorChildNum = 0;3314cursorNode = cursorNode->getFirstChild();3315}33163317node->setVisitCount(visitCount-1);3318dupNode->setVisitCount(visitCount);3319node = dupNode;3320}3321else3322{3323if (node->getReferenceCount() > 1)3324{3325// on x86, prevent remat of the l2a again thereby allowing3326// nodes to use the result of the add already done3327//3328if (!self()->canFoldLargeOffsetInAddressing())3329{3330if (!rematerializedNodes->find(node))3331rematerializedNodes->add(node);3332node->setVisitCount(visitCount-1);3333}3334}3335else3336rematerializedNodes->remove(node);33373338if (parent &&3339((parent->getOpCode().isArrayRef() &&3340!self()->canFoldLargeOffsetInAddressing() &&3341!parent->getSecondChild()->getOpCode().isLoadConst()) ||3342!self()->getSupportsConstantOffsetInAddressing()) &&3343performTransformation(self()->comp(), "%sYanking %p(%s) in decompression sequence\n", OPT_DETAILS, node, node->getOpCode().getName()))3344{3345if ((node->getOpCodeValue() == TR::l2a) &&3346(node->getFirstChild()->getOpCodeValue() == TR::ladd))3347{3348TR::TreeTop *cursorTree = tt;3349while (cursorTree)3350{3351bool addTree = false;3352TR::Node *cursorNode = cursorTree->getNode();3353if (cursorNode->getOpCodeValue() == TR::NULLCHK)3354{3355TR::Node *nullchkRef = cursorNode->getNullCheckReference();3356if ((nullchkRef->getOpCodeValue() == TR::l2a) &&3357(nullchkRef->getFirstChild() == node->getFirstChild()->getFirstChild()))3358{3359addTree = true;3360}3361}33623363if (!addTree && (cursorNode->getOpCodeValue() == TR::treetop) &&3364(cursorNode->getFirstChild() == node->getFirstChild()->getFirstChild()))3365{3366addTree = true;3367}33683369if (addTree)3370{3371TR::Node *ttNode = TR::Node::create(TR::treetop, 1, node);33723373if (self()->comp()->getOption(TR_TraceCG))3374traceMsg(self()->comp(), "Placing treetop %p (to hide delay) after tree %p for l2a %p\n", ttNode, cursorNode, node);33753376TR::TreeTop *treeTop = TR::TreeTop::create(self()->comp(), ttNode);3377TR::TreeTop *nextTT = cursorTree->getNextTreeTop();3378cursorTree->join(treeTop);3379treeTop->join(nextTT);3380break;3381}3382else3383{3384if ((cursorNode->getOpCodeValue() == TR::BBStart) &&3385(!cursorNode->getBlock()->isExtensionOfPreviousBlock()))3386break;3387}33883389cursorTree = cursorTree->getPrevTreeTop();3390}3391}3392}3393}3394}33953396for (int32_t i = 0; i < node->getNumChildren(); ++i)3397{3398TR::Node *child = node->getChild(i);3399self()->rematerializeCompressedRefs(autoSymRef, tt, node, i, child, visitCount, rematerializedNodes);3400}34013402static bool disableBranchlessPassThroughNULLCHK = feGetEnv("TR_disableBranchlessPassThroughNULLCHK") != NULL;3403if (node->getOpCode().isNullCheck() && reference &&3404(self()->performsChecksExplicitly() || (disableBranchlessPassThroughNULLCHK && node->getFirstChild()->getOpCodeValue() == TR::PassThrough)) &&3405((node->getFirstChild()->getOpCodeValue() == TR::l2a) ||3406(reference->getOpCodeValue() == TR::l2a)) &&3407performTransformation(self()->comp(), "%sTransforming null check reference %p in null check node %p to be checked explicitly\n", OPT_DETAILS, reference, node))3408{3409if (node->getFirstChild()->getOpCodeValue() != TR::PassThrough)3410{3411TR::Node *immChild = node->getFirstChild();3412TR::Node *ttNode = NULL;3413bool addedToList = false;3414if (node->getOpCode().isResolveCheck())3415{3416ttNode = TR::Node::createWithSymRef(TR::ResolveCHK, 1, 1, immChild, node->getSymbolReference());3417TR::Node::recreate(node, TR::NULLCHK);3418}3419else3420{3421if (immChild->getOpCodeValue() == TR::l2a)3422{3423if ((immChild->getReferenceCount() > 1) &&3424!rematerializedNodes->find(immChild))3425{3426rematerializedNodes->add(immChild);3427addedToList = true;3428}34293430immChild->setVisitCount(visitCount-1);3431TR::Node *anchorNode = TR::Node::create(TR::treetop, 1, immChild->getFirstChild()->getFirstChild());3432TR::TreeTop *anchorTree = TR::TreeTop::create(self()->comp(), anchorNode);3433immChild->getFirstChild()->getFirstChild()->setVisitCount(visitCount-1);3434TR::TreeTop *nextTT = tt->getNextTreeTop();3435tt->join(anchorTree);3436anchorTree->join(nextTT);34373438TR::Node *n = immChild->getFirstChild();3439{3440while ((n != reference) &&3441(n->getOpCodeValue() != TR::l2a))3442{3443n->setVisitCount(visitCount-1);3444n = n->getFirstChild();3445}3446}3447}3448else3449ttNode = TR::Node::create(TR::treetop, 1, immChild);3450}34513452if (ttNode)3453{3454TR::TreeTop *treeTop = TR::TreeTop::create(self()->comp(), ttNode);3455immChild->setVisitCount(visitCount-1);3456TR::TreeTop *nextTT = tt->getNextTreeTop();3457tt->join(treeTop);3458treeTop->join(nextTT);3459}34603461TR::Node *passThroughNode = TR::Node::create(TR::PassThrough, 1, reference);3462passThroughNode->setVisitCount(visitCount);3463node->setAndIncChild(0, passThroughNode);3464if (ttNode || !addedToList)3465immChild->recursivelyDecReferenceCount();3466else3467immChild->decReferenceCount();3468}34693470if ((reference->getOpCodeValue() == TR::l2a) &&3471(!alreadyVisitedNullCheckReference || (reference->getReferenceCount() == 1)) &&3472(((reference->getFirstChild()->getOpCodeValue() == TR::ladd) &&3473reference->getFirstChild()->containsCompressionSequence()) ||3474reference->getFirstChild()->getOpCodeValue() == TR::lshl) &&3475performTransformation(self()->comp(), "%sStrength reducing null check reference %p in null check node %p \n", OPT_DETAILS, reference, node))3476{3477bool addedToList = false;3478if (node->getFirstChild()->getOpCodeValue() == TR::PassThrough)3479{3480if ((reference->getReferenceCount() > 1) &&3481!rematerializedNodes->find(reference))3482{3483rematerializedNodes->add(reference);3484addedToList = true;3485}34863487TR::Node *passThroughNode = node->getFirstChild();3488TR::Node *grandChild = reference->getFirstChild()->getFirstChild();3489TR::Node *l2aNode = TR::Node::create(TR::l2a, 1, grandChild);3490if (reference->isNonNull())3491l2aNode->setIsNonNull(true);3492else if (reference->isNull())3493l2aNode->setIsNull(true);3494passThroughNode->setAndIncChild(0, l2aNode);3495if (addedToList)3496reference->decReferenceCount();3497else3498reference->recursivelyDecReferenceCount();3499reference->setVisitCount(visitCount-1);3500}3501}3502}35033504if ((node->getOpCodeValue() == TR::ifacmpeq) ||3505(node->getOpCodeValue() == TR::ifacmpne))3506{3507TR::Node *reference = node->getFirstChild();3508TR::Node *secondChild = node->getSecondChild();35093510if ((reference->getOpCodeValue() == TR::l2a) &&3511(!alreadyVisitedReferenceInNullTest || (reference->getReferenceCount() == 1)) &&3512(((reference->getFirstChild()->getOpCodeValue() == TR::ladd) &&3513reference->getFirstChild()->containsCompressionSequence())||3514reference->getFirstChild()->getOpCodeValue() == TR::lshl))3515{3516if ((secondChild->getOpCodeValue() == TR::aconst) &&3517(secondChild->getAddress() == 0) &&3518performTransformation(self()->comp(), "%sTransforming reference %p in null comparison node %p \n", OPT_DETAILS, reference, node))3519{3520bool addedToList = false;3521if ((reference->getReferenceCount() > 1) &&3522!rematerializedNodes->find(reference))3523{3524rematerializedNodes->add(reference);3525addedToList = true;3526}35273528TR::Node *compressedValue = reference->getFirstChild()->getFirstChild();3529TR::Node *l2aNode = TR::Node::create(TR::l2a, 1, compressedValue);3530if (reference->isNonNull())3531l2aNode->setIsNonNull(true);3532else if (reference->isNull())3533l2aNode->setIsNull(true);35343535node->setAndIncChild(0, l2aNode);3536if (addedToList)3537reference->decReferenceCount();3538else3539reference->recursivelyDecReferenceCount();3540reference->setVisitCount(visitCount-1);3541}3542}3543}35443545if (address && node->getOpCode().isStoreIndirect())3546{3547if (address->getOpCodeValue() == TR::l2a && (address->getReferenceCount() == 1 || !alreadyVisitedReferenceInStore) &&3548((address->getFirstChild()->getOpCodeValue() == TR::ladd && address->getFirstChild()->containsCompressionSequence()) ||3549address->getFirstChild()->getOpCodeValue() == TR::lshl))3550{3551// Check for write barriers that we can skip and which are not underneath an ArrayStoreCHK. In these cases we are safe3552// to optimize the write barrier to a simple store, thus avoiding the need to compress / uncompress the pointer.3553if (node->getOpCode().isWrtBar() && node->skipWrtBar())3554{3555// This check is overly conservative to ensure functional correctness.3556bool isPossiblyUnderArrayStoreCheck = tt->getNode()->getOpCodeValue() == TR::ArrayStoreCHK || (node->getReferenceCount() > 1 && !tt->getNode()->getOpCode().isResolveCheck());35573558if (!isPossiblyUnderArrayStoreCheck && performTransformation(self()->comp(), "%sStoring compressed pointer [%p] directly into %p in tree %p\n", OPT_DETAILS, address, node, tt->getNode()))3559{3560bool addedToList = false;3561if ((address->getReferenceCount() > 1) && !rematerializedNodes->find(address))3562{3563rematerializedNodes->add(address);3564addedToList = true;3565}35663567TR::Node *l2iNode = NULL;3568TR::ILOpCodes loadOp = self()->comp()->il.opCodeForIndirectLoad(TR::Int32);3569TR::Node *n = address;3570while (n->getOpCodeValue() != loadOp)3571n = n->getFirstChild();3572l2iNode = n;35733574if (node->getOpCode().isWrtBar())3575{3576int32_t lastChildNum = node->getNumChildren()-1;3577node->getChild(lastChildNum)->recursivelyDecReferenceCount();3578node->setNumChildren(lastChildNum);3579}35803581TR::Node::recreate(node, self()->comp()->il.opCodeForIndirectStore(TR::Int32));35823583TR::Node *immChild = node->getSecondChild();3584node->setAndIncChild(1, l2iNode);35853586address->incReferenceCount();3587immChild->recursivelyDecReferenceCount();35883589if (addedToList)3590address->decReferenceCount();3591else3592address->recursivelyDecReferenceCount();35933594address->setVisitCount(visitCount-1);3595}3596}3597}3598}3599}360036013602void3603J9::CodeGenerator::yankCompressedRefs(3604TR::TreeTop *tt,3605TR::Node *parent,3606int32_t childNum,3607TR::Node *node,3608vcount_t visitCount,3609vcount_t secondVisitCount)3610{3611if (node->getVisitCount() >= visitCount)3612return;36133614node->setVisitCount(visitCount);36153616for (int32_t i = 0; i < node->getNumChildren(); ++i)3617{3618TR::Node *child = node->getChild(i);3619self()->yankCompressedRefs(tt, node, i, child, visitCount, secondVisitCount);3620}36213622if (parent &&3623(parent->getOpCodeValue() == TR::treetop) &&3624(node->getOpCodeValue() == TR::l2a) &&3625(node->getFirstChild()->getOpCodeValue() == TR::ladd &&3626node->getFirstChild()->containsCompressionSequence()))3627{36283629//printf("Looking at node %p in %s\n", node, comp()->signature()); fflush(stdout);3630TR::TreeTop *firstTree = tt;3631TR::TreeTop *lastTree = tt;3632bool nullCheckTree = false;3633bool exprNeedsChecking = true;3634if ((node->getFirstChild()->getFirstChild()->getOpCodeValue() == TR::iu2l) &&3635(node->getFirstChild()->getFirstChild()->getFirstChild()->getOpCodeValue() == TR::iloadi) &&3636((node->getFirstChild()->getFirstChild()->getFirstChild()->getFirstChild()->getOpCode().isLoadVarDirect() &&3637node->getFirstChild()->getFirstChild()->getFirstChild()->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm()) ||3638(node->getFirstChild()->getFirstChild()->getFirstChild()->getFirstChild()->getOpCodeValue() == TR::aRegStore)))3639exprNeedsChecking = false;36403641TR::TreeTop *prevTree = tt->getPrevTreeTop();3642TR::Node *prevNode = prevTree->getNode();3643if (prevNode->getOpCodeValue() == TR::NULLCHK)3644{3645if (prevNode->getFirstChild()->getOpCodeValue() == TR::PassThrough)3646{3647TR::Node *reference = prevNode->getNullCheckReference();3648if ((reference == node) ||3649((reference->getOpCodeValue() == TR::l2a) &&3650(reference->getFirstChild() == node->getFirstChild()->getFirstChild())))3651{3652nullCheckTree = true;3653firstTree = prevTree;3654prevTree = prevTree->getPrevTreeTop();3655prevNode = prevTree->getNode();3656}3657}3658}36593660if ((prevNode->getOpCodeValue() == TR::treetop) &&3661(prevNode->getFirstChild() == node->getFirstChild()->getFirstChild()))3662firstTree = prevTree;3663else3664firstTree = tt;36653666if (firstTree != tt)3667{3668TR_BitVector symbolReferencesInNode(self()->comp()->getSymRefCount(), self()->comp()->trMemory(), stackAlloc);36693670////bool canYank = collectSymRefs(node, &symbolReferencesInNode, secondVisitCount);3671// since symRefs need to be collected for each treetop, we'll need a fresh visitCount3672// for every walk of a tree3673//3674bool canYank = self()->collectSymRefs(node, &symbolReferencesInNode, self()->comp()->incVisitCount());36753676TR_BitVector intersection(self()->comp()->getSymRefCount(), self()->comp()->trMemory(), stackAlloc);36773678//printf("canYank %d node %d in %s\n", canYank, node, comp()->signature()); fflush(stdout);36793680if (canYank)3681{3682TR::TreeTop *cursorTree = firstTree->getPrevTreeTop();3683int32_t numTrees = 0;3684while (cursorTree)3685{3686numTrees++;3687TR::Node *cursorNode = cursorTree->getNode();3688//printf("canYank %d node %p cursor %p in %s\n", canYank, node, cursorNode, comp()->signature()); fflush(stdout);3689TR::Node *childNode = NULL;3690if (cursorNode->getNumChildren() > 0)3691childNode = cursorNode->getFirstChild();36923693if (cursorNode && cursorNode->getOpCode().hasSymbolReference() &&3694(cursorNode->getOpCode().isStore() || cursorNode->getOpCode().isCall()))3695{3696if (symbolReferencesInNode.get(cursorNode->getSymbolReference()->getReferenceNumber()))3697{3698break;3699}37003701intersection.empty();3702cursorNode->getSymbolReference()->getUseDefAliases().getAliasesAndUnionWith(intersection);3703intersection &= symbolReferencesInNode;3704if (!intersection.isEmpty())3705{3706break;3707}3708}37093710if (childNode && childNode->getOpCode().hasSymbolReference())3711{3712if (childNode && childNode->getOpCode().hasSymbolReference() &&3713(childNode->getOpCode().isStore() || childNode->getOpCode().isCall()))3714{3715if (symbolReferencesInNode.get(childNode->getSymbolReference()->getReferenceNumber()))3716{3717break;3718}37193720intersection.empty();3721childNode->getSymbolReference()->getUseDefAliases().getAliasesAndUnionWith(intersection);3722intersection &= symbolReferencesInNode;3723if (!intersection.isEmpty())3724{3725break;3726}3727}3728}37293730if (nullCheckTree)3731{3732if (cursorNode->getOpCode().isStore())3733{3734if (cursorNode->getSymbol()->isStatic() ||3735cursorNode->getSymbol()->isShadow() ||3736!cursorNode->getSymbolReference()->getUseonlyAliases().isZero(self()->comp()))3737{3738break;3739}3740}3741}37423743if (cursorNode->exceptionsRaised())3744{3745if (nullCheckTree || exprNeedsChecking)3746break;3747}37483749if (cursorNode->getOpCodeValue() == TR::BBStart)3750{3751break;3752}37533754cursorTree = cursorTree->getPrevTreeTop();3755}37563757if (cursorTree != firstTree->getPrevTreeTop())3758{3759/////printf("Yanking l2a node %p past %d trees in %s\n", node, numTrees, comp()->signature()); fflush(stdout);3760TR::TreeTop *nextTree = cursorTree->getNextTreeTop();3761TR::TreeTop *prevTreeAtSrc = firstTree->getPrevTreeTop();3762TR::TreeTop *nextTreeAtSrc = lastTree->getNextTreeTop();3763prevTreeAtSrc->join(nextTreeAtSrc);3764cursorTree->join(firstTree);3765lastTree->join(nextTree);3766}3767}3768}3769}3770}377137723773void3774J9::CodeGenerator::anchorRematNodesIfNeeded(3775TR::Node *node,3776TR::TreeTop *tt,3777List<TR::Node> *rematerializedNodes)3778{3779TR::SymbolReference *symRef = node->getSymbolReference();3780TR::SparseBitVector aliases(self()->comp()->allocator());3781if (symRef->sharesSymbol())3782symRef->getUseDefAliases().getAliases(aliases);37833784ListIterator<TR::Node> nodesIt(rematerializedNodes);3785for (TR::Node * rematNode = nodesIt.getFirst(); rematNode != NULL; rematNode = nodesIt.getNext())3786{3787if (rematNode->getOpCodeValue() == TR::l2a)3788{3789TR::Node *load = rematNode->getFirstChild();3790while (load->getOpCodeValue() != TR::iu2l)3791load = load->getFirstChild();3792load = load->getFirstChild();3793if (load->getOpCode().isLoadIndirect() &&3794((load->getSymbolReference() == node->getSymbolReference()) ||3795(aliases.ValueAt(load->getSymbolReference()->getReferenceNumber()))))3796{3797rematerializedNodes->remove(rematNode);3798rematNode->setVisitCount(self()->comp()->getVisitCount());3799if (self()->comp()->getOption(TR_TraceCG))3800{3801if (node->getOpCode().isStoreIndirect())3802traceMsg(self()->comp(), "Found previous load %p same as store %p, anchoring load\n", load, node);3803else3804traceMsg(self()->comp(), "Found previous load %p aliases with node %p, anchoring load\n", load, node);3805}3806TR::Node *ttNode = TR::Node::create(TR::treetop, 1, rematNode);3807TR::TreeTop *treeTop = TR::TreeTop::create(self()->comp(), ttNode);3808TR::TreeTop *prevTree = tt->getPrevTreeTop();3809prevTree->join(treeTop);3810treeTop->join(tt);3811}3812}3813}3814}381538163817/**3818* Insert asyncCheck's before method returns. Without this, methods3819* with no loops or calls will never be sa/mpled, and will be stuck3820* forever at their initial opt-level. (Important for mpegaudio,3821* which has some large, warm methods with no loops or calls).3822*/3823void J9::CodeGenerator::insertEpilogueYieldPoints()3824{3825// Look for all returns, and insert async check before them3826TR::CFG * cfg = self()->comp()->getFlowGraph();38273828for (TR::TreeTop * treeTop = self()->comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())3829{38303831TR::Node * node = treeTop->getNode();3832TR::ILOpCodes opCode = node->getOpCodeValue();38333834if (opCode == TR::BBStart)3835{3836TR::Block * block = node->getBlock();38373838TR::TreeTop * tt1 = block->getLastRealTreeTop();3839TR::Node * node1 = tt1->getNode();38403841if (node1->getOpCode().isReturn())3842{3843TR::TreeTop *prevTT = tt1->getPrevTreeTop();3844if (node1->getNumChildren()>0)3845{3846//anchor the return value3847TR::Node *ttNode = TR::Node::create(TR::treetop, 1, node1->getFirstChild());3848TR::TreeTop *anchorTree = TR::TreeTop::create(self()->comp(), ttNode);3849prevTT->join(anchorTree);3850anchorTree->join(tt1);3851prevTT = anchorTree;3852}38533854TR::Node *asyncNode = TR::Node::createWithSymRef(node, TR::asynccheck, 0,3855self()->comp()->getSymRefTab()->findOrCreateAsyncCheckSymbolRef(self()->comp()->getMethodSymbol()));3856TR::TreeTop *asyncTree = TR::TreeTop::create(self()->comp(), asyncNode);3857prevTT->join(asyncTree);3858asyncTree->join(tt1);3859treeTop = tt1->getNextTreeTop();3860#if 03861// Asynccheck's need to be at the beginning of blocks3862TR::Block * returnBlock = block->split(tt1, cfg);3863treeTop = tt1->getNextTreeTop();3864TR::Node *asyncNode = TR::Node::createWithSymRef(node, TR::asynccheck, 1, 0,3865comp()->getSymRefTab()->findOrCreateAsyncCheckSymbolRef(comp()->getMethodSymbol()));3866TR::TreeTop *asyncTree = TR::TreeTop::create(comp(), asyncNode);38673868returnBlock->prepend(asyncTree);3869#endif3870}3871}3872}3873}387438753876TR::TreeTop *3877J9::CodeGenerator::genSymRefStoreToArray(3878TR::Node* refNode,3879TR::Node* arrayAddressNode,3880TR::Node* firstOffset,3881TR::Node* loadNode,3882int32_t secondOffset,3883TR::TreeTop* insertionPoint)3884{3885TR::Node* offsetNode;38863887if (firstOffset)3888offsetNode = TR::Node::create(TR::iadd, 2,3889firstOffset,3890TR::Node::create(refNode, TR::iconst, 0, secondOffset));3891else3892offsetNode = TR::Node::create(refNode, TR::iconst, 0, secondOffset);38933894if (self()->comp()->target().is64Bit())3895{3896offsetNode = TR::Node::create(TR::i2l, 1, offsetNode);3897}38983899TR::Node* addrNode = TR::Node::create(self()->comp()->target().is64Bit()?TR::aladd:TR::aiadd,39002, arrayAddressNode, offsetNode);3901TR::Node* storeNode =3902TR::Node::createWithSymRef(self()->comp()->il.opCodeForIndirectStore(loadNode->getDataType()), 2, 2,3903addrNode, loadNode,3904self()->symRefTab()->findOrCreateGenericIntShadowSymbolReference(0));3905TR::TreeTop* storeTreeTop = TR::TreeTop::create(self()->comp(), storeNode);3906insertionPoint->insertTreeTopsAfterMe(storeTreeTop);3907return storeTreeTop;3908}390939103911bool3912J9::CodeGenerator::collectSymRefs(3913TR::Node *node,3914TR_BitVector *symRefs,3915vcount_t visitCount)3916{3917if (node->getVisitCount() >= visitCount)3918return true;39193920node->setVisitCount(visitCount);392139223923if (node->getOpCode().hasSymbolReference())3924{3925if (node->getOpCode().isLoadVar())3926{3927TR::SymbolReference *symRef = node->getSymbolReference();3928symRef->getUseDefAliases().getAliasesAndUnionWith(*symRefs);39293930symRefs->set(symRef->getReferenceNumber());3931}3932else3933return false;3934}39353936for (int32_t i = 0; i < node->getNumChildren(); ++i)3937{3938TR::Node *child = node->getChild(i);3939if (!self()->collectSymRefs(child, symRefs, visitCount))3940return false;3941}39423943return true;3944}39453946bool3947J9::CodeGenerator::willGenerateNOPForVirtualGuard(TR::Node *node)3948{3949TR::Compilation *comp = self()->comp();39503951if (!(node->isNopableInlineGuard() || node->isHCRGuard() || node->isOSRGuard())3952|| !self()->getSupportsVirtualGuardNOPing())3953return false;39543955TR_VirtualGuard *virtualGuard = comp->findVirtualGuardInfo(node);39563957if (!((comp->performVirtualGuardNOPing() || node->isHCRGuard() || node->isOSRGuard() || self()->needClassAndMethodPointerRelocations()) &&3958comp->isVirtualGuardNOPingRequired(virtualGuard)) &&3959virtualGuard->canBeRemoved())3960return false;39613962if ( node->getOpCodeValue() != TR::ificmpne3963&& node->getOpCodeValue() != TR::ifacmpne3964&& node->getOpCodeValue() != TR::iflcmpne)3965{3966// not expecting reversed comparison3967// Raise an assume if the optimizer requested that this virtual guard must be NOPed3968//3969TR_ASSERT(virtualGuard->canBeRemoved(), "virtualGuardHelper: a non-removable virtual guard cannot be NOPed");39703971return false;3972}39733974return true;3975}39763977/** \brief3978* Following codegen phase walks the blocks in the CFG and checks for the virtual guard performing TR_MethodTest3979* and guarding an inlined interface call.3980*3981* \details3982* Virtual Guard performing TR_MethodTest would look like following.3983* n1n BBStart <block_X>3984* ...3985* n2n ifacmpne goto -> nXXn3986* n3n aloadi <offset of inlined method in VTable>3987* n4n aload <vft>3988* n5n aconst <J9Method of inlined method>3989* n6n BBEnd <block_X>3990* For virtual dispatch sequence, we know that this is the safe check but in case of interface call, classes implementing3991* that interface would have different size of VTable. This makes executing above check unsafe when VTable of the class of3992* the receiver object is smaller, effectively making reference in n3n to pointing to a garbage location which might lead3993* to a segmentation fault if the reference in not memory mapped or if bychance it contains J9Method pointer of same inlined3994* method then it will execute a code which should not be executed.3995* For this kind of Virtual guards which are not nop'd we need to add a range check to make sure the address we are going to3996* access is pointing to a valid location in VTable. There are mainly two ways we can add this range check test. First one is3997* during the conception of the virtual guard. There are many downsides of doing so especially when other optimizations which3998* can moved guards around (for example loop versioner, virtualguard head merger, etc) needs to make sure to move range check3999* test around as well. Other way is to scan for this type of guards after optimization is finished like here in CodeGen Phase4000* and add a range check test here.4001* At the end of this function, we would have following code around them method test.4002* BBStart <block_X>4003* ...4004* ifacmple goto nXXn4005* aloadi <offset of VTableHeader.size from J9Class*>4006* aload <vft>4007* aconst <Index of the inlined method in VTable of class of inlined method>4008* BBEnd <block_X>4009*4010* BBStart <block_Y>4011* ifacmpne goto -> nXXn4012* aloadi <offset of inlined method in VTable>4013* aload <vft>4014* aconst <J9Method of inlined method>4015* BBEnd <block_Y>4016*/4017void4018J9::CodeGenerator::fixUpProfiledInterfaceGuardTest()4019{4020TR::Compilation *comp = self()->comp();4021TR::CFG * cfg = comp->getFlowGraph();4022TR::NodeChecklist checklist(comp);4023for (TR::AllBlockIterator iter(cfg, comp); iter.currentBlock() != NULL; ++iter)4024{4025TR::Block *block = iter.currentBlock();4026TR::TreeTop *treeTop = block->getLastRealTreeTop();4027TR::Node *node = treeTop->getNode();4028if (node->getOpCode().isIf() && node->isTheVirtualGuardForAGuardedInlinedCall() && !checklist.contains(node))4029{4030TR_VirtualGuard *vg = comp->findVirtualGuardInfo(node);4031// Mainly we need to make sure that virtual guard which performs the TR_MethodTest and can be NOP'd are needed the range check.4032if (vg && vg->getTestType() == TR_MethodTest && !(self()->willGenerateNOPForVirtualGuard(node)))4033{4034TR::SymbolReference *callSymRef = vg->getSymbolReference();4035TR_ASSERT_FATAL(callSymRef != NULL, "Guard n%dn for the inlined call should have stored symbol reference for the call", node->getGlobalIndex());4036if (callSymRef->getSymbol()->castToMethodSymbol()->isInterface())4037{4038TR::DebugCounter::incStaticDebugCounter(comp, TR::DebugCounter::debugCounterName(comp, "profiledInterfaceTest/({%s}{%s})", comp->signature(), comp->getHotnessName(comp->getMethodHotness())));4039dumpOptDetails(comp, "Need to add a rangecheck before n%dn in block_%d\n",node->getGlobalIndex(), block->getNumber());40404041// We need a VFT Load of the receiver object to get the VTableHeader.size to check the range. As this operation is happening during codegen phase, only4042// known concrete way we can have this information is through aloadi child of the guard that has single child which is vft load of receiver object.4043// Now instead of accessing VFT load from the child of the aloadi, we could have treetop's the aloadi during inlining where we generate the virtual guard4044// to access information from the treetop. Because of the same reasons lined up behind adding range check test during codegen phase in the description of this function,4045// we would need to make changes in all optimizations moving Virtual Guard around to keep that treetop together before guard which will be very difficult to enforce.4046// Also as children of virtual guard is very self contained and atm it is very unlikely that other optimizations are going to find opportunity of manipulating them and4047// Because of the fact that it is very unlikely that we will have another aloadi node with same VTable offset of same receiver object, this child would not be commoned out4048// and have only single reference in this virtual guard therefore splitting of block will not store it to temp slot.4049// In rare case child of the virtual guard is manipulated then illegal memory reference load would hace occured before the Virtual Guard which4050// is already a bug as mentioned in the description of this function and it would be safer to fail compilation.4051TR::Node *vTableLoad = node->getFirstChild();4052if (!(vTableLoad->getOpCodeValue() == TR::aloadi && comp->getSymRefTab()->isVtableEntrySymbolRef(vTableLoad->getSymbolReference())))4053comp->failCompilation<TR::CompilationException>("Abort compilation as Virtual Guard has generated illegal memory reference");4054TR::Node *vTableSizeOfReceiver = NULL;4055TR::Node *rangeCheckTest = NULL;4056if (self()->comp()->target().is64Bit())4057{4058vTableSizeOfReceiver = TR::Node::createWithSymRef(TR::lloadi, 1, 1, vTableLoad->getFirstChild(),4059comp->getSymRefTab()->findOrCreateVtableEntrySymbolRef(comp->getMethodSymbol(),4060sizeof(J9Class)+ offsetof(J9VTableHeader, size)));4061rangeCheckTest = TR::Node::createif(TR::iflcmple, vTableSizeOfReceiver,4062TR::Node::lconst(node, (vTableLoad->getSymbolReference()->getOffset() - sizeof(J9Class) - sizeof(J9VTableHeader)) / sizeof(UDATA)) ,4063node->getBranchDestination());4064}4065else4066{4067vTableSizeOfReceiver = TR::Node::createWithSymRef(TR::iloadi, 1, 1, vTableLoad->getFirstChild(),4068comp->getSymRefTab()->findOrCreateVtableEntrySymbolRef(comp->getMethodSymbol(),4069sizeof(J9Class)+ offsetof(J9VTableHeader, size)));4070rangeCheckTest = TR::Node::createif(TR::ificmple, vTableSizeOfReceiver,4071TR::Node::iconst(node, (vTableLoad->getSymbolReference()->getOffset() - sizeof(J9Class) - sizeof(J9VTableHeader)) / sizeof(UDATA)) ,4072node->getBranchDestination());4073}4074TR::TreeTop *rangeTestTT = TR::TreeTop::create(comp, treeTop->getPrevTreeTop(), rangeCheckTest);4075TR::Block *newBlock = block->split(treeTop, cfg, false, false);4076cfg->addEdge(block, node->getBranchDestination()->getEnclosingBlock());4077newBlock->setIsExtensionOfPreviousBlock();4078if (node->getNumChildren() == 3)4079{4080TR::Node *currentBlockGlRegDeps = node->getChild(2);4081TR::Node *exitGlRegDeps = TR::Node::create(TR::GlRegDeps, currentBlockGlRegDeps->getNumChildren());4082for (int i = 0; i < currentBlockGlRegDeps->getNumChildren(); i++)4083{4084TR::Node *child = currentBlockGlRegDeps->getChild(i);4085exitGlRegDeps->setAndIncChild(i, child);4086}4087rangeCheckTest->addChildren(&exitGlRegDeps, 1);4088}4089// While walking all blocks in CFG, when we find the location to add the range check, it will split the original block and4090// We will have actual Virtual Guard in new block. As Block Iterator guarantees to visit all block in the CFG,4091// While going over the blocks, we will encounter same virtual guard in newly created block after split.4092// We need to make sure we are not examining already visited guard.4093// Add checked virtual guard node to NodeChecklist to make sure we check all the nodes only once.4094checklist.add(node);4095}4096}4097}4098}4099}4100410141024103void4104J9::CodeGenerator::allocateLinkageRegisters()4105{4106if (self()->comp()->isGPUCompilation())4107return;41084109TR::Delimiter d(self()->comp(), self()->comp()->getOptions()->getAnyOption(TR_TraceOptDetails|TR_CountOptTransformations), "AllocateLinkageRegisters");41104111if (!self()->prepareForGRA())4112{4113dumpOptDetails(self()->comp(), " prepareForGRA failed -- giving up\n");4114return;4115}41164117TR::Block *firstBlock = self()->comp()->getStartBlock();4118const int32_t numParms = self()->comp()->getMethodSymbol()->getParameterList().getSize();41194120if (numParms == 0) return ;41214122TR_BitVector globalRegsWithRegLoad(self()->getNumberOfGlobalRegisters(), self()->comp()->trMemory(), stackAlloc); // indexed by global register number4123TR_BitVector killedParms(numParms, self()->comp()->trMemory(), stackAlloc); // indexed by parm->getOrdinal()4124TR::Node **regLoads = (TR::Node**)self()->trMemory()->allocateStackMemory(numParms*sizeof(regLoads[0])); // indexed by parm->getOrdinal() to give the RegLoad for a given parm4125memset(regLoads, 0, numParms*sizeof(regLoads[0]));41264127// If the first block is in a loop, then it can be reached by parm stores in other blocks.4128// Conservatively, don't use RegLoads for any parm that is stored anywhere in the method.4129//4130if (firstBlock->getPredecessors().size() > 1)4131{4132// Rather than put regStores in all predecessors, we give up.4133//4134dumpOptDetails(self()->comp(), " First basic block is in a loop -- giving up\n");4135return;4136}41374138// Initialize regLoads and usedGlobalRegs from the RegLoads already present on the BBStart node4139//4140TR::Node *bbStart = self()->comp()->getStartTree()->getNode();4141TR_ASSERT(bbStart->getOpCodeValue() == TR::BBStart, "assertion failure");4142TR::Node *oldRegDeps = (bbStart->getNumChildren() > 0)? bbStart->getFirstChild() : NULL;4143if (oldRegDeps)4144{4145TR_ASSERT(oldRegDeps->getOpCodeValue() == TR::GlRegDeps, "assertion failure");4146for (uint16_t i=0; i < oldRegDeps->getNumChildren(); i++)4147{4148TR::Node *regLoad = oldRegDeps->getChild(i);4149TR_ASSERT(regLoad->getSymbol() && regLoad->getSymbol()->isParm(), "First basic block can have only parms live on entry");4150dumpOptDetails(self()->comp(), " Parm %d has RegLoad %s\n", regLoad->getSymbol()->getParmSymbol()->getOrdinal(), self()->comp()->getDebug()->getName(regLoad));4151regLoads[regLoad->getSymbol()->getParmSymbol()->getOrdinal()] = regLoad;4152if (regLoad->getType().isInt64() && self()->comp()->target().is32Bit() && !self()->use64BitRegsOn32Bit())4153{4154globalRegsWithRegLoad.set(regLoad->getLowGlobalRegisterNumber());4155globalRegsWithRegLoad.set(regLoad->getHighGlobalRegisterNumber());4156}4157else4158{4159globalRegsWithRegLoad.set(regLoad->getGlobalRegisterNumber());4160}4161}4162}4163if (self()->comp()->getOption(TR_TraceOptDetails))4164{4165dumpOptDetails(self()->comp(), " Initial globalRegsWithRegLoad: ");4166self()->getDebug()->print(self()->comp()->getOptions()->getLogFile(), &globalRegsWithRegLoad);4167dumpOptDetails(self()->comp(), "\n");4168}416941704171// Recursively replace parm loads with regLoads; create new RegLoads as necessary4172//4173vcount_t visitCount = self()->comp()->incVisitCount();4174int32_t numRegLoadsAdded = 0;4175for(TR::TreeTop *tt = firstBlock->getFirstRealTreeTop(); tt; tt = tt->getNextTreeTop())4176{4177TR::Node *node = tt->getNode();4178if (node->getOpCodeValue() == TR::BBStart && !node->getBlock()->isExtensionOfPreviousBlock())4179break;4180numRegLoadsAdded += self()->changeParmLoadsToRegLoads(node, regLoads, &globalRegsWithRegLoad, killedParms, visitCount);4181if (node->getOpCode().isStoreDirect() && node->getSymbol()->isParm())4182{4183killedParms.set(node->getSymbol()->getParmSymbol()->getOrdinal());4184if (self()->comp()->getOption(TR_TraceOptDetails))4185{4186dumpOptDetails(self()->comp(), " Found store %s\n killedParms is now ", self()->comp()->getDebug()->getName(node));4187self()->getDebug()->print(self()->comp()->getOptions()->getLogFile(), &killedParms);4188dumpOptDetails(self()->comp(), "\n");4189}4190}4191}41924193// Make sure all RegLoads are present on the BBStart's regdeps4194//4195if (numRegLoadsAdded > 0)4196{4197uint16_t numOldRegDeps = oldRegDeps? oldRegDeps->getNumChildren() : 0;4198uint16_t numNewRegDeps = numOldRegDeps + numRegLoadsAdded;41994200// Create GlRegDeps4201//4202TR::Node *newRegDeps = TR::Node::create(bbStart, TR::GlRegDeps, numNewRegDeps);4203uint16_t childNum=0;42044205for (int32_t parmNum=0; parmNum < numParms; parmNum++)4206if (regLoads[parmNum])4207newRegDeps->setAndIncChild(childNum++, regLoads[parmNum]);42084209// Remove existing regdeps from oldRegDeps4210//4211for (childNum = 0; childNum < numOldRegDeps; childNum++)4212oldRegDeps->getChild(childNum)->decReferenceCount();42134214// Stick the new regDeps on bbStart4215//4216bbStart->setAndIncChild(0, newRegDeps);4217bbStart->setNumChildren(1);42184219dumpOptDetails(self()->comp(), " Created new GlRegDeps %s on BBStart %s\n",4220self()->comp()->getDebug()->getName(newRegDeps),4221self()->comp()->getDebug()->getName(bbStart));4222}4223}422442254226void4227J9::CodeGenerator::swapChildrenIfNeeded(TR::Node *store, char *optDetails)4228{4229TR::Node *valueChild = store->getValueChild();42304231// swap children to increase the chances of being able to use location "a" as an accumulator instead of needing a temp copy4232//4233// could also do this for another commutative operation -- like pdmul, but the advantage isn't as clear with multiply as the4234// the relative size of the operands and how the instruction is actually encoded are important factors too for determining the best operand ordering4235// reorder:4236// pdstore "a"4237// pdadd4238// x4239// pdload "a"4240// to:4241// pdstore "a"4242// pdadd4243// pdload "a"4244// x4245//4246if (valueChild->getOpCode().isCommutative() && (valueChild->getOpCode().isPackedAdd()))4247{4248if (valueChild->getFirstChild()->getOpCode().isLoadVar() &&4249valueChild->getSecondChild()->getOpCode().isLoadVar() &&4250valueChild->getFirstChild()->getSymbolReference() == valueChild->getSecondChild()->getSymbolReference())4251{4252// avoid continual swapping of this case4253// pdstore "a"4254// pdadd4255// pdload "a"4256// pdload "a"4257}4258else if (valueChild->getSecondChild()->getOpCode().isLoadVar() &&4259(valueChild->getSecondChild()->getSymbolReference() == store->getSymbolReference()) &&4260!self()->comp()->getOption(TR_DisableBCDArithChildOrdering) &&4261performTransformation(self()->comp(), "%s%s valueChild %s [%s] second child %s [%s] symRef matches store symRef (#%d) so swap children\n",4262optDetails, store->getOpCode().getName(),valueChild->getOpCode().getName(),4263valueChild->getName(self()->comp()->getDebug()), valueChild->getSecondChild()->getOpCode().getName(),valueChild->getSecondChild()->getName(self()->comp()->getDebug()),store->getSymbolReference()->getReferenceNumber()))4264{4265valueChild->swapChildren();4266}4267}4268}426942704271uint16_t4272J9::CodeGenerator::changeParmLoadsToRegLoads(TR::Node *node, TR::Node **regLoads, TR_BitVector *globalRegsWithRegLoad, TR_BitVector &killedParms, vcount_t visitCount)4273{4274if (node->getVisitCount() == visitCount)4275{4276return 0;4277}4278else4279node->setVisitCount(visitCount);42804281uint16_t numNewRegLoads = 0;42824283if (node->getOpCode().isLoadAddr() && node->getOpCode().hasSymbolReference() && node->getSymbol()->isParm())4284{4285killedParms.set(node->getSymbol()->getParmSymbol()->getOrdinal());4286if (self()->comp()->getOption(TR_TraceOptDetails))4287{4288dumpOptDetails(self()->comp(), " Found loadaddr %s\n killedParms is now ", self()->comp()->getDebug()->getName(node));4289self()->getDebug()->print(self()->comp()->getOptions()->getLogFile(), &killedParms);4290dumpOptDetails(self()->comp(), "\n");4291}4292}42934294if (node->getOpCode().isLoadVar() && node->getSymbol()->isParm())4295{4296TR::ParameterSymbol *parm = node->getSymbol()->getParmSymbol();4297int8_t lri = parm->getLinkageRegisterIndex();4298TR::ILOpCodes regLoadOp = self()->comp()->il.opCodeForRegisterLoad(parm->getDataType());42994300if (regLoads[parm->getOrdinal()] == NULL && lri != -1 && !killedParms.isSet(parm->getOrdinal()))4301{4302// Transmute this node into a regLoad43034304if ((node->getType().isInt64() && self()->comp()->target().is32Bit() && !self()->use64BitRegsOn32Bit()))4305{4306if (self()->getDisableLongGRA())4307{4308dumpOptDetails(self()->comp(), " GRA not supported for longs; leaving %s unchanged\n", self()->comp()->getDebug()->getName(node));4309}4310else4311{4312// Endianness affects how longs are passed4313//4314int8_t lowLRI, highLRI;4315if (self()->comp()->target().cpu.isBigEndian())4316{4317highLRI = lri;4318lowLRI = lri+1;4319}4320else4321{4322lowLRI = lri;4323highLRI = lri+1;4324}4325TR_GlobalRegisterNumber lowReg = self()->getLinkageGlobalRegisterNumber(lowLRI, node->getDataType());4326TR_GlobalRegisterNumber highReg = self()->getLinkageGlobalRegisterNumber(highLRI, node->getDataType());43274328if (lowReg != -1 && highReg != -1 && !globalRegsWithRegLoad->isSet(lowReg) && !globalRegsWithRegLoad->isSet(highReg)4329&& performTransformation(self()->comp(), "O^O LINKAGE REGISTER ALLOCATION: transforming %s into %s\n", self()->comp()->getDebug()->getName(node), self()->comp()->getDebug()->getName(regLoadOp)))4330{4331// Both halves are in regs, and both regs are available.4332// Transmute load into regload4333//4334if(parm->getDataType() == TR::Aggregate)4335{4336dumpOptDetails(self()->comp(), "\tNot doing transformation for parm %p because it is an aggregate.\n",node);4337}4338else4339{4340TR::Node::recreate(node, self()->comp()->il.opCodeForRegisterLoad(parm->getDataType()));4341node->setLowGlobalRegisterNumber(lowReg);4342node->setHighGlobalRegisterNumber(highReg);43434344// Update state to include the new regLoad4345//4346regLoads[parm->getOrdinal()] = node;4347globalRegsWithRegLoad->set(lowReg);4348globalRegsWithRegLoad->set(highReg);4349numNewRegLoads++;4350}4351}4352}4353}4354else if (self()->comp()->target().cpu.isZ() && self()->comp()->target().isLinux() && parm->getDataType() == TR::Aggregate &&4355(parm->getSize() <= 2 || parm->getSize() == 4 || parm->getSize() == 8))4356{4357// On zLinux aggregates with a size of 1, 2, 4 or 8 bytes are passed by value in registers.4358// Otherwise they are passed by reference via buffer4359// Here transform the value in register to aggregate again4360TR::DataType dt = TR::NoType;4361if (parm->getSize() == 8)4362dt = (node->getOpCode().isDouble()) ? TR::Double : TR::Int64;4363else if (parm->getSize() == 4)4364dt = (node->getOpCode().isFloat()) ? TR::Float : TR::Int32;4365else if (parm->getSize() == 2)4366dt = TR::Int16;4367else if (parm->getSize() == 1)4368dt = TR::Int8;43694370// if not 64 bit and data type is 64 bit, need to place it into two registers4371if ((self()->comp()->target().is32Bit() && !self()->use64BitRegsOn32Bit()) && dt == TR::Int64)4372{4373TR_GlobalRegisterNumber lowReg = self()->getLinkageGlobalRegisterNumber(lri+1, dt);4374TR_GlobalRegisterNumber highReg = self()->getLinkageGlobalRegisterNumber(lri, dt);43754376if (lowReg != -1 && highReg != -1 && !globalRegsWithRegLoad->isSet(lowReg) && !globalRegsWithRegLoad->isSet(highReg) &&4377performTransformation(self()->comp(), "O^O LINKAGE REGISTER ALLOCATION: transforming aggregate parm %s into xRegLoad\n", self()->comp()->getDebug()->getName(node)))4378{4379TR::Node::recreate(node, self()->comp()->il.opCodeForRegisterLoad(dt));43804381node->setLowGlobalRegisterNumber(lowReg);4382node->setHighGlobalRegisterNumber(highReg);43834384globalRegsWithRegLoad->set(lowReg);4385globalRegsWithRegLoad->set(highReg);43864387regLoads[parm->getOrdinal()] = node;4388numNewRegLoads++;4389}4390}4391else4392{4393TR_GlobalRegisterNumber reg = self()->getLinkageGlobalRegisterNumber(lri, dt);43944395if (reg != -1 && !globalRegsWithRegLoad->isSet(reg) &&4396performTransformation(self()->comp(), "O^O LINKAGE REGISTER ALLOCATION: transforming aggregate parm %s into xRegLoad\n", self()->comp()->getDebug()->getName(node)))4397{4398TR::Node::recreate(node, self()->comp()->il.opCodeForRegisterLoad(dt));43994400node->setGlobalRegisterNumber(reg);4401globalRegsWithRegLoad->set(reg);44024403regLoads[parm->getOrdinal()] = node;4404numNewRegLoads++;4405}4406}4407}4408else4409{4410TR_GlobalRegisterNumber reg = self()->getLinkageGlobalRegisterNumber(parm->getLinkageRegisterIndex(), node->getDataType());4411if (reg != -1 && !globalRegsWithRegLoad->isSet(reg)4412&& performTransformation(self()->comp(), "O^O LINKAGE REGISTER ALLOCATION: transforming %s into %s\n", self()->comp()->getDebug()->getName(node), self()->comp()->getDebug()->getName(regLoadOp)))4413{4414// Transmute load into regload4415//4416if(parm->getDataType() == TR::Aggregate) // for aggregates, must look at node type to determine register type as parm type is still 'aggregate'4417{4418dumpOptDetails(self()->comp(), "\tNot doing transformation for parm %p because it is an aggregate.\n",node);4419}4420else4421{4422TR::Node::recreate(node, self()->comp()->il.opCodeForRegisterLoad(parm->getDataType()));4423node->setGlobalRegisterNumber(reg);44244425// Update state to include the new regLoad4426//4427regLoads[parm->getOrdinal()] = node;4428globalRegsWithRegLoad->set(reg);4429numNewRegLoads++;4430}4431}4432}4433}4434else4435{4436// We already have a regLoad for this parm.4437// It's awkward to common the parm at this point because we'd need a pointer to its parent.4438// Let's conservatively do nothing, on the assumption that CSE usually4439// commons all the parm loads anyway, so we should rarely hit this4440// case.4441}4442}4443else4444{4445for (int i = 0; i < node->getNumChildren(); i++)4446numNewRegLoads += self()->changeParmLoadsToRegLoads(node->getChild(i), regLoads, globalRegsWithRegLoad, killedParms, visitCount);4447}44484449return numNewRegLoads;4450}445144524453void4454J9::CodeGenerator::setUpForInstructionSelection()4455{4456self()->comp()->incVisitCount();44574458// prepareNodeForInstructionSelection is called during a separate walk of the treetops because4459// the _register and _label fields are unioned members of a node. prepareNodeForInstructionSelection4460// zeros the _register field while the second for loop sets label fields on destination nodes.4461//4462TR::TreeTop * tt=NULL, *prev = NULL;44634464if (self()->comp()->getOption(TR_EnableOSR))4465{4466TR::Block *block;4467for (tt = self()->comp()->getStartTree(); tt; tt = tt->getNextTreeTop())4468{4469if (tt->getNode()->getOpCodeValue() == TR::BBStart)4470{4471block = tt->getNode()->getBlock();4472if (!block->isOSRCodeBlock())4473{4474tt = block->getExit();4475continue;4476}4477}4478self()->eliminateLoadsOfLocalsThatAreNotStored(tt->getNode(), -1);4479}44804481self()->comp()->incVisitCount();4482}44834484for (tt = self()->comp()->getStartTree(); tt; tt = tt->getNextTreeTop())4485{4486self()->prepareNodeForInstructionSelection(tt->getNode());4487}44884489bool doRefinedAliasing = self()->enableRefinedAliasSets();44904491if (doRefinedAliasing)4492{4493_refinedAliasWalkCollector.methodInfo = TR_PersistentMethodInfo::get(self()->comp());4494_refinedAliasWalkCollector.killsEverything = !_refinedAliasWalkCollector.methodInfo;4495_refinedAliasWalkCollector.killsAddressStatics = false;4496_refinedAliasWalkCollector.killsIntStatics = false;4497_refinedAliasWalkCollector.killsNonIntPrimitiveStatics = false;4498_refinedAliasWalkCollector.killsAddressFields = false;4499_refinedAliasWalkCollector.killsIntFields = false;4500_refinedAliasWalkCollector.killsNonIntPrimitiveFields = false;4501_refinedAliasWalkCollector.killsAddressArrayShadows = false;4502_refinedAliasWalkCollector.killsIntArrayShadows = false;4503_refinedAliasWalkCollector.killsNonIntPrimitiveArrayShadows = false;4504}45054506for (tt = self()->comp()->getStartTree(); tt; prev=tt, tt = tt->getNextTreeTop())4507{4508TR::Node * node = tt->getNode();45094510if ((node->getOpCodeValue() == TR::treetop) ||4511node->getOpCode().isAnchor() ||4512node->getOpCode().isCheck())4513{4514node = node->getFirstChild();4515if (node->getOpCode().isResolveCheck() && doRefinedAliasing)4516{4517_refinedAliasWalkCollector.killsEverything = true;4518}4519}45204521TR::ILOpCode & opcode = node->getOpCode();45224523if (opcode.getOpCodeValue() == TR::BBStart)4524{4525self()->setCurrentBlock(node->getBlock());4526}4527else if (opcode.isLoadVarOrStore())4528{4529TR::Symbol * sym = node->getSymbol();4530TR::AutomaticSymbol *local = sym->getAutoSymbol();4531if (local)4532{4533local->incReferenceCount();4534}4535else if (doRefinedAliasing && !_refinedAliasWalkCollector.killsEverything)4536{4537if (sym->getStaticSymbol())4538{4539if (sym->getType().isAddress()) _refinedAliasWalkCollector.killsAddressStatics = true;4540else if (sym->getType().isInt32()) _refinedAliasWalkCollector.killsIntStatics = true;4541else _refinedAliasWalkCollector.killsNonIntPrimitiveStatics = true;4542}4543else if (sym->isArrayShadowSymbol())4544{4545if (sym->getType().isAddress()) _refinedAliasWalkCollector.killsAddressArrayShadows = true;4546else if (sym->getType().isInt32()) _refinedAliasWalkCollector.killsIntArrayShadows = true;4547else _refinedAliasWalkCollector.killsNonIntPrimitiveArrayShadows = true;4548}4549else if (sym->getShadowSymbol())4550{4551if (sym->getType().isAddress()) _refinedAliasWalkCollector.killsAddressFields = true;4552else if (sym->getType().isInt32()) _refinedAliasWalkCollector.killsIntFields = true;4553else _refinedAliasWalkCollector.killsNonIntPrimitiveFields = true;4554}4555}4556}4557else if (opcode.isBranch())4558{4559if (node->getBranchDestination()->getNode()->getLabel() == NULL)4560{4561// need to get the label type from the target block for RAS4562TR::LabelSymbol * label =4563TR::LabelSymbol::create(self()->trHeapMemory(),self(),node->getBranchDestination()->getNode()->getBlock());45644565node->getBranchDestination()->getNode()->setLabel(label);45664567}4568}4569else if (opcode.isJumpWithMultipleTargets() && !opcode.isSwitch())4570{4571for (auto e = self()->getCurrentBlock()->getSuccessors().begin(); e != self()->getCurrentBlock()->getSuccessors().end(); ++e)4572{4573if (toBlock((*e)->getTo())->getEntry()!=NULL &&4574toBlock((*e)->getTo())->getEntry()->getNode()->getLabel() == NULL)4575{4576TR::LabelSymbol * label = generateLabelSymbol(self());4577toBlock((*e)->getTo())->getEntry()->getNode()->setLabel(label);4578}4579}4580}4581else if (opcode.isSwitch())4582{4583uint16_t upperBound = node->getCaseIndexUpperBound();4584for (int i = 1; i < upperBound; ++i)4585{4586if (node->getChild(i)->getBranchDestination()->getNode()->getLabel() == NULL)4587{4588TR::LabelSymbol *label = generateLabelSymbol(self());4589node->getChild(i)->getBranchDestination()->getNode()->setLabel(label);45904591}4592}4593}4594else if (opcode.isCall() || opcode.getOpCodeValue() == TR::arraycopy)4595{4596self()->setUpStackSizeForCallNode(node);45974598if (doRefinedAliasing)4599{4600TR::ResolvedMethodSymbol * callSymbol = node->getSymbol()->getResolvedMethodSymbol();4601TR_PersistentMethodInfo * callInfo;4602if (!_refinedAliasWalkCollector.killsEverything && !opcode.isCallIndirect() && callSymbol &&4603(callInfo = TR_PersistentMethodInfo::get(callSymbol->getResolvedMethod())) &&4604callInfo->hasRefinedAliasSets())4605{4606if (!callInfo->doesntKillAddressStatics()) _refinedAliasWalkCollector.killsAddressStatics = true;4607if (!callInfo->doesntKillIntStatics()) _refinedAliasWalkCollector.killsIntStatics = true;4608if (!callInfo->doesntKillNonIntPrimitiveStatics()) _refinedAliasWalkCollector.killsNonIntPrimitiveStatics = true;4609if (!callInfo->doesntKillAddressFields()) _refinedAliasWalkCollector.killsAddressFields = true;4610if (!callInfo->doesntKillIntFields()) _refinedAliasWalkCollector.killsIntFields = true;4611if (!callInfo->doesntKillNonIntPrimitiveFields()) _refinedAliasWalkCollector.killsNonIntPrimitiveFields = true;4612if (!callInfo->doesntKillAddressArrayShadows()) _refinedAliasWalkCollector.killsAddressArrayShadows = true;4613if (!callInfo->doesntKillIntArrayShadows()) _refinedAliasWalkCollector.killsIntArrayShadows = true;4614if (!callInfo->doesntKillNonIntPrimitiveArrayShadows()) _refinedAliasWalkCollector.killsNonIntPrimitiveArrayShadows = true;4615}4616else4617{4618_refinedAliasWalkCollector.killsEverything = true;4619}4620}46214622}4623else if (opcode.getOpCodeValue() == TR::monent)4624{4625_refinedAliasWalkCollector.killsEverything = true;4626}4627}46284629if (doRefinedAliasing && !_refinedAliasWalkCollector.killsEverything)4630{4631TR_PersistentMethodInfo *methodInfo = _refinedAliasWalkCollector.methodInfo;46324633methodInfo->setDoesntKillEverything(true);4634if (!_refinedAliasWalkCollector.killsAddressStatics) methodInfo->setDoesntKillAddressStatics(true);4635if (!_refinedAliasWalkCollector.killsIntStatics) methodInfo->setDoesntKillIntStatics(true);4636if (!_refinedAliasWalkCollector.killsNonIntPrimitiveStatics) methodInfo->setDoesntKillNonIntPrimitiveStatics(true);4637if (!_refinedAliasWalkCollector.killsAddressFields) methodInfo->setDoesntKillAddressFields(true);4638if (!_refinedAliasWalkCollector.killsIntFields) methodInfo->setDoesntKillIntFields(true);4639if (!_refinedAliasWalkCollector.killsNonIntPrimitiveFields) methodInfo->setDoesntKillNonIntPrimitiveFields(true);4640if (!_refinedAliasWalkCollector.killsAddressArrayShadows) methodInfo->setDoesntKillAddressArrayShadows(true);4641if (!_refinedAliasWalkCollector.killsIntArrayShadows) methodInfo->setDoesntKillIntArrayShadows(true);4642if (!_refinedAliasWalkCollector.killsNonIntPrimitiveArrayShadows) methodInfo->setDoesntKillNonIntPrimitiveArrayShadows(true);4643}46444645if (self()->comp()->target().cpu.isX86() && self()->getInlinedGetCurrentThreadMethod())4646{4647TR::RealRegister *ebpReal = self()->getRealVMThreadRegister();46484649if (ebpReal)4650{4651ebpReal->setState(TR::RealRegister::Locked);4652ebpReal->setAssignedRegister(ebpReal->getRegister());4653}4654}4655}46564657bool4658J9::CodeGenerator::wantToPatchClassPointer(TR::Compilation *comp,4659const TR_OpaqueClassBlock *allegedClassPointer,4660const uint8_t *inCodeAt)4661{4662return TR::CodeGenerator::wantToPatchClassPointer(comp, allegedClassPointer, "in code at", inCodeAt);4663}46644665bool4666J9::CodeGenerator::wantToPatchClassPointer(const TR_OpaqueClassBlock *allegedClassPointer, const uint8_t *inCodeAt)4667{4668return TR::CodeGenerator::wantToPatchClassPointer(self()->comp(), allegedClassPointer, inCodeAt);4669}46704671bool4672J9::CodeGenerator::wantToPatchClassPointer(const TR_OpaqueClassBlock *allegedClassPointer, const TR::Node *forNode)4673{4674return TR::CodeGenerator::wantToPatchClassPointer(self()->comp(), allegedClassPointer, "for node", forNode);4675}46764677bool4678J9::CodeGenerator::supportsJitMethodEntryAlignment()4679{4680return self()->fej9()->supportsJitMethodEntryAlignment();4681}46824683bool4684J9::CodeGenerator::mustGenerateSwitchToInterpreterPrePrologue()4685{4686TR::Compilation *comp = self()->comp();46874688return comp->usesPreexistence() ||4689comp->getOption(TR_EnableHCR) ||4690!comp->fej9()->isAsyncCompilation() ||4691comp->getOption(TR_FullSpeedDebug);4692}46934694extern void VMgenerateCatchBlockBBStartPrologue(TR::Node *node, TR::Instruction *fenceInstruction, TR::CodeGenerator *cg);46954696void4697J9::CodeGenerator::generateCatchBlockBBStartPrologue(4698TR::Node *node,4699TR::Instruction *fenceInstruction)4700{4701if (self()->comp()->fej9vm()->getReportByteCodeInfoAtCatchBlock())4702{4703// Note we should not use `fenceInstruction` here because it is not the first instruction in this BB. The first4704// instruction is a label that incoming branches will target. We will use this label (first instruction in the4705// block) in `createMethodMetaData` to populate a list of non-mergeable GC maps so as to ensure the GC map at the4706// catch block entry is always present if requested.4707node->getBlock()->getFirstInstruction()->setNeedsGCMap();4708}47094710VMgenerateCatchBlockBBStartPrologue(node, fenceInstruction, self());4711}47124713void4714J9::CodeGenerator::registerAssumptions()4715{4716for(auto it = self()->getJNICallSites().begin();4717it != self()->getJNICallSites().end(); ++it)4718{4719TR_OpaqueMethodBlock *method = (*it)->getKey()->getPersistentIdentifier();4720TR::Instruction *i = (*it)->getValue();4721#ifdef J9VM_OPT_JITSERVER4722if (self()->comp()->isOutOfProcessCompilation())4723{4724// For JITServer we need to build a list of assumptions that will be sent to client at end of compilation4725intptr_t offset = i->getBinaryEncoding() - self()->getBinaryBufferStart();4726SerializedRuntimeAssumption* sar =4727new (self()->trHeapMemory()) SerializedRuntimeAssumption(RuntimeAssumptionOnRegisterNative, (uintptr_t)method, offset);4728self()->comp()->getSerializedRuntimeAssumptions().push_front(sar);4729}4730else4731#endif // J9VM_OPT_JITSERVER4732{4733TR_PatchJNICallSite::make(self()->fe(), self()->trPersistentMemory(), (uintptr_t) method, i->getBinaryEncoding(), self()->comp()->getMetadataAssumptionList());4734}4735}4736}47374738void4739J9::CodeGenerator::jitAddPicToPatchOnClassUnload(void *classPointer, void *addressToBePatched)4740{4741#ifdef J9VM_OPT_JITSERVER4742if (self()->comp()->isOutOfProcessCompilation())4743{4744intptr_t offset = (uint8_t*)addressToBePatched - self()->getBinaryBufferStart();4745SerializedRuntimeAssumption* sar =4746new (self()->trHeapMemory()) SerializedRuntimeAssumption(RuntimeAssumptionOnClassUnload, (uintptr_t)classPointer, offset, sizeof(uintptr_t));4747self()->comp()->getSerializedRuntimeAssumptions().push_front(sar);4748}4749else4750#endif // J9VM_OPT_JITSERVER4751{4752createClassUnloadPicSite(classPointer, addressToBePatched, sizeof(uintptr_t), self()->comp()->getMetadataAssumptionList());4753self()->comp()->setHasClassUnloadAssumptions();4754}4755}47564757void4758J9::CodeGenerator::jitAdd32BitPicToPatchOnClassUnload(void *classPointer, void *addressToBePatched)4759{4760#ifdef J9VM_OPT_JITSERVER4761if (self()->comp()->isOutOfProcessCompilation())4762{4763intptr_t offset = (uint8_t*)addressToBePatched - self()->getBinaryBufferStart();4764SerializedRuntimeAssumption* sar =4765new (self()->trHeapMemory()) SerializedRuntimeAssumption(RuntimeAssumptionOnClassUnload, (uintptr_t)classPointer, offset, 4);4766self()->comp()->getSerializedRuntimeAssumptions().push_front(sar);4767}4768else4769#endif // J9VM_OPT_JITSERVER4770{4771createClassUnloadPicSite(classPointer, addressToBePatched,4, self()->comp()->getMetadataAssumptionList());4772self()->comp()->setHasClassUnloadAssumptions();4773}4774}47754776void4777J9::CodeGenerator::jitAddPicToPatchOnClassRedefinition(void *classPointer, void *addressToBePatched, bool unresolved)4778{4779if (!self()->comp()->compileRelocatableCode())4780{4781#ifdef J9VM_OPT_JITSERVER4782if (self()->comp()->isOutOfProcessCompilation())4783{4784TR_RuntimeAssumptionKind kind = unresolved ? RuntimeAssumptionOnClassRedefinitionUPIC : RuntimeAssumptionOnClassRedefinitionPIC;4785uintptr_t key = unresolved ? (uintptr_t)-1 : (uintptr_t)classPointer;4786intptr_t offset = (uint8_t*)addressToBePatched - self()->getBinaryBufferStart();4787SerializedRuntimeAssumption* sar =4788new (self()->trHeapMemory()) SerializedRuntimeAssumption(kind, key, offset, sizeof(uintptr_t));4789self()->comp()->getSerializedRuntimeAssumptions().push_front(sar);4790}4791else4792#endif // J9VM_OPT_JITSERVER4793{4794createClassRedefinitionPicSite(unresolved? (void*)-1 : classPointer, addressToBePatched, sizeof(uintptr_t), unresolved, self()->comp()->getMetadataAssumptionList());4795self()->comp()->setHasClassRedefinitionAssumptions();4796}4797}4798}47994800void4801J9::CodeGenerator::jitAdd32BitPicToPatchOnClassRedefinition(void *classPointer, void *addressToBePatched, bool unresolved)4802{4803if (!self()->comp()->compileRelocatableCode())4804{4805#ifdef J9VM_OPT_JITSERVER4806if (self()->comp()->isOutOfProcessCompilation())4807{4808TR_RuntimeAssumptionKind kind = unresolved ? RuntimeAssumptionOnClassRedefinitionUPIC : RuntimeAssumptionOnClassRedefinitionPIC;4809uintptr_t key = unresolved ? (uintptr_t)-1 : (uintptr_t)classPointer;4810intptr_t offset = (uint8_t*)addressToBePatched - self()->getBinaryBufferStart();4811SerializedRuntimeAssumption* sar =4812new (self()->trHeapMemory()) SerializedRuntimeAssumption(kind, key, offset, 4);4813self()->comp()->getSerializedRuntimeAssumptions().push_front(sar);4814}4815else4816#endif // J9VM_OPT_JITSERVER4817{4818createClassRedefinitionPicSite(unresolved? (void*)-1 : classPointer, addressToBePatched, 4, unresolved, self()->comp()->getMetadataAssumptionList());4819self()->comp()->setHasClassRedefinitionAssumptions();4820}4821}4822}482348244825void4826J9::CodeGenerator::createHWPRecords()4827{4828if (self()->comp()->getPersistentInfo()->isRuntimeInstrumentationEnabled() &&4829self()->comp()->getOption(TR_EnableHardwareProfileIndirectDispatch))4830{4831self()->comp()->fej9()->createHWProfilerRecords(self()->comp());4832}4833}483448354836TR::Linkage *4837J9::CodeGenerator::createLinkageForCompilation()4838{4839return self()->getLinkage(self()->comp()->getJittedMethodSymbol()->getLinkageConvention());4840}484148424843TR::TreeTop *4844J9::CodeGenerator::lowerTree(TR::Node *root, TR::TreeTop *treeTop)4845{4846return self()->fej9()->lowerTree(self()->comp(), root, treeTop);4847}484848494850bool4851J9::CodeGenerator::needClassAndMethodPointerRelocations()4852{4853return self()->fej9()->needClassAndMethodPointerRelocations();4854}48554856bool4857J9::CodeGenerator::needRelocationsForLookupEvaluationData()4858{4859return self()->fej9()->needRelocationsForLookupEvaluationData();4860}48614862bool4863J9::CodeGenerator::needRelocationsForStatics()4864{4865return self()->fej9()->needRelocationsForStatics();4866}48674868bool4869J9::CodeGenerator::needRelocationsForCurrentMethodPC()4870{4871return self()->fej9()->needRelocationsForCurrentMethodPC();4872}48734874bool4875J9::CodeGenerator::needRelocationsForHelpers()4876{4877return self()->fej9()->needRelocationsForHelpers();4878}48794880#if defined(J9VM_OPT_JITSERVER)4881bool4882J9::CodeGenerator::needRelocationsForBodyInfoData()4883{4884return self()->fej9()->needRelocationsForBodyInfoData();4885}48864887bool4888J9::CodeGenerator::needRelocationsForPersistentInfoData()4889{4890return self()->fej9()->needRelocationsForPersistentInfoData();4891}4892#endif /* defined(J9VM_OPT_JITSERVER) */489348944895bool4896J9::CodeGenerator::isMethodInAtomicLongGroup(TR::RecognizedMethod rm)4897{4898switch (rm)4899{4900case TR::java_util_concurrent_atomic_AtomicLong_addAndGet:4901case TR::java_util_concurrent_atomic_AtomicLongArray_addAndGet:4902case TR::java_util_concurrent_atomic_AtomicLongArray_decrementAndGet:4903case TR::java_util_concurrent_atomic_AtomicLongArray_getAndAdd:4904case TR::java_util_concurrent_atomic_AtomicLongArray_getAndDecrement:4905case TR::java_util_concurrent_atomic_AtomicLongArray_getAndIncrement:4906case TR::java_util_concurrent_atomic_AtomicLongArray_getAndSet:4907case TR::java_util_concurrent_atomic_AtomicLongArray_incrementAndGet:4908case TR::java_util_concurrent_atomic_AtomicLong_decrementAndGet:4909case TR::java_util_concurrent_atomic_AtomicLong_getAndAdd:4910case TR::java_util_concurrent_atomic_AtomicLong_getAndDecrement:4911case TR::java_util_concurrent_atomic_AtomicLong_getAndIncrement:4912case TR::java_util_concurrent_atomic_AtomicLong_getAndSet:4913case TR::java_util_concurrent_atomic_AtomicLong_incrementAndGet:4914return true;49154916default:4917return false;4918}4919}492049214922void4923J9::CodeGenerator::trimCodeMemoryToActualSize()4924{4925uint8_t *bufferStart = self()->getBinaryBufferStart();4926size_t actualCodeLengthInBytes = self()->getCodeEnd() - bufferStart;49274928TR::VMAccessCriticalSection trimCodeMemoryAllocation(self()->comp());4929self()->getCodeCache()->trimCodeMemoryAllocation(bufferStart, actualCodeLengthInBytes);4930}493149324933void4934J9::CodeGenerator::reserveCodeCache()4935{4936self()->setCodeCache(self()->fej9()->getDesignatedCodeCache(self()->comp()));4937if (!self()->getCodeCache()) // Cannot reserve a cache; all are used4938{4939// We may reach this point if all code caches have been used up4940// If some code caches have some space but cannot be used because they are reserved4941// we will throw an exception in the call to getDesignatedCodeCache49424943if (self()->comp()->compileRelocatableCode())4944{4945self()->comp()->failCompilation<TR::RecoverableCodeCacheError>("Cannot reserve code cache");4946}49474948self()->comp()->failCompilation<TR::CodeCacheError>("Cannot reserve code cache");4949}4950}495149524953uint8_t *4954J9::CodeGenerator::allocateCodeMemoryInner(4955uint32_t warmCodeSizeInBytes,4956uint32_t coldCodeSizeInBytes,4957uint8_t **coldCode,4958bool isMethodHeaderNeeded)4959{4960TR::Compilation *comp = self()->comp();49614962TR::CodeCache * codeCache = self()->getCodeCache();4963if (!codeCache)4964{4965if (comp->compileRelocatableCode())4966{4967comp->failCompilation<TR::RecoverableCodeCacheError>("Failed to get current code cache");4968}49694970comp->failCompilation<TR::CodeCacheError>("Failed to get current code cache");4971}49724973TR_ASSERT(codeCache->isReserved(), "Code cache should have been reserved.");49744975bool hadClassUnloadMonitor;4976bool hadVMAccess = self()->fej9()->releaseClassUnloadMonitorAndAcquireVMaccessIfNeeded(comp, &hadClassUnloadMonitor);49774978uint8_t *warmCode = TR::CodeCacheManager::instance()->allocateCodeMemory(4979warmCodeSizeInBytes,4980coldCodeSizeInBytes,4981&codeCache,4982coldCode,4983self()->fej9()->needsContiguousCodeAndDataCacheAllocation(),4984isMethodHeaderNeeded);49854986self()->fej9()->acquireClassUnloadMonitorAndReleaseVMAccessIfNeeded(comp, hadVMAccess, hadClassUnloadMonitor);49874988if (codeCache != self()->getCodeCache())4989{4990TR_ASSERT(!codeCache || codeCache->isReserved(), "Substitute code cache isn't marked as reserved");4991comp->setRelocatableMethodCodeStart(warmCode);4992self()->switchCodeCacheTo(codeCache);4993}49944995if (!warmCode)4996{4997if (jitConfig->runtimeFlags & J9JIT_CODE_CACHE_FULL)4998{4999comp->failCompilation<TR::CodeCacheError>("Failed to allocate code memory");5000}50015002comp->failCompilation<TR::RecoverableCodeCacheError>("Failed to allocate code memory");5003}50045005TR_ASSERT_FATAL( !((warmCodeSizeInBytes && !warmCode) || (coldCodeSizeInBytes && !coldCode)), "Allocation failed but didn't throw an exception");50065007return warmCode;5008}500950105011TR::Node *5012J9::CodeGenerator::generatePoisonNode(TR::Block *currentBlock, TR::SymbolReference *liveAutoSymRef)5013{5014bool poisoned = true;5015TR::Node *storeNode = NULL;50165017if (liveAutoSymRef->getSymbol()->getType().isAddress())5018storeNode = TR::Node::createStore(liveAutoSymRef, TR::Node::aconst(currentBlock->getEntry()->getNode(), 0x0));5019else if (liveAutoSymRef->getSymbol()->getType().isInt64())5020storeNode = TR::Node::createStore(liveAutoSymRef, TR::Node::lconst(currentBlock->getEntry()->getNode(), 0xc1aed1e5));5021else if (liveAutoSymRef->getSymbol()->getType().isInt32())5022storeNode = TR::Node::createStore(liveAutoSymRef, TR::Node::iconst(currentBlock->getEntry()->getNode(), 0xc1aed1e5));5023else5024poisoned = false;50255026TR::Compilation *comp = self()->comp();5027if (comp->getOption(TR_TraceCG) && comp->getOption(TR_PoisonDeadSlots))5028{5029if (poisoned)5030{5031traceMsg(comp, "POISON DEAD SLOTS --- Live local %d from parent block %d going dead .... poisoning slot with node 0x%x .\n", liveAutoSymRef->getReferenceNumber() , currentBlock->getNumber(), storeNode);5032}5033else5034{5035traceMsg(comp, "POISON DEAD SLOTS --- Live local %d of unsupported type from parent block %d going dead .... poisoning skipped.\n", liveAutoSymRef->getReferenceNumber() , currentBlock->getNumber());5036}5037}50385039return storeNode;5040}50415042uint32_t5043J9::CodeGenerator::initializeLinkageInfo(void *linkageInfoPtr)5044{5045J9::PrivateLinkage::LinkageInfo *linkageInfo = (J9::PrivateLinkage::LinkageInfo *)linkageInfoPtr;50465047TR::Recompilation * recomp = self()->comp()->getRecompilationInfo();5048if (recomp && recomp->couldBeCompiledAgain())5049{5050if (recomp->useSampling())5051linkageInfo->setSamplingMethodBody();5052else5053linkageInfo->setCountingMethodBody();5054}50555056linkageInfo->setReservedWord((self()->getBinaryBufferCursor() - self()->getCodeStart()));5057linkageInfo->setReturnInfo(self()->comp()->getReturnInfo());50585059return linkageInfo->getWord();5060}50615062// I need to preserve the type information for monitorenter/exit through5063// code generation, but the secondChild is being used for other monitor5064// optimizations and I can't find anywhere to stick it on the TR::Node.5065// Creating the node with more children doesn't seem to help either.5066//5067void5068J9::CodeGenerator::addMonClass(TR::Node* monNode, TR_OpaqueClassBlock* clazz)5069{5070_monitorMapping[monNode->getGlobalIndex()] = clazz;5071}50725073TR_OpaqueClassBlock *5074J9::CodeGenerator::getMonClass(TR::Node* monNode)5075{5076auto it = _monitorMapping.find(monNode->getGlobalIndex());5077return it != _monitorMapping.end() ? it->second : NULL;5078}50795080TR_YesNoMaybe5081J9::CodeGenerator::isMonitorValueBasedOrValueType(TR::Node* monNode)5082{5083if (TR::Compiler->om.areValueTypesEnabled() || TR::Compiler->om.areValueBasedMonitorChecksEnabled())5084{5085TR_OpaqueClassBlock *clazz = self()->getMonClass(monNode);50865087if (!clazz)5088return TR_maybe;50895090//java.lang.Object class is only set when monitor is java.lang.Object but not its subclass5091if (clazz == self()->comp()->getObjectClassPointer())5092return TR_no;50935094// J9ClassIsValueType is mutually exclusive to J9ClassHasIdentity5095if (!TR::Compiler->om.areValueBasedMonitorChecksEnabled() && TR::Compiler->cls.classHasIdentity(clazz))5096return TR_no;50975098if (!TR::Compiler->cls.isConcreteClass(self()->comp(), clazz))5099return TR_maybe;51005101if (TR::Compiler->cls.isValueBasedOrValueTypeClass(clazz))5102return TR_yes;5103}5104return TR_no;5105}51065107bool5108J9::CodeGenerator::isProfiledClassAndCallSiteCompatible(TR_OpaqueClassBlock *profiledClass, TR_OpaqueClassBlock *callSiteMethodClass)5109{5110/* Check if the profiled class should be allowed to be used for a guarded devirtualization of a particular call site.5111A call site can end up with an incompatible profiled class in two ways.51121) The inlining context of this compile might allow for type refinement of a callSite class. If this the profiledClass5113is from a call chain that differs to the current compile inlining, then it's possible that the profiledClass is5114incompatible with the refined type at the callSite in this compile. Historically the JIT would go as far as5115converting an invokeInterface to an invokeVirtual based on this type refinement, which would result in a crash if the5116profiledClass was incompatible. Due to correctness issues, interface->virtual conversions was removed, but we can5117still refine the class type for an invokevirtual resulting in the same profiledClass incompatibility which can result5118in an ineffectual guarded devirtualization but not a crash.51192) With shared classes, a J9ROMClass can be shared among classes of different class-loaders. Since profiling data is keyed5120by the bytecode address, the profiled data from all classes sharing the same J9ROMClass will be merged. Because of this,5121a profiled class can be derived from the profiling of a method in a class that is incompatible with the call site.5122So how to do we ensure compatibility?5123In most cases an isInstanceOf() check is enough to ensure that the profiled class is compatible, but this can fail when the5124callSiteMethodClass is an Interface. This happens when the call site is calling a method of an Abstract class which is5125not implemented by the class but is required by an Interface that the Abstract class implements. In such a case the Abstract5126class's VFT entries for all unimplemented methods will point at the Interface methods. By default the JIT uses the class of5127the VFT entry method to populate the callSiteMethodClass. When the Interface is defined in a parent class-loader, it's5128possible for an incompatible profiled class to implement the same parent class-loader Interface and as a result pass the5129isInstanceOf() test. Therefore we can only use the isInstanceOf() check when the callSiteMethodClass is not an Interface.51305131*/5132if (!fej9()->isInterfaceClass(callSiteMethodClass) && fej9()->isInstanceOf(profiledClass, callSiteMethodClass, true, true) == TR_yes)5133{5134return true;5135}5136return false;5137}513851395140