TR::Node *TR_OutlinedInstructions::createOutlinedCallNode(TR::Node *callNode, TR::ILOpCodes callOp) { int32_t i; TR::Node *child; //We pass true for getSymbolReference because TR::Node *newCallNode = TR::Node::createWithSymRef(callNode, callOp, callNode->getNumChildren(), callNode->getSymbolReference()); newCallNode->setReferenceCount(1); for (i=0; i<callNode->getNumChildren(); i++) { child = callNode->getChild(i); if (child->getRegister() != NULL) { // Child has already been evaluated outside this tree. // newCallNode->setAndIncChild(i, child); } else if (child->getOpCode().isLoadConst()) { // Copy unevaluated constant nodes. // child = TR::Node::copy(child); child->setReferenceCount(1); newCallNode->setChild(i, child); } else { if ((child->getOpCodeValue() == TR::loadaddr) && /*(callNode->getOpCodeValue() == TR::instanceof || callNode->getOpCodeValue() == TR::checkcast || callNode->getOpCodeValue() == TR::checkcastAndNULLCHK || callNode->getOpCodeValue() == TR::New || callNode->getOpCodeValue() == TR::anewarray) &&*/ (child->getSymbolReference()->getSymbol()) && (child->getSymbolReference()->getSymbol()->getStaticSymbol())) { child = TR::Node::copy(child); child->setReferenceCount(1); newCallNode->setChild(i, child); } else { // Be very conservative at this point, even though it is possible to make it less so. For example, this will catch // the case of an unevaluated argument not persisting outside of the outlined region even though one of its subtrees will. // (void)_cg->evaluate(child); // Do not decrement the reference count here. It will be decremented when the call node is evaluated // again in the helper instruction stream. // newCallNode->setAndIncChild(i, child); } } } if(callNode->isPreparedForDirectJNI()) { newCallNode->setPreparedForDirectJNI(); } return newCallNode; }
// resolved casts that are not to abstract, interface, or array need a super test bool OMR::TreeEvaluator::instanceOfOrCheckCastNeedSuperTest(TR::Node * node, TR::CodeGenerator *cg) { TR::Node *castClassNode = node->getSecondChild(); TR::MethodSymbol *helperSym = node->getSymbol()->castToMethodSymbol(); TR::SymbolReference *castClassSymRef = castClassNode->getSymbolReference(); if (!TR::TreeEvaluator::isStaticClassSymRef(castClassSymRef)) { // We could theoretically do a super test on something with no sym, but it would require significant // changes to platform code. The benefit is little at this point (shows up from reference arraycopy reductions) if (cg->supportsInliningOfIsInstance() && node->getOpCodeValue() == TR::instanceof && node->getSecondChild()->getOpCodeValue() != TR::loadaddr) return true; else return false; } TR::StaticSymbol *castClassSym = castClassSymRef->getSymbol()->getStaticSymbol(); if (castClassSymRef->isUnresolved()) { return false; } else { TR_OpaqueClassBlock * clazz; // If the class is a regular class (i.e., not an interface nor an array) and // not known to be a final class, an inline superclass test can be generated. // If the helper does not preserve all the registers there will not be // enough registers to do the superclass test inline. // Also, don't generate the superclass test if optimizing for space. // if (castClassSym && (clazz = (TR_OpaqueClassBlock *) castClassSym->getStaticAddress()) && !TR::Compiler->cls.isClassArray(cg->comp(), clazz) && !TR::Compiler->cls.isInterfaceClass(cg->comp(), clazz) && !TR::Compiler->cls.isClassFinal(cg->comp(), clazz) && helperSym->preservesAllRegisters() && !cg->comp()->getOption(TR_OptimizeForSpace)) return true; } return false; }
// unresolved casts or casts to things other than abstract or interface benefit from // an equality test bool OMR::TreeEvaluator::instanceOfOrCheckCastNeedEqualityTest(TR::Node * node, TR::CodeGenerator *cg) { TR::Node *castClassNode = node->getSecondChild(); TR::SymbolReference *castClassSymRef = castClassNode->getSymbolReference(); if (!TR::TreeEvaluator::isStaticClassSymRef(castClassSymRef)) { return true; } TR::StaticSymbol *castClassSym = castClassSymRef->getSymbol()->getStaticSymbol(); if (castClassSymRef->isUnresolved()) { return false; } else { TR_OpaqueClassBlock * clazz; if (castClassSym && (clazz = (TR_OpaqueClassBlock *) castClassSym->getStaticAddress()) && !TR::Compiler->cls.isInterfaceClass(cg->comp(), clazz) && ( !TR::Compiler->cls.isAbstractClass(cg->comp(), clazz) // here be dragons // int.class, char.class, etc are final & abstract // usually instanceOf calls on these classes are ripped out by the optimizer // but in some cases they can persist to codegen which without the following // case causes assertions because we opt out of calling the helper and doing // all inline tests. Really we could just jmp to the failed side, but to reduce // service risk we are going to do an equality test that we know will fail // NOTE final abstract is not enough - all array classes are final abstract // to prevent them being used with new and being extended... || (TR::Compiler->cls.isAbstractClass(cg->comp(), clazz) && TR::Compiler->cls.isClassFinal(cg->comp(), clazz) && TR::Compiler->cls.isPrimitiveClass(cg->comp(), clazz))) ) return true; } return false; }
int32_t TR_LocalAnalysisInfo::HashTable::hash(TR::Node *node) { // Hash on the opcode and value numbers of the children // uint32_t h, g; int32_t numChildren = node->getNumChildren(); h = (node->getOpCodeValue() << 4) + numChildren; g = 0; for (int32_t i = numChildren-1; i >= 0; i--) { TR::Node *child = node->getChild(i); h <<= 4; if (child->getOpCode().hasSymbolReference()) h += (int32_t)(intptrj_t)child->getSymbolReference()->getSymbol(); else h++; g = h & 0xF0000000; h ^= g >> 24; } return (h ^ g) % _numBuckets; }
bool TR_ExpressionsSimplification::tranformSummationReductionCandidate(TR::TreeTop *treeTop, LoopInfo *loopInfo, bool *isPreheaderBlockInvalid) { TR::Node *node = treeTop->getNode(); TR::Node *opNode = node->getFirstChild(); TR::Node *expNode = NULL; int32_t expChildNumber = 0; bool removeOnly = false; bool replaceWithNewNode = false; if (opNode->getOpCodeValue() == TR::iadd || opNode->getOpCodeValue() == TR::isub) { if (opNode->getSecondChild()->getOpCode().hasSymbolReference() && node->getSymbolReference() == opNode->getSecondChild()->getSymbolReference()) { expChildNumber = 0; expNode = opNode->getFirstChild(); } else { expChildNumber = 1; expNode = opNode->getSecondChild(); } expNode = iaddisubSimplifier(expNode, loopInfo); replaceWithNewNode = true; } else if (opNode->getOpCodeValue() == TR::ixor || opNode->getOpCodeValue() == TR::ineg) { expNode = ixorinegSimplifier(opNode, loopInfo, &removeOnly); } if (expNode) { if (trace()) comp()->getDebug()->print(comp()->getOutFile(), expNode, 0, true); TR::Block *entryBlock = _currentRegion->getEntryBlock(); TR::Block *preheaderBlock = findPredecessorBlock(entryBlock); if (!preheaderBlock) { if (trace()) traceMsg(comp(), "Fail to find a place to put the hoist code in\n"); *isPreheaderBlockInvalid = true; return true; } if (loopInfo->getNumIterations() > 0 || // make sure that the loop is going to be executed at least once _currentRegion->isCanonicalizedLoop()) // or that the loop is canonicalized, in which case the preheader is { // executed in its first iteration and is protected. if (performTransformation(comp(), "%sMove out loop-invariant node [%p] to block_%d\n", OPT_DETAILS, node, preheaderBlock->getNumber())) { if (!(removeOnly)) { TR::Node *newNode = node->duplicateTree(); if (replaceWithNewNode) newNode->getFirstChild()->setAndIncChild(expChildNumber, expNode); transformNode(newNode, preheaderBlock); } TR::TransformUtil::removeTree(comp(), treeTop); } } } return (expNode != NULL); }
int32_t TR::DeadTreesElimination::process(TR::TreeTop *startTree, TR::TreeTop *endTree) { TR::StackMemoryRegion stackRegion(*comp()->trMemory()); LongestPathMap longestPaths(std::less<TR::Node*>(), stackRegion); typedef TR::typed_allocator<CRAnchor, TR::Region&> CRAnchorAlloc; typedef TR::forward_list<CRAnchor, CRAnchorAlloc> CRAnchorList; CRAnchorList anchors(stackRegion); vcount_t visitCount = comp()->incOrResetVisitCount(); TR::TreeTop *treeTop; for (treeTop = startTree; (treeTop != endTree); treeTop = treeTop->getNextTreeTop()) treeTop->getNode()->initializeFutureUseCounts(visitCount); TR::Block *block = NULL; bool delayedRegStoresBeforeThisPass = _delayedRegStores; // Update visitCount as they are used in this optimization and need to be visitCount = comp()->incOrResetVisitCount(); for (TR::TreeTopIterator iter(startTree, comp()); iter != endTree; ++iter) { TR::Node *node = iter.currentTree()->getNode(); if (node->getOpCodeValue() == TR::BBStart) { block = node->getBlock(); if (!block->isExtensionOfPreviousBlock()) longestPaths.clear(); } int vcountLimit = MAX_VCOUNT - 3; if (comp()->getVisitCount() > vcountLimit) { dumpOptDetails(comp(), "%sVisit count %d exceeds limit %d; stopping\n", optDetailString(), comp()->getVisitCount(), vcountLimit); return 0; } // correct at all intermediate stages // if ((node->getOpCodeValue() != TR::treetop) && (!node->getOpCode().isAnchor() || (node->getFirstChild()->getReferenceCount() != 1)) && (!node->getOpCode().isStoreReg() || (node->getFirstChild()->getReferenceCount() != 1)) && (delayedRegStoresBeforeThisPass || (iter.currentTree() == block->getLastRealTreeTop()) || !node->getOpCode().isStoreReg() || (node->getVisitCount() == visitCount))) { if (node->getOpCode().isAnchor() && node->getFirstChild()->getOpCode().isLoadIndirect()) anchors.push_front(CRAnchor(iter.currentTree(), block)); TR::TransformUtil::recursivelySetNodeVisitCount(node, visitCount); continue; } if (node->getOpCode().isStoreReg()) _delayedRegStores = true; TR::Node *child = node->getFirstChild(); if (child->getOpCodeValue() == TR::PassThrough) { TR::Node *newChild = child->getFirstChild(); node->setAndIncChild(0, newChild); newChild->incFutureUseCount(); if (child->getReferenceCount() <= 1) optimizer()->prepareForNodeRemoval(child); child->recursivelyDecReferenceCount(); recursivelyDecFutureUseCount(child); child = newChild; } bool treeTopCanBeEliminated = false; // If the treetop child has been seen before then it must be anchored // somewhere above already; so we don't need the treetop to be anchoring // this node (as the computation is already done at the first reference to // the node). // if (visitCount == child->getVisitCount()) { treeTopCanBeEliminated = true; } else { TR::ILOpCode &childOpCode = child->getOpCode(); TR::ILOpCodes opCodeValue = childOpCode.getOpCodeValue(); bool seenConditionalBranch = false; bool callWithNoSideEffects = child->getOpCode().isCall() && child->getSymbolReference()->getSymbol()->isResolvedMethod() && child->getSymbolReference()->getSymbol()->castToResolvedMethodSymbol()->isSideEffectFree(); if (callWithNoSideEffects) { treeTopCanBeEliminated = true; } else if (!((childOpCode.isCall() && !callWithNoSideEffects) || childOpCode.isStore() || ((opCodeValue == TR::New || opCodeValue == TR::anewarray || opCodeValue == TR::newarray) && child->getReferenceCount() > 1) || opCodeValue == TR::multianewarray || opCodeValue == TR::MergeNew || opCodeValue == TR::checkcast || opCodeValue == TR::Prefetch || opCodeValue == TR::iu2l || ((childOpCode.isDiv() || childOpCode.isRem()) && child->getNumChildren() == 3))) { // Perform the rather complex check to see whether its safe // to disconnect the child node from the treetop // bool safeToReplaceNode = false; if (child->getReferenceCount() == 1) { safeToReplaceNode = true; #ifdef J9_PROJECT_SPECIFIC if (child->getOpCode().isPackedExponentiation()) { // pdexp has a possible message side effect in truncating or no significant digits left cases safeToReplaceNode = false; } #endif if (opCodeValue == TR::loadaddr) treeTopCanBeEliminated = true; } else if (!_cannotBeEliminated) { safeToReplaceNode = isSafeToReplaceNode( child, iter.currentTree(), &seenConditionalBranch, visitCount, comp(), &_targetTrees, _cannotBeEliminated, longestPaths); } if (safeToReplaceNode) { if (childOpCode.hasSymbolReference()) { TR::SymbolReference *symRef = child->getSymbolReference(); if (symRef->getSymbol()->isAuto() || symRef->getSymbol()->isParm()) treeTopCanBeEliminated = true; else { if (childOpCode.isLoad() || (opCodeValue == TR::loadaddr) || (opCodeValue == TR::instanceof) || (((opCodeValue == TR::New) || (opCodeValue == TR::anewarray || opCodeValue == TR::newarray)) && ///child->getFirstChild()->isNonNegative())) child->markedAllocationCanBeRemoved())) // opCodeValue == TR::multianewarray || // opCodeValue == TR::MergeNew) treeTopCanBeEliminated = true; } } else treeTopCanBeEliminated = true; } } // Fix for the case when a float to non-float conversion node swings // down past a branch on IA32; this would cause a FP value to be commoned // across a branch where there was none originally; this causes pblms // as a value is left on the stack. // if (treeTopCanBeEliminated && seenConditionalBranch) { if (!cg()->getSupportsJavaFloatSemantics()) { if (child->getOpCode().isConversion() || child->getOpCode().isBooleanCompare()) { if (child->getFirstChild()->getOpCode().isFloatingPoint() && !child->getOpCode().isFloatingPoint()) treeTopCanBeEliminated = false; } } } if (treeTopCanBeEliminated) { TR::NodeChecklist visited(comp()); bool containsFloatingPoint = false; for (int32_t i = 0; i < child->getNumChildren(); ++i) { // Anchor nodes with reference count > 1 // bool highGlobalIndex = false; if (fixUpTree(child->getChild(i), iter.currentTree(), visited, highGlobalIndex, self(), visitCount)) containsFloatingPoint = true; if (highGlobalIndex) { dumpOptDetails(comp(), "%sGlobal index limit exceeded; stopping\n", optDetailString()); return 0; } } if (seenConditionalBranch && containsFloatingPoint) { if (!cg()->getSupportsJavaFloatSemantics()) treeTopCanBeEliminated = false; } } } // Update visitCount as they are used in this optimization and need to be // correct at all intermediate stages // if (!treeTopCanBeEliminated) TR::TransformUtil::recursivelySetNodeVisitCount(node, visitCount); if (treeTopCanBeEliminated) { TR::TreeTop *prevTree = iter.currentTree()->getPrevTreeTop(); TR::TreeTop *nextTree = iter.currentTree()->getNextTreeTop(); if (!node->getOpCode().isStoreReg() || (node->getFirstChild()->getReferenceCount() == 1)) { // Actually going to remove the treetop now // if (performTransformation(comp(), "%sRemove tree : [" POINTER_PRINTF_FORMAT "] ([" POINTER_PRINTF_FORMAT "] = %s)\n", optDetailString(), node, node->getFirstChild(), node->getFirstChild()->getOpCode().getName())) { prevTree->join(nextTree); optimizer()->prepareForNodeRemoval(node); ///child->recursivelyDecReferenceCount(); node->recursivelyDecReferenceCount(); recursivelyDecFutureUseCount(child); iter.jumpTo(prevTree); if (child->getReferenceCount() == 1) requestOpt(OMR::treeSimplification, true, block); if (nextTree->getNode()->getOpCodeValue() == TR::Goto && prevTree->getNode()->getOpCodeValue() == TR::BBStart && !prevTree->getNode()->getBlock()->isExtensionOfPreviousBlock()) { requestOpt( OMR::redundantGotoElimination, prevTree->getNode()->getBlock()); } } } else { if (performTransformation(comp(), "%sMove tree : [" POINTER_PRINTF_FORMAT "]([" POINTER_PRINTF_FORMAT "] = %s) to end of block\n", optDetailString(), node, node->getFirstChild(), node->getFirstChild()->getOpCode().getName())) { prevTree->join(nextTree); node->setVisitCount(visitCount); TR::TreeTop *lastTree = findLastTreetop(block, prevTree); TR::TreeTop *prevLastTree = lastTree->getPrevTreeTop(); TR::TreeTop *cursorTreeTop = nextTree; while (cursorTreeTop != lastTree) { if (cursorTreeTop->getNode()->getOpCode().isStoreReg() && (cursorTreeTop->getNode()->getGlobalRegisterNumber() == iter.currentTree()->getNode()->getGlobalRegisterNumber())) { lastTree = cursorTreeTop; prevLastTree = lastTree->getPrevTreeTop(); break; } cursorTreeTop = cursorTreeTop->getNextTreeTop(); } if (lastTree->getNode()->getOpCodeValue() == TR::BBStart) { prevLastTree = lastTree; lastTree = block->getExit(); } TR::Node *lastNode = lastTree->getNode(); TR::Node *prevLastNode = prevLastTree->getNode(); if (lastNode->getOpCode().isIf() && !lastNode->getOpCode().isCompBranchOnly() && prevLastNode->getOpCode().isStoreReg() && ((prevLastNode->getFirstChild() == lastNode->getFirstChild()) || (prevLastNode->getFirstChild() == lastNode->getSecondChild()))) { lastTree = prevLastTree; prevLastTree = lastTree->getPrevTreeTop(); } prevLastTree->join(iter.currentTree()); iter.currentTree()->join(lastTree); iter.jumpTo(prevTree); requestOpt(OMR::treeSimplification, true, block); } } } } for (auto it = anchors.begin(); it != anchors.end(); ++it) { TR::Node *anchor = it->tree->getNode(); TR::Node *load = anchor->getChild(0); if (load->getReferenceCount() > 1) continue; // We can eliminate the indirect load immediately, but for the moment the // subtree providing the base object has to be anchored. TR::Node *heapBase = anchor->getChild(1); TR::Node::recreate(anchor, TR::treetop); anchor->setAndIncChild(0, load->getChild(0)); anchor->setChild(1, NULL); anchor->setNumChildren(1); if (!heapBase->getOpCode().isLoadConst()) { it->tree->insertAfter( TR::TreeTop::create( comp(), TR::Node::create(heapBase, TR::treetop, 1, heapBase))); } load->recursivelyDecReferenceCount(); heapBase->recursivelyDecReferenceCount(); // A later pass of dead trees can likely move (or even remove) the base // object expression. requestOpt(OMR::deadTreesElimination, true, it->block); } return 1; // actual cost }
void TR_S390BinaryAnalyser::genericAnalyser(TR::Node * root, TR::InstOpCode::Mnemonic regToRegOpCode, TR::InstOpCode::Mnemonic memToRegOpCode, TR::InstOpCode::Mnemonic copyOpCode) { TR::Node * firstChild; TR::Node * secondChild; firstChild = root->getFirstChild(); secondChild = root->getSecondChild(); TR::Register * firstRegister = firstChild->getRegister(); TR::Register * secondRegister = secondChild->getRegister(); TR::Compilation *comp = TR::comp(); TR::SymbolReference * firstReference = firstChild->getOpCode().hasSymbolReference() ? firstChild->getSymbolReference() : NULL; TR::SymbolReference * secondReference = secondChild->getOpCode().hasSymbolReference() ? secondChild->getSymbolReference() : NULL; setInputs(firstChild, firstRegister, secondChild, secondRegister, false, false, comp, (cg()->isAddressOfStaticSymRefWithLockedReg(firstReference) || cg()->isAddressOfPrivateStaticSymRefWithLockedReg(firstReference)), (cg()->isAddressOfStaticSymRefWithLockedReg(secondReference) || cg()->isAddressOfPrivateStaticSymRefWithLockedReg(secondReference))); /* * Check if SH or CH can be used to evaluate this integer subtract/compare node. * The second operand of SH/CH is a 16-bit number from memory. And using * these directly can save a load instruction. */ bool is16BitMemory2Operand = false; if (secondChild->getOpCodeValue() == TR::s2i && secondChild->getFirstChild()->getOpCodeValue() == TR::sloadi && secondChild->isSingleRefUnevaluated() && secondChild->getFirstChild()->isSingleRefUnevaluated()) { bool supported = true; if (memToRegOpCode == TR::InstOpCode::S) { memToRegOpCode = TR::InstOpCode::SH; } else if (memToRegOpCode == TR::InstOpCode::C) { memToRegOpCode = TR::InstOpCode::CH; } else { supported = false; } if (supported) { setMem2(); is16BitMemory2Operand = true; } } if (getEvalChild1()) { firstRegister = cg()->evaluate(firstChild); } if (getEvalChild2()) { secondRegister = cg()->evaluate(secondChild); } remapInputs(firstChild, firstRegister, secondChild, secondRegister); if (getCopyReg1()) { TR::Register * thirdReg; bool done = false; if (firstRegister->getKind() == TR_GPR64) { thirdReg = cg()->allocate64bitRegister(); } else if (firstRegister->getKind() == TR_VRF) { TR_ASSERT(false,"VRF: genericAnalyser unimplemented"); } else if (firstRegister->getKind() != TR_FPR && firstRegister->getKind() != TR_VRF) { thirdReg = cg()->allocateRegister(); } else { thirdReg = cg()->allocateRegister(TR_FPR); } if (cg()->getS390ProcessorInfo()->supportsArch(TR_S390ProcessorInfo::TR_z196)) { if (getBinaryReg3Reg2() || secondRegister != NULL) { if (regToRegOpCode == TR::InstOpCode::SR) { generateRRRInstruction(cg(), TR::InstOpCode::SRK, root, thirdReg, firstRegister, secondRegister); done = true; } else if (regToRegOpCode == TR::InstOpCode::SLR) { generateRRRInstruction(cg(), TR::InstOpCode::SLRK, root, thirdReg, firstRegister, secondRegister); done = true; } else if (regToRegOpCode == TR::InstOpCode::SGR) { generateRRRInstruction(cg(), TR::InstOpCode::SGRK, root, thirdReg, firstRegister, secondRegister); done = true; } else if (regToRegOpCode == TR::InstOpCode::SLGR) { generateRRRInstruction(cg(), TR::InstOpCode::SLGRK, root, thirdReg, firstRegister, secondRegister); done = true; } } } if (!done) { generateRRInstruction(cg(), copyOpCode, root, thirdReg, firstRegister); if (getBinaryReg3Reg2() || (secondRegister != NULL)) { generateRRInstruction(cg(), regToRegOpCode, root, thirdReg, secondRegister); } else { TR::Node* loadBaseAddr = is16BitMemory2Operand ? secondChild->getFirstChild() : secondChild; TR::MemoryReference * tempMR = generateS390MemoryReference(loadBaseAddr, cg()); //floating-point arithmatics don't have RXY format instructions, so no long displacement if (secondChild->getOpCode().isFloatingPoint()) { tempMR->enforce4KDisplacementLimit(secondChild, cg(), NULL); } generateRXInstruction(cg(), memToRegOpCode, root, thirdReg, tempMR); tempMR->stopUsingMemRefRegister(cg()); if (is16BitMemory2Operand) { cg()->decReferenceCount(secondChild->getFirstChild()); } } } root->setRegister(thirdReg); } else if (getBinaryReg1Reg2()) { generateRRInstruction(cg(), regToRegOpCode, root, firstRegister, secondRegister); root->setRegister(firstRegister); } else // assert getBinaryReg1Mem2() == true { TR_ASSERT( !getInvalid(), "TR_S390BinaryAnalyser::invalid case\n"); TR::MemoryReference * tempMR = generateS390MemoryReference(is16BitMemory2Operand ? secondChild->getFirstChild() : secondChild, cg()); //floating-point arithmatics don't have RXY format instructions, so no long displacement if (secondChild->getOpCode().isFloatingPoint()) { tempMR->enforce4KDisplacementLimit(secondChild, cg(), NULL); } generateRXInstruction(cg(), memToRegOpCode, root, firstRegister, tempMR); tempMR->stopUsingMemRefRegister(cg()); if (is16BitMemory2Operand) cg()->decReferenceCount(secondChild->getFirstChild()); root->setRegister(firstRegister); } cg()->decReferenceCount(firstChild); cg()->decReferenceCount(secondChild); return; }
// Returns true if there is any constraint to the move bool TR_LocalLiveRangeReduction::isAnySymInDefinedOrUsedBy(TR_TreeRefInfo *currentTreeRefInfo, TR::Node *currentNode, TR_TreeRefInfo *movingTreeRefInfo ) { TR::Node *movingNode = movingTreeRefInfo->getTreeTop()->getNode(); // ignore anchors // if (movingNode->getOpCode().isAnchor()) movingNode = movingNode->getFirstChild(); TR::ILOpCode &opCode = currentNode->getOpCode(); ////if ((opCode.getOpCodeValue() == TR::monent) || (opCode.getOpCodeValue() == TR::monexit)) if (nodeMaybeMonitor(currentNode)) { if (trace()) traceMsg(comp(),"cannot move %p beyond monitor %p\n",movingNode,currentNode); return true; } // Don't move gc points or things across gc points // if (movingNode->canGCandReturn() || currentNode->canGCandReturn()) { if (trace()) traceMsg(comp(), "cannot move gc points %p past %p\n", movingNode, currentNode); return true; } // Don't move checks or calls at all // if (containsCallOrCheck(movingTreeRefInfo,movingNode)) { if (trace()) traceMsg(comp(),"cannot move check or call %s\n", getDebug()->getName(movingNode)); return true; } // Don't move object header store past a GC point // if ((currentNode->getOpCode().isWrtBar() || currentNode->canCauseGC()) && mayBeObjectHeaderStore(movingNode, fe())) { if (trace()) traceMsg(comp(),"cannot move possible object header store %s past GC point %s\n", getDebug()->getName(movingNode), getDebug()->getName(currentNode)); return true; } if (TR::Compiler->target.cpu.isPower() && opCode.getOpCodeValue() == TR::allocationFence) { // Can't move allocations past flushes if (movingNode->getOpCodeValue() == TR::treetop && movingNode->getFirstChild()->getOpCode().isNew() && (currentNode->getAllocation() == NULL || currentNode->getAllocation() == movingNode->getFirstChild())) { if (trace()) { traceMsg(comp(),"cannot move %p beyond flush %p - ", movingNode, currentNode); if (currentNode->getAllocation() == NULL) traceMsg(comp(),"(flush with null allocation)\n"); else traceMsg(comp(),"(flush for allocation %p)\n", currentNode->getAllocation()); } return true; } // Can't move certain stores past flushes // Exclude all indirect stores, they may be for stack allocs, in which case the flush is needed at least as a scheduling barrier // Direct stores to autos and parms are the only safe candidates if (movingNode->getOpCode().isStoreIndirect() || (movingNode->getOpCode().isStoreDirect() && !movingNode->getSymbol()->isParm() && !movingNode->getSymbol()->isAuto())) { if (trace()) traceMsg(comp(),"cannot move %p beyond flush %p - (flush for possible stack alloc)", movingNode, currentNode); return true; } } for (int32_t i = 0; i < currentNode->getNumChildren(); i++) { TR::Node *child = currentNode->getChild(i); //Any node that has side effects (like call and newarrya) cannot be evaluated in the middle of the tree. if (movingTreeRefInfo->getFirstRefNodesList()->find(child)) { //for calls and unresolve symbol that are not under check if (child->exceptionsRaised() || (child->getOpCode().hasSymbolReference() && child->getSymbolReference()->isUnresolved())) { if (trace()) traceMsg(comp(),"cannot move %p beyond %p - cannot change evaluation point of %p\n ",movingNode,currentTreeRefInfo->getTreeTop()->getNode(),child); return true; } else if(movingNode->getOpCode().isStore()) { TR::SymbolReference *stSymRef = movingNode->getSymbolReference(); int32_t stSymRefNum = stSymRef->getReferenceNumber(); //TR::SymbolReference *stSymRef = movingNode->getSymbolReference(); int32_t numHelperSymbols = comp()->getSymRefTab()->getNumHelperSymbols(); if ((comp()->getSymRefTab()->isNonHelper(stSymRefNum, TR::SymbolReferenceTable::vftSymbol))|| (comp()->getSymRefTab()->isNonHelper(stSymRefNum, TR::SymbolReferenceTable::contiguousArraySizeSymbol))|| (comp()->getSymRefTab()->isNonHelper(stSymRefNum, TR::SymbolReferenceTable::discontiguousArraySizeSymbol))|| (stSymRef == comp()->getSymRefTab()->findHeaderFlagsSymbolRef())|| (stSymRef->getSymbol() == comp()->getSymRefTab()->findGenericIntShadowSymbol())) return true; } else if (movingNode->getOpCode().isResolveOrNullCheck()) { if (trace()) traceMsg(comp(),"cannot move %p beyond %p - node %p under ResolveOrNullCheck",movingNode,currentTreeRefInfo->getTreeTop()->getNode(),currentNode); return true; } else if (TR::Compiler->target.is64Bit() && movingNode->getOpCode().isBndCheck() && ((opCode.getOpCodeValue() == TR::i2l) || (opCode.getOpCodeValue() == TR::iu2l)) && !child->isNonNegative()) { if (trace()) traceMsg(comp(),"cannot move %p beyond %p - changing the eval point of %p will casue extra cg instruction ",movingNode,currentTreeRefInfo->getTreeTop()->getNode(),currentNode); return true; } } //don't recurse over nodes each are not the first reference if (child->getReferenceCount()==1 || currentTreeRefInfo->getFirstRefNodesList()->find(child)) { if (isAnySymInDefinedOrUsedBy(currentTreeRefInfo, child, movingTreeRefInfo )) return true; } } return false; }
TR_BitVector * addVeryRefinedCallAliasSets(TR::ResolvedMethodSymbol * methodSymbol, TR_BitVector * aliases, List<void> * methodsPeeked) { TR::Compilation *comp = TR::comp(); void * methodId = methodSymbol->getResolvedMethod()->getPersistentIdentifier(); if (methodsPeeked->find(methodId)) { // This can't be allocated into the alias region as it must be accessed across optimizations TR_BitVector *heapAliases = new (comp->trHeapMemory()) TR_BitVector(comp->getSymRefCount(), comp->trMemory(), heapAlloc, growable); *heapAliases |= *aliases; return heapAliases; } // stop if the peek is getting very deep // if (methodsPeeked->getSize() >= PEEK_THRESHOLD) return 0; methodsPeeked->add(methodId); dumpOptDetails(comp, "O^O REFINING ALIASES: Peeking into the IL to refine aliases \n"); if (!methodSymbol->getResolvedMethod()->genMethodILForPeeking(methodSymbol, comp, true)) return 0; TR::SymbolReferenceTable * symRefTab = comp->getSymRefTab(); for (TR::TreeTop * tt = methodSymbol->getFirstTreeTop(); tt; tt = tt->getNextTreeTop()) { TR::Node *node = tt->getNode(); if (node->getOpCode().isResolveCheck()) return 0; if ((node->getOpCodeValue() == TR::treetop) || (node->getOpCodeValue() == TR::compressedRefs) || node->getOpCode().isCheck()) node = node->getFirstChild(); if (node->getOpCode().isStore()) { TR::SymbolReference * symRefInCallee = node->getSymbolReference(), * symRefInCaller; TR::Symbol * symInCallee = symRefInCallee->getSymbol(); TR::DataType type = symInCallee->getDataType(); if (symInCallee->isShadow()) { if (symInCallee->isArrayShadowSymbol()) symRefInCaller = symRefTab->getSymRef(symRefTab->getArrayShadowIndex(type)); else if (symInCallee->isArrayletShadowSymbol()) symRefInCaller = symRefTab->getSymRef(symRefTab->getArrayletShadowIndex(type)); else symRefInCaller = symRefTab->findShadowSymbol(symRefInCallee->getOwningMethod(comp), symRefInCallee->getCPIndex(), type); if (symRefInCaller) { if (symRefInCaller->reallySharesSymbol(comp)) symRefInCaller->setSharedShadowAliases(aliases, symRefTab); aliases->set(symRefInCaller->getReferenceNumber()); } } else if (symInCallee->isStatic()) { symRefInCaller = symRefTab->findStaticSymbol(symRefInCallee->getOwningMethod(comp), symRefInCallee->getCPIndex(), type); if (symRefInCaller) { if (symRefInCaller->reallySharesSymbol(comp)) symRefInCaller->setSharedStaticAliases(aliases, symRefTab); else aliases->set(symRefInCaller->getReferenceNumber()); } } } else if (node->getOpCode().isCall()) { if (node->getOpCode().isCallIndirect()) return 0; TR::ResolvedMethodSymbol * calleeSymbol = node->getSymbol()->getResolvedMethodSymbol(); if (!calleeSymbol) return 0; TR_ResolvedMethod * calleeMethod = calleeSymbol->getResolvedMethod(); if (!calleeMethod->isCompilable(comp->trMemory()) || calleeMethod->isJNINative()) return 0; if (!addVeryRefinedCallAliasSets(calleeSymbol, aliases, methodsPeeked)) return 0; } else if (node->getOpCodeValue() == TR::monent) return 0; } // This can't be allocated into the alias region as it must be accessed across optimizations TR_BitVector *heapAliases = new (comp->trHeapMemory()) TR_BitVector(comp->getSymRefCount(), comp->trMemory(), heapAlloc, growable); *heapAliases |= *aliases; return heapAliases; }
void TR_Debug::print(TR::FILE *pOutFile, TR::S390CallSnippet * snippet) { uint8_t * bufferPos = snippet->getSnippetLabel()->getCodeLocation(); TR::Node * callNode = snippet->getNode(); TR::SymbolReference * methodSymRef = snippet->getRealMethodSymbolReference(); if(!methodSymRef) methodSymRef = callNode->getSymbolReference(); TR::MethodSymbol * methodSymbol = methodSymRef->getSymbol()->castToMethodSymbol(); TR::SymbolReference * glueRef; int8_t padbytes = snippet->getPadBytes(); printSnippetLabel(pOutFile, snippet->getSnippetLabel(), bufferPos, methodSymRef->isUnresolved() ? "Unresolved Call Snippet" : "Call Snippet"); bufferPos = printS390ArgumentsFlush(pOutFile, callNode, bufferPos, snippet->getSizeOfArguments()); if (methodSymRef->isUnresolved() || _comp->compileRelocatableCode()) { if (methodSymbol->isSpecial()) { glueRef = _cg->getSymRef(TR_S390interpreterUnresolvedSpecialGlue); } else if (methodSymbol->isStatic()) { glueRef = _cg->getSymRef(TR_S390interpreterUnresolvedStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterUnresolvedDirectVirtualGlue); } } else { bool synchronised = methodSymbol->isSynchronised(); if ((methodSymbol->isVMInternalNative() || methodSymbol->isJITInternalNative())) { glueRef = _cg->getSymRef(TR_S390nativeStaticHelper); } else { switch (callNode->getDataType()) { case TR::NoType: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncVoidStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterVoidStaticGlue); } break; case TR::Int8: case TR::Int16: case TR::Int32: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncIntStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterIntStaticGlue); } break; case TR::Address: if (TR::Compiler->target.is64Bit()) { if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncLongStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterLongStaticGlue); } } else { if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncIntStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterIntStaticGlue); } } break; case TR::Int64: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncLongStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterLongStaticGlue); } break; case TR::Float: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncFloatStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterFloatStaticGlue); } break; case TR::Double: if (synchronised) { glueRef = _cg->getSymRef(TR_S390interpreterSyncDoubleStaticGlue); } else { glueRef = _cg->getSymRef(TR_S390interpreterDoubleStaticGlue); } break; default: TR_ASSERT(0, "Bad return data type for a call node. DataType was %s\n", getName(callNode->getDataType())); } } } bufferPos = printRuntimeInstrumentationOnOffInstruction(pOutFile, bufferPos, false); // RIOFF if (snippet->getKind() == TR::Snippet::IsUnresolvedCall) { int lengthOfLoad = (TR::Compiler->target.is64Bit())?6:4; printPrefix(pOutFile, NULL, bufferPos, 6); trfprintf(pOutFile, "LARL \tGPR14, *+%d <%p>\t# Start of Data Const.", 8 + lengthOfLoad + padbytes, bufferPos + 8 + lengthOfLoad + padbytes); bufferPos += 6; if (TR::Compiler->target.is64Bit()) { printPrefix(pOutFile, NULL, bufferPos, 6); trfprintf(pOutFile, "LG \tGPR_EP, 0(,GPR14)"); bufferPos += 6; } else { printPrefix(pOutFile, NULL, bufferPos, 4); trfprintf(pOutFile, "L \tGPR_EP, 0(,GPR14)"); bufferPos += 4; } printPrefix(pOutFile, NULL, bufferPos, 2); trfprintf(pOutFile, "BCR \tGPR_EP"); bufferPos += 2; } else { printPrefix(pOutFile, NULL, bufferPos, 6); trfprintf(pOutFile, "BRASL \tGPR14, <%p>\t# Branch to Helper Method %s", snippet->getSnippetDestAddr(), snippet->usedTrampoline()?"- Trampoline Used.":""); bufferPos += 6; } if (padbytes == 2) { printPrefix(pOutFile, NULL, bufferPos, 2); trfprintf(pOutFile, "DC \t0x0000 \t\t\t# 2-bytes padding for alignment"); bufferPos += 2; } else if (padbytes == 4) { printPrefix(pOutFile, NULL, bufferPos, 4) ; trfprintf(pOutFile, "DC \t0x00000000 \t\t# 4-bytes padding for alignment"); bufferPos += 4; } else if (padbytes == 6) { printPrefix(pOutFile, NULL, bufferPos, 6) ; trfprintf(pOutFile, "DC \t0x000000000000 \t\t# 6-bytes padding for alignment"); bufferPos += 6; } printPrefix(pOutFile, NULL, bufferPos, sizeof(intptrj_t)); trfprintf(pOutFile, "DC \t%p \t\t# Method Address", glueRef->getMethodAddress()); bufferPos += sizeof(intptrj_t); printPrefix(pOutFile, NULL, bufferPos, sizeof(intptrj_t)); trfprintf(pOutFile, "DC \t%p \t\t# Call Site RA", snippet->getCallRA()); bufferPos += sizeof(intptrj_t); if (methodSymRef->isUnresolved()) { printPrefix(pOutFile, NULL, bufferPos, 0); } else { printPrefix(pOutFile, NULL, bufferPos, sizeof(intptrj_t)); } trfprintf(pOutFile, "DC \t%p \t\t# Method Pointer", methodSymRef->isUnresolved() ? 0 : methodSymbol->getMethodAddress()); }
TR::Node * OMR::TransformUtil::scalarizeArrayCopy( TR::Compilation *comp, TR::Node *node, TR::TreeTop *tt, bool useElementType, bool &didTransformArrayCopyNode, TR::SymbolReference *sourceRef, TR::SymbolReference *targetRef, bool castToIntegral) { TR::CodeGenerator *cg = comp->cg(); didTransformArrayCopyNode = false; if ((comp->getOptLevel() == noOpt) || !comp->getOption(TR_ScalarizeSSOps) || node->getOpCodeValue() != TR::arraycopy || node->getNumChildren() != 3 || comp->requiresSpineChecks() || !node->getChild(2)->getOpCode().isLoadConst() || cg->getOptimizationPhaseIsComplete()) return node; int64_t byteLen = node->getChild(2)->get64bitIntegralValue(); if (byteLen == 0) { if (tt) { // Anchor the first two children if (!node->getFirstChild()->safeToDoRecursiveDecrement()) TR::TreeTop::create(comp, tt->getPrevTreeTop(), TR::Node::create(TR::treetop, 1, node->getFirstChild())); if (!node->getSecondChild()->safeToDoRecursiveDecrement()) TR::TreeTop::create(comp, tt->getPrevTreeTop(), TR::Node::create(TR::treetop, 1, node->getSecondChild())); tt->getPrevTreeTop()->join(tt->getNextTreeTop()); tt->getNode()->recursivelyDecReferenceCount(); didTransformArrayCopyNode = true; } return node; } else if (byteLen < 0) { return node; } else if (byteLen > TR_MAX_OTYPE_SIZE) { return node; } TR::DataType dataType = TR::Aggregate; // Get the element datatype from the (hidden) 4th child TR::DataType elementType = node->getArrayCopyElementType(); int32_t elementSize = TR::Symbol::convertTypeToSize(elementType); if (byteLen == elementSize) { dataType = elementType; } else if (!useElementType) { switch (byteLen) { case 1: dataType = TR::Int8; break; case 2: dataType = TR::Int16; break; case 4: dataType = TR::Int32; break; case 8: dataType = TR::Int64; break; } } else { return node; } // load/store double on 64-bit PPC requires offset to be word aligned // abort if this requirement is not met. // TODO: also need to check if the first two children are aload nodes bool cannot_use_load_store_long = false; if (TR::Compiler->target.cpu.isPower()) if (dataType == TR::Int64 && TR::Compiler->target.is64Bit()) { TR::Node * firstChild = node->getFirstChild(); if (firstChild->getNumChildren() == 2) { TR::Node *offsetChild = firstChild->getSecondChild(); TR_ASSERT(offsetChild->getOpCodeValue() != TR::iconst, "iconst shouldn't be used for 64-bit array indexing"); if (offsetChild->getOpCodeValue() == TR::lconst) { if ((offsetChild->getLongInt() & 0x3) != 0) cannot_use_load_store_long = true; } } TR::Node *secondChild = node->getSecondChild(); if (secondChild->getNumChildren() == 2) { TR::Node *offsetChild = secondChild->getSecondChild(); TR_ASSERT(offsetChild->getOpCodeValue() != TR::iconst, "iconst shouldn't be used for 64-bit array indexing"); if (offsetChild->getOpCodeValue() == TR::lconst) { if ((offsetChild->getLongInt() & 0x3) != 0) cannot_use_load_store_long = true; } } } if (cannot_use_load_store_long) return node; TR::SymbolReference *nodeRef; targetRef = comp->getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(0); sourceRef = targetRef; bool trace = comp->getOption(TR_TraceScalarizeSSOps); if (trace) traceMsg(comp,"scalarizeArrayCopy: node %p got targetRef (#%d) and sourceRef (#%d)\n", node,targetRef?targetRef->getReferenceNumber():-1,sourceRef?sourceRef->getReferenceNumber():-1); if (targetRef == NULL || sourceRef == NULL) { if (trace) traceMsg(comp,"do not scalarizeArrayCopy node %p : targetRef is NULL (%s) or sourceRef is NULL (%s)\n",node,targetRef?"no":"yes",sourceRef?"no":"yes"); return node; } #ifdef J9_PROJECT_SPECIFIC if (targetRef->getSymbol()->getDataType().isBCD() || sourceRef->getSymbol()->getDataType().isBCD()) { return node; } #endif if (performTransformation(comp, "%sScalarize arraycopy 0x%p\n", OPT_DETAILS, node)) { TR::Node *store = TR::TransformUtil::scalarizeAddressParameter(comp, node->getSecondChild(), byteLen, dataType, targetRef, true); TR::Node *load = TR::TransformUtil::scalarizeAddressParameter(comp, node->getFirstChild(), byteLen, dataType, sourceRef, false); if (tt) { // Transforming // treetop // arrayCopy <-- node // into // *store // node->recursivelyDecReferenceCount(); tt->setNode(node); } else { for (int16_t c = node->getNumChildren() - 1; c >= 0; c--) cg->recursivelyDecReferenceCount(node->getChild(c)); } TR::Node::recreate(node, store->getOpCodeValue()); node->setSymbolReference(store->getSymbolReference()); if (store->getOpCode().isStoreIndirect()) { node->setChild(0, store->getFirstChild()); node->setAndIncChild(1, load); node->setNumChildren(2); } else { node->setAndIncChild(0, load); node->setNumChildren(1); } didTransformArrayCopyNode = true; } return node; }
TR_ExpressionsSimplification::LoopInfo* TR_ExpressionsSimplification::findLoopInfo(TR_RegionStructure* region) { ListIterator<TR::CFGEdge> exitEdges(®ion->getExitEdges()); if (region->getExitEdges().getSize() != 1) { if (trace()) traceMsg(comp(), "Region with more than 1 exit edges can't be handled\n"); return 0; } TR_StructureSubGraphNode* exitNode = toStructureSubGraphNode(exitEdges.getFirst()->getFrom()); if (!exitNode->getStructure()->asBlock()) { if (trace()) traceMsg(comp(), "The exit block can't be found\n"); return 0; } TR::Block *exitBlock = exitNode->getStructure()->asBlock()->getBlock(); TR::Node *lastTreeInExitBlock = exitBlock->getLastRealTreeTop()->getNode(); if (trace()) { traceMsg(comp(), "The exit block is %d\n", exitBlock->getNumber()); traceMsg(comp(), "The branch node is %p\n", lastTreeInExitBlock); } if (!lastTreeInExitBlock->getOpCode().isBranch()) { if (trace()) traceMsg(comp(), "The branch node couldn't be found\n"); return 0; } if (lastTreeInExitBlock->getNumChildren() < 2) { if (trace()) traceMsg(comp(), "The branch node has less than 2 children\n"); return 0; } TR::Node *firstChildOfLastTree = lastTreeInExitBlock->getFirstChild(); TR::Node *secondChildOfLastTree = lastTreeInExitBlock->getSecondChild(); if (!firstChildOfLastTree->getOpCode().hasSymbolReference()) { if (trace()) traceMsg(comp(), "The branch node's first child node %p - its opcode does not have a symbol reference\n", firstChildOfLastTree); return 0; } TR::SymbolReference *firstChildSymRef = firstChildOfLastTree->getSymbolReference(); if (trace()) traceMsg(comp(), "Symbol Reference: %p Symbol: %p\n", firstChildSymRef, firstChildSymRef->getSymbol()); // Locate the induction variable that matches with the exit node symbol // TR_InductionVariable *indVar = region->findMatchingIV(firstChildSymRef); if (!indVar) return 0; if (!indVar->getIncr()->asIntConst()) { if (trace()) traceMsg(comp(), "Increment is not a constant\n"); return 0; } int32_t increment = indVar->getIncr()->getLowInt(); _visitCount = comp()->incVisitCount(); bool indVarWrittenAndUsedUnexpectedly = false; if (firstChildOfLastTree->getReferenceCount() > 1) { TR::TreeTop *cursorTreeTopInExitBlock = exitBlock->getEntry(); TR::TreeTop *exitTreeTopInExitBlock = exitBlock->getExit(); bool loadSeen = false; while (cursorTreeTopInExitBlock != exitTreeTopInExitBlock) { TR::Node *cursorNode = cursorTreeTopInExitBlock->getNode(); if (checkForLoad(cursorNode, firstChildOfLastTree)) loadSeen = true; if (!cursorNode->getOpCode().isStore() && (cursorNode->getNumChildren() > 0)) cursorNode = cursorNode->getFirstChild(); if (cursorNode->getOpCode().isStore() && (cursorNode->getSymbolReference() == firstChildSymRef)) { indVarWrittenAndUsedUnexpectedly = true; if ((cursorNode->getFirstChild() == firstChildOfLastTree) || !loadSeen) indVarWrittenAndUsedUnexpectedly = false; else break; } cursorTreeTopInExitBlock = cursorTreeTopInExitBlock->getNextTreeTop(); } } if (indVarWrittenAndUsedUnexpectedly) { return 0; } int32_t lowerBound; int32_t upperBound = 0; TR::Node *bound = 0; bool equals = false; switch(lastTreeInExitBlock->getOpCodeValue()) { case TR::ificmplt: case TR::ificmpgt: equals = true; case TR::ificmple: case TR::ificmpge: if (!(indVar->getEntry() && indVar->getEntry()->asIntConst())) { if (trace()) traceMsg(comp(), "Entry value is not a constant\n"); return 0; } lowerBound = indVar->getEntry()->getLowInt(); if (secondChildOfLastTree->getOpCode().isLoadConst()) { upperBound = secondChildOfLastTree->getInt(); } else if (secondChildOfLastTree->getOpCode().isLoadVar()) { bound = secondChildOfLastTree; } else { if (trace()) traceMsg(comp(), "Second child is not a const or a load\n"); return 0; } return new (trStackMemory()) LoopInfo(bound, lowerBound, upperBound, increment, equals); default: if (trace()) traceMsg(comp(), "The condition has not been implemeted\n"); return 0; } return 0; }
static bool isSafeToReplaceNode(TR::Node *currentNode, TR::TreeTop *curTreeTop, bool *seenConditionalBranch, vcount_t visitCount, TR::Compilation *comp, List<OMR::TreeInfo> *targetTrees, bool &cannotBeEliminated, LongestPathMap &longestPaths) { LexicalTimer tx("safeToReplace", comp->phaseTimer()); TR::SparseBitVector symbolReferencesInNode(comp->allocator()); // Collect all symbols that could be killed between here and the next reference // comp->incVisitCount(); //////vcount_t visitCount = comp->getVisitCount(); int32_t numDeadSubNodes = 0; bool cantMoveUnderBranch = false; bool seenInternalPointer = false; bool seenArraylet = false; int32_t curMaxHeight = getLongestPathOfDAG(currentNode, longestPaths); collectSymbolReferencesInNode(currentNode, symbolReferencesInNode, &numDeadSubNodes, visitCount, comp, &seenInternalPointer, &seenArraylet, &cantMoveUnderBranch); bool registersScarce = comp->cg()->areAssignableGPRsScarce(); #ifdef J9_PROJECT_SPECIFIC bool isBCD = currentNode->getType().isBCD(); #endif if (numDeadSubNodes > 1 && #ifdef J9_PROJECT_SPECIFIC !isBCD && #endif registersScarce) { return false; } OMR::TreeInfo *curTreeInfo = findOrCreateTreeInfo(curTreeTop, targetTrees, comp); int32_t curHeight = curTreeInfo->getHeight()+curMaxHeight; if (curHeight > MAX_ALLOWED_HEIGHT) { cannotBeEliminated = true; return false; } // TEMPORARY // Don't allow removal of a node containing an unresolved reference if // the gcOnResolve option is set // bool isUnresolvedReference = currentNode->hasUnresolvedSymbolReference(); if (isUnresolvedReference) return false; bool mayBeVolatileReference = currentNode->mightHaveVolatileSymbolReference(); //if (mayBeVolatileReference) // return false; // Now scan forwards through the trees looking for the next use and checking // to see if any symbols in the subtree are getting modified; if so it is not // safe to replace the node at its next use. // comp->incVisitCount(); for (TR::TreeTop *treeTop = curTreeTop->getNextTreeTop(); treeTop; treeTop = treeTop->getNextTreeTop()) { TR::Node *node = treeTop->getNode(); if(node->getOpCodeValue() == TR::treetop) node = node->getFirstChild(); if (node->getOpCodeValue() == TR::BBStart && !node->getBlock()->isExtensionOfPreviousBlock()) return true; if (cantMoveUnderBranch && (node->getOpCode().isBranch() || node->getOpCode().isJumpWithMultipleTargets())) return false; if (node->canGCandReturn() && seenInternalPointer) return false; int32_t tempHeight = 0; int32_t maxHeight = 0; bool canMoveIfVolatile = true; if (containsNode(node, currentNode, visitCount, comp, &tempHeight, &maxHeight, canMoveIfVolatile)) { // TEMPORARY // Disable moving an unresolved reference down to the middle of a // JNI call, until the resolve helper is fixed properly // if (isUnresolvedReference && node->getFirstChild()->getOpCode().isCall() && node->getFirstChild()->getSymbol()->castToMethodSymbol()->isJNI()) return false; if (curTreeInfo) { OMR::TreeInfo *treeInfo = findOrCreateTreeInfo(treeTop, targetTrees, comp); int32_t height = treeInfo->getHeight(); int32_t maxHeightUsed = maxHeight; if (maxHeightUsed < curMaxHeight) maxHeightUsed = curMaxHeight; if (height < curTreeInfo->getHeight()) height = curTreeInfo->getHeight(); height++; if ((height+maxHeightUsed) > MAX_ALLOWED_HEIGHT) { cannotBeEliminated = true; return false; } treeInfo->setHeight(height); } return true; } if (mayBeVolatileReference && !canMoveIfVolatile) return false; if ((node->getOpCode().isBranch() && (node->getOpCodeValue() != TR::Goto)) || (node->getOpCode().isJumpWithMultipleTargets() && node->getOpCode().hasBranchChildren())) *seenConditionalBranch = true; if (node->getOpCodeValue() == TR::treetop || node->getOpCode().isNullCheck() || node->getOpCode().isResolveCheck() || node->getOpCodeValue() == TR::ArrayStoreCHK || node->getOpCode().isSpineCheck()) { node = node->getFirstChild(); } if (node->getOpCode().isStore()) { // For a store, just the single symbol reference is killed. // Resolution of the store symbol is handled by TR::ResolveCHK // if (symbolReferencesInNode.ValueAt(node->getSymbolReference()->getReferenceNumber())) return false; } // Node Aliasing Changes // Check if the definition modifies any symbol in the subtree // if (node->mayKill(true).containsAny(symbolReferencesInNode, comp)) return false; } return true; }
void TR_ExpressionsSimplification::setSummationReductionCandidates(TR::Node *node, TR::TreeTop *tt) { // Must be a store node // if (node->getOpCodeValue() != TR::istore /* || node->getOpCodeValue() != TR::astore */) { if (trace()) traceMsg(comp(), "Node %p: The opcode is not istore so not a summation reduction candidate\n",node); return; } TR::Node *opNode = node->getFirstChild(); if (opNode->getOpCodeValue() == TR::iadd || opNode->getOpCodeValue() == TR::isub) { TR::Node *firstNode = opNode->getFirstChild(); TR::Node *secondNode = opNode->getSecondChild(); if (firstNode->getOpCode().hasSymbolReference() && node->getSymbolReference() == firstNode->getSymbolReference() && opNode->getReferenceCount() == 1 && firstNode->getReferenceCount() == 1) { // The second node must be loop invariant // if (!_currentRegion->isExprInvariant(secondNode)) { if (trace()) { traceMsg(comp(), "The node %p is not loop invariant\n",secondNode); // This can be the arithmetic series case // only when the node is an induction variable if (secondNode->getNumChildren() == 1 && secondNode->getOpCode().hasSymbolReference()) { TR_InductionVariable *indVar = _currentRegion->findMatchingIV(secondNode->getSymbolReference()); if (indVar) { //printf("Found Candidate of arithmetic series\n" ); } } } return; } _candidateTTs->add(tt); } else if (secondNode->getOpCode().hasSymbolReference() && node->getSymbolReference() == secondNode->getSymbolReference() && opNode->getReferenceCount() == 1 && secondNode->getReferenceCount() == 1 && _currentRegion->isExprInvariant(firstNode)) { _candidateTTs->add(tt); } } else if (opNode->getOpCodeValue() == TR::ixor || opNode->getOpCodeValue() == TR::ineg) { if (opNode->getFirstChild()->getOpCode().hasSymbolReference() && node->getSymbolReference() == opNode->getFirstChild()->getSymbolReference() && opNode->getReferenceCount() == 1 && opNode->getFirstChild()->getReferenceCount() == 1 && (opNode->getOpCodeValue() == TR::ineg || _currentRegion->isExprInvariant(opNode->getSecondChild()))) _candidateTTs->add(tt); else if (opNode->getOpCodeValue() == TR::ixor && opNode->getSecondChild()->getOpCode().hasSymbolReference() && node->getSymbolReference() == opNode->getSecondChild()->getSymbolReference() && opNode->getReferenceCount() == 1 && opNode->getSecondChild()->getReferenceCount() == 1 && _currentRegion->isExprInvariant(opNode->getFirstChild())) _candidateTTs->add(tt); } }
// Checks for syntactic equivalence and returns the side-table index // of the syntactically equivalent node if it found one; else it returns // -1 signifying that this is the first time any node similar syntactically // to this node has been seen. Adds the node to the hash table if seen for the // first time. // // int TR_LocalAnalysisInfo::hasOldExpressionOnRhs(TR::Node *node, bool recalcContainsCall, bool storeLhsContainsCall) { // // Get the relevant portion of the subtree // for this node; this is different for a null check // as its null check reference is the only // sub-expression that matters // TR::Node *relevantSubtree = NULL; if (node->getOpCodeValue() == TR::NULLCHK) relevantSubtree = node->getNullCheckReference(); else relevantSubtree = node; // containsCall checks whether the relevant node has some // sub-expression that cannot be commoned, e.g. call or a new // bool nodeContainsCall; if (!recalcContainsCall && (relevantSubtree == node)) { // can use pre-calculated value of containsCall and storeLhsContainsCall, to avoid visitCount overflow nodeContainsCall = node->containsCall(); } else { storeLhsContainsCall = false; nodeContainsCall = containsCall(relevantSubtree, storeLhsContainsCall); } if (nodeContainsCall) { // // If the node is not a store, a call-like sub-expression is inadmissable; // if the node is a store, a call-like sub-expression is allowed on the RHS // of the store as this does not inhibit privatization in any way as // the private temp store's RHS simply points at original RHS. But if a call-like // sub-expression is present in the LHS of the store, that is inadmissable // if (!node->getOpCode().isStore() || storeLhsContainsCall) return 0; } bool seenIndirectStore = false; #ifdef J9_PROJECT_SPECIFIC bool seenIndirectBCDStore = false; #endif bool seenWriteBarrier = false; int32_t storeNumChildren = node->getNumChildren(); // If node is a null check, compare the // null check reference only to establish syntactic equivalence // if (node->getOpCodeValue() == TR::NULLCHK) /////if (node->getOpCode().isNullCheck()) { int32_t k; for (k=0;k<_numNullChecks;k++) { if (!(_nullCheckNodesAsArray[k] == NULL)) { if (areSyntacticallyEquivalent(_nullCheckNodesAsArray[k]->getNullCheckReference(), node->getNullCheckReference())) return _nullCheckNodesAsArray[k]->getLocalIndex(); } } _nullCheckNodesAsArray[_numNullChecks++] = node; } else { // // If this node is a global store, then equivalence check is different. // We try to give a store to field (or static) o.f the same index as // a load of o.f. This is so that privatization happens for fields/statics. // So the store's opcode value is changed temporarily to be a load before // syntactic equivalence is checked; this enables matching stores/loads to // same global symbol. // if (node->getOpCode().isStore() && !node->getSymbolReference()->getSymbol()->isAutoOrParm()) { if (node->getOpCode().isWrtBar()) seenWriteBarrier = true; #ifdef J9_PROJECT_SPECIFIC seenIndirectBCDStore = node->getType().isBCD(); #endif if (node->getOpCode().isStoreIndirect()) { if (seenWriteBarrier) { TR::Node::recreate(node, _compilation->il.opCodeForIndirectArrayLoad(node->getDataType())); } else { TR::Node::recreate(node, _compilation->il.opCodeForCorrespondingIndirectStore(node->getOpCodeValue())); } node->setNumChildren(1); } else { TR::Node::recreate(node, _compilation->il.opCodeForDirectLoad(node->getDataType())); node->setNumChildren(0); } #ifdef J9_PROJECT_SPECIFIC if (seenIndirectBCDStore) node->setBCDStoreIsTemporarilyALoad(true); #endif seenIndirectStore = true; } int32_t hashValue = _hashTable->hash(node); HashTable::Cursor cursor(_hashTable, hashValue); TR::Node *other; for (other = cursor.firstNode(); other; other = cursor.nextNode()) { // Convert other node's opcode to be a load temporarily // (only for syntactic equivalence check; see explanation above) // to enable matching global stores/loads. // bool seenOtherIndirectStore = false; #ifdef J9_PROJECT_SPECIFIC bool seenOtherIndirectBCDStore = false; #endif bool seenOtherWriteBarrier = false; int32_t otherStoreNumChildren = other->getNumChildren(); if (other->getOpCode().isStore() && !other->getSymbolReference()->getSymbol()->isAutoOrParm()) { if (other->getOpCode().isWrtBar()) seenOtherWriteBarrier = true; #ifdef J9_PROJECT_SPECIFIC seenOtherIndirectBCDStore = other->getType().isBCD(); #endif if (other->getOpCode().isStoreIndirect()) { if (seenOtherWriteBarrier) { TR::Node::recreate(other, _compilation->il.opCodeForIndirectArrayLoad(other->getDataType())); } else { TR::Node::recreate(other, _compilation->il.opCodeForCorrespondingIndirectStore(other->getOpCodeValue())); } other->setNumChildren(1); } else { TR::Node::recreate(other, _compilation->il.opCodeForDirectLoad(other->getDataType())); other->setNumChildren(0); } #ifdef J9_PROJECT_SPECIFIC if (seenOtherIndirectBCDStore) other->setBCDStoreIsTemporarilyALoad(true); #endif seenOtherIndirectStore = true; } bool areSame = areSyntacticallyEquivalent(node, other); // Restore the other node's state to what it was originally // (if it was a global store) // if (seenOtherWriteBarrier) { other->setNumChildren(otherStoreNumChildren); if (otherStoreNumChildren == 3) TR::Node::recreate(other, TR::awrtbari); else TR::Node::recreate(other, TR::awrtbar); } else if (seenOtherIndirectStore) { other->setNumChildren(otherStoreNumChildren); #ifdef J9_PROJECT_SPECIFIC if (seenOtherIndirectBCDStore) other->setBCDStoreIsTemporarilyALoad(false); #endif if (other->getOpCode().isIndirect()) TR::Node::recreate(other, _compilation->il.opCodeForCorrespondingIndirectLoad(other->getOpCodeValue())); else TR::Node::recreate(other, _compilation->il.opCodeForDirectStore(other->getDataType())); } if (areSame) { if (seenWriteBarrier) { node->setNumChildren(storeNumChildren); if (storeNumChildren == 3) TR::Node::recreate(node, TR::awrtbari); else TR::Node::recreate(node, TR::awrtbar); } else if (seenIndirectStore) { node->setNumChildren(storeNumChildren); #ifdef J9_PROJECT_SPECIFIC if (seenIndirectBCDStore) node->setBCDStoreIsTemporarilyALoad(false); #endif if (node->getOpCode().isIndirect()) TR::Node::recreate(node, _compilation->il.opCodeForCorrespondingIndirectLoad(node->getOpCodeValue())); else TR::Node::recreate(node, _compilation->il.opCodeForDirectStore(node->getDataType())); } return other->getLocalIndex(); } } // No match from existing nodes in the hash table; // add this node to the hash table. // _hashTable->add(node, hashValue); } // Restore this node's state to what it was before // (if it was a global store) // if (seenWriteBarrier) { node->setNumChildren(storeNumChildren); if (storeNumChildren == 3) TR::Node::recreate(node, TR::awrtbari); else TR::Node::recreate(node, TR::awrtbar); } else if (seenIndirectStore) { node->setNumChildren(storeNumChildren); #ifdef J9_PROJECT_SPECIFIC if (seenIndirectBCDStore) node->setBCDStoreIsTemporarilyALoad(false); #endif if (node->getOpCode().isIndirect()) TR::Node::recreate(node, _compilation->il.opCodeForCorrespondingIndirectLoad(node->getOpCodeValue())); else TR::Node::recreate(node, _compilation->il.opCodeForDirectStore(node->getDataType())); } return -1; }
TR_LocalAnalysisInfo::TR_LocalAnalysisInfo(TR::Compilation *c, bool t) : _compilation(c), _trace(t), _trMemory(c->trMemory()) { _numNodes = -1; #if 0 // somehow stops PRE from happening // We are going to increment visit count for every tree so can reach max // for big methods quickly. Perhaps can improve containsCall() in the future. comp()->resetVisitCounts(0); #endif if (comp()->getVisitCount() > HIGH_VISIT_COUNT) { _compilation->resetVisitCounts(1); dumpOptDetails(comp(), "\nResetting visit counts for this method before LocalAnalysisInfo\n"); } TR::CFG *cfg = comp()->getFlowGraph(); _numBlocks = cfg->getNextNodeNumber(); TR_ASSERT(_numBlocks > 0, "Local analysis, node numbers not assigned"); // Allocate information on the stack. It is the responsibility of the user // of this class to determine the life of the information by using jitStackMark // and jitStackRelease. // //_blocksInfo = (TR::Block **) trMemory()->allocateStackMemory(_numBlocks*sizeof(TR::Block *)); //memset(_blocksInfo, 0, _numBlocks*sizeof(TR::Block *)); TR::TreeTop *currentTree = comp()->getStartTree(); // Only do this if not done before; typically this would be done in the // first call to this method through LocalTransparency and would NOT // need to be re-done by LocalAnticipatability. // if (_numNodes < 0) { _optimizer = comp()->getOptimizer(); int32_t numBuckets; int32_t numNodes = comp()->getNodeCount(); if (numNodes < 10) numBuckets = 1; else if (numNodes < 100) numBuckets = 7; else if (numNodes < 500) numBuckets = 31; else if (numNodes < 3000) numBuckets = 127; else if (numNodes < 6000) numBuckets = 511; else numBuckets = 1023; // Allocate hash table for matching expressions // HashTable hashTable(numBuckets, comp()); _hashTable = &hashTable; // Null checks are handled differently as the criterion for // commoning a null check is different than that used for // other nodes; for a null check, the null check reference is // important (and not the actual indirect access itself) // _numNullChecks = 0; while (currentTree) { if (currentTree->getNode()->getOpCodeValue() == TR::NULLCHK) //////if (currentTree->getNode()->getOpCode().isNullCheck()) _numNullChecks++; currentTree = currentTree->getNextTreeTop(); } if (_numNullChecks == 0) _nullCheckNodesAsArray = NULL; else { _nullCheckNodesAsArray = (TR::Node**)trMemory()->allocateStackMemory(_numNullChecks*sizeof(TR::Node*)); memset(_nullCheckNodesAsArray, 0, _numNullChecks*sizeof(TR::Node*)); } currentTree = comp()->getStartTree(); int32_t symRefCount = comp()->getSymRefCount(); _checkSymbolReferences = new (trStackMemory()) TR_BitVector(symRefCount, trMemory(), stackAlloc); _numNodes = 1; _numNullChecks = 0; // This loop counts all the nodes that are going to take part in PRE. // This is a computation intensive loop as we check if the node that // is syntactically equivalent to a given node has been seen before // and if so we use the local index of the original node (that // is syntactically equivalent to the given node). Could be improved // in complexity with value numbering at some stage. // _visitCount = comp()->incVisitCount(); while (currentTree) { TR::Node *firstNodeInTree = currentTree->getNode(); TR::ILOpCode *opCode = &firstNodeInTree->getOpCode(); if (((firstNodeInTree->getOpCodeValue() == TR::treetop) || (comp()->useAnchors() && firstNodeInTree->getOpCode().isAnchor())) && (firstNodeInTree->getFirstChild()->getOpCode().isStore())) { firstNodeInTree->setLocalIndex(-1); if (comp()->useAnchors() && firstNodeInTree->getOpCode().isAnchor()) firstNodeInTree->getSecondChild()->setLocalIndex(-1); firstNodeInTree = firstNodeInTree->getFirstChild(); opCode = &firstNodeInTree->getOpCode(); } // This call finds nodes with opcodes that are supported by PRE // in this subtree; this accounts for all opcodes other than stores/checks // which are handled later on below // bool firstNodeInTreeHasCallsInStoreLhs = false; countSupportedNodes(firstNodeInTree, NULL, firstNodeInTreeHasCallsInStoreLhs); if ((opCode->isStore() && !firstNodeInTree->getSymbolReference()->getSymbol()->isAutoOrParm()) || opCode->isCheck()) { int32_t oldExpressionOnRhs = hasOldExpressionOnRhs(firstNodeInTree); // // Return value 0 denotes that the node contains some sub-expression // that cannot participate in PRE; e.g. a call or a new // // Return value -1 denotes that the node can participate in PRE // but did not match with any existing expression seen so far // // Any other return value (should be positive always) denotes that // the node can participate in PRE and has been matched with a seen // expression having local index == return value // if (oldExpressionOnRhs == -1) { if (trace()) { traceMsg(comp(), "\nExpression #%d is : \n", _numNodes); comp()->getDebug()->print(comp()->getOutFile(), firstNodeInTree, 6, true); } firstNodeInTree->setLocalIndex(_numNodes++); } else firstNodeInTree->setLocalIndex(oldExpressionOnRhs); if (opCode->isCheck() && (firstNodeInTree->getFirstChild()->getOpCode().isStore() && !firstNodeInTree->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm())) { int oldExpressionOnRhs = hasOldExpressionOnRhs(firstNodeInTree->getFirstChild()); if (oldExpressionOnRhs == -1) { if (trace()) { traceMsg(comp(), "\nExpression #%d is : \n", _numNodes); comp()->getDebug()->print(comp()->getOutFile(), firstNodeInTree->getFirstChild(), 6, true); } firstNodeInTree->getFirstChild()->setLocalIndex(_numNodes++); } else firstNodeInTree->getFirstChild()->setLocalIndex(oldExpressionOnRhs); } } else firstNodeInTree->setLocalIndex(-1); currentTree = currentTree->getNextTreeTop(); } } _supportedNodesAsArray = (TR::Node**)trMemory()->allocateStackMemory(_numNodes*sizeof(TR::Node*)); memset(_supportedNodesAsArray, 0, _numNodes*sizeof(TR::Node*)); _checkExpressions = new (trStackMemory()) TR_BitVector(_numNodes, trMemory(), stackAlloc); //_checkExpressions.init(_numNodes, trMemory(), stackAlloc); // This loop goes through the trees and collects the nodes // that would take part in PRE. Each node has its local index set to // the bit position that it occupies in the bit vector analyses. // currentTree = comp()->getStartTree(); _visitCount = comp()->incVisitCount(); while (currentTree) { TR::Node *firstNodeInTree = currentTree->getNode(); TR::ILOpCode *opCode = &firstNodeInTree->getOpCode(); if (((firstNodeInTree->getOpCodeValue() == TR::treetop) || (comp()->useAnchors() && firstNodeInTree->getOpCode().isAnchor())) && (firstNodeInTree->getFirstChild()->getOpCode().isStore())) { firstNodeInTree = firstNodeInTree->getFirstChild(); opCode = &firstNodeInTree->getOpCode(); } collectSupportedNodes(firstNodeInTree, NULL); if ((opCode->isStore() && !firstNodeInTree->getSymbolReference()->getSymbol()->isAutoOrParm()) || opCode->isCheck()) { if (opCode->isCheck()) { _checkSymbolReferences->set(firstNodeInTree->getSymbolReference()->getReferenceNumber()); _checkExpressions->set(firstNodeInTree->getLocalIndex()); } if (!_supportedNodesAsArray[firstNodeInTree->getLocalIndex()]) _supportedNodesAsArray[firstNodeInTree->getLocalIndex()] = firstNodeInTree; if (opCode->isCheck() && firstNodeInTree->getFirstChild()->getOpCode().isStore() && !firstNodeInTree->getFirstChild()->getSymbolReference()->getSymbol()->isAutoOrParm() && !_supportedNodesAsArray[firstNodeInTree->getFirstChild()->getLocalIndex()]) _supportedNodesAsArray[firstNodeInTree->getFirstChild()->getLocalIndex()] = firstNodeInTree->getFirstChild(); } currentTree = currentTree->getNextTreeTop(); } //initialize(toBlock(cfg->getStart())); }
// Collects nodes that involved in PRE that are not stores or checks. // These nodes require temps. // bool TR_LocalAnalysisInfo::collectSupportedNodes(TR::Node *node, TR::Node *parent) { if (node->getVisitCount() == _visitCount) return false; node->setVisitCount(_visitCount); bool flag = false; bool childRelevant = false; TR::ILOpCode &opCode = node->getOpCode(); int32_t i; for (i = 0; i < node->getNumChildren(); i++) { TR::Node *child = node->getChild(i); if (collectSupportedNodes(child, node)) flag = true; if (_checkExpressions->get(child->getLocalIndex())) childRelevant = true; } if (TR_LocalAnalysis::isSupportedNode(node, _compilation, parent)) { _supportedNodesAsArray[node->getLocalIndex()] = node; bool indirectionSafe = true; if (opCode.isIndirect() && (opCode.isLoadVar() || opCode.isStore())) { indirectionSafe = false; if (node->getFirstChild()->isThisPointer() && node->getFirstChild()->isNonNull()) { indirectionSafe = true; TR::Node *firstChild = node->getFirstChild(); TR::SymbolReference *symRef = firstChild->getSymbolReference(); int32_t len; const char *sig = symRef->getTypeSignature(len); TR::SymbolReference *otherSymRef = node->getSymbolReference(); TR_OpaqueClassBlock *cl = NULL; if (sig && (len > 0)) cl = _compilation->fe()->getClassFromSignature(sig, len, symRef->getOwningMethod(_compilation)); TR_OpaqueClassBlock *otherClassObject = NULL; int32_t otherLen; const char *otherSig = otherSymRef->getOwningMethod(_compilation)->classNameOfFieldOrStatic(otherSymRef->getCPIndex(), otherLen); if (otherSig) { otherSig = classNameToSignature(otherSig, otherLen, _compilation); otherClassObject = _compilation->fe()->getClassFromSignature(otherSig, otherLen, otherSymRef->getOwningMethod(_compilation)); } if (!cl || !otherClassObject || (cl != otherClassObject)) indirectionSafe = false; } } if (childRelevant || (!indirectionSafe || (opCode.isArrayLength())) || (node->getOpCode().isArrayRef()) || (opCode.hasSymbolReference() && (node->getSymbolReference()->isUnresolved() || node->getSymbol()->isArrayShadowSymbol())) || (opCode.isDiv() || opCode.isRem())) _checkExpressions->set(node->getLocalIndex()); } return flag; }