Path: blob/master/runtime/compiler/optimizer/EscapeAnalysis.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#ifdef J9ZTPF23#define __TPF_DO_NOT_MAP_ATOE_REMOVE24#endif2526#include "optimizer/EscapeAnalysis.hpp"27#include "optimizer/EscapeAnalysisTools.hpp"2829#include <algorithm>30#include <stdint.h>31#include <stdio.h>32#include <string.h>33#include "codegen/CodeGenerator.hpp"34#include "env/FrontEnd.hpp"35#include "codegen/RecognizedMethods.hpp"36#include "compile/Compilation.hpp"37#include "compile/CompilationTypes.hpp"38#include "compile/Method.hpp"39#include "compile/ResolvedMethod.hpp"40#include "compile/SymbolReferenceTable.hpp"41#include "compile/VirtualGuard.hpp"42#include "control/Options.hpp"43#include "control/Options_inlines.hpp"44#include "control/Recompilation.hpp"45#include "control/RecompilationInfo.hpp"46#include "cs2/bitvectr.h"47#include "env/CompilerEnv.hpp"48#include "env/ObjectModel.hpp"49#include "env/TRMemory.hpp"50#include "env/jittypes.h"51#include "env/VMAccessCriticalSection.hpp"52#include "env/VMJ9.h"53#include "il/AliasSetInterface.hpp"54#include "il/AutomaticSymbol.hpp"55#include "il/Block.hpp"56#include "il/DataTypes.hpp"57#include "il/ILOpCodes.hpp"58#include "il/ILOps.hpp"59#include "il/MethodSymbol.hpp"60#include "il/Node.hpp"61#include "il/Node_inlines.hpp"62#include "il/ParameterSymbol.hpp"63#include "il/ResolvedMethodSymbol.hpp"64#include "il/StaticSymbol.hpp"65#include "il/Symbol.hpp"66#include "il/SymbolReference.hpp"67#include "il/TreeTop.hpp"68#include "il/TreeTop_inlines.hpp"69#include "infra/Array.hpp"70#include "infra/Assert.hpp"71#include "infra/BitVector.hpp"72#include "infra/Cfg.hpp"73#include "infra/Checklist.hpp"74#include "infra/Link.hpp"75#include "infra/List.hpp"76#include "infra/SimpleRegex.hpp"77#include "infra/TRCfgEdge.hpp"78#include "infra/TRCfgNode.hpp"79#include "optimizer/Inliner.hpp"80#include "optimizer/Optimization.hpp"81#include "optimizer/OptimizationManager.hpp"82#include "optimizer/Optimizations.hpp"83#include "optimizer/Optimizer.hpp"84#include "optimizer/Structure.hpp"85#include "optimizer/TransformUtil.hpp"86#include "optimizer/DataFlowAnalysis.hpp"87#include "optimizer/UseDefInfo.hpp"88#include "optimizer/ValueNumberInfo.hpp"89#include "optimizer/LocalOpts.hpp"90#include "optimizer/MonitorElimination.hpp"91#include "ras/Debug.hpp"92#include "runtime/J9Profiler.hpp"93#include "runtime/J9Runtime.hpp"9495#define OPT_DETAILS "O^O ESCAPE ANALYSIS: "9697#define MAX_SIZE_FOR_ONE_CONTIGUOUS_OBJECT 2416 // Increased from 7298#define MAX_SIZE_FOR_ALL_OBJECTS 3000 // Increased from 50099#define MAX_SNIFF_BYTECODE_SIZE 1600100101#define LOCAL_OBJECTS_COLLECTABLE 1102103extern void createGuardSiteForRemovedGuard(TR::Compilation *comp, TR::Node* ifNode);104105static bool blockIsInLoop(TR::Block *block)106{107for (TR_Structure *s = block->getStructureOf()->getParent(); s; s = s->getParent())108{109TR_RegionStructure *region = s->asRegion();110if (region->isNaturalLoop() || region->containsInternalCycles())111return true;112}113return false;114}115116TR_EscapeAnalysis::TR_EscapeAnalysis(TR::OptimizationManager *manager)117: TR::Optimization(manager),118_newObjectNoZeroInitSymRef(NULL),119_newArrayNoZeroInitSymRef(NULL),120_dependentAllocations(manager->comp()->trMemory()),121_inlineCallSites(manager->comp()->trMemory()),122_dememoizedAllocs(manager->comp()->trMemory()),123_devirtualizedCallSites(manager->comp()->trMemory()),124_aNewArrayNoZeroInitSymRef(NULL)125{126127_newObjectNoZeroInitSymRef = comp()->getSymRefTab()->findOrCreateNewObjectNoZeroInitSymbolRef(0);128_newArrayNoZeroInitSymRef = comp()->getSymRefTab()->findOrCreateNewArrayNoZeroInitSymbolRef(0);129_aNewArrayNoZeroInitSymRef = comp()->getSymRefTab()->findOrCreateANewArrayNoZeroInitSymbolRef(0);130_maxPassNumber = 0;131132_dememoizationSymRef = NULL;133134_createStackAllocations = true;135_createLocalObjects = cg()->supportsStackAllocations();136_desynchronizeCalls = true;137#if CHECK_MONITORS138/* monitors */139_removeMonitors = true;140#endif141142static char *disableLoopAliasAllocationChecking = feGetEnv("TR_disableEALoopAliasAllocationChecking");143_doLoopAllocationAliasChecking = (disableLoopAliasAllocationChecking == NULL);144}145146char *TR_EscapeAnalysis::getClassName(TR::Node *classNode)147{148char *className = NULL;149150if (classNode->getOpCodeValue() == TR::loadaddr)151{152TR::SymbolReference *symRef = classNode->getSymbolReference();153154if (symRef->getSymbol()->isClassObject())155{156int32_t classNameLength;157char *classNameChars = TR::Compiler->cls.classNameChars(comp(), symRef, classNameLength);158159if (NULL != classNameChars)160{161className = (char *)trMemory()->allocateStackMemory(classNameLength+1, TR_Memory::EscapeAnalysis);162memcpy(className, classNameChars, classNameLength);163className[classNameLength] = 0;164}165}166}167return className;168}169170bool TR_EscapeAnalysis::isImmutableObject(TR::Node *node)171{172// For debugging issues with the special handling of immutable objects173// that allows them to be discontiguously allocated even if they escape174static char *disableImmutableObjectHandling = feGetEnv("TR_disableEAImmutableObjectHandling");175176if (disableImmutableObjectHandling)177{178return false;179}180181if (node->getOpCodeValue() != TR::New)182{183return false;184}185186char *className = getClassName(node->getFirstChild());187188if (NULL != className &&189!strncmp("java/lang/", className, 10) &&190(!strcmp("Integer", &className[10]) ||191!strcmp("Long", &className[10]) ||192!strcmp("Short", &className[10]) ||193!strcmp("Byte", &className[10]) ||194!strcmp("Boolean", &className[10]) ||195!strcmp("Character", &className[10]) ||196!strcmp("Double", &className[10]) ||197!strcmp("Float", &className[10])))198{199return true;200}201202203return false;204}205206bool TR_EscapeAnalysis::isImmutableObject(Candidate *candidate)207{208if (candidate->_isImmutable)209return true;210211bool b = isImmutableObject(candidate->_node);212candidate->_isImmutable = b;213return b;214}215216217218int32_t TR_EscapeAnalysis::perform()219{220if (comp()->isOptServer() && (comp()->getMethodHotness() <= warm))221return 0;222223// EA generates direct stores/loads to instance field which is different224// from a normal instance field read/write. Field watch would need special handling225// for stores/loads generated by EA.226if (comp()->incompleteOptimizerSupportForReadWriteBarriers())227return 0;228229static char *doESCNonQuiet = feGetEnv("TR_ESCAPENONQUIET");230if (doESCNonQuiet && comp()->getOutFile() == NULL)231return 0;232233int32_t nodeCount = 0;234vcount_t visitCount = comp()->incVisitCount(); //@TODO: needs a change to TR_Node's235//countNumberOfNodesInSubtree236//we should probably leave it as is237//for the next iteration238TR::TreeTop *tt = comp()->getStartTree();239for (; tt; tt = tt->getNextTreeTop())240nodeCount += tt->getNode()->countNumberOfNodesInSubtree(visitCount);241242// Set thresholds depending on the method's hotness243//244TR_Hotness methodHotness = comp()->getMethodHotness();245if (methodHotness > hot)246{247_maxPassNumber = 6;248_maxSniffDepth = 8;249_maxInlinedBytecodeSize = 5000 - nodeCount;250}251else252{253_maxPassNumber = 3;254//_maxPassNumber = (methodHotness < hot) ? 2 : 3;255_maxSniffDepth = 4;256_maxInlinedBytecodeSize = 4000 - nodeCount;257}258259// under HCR we can protect the top level sniff with an HCR guard260// nested sniffs are not currently supported261if (comp()->getHCRMode() != TR::none)262_maxSniffDepth = 1;263264TR_ASSERT_FATAL(_maxSniffDepth < 16, "The argToCall and nonThisArgToCall flags are 16 bits - a depth limit greater than 16 will not fit in these flags");265266if (getLastRun())267_maxPassNumber = 0; // Notwithstanding our heuristics, if this is the last run, our max "pass number" is zero (which is the first pass)268269_maxPeekedBytecodeSize = comp()->getMaxPeekedBytecodeSize();270271// Escape analysis is organized so that it may decide another pass of272// the analysis is required immediately after the current one. It leaves273// it up to the optimization strategy to re-invoke the analysis, but we274// keep track here of the number of passes through the analysis so we275// can restrict the number of passes. Each time we end the local loop of276// passes the current pass number is reset to zero in case escape analysis277// is called again later in the optimization strategy.278//279if (manager()->numPassesCompleted() == 0)280{281//282void *data = manager()->getOptData();283TR_BitVector *peekableCalls = NULL;284if (data != NULL)285{286peekableCalls = ((TR_EscapeAnalysis::PersistentData *)data)->_peekableCalls;287delete ((TR_EscapeAnalysis::PersistentData *) data) ;288manager()->setOptData(NULL);289}290manager()->setOptData(new (comp()->allocator()) TR_EscapeAnalysis::PersistentData(comp()));291if (peekableCalls != NULL)292((TR_EscapeAnalysis::PersistentData *)manager()->getOptData())->_peekableCalls = peekableCalls;293}294else295{296if (trace())297{298/////printf("secs Performing pass %d of Escape Analysis for %s\n", _currentPass, comp()->signature());299}300}301302int32_t cost = 0;303304{305TR::StackMemoryRegion stackMemoryRegion(*trMemory());306_callsToProtect = new (trStackMemory()) CallLoadMap(CallLoadMapComparator(), comp()->trMemory()->currentStackRegion());307308#if CHECK_MONITORS309/* monitors */310TR_MonitorStructureChecker inspector;311if (inspector.checkMonitorStructure(comp()->getFlowGraph()))312{313_removeMonitors = false;314if (trace())315traceMsg(comp(), "Disallowing monitor-removal because of strange monitor structure\n");316}317#endif318319cost = performAnalysisOnce();320321if (!_callsToProtect->empty() && manager()->numPassesCompleted() < _maxPassNumber)322{323TR::CFG *cfg = comp()->getFlowGraph();324TR::Block *block = NULL;325TR::TreeTop *lastTree = comp()->findLastTree();326TR_EscapeAnalysisTools tools(comp());327RemainingUseCountMap *remainingUseCount = new (comp()->trStackMemory()) RemainingUseCountMap(RemainingUseCountMapComparator(), comp()->trMemory()->currentStackRegion());328for (TR::TreeTop *tt = comp()->findLastTree(); tt != NULL; tt = tt->getPrevTreeTop())329{330TR::Node *node = tt->getNode();331if (node->getOpCodeValue() == TR::BBEnd)332block = node->getBlock();333else if (node->getStoreNode() && node->getStoreNode()->getOpCode().isStoreDirect())334node = node->getStoreNode()->getFirstChild();335else if (node->getOpCode().isCheck() || node->getOpCode().isAnchor() || node->getOpCodeValue() == TR::treetop)336node = node->getFirstChild();337338auto nodeLookup = _callsToProtect->find(node);339if (nodeLookup == _callsToProtect->end()340|| TR_EscapeAnalysisTools::isFakeEscape(node)341|| node->getSymbol() == NULL342|| node->getSymbol()->getResolvedMethodSymbol() == NULL343|| node->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod() == NULL)344continue;345346if (node->getReferenceCount() > 1)347{348auto useCount = remainingUseCount->find(node);349if (useCount == remainingUseCount->end())350{351(*remainingUseCount)[node] = node->getReferenceCount() - 1;352continue;353}354if (useCount->second > 1)355{356useCount->second -= 1;357continue;358}359}360361if (!performTransformation(comp(), "%sHCR CALL PEEKING: Protecting call [%p] n%dn with an HCR guard and escape helper\n", OPT_DETAILS, node, node->getGlobalIndex()))362continue;363364((TR_EscapeAnalysis::PersistentData*)manager()->getOptData())->_processedCalls->set(node->getGlobalIndex());365366_repeatAnalysis = true;367368optimizer()->setValueNumberInfo(NULL);369cfg->invalidateStructure();370371TR::TreeTop *prevTT = tt->getPrevTreeTop();372TR::Block *callBlock = block->split(tt, comp()->getFlowGraph(), true, true);373374// check uncommoned nodes for stores of the candidate - if so we need to add the new temp to the375// list of loads376for (TR::TreeTop *itr = block->getExit(); itr != prevTT; itr = itr->getPrevTreeTop())377{378TR::Node *storeNode = itr->getNode()->getStoreNode();379if (storeNode380&& storeNode->getOpCodeValue() == TR::astore381&& nodeLookup->second.first->get(storeNode->getFirstChild()->getGlobalIndex()))382nodeLookup->second.second->push_back(TR::Node::createWithSymRef(TR::aload, 0, storeNode->getSymbolReference()));383}384385TR::Node *guard = TR_VirtualGuard::createHCRGuard(comp(),386node->getByteCodeInfo().getCallerIndex(),387node,388NULL,389node->getSymbol()->getResolvedMethodSymbol(),390node->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod()->classOfMethod());391block->getExit()->insertBefore(TR::TreeTop::create(comp(), guard));392393TR::Block *heapificationBlock = TR::Block::createEmptyBlock(node, comp(), MAX_COLD_BLOCK_COUNT);394heapificationBlock->getExit()->join(lastTree->getNextTreeTop());395lastTree->join(heapificationBlock->getEntry());396lastTree = heapificationBlock->getExit();397heapificationBlock->setIsCold();398399guard->setBranchDestination(heapificationBlock->getEntry());400cfg->addNode(heapificationBlock);401cfg->addEdge(block, heapificationBlock);402cfg->addEdge(heapificationBlock, callBlock);403404heapificationBlock->getExit()->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(node, TR::Goto, 0, callBlock->getEntry())));405tools.insertFakeEscapeForLoads(heapificationBlock, node, nodeLookup->second.second);406traceMsg(comp(), "Created heapification block_%d\n", heapificationBlock->getNumber());407408((TR_EscapeAnalysis::PersistentData*)manager()->getOptData())->_peekableCalls->set(node->getGlobalIndex());409_callsToProtect->erase(nodeLookup);410tt = prevTT->getNextTreeTop();411}412}413} // scope of the stack memory region414415if (_repeatAnalysis && manager()->numPassesCompleted() < _maxPassNumber)416{417// Ask the optimizer to repeat this analysis418//419requestOpt(OMR::eachEscapeAnalysisPassGroup);420manager()->incNumPassesCompleted();421}422else423{424// Don't repeat this analysis, reset the pass count for next time425//426manager()->setNumPassesCompleted(0);427}428429return cost;430}431432const char *433TR_EscapeAnalysis::optDetailString() const throw()434{435return "O^O ESCAPE ANALYSIS: ";436}437438void TR_EscapeAnalysis::rememoize(Candidate *candidate, bool mayDememoizeNextTime)439{440if (!candidate->_dememoizedConstructorCall)441return;442443TR_ASSERT(candidate->_treeTop->getEnclosingBlock() == candidate->_dememoizedConstructorCall->getEnclosingBlock(),444"Dememoized constructor call %p must be in the same block as allocation %p", candidate->_treeTop->getNode(), candidate->_dememoizedConstructorCall->getNode());445if (trace())446traceMsg(comp(), " Rememoizing%s [%p] using constructor call [%p]\n", mayDememoizeNextTime?"":" and inlining", candidate->_node, candidate->_dememoizedConstructorCall->getNode()->getFirstChild());447448// Change trees back449//450candidate->_node->getFirstChild()->recursivelyDecReferenceCount(); // remove loadaddr of class451candidate->_node->setAndIncChild(0, candidate->_dememoizedConstructorCall->getNode()->getFirstChild()->getSecondChild()); // original call argument452TR::Node::recreate(candidate->_node, TR::acall);453candidate->_node->setSymbolReference(candidate->_dememoizedMethodSymRef);454candidate->_dememoizedConstructorCall->unlink(true);455456// Only rememoize once457//458_inlineCallSites.remove(candidate->_dememoizedConstructorCall);459candidate->_dememoizedConstructorCall = NULL;460candidate->_dememoizedMethodSymRef = NULL;461462if (!mayDememoizeNextTime)463{464// Inline the memoization method so we can apply EA to it even though dememoization failed.465// This also prevents us from re-trying dememoization when it's hopeless.466//467_inlineCallSites.add(candidate->_treeTop);468}469}470471static const char *ynmString(TR_YesNoMaybe arg)472{473switch (arg)474{475case TR_yes:476return "yes";477case TR_no:478return "no";479case TR_maybe:480return "maybe";481}482return "";483}484485static TR_YesNoMaybe ynmOr(TR_YesNoMaybe left, TR_YesNoMaybe right)486{487switch (left)488{489case TR_yes:490return TR_yes;491case TR_no:492return right;493case TR_maybe:494return (right == TR_yes)? TR_yes : TR_maybe;495}496return TR_maybe;497}498499static TR_YesNoMaybe candidateHasField(Candidate *candidate, TR::Node *fieldNode, int32_t fieldOffset, TR_EscapeAnalysis *ea)500{501TR::Compilation *comp = ea->comp();502TR::SymbolReference *fieldSymRef = fieldNode->getSymbolReference();503int32_t fieldSize = fieldNode->getSize();504505int32_t minHeaderSize, maxHeaderSize;506if (candidate->_origKind == TR::New)507{508minHeaderSize = maxHeaderSize = comp->fej9()->getObjectHeaderSizeInBytes();509}510else511{512minHeaderSize = std::min(TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), TR::Compiler->om.discontiguousArrayHeaderSizeInBytes());513maxHeaderSize = std::max(TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), TR::Compiler->om.discontiguousArrayHeaderSizeInBytes());514}515516TR_YesNoMaybe withinObjectBound = TR_maybe;517TR_YesNoMaybe withinObjectHeader = TR_maybe;518TR_YesNoMaybe belongsToAllocatedClass = TR_maybe;519TR_YesNoMaybe result = TR_maybe;520521if (fieldOffset + fieldSize <= candidate->_size)522withinObjectBound = TR_yes;523else524withinObjectBound = TR_no;525526if (fieldOffset + fieldSize <= minHeaderSize)527withinObjectHeader = TR_yes;528else if (fieldOffset > maxHeaderSize)529withinObjectHeader = TR_no;530else531withinObjectHeader = TR_maybe;532533// Test a few conditions to try to avoid calling getDeclaringClassFromFieldOrStatic534// because that requires VM access.535//536static char *debugEAFieldValidityCheck = feGetEnv("TR_debugEAFieldValidityCheck");537if (withinObjectHeader == TR_yes)538{539result = TR_yes;540}541else542{543TR_OpaqueClassBlock *fieldClassInCP = fieldSymRef->getOwningMethod(comp)->getClassFromFieldOrStatic(comp, fieldSymRef->getCPIndex());544if ( fieldClassInCP545&& TR_yes == comp->fej9()->isInstanceOf((TR_OpaqueClassBlock*)candidate->_class, fieldClassInCP, true))546{547// Short cut: There's no need to look up the declaring class of the548// field because we already know the candidate's class contains the549// field since it inherits the class we're using to access the field550// in the constant pool.551//552if (!debugEAFieldValidityCheck553|| performTransformation(comp, "%sQuick Using candidateHasField=yes (withinObjectBound=%s) for candidate [%p] field access [%p]\n",554OPT_DETAILS, ynmString(withinObjectBound), candidate->_node, fieldNode))555{556belongsToAllocatedClass = TR_yes;557result = TR_yes;558}559}560}561562// If we're still not sure, go ahead and try getDeclaringClassFromFieldOrStatic563//564if (result == TR_maybe)565{566TR::VMAccessCriticalSection candidateHasFieldCriticalSection(comp->fej9(),567TR::VMAccessCriticalSection::tryToAcquireVMAccess,568comp);569570if (candidateHasFieldCriticalSection.hasVMAccess())571{572TR_OpaqueClassBlock *fieldDeclaringClass = fieldSymRef->getOwningMethod(comp)->getDeclaringClassFromFieldOrStatic(comp, fieldSymRef->getCPIndex());573if (fieldDeclaringClass)574belongsToAllocatedClass = comp->fej9()->isInstanceOf((TR_OpaqueClassBlock*)candidate->_class, fieldDeclaringClass, true);575576result = ynmOr(withinObjectHeader, belongsToAllocatedClass);577578if (debugEAFieldValidityCheck)579{580if (!performTransformation(comp, "%sUsing candidateHasField=%s (withinObjectBound=%s) for candidate [%p] field access [%p]\n",581OPT_DETAILS, ynmString(result), ynmString(withinObjectBound), candidate->_node, fieldNode))582{583// Conservatively return TR_no.584// We do the performTransformation even if result is already TR_no585// just to support countOptTransformations.586//587result = TR_no;588}589}590}591else if (ea->trace())592{593traceMsg(comp, " Unable to acquire vm access; conservatively assume field [%p] does not belong to candidate [%p]\n", fieldNode, candidate->_node);594}595}596597if (debugEAFieldValidityCheck)598{599if ( (withinObjectBound != result)600&& !performTransformation(comp, "%sSubstituting candidateHasField=%s (withinObjectBound=%s) for candidate [%p] field access [%p]\n",601OPT_DETAILS, ynmString(result), ynmString(withinObjectBound), candidate->_node, fieldNode))602{603// Use old logic for debugging purposes604// Note: This is not necessarily correct, hence the env var guard.605// Once we have confidence in the newer logic, this withinObjectBound606// logic can eventually be deleted.607//608result = withinObjectBound;609}610}611612if (ea->trace())613traceMsg(comp, " Candidate [%p] field access [%p] candidateHasField=%s (withinObjectBound=%s withinObjectHeader=%s belongsToAllocatedClass=%s)\n",614candidate->_node, fieldNode,615ynmString(result),616ynmString(withinObjectBound),617ynmString(withinObjectHeader),618ynmString(belongsToAllocatedClass));619620return result;621}622623//624// Hack markers625//626627// PR 78801: Currently, BCD shadows don't have reliable size information, and628// BCD temps require size information. This makes it hard to create BCD temps629// from shadows.630//631#define CANT_CREATE_BCD_TEMPS (1)632633int32_t TR_EscapeAnalysis::performAnalysisOnce()634{635int32_t cost = 0;636Candidate *candidate, *next;637638if (trace())639{640traceMsg(comp(), "Starting Escape Analysis pass %d\n", manager()->numPassesCompleted());641comp()->dumpMethodTrees("Trees before Escape Analysis");642}643644_useDefInfo = NULL; // Build these only if required645_invalidateUseDefInfo = false;646_valueNumberInfo = NULL;647_otherDefsForLoopAllocation = NULL;648_methodSymbol = NULL;649_nodeUsesThroughAselect = NULL;650_repeatAnalysis = false;651_somethingChanged = false;652_inBigDecimalAdd = false;653_candidates.setFirst(NULL);654_inlineCallSites.deleteAll();655_dependentAllocations.deleteAll();656_fixedVirtualCallSites.setFirst(NULL);657658_parms = NULL;659_ignoreableUses = NULL;660_nonColdLocalObjectsValueNumbers = NULL;661_allLocalObjectsValueNumbers = NULL;662_visitedNodes = NULL;663_aliasesOfAllocNode = NULL;664_aliasesOfOtherAllocNode = NULL;665_notOptimizableLocalObjectsValueNumbers = NULL;666_notOptimizableLocalStringObjectsValueNumbers = NULL;667668// Walk the trees and find the "new" nodes.669// Any that are candidates for local allocation or desynchronization are670// added to the list of candidates.671//672findCandidates();673cost++;674675if (!_candidates.isEmpty())676{677_useDefInfo = optimizer()->getUseDefInfo();678_blocksWithFlushOnEntry = new (trStackMemory()) TR_BitVector(comp()->getFlowGraph()->getNextNodeNumber(), trMemory(), stackAlloc);679_visitedNodes = new (trStackMemory()) TR_BitVector(comp()->getNodeCount(), trMemory(), stackAlloc, growable);680_aliasesOfAllocNode =681_doLoopAllocationAliasChecking682? new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable) : NULL;683_aliasesOfOtherAllocNode =684_doLoopAllocationAliasChecking685? new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable) : NULL;686687if (!_useDefInfo)688{689if (trace())690traceMsg(comp(), "Can't do Escape Analysis, no use/def information\n");691_candidates.setFirst(NULL);692}693694_valueNumberInfo = optimizer()->getValueNumberInfo();695if (!_valueNumberInfo)696{697if (trace())698traceMsg(comp(), "Can't do Escape Analysis, no value number information\n");699_candidates.setFirst(NULL);700}701else702{703_ignoreableUses = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc);704_nonColdLocalObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);705_allLocalObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);706_notOptimizableLocalObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);707_notOptimizableLocalStringObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);708}709}710711if ( !_candidates.isEmpty())712{713findLocalObjectsValueNumbers();714findIgnoreableUses();715}716717// Complete the candidate info by finding all uses and defs that are reached718// from each candidate.719//720if (!_candidates.isEmpty())721{722checkDefsAndUses();723cost++;724}725726if (trace())727printCandidates("Initial candidates");728729// Look through the trees to see which candidates escape the method. This730// may involve sniffing into called methods.731//732_sniffDepth = 0;733_parms = NULL;734if (!_candidates.isEmpty())735{736//if (comp()->getMethodSymbol()->mayContainMonitors())737if (cg()->getEnforceStoreOrder())738{739TR_FlowSensitiveEscapeAnalysis flowSensitiveAnalysis(comp(), optimizer(), comp()->getFlowGraph()->getStructure(), this);740}741742bool ignoreRecursion = false;743checkEscape(comp()->getStartTree(), false, ignoreRecursion);744cost++;745}746747//fixup those who have virtual calls748for (candidate = _candidates.getFirst(); candidate; candidate = next)749{750next = candidate->getNext();751752if (!candidate->isLocalAllocation())753continue;754755if (!candidate->hasVirtualCallsToBeFixed())756continue;757758dumpOptDetails(comp(), "Fixup indirect calls sniffed for candidate =%p\n",candidate->_node);759TR::TreeTop *callSite, *callSiteNext = NULL;760761ListIterator<TR::TreeTop> it(candidate->getVirtualCallSitesToBeFixed());762for (callSite = it.getFirst(); callSite; callSite = callSiteNext)763{764//TR::TreeTop *directCallTree = findCallSiteFixed(callSite);765bool found = findCallSiteFixed(callSite);766callSiteNext = it.getNext();767if (!found)768{769if (!_devirtualizedCallSites.find(callSite))770_devirtualizedCallSites.add(callSite);771772_fixedVirtualCallSites.add(new (trStackMemory()) TR_EscapeAnalysis::TR_CallSitesFixedMapper(callSite, NULL));773dumpOptDetails(comp(), "adding Map:vCall = %p direct = %p\n",callSite, NULL);774_repeatAnalysis = true;775_somethingChanged = true;776777candidate->getCallSites()->remove(callSite);778//candidate->getCallSites()->add(directCallTree);779}780else781{782dumpOptDetails(comp(), "found MAp for %p\n",callSite);783//fixup the callSite list784candidate->getCallSites()->remove(callSite);785//candidate->getCallSites()->add(directCallTree);786}787}788789candidate->setLocalAllocation(false);790if (trace())791traceMsg(comp(), " Make [%p] non-local because we'll try it again in another pass\n", candidate->_node);792793}794795//fixup those callSite which were devirtualize796//fixup the coldBlockInfo too797for (candidate = _candidates.getFirst(); candidate; candidate = next)798{799next = candidate->getNext();800if (!candidate->isLocalAllocation())801continue;802803TR::TreeTop *callSite, *callSiteNext = NULL;804805ListIterator<TR::TreeTop> it(candidate->getCallSites());806for (callSite = it.getFirst(); callSite; callSite = callSiteNext)807{808callSiteNext = it.getNext();809//TR::TreeTop *directCallTree = findCallSiteFixed(callSite);810bool found = findCallSiteFixed(callSite);811if (found)812{813if (trace())814traceMsg(comp(), "replacing callsite %p for candidate %p with it's direct call\n",callSite,candidate->_node);815candidate->getCallSites()->remove(callSite);816candidate->setLocalAllocation(false);817//candidate->getCallSites()->add(directCallTree);818}819}820821ListIterator<TR_ColdBlockEscapeInfo> coldBlockInfoIt(candidate->getColdBlockEscapeInfo());822for (TR_ColdBlockEscapeInfo *info = coldBlockInfoIt.getFirst(); info != NULL; info = coldBlockInfoIt.getNext())823{824ListIterator<TR::TreeTop> treesIt(info->getTrees());825for (TR::TreeTop *escapeTree = treesIt.getFirst(); escapeTree != NULL; escapeTree = treesIt.getNext())826{827if (findCallSiteFixed(escapeTree))828{829candidate->setLocalAllocation(false);830break;831}832}833if (!candidate->isLocalAllocation())834break;835}836}837838// Check whether tentative dememoization can proceed839//840bool shouldRepeatDueToDememoization = false;841for (candidate = _candidates.getFirst(); candidate; candidate = next)842{843next = candidate->getNext();844845if (candidate->_dememoizedConstructorCall)846{847if ( candidate->isLocalAllocation()848&& !candidate->mustBeContiguousAllocation()849&& candidate->getCallSites()->isSingleton()850&& candidate->getCallSites()->find(candidate->_dememoizedConstructorCall)851&& performTransformation(comp(), "%sDememoizing [%p]\n", OPT_DETAILS, candidate->_node))852{853// Dememoization worked!854// Inline the constructor and catch this candidate on the next pass855candidate->setLocalAllocation(false);856857if (trace())858traceMsg(comp(), "2 setting local alloc %p to false\n", candidate->_node);859860_inlineCallSites.add(candidate->_dememoizedConstructorCall);861_repeatAnalysis = true;862}863else864{865// Dememoization failed on this pass; must re-memoize instead866867bool mayDememoizeNextTime = true;868869// allow the call to be inlined at least in the last pass870// and prevent from dememoizing the call again871//872if (candidate->isLocalAllocation())873_repeatAnalysis = true;874875if (_repeatAnalysis)876{877if (manager()->numPassesCompleted() == _maxPassNumber-1)878mayDememoizeNextTime = false;879else880shouldRepeatDueToDememoization = true;881}882else883mayDememoizeNextTime = false;884885if (trace())886{887traceMsg(comp(), " Fail [%p] because dememoization failed; will%s attempt again on next EA pass\n", candidate->_node, mayDememoizeNextTime? "":" NOT");888traceMsg(comp(), " Fail [%p] because dememoization failed; will%s attempt dememoization again on next EA pass\n", candidate->_node, mayDememoizeNextTime? "":" NOT");889traceMsg(comp(), " 4 booleans are %d %d %d %d\n", candidate->isLocalAllocation(), candidate->mustBeContiguousAllocation(), candidate->getCallSites()->isSingleton(), candidate->getCallSites()->find(candidate->_dememoizedConstructorCall));890}891892// if mayDememoizeNextTime is false, then the following call to893// rememoize will add valueOf to the list of calls to be inlined894//895rememoize(candidate, mayDememoizeNextTime);896if (trace())897traceMsg(comp(), "8 removing cand %p to false\n", candidate->_node);898}899_candidates.remove(candidate);900}901}902903// Decide whether or not another pass of escape analysis is appropriate.904// If we are allowed to do another pass and there are candidates which are905// contiguous only because they are arguments to calls and those calls can906// be inlined, then inline the calls and mark the candidates so that they907// are not replaced in this pass.908// This should result in the candidates being found to be non-contiguous909// candidates in a later pass.910//911if (manager()->numPassesCompleted() < _maxPassNumber)912{913for (candidate = _candidates.getFirst(); candidate; candidate = next)914{915next = candidate->getNext();916if (!candidate->isLocalAllocation())917continue;918919if (trace())920traceMsg(comp(), " 0 Look at [%p] must be %d\n", candidate->_node, candidate->mustBeContiguousAllocation());921922if (candidate->mustBeContiguousAllocation() || !candidate->hasCallSites() ||923(candidate->_stringCopyNode && (candidate->_stringCopyNode != candidate->_node) &&924!candidate->escapesInColdBlocks() &&925!candidate->isLockedObject() &&926!candidate->_seenSelfStore &&927!candidate->_seenStoreToLocalObject))928continue;929930931if (trace())932traceMsg(comp(), " 0.5 Look at [%p]\n", candidate->_node);933934// If any of the call sites for this parm is a guarded virtual call - there would be nothing935// gained by inlining any of them - we will still end up with a call and will have to make936// it contiguous937//938TR::TreeTop *callSite;939bool seenGuardedCall = false;940ListIterator<TR::TreeTop> it(candidate->getCallSites());941for (callSite = it.getFirst(); callSite; callSite = it.getNext())942{943TR::Node *callNode = callSite->getNode();944if (callNode->isTheVirtualCallNodeForAGuardedInlinedCall())945{946seenGuardedCall = true;947break;948}949}950951if (trace())952traceMsg(comp(), " 1 Look at [%p]\n", candidate->_node);953954// If any of the calls is a guarded virtual call or955// If the depth of inlining required is greater than the number of956// passes left, or if the number of bytecodes needed to be inlined957// will exceed the maximum, enough inlining can't be done.958// In this case force the candidate to be contiguous.959//960if (seenGuardedCall ||961candidate->_maxInlineDepth >= (_maxPassNumber-manager()->numPassesCompleted()) ||962candidate->_inlineBytecodeSize > (_maxInlinedBytecodeSize-getOptData()->_totalInlinedBytecodeSize))963{964candidate->setMustBeContiguousAllocation();965if (trace())966traceMsg(comp(), " Make [%p] contiguous because we can't inline enough\n", candidate->_node);967continue;968}969970// Take each call site that needs to be inlined and add it to the971// list of inlined call sites972//973while ((callSite = candidate->getCallSites()->popHead()))974{975TR::Node *node = callSite->getNode();976if (node->getOpCode().isTreeTop())977node = node->getFirstChild();978979//traceMsg(comp(), "For alloc node %p call site %p\n", candidate->_node, node);980//if (node->isTheVirtualCallNodeForAGuardedInlinedCall())981if (!_inlineCallSites.find(callSite))982{983if (comp()->getMethodHotness() <= warm)984{985// Up to warm, inlining at this point can interfere with existing986// profiling and compilation heuristics, causing us to miss even987// better inlining opportunities in subsequent hot and scorching988// compiles. Only inline selected methods where the benefit of989// profiling heuristics is outweighed by the cost of not inlining990// at warm.991//992// TODO: There must be a similar heuristic in the inliner for this993// sort of thing? They ought to share code.994//995switch (node->getSymbol()->castToMethodSymbol()->getRecognizedMethod())996{997case TR::java_lang_Object_init:998break;999default:1000candidate->setMustBeContiguousAllocation();1001if (trace())1002traceMsg(comp(), " Make [%p] contiguous because we can't inline it at %s\n", candidate->_node, comp()->getHotnessName());1003continue;1004}1005}10061007_inlineCallSites.add(callSite);1008}1009}10101011_repeatAnalysis = true;1012candidate->setLocalAllocation(false);1013if (trace())1014traceMsg(comp(), " Make [%p] non-local because we'll try it again in another pass\n", candidate->_node);1015}1016}10171018// Apply filters to candidates1019//1020for (candidate = _candidates.getFirst(); candidate; candidate = next)1021{1022next = candidate->getNext();10231024if (candidate->_kind == TR::New)1025{1026static bool doEAOpt = feGetEnv("TR_DisableEAOpt") ? false : true;1027if (!doEAOpt &&1028comp()->useCompressedPointers())1029{1030if (candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)1031{1032candidate->setLocalAllocation(false);1033if (trace())1034traceMsg(comp(), " Make [%p] non-local because self store seen in compressed pointers mode\n", candidate->_node);1035}1036}10371038if ( CANT_CREATE_BCD_TEMPS1039&& candidate->isLocalAllocation()1040&& !candidate->isContiguousAllocation()1041&& candidate->_fields)1042{1043for (int32_t i = candidate->_fields->size()-1; i >= 0; i--)1044{1045TR::SymbolReference *field = candidate->_fields->element(i).fieldSymRef();1046if (field && field->getSymbol()->getDataType().isBCD())1047{1048candidate->setMustBeContiguousAllocation();1049if (trace())1050traceMsg(comp(), " Make [%p] contiguous because we can't create temp for BCD field #%d\n", candidate->_node, field->getReferenceNumber());1051break;1052}1053}1054}10551056if (candidate->isLocalAllocation() && candidate->isContiguousAllocation())1057{1058if (!_createLocalObjects)1059{1060candidate->setLocalAllocation(false);1061if (trace())1062traceMsg(comp(), " Make [%p] non-local because we can't create local objects\n", candidate->_node);1063}1064}106510661067if (candidate->isLocalAllocation() &&1068candidate->escapesInColdBlocks() &&1069(candidate->isLockedObject() ||1070candidate->_seenSelfStore ||1071candidate->_seenStoreToLocalObject))1072{1073candidate->setLocalAllocation(false);1074if (trace())1075traceMsg(comp(), " Make [%p] non-local because we can't have locking when candidate escapes in cold blocks\n", candidate->_node);1076}10771078// Value type fields of objects created with a NEW bytecode must be initialized1079// with their default values. EA is not yet set up to perform such iniitialization1080// if the value type's own fields have not been inlined into the class that1081// has a field of that type, so remove the candidate from consideration.1082if (candidate->_kind == TR::New)1083{1084TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock *)candidate->_node->getFirstChild()->getSymbol()->getStaticSymbol()->getStaticAddress();10851086if (!TR::Compiler->cls.isZeroInitializable(clazz))1087{1088if (trace())1089traceMsg(comp(), " Fail [%p] because the candidate is not zero initializable (that is, it has a field of a value type whose fields have not been inlined into this candidate's class)\n", candidate->_node);1090rememoize(candidate);1091_candidates.remove(candidate);1092continue;1093}1094}10951096// If a contiguous candidate has reference slots, then stack-allocating it means putting1097// stores in the first block of the method. If the first block is really hot, those stores1098// are expensive, and stack-allocation is probably not worthwhile.1099//1100bool objectHasReferenceFields = false;1101#if LOCAL_OBJECTS_COLLECTABLE1102switch (candidate->_kind)1103{1104case TR::New:1105if (comp()->fej9()->getReferenceSlotsInClass(comp(), (TR_OpaqueClassBlock *)candidate->_node->getFirstChild()->getSymbol()->getStaticSymbol()->getStaticAddress()))1106objectHasReferenceFields = true;1107break;1108case TR::anewarray:1109objectHasReferenceFields = true;1110break;1111default:1112break;1113}1114#endif1115if (candidate->isLocalAllocation() &&1116(candidate->isInAColdBlock() ||1117( objectHasReferenceFields1118&& candidate->isContiguousAllocation()1119&& (comp()->getStartBlock()->getFrequency() > 4*candidate->_block->getFrequency())))1120&& !candidate->usedInNonColdBlock())1121//((candidate->isContiguousAllocation() && !candidate->lockedInNonColdBlock()) ||1122// (!candidate->isContiguousAllocation() && !candidate->usedInNonColdBlock())))1123{1124candidate->setLocalAllocation(false);1125if (trace())1126traceMsg(comp(), " Make [%p] non-local because the uses are not in hot enough blocks\n", candidate->_node);1127}11281129// If the candidate has more than one value number, and a suspicious1130// field, reject the candidate to preserve r13 behaviour. For1131// candidates with one value number, we can reach definite conclusions1132// about what to do with them because there's only one possibility.1133// (They're usually non-contiguous.)1134//1135if (candidate->_valueNumbers->size()> 1 && candidate->_fields)1136{1137for (int32_t i = candidate->_fields->size()-1; i >= 0; i--)1138{1139if (candidate->_fields->element(i).hasBadFieldSymRef())1140{1141if (trace())1142traceMsg(comp(), " Fail [%p] because candidate is dereferenced via a field that does not belong to allocated class\n", candidate->_node);1143rememoize(candidate);1144_candidates.remove(candidate);1145break;1146}1147}1148}11491150if (candidate->_stringCopyNode && (candidate->_stringCopyNode != candidate->_node))1151{1152if (!candidate->escapesInColdBlocks() &&1153!candidate->isLockedObject() &&1154!candidate->_seenSelfStore &&1155!candidate->_seenStoreToLocalObject)1156candidate->setMustBeContiguousAllocation();1157else1158candidate->_stringCopyNode = NULL;1159}11601161if (candidate->_dememoizedMethodSymRef && candidate->isContiguousAllocation())1162{1163if (trace())1164traceMsg(comp(), " Fail [%p] because dememoized allocations must be non-contiguous\n", candidate->_node);1165rememoize(candidate);1166_candidates.remove(candidate);1167}11681169continue;1170}11711172if (candidate->_kind == TR::anewarray)1173{1174// Array Candidates for contiguous allocation that have unresolved1175// base classes must be rejected, since we cannot initialize the array1176// header. If the component type is a value type, reject the array1177// as we can't initialize the elements to the default value yet.1178//1179if (candidate->isContiguousAllocation())1180{1181TR::Node *classNode = candidate->_node->getSecondChild();1182if (classNode->getOpCodeValue() != TR::loadaddr ||1183classNode->getSymbolReference()->isUnresolved())1184{1185if (trace())1186traceMsg(comp(), " Fail [%p] because base class is unresolved\n", candidate->_node);1187rememoize(candidate);1188_candidates.remove(candidate);1189}1190else1191{1192TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock*)classNode->getSymbol()->castToStaticSymbol()->getStaticAddress();11931194if (TR::Compiler->cls.isValueTypeClass(clazz))1195{1196if (trace())1197traceMsg(comp(), " Fail [%p] because array has value type elements\n", candidate->_node);1198rememoize(candidate);1199_candidates.remove(candidate);1200}1201}1202}1203}12041205if (candidate->isProfileOnly() && candidate->isLocalAllocation())1206{1207candidate->setLocalAllocation(false);12081209if (trace())1210traceMsg(comp(), "3 setting local alloc %p to false\n", candidate->_node);12111212if (performTransformation(comp(), "%sInitiate value profiling for length of %s [%p]\n",OPT_DETAILS,1213candidate->_node->getOpCode().getName(),1214candidate->_node))1215{1216if (optimizer()->switchToProfiling())1217{1218TR::Recompilation *recomp = comp()->getRecompilationInfo();1219TR_ValueProfiler *valueProfiler = recomp? recomp->getValueProfiler() : NULL;1220TR::Node *numElementsNode = candidate->_node->getFirstChild();12211222TR_ByteCodeInfo originalBcInfo = TR_ProfiledNodeVersioning::temporarilySetProfilingBcInfoOnNewArrayLengthChild(candidate->_node, comp());1223valueProfiler->addProfilingTrees(numElementsNode, candidate->_treeTop, 5);1224numElementsNode->setByteCodeInfo(originalBcInfo);1225}1226else if (trace())1227{1228traceMsg(comp(), " Unable to switch to profiling mode; no profiling trees added for [%p]\n", candidate->_node);1229}1230}1231}12321233// Remove all array candidates that are not locally allocatable1234//1235if (!candidate->isLocalAllocation())1236{1237if (trace())1238traceMsg(comp(), " Fail [%p] array candidate is not locally allocatable\n", candidate->_node);1239rememoize(candidate);1240_candidates.remove(candidate);1241continue;1242}1243}12441245// Check for size limits on total object allocation size.1246//1247if (!_candidates.isEmpty())1248{1249checkObjectSizes();1250cost++;1251}12521253if (trace())1254printCandidates("Final candidates");12551256// When we do stack allocation we generate number of stores1257// in the first block of the method, so that we can initialize the1258// stack allocated object correctly. However, if the first block ends up1259// being in a loop, those stores end up resetting the stack allocated object1260// even though the new might be under an if later on.1261if (comp()->getStartBlock() && !_candidates.isEmpty())1262{1263TR::Block *block = comp()->getStartBlock();12641265if (blockIsInLoop(block))1266{1267comp()->getFlowGraph()->setStructure(NULL);1268TR::Block *firstBlockReplacement = toBlock(comp()->getFlowGraph()->addNode(1269TR::Block::createEmptyBlock(block->getEntry()->getNode(), comp(), std::max(MAX_COLD_BLOCK_COUNT+1, block->getFrequency()/10))));1270firstBlockReplacement->getExit()->join(block->getEntry());1271comp()->setStartTree(firstBlockReplacement->getEntry());12721273TR::CFGEdge *edgeToRemove = comp()->getFlowGraph()->getStart()->asBlock()->getSuccessors().front();12741275comp()->getFlowGraph()->addEdge(TR::CFGEdge::createEdge(comp()->getFlowGraph()->getStart()->asBlock(), firstBlockReplacement, trMemory()));1276comp()->getFlowGraph()->addEdge(TR::CFGEdge::createEdge(firstBlockReplacement, block, trMemory()));12771278comp()->getFlowGraph()->removeEdge(edgeToRemove);1279}1280}12811282// Now each remaining candidate is known not to escape the method.1283// All synchronizations on the objects can be removed, and those1284// marked for local allocation can be locally allocated.1285// Go through the trees one more time, fixing up loads and stores for1286// the object.1287//1288if (!_candidates.isEmpty())1289{1290fixupTrees();1291cost++;1292}12931294int32_t nonContiguousAllocations = 0;1295int32_t tempsCreatedForColdEscapePoints = 0;12961297// Now fix up the new nodes themselves and insert any initialization code1298// that is necessary.1299//1300for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())1301{1302if (candidate->isLocalAllocation())1303{1304if (performTransformation(comp(), "%sStack allocating candidate [%p]\n",OPT_DETAILS, candidate->_node))1305{1306//printf("stack allocation in %s %s\n",comp()->signature(),comp()->getHotnessName(comp()->getMethodHotness()));fflush(stdout);13071308if (candidate->isContiguousAllocation())1309{1310if (candidate->_stringCopyNode && (candidate->_stringCopyNode != candidate->_node))1311avoidStringCopyAllocation(candidate);1312else1313makeContiguousLocalAllocation(candidate);1314}1315else1316{1317makeNonContiguousLocalAllocation(candidate);1318++nonContiguousAllocations;1319}13201321if (candidate->escapesInColdBlocks())1322{1323heapifyForColdBlocks(candidate);1324if (candidate->_fields)1325{1326int32_t i;1327for (i = candidate->_fields->size()-1; i >= 0; i--)1328{1329if (((*candidate->_fields)[i]._symRef == NULL) &&1330!(*candidate->_fields)[i].hasBadFieldSymRef())1331{1332//printf("Conservative aliasing reqd in %s\n", comp()->signature()); fflush(stdout);1333comp()->getSymRefTab()->aliasBuilder.setConservativeGenericIntShadowAliasing(true);1334}1335}1336}1337else1338comp()->getSymRefTab()->aliasBuilder.setConservativeGenericIntShadowAliasing(true);13391340tempsCreatedForColdEscapePoints++;1341}13421343if (candidate->_seenFieldStore)1344_repeatAnalysis = true;134513461347_somethingChanged = true;1348}1349}1350}13511352_somethingChanged |= devirtualizeCallSites();13531354// If there are any call sites to be inlined, do it now1355//1356_somethingChanged |= inlineCallSites();13571358// Use/def and value number information must be recalculated for later1359// optimization passes.1360//1361if (_somethingChanged || _invalidateUseDefInfo)1362{1363optimizer()->setUseDefInfo(NULL);1364_useDefInfo = NULL;1365}1366if (_somethingChanged)1367{1368optimizer()->setValueNumberInfo(NULL);1369requestOpt(OMR::treeSimplification);1370requestOpt(OMR::globalValuePropagation);1371}1372else1373{1374if (!shouldRepeatDueToDememoization)1375_repeatAnalysis = false;1376else1377{1378// fast forward the current pass to the n-2th pass because1379// in performAnalysisOnce, _currentPass is inc'ed before1380// calling EA again1381// (we really want to inline in the n-1th pass)1382manager()->setNumPassesCompleted(_maxPassNumber-2);1383_repeatAnalysis = true; // should already be true, just being paranoid1384}1385}13861387// If we created non-contiguous allocations, and the method contains1388// catch blocks, the alias sets must be marked as non-valid.1389//1390if ((nonContiguousAllocations > 0) ||1391(tempsCreatedForColdEscapePoints > 0))1392{1393bool containsCatchBlocks = false;1394for (TR::CFGNode *node = comp()->getFlowGraph()->getFirstNode(); !containsCatchBlocks && node; node = node->getNext())1395if (!((TR::Block *)node)->getExceptionPredecessors().empty())1396containsCatchBlocks = true;13971398if (containsCatchBlocks)1399optimizer()->setAliasSetsAreValid(false);1400}140114021403if (trace())1404{1405comp()->dumpMethodTrees("Trees after Escape Analysis");1406traceMsg(comp(), "Ending Escape Analysis");1407}14081409return cost; // actual cost1410}14111412void TR_EscapeAnalysis::findIgnoreableUses()1413{1414if (comp()->getOSRMode() != TR::voluntaryOSR)1415return;14161417TR::NodeChecklist visited(comp());1418bool inOSRCodeBlock = false;14191420// Gather all uses under fake prepareForOSR calls - they will be tracked as ignoreable1421for (TR::TreeTop *treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())1422{1423if (treeTop->getNode()->getOpCodeValue() == TR::BBStart)1424inOSRCodeBlock = treeTop->getNode()->getBlock()->isOSRCodeBlock();1425else if (inOSRCodeBlock1426&& treeTop->getNode()->getNumChildren() > 01427&& treeTop->getNode()->getFirstChild()->getOpCodeValue() == TR::call1428&& treeTop->getNode()->getFirstChild()->getSymbolReference()->getReferenceNumber() == TR_prepareForOSR)1429{1430TR::Node *callNode = treeTop->getNode()->getFirstChild();1431for (int i = 0; i < callNode->getNumChildren(); ++i)1432findIgnoreableUses(callNode->getChild(i), visited);1433}1434}1435}14361437void TR_EscapeAnalysis::findIgnoreableUses(TR::Node *node, TR::NodeChecklist &visited)1438{1439if (visited.contains(node))1440return;1441visited.add(node);1442if (trace())1443traceMsg(comp(), "Marking n%dn as an ignoreable use\n", node->getGlobalIndex());1444_ignoreableUses->set(node->getGlobalIndex());14451446int32_t i;1447for (i = 0; i < node->getNumChildren(); i++)1448{1449TR::Node *child = node->getChild(i);1450findIgnoreableUses(child, visited);1451}1452}14531454void TR_EscapeAnalysis::findLocalObjectsValueNumbers()1455{1456TR::NodeChecklist visited(comp());1457TR::TreeTop *treeTop;14581459for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())1460{1461TR::Node *node = treeTop->getNode();1462findLocalObjectsValueNumbers(node, visited);1463}1464}14651466void TR_EscapeAnalysis::findLocalObjectsValueNumbers(TR::Node *node, TR::NodeChecklist& visited)1467{1468if (visited.contains(node))1469return;1470visited.add(node);14711472if (node->getOpCode().hasSymbolReference() &&1473node->getSymbolReference()->getSymbol()->isLocalObject())1474{1475_allLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));1476if (!node->escapesInColdBlock())1477{1478_nonColdLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));1479if (node->cannotTrackLocalUses())1480{1481if (!_notOptimizableLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(node)))1482{1483//dumpOptDetails(comp(), "Local object %p value number %d detected\n", node, _valueNumberInfo->getValueNumber(node));14841485_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));1486}14871488if (node->cannotTrackLocalStringUses())1489{1490if (!_notOptimizableLocalStringObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(node)))1491{1492//dumpOptDetails(comp(), "Local object %p value number %d detected\n", node, _valueNumberInfo->getValueNumber(node));14931494_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));1495}1496}1497}1498}1499}15001501int32_t i;1502for (i = 0; i < node->getNumChildren(); i++)1503{1504TR::Node *child = node->getChild(i);1505findLocalObjectsValueNumbers(child, visited);1506}1507}150815091510void TR_EscapeAnalysis::findCandidates()1511{1512TR::NodeChecklist visited (comp());1513int32_t i;1514bool foundUserAnnotation=false;1515const char *className = NULL;1516for (_curTree = comp()->getStartTree(); _curTree; _curTree = _curTree->getNextTreeTop())1517{1518TR::Node *node = _curTree->getNode();15191520if (visited.contains(node))1521continue;1522visited.add(node);15231524if (node->getOpCodeValue() == TR::BBStart)1525{1526_curBlock = node->getBlock();1527continue;1528}15291530if (!node->getNumChildren())1531continue;15321533node = node->getFirstChild();15341535if (visited.contains(node))1536continue;1537visited.add(node);15381539if (node->getOpCode().isNew() && node->isHeapificationAlloc())1540{1541if (trace())1542traceMsg(comp(), "Reject candidate %s n%dn [%p] because it is for heapification\n", node->getOpCode().getName(), node->getGlobalIndex(), node);1543continue;1544}15451546TR::SymbolReference *dememoizedMethodSymRef = NULL;1547TR::TreeTop *dememoizedConstructorCall = NULL;1548if (!comp()->fej9()->callTargetsNeedRelocations() && node->getOpCodeValue() == TR::acall1549&& node->getSymbol()->getMethodSymbol()->getRecognizedMethod() == TR::java_lang_Integer_valueOf1550&& !node->isTheVirtualCallNodeForAGuardedInlinedCall()1551&& manager()->numPassesCompleted() < _maxPassNumber)1552{1553// Dememoization: Let's look for a constructor call we could use instead1554//1555_dememoizationSymRef = node->getSymbolReference();15561557if (trace()) traceMsg(comp(), "Attempt dememoize on %p\n", node);1558TR_OpaqueMethodBlock *constructor = comp()->getOption(TR_DisableDememoization)? NULL : comp()->fej9()->getMethodFromName("java/lang/Integer", "<init>", "(I)V");1559if ( constructor1560&& performTransformation(comp(), "%sTry dememoizing %p\n", OPT_DETAILS, node))1561{1562// Replace this call with a allocation+constructor and hope for the best.1563//1564// NOTE! This is not actually correct unless subsequent analysis1565// can prove it's correct; if it's not, we must rememoize this.1566//1567dememoizedMethodSymRef = node->getSymbolReference();1568TR::SymbolReference *constructorSymRef = comp()->getSymRefTab()->findOrCreateMethodSymbol(JITTED_METHOD_INDEX, -1,1569comp()->fej9()->createResolvedMethod(trMemory(), constructor), TR::MethodSymbol::Special);1570dememoizedConstructorCall = TR::TreeTop::create(comp(), _curTree,1571TR::Node::create(TR::treetop, 1,1572TR::Node::createWithSymRef(TR::call, 2, 2,1573node,1574node->getFirstChild(),1575constructorSymRef)));1576node->getFirstChild()->decReferenceCount();1577node->setAndIncChild(0,1578TR::Node::createWithSymRef(node, TR::loadaddr, 0,1579comp()->getSymRefTab()->findOrCreateClassSymbol(comp()->getMethodSymbol(), -1,1580comp()->fej9()->getClassFromSignature("java/lang/Integer", 17, comp()->getCurrentMethod(), true))));1581TR::Node::recreate(node, TR::New);1582if (!_dememoizedAllocs.find(node))1583_dememoizedAllocs.add(node);1584node->setSymbolReference(comp()->getSymRefTab()->findOrCreateNewObjectSymbolRef(comp()->getMethodSymbol()));1585}1586}158715881589if (node->getOpCodeValue() != TR::New &&1590node->getOpCodeValue() != TR::newarray &&1591node->getOpCodeValue() != TR::anewarray)1592continue;15931594static char *noEscapeArrays = feGetEnv("TR_NOESCAPEARRAY");1595if (noEscapeArrays)1596{1597if (node->getOpCodeValue() != TR::New)1598continue;1599}160016011602// Found a "new" opcode. See if it is a candidate for local allocation.1603//1604//1605bool inAColdBlock = false;1606if (_curBlock->isCold() ||1607_curBlock->isCatchBlock() ||1608(_curBlock->getFrequency() == (MAX_COLD_BLOCK_COUNT+1)))1609inAColdBlock = true;16101611if (trace())1612{1613if (node->getOpCodeValue() == TR::New)1614{1615const char *className = getClassName(node->getFirstChild());1616traceMsg(comp(), "Found [%p] new %s\n", node,1617className ? className : "<Missing class name>");1618}1619else if (node->getOpCodeValue() == TR::newarray)1620traceMsg(comp(), "Found [%p] newarray of type %d\n", node, node->getSecondChild()->getInt());1621else1622{1623const char *className = getClassName(node->getSecondChild());1624traceMsg(comp(), "Found [%p] anewarray %s\n", node,1625className ? className : "<Missing class name>");1626}1627}16281629foundUserAnnotation=false;16301631// Make this a candidate for local allocation and/or desynchronization.1632// Checks for escape are done after the candidates have been collected.1633//1634TR_OpaqueClassBlock *classInfo = 0;1635Candidate *candidate = createCandidateIfValid(node, classInfo,foundUserAnnotation);1636if (!candidate)1637continue;1638if (dememoizedConstructorCall)1639{1640candidate->_dememoizedMethodSymRef = dememoizedMethodSymRef;1641candidate->_dememoizedConstructorCall = dememoizedConstructorCall;1642//candidate->setObjectIsReferenced();1643candidate->getCallSites()->add(dememoizedConstructorCall);1644}16451646// candidate->_size is:1647// -1 if it is not a valid candidate.1648// 0 if it is a valid candidate for desynchronizing only.1649// allocation size otherwise.1650//1651candidate->setLocalAllocation(_createStackAllocations && (candidate->_size > 0));1652if (trace())1653traceMsg(comp(), "4 setting local alloc %p to %s\n", candidate->_node, candidate->isLocalAllocation()? "true":"false");16541655if(foundUserAnnotation)1656{1657candidate->setForceLocalAllocation(true);1658candidate->setObjectIsReferenced();1659if (trace())1660traceMsg(comp(), " Force [%p] to be locally allocated due to annotation of %s\n", node, className);1661}16621663if (candidate->isLocalAllocation())1664{1665if (node->getSymbolReference() == _newObjectNoZeroInitSymRef ||1666node->getSymbolReference() == _newArrayNoZeroInitSymRef ||1667node->getSymbolReference() == _aNewArrayNoZeroInitSymRef)1668{1669candidate->setExplicitlyInitialized();1670}16711672if (blockIsInLoop(_curBlock))1673candidate->setInsideALoop();16741675if (inAColdBlock)1676candidate->setInAColdBlock(true);1677}167816791680_candidates.add(candidate);1681}16821683if (trace())1684{1685comp()->dumpMethodTrees("Trees after finding candidates");1686}1687}168816891690Candidate *TR_EscapeAnalysis::createCandidateIfValid(TR::Node *node, TR_OpaqueClassBlock *&classInfo,bool foundUserAnnotation)1691{1692// If user has annotated this objects class, force it to be on the stack1693if(!foundUserAnnotation)1694{1695// The only case where an object allocation can automatically escape is when1696// it implements the "Runnable" interface. Check for that first and dismiss1697// it immediately. If the class is unresolved, we don't know so we have to1698// assume the worst.1699//1700if (node->getOpCodeValue() == TR::New)1701{1702TR::Node *classNode = node->getFirstChild();1703if (classNode->getOpCodeValue() != TR::loadaddr)1704{1705if (trace())1706traceMsg(comp(), " Node [%p] failed: child is not TR::loadaddr\n", node);1707return NULL;1708}17091710if (classNode->getSymbolReference()->isUnresolved())1711{1712if (trace())1713traceMsg(comp(), " Node [%p] failed: class is unresolved\n", node);1714return NULL;1715}17161717TR::StaticSymbol *classSym = classNode->getSymbol()->castToStaticSymbol();17181719// Removed assume, does not make sense when doing aot -- ALI1720// TR_ASSERT(comp()->getRunnableClassPointer(), "Need access to java/lang/Runnable");1721if (comp()->getRunnableClassPointer() &&1722comp()->fej9()->isInstanceOf((TR_OpaqueClassBlock *)classSym->getStaticAddress(), comp()->getRunnableClassPointer(), true) == TR_yes)1723{1724if (trace())1725{1726const char *className = getClassName(classNode);1727traceMsg(comp(), "secs Class %s implements Runnable in %s\n",1728className ? className : "<Missing class name>",1729comp()->signature());1730traceMsg(comp(), " Node [%p] failed: class implements the Runnable interface\n", node);1731}1732return NULL;1733}1734}1735// Don't convert double-word arrays if platform does not have double-word aligned stacks1736// will handle stack alignment later1737else if (!comp()->cg()->getHasDoubleWordAlignedStack() &&1738node->getOpCodeValue() == TR::newarray && !comp()->getOption(TR_EnableSIMDLibrary))1739{1740TR::Node *typeNode = node->getSecondChild();1741if (typeNode->getInt() == 7 || typeNode->getInt() == 11)1742{1743if (trace())1744traceMsg(comp(), " Node [%p] failed: double-size array\n", node);1745return NULL;1746}1747}1748}174917501751if (comp()->cg()->getSupportsStackAllocationOfArraylets())1752{1753if (node->getOpCodeValue() != TR::New)1754{1755if (trace())1756traceMsg(comp(), " Node [%p] failed: arraylet\n", node);17571758return NULL;1759}1760}17611762bool profileOnly = false;17631764// See if the VM thinks it is valid to eliminate this allocation node. If not1765// the allocation can't be made into a stack allocation. If it is an object1766// allocation we can still look for desynchronization opportunities.1767//1768int32_t size = comp()->canAllocateInlineOnStack(node, classInfo);17691770if (((node->getOpCodeValue() == TR::newarray) || (node->getOpCodeValue() == TR::anewarray)) &&1771(node->getFirstChild()->getOpCodeValue() == TR::iconst))1772{1773if (node->getFirstChild()->getInt() == 0)1774return NULL;1775}17761777if (classInfo &&1778!TR::Compiler->cls.sameClassLoaders(comp(), classInfo, comp()->getJittedMethodSymbol()->getResolvedMethod()->containingClass()) &&1779!comp()->fej9()->isClassLoadedBySystemClassLoader(classInfo))1780return NULL;17811782if (size <= 0)1783{1784if (trace())1785traceMsg(comp(), " Node [%p] failed: VM can't skip allocation (code %d, class %p)\n", node, size, classInfo);17861787if ( size == 01788&& classInfo1789&& (manager()->numPassesCompleted() == 0)1790&& optimizer()->isEnabled(OMR::profiledNodeVersioning)1791&& !_curBlock->isCold())1792{1793TR::Node *numElementsNode = NULL;1794switch (node->getOpCodeValue())1795{1796case TR::newarray:1797case TR::anewarray:1798numElementsNode = node->getFirstChild();1799break;1800case TR::New:1801case TR::multianewarray:1802// Can't do anything with these yet1803break;1804default:1805break;1806}18071808TR::Recompilation *recomp = comp()->getRecompilationInfo();1809TR_ValueProfiler *valueProfiler = recomp? recomp->getValueProfiler() : NULL;18101811if ( numElementsNode1812&& valueProfiler1813&& performTransformation(comp(), "%sContinue analyzing %s node %s for size-profiling opportunity\n", OPT_DETAILS,1814node->getOpCode().getName(),1815comp()->getDebug()->getName(node)))1816{1817profileOnly = true;1818size = TR::Compiler->om.contiguousArrayHeaderSizeInBytes(); // Must be at least this big1819}1820else1821{1822return NULL;1823}1824}1825else if (node->getOpCodeValue() == TR::New && classInfo)1826size = 0;1827else1828return NULL;1829}1830else1831{1832// j/l/Reference objects are no longer enqueued by a native call in the constructor.1833// This native was preventing j/l/Reference objects from being stack allocated, but1834// we now need to explicitly prevent j/l/Reference (and its subclasses) from being1835// stack allocated because the GC can't discover them during scanning (this is non-1836// trivial to do apparently).1837//1838TR_OpaqueClassBlock *jlReference = comp()->getReferenceClassPointer();1839TR_OpaqueClassBlock *jlObject = comp()->getObjectClassPointer();1840TR_OpaqueClassBlock *currentClass = classInfo;18411842while (currentClass && currentClass != jlObject)1843{1844if (currentClass == jlReference)1845{1846if (trace())1847traceMsg(comp(), " Node [%p] failed: class %p is subclass of j/l/r/Reference\n", node, classInfo);18481849return NULL;1850}1851else1852{1853currentClass = comp()->fej9()->getSuperClass(currentClass);1854}1855}1856}18571858Candidate *result = NULL;1859result = new (trStackMemory()) Candidate(node, _curTree, _curBlock, size, classInfo, comp());1860result->setProfileOnly(profileOnly);1861return result;1862}1863186418651866bool TR_EscapeAnalysis::isEscapePointCold(Candidate *candidate, TR::Node *node)1867{1868static const char *disableColdEsc = feGetEnv("TR_DisableColdEscape");1869if (!disableColdEsc &&1870(_inColdBlock ||1871(candidate->isInsideALoop() &&1872(candidate->_block->getFrequency() > 4*_curBlock->getFrequency()))) &&1873(candidate->_origKind == TR::New))1874return true;18751876return false;1877}187818791880void TR_EscapeAnalysis::checkDefsAndUses()1881{1882Candidate *candidate, *next;18831884gatherUsesThroughAselect();18851886for (candidate = _candidates.getFirst(); candidate; candidate = next)1887{1888next = candidate->getNext();1889TR::Node *node = candidate->_node;1890int32_t newVN = _valueNumberInfo->getValueNumber(node);1891candidate->_valueNumbers = new (trStackMemory()) TR_Array<int32_t>(trMemory(), 8, false, stackAlloc);1892candidate->_valueNumbers->add(newVN);18931894// Accumulate the set of value numbers that can be reached by this1895// allocation. This also checks that it is valid to allocate on the stack.1896//1897if (candidate->isInsideALoop())1898{1899if (_otherDefsForLoopAllocation)1900_otherDefsForLoopAllocation->empty();1901else1902_otherDefsForLoopAllocation= new (trStackMemory()) TR_BitVector(_useDefInfo->getNumDefNodes(), trMemory(), stackAlloc);1903}19041905if (comp()->getOptions()->realTimeGC() &&1906comp()->compilationShouldBeInterrupted(ESC_CHECK_DEFSUSES_CONTEXT))1907{1908comp()->failCompilation<TR::CompilationInterrupted>("interrupted in Escape Analysis");1909}19101911if (checkDefsAndUses(node, candidate))1912{1913if (candidate->_valueNumbers->size() > 1)1914{1915candidate->setMustBeContiguousAllocation();1916if (trace())1917traceMsg(comp(), " Make [%p] contiguous because its uses can be reached from other defs\n", candidate->_node);1918}1919}1920else1921{1922candidate->setLocalAllocation(false);1923if (trace())1924traceMsg(comp(), "5 setting local alloc %p to false\n", candidate->_node);1925}1926}19271928_vnTemp = new (trStackMemory()) TR_BitVector( optimizer()->getValueNumberInfo()->getNumberOfNodes(), trMemory(), stackAlloc, notGrowable);1929_vnTemp2 = new (trStackMemory()) TR_BitVector(optimizer()->getValueNumberInfo()->getNumberOfNodes(), trMemory(), stackAlloc, notGrowable);19301931TR::TreeTop *tt = comp()->getStartTree();1932for (; tt; tt = tt->getNextTreeTop())1933{1934bool storeOfObjectIntoField = false;1935TR::Node *node = tt->getNode();1936if (!node->getOpCode().isStore())1937{1938if (node->getNumChildren() > 0)1939node = node->getFirstChild();1940}19411942bool storeIntoOtherLocalObject = false;1943int32_t baseChildVN = -1;1944if (node->getOpCode().isStoreIndirect() ||1945(node->getOpCodeValue() == TR::arraycopy))1946{1947TR::Node *baseObject = node;19481949if (node->getSymbol()->isArrayShadowSymbol() &&1950node->getFirstChild()->getOpCode().isArrayRef())1951baseObject = node->getFirstChild();1952else if (node->getOpCodeValue() == TR::arraycopy)1953{1954if (node->getNumChildren() == 5)1955baseObject = node->getChild(3);1956else if (node->getFirstChild()->getOpCode().isArrayRef())1957baseObject = node->getFirstChild();1958}19591960if (node->getOpCode().isStoreIndirect() &&1961(baseObject->getFirstChild() == node->getSecondChild()))1962storeOfObjectIntoField = true;1963else1964{1965TR::Node *baseChild = baseObject;19661967if ((node->getOpCodeValue() != TR::arraycopy) ||1968(node->getNumChildren() != 5))1969baseChild = baseObject->getFirstChild();19701971baseChild = resolveSniffedNode(baseChild);19721973if ((baseChild && (baseChild->getOpCodeValue() == TR::loadaddr) &&1974baseChild->getSymbolReference()->getSymbol()->isAuto() &&1975baseChild->getSymbolReference()->getSymbol()->isLocalObject())1976)1977{1978baseChildVN = _valueNumberInfo->getValueNumber(baseChild);1979if (node->getOpCodeValue() == TR::arraycopy)1980{1981_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);1982_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);1983storeOfObjectIntoField = false;1984if (trace())1985traceMsg(comp(), "Reached 0 with baseChild %p VN %d\n", baseChild, baseChildVN);1986}1987else1988{1989if (!baseChild->cannotTrackLocalUses())1990{1991storeOfObjectIntoField = true;1992storeIntoOtherLocalObject = true;1993if (trace())1994traceMsg(comp(), "Reached 1 with baseChild %p VN %d\n", baseChild, baseChildVN);1995}1996else1997{1998_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);1999_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);2000storeOfObjectIntoField = false;2001}2002}2003}2004else if (baseChild && _useDefInfo)2005{2006uint16_t baseIndex = baseChild->getUseDefIndex();2007if (_useDefInfo->isUseIndex(baseIndex))2008{2009TR_UseDefInfo::BitVector defs(comp()->allocator());2010_useDefInfo->getUseDef(defs, baseIndex);2011if (!defs.IsZero())2012{2013TR_UseDefInfo::BitVector::Cursor cursor(defs);2014for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())2015{2016int32_t defIndex = cursor;20172018if (defIndex < _useDefInfo->getFirstRealDefIndex())2019{2020storeOfObjectIntoField = false;2021break;2022}20232024TR::TreeTop *defTree = _useDefInfo->getTreeTop(defIndex);2025TR::Node *defNode = defTree->getNode();20262027if (defNode &&2028(defNode->getOpCodeValue() == TR::astore) &&2029(defNode->getNumChildren() > 0))2030{2031TR::Node *defChild = defNode->getFirstChild();20322033if (defChild && (defChild->getOpCodeValue() == TR::loadaddr) &&2034defChild->getSymbolReference()->getSymbol()->isAuto() &&2035defChild->getSymbolReference()->getSymbol()->isLocalObject() &&2036!defChild->cannotTrackLocalUses())2037{2038if (node->getOpCode().isStoreIndirect() &&2039(_valueNumberInfo->getValueNumber(defChild) == _valueNumberInfo->getValueNumber(baseChild)))2040{2041baseChildVN = _valueNumberInfo->getValueNumber(baseChild);2042storeOfObjectIntoField = true;2043storeIntoOtherLocalObject = true;2044}2045else2046{2047_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));2048_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));2049_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));2050_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));2051storeOfObjectIntoField = false;2052break;2053}2054}2055else2056{2057_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));2058_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));2059_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));2060_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));2061storeOfObjectIntoField = false;2062break;2063}2064}2065}2066}2067}2068}2069}2070}20712072if (storeOfObjectIntoField)2073{2074int32_t valueNumber = _valueNumberInfo->getValueNumber(node->getSecondChild());2075Candidate *candidate, *next;2076bool foundAccess = false;2077for (candidate = _candidates.getFirst(); candidate; candidate = next)2078{2079next = candidate->getNext();2080if (usesValueNumber(candidate, valueNumber))2081{2082TR::NodeChecklist visited (comp());2083TR::TreeTop *cursorTree = comp()->getStartTree();2084for (; cursorTree; cursorTree = cursorTree->getNextTreeTop())2085{2086TR::Node *cursorNode = cursorTree->getNode();2087if (!storeIntoOtherLocalObject)2088{2089if (collectValueNumbersOfIndirectAccessesToObject(cursorNode, candidate, node, visited))2090foundAccess = true;2091}2092else2093{2094if (collectValueNumbersOfIndirectAccessesToObject(cursorNode, candidate, node, visited, baseChildVN))2095foundAccess = true;2096}2097}2098}2099}2100}210121022103if (node->getOpCode().isCall() &&2104(node->getSymbol()->getResolvedMethodSymbol()) &&2105(node->getReferenceCount() > 1) &&2106(node->getNumChildren() > 0))2107{2108TR::ResolvedMethodSymbol *methodSymbol = node->getSymbol()->getResolvedMethodSymbol();2109switch (methodSymbol->getRecognizedMethod())2110{2111case TR::java_lang_Throwable_fillInStackTrace:2112case TR::java_math_BigDecimal_possibleClone:2113{2114int32_t firstArgIndex = node->getFirstArgumentIndex();2115int32_t nodeVN = _valueNumberInfo->getValueNumber(node->getChild(firstArgIndex));2116for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())2117{2118if (usesValueNumber(candidate, nodeVN))2119{2120// Remember the value number of the fillInStackTrace call itself2121// It's return value can be assigned to a local and the local can be used2122// which would mean we cannot eliminate the fillInStackTrace.2123//2124if (methodSymbol && (!methodSymbol->getResolvedMethod()->virtualMethodIsOverridden() || !node->getOpCode().isIndirect()))2125{2126candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));2127}2128}2129}2130}2131default:2132break;2133}2134}2135}2136}21372138void TR_EscapeAnalysis::printUsesThroughAselect(void)2139{2140if (trace())2141{2142if (_nodeUsesThroughAselect)2143{2144traceMsg(comp(), "\nNodes used through aselect operations\n");21452146for (auto mi = _nodeUsesThroughAselect->begin(); mi != _nodeUsesThroughAselect->end(); mi++)2147{2148TR::Node *key = mi->first;2149int32_t nodeIdx = key->getGlobalIndex();21502151traceMsg(comp(), " node [%p] n%dn is used by {", key, nodeIdx);21522153bool first = true;21542155for (auto di = mi->second->begin(), end = mi->second->end(); di != end; di++)2156{2157TR::Node *aselectNode = *di;2158traceMsg(comp(), "%s[%p] n%dn", (first ? "" : ", "), aselectNode,2159aselectNode->getGlobalIndex());2160first = false;2161}21622163traceMsg(comp(), "}\n");2164}2165}2166else2167{2168traceMsg(comp(), "\nNo nodes used through aselect operations\n");2169}2170}2171}21722173void TR_EscapeAnalysis::gatherUsesThroughAselect(void)2174{2175TR::NodeChecklist visited(comp());2176TR::TreeTop *tt = comp()->getStartTree();21772178for (; tt; tt = tt->getNextTreeTop())2179{2180TR::Node *node = tt->getNode();2181gatherUsesThroughAselectImpl(node, visited);2182}21832184if (trace())2185{2186printUsesThroughAselect();2187}2188}21892190void TR_EscapeAnalysis::gatherUsesThroughAselectImpl(TR::Node *node, TR::NodeChecklist& visited)2191{2192if (visited.contains(node))2193{2194return;2195}2196visited.add(node);21972198for (int32_t i=0; i<node->getNumChildren(); i++)2199{2200gatherUsesThroughAselectImpl(node->getChild(i), visited);2201}22022203// If this is an aselect operation, for each of its child operands (other than2204// the condition) add the aselect node to the array of nodes that use that child2205if (node->getOpCode().isSelect() && node->getDataType() == TR::Address)2206{2207associateAselectWithChild(node, 1);2208associateAselectWithChild(node, 2);2209}2210}22112212void TR_EscapeAnalysis::associateAselectWithChild(TR::Node *aselectNode, int32_t idx)2213{2214TR::Region &stackMemoryRegion = trMemory()->currentStackRegion();2215TR::Node *child = aselectNode->getChild(idx);22162217NodeDeque *currChildUses;22182219if (NULL == _nodeUsesThroughAselect)2220{2221_nodeUsesThroughAselect =2222new (trStackMemory()) NodeToNodeDequeMap((NodeComparator()),2223NodeToNodeDequeMapAllocator(stackMemoryRegion));2224}22252226auto search = _nodeUsesThroughAselect->find(child);2227bool nodeAlreadyMapsToAselect = false;22282229if (_nodeUsesThroughAselect->end() != search)2230{2231currChildUses = search->second;22322233// Does NodeDeque already contain this aselect node?2234nodeAlreadyMapsToAselect =2235(std::find(search->second->begin(), search->second->end(),2236aselectNode) != search->second->end());2237}2238else2239{2240currChildUses = new (trStackMemory()) NodeDeque(stackMemoryRegion);2241(*_nodeUsesThroughAselect)[child] = currChildUses;2242}22432244if (!nodeAlreadyMapsToAselect)2245{2246currChildUses->push_back(aselectNode);2247}2248}22492250bool TR_EscapeAnalysis::collectValueNumbersOfIndirectAccessesToObject(TR::Node *node, Candidate *candidate, TR::Node *indirectStore, TR::NodeChecklist& visited, int32_t baseChildVN)2251{2252if (visited.contains(node))2253return false;2254visited.add(node);22552256bool foundAccess = false;22572258if (node->getOpCode().isLoadIndirect())2259{2260bool sameSymbol = false;2261if (node->getSymbolReference()->getReferenceNumber() == indirectStore->getSymbolReference()->getReferenceNumber())2262sameSymbol = true;2263else if (indirectStore->getSymbolReference()->sharesSymbol())2264{2265if (indirectStore->getSymbolReference()->getUseDefAliases().contains(node->getSymbolReference(), comp()))2266sameSymbol = true;2267}22682269if (trace())2270traceMsg(comp(), "store node %p load node %p candidate %p baseChildVN %d\n", indirectStore, node, candidate->_node, baseChildVN);22712272if (sameSymbol)2273{2274TR::Node *base = node->getFirstChild();22752276if (/* node->getSymbol()->isArrayShadowSymbol() && */2277base->getOpCode().isArrayRef())2278base = base->getFirstChild();22792280int32_t baseVN = _valueNumberInfo->getValueNumber(base);22812282//traceMsg(comp(), "store node %p load node %p candidate %p baseChildVN %d baseVN %d\n", indirectStore, node, candidate->_node, baseChildVN, baseVN);22832284if (candidate->_valueNumbers)2285{2286if ((baseChildVN == -1) && usesValueNumber(candidate, baseVN))2287{2288candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));2289if (checkDefsAndUses(node, candidate))2290foundAccess = true;2291else2292{2293TR::Node *resolvedBaseObject = resolveSniffedNode(indirectStore->getFirstChild());2294if (resolvedBaseObject)2295{2296_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(resolvedBaseObject));2297_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(resolvedBaseObject));2298}2299}2300}2301else if (baseChildVN != -1)2302{2303if (baseChildVN == baseVN)2304{2305candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));2306if (checkDefsAndUses(node, candidate))2307foundAccess = true;2308else2309{2310_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);2311_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);2312}2313}2314else2315{2316TR::Node *storeBase = indirectStore->getFirstChild();2317if (/* indirectStore->getSymbol()->isArrayShadowSymbol() && */2318storeBase->getOpCode().isArrayRef())2319storeBase = storeBase->getFirstChild();232023212322if (base->getOpCode().hasSymbolReference() && base->getSymbolReference()->getSymbol()->isAuto())2323{2324if (_useDefInfo)2325{2326uint16_t baseIndex = base->getUseDefIndex();2327//uint16_t storeBaseIndex = storeBase->getUseDefIndex();2328TR_UseDefInfo::BitVector baseDefs(comp()->allocator());2329_useDefInfo->getUseDef(baseDefs, baseIndex);2330//TR_UseDefInfo::BitVector storeBaseDefs(comp()->allocator());2331//_useDefInfo->getUseDef(storeBaseDefs, storeBaseIndex);2332//traceMsg(comp(), "store base index %d store base %p base index %p base %p\n", storeBaseIndex, storeBase, baseIndex, base);23332334_vnTemp->set(_valueNumberInfo->getValueNumber(storeBase));2335while (*_vnTemp2 != *_vnTemp)2336{2337_vnTemp->print(comp());2338*_vnTemp2 = *_vnTemp;2339int32_t i;2340for (i = _useDefInfo->getNumDefOnlyNodes()-1; i >= 0; --i)2341{2342int32_t useDefIndex = i + _useDefInfo->getFirstDefIndex();2343TR::Node *defNode = _useDefInfo->getNode(useDefIndex);2344//traceMsg(comp(), "def node %p\n", defNode);23452346if (defNode && defNode->getOpCode().isStore())2347{2348if (_vnTemp->get(_valueNumberInfo->getValueNumber(defNode)))2349{2350TR_UseDefInfo::BitVector usesOfThisDef(comp()->allocator());2351_useDefInfo->getUsesFromDef(usesOfThisDef, defNode->getUseDefIndex()+_useDefInfo->getFirstDefIndex());2352if (!usesOfThisDef.IsZero())2353{2354TR_UseDefInfo::BitVector::Cursor cursor(usesOfThisDef);2355for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())2356{2357int32_t useIndex = cursor;2358TR::Node *useNode = _useDefInfo->getNode(useIndex+_useDefInfo->getFirstUseIndex());2359int32_t useNodeVN = _valueNumberInfo->getValueNumber(useNode);2360//traceMsg(comp(), "use node %p vn %d\n", useNode, useNodeVN);23612362_vnTemp->set(useNodeVN);2363}2364}2365}2366}2367}2368}23692370TR_UseDefInfo::BitVector::Cursor cursor(baseDefs);2371for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())2372{2373int32_t defIndex = _useDefInfo->getFirstDefIndex() + (int32_t) cursor;2374//TODO: Temporary fix to overcome case when defIndex = 02375if (defIndex < _useDefInfo->getFirstRealDefIndex())2376continue;23772378TR::Node *defNode = _useDefInfo->getNode(defIndex);2379if (_vnTemp->get(_valueNumberInfo->getValueNumber(defNode)))2380{2381candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));2382break;2383}2384}2385}2386}23872388_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);2389_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);2390}2391}2392}2393}2394}239523962397int32_t i;2398for (i=0;i<node->getNumChildren(); i++)2399{2400if (collectValueNumbersOfIndirectAccessesToObject(node->getChild(i), candidate, indirectStore, visited, baseChildVN))2401foundAccess = true;2402}2403return foundAccess;2404}240524062407bool TR_EscapeAnalysis::checkUsesThroughAselect(TR::Node *node, Candidate *candidate)2408{2409bool returnValue = true;24102411if (_nodeUsesThroughAselect)2412{2413auto search = _nodeUsesThroughAselect->find(node);24142415// Is this node referenced directly by any aselect nodes?2416if (_nodeUsesThroughAselect->end() != search)2417{2418for (auto di = search->second->begin(), end = search->second->end(); di != end; di++)2419{2420TR::Node* aselectNode = *di;2421int32_t aselectVN = _valueNumberInfo->getValueNumber(aselectNode);2422int32_t i;24232424// Check whether this aselect has already been accounted for with this candidate2425for (i = candidate->_valueNumbers->size()-1; i >= 0; i--)2426{2427if (candidate->_valueNumbers->element(i) == aselectVN)2428{2429break;2430}2431}24322433// If this aselect has not been accounted for with this candidate, check for its uses2434if (i < 0)2435{2436candidate->_valueNumbers->add(aselectVN);24372438if (trace())2439{2440traceMsg(comp(), " Checking uses of node %p through aselect operation %p for candidate %p\n", node, aselectNode, candidate->_node);2441}24422443if (!checkDefsAndUses(aselectNode, candidate))2444{2445returnValue = false;2446}2447}2448}2449}2450}24512452return returnValue;2453}245424552456bool TR_EscapeAnalysis::checkDefsAndUses(TR::Node *node, Candidate *candidate)2457{2458TR::Node *next;2459_useDefInfo->buildDefUseInfo();2460bool returnValue = true;24612462if (_nodeUsesThroughAselect && !checkUsesThroughAselect(node, candidate))2463{2464returnValue = false;2465}24662467for (next = _valueNumberInfo->getNext(node); next != node; next = _valueNumberInfo->getNext(next))2468{2469int32_t udIndex = next->getUseDefIndex();24702471if (_useDefInfo->isDefIndex(udIndex))2472{2473if (next->getOpCode().isStore() && next->getSymbol()->isAutoOrParm())2474{2475TR::SymbolReference *symRef = next->getSymbolReference();2476if (!candidate->getSymRefs()->find(symRef))2477candidate->addSymRef(symRef);24782479// Find all uses of this def and see if their value numbers are2480// already known in the array of value numbers.2481// If not, add the new value number and recurse to find value2482// numbers of nodes reachable from this use.2483//24842485TR_UseDefInfo::BitVector defUse(comp()->allocator());2486_useDefInfo->getUsesFromDef(defUse, udIndex-_useDefInfo->getFirstDefIndex());2487if (!defUse.IsZero())2488{2489TR_UseDefInfo::BitVector::Cursor cursor(defUse);2490for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())2491{2492int32_t useIndex = cursor;2493TR::Node *useNode = _useDefInfo->getNode(useIndex+_useDefInfo->getFirstUseIndex());24942495// Only add this value number if it's not to be ignored2496if (_ignoreableUses->get(useNode->getGlobalIndex()))2497{2498continue;2499}25002501int32_t useNodeVN = _valueNumberInfo->getValueNumber(useNode);2502int32_t i;25032504for (i = candidate->_valueNumbers->size()-1; i >= 0; i--)2505{2506if (candidate->_valueNumbers->element(i) == useNodeVN)2507{2508break;2509}2510}25112512if (i < 0)2513{2514candidate->_valueNumbers->add(useNodeVN);25152516if (candidate->isInsideALoop())2517{2518static char *p = feGetEnv("TR_NoLoopAlloc");2519if (!p)2520{2521// For an allocation inside a loop we must make sure2522// that two generations of the allocation can't2523// co-exist.2524// There are 2 ways this can happen - check them.2525//2526if (trace())2527traceMsg(comp(), " Look at other defs for use node %p of candidate %p\n", useNode, candidate->_node);2528////_otherDefsForLoopAllocation->set(udIndex);25292530if (!checkOverlappingLoopAllocation(useNode, candidate))2531{2532if (trace())2533traceMsg(comp(), " Make [%p] non-local because it overlaps with use [%p]\n", candidate->_node, useNode);2534/////printf("secs Overlapping loop allocation in %s\n", comp()->signature());2535returnValue = false;2536}2537if (!checkOtherDefsOfLoopAllocation(useNode, candidate, (next->getFirstChild() == candidate->_node)))2538{2539if (trace())2540traceMsg(comp(), " Make [%p] non-local because multiple defs to node [%p]\n", candidate->_node, useNode);2541returnValue = false;2542}2543}2544else2545returnValue = false;2546}2547if (!checkDefsAndUses(useNode, candidate))2548returnValue = false;2549}2550}2551}2552}2553}25542555if (_useDefInfo->isUseIndex(udIndex))2556{2557if (_nodeUsesThroughAselect && !checkUsesThroughAselect(next, candidate))2558{2559returnValue = false;2560}2561}2562}2563return returnValue;2564}25652566bool TR_EscapeAnalysis::checkOtherDefsOfLoopAllocation(TR::Node *useNode, Candidate *candidate, bool isImmediateUse)2567{2568// The allocation is inside a loop and a use has been found that has other2569// defs too. Find all the possible defs for this use and make sure none of2570// them lead back to the allocation. If they do, it means that generations2571// of the allocation from different loop iterations may be alive at the same2572// time, so the allocation must be done from the heap and not the stack.2573//2574// In some limited cases, we can be sure that an object from a prior loop iteration2575// was not live at the same time as an object from the next loop iteration without expensive analysis.2576// One such "special" case is when all defs for uses reached by our candidate for stack allocation2577// were fed by allocations; in this case it's easy to see that it was not an object from a prior iteration2578// since it is a fresh allocation being done at that program point.2579//2580// There is one other special case dealt with in the code below related to a java/lang/Integer cache2581// where again it's trivial to prove that the value cannot be a candidate allocation from a prior loop iteration2582//2583// There may be other such examples that can be added in the future, e.g. if the value is an already stack allocated2584// object from a prior pass of escape analysis, it obviously cannot be a candidate for stack allocation in this pass.2585//2586int32_t useIndex = useNode->getUseDefIndex();2587if (useIndex <= 0)2588return true;25892590TR_UseDefInfo::BitVector defs(comp()->allocator());2591_useDefInfo->getUseDef(defs, useIndex);2592TR_UseDefInfo::BitVector::Cursor cursor(defs);2593for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())2594{2595int32_t defIndex = cursor;2596if (defIndex < _useDefInfo->getFirstRealDefIndex() /* || _otherDefsForLoopAllocation->get(defIndex) */)2597{2598continue;2599}26002601bool seenOtherDef = false;2602if (_otherDefsForLoopAllocation->get(defIndex))2603seenOtherDef = true;26042605// Ignore the def that is the one that caused us to look at this use in2606// the first place2607//2608TR::Node *defNode = _useDefInfo->getNode(defIndex);2609if (!seenOtherDef &&2610isImmediateUse &&2611_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(candidate->_node))2612///_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(useNode))2613{2614if (trace())2615traceMsg(comp(), " Ignoring def node [%p] for use node [%p]\n", defNode, useNode);2616continue;2617}26182619_otherDefsForLoopAllocation->set(defIndex);26202621if (trace())2622traceMsg(comp(), " Look at def node [%p] for use node [%p]\n", defNode, useNode);26232624bool allnewsonrhs;26252626if (_doLoopAllocationAliasChecking)2627{2628allnewsonrhs = checkAllNewsOnRHSInLoopWithAliasing(defIndex, useNode, candidate);2629}2630else2631{2632allnewsonrhs = checkAllNewsOnRHSInLoop(defNode, useNode, candidate);2633}263426352636if (!allnewsonrhs &&2637!(defNode->getOpCode().isStoreDirect() &&2638((defNode->getFirstChild()->getOpCodeValue() == TR::aconst) ||2639(defNode->getFirstChild()->getOpCode().isLoadVar() && // load from a static or array shadow or shadow (field) based off a non local object are fine since such memory locations would imply that the object being pointed at escaped already (meaning there would be another escape point anyway)2640(defNode->getFirstChild()->getSymbol()->isStatic() ||2641(defNode->getFirstChild()->getSymbol()->isShadow() &&2642(defNode->getFirstChild()->getSymbol()->isArrayShadowSymbol() ||2643!_nonColdLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(defNode->getFirstChild()->getFirstChild())))))))))2644{2645if (_valueNumberInfo->getValueNumber(defNode) != _valueNumberInfo->getValueNumber(useNode))2646{2647// If the use is outside the loop, make sure that there are stores to temp t on all possible2648// paths from the allocation to the use (load of temp t). This will ensure that a prior iteration's2649// allocation is not what is pointed at by temp t when we reach the use of temp t.2650//2651if (checkIfUseIsInSameLoopAsDef(_useDefInfo->getTreeTop(defIndex), useNode) ||2652checkIfUseIsInLoopAndOverlapping(candidate, _useDefInfo->getTreeTop(defIndex), useNode))2653{2654if (trace())2655traceMsg(comp(), " Def node [%p] same as candidate [%p]\n", defNode, candidate->_node);2656return false;2657}2658}2659}26602661if (!seenOtherDef && defNode->getOpCode().isStore() && defNode->getSymbol()->isAutoOrParm())2662{2663if (!checkOtherDefsOfLoopAllocation(defNode->getFirstChild(), candidate, false))2664return false;2665}26662667if (trace())2668traceMsg(comp(), " Def node [%p] not the same as candidate [%p]\n", defNode, candidate->_node);2669}2670return true;2671}26722673bool TR_EscapeAnalysis::checkAllNewsOnRHSInLoopWithAliasing(int32_t defIndex, TR::Node *useNode, Candidate *candidate)2674{2675TR_ASSERT(_doLoopAllocationAliasChecking, "Reached checkAllNewsOnRHSInLoopWithAliasing unexpectedly");26762677// _aliasesOfAllocNode contains sym refs that are just aliases for a fresh allocation2678// i.e. it is just a simple attempt at tracking allocations in cases such as :2679// ...2680// a = new A()2681// ...2682// b = a2683// ...2684// c = b2685//2686// In this case a, b and c will all be considered aliases of an alloc node and so a load of2687// any of those sym refs will be treated akin to how the fresh allocation would have been in the below logic2688//26892690TR::Node *defNode = _useDefInfo->getNode(defIndex);2691int32_t useIndex = useNode->getUseDefIndex();2692bool allnewsonrhs = false;26932694if ((defNode->getFirstChild() == candidate->_node) &&2695(_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(useNode)))2696{2697if (trace())2698{2699traceMsg(comp(), " Value numbers match for def node [%p] with use node [%p]\n", defNode, useNode);2700}2701allnewsonrhs = true;2702}2703else if ((_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(candidate->_node)) &&2704(_useDefInfo->getTreeTop(defIndex)->getEnclosingBlock() == candidate->_block) &&2705_aliasesOfAllocNode->get(defNode->getSymbolReference()->getReferenceNumber()))2706{2707if (trace())2708{2709traceMsg(comp(), " Value numbers match for def node [%p] with candidate node [%p], and def node's symref is alias of candidate allocation\n", defNode, candidate->_node);2710}2711allnewsonrhs = true;2712}2713else2714{2715allnewsonrhs = true;2716TR_UseDefInfo::BitVector defs2(comp()->allocator());2717_useDefInfo->getUseDef(defs2, useIndex);2718TR_UseDefInfo::BitVector::Cursor cursor2(defs2);27192720// Loop over definitions for this use and over all the candidate2721// allocations. If the definition comes directly from a candidate2722// for stack allocation, it's harmless; if it's copied from a2723// variable that's aliased with a candidate for stack allocation2724// that was allocated in the same block, it's harmless2725for (cursor2.SetToFirstOne(); cursor2.Valid(); cursor2.SetToNextOne())2726{2727int32_t defIndex2 = cursor2;2728if (defIndex2 == 0)2729{2730allnewsonrhs = false;2731break;2732}27332734TR::Node *defNode2 = _useDefInfo->getNode(defIndex2);2735TR::Node *firstChild = defNode2->getFirstChild();27362737// Is RHS for this reaching definition harmless? I.e., not a2738// definition that can escape the loop. It is considered harmless if2739// it is a candidate for stack allocation, an alias of a candidate2740// or it is an entry in the cache for java.lang.Integer, et al.2741bool rhsIsHarmless = false;27422743for (Candidate *otherAllocNode = _candidates.getFirst(); otherAllocNode; otherAllocNode = otherAllocNode->getNext())2744{2745// A reaching definition that is an allocation node for a candidate2746// for stack allocation is harmless. Also, a reaching definition2747// that has the value number of a candidate allocation, other than the2748// current candidate, is harmless. The added restriction in the2749// second case avoids allowing the current candidate through from a2750// a previous loop iteration.2751if (otherAllocNode->_node == firstChild2752|| (candidate->_node != otherAllocNode->_node2753&& _valueNumberInfo->getValueNumber(otherAllocNode->_node)2754== _valueNumberInfo->getValueNumber(firstChild)))2755{2756rhsIsHarmless = true;2757break;2758}27592760if (trace())2761{2762traceMsg(comp(), " Look at defNode2 [%p] with otherAllocNode [%p]\n", defNode2, otherAllocNode);2763}27642765if (!rhsIsHarmless &&2766(_valueNumberInfo->getValueNumber(defNode2) == _valueNumberInfo->getValueNumber(otherAllocNode->_node)))2767{2768TR::TreeTop *treeTop;2769bool collectAliases = false;2770_aliasesOfOtherAllocNode->empty();2771_visitedNodes->empty();2772for (treeTop = otherAllocNode->_treeTop->getEnclosingBlock()->getEntry(); treeTop; treeTop = treeTop->getNextTreeTop())2773{2774TR::Node *node = treeTop->getNode();2775if (node->getOpCodeValue() == TR::BBEnd)2776break;27772778// Until we reach otherAllocNode, call visitTree to2779// ignore nodes in those trees. After we've reached2780// otherAllocNode, call collectAliasesOfAllocations to2781// track its aliases in _aliasesOfOtherAllocNode2782if (!collectAliases)2783{2784visitTree(treeTop->getNode());2785}2786else2787{2788collectAliasesOfAllocations(treeTop->getNode(), otherAllocNode->_node);2789}27902791if (treeTop == otherAllocNode->_treeTop)2792{2793collectAliases = true;2794}2795}27962797if ((_useDefInfo->getTreeTop(defIndex2)->getEnclosingBlock() == otherAllocNode->_block) &&2798_aliasesOfOtherAllocNode->get(defNode2->getSymbolReference()->getReferenceNumber()))2799{2800if (trace())2801{2802traceMsg(comp(), " rhs is harmless for defNode2 [%p] with otherAllocNode [%p]\n", defNode2, otherAllocNode);2803}2804rhsIsHarmless = true;2805break;2806}2807}2808}28092810if (!rhsIsHarmless)2811{2812if (trace())2813{2814traceMsg(comp(), " defNode2 vn=%d is local %d\n", _valueNumberInfo->getValueNumber(defNode2), _allLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(defNode2)));2815}28162817// References to objects that were previously made local are also harmless2818if (_allLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(defNode2)))2819{2820rhsIsHarmless = true;2821}2822}28232824if (!rhsIsHarmless)2825{2826// Another special case when it is certain that the rhs of the def is not a candidate allocation from a prior iteration2827// In this case we are loading a value from an Integer cache anyway and that should be an allocation that has already escaped2828// that has nothing to do with the candidate allocation2829//2830if (firstChild->getOpCode().hasSymbolReference() &&2831firstChild->getSymbol()->isArrayShadowSymbol())2832{2833TR::Node *addr = firstChild->getFirstChild();2834if (addr->getOpCode().isArrayRef())2835{2836TR::Node *underlyingArray = addr->getFirstChild();28372838int32_t fieldNameLen = -1;2839char *fieldName = NULL;2840if (underlyingArray && underlyingArray->getOpCode().hasSymbolReference() &&2841underlyingArray->getSymbolReference()->getSymbol()->isStaticField())2842{2843fieldName = underlyingArray->getSymbolReference()->getOwningMethod(comp())->staticName(underlyingArray->getSymbolReference()->getCPIndex(), fieldNameLen, comp()->trMemory());2844}28452846if (fieldName && (fieldNameLen > 10) &&2847!strncmp("java/lang/", fieldName, 10) &&2848(!strncmp("Integer$IntegerCache.cache", &fieldName[10], 26) ||2849!strncmp("Long$LongCache.cache", &fieldName[10], 20) ||2850!strncmp("Short$ShortCache.cache", &fieldName[10], 22) ||2851!strncmp("Byte$ByteCache.cache", &fieldName[10], 20) ||2852!strncmp("Character$CharacterCache.cache", &fieldName[10], 30)))28532854{2855if (trace())2856{2857traceMsg(comp(), " rhs is harmless for defNode2 [%p] access of Integer cache\n", defNode2);2858}28592860rhsIsHarmless = true;2861}2862}2863}2864}28652866if (!rhsIsHarmless)2867{2868if (trace())2869{2870traceMsg(comp(), " rhs not harmless for defNode2 [%p]\n", defNode2);2871}28722873allnewsonrhs = false;2874break;2875}2876}2877}28782879return allnewsonrhs;2880}28812882bool TR_EscapeAnalysis::checkAllNewsOnRHSInLoop(TR::Node *defNode, TR::Node *useNode, Candidate *candidate)2883{2884TR_ASSERT(!_doLoopAllocationAliasChecking, "Reached checkAllNewsOnRHSInLoop unexpectedly");28852886int32_t useIndex = useNode->getUseDefIndex();2887bool allnewsonrhs = false;28882889if ((_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(candidate->_node)))2890{2891if ((defNode->getFirstChild() == candidate->_node) &&2892(_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(useNode)))2893allnewsonrhs = true;2894else2895{2896allnewsonrhs = true;2897TR_UseDefInfo::BitVector defs2(comp()->allocator());2898_useDefInfo->getUseDef(defs2, useIndex);2899TR_UseDefInfo::BitVector::Cursor cursor2(defs2);2900for (cursor2.SetToFirstOne(); cursor2.Valid(); cursor2.SetToNextOne())2901{2902int32_t defIndex2 = cursor2;2903if (defIndex2 == 0)2904{2905allnewsonrhs = false;2906break;2907}29082909TR::Node *defNode2 = _useDefInfo->getNode(defIndex2);2910TR::Node *firstChild = defNode2->getFirstChild();2911bool rhsIsHarmless = false;2912for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())2913{2914if (candidate->_node == firstChild)2915{2916rhsIsHarmless = true;2917break;2918}2919}292029212922if (!rhsIsHarmless)2923{2924if (firstChild->getOpCode().hasSymbolReference() &&2925firstChild->getSymbol()->isArrayShadowSymbol())2926{2927TR::Node *addr = firstChild->getFirstChild();2928if (addr->getOpCode().isArrayRef())2929{2930TR::Node *underlyingArray = addr->getFirstChild();29312932int32_t fieldNameLen = -1;2933char *fieldName = NULL;2934if (underlyingArray && underlyingArray->getOpCode().hasSymbolReference() &&2935underlyingArray->getSymbolReference()->getSymbol()->isStaticField())2936{2937fieldName = underlyingArray->getSymbolReference()->getOwningMethod(comp())->staticName(underlyingArray->getSymbolReference()->getCPIndex(), fieldNameLen, comp()->trMemory());2938}29392940if (fieldName && (fieldNameLen > 0) &&2941!strncmp(fieldName, "java/lang/Integer$IntegerCache.cache", 36))2942rhsIsHarmless = true;2943}2944}2945}29462947if (!rhsIsHarmless)2948{2949allnewsonrhs = false;2950break;2951}2952}2953}2954}29552956return allnewsonrhs;2957}29582959bool TR_EscapeAnalysis::checkOverlappingLoopAllocation(TR::Node *useNode, Candidate *candidate)2960{2961// The allocation is inside a loop and a use has been found that has other2962// defs too. If the allocation can be used directly while the use node2963// holds a previous generation, the allocation cannot be made local.2964// To check this, walk forward from the candidate allocation to find the use2965// node. If it is found in the same extended block before the last use of the2966// allocation node the two can co-exist so the allocation cannot be local.2967//2968TR::TreeTop *treeTop;2969_visitedNodes->empty();2970if (_doLoopAllocationAliasChecking)2971{2972_aliasesOfAllocNode->empty();2973}2974rcount_t numReferences = 0; //candidate->_node->getReferenceCount()-1;2975for (treeTop = candidate->_treeTop->getEnclosingBlock()->getEntry(); treeTop; treeTop = treeTop->getNextTreeTop())2976{2977TR::Node *node = treeTop->getNode();2978if (node->getOpCodeValue() == TR::BBEnd)2979break;2980if (!checkOverlappingLoopAllocation(treeTop->getNode(), useNode, candidate->_node, numReferences))2981return false;2982if (treeTop == candidate->_treeTop)2983numReferences = candidate->_node->getReferenceCount();29842985//if (numReferences == 0)2986// break;2987}2988return true;2989}29902991bool TR_EscapeAnalysis::checkOverlappingLoopAllocation(TR::Node *node, TR::Node *useNode, TR::Node *allocNode, rcount_t &numReferences)2992{2993if (_visitedNodes->get(node->getGlobalIndex()))2994{2995return true;2996}29972998_visitedNodes->set(node->getGlobalIndex());29993000if (_doLoopAllocationAliasChecking3001&& node->getOpCode().isStore() && node->getSymbol()->isAutoOrParm())3002{3003if (node->getFirstChild() == allocNode)3004{3005_aliasesOfAllocNode->set(node->getSymbolReference()->getReferenceNumber());3006}3007else if (!_visitedNodes->get(node->getFirstChild()->getGlobalIndex())3008&& node->getFirstChild()->getOpCode().isLoadVarDirect()3009&& node->getFirstChild()->getSymbol()->isAutoOrParm()3010&& _aliasesOfAllocNode->get(node->getFirstChild()->getSymbolReference()->getReferenceNumber()))3011{3012_aliasesOfAllocNode->set(node->getSymbolReference()->getReferenceNumber());3013}3014else3015{3016_aliasesOfAllocNode->reset(node->getSymbolReference()->getReferenceNumber());3017}3018}30193020if ((node != allocNode)3021&& (_valueNumberInfo->getValueNumber(node) == _valueNumberInfo->getValueNumber(useNode)))3022{3023if (!_doLoopAllocationAliasChecking3024|| (!(node->getOpCode().isLoadVarDirect()3025&& _aliasesOfAllocNode->get(node->getSymbolReference()->getReferenceNumber()))3026&& (numReferences > 0)))3027{3028return false;3029}3030}3031//if (node == allocNode)3032// {3033// if (--numReferences == 0)3034// return true;3035// }3036for (int32_t i = 0; /* numReferences > 0 && */ i < node->getNumChildren(); i++)3037{3038if (!checkOverlappingLoopAllocation(node->getChild(i), useNode, allocNode, numReferences))3039return false;3040}3041return true;3042}304330443045void TR_EscapeAnalysis::visitTree(TR::Node *node)3046{3047if (_visitedNodes->get(node->getGlobalIndex()))3048{3049return;3050}30513052_visitedNodes->set(node->getGlobalIndex());30533054for (int32_t i = 0; i < node->getNumChildren(); i++)3055{3056visitTree(node->getChild(i));3057}3058}30593060void TR_EscapeAnalysis::collectAliasesOfAllocations(TR::Node *node, TR::Node *allocNode)3061{3062TR_ASSERT(_doLoopAllocationAliasChecking, "Reached collectAliasesOfAllocations unexpectedly");3063if (_visitedNodes->get(node->getGlobalIndex()))3064{3065return;3066}30673068_visitedNodes->set(node->getGlobalIndex());30693070if (node->getOpCode().isStore() && node->getSymbol()->isAutoOrParm())3071{3072if (node->getFirstChild() == allocNode)3073{3074_aliasesOfOtherAllocNode->set(node->getSymbolReference()->getReferenceNumber());3075}3076else if (!_visitedNodes->get(node->getFirstChild()->getGlobalIndex())3077&& node->getFirstChild()->getOpCode().isLoadVarDirect()3078&& node->getFirstChild()->getSymbol()->isAutoOrParm()3079&& _aliasesOfOtherAllocNode->get(node->getFirstChild()->getSymbolReference()->getReferenceNumber()))3080{3081_aliasesOfOtherAllocNode->set(node->getSymbolReference()->getReferenceNumber());3082}3083else3084{3085_aliasesOfOtherAllocNode->reset(node->getSymbolReference()->getReferenceNumber());3086}3087}30883089for (int32_t i = 0; i < node->getNumChildren(); i++)3090{3091collectAliasesOfAllocations(node->getChild(i), allocNode);3092}3093}309430953096bool TR_EscapeAnalysis::checkIfUseIsInSameLoopAsDef(TR::TreeTop *defTree, TR::Node *useNode)3097{3098TR::Block *block = defTree->getEnclosingBlock();3099TR_RegionStructure *highestCyclicStructure = NULL;3100TR_Structure *structure = block->getStructureOf()->getParent();3101while (structure)3102{3103if (!structure->asRegion()->isAcyclic())3104highestCyclicStructure = structure->asRegion();3105structure = structure->getParent();3106}31073108if (highestCyclicStructure)3109{3110TR::NodeChecklist visited (comp());3111TR_ScratchList<TR::Block> blocksInRegion(trMemory());3112highestCyclicStructure->getBlocks(&blocksInRegion);31133114ListIterator<TR::Block> blocksIt(&blocksInRegion);3115TR::Block *nextBlock;3116for (nextBlock = blocksIt.getCurrent(); nextBlock; nextBlock=blocksIt.getNext())3117{3118TR::TreeTop *currentTree = nextBlock->getEntry();3119TR::TreeTop *exitTree = nextBlock->getExit();3120while (currentTree &&3121(currentTree != exitTree))3122{3123if (checkUse(currentTree->getNode(), useNode, visited))3124return true;31253126currentTree = currentTree->getNextTreeTop();3127}3128}31293130return false;3131}3132else3133return true;31343135return true;3136}313731383139bool TR_EscapeAnalysis::checkIfUseIsInLoopAndOverlapping(Candidate *candidate, TR::TreeTop *defTree, TR::Node *useNode)3140{3141TR::NodeChecklist visited (comp());3142TR::BlockChecklist vBlocks (comp());3143TR::TreeTop *allocTree = candidate->_treeTop;3144if (trace())3145traceMsg(comp(), "Started checking for candidate %p\n", candidate->_node);3146bool decisionMade = false;3147bool b = checkIfUseIsInLoopAndOverlapping(allocTree->getNextTreeTop(), candidate->_block->getExit(), defTree, useNode, visited, vBlocks, decisionMade);3148if (trace())3149traceMsg(comp(), "Finished checking for candidate %p\n", candidate->_node);3150return b;3151}315231533154bool TR_EscapeAnalysis::checkIfUseIsInLoopAndOverlapping(TR::TreeTop *start, TR::TreeTop *end, TR::TreeTop *defTree, TR::Node *useNode, TR::NodeChecklist& visited, TR::BlockChecklist& vBlocks, bool & decisionMade)3155{3156TR::TreeTop *currentTree = start;3157while (currentTree && (currentTree != end))3158{3159if (checkUse(currentTree->getNode(), useNode, visited))3160{3161decisionMade = true;3162if (trace())3163traceMsg(comp(), "Returning TRUE at %p\n", currentTree->getNode());3164return true;3165}31663167if (currentTree == defTree)3168{3169if (trace())3170traceMsg(comp(), "Returning FALSE at %p\n", currentTree->getNode());3171decisionMade = true;3172return false;3173}31743175if (currentTree->getNode()->getOpCode().isStore() &&3176(currentTree->getNode()->getSymbolReference() == useNode->getSymbolReference()))3177{3178if (trace())3179traceMsg(comp(), "Returning FALSE at %p\n", currentTree->getNode());3180decisionMade = true;3181return false;3182}31833184if ((currentTree->getNode()->getNumChildren() > 0) &&3185currentTree->getNode()->getFirstChild()->getOpCode().isStore() &&3186(currentTree->getNode()->getFirstChild()->getSymbolReference() == useNode->getSymbolReference()))3187{3188if (trace())3189traceMsg(comp(), "Returning FALSE at %p\n", currentTree->getNode());3190decisionMade = true;3191return false;3192}31933194currentTree = currentTree->getNextTreeTop();3195}31963197TR::Block *block = end->getEnclosingBlock();3198vBlocks.add(block);3199TR::CFG *cfg = comp()->getFlowGraph();32003201for (auto nextEdge = block->getSuccessors().begin(); nextEdge != block->getSuccessors().end(); ++nextEdge)3202{3203TR::Block *next = toBlock((*nextEdge)->getTo());3204decisionMade = false;3205if (!vBlocks.contains(next) && (next != cfg->getEnd()))3206{3207if (trace())3208traceMsg(comp(), "Looking at block_%d\n", next->getNumber());3209bool b = checkIfUseIsInLoopAndOverlapping(next->getEntry(), next->getExit(), defTree, useNode, visited, vBlocks, decisionMade);3210if (decisionMade)3211{3212if (b)3213return true;3214}3215}3216else3217decisionMade = true;3218}32193220for (auto nextEdge = block->getExceptionSuccessors().begin(); nextEdge != block->getExceptionSuccessors().end(); ++nextEdge)3221{3222TR::Block *next = toBlock((*nextEdge)->getTo());3223decisionMade = false;3224if (!vBlocks.contains(next) && (next != cfg->getEnd()))3225{3226if (trace())3227traceMsg(comp(), "Looking at block_%d\n", next->getNumber());3228bool b = checkIfUseIsInLoopAndOverlapping(next->getEntry(), next->getExit(), defTree, useNode, visited, vBlocks, decisionMade);3229if (decisionMade)3230{3231if (b)3232return true;3233}3234}3235else3236decisionMade = true;3237}32383239if (trace())3240traceMsg(comp(), "Returning FALSE at block_%d\n", block->getNumber());3241return false;3242}324332443245bool TR_EscapeAnalysis::checkUse(TR::Node *node, TR::Node *useNode, TR::NodeChecklist& visited)3246{3247if (visited.contains(node))3248return false;3249visited.add(node);32503251if (node == useNode)3252return true;32533254int32_t i;3255for (i = 0; i < node->getNumChildren(); ++i)3256{3257if (checkUse(node->getChild(i), useNode, visited))3258return true;3259}32603261return false;3262}326332643265Candidate *TR_EscapeAnalysis::findCandidate(int32_t valueNumber)3266{3267for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())3268{3269if (candidate->_valueNumbers->element(0) == valueNumber)3270return candidate;3271}3272return NULL;3273}32743275bool TR_EscapeAnalysis::usesValueNumber(Candidate *candidate, int32_t valueNumber)3276{3277for (int32_t i = candidate->_valueNumbers->size()-1; i >= 0; i--)3278{3279if (candidate->_valueNumbers->element(i) == valueNumber)3280return true;3281}3282return false;3283}32843285// Remove any candidates that match the given value number3286//3287void TR_EscapeAnalysis::forceEscape(TR::Node *node, TR::Node *reason, bool forceFail)3288{3289TR::Node *resolvedNode = resolveSniffedNode(node);3290if (!resolvedNode)3291return;32923293int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);3294Candidate *candidate, *next;3295for (candidate = _candidates.getFirst(); candidate; candidate = next)3296{3297next = candidate->getNext();3298if (usesValueNumber(candidate, valueNumber))3299{3300if (!forceFail && checkIfEscapePointIsCold(candidate, reason))3301{3302if (!isImmutableObject(candidate))3303{3304if (trace())3305traceMsg(comp(), " Make [%p] contiguous because of node [%p]\n", candidate->_node, reason);3306candidate->setMustBeContiguousAllocation();3307//candidate->setLocalAllocation(false);3308}3309else3310candidate->setObjectIsReferenced();3311}3312else3313{3314if(candidate->forceLocalAllocation())3315{3316if(trace())3317traceMsg(comp(), " Normally would fail [%p] because it escapes via node [%p] (cold %d), but user forces it to be local\n",3318candidate->_node, reason, _inColdBlock);3319continue;3320}33213322if (trace())3323traceMsg(comp(), " Fail [%p] because it escapes via node [%p] (cold %d)\n", candidate->_node, reason, _inColdBlock);33243325rememoize(candidate);3326_candidates.remove(candidate);3327}3328}3329}3330}333133323333void TR_EscapeAnalysis::markCandidatesUsedInNonColdBlock(TR::Node *node)3334{3335TR::Node *resolvedNode = resolveSniffedNode(node);3336if (!resolvedNode)3337return;33383339int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);3340Candidate *candidate, *next;3341for (candidate = _candidates.getFirst(); candidate; candidate = next)3342{3343next = candidate->getNext();3344if (!candidate->usedInNonColdBlock() && usesValueNumber(candidate, valueNumber))3345{3346candidate->setUsedInNonColdBlock();3347if (trace())3348traceMsg(comp(), " Mark [%p] used in non-cold block because of node [%p]\n", candidate->_node, node);3349}3350}3351}3352335333543355bool TR_EscapeAnalysis::detectStringCopy(TR::Node *node)3356{3357TR::Node *baseNode = node->getFirstChild();3358TR::Node *valueNode = node->getSecondChild();33593360Candidate *candidate, *next;3361for (candidate = _candidates.getFirst(); candidate; candidate = next)3362{3363next = candidate->getNext();3364if ((baseNode == candidate->_node) &&3365(baseNode->getOpCodeValue() == TR::New) &&3366node->getOpCode().isIndirect() &&3367(baseNode->getFirstChild()->getSymbolReference()->getSymbol()->getStaticSymbol()->getStaticAddress() == comp()->getStringClassPointer()))3368{3369if (valueNode->getOpCode().isIndirect() &&3370(valueNode->getSymbolReference() == node->getSymbolReference()) &&3371(valueNode->getFirstChild()->getOpCode().isLoadVar() && !valueNode->getFirstChild()->getSymbolReference()->isUnresolved()) &&3372((valueNode->getFirstChild() == candidate->_stringCopyNode) ||3373(candidate->_stringCopyNode == NULL)))3374{3375bool fitsPattern = true;3376if (!candidate->_stringCopyNode)3377{3378TR::TreeTop *cursorTree = candidate->_treeTop->getNextTreeTop();3379while (cursorTree)3380{3381TR::Node *cursorNode = cursorTree->getNode();3382if ((cursorNode == node) ||3383(cursorNode->getOpCode().isAnchor() && (cursorNode->getFirstChild() == node)) ||3384(cursorNode->getOpCodeValue() == TR::BBEnd))3385break;33863387if (cursorNode->getOpCodeValue() == TR::treetop)3388{3389if (cursorNode->getFirstChild()->getOpCode().isCall() ||3390cursorNode->getFirstChild()->getOpCode().isStore())3391fitsPattern = false;3392}3393else if (cursorNode->getOpCodeValue() == TR::astore)3394{3395if ((cursorNode->getFirstChild() != baseNode) &&3396(cursorNode->getFirstChild() != valueNode->getFirstChild()))3397fitsPattern = false;3398}3399else if (cursorNode->getOpCodeValue() == TR::NULLCHK)3400{3401if (cursorNode->getFirstChild() != valueNode)3402fitsPattern = false;3403}3404else if (cursorNode->getOpCode().isAnchor())3405{3406// do nothing;3407}3408else3409fitsPattern = false;34103411if (!fitsPattern)3412break;34133414cursorTree = cursorTree->getNextTreeTop();3415}3416}34173418if (fitsPattern)3419{3420candidate->_stringCopyNode = valueNode->getFirstChild();3421return true;3422}3423else3424candidate->_stringCopyNode = baseNode;3425}3426else3427candidate->_stringCopyNode = baseNode;3428}3429}34303431return false;3432}3433343434353436343734383439// Restrict any candidates that match the given value number.3440// The restriction can be to prevent the local allocation or just to make it3441// a contiguous local allocation. Desynchronization is not affected.3442// Return "true" if any candidates were restricted.3443//3444bool TR_EscapeAnalysis::restrictCandidates(TR::Node *node, TR::Node *reason, restrictionType type)3445{3446TR::Node *resolvedNode = resolveSniffedNode(node);3447if (!resolvedNode)3448return false;34493450bool locked = false;3451if (reason &&3452((reason->getOpCodeValue() == TR::monent) ||3453(reason->getOpCodeValue() == TR::monexit)))3454locked = true;34553456int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);3457Candidate *candidate;3458bool wasRestricted = false;3459for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())3460{3461if (candidate->isLocalAllocation() && usesValueNumber(candidate, valueNumber))3462{3463if (reason->getOpCodeValue() == TR::arraycopy)3464candidate->_seenArrayCopy = true;34653466if (locked)3467{3468if (!_inColdBlock)3469{3470candidate->setLockedInNonColdBlock(true);3471candidate->setUsedInNonColdBlock(true);3472if (trace())3473traceMsg(comp(), " Mark [%p] used and locked in non-cold block because of node [%p]\n", candidate->_node, node);3474}34753476candidate->setLockedObject(true);3477int32_t lockedObjectValueNumber = _valueNumberInfo->getValueNumber(reason->getFirstChild());3478Candidate *lockedCandidate = findCandidate(lockedObjectValueNumber);3479if (!lockedCandidate)3480{3481if (trace())3482traceMsg(comp(), " Make [%p] non-local because of node [%p]\n", candidate->_node, reason);3483wasRestricted = true;3484//candidate->setLocalAllocation(false);3485forceEscape(reason->getFirstChild(), reason);3486continue;3487}34883489TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());3490if (_parms && fej9->hasTwoWordObjectHeader())3491{3492TR_ScratchList<TR_ResolvedMethod> resolvedMethodsInClass(trMemory());3493fej9->getResolvedMethods(trMemory(), (TR_OpaqueClassBlock *) candidate->_class, &resolvedMethodsInClass);3494bool containsSyncMethod = false;3495ListIterator<TR_ResolvedMethod> resolvedIt(&resolvedMethodsInClass);3496TR_ResolvedMethod *resolvedMethod;3497for (resolvedMethod = resolvedIt.getFirst(); resolvedMethod; resolvedMethod = resolvedIt.getNext())3498{3499if (resolvedMethod->isSynchronized())3500{3501containsSyncMethod = true;3502break;3503}3504}3505if (!containsSyncMethod)3506{3507if (trace())3508traceMsg(comp(), " Make [%p] non-local because of node [%p]\n", candidate->_node, reason);3509wasRestricted = true;3510candidate->setLocalAllocation(false);3511continue;3512}3513}3514}35153516if (type == MakeNonLocal)3517{3518if (checkIfEscapePointIsCold(candidate, reason))3519{3520//candidate->setObjectIsReferenced();3521if (trace())3522traceMsg(comp(), " Do not make [%p] non-local because of cold node [%p]\n", candidate->_node, reason);3523}3524else3525{3526if (trace())3527traceMsg(comp(), " Make [%p] non-local because of node [%p]\n", candidate->_node, reason);3528candidate->setLocalAllocation(false);3529}35303531if (!isImmutableObject(candidate))3532wasRestricted = true;3533}3534else3535{3536if (type == MakeContiguous)3537{3538// make contiguous3539//3540if (checkIfEscapePointIsCold(candidate, reason))3541{3542//candidate->setObjectIsReferenced();3543if (trace())3544traceMsg(comp(), " Do not make [%p] contiguous because of cold node [%p]\n", candidate->_node, reason);3545}3546else3547{3548if (trace())3549traceMsg(comp(), " Make [%p] contiguous because of node [%p]\n", candidate->_node, reason);3550candidate->setMustBeContiguousAllocation();3551}35523553if (!isImmutableObject(candidate))3554wasRestricted = true;3555}3556else if (!candidate->objectIsReferenced() &&3557!candidate->mustBeContiguousAllocation())3558{3559if (trace())3560traceMsg(comp(), " Make [%p] object-referenced because of node [%p]\n", candidate->_node, reason);3561candidate->setObjectIsReferenced();3562wasRestricted = true;3563}3564}3565}3566}3567return wasRestricted;3568}35693570357135723573bool TR_EscapeAnalysis::checkIfEscapePointIsCold(Candidate *candidate, TR::Node *node)3574{3575if (_curBlock->isOSRCodeBlock() ||3576_curBlock->isOSRCatchBlock())3577return false;35783579if (isEscapePointCold(candidate, node))3580{3581int32_t j;3582bool canStoreToHeap = true;3583for(j=0;j<node->getNumChildren();j++)3584{3585TR::Node *child = node->getChild(j);3586TR::Node *resolvedChildAtTopLevel = resolveSniffedNode(child);3587if (!resolvedChildAtTopLevel)3588continue;35893590if (usesValueNumber(candidate, _valueNumberInfo->getValueNumber(resolvedChildAtTopLevel)))3591{3592if (resolvedChildAtTopLevel->getOpCode().isLoadVarDirect() &&3593(_curBlock != candidate->_block) &&3594(_curBlock != comp()->getStartBlock()))3595{3596bool recognizedCatch = true;3597if (_curBlock->isCatchBlock())3598{3599TR::Node *firstTree = _curBlock->getEntry()->getNextTreeTop()->getNode();3600if (!firstTree->getOpCode().isStoreDirect() ||3601!firstTree->getSymbol()->isAuto() ||3602!firstTree->getFirstChild()->getOpCode().hasSymbolReference() ||3603(firstTree->getFirstChild()->getSymbolReference() != comp()->getSymRefTab()->findOrCreateExcpSymbolRef()))3604recognizedCatch = false;3605}3606if (recognizedCatch)3607{3608if (trace())3609traceMsg(comp(), "Adding cold block info for child %p value number %d candidate %p\n", child, _valueNumberInfo->getValueNumber(resolvedChildAtTopLevel), candidate->_node);36103611candidate->addColdBlockEscapeInfo(_curBlock, resolvedChildAtTopLevel, _curTree);3612}3613else3614{3615if (trace())3616traceMsg(comp(), " For candidate [%p], seen an unexpected opcode in child [%p] of call [%p]\n", candidate->_node, child, node);36173618canStoreToHeap = false;3619}3620}3621else3622{3623if (trace())3624traceMsg(comp(), " For candidate [%p], seen an unexpected opcode in child [%p] of call [%p]\n", candidate->_node, child, node);36253626canStoreToHeap = false;3627}3628}3629}36303631if (canStoreToHeap)3632{3633candidate->setObjectIsReferenced();36343635if (!isImmutableObject(candidate) && (_parms || !node->getOpCode().isReturn()))3636{3637//candidate->setObjectIsReferenced();3638if (trace())3639traceMsg(comp(), " Make candidate [%p] contiguous to allow heapification\n", candidate->_node);3640candidate->setMustBeContiguousAllocation();3641}36423643return true;3644}3645}3646return false;3647}36483649365036513652static void checkForDifferentSymRefs(Candidate *candidate, int32_t i, TR::SymbolReference *symRef, TR_EscapeAnalysis *ea, bool peeking)3653{3654static char *dontCheckForDifferentSymRefsInEA = feGetEnv("TR_dontCheckForDifferentSymRefsInEA");3655if (dontCheckForDifferentSymRefsInEA)3656{3657// We don't need this logic anymore generally. Leaving it in place for3658// Java8 release to reduce disruption and risk.3659//3660return;3661}36623663TR::Compilation *comp = TR::comp();3664TR::SymbolReference *memorizedSymRef = candidate->_fields->element(i).fieldSymRef();3665TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());36663667if (memorizedSymRef &&3668(memorizedSymRef != symRef) &&3669(symRef->isUnresolved() ||3670memorizedSymRef->isUnresolved() ||3671((symRef->getOffset() >= (int32_t) fej9->getObjectHeaderSizeInBytes()) &&3672(memorizedSymRef->getOffset() >= (int32_t) fej9->getObjectHeaderSizeInBytes()))))3673{3674if ( memorizedSymRef->getCPIndex() == -13675|| symRef->getCPIndex() == -13676|| !TR::Compiler->cls.jitFieldsAreSame(comp, memorizedSymRef->getOwningMethod(comp), memorizedSymRef->getCPIndex(), symRef->getOwningMethod(comp), symRef->getCPIndex(), symRef->getSymbol()->isStatic()))3677{3678bool aliasingIsSafe = false;3679if (peeking)3680{3681// Aliasing queries don't even work on peeked nodes because their3682// symRef numbers refer to a different symRef table, so aliasing3683// info can't possibly be required for correctness.3684//3685// Having said that, we'll use "false" here to be conservative.3686//3687aliasingIsSafe = false;3688}3689else3690{3691aliasingIsSafe = symRef->getUseDefAliases(false).contains(memorizedSymRef, comp);3692}3693if (!aliasingIsSafe)3694{3695if (ea->trace())3696{3697traceMsg(comp, "candidate n%dn %p excluded coz of ambiguous field symrefs #%d [%s] and [%s]\n",3698candidate->_node->getGlobalIndex(), candidate->_node,3699memorizedSymRef->getReferenceNumber(), memorizedSymRef->getName(comp->getDebug()),3700symRef->getName(comp->getDebug()));3701}3702//(*candidate->_fields)[i]._isPresentInAllocatedClass=false;3703candidate->setLocalAllocation(false);3704}3705}3706}3707}370837093710TR::SymbolReference *FieldInfo::fieldSymRef()3711{3712return _goodFieldSymrefs->getHeadData();3713}37143715bool FieldInfo::symRefIsForFieldInAllocatedClass(TR::SymbolReference *symRef)3716{3717if (_goodFieldSymrefs->find(symRef))3718return true;37193720if (_badFieldSymrefs->find(symRef))3721return false;37223723TR_ASSERT(0, "symRefIsForFieldInAllocatedClass expects symref #%d to have been remembered", symRef->getReferenceNumber());3724return true;3725}37263727bool FieldInfo::hasBadFieldSymRef()3728{3729return !_badFieldSymrefs->isEmpty();3730}37313732void FieldInfo::rememberFieldSymRef(TR::Node *fieldNode, int32_t fieldOffset, Candidate *candidate, TR_EscapeAnalysis *ea)3733{3734TR_ASSERT(!ea->_parms, "rememberFieldSymRef: cannot remember peeked field SymRefs");37353736TR::SymbolReference *symRef = fieldNode->getSymbolReference();3737if (_goodFieldSymrefs->find(symRef) || _badFieldSymrefs->find(symRef))3738{3739// Nothing to do3740}3741else3742{3743bool isGood = false;3744switch (candidateHasField(candidate, fieldNode, _offset, ea))3745{3746case TR_yes:3747isGood = true;3748break;3749case TR_no:3750isGood = false;3751break;3752default:3753// Older (questionable) r11-era logic based on object size bound3754isGood = (_offset + _size <= candidate->_size);3755break;3756}37573758if (isGood)3759{3760int32_t fieldSize = fieldNode->getSize();3761if (ea->comp()->useCompressedPointers() && fieldNode->getDataType() == TR::Address)3762fieldSize = TR::Compiler->om.sizeofReferenceField();3763_size = fieldSize;3764_goodFieldSymrefs->add(symRef);3765}3766else3767{3768_badFieldSymrefs->add(symRef);3769}3770}3771}377237733774// Remember the use of a field in any candidates that can match the given node.3775//3776void TR_EscapeAnalysis::referencedField(TR::Node *base, TR::Node *field, bool isStore, bool seenSelfStore, bool seenStoreToLocalObject)3777{3778TR::Node *resolvedNode = resolveSniffedNode(base);3779if (!resolvedNode)3780return;37813782TR::SymbolReference *symRef = field->getSymbolReference();3783if (symRef->isUnresolved())3784{3785forceEscape(base, field, true);3786return;3787}37883789bool usesStackTrace = false;3790if (!isStore)3791{3792if (symRef->getSymbol()->getRecognizedField() == TR::Symbol::Java_lang_Throwable_stackTrace)3793usesStackTrace = true;3794}3795int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);3796int32_t storedValueNumber = -1;3797if (seenStoreToLocalObject)3798{3799TR::Node *resolvedStoredValueNode = resolveSniffedNode(field->getSecondChild());3800if (resolvedStoredValueNode)3801storedValueNumber = _valueNumberInfo->getValueNumber(resolvedStoredValueNode);3802else3803seenStoreToLocalObject = false;3804}38053806Candidate *candidate;3807for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())3808{3809if (seenStoreToLocalObject)3810{3811if (candidate->isLocalAllocation() && usesValueNumber(candidate, storedValueNumber))3812{3813if (candidate->isInsideALoop())3814{3815candidate->setLocalAllocation(false);3816if (trace())3817traceMsg(comp(), "7 setting local alloc %p to false\n", candidate->_node);3818}3819else3820candidate->_seenStoreToLocalObject = true;3821}3822}38233824if (candidate->isLocalAllocation() && usesValueNumber(candidate, valueNumber))3825{3826if (usesStackTrace)3827{3828candidate->setUsesStackTrace();3829candidate->setMustBeContiguousAllocation();3830if (trace())3831traceMsg(comp(), " Make [%p] contiguous because of setUsesStackTrace\n", candidate->_node);3832}38333834// Only remember fields that are actually present in the allocated3835// object. It is possible to reach uses which (via downcasting) are3836// referencing a derived class, or even an unrelated class. At run3837// time the local allocation would never reach these program points,3838// but they are still "reachable" from a dataflow perspective, so we3839// must be aware of them.3840//3841if (isStore)3842{3843candidate->_seenFieldStore = true;3844if (seenSelfStore)3845candidate->_seenSelfStore = true;3846}38473848int32_t fieldOffset = symRef->getOffset();3849if (candidate->_origKind == TR::New)3850{3851fieldOffset = symRef->getOffset();3852}3853else3854{3855TR::Node *offsetNode = NULL;3856if (field->getFirstChild()->getOpCode().isArrayRef())3857offsetNode = field->getFirstChild()->getSecondChild();38583859if (offsetNode && offsetNode->getOpCode().isLoadConst())3860{3861if (offsetNode->getType().isInt64())3862fieldOffset = (int32_t) offsetNode->getLongInt();3863else3864fieldOffset = offsetNode->getInt();3865}3866}38673868TR::DataType refType = symRef->getSymbol()->getDataType();3869TR::DataType fieldType = refType;3870int N = 1;3871if (refType.isVector())3872{3873fieldType = refType.vectorToScalar();3874N = TR::Symbol::convertTypeToSize(refType)/TR::Symbol::convertTypeToSize(fieldType) ;3875}3876for (int j = 0; j < N; j++)3877{3878const bool isPeeking = (_parms != NULL);38793880int32_t i;3881if (!candidate->_fields)3882{3883candidate->_fields = new (trStackMemory()) TR_Array<FieldInfo>(trMemory(), 8, false, stackAlloc);3884i = -1;3885}3886else3887{3888for (i = candidate->_fields->size()-1; i >= 0; i--)3889{3890if (candidate->_fields->element(i)._offset == fieldOffset)3891{3892checkForDifferentSymRefs(candidate, i, symRef, this, isPeeking);3893break;3894}3895}3896}3897if (i < 0)3898{3899i = candidate->_fields->size();3900(*candidate->_fields)[i]._offset = fieldOffset;3901int32_t fieldSize = field->getSize();3902if (comp()->useCompressedPointers() && field->getDataType() == TR::Address)3903fieldSize = TR::Compiler->om.sizeofReferenceField();3904(*candidate->_fields)[i]._symRef = NULL;3905(*candidate->_fields)[i]._size = fieldSize;3906(*candidate->_fields)[i]._vectorElem = 0;3907(*candidate->_fields)[i]._goodFieldSymrefs = new (trStackMemory()) TR_ScratchList<TR::SymbolReference>(trMemory());3908(*candidate->_fields)[i]._badFieldSymrefs = new (trStackMemory()) TR_ScratchList<TR::SymbolReference>(trMemory());3909}3910if (!isPeeking)3911(*candidate->_fields)[i].rememberFieldSymRef(field, fieldOffset, candidate, this);39123913if (N > 1) // vector3914{3915(*candidate->_fields)[i]._vectorElem = j+1;3916fieldOffset += TR::Symbol::convertTypeToSize(fieldType);3917}3918}3919}3920}3921}3922392339243925// Resolve the node if it is a parameter reference3926//3927TR::Node *TR_EscapeAnalysis::resolveSniffedNode(TR::Node *node)3928{3929if (_parms == NULL)3930return node;3931if (!node->getOpCode().isLoadVarOrStore() &&3932(node->getOpCodeValue() != TR::loadaddr))3933return NULL;3934TR::Symbol *sym = node->getSymbol();3935if (!sym->isParm())3936return NULL;3937return _parms->element(sym->getParmSymbol()->getOrdinal());3938}39393940void TR_EscapeAnalysis::checkEscape(TR::TreeTop *firstTree, bool isCold, bool & ignoreRecursion)3941{3942TR::Node *node;3943TR::TreeTop *treeTop;39443945// Do string copy pattern matching first and fix value numbers accordingly3946for (treeTop = firstTree; treeTop && !_candidates.isEmpty(); treeTop = treeTop->getNextTreeTop())3947{3948node = treeTop->getNode();3949if (node->getOpCode().isStoreIndirect() && detectStringCopy(node))3950{3951TR::Node *baseNode = node->getFirstChild();3952int32_t baseNodeVN = _valueNumberInfo->getValueNumber(baseNode);3953TR::Node *copyNode = node->getSecondChild()->getFirstChild();3954int32_t copyNodeVN = _valueNumberInfo->getValueNumber(copyNode);3955Candidate *baseCandidate = findCandidate(baseNodeVN);3956Candidate *candidate = NULL;39573958TR_ASSERT(baseCandidate, "There must be a candidate corresponding to the base node VN");3959if (trace())3960traceMsg(comp(), "Base candidate: [%p], base node VN: %d, copy node VN: %d\n",3961baseCandidate->_node, baseNodeVN, copyNodeVN);39623963for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())3964{3965if (usesValueNumber(candidate, copyNodeVN))3966{3967for (int32_t i = baseCandidate->_valueNumbers->size()-1; i >= 0; i--)3968{3969int32_t valueNumber = baseCandidate->_valueNumbers->element(i);3970if (!candidate->_valueNumbers->contains(valueNumber))3971candidate->_valueNumbers->add(valueNumber);3972}3973}3974}3975}3976else if (0 && (node->getOpCodeValue() != TR::call) &&3977(node->getNumChildren() > 0))3978{3979node = node->getFirstChild();3980if ((node->getOpCodeValue() == TR::call) &&3981!node->getSymbolReference()->isUnresolved() &&3982!node->getSymbol()->castToMethodSymbol()->isHelper() &&3983(node->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->getRecognizedMethod() == TR::java_lang_String_init_String) &&3984(treeTop->getPrevTreeTop()->getNode()->getNumChildren() > 0) &&3985(node->getFirstChild()->getOpCodeValue() == TR::New) &&3986(node->getFirstChild() == treeTop->getPrevTreeTop()->getNode()->getFirstChild()))3987{3988TR::Node *baseNode = node->getFirstChild();3989Candidate *candidate, *next;3990for (candidate = _candidates.getFirst(); candidate; candidate = next)3991{3992next = candidate->getNext();39933994if ((candidate->_stringCopyNode == NULL) ||3995(candidate->_stringCopyNode == node->getSecondChild()))3996{3997if ((baseNode == candidate->_node) &&3998(baseNode->getOpCodeValue() == TR::New) &&3999(baseNode->getFirstChild()->getSymbolReference()->getSymbol()->getStaticSymbol()->getStaticAddress() == comp()->getStringClassPointer()) &&4000(candidate->_treeTop->getNextTreeTop() == treeTop))4001{4002candidate->_stringCopyCallTree = treeTop;4003candidate->_stringCopyNode = node->getSecondChild();4004//traceMsg(comp(), "11cand node %p string copy node %p and node %p\n", candidate->_node, candidate->_stringCopyNode, node);4005TR::Node *baseNode = node->getFirstChild();4006int32_t baseNodeVN = _valueNumberInfo->getValueNumber(baseNode);4007TR::Node *copyNode = node->getSecondChild();4008int32_t copyNodeVN = _valueNumberInfo->getValueNumber(copyNode);4009Candidate *baseCandidate = findCandidate(baseNodeVN);4010Candidate *candidate = NULL;40114012TR_ASSERT(baseCandidate, "There must be a candidate corresponding to the base node VN");4013if (trace())4014traceMsg(comp(), "Base candidate: [%p], base node VN: %d, copy node VN: %d\n",4015baseCandidate->_node, baseNodeVN, copyNodeVN);40164017for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())4018{4019if (usesValueNumber(candidate, copyNodeVN))4020{4021for (int32_t i = baseCandidate->_valueNumbers->size()-1; i >= 0; i--)4022{4023int32_t valueNumber = baseCandidate->_valueNumbers->element(i);4024if (!candidate->_valueNumbers->contains(valueNumber))4025candidate->_valueNumbers->add(valueNumber);4026}4027}4028}4029}4030else if (candidate->_node == node->getFirstChild())4031{4032candidate->_stringCopyNode = node->getFirstChild();4033//traceMsg(comp(), "22cand node %p string copy node %p and node %p\n", candidate->_node, candidate->_stringCopyNode, node);4034}4035}4036}4037}4038}4039}40404041// First eliminate all allocations that are not allowed because of nodes4042// other than calls, then go through again and eliminate the allocations4043// that are not allowed because of calls alone. This reduces the amount of4044// sniffing required into called methods.4045//4046_classObjectLoadForVirtualCall = false;4047TR::NodeChecklist vnsNoCall (comp());40484049for (treeTop = firstTree; treeTop && !_candidates.isEmpty(); treeTop = treeTop->getNextTreeTop())4050{4051node = treeTop->getNode();4052if (!_parms)4053{4054_curTree = treeTop;4055//_curNode = node;4056}40574058if (node->getOpCodeValue() == TR::BBStart)4059{4060if (!_parms || !_inColdBlock)4061{4062_inColdBlock = false;4063if (!_parms)4064_curBlock = node->getBlock();4065if (((_curBlock->isCold() ||4066_curBlock->isCatchBlock() ||4067//(_curBlock->getHotness(comp()->getFlowGraph()) == deadCold)) &&4068(_curBlock->getFrequency() == (MAX_COLD_BLOCK_COUNT+1))) &&4069!_parms) ||4070isCold)4071_inColdBlock = true;4072}4073}40744075if (!vnsNoCall.contains(node))4076checkEscapeViaNonCall(node, vnsNoCall);4077}40784079bool oldIgnoreRecursion = ignoreRecursion;4080TR::NodeChecklist vnsCall (comp());4081for (treeTop = firstTree; treeTop && !_candidates.isEmpty(); treeTop = treeTop->getNextTreeTop())4082{4083node = treeTop->getNode();4084if (!_parms)4085{4086_curTree = treeTop;4087//_curNode = node;4088}40894090if (node->getOpCodeValue() == TR::BBStart)4091{4092if (!_parms || !_inColdBlock)4093{4094_inColdBlock = false;4095if (!_parms)4096_curBlock = node->getBlock();4097if ((_curBlock->isCold() ||4098_curBlock->isCatchBlock() ||4099//(_curBlock->getHotness(comp()->getFlowGraph()) == deadCold)) &&4100(_curBlock->getFrequency() == (MAX_COLD_BLOCK_COUNT+1))) &&4101!_parms)4102_inColdBlock = true;4103}4104}41054106ignoreRecursion = oldIgnoreRecursion;4107if (node->getOpCode().isCheck() || node->getOpCodeValue() == TR::treetop)4108node = node->getFirstChild();4109if (node->getOpCode().isCall() && !vnsCall.contains(node))4110{4111if (node->getSymbolReference()->getReferenceNumber() != TR_prepareForOSR4112|| comp()->getOSRMode() != TR::voluntaryOSR4113|| _curBlock->isOSRInduceBlock())4114checkEscapeViaCall(node, vnsCall, ignoreRecursion);4115}4116}4117}41184119static bool isConstantClass(TR::Node *classNode, TR_EscapeAnalysis *ea)4120{4121bool result = false;4122TR::Compilation *comp = ea->comp();41234124// New logic.4125// If classNode represents a class address, return that class.4126//4127if ( classNode->getOpCodeValue() == TR::loadaddr4128&& classNode->getSymbol()->isStatic()4129&& !classNode->getSymbolReference()->isUnresolved()4130){4131result = true;4132}41334134if (ea->trace())4135traceMsg(comp, " isConstantClass(%p)=%s (supportsInliningOfIsInstance=%s)\n", classNode, result?"true":"false", comp->cg()->supportsInliningOfIsInstance()?"true":"false");4136return result;4137}41384139static bool isFinalizableInlineTest(TR::Compilation *comp, TR::Node *candidate, TR::Node *root, TR::Node *vftLoad)4140{4141TR_ASSERT(vftLoad->getOpCode().isLoadIndirect() &&4142vftLoad->getFirstChild() == candidate &&4143vftLoad->getSymbolReference()->getSymbol()->isClassObject() &&4144candidate->getOpCode().isRef(),4145"Expecting indirect load of class ptr off potential candidate reference");41464147TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());41484149bool is64Bit = comp->target().is64Bit();41504151// root4152// r1 - first child of root4153// r11 - first child of first child of root4154// r12 - second child of first child of root4155// r2 - second child of root4156TR::Node *r1 = (root->getNumChildren() > 0) ? root->getFirstChild() : NULL;4157TR::Node *r2 = (root->getNumChildren() > 1) ? root->getSecondChild() : NULL;4158TR::Node *r11 = (r1 && r1->getNumChildren() > 0) ? r1->getFirstChild() : NULL;4159TR::Node *r12 = (r1 && r1->getNumChildren() > 1) ? r1->getSecondChild() : NULL;41604161bool castDownToInt = is64Bit && r11 && (r11->getOpCodeValue() == TR::l2i);4162bool usesLongOps = is64Bit && !castDownToInt;41634164TR::ILOpCodes ifOp = usesLongOps ? TR::iflcmpne : TR::ificmpne;4165TR::ILOpCodes andOp = usesLongOps ? TR::land : TR::iand;4166TR::ILOpCodes loadOp = is64Bit ? TR::lloadi : TR::iloadi;4167TR::ILOpCodes constOp = usesLongOps ? TR::lconst : TR::iconst;41684169TR::Node *loadNode = castDownToInt ? r11->getFirstChild() : r11;41704171/*4172Looking for a pattern of:41734174if[i/l]cmpne <root>4175[i/l]and <r1>4176[i/l]loadi <classAndDepthFlags> <r11/loadNode>4177aloadi <vft-symbol> <vftLoad>4178... <ref>4179[i/l]const <FlagValueForFinalizerCheck> <r12>4180[i/l]const 0 <r2>41814182or41834184ificmpne <root>4185iand <r1>4186l2i <r11>4187lloadi <classAndDepthFlags> <loadNode>4188aloadi <vft-symbol> <vftLoad>4189... <ref>4190iconst <FlagValueForFinalizerCheck> <r12>4191iconst 0 <r2>4192*/41934194return root->getOpCodeValue() == ifOp &&4195r1->getOpCodeValue() == andOp &&4196r2->getOpCodeValue() == constOp &&4197(usesLongOps ? r2->getLongInt() : r2->getInt() ) == 0 &&4198loadNode->getOpCodeValue() == loadOp &&4199r12->getOpCodeValue() == constOp &&4200(usesLongOps ? r12->getLongInt() : r12->getInt())4201== fej9->getFlagValueForFinalizerCheck() &&4202loadNode->getFirstChild() == vftLoad /*&& (implied by the above assume)4203root->getFirstChild()->getFirstChild()->getFirstChild()->getFirstChild() == candidate*/;4204}42054206void TR_EscapeAnalysis::checkEscapeViaNonCall(TR::Node *node, TR::NodeChecklist& visited)4207{4208visited.add(node);42094210int32_t i;4211int32_t valueNumber;4212Candidate *candidate;4213bool wasRestricted = false;4214TR::Node *child;42154216// Handle cases that can validly perform an array calculation via TR::aiadd and4217// that don't force the base candidate to be contiguous.4218// Other uses of TR::aiadd to address fields or access array elements will4219// be found during normal processing of checkEscapeViaNonCall and force the4220// base candidate to be contiguous.4221//4222if (node->getOpCode().isLoadVarOrStore() &&4223node->getSymbol()->isArrayShadowSymbol() &&4224node->getOpCode().isIndirect())4225{4226child = node->getFirstChild();4227if (child->getOpCode().isArrayRef())4228{4229TR::Node *arrayOffset = child->getSecondChild();4230if (arrayOffset->getOpCodeValue() == TR::iconst || arrayOffset->getOpCodeValue() == TR::lconst)4231{4232valueNumber = _valueNumberInfo->getValueNumber(child->getFirstChild());4233if (findCandidate(valueNumber))4234visited.add(child);4235}4236}4237}42384239if (node->getOpCode().isBooleanCompare() && node->getFirstChild()->getType().isAddress())4240{4241// If child is a candidate, prohibit dememoization4242//4243if (node->getSecondChild()->isNull())4244{4245// dememoization doesn't break compares with NULL4246}4247else4248{4249for (i = node->getNumChildren() - 1; i >= 0; i--)4250{4251child = node->getChild(i);4252candidate = findCandidate(_valueNumberInfo->getValueNumber(child));4253if (candidate && candidate->_dememoizedConstructorCall)4254{4255if (trace())4256traceMsg(comp(), "Rememoize [%p] due to [%p] under address compare [%p]\n", candidate->_node, child, node);4257rememoize(candidate);4258_candidates.remove(candidate);4259}4260}4261}4262}42634264bool classObjectLoadForVirtualCall = _classObjectLoadForVirtualCall;4265for (i = node->getNumChildren() - 1; i >= 0; i--)4266{4267child = node->getChild(i);4268if (!visited.contains(child))4269{4270if (node->getOpCode().isCallIndirect() &&4271(i < node->getFirstArgumentIndex()))4272_classObjectLoadForVirtualCall = true;4273else4274_classObjectLoadForVirtualCall = false;42754276checkEscapeViaNonCall(child, visited);42774278_classObjectLoadForVirtualCall = false;4279}4280}42814282if (node->getOpCodeValue() == TR::areturn)4283{4284static const char *noChar = feGetEnv("TR_NoChar");42854286if (_parms)4287{4288// In a called method, if we're returning an argument to the caller,4289// we can just add the call's value number to the bag of value numbers4290// for the candidate corresponding to the argument being returned.4291// If there is some reason to worry (eg. an assignment to the parm),4292// that will be rejected by other means.4293//4294// HOWEVER this logic has been disabled because at this stage it is4295// too late to add new value numbers to candidates. Much analysis has4296// already occurred, and won't be repeated for the newly added VNs.4297//4298TR::Node *argument = resolveSniffedNode(node->getFirstChild());4299TR::Node *callNode = _curTree->getNode()->getFirstChild();43004301bool doit = true;4302if (!_methodSymbol ||4303!_inBigDecimalAdd ||4304(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_possibleClone))4305doit = false;4306else4307{4308if (trace())4309traceMsg(comp(), "seen bd possible clone at node %p\n", callNode);4310}43114312if ( argument4313&& doit4314&& (callNode->getOpCodeValue() == TR::acall || callNode->getOpCodeValue() == TR::acalli)4315&& _sniffDepth == 1 // Note: this only goes one level deep. If a returns it to b which returns it to the caller, we'll call that an escape.4316&& performTransformation(comp(), "%sPeeked method call [%p] returning argument [%p] NOT considered an escape\n", OPT_DETAILS, callNode, argument))4317{4318// Bingo. Add the call node's value number to the bag for every4319// candidate for which argument is already in the bag.4320//4321if (trace())4322traceMsg(comp(), "call node is %p (depth %d) for which return opt was done\n", callNode, _sniffDepth);4323#if 04324//4325//Note : It's too late anyway for this here...see above comment...so it is disabled4326//4327int32_t argumentValueNumber = _valueNumberInfo->getValueNumber(argument);4328int32_t callValueNumber = _valueNumberInfo->getValueNumber(callNode);43294330if (trace())4331traceMsg(comp(), " Adding call VN %d to all candidates that already have arg VN %d\n", callValueNumber, argumentValueNumber);43324333for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())4334{4335if (candidate->_valueNumbers->contains(argumentValueNumber))4336{4337if (trace())4338traceMsg(comp(), " %s\n", comp()->getDebug()->getName(candidate->_node));4339candidate->_valueNumbers->add(callValueNumber);4340}4341}4342#endif4343}4344else4345{4346forceEscape(node->getFirstChild(), node, true);4347return;4348}4349}43504351// If a return is the only way this object escapes, we cannot make4352// it a local allocation but we can desynchronize it.4353//4354if (!_methodSymbol /* ||4355noChar ||4356( comp()->getJittedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_toString) ||4357(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_longString1) */)4358restrictCandidates(node->getFirstChild(), node, MakeNonLocal);4359return;4360}43614362if (node->getOpCodeValue() == TR::athrow)4363{4364forceEscape(node->getFirstChild(), node);4365return;4366}43674368if (node->getOpCode().hasSymbolReference() &&4369(node->getSymbolReference()->getSymbol() == comp()->getSymRefTab()->findGenericIntShadowSymbol() ||4370node->getSymbol()->isUnsafeShadowSymbol() ||4371node->getDataType().isBCD() ||4372node->getSymbolReference()->getSymbol()->getDataType().isBCD()))4373{4374// PR 80372: Don't take any chances with low-level symbols like GIS and4375// Unsafe. Reject the base object as a candidate, and continue processing4376// in case node is a store and we need to force the RHS to escape.4377//4378TR::Node *baseRef = node->getFirstChild();4379while (baseRef->getOpCode().isArrayRef())4380baseRef = baseRef->getFirstChild();43814382forceEscape(baseRef, node, true);4383}43844385if (node->getOpCode().isArrayRef())4386{4387// If the base of the address calculation is a candidate, it must be4388// contiguous4389//4390restrictCandidates(node->getFirstChild(), node, MakeContiguous);4391return;4392}43934394// Handle loads and stores4395//4396if (node->getOpCode().isLoadVarOrStore())4397{4398if (!_inColdBlock)4399markCandidatesUsedInNonColdBlock(node);44004401if (node->getOpCode().isIndirect())4402{4403bool seenSelfStore = false;4404bool seenStoreToLocalObject = false;44054406// Handle escapes via indirect store of a candidate4407//4408if (node->getOpCode().isStore())4409{4410TR::Node *baseObject = node->getFirstChild();4411if (node->getSymbol()->isArrayShadowSymbol() &&4412baseObject->getOpCode().isArrayRef())4413baseObject = baseObject->getFirstChild();44144415//detectStringCopy(node);44164417// TODO : the code related to local object value numbers4418// can be turned back on if value numbering gives same value numbers4419// to 2 loads of fields of local objects. This is currently not done4420// in value numbering. As a result,4421// <local_object>.f = <new_that_may_be_stack_allocated>4422// <static> = <local_object>.f4423// is a problematic case. We won't track the above escape point and4424// wrongly stack allocate the new. If we are able to track a local4425// object field's value numbers we can hope to see if it 'really' escapes4426// or not.4427//4428//if (!baseObject->getOpCode().hasSymbolReference() ||4429// (!(_nonColdlocalObjectsValueNumbers &&4430// _nonColdlocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(baseObject)))))44314432// java/lang/Throwable.cause addition in SC1411, which disables fillInStackTrace opt in javac4433if ((node->getSecondChild() != baseObject) &&4434(!baseObject->getOpCode().hasSymbolReference() ||4435!node->getSecondChild()->getOpCode().hasSymbolReference() ||4436((baseObject->getReferenceCount() != 1) &&4437(!((baseObject->getReferenceCount() == 2) && (node->getOpCodeValue() == TR::awrtbari) && (node->getChild(2) == baseObject)))) ||4438(node->getSecondChild()->getReferenceCount() != 1) ||4439(baseObject->getSymbolReference() != node->getSecondChild()->getSymbolReference())))4440{4441TR::Node *resolvedBaseObject = resolveSniffedNode(baseObject);4442bool stringCopyOwningMethod = false;4443TR::ResolvedMethodSymbol *owningMeth = node->getSymbolReference()->getOwningMethodSymbol(comp());4444TR::RecognizedMethod methodId = owningMeth->getRecognizedMethod();4445if (methodId == TR::java_lang_String_init_String)4446{4447char *sig = owningMeth->getResolvedMethod()->signatureChars();4448if (!strncmp(sig, "(Ljava/lang/String;)", 20))4449{4450stringCopyOwningMethod = true;4451}4452}44534454if ((!_nonColdLocalObjectsValueNumbers ||4455!_notOptimizableLocalObjectsValueNumbers ||4456!resolvedBaseObject ||4457(comp()->useCompressedPointers() && (TR::Compiler->om.compressedReferenceShift() > 3) && !cg()->supportsStackAllocations()) ||4458!resolvedBaseObject->getOpCode().hasSymbolReference() ||4459!_nonColdLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(resolvedBaseObject)) ||4460(((node->getSymbolReference()->getSymbol()->getRecognizedField() != TR::Symbol::Java_lang_String_value) ||4461stringCopyOwningMethod ||4462_notOptimizableLocalStringObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(resolvedBaseObject))) &&4463_notOptimizableLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(resolvedBaseObject)))))4464{4465forceEscape(node->getSecondChild(), node);4466}4467else4468{4469seenStoreToLocalObject = true;4470restrictCandidates(node->getSecondChild(), node, MakeContiguous);4471}4472}4473else4474{4475static char *allowSelfStoresToLocalObjects = feGetEnv("TR_allowSelfStoresToLocalObjects");4476if (allowSelfStoresToLocalObjects)4477{4478seenSelfStore = true;4479if (baseObject->getOpCode().hasSymbolReference())4480restrictCandidates(node->getSecondChild(), node, MakeContiguous);4481}4482else4483{4484forceEscape(node->getSecondChild(), node);4485}4486}4487}44884489child = node->getFirstChild();4490if (node->getSymbol()->isArrayShadowSymbol() &&4491child->getOpCode().isArrayRef())4492child = child->getFirstChild();44934494// Remember indirect loads or stores for fields of local allocations.4495//4496if (node->getOpCode().isStore())4497{4498//if (seenSelfStore)4499referencedField(child, node, true, seenSelfStore, seenStoreToLocalObject);4500//else4501// referencedField(child, node, true);4502}4503else4504referencedField(child, node, false);45054506// If the field is unresolved it must be left as a field reference, so4507// force the allocation to be contiguous.4508//4509if (node->getSymbolReference()->isUnresolved())4510restrictCandidates(child, node, MakeContiguous);4511// Similarly if the field is not a regular field make the allocation4512// contiguous (unless it's a class load for a vcall or inline finalizable test)4513// (If it's an inline finalizable test we have to clean the test up since the object will no longer exist)4514//4515else if (node->getSymbolReference()->getOffset() < (int32_t)comp()->fej9()->getObjectHeaderSizeInBytes() && !node->getSymbol()->isArrayShadowSymbol())4516{4517if (!node->getSymbolReference()->getSymbol()->isClassObject() || node->getOpCode().isStore() ||4518(!classObjectLoadForVirtualCall && !isFinalizableInlineTest(comp(), child, _curTree->getNode(), node)))4519{4520restrictCandidates(child, node, MakeContiguous);4521}4522}4523}45244525else // Direct load or store4526{4527if (node->getOpCode().isStore() &&4528(comp()->getSymRefTab()->findThisRangeExtensionSymRef() != node->getSymbolReference()))4529{4530// Handle escapes via direct store of a candidate.4531// In a sniffed method even a store into a local may escape since4532// we can't keep track of the local stored into (we have no value4533// number information for it).4534//4535if ((_parms || !node->getSymbol()->isAutoOrParm()) &&4536(!_methodSymbol ||4537(_parms && node->getSymbol()->isAutoOrParm() && !node->getFirstChild()->isThisPointer()) ||4538((_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_add) &&4539(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_longAdd) &&4540(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_slAdd))))4541forceEscape(node->getFirstChild(), node);45424543// PR 934604544if (node->getSymbolReference()->getSymbol()->isAuto() &&4545node->getSymbol()->castToAutoSymbol()->isPinningArrayPointer())4546restrictCandidates(node->getFirstChild(), node, MakeContiguous);45474548// Handle escapes via store into a parameter for a called method4549// (this is conservative, but hopefully it doesn't happen too often)4550//4551if (_parms)4552forceEscape(node, node);4553}4554}4555return;4556}45574558// Handle arraycopy nodes.4559// Any candidates being used for arraycopy must be allocated contiguously.4560//4561if (node->getOpCodeValue() == TR::arraycopy)4562{4563if (node->getNumChildren() == 5)4564{4565restrictCandidates(node->getFirstChild(), node, MakeContiguous);4566restrictCandidates(node->getSecondChild(), node, MakeContiguous);4567}45684569if (node->getNumChildren() == 3)4570{4571if (node->getFirstChild()->getOpCode().isArrayRef())4572restrictCandidates(node->getFirstChild()->getFirstChild(), node, MakeContiguous);4573if (node->getSecondChild()->getOpCode().isArrayRef())4574restrictCandidates(node->getSecondChild()->getFirstChild(), node, MakeContiguous);4575}45764577return;4578}45794580if (_sniffDepth > 0)4581return;45824583// Look for some direct references to candidates, and decide if a separate4584// object must be created for them to handle the references.4585//4586if (node->getOpCode().isCheckCast() ||4587node->getOpCodeValue() == TR::instanceof)4588{4589valueNumber = _valueNumberInfo->getValueNumber(node->getFirstChild());4590candidate = findCandidate(valueNumber);4591if (candidate)4592{4593TR::Node *classNode = node->getSecondChild();4594if (!isConstantClass(classNode, this))4595{4596// We don't know the class statically. The object must stay contiguous.4597//4598wasRestricted |= restrictCandidates(node->getFirstChild(), node, MakeContiguous);4599}4600else if (node->getOpCode().isCheckCast() &&4601comp()->fej9()->isInstanceOf((TR_OpaqueClassBlock *) candidate->_class, (TR_OpaqueClassBlock*)classNode->getSymbol()->castToStaticSymbol()->getStaticAddress(), true) != TR_yes)4602{4603// We will be able to predict the result of the cast. For instanceof and4604// for a succeeding checkcast we will remove this candidate reference.4605// For a failing checkcast the candidate reference will remain, but can4606// become a separate "java/lang/Object" object.4607//4608wasRestricted |= restrictCandidates(node->getFirstChild(), node, MakeObjectReferenced);4609}4610}4611}46124613else if (node->getOpCodeValue() == TR::ifacmpeq ||4614node->getOpCodeValue() == TR::ifacmpne)4615{4616// If one of the children is a candidate we may be able to determine if4617// the comparison will succeed or fail4618//4619int32_t firstValue = _valueNumberInfo->getValueNumber(node->getFirstChild());4620int32_t secondValue = _valueNumberInfo->getValueNumber(node->getSecondChild());4621bool predictResult = false;4622if (firstValue == secondValue)4623predictResult = true;4624else4625{4626candidate = findCandidate(firstValue);4627if (candidate && !usesValueNumber(candidate, secondValue))4628predictResult = true;4629else4630{4631candidate = findCandidate(secondValue);4632if (candidate && !usesValueNumber(candidate, firstValue))4633predictResult = true;4634}4635}46364637if (!predictResult)4638{4639wasRestricted = restrictCandidates(node->getFirstChild(), node, MakeObjectReferenced);4640wasRestricted |= restrictCandidates(node->getSecondChild(), node, MakeObjectReferenced);4641}4642}46434644else if (node->getOpCodeValue() != TR::treetop &&4645!node->getOpCode().isArrayRef() &&4646node->getOpCodeValue() != TR::PassThrough &&4647!node->getOpCode().isArrayLength() &&4648node->getOpCodeValue() != TR::NULLCHK &&4649node->getOpCodeValue() != TR::ResolveCHK &&4650node->getOpCodeValue() != TR::ResolveAndNULLCHK &&4651node->getOpCodeValue() != TR::instanceof &&4652#if CHECK_MONITORS4653((node->getOpCodeValue() != TR::monent && node->getOpCodeValue() != TR::monexit) || !_removeMonitors) &&4654#endif4655!node->getOpCode().isCall())4656{4657// Any other direct reference to a candidate means that there must be a4658// local object even if the fields are allocated non-contiguously4659//4660for (i = node->getNumChildren()-1; i >= 0; i--)4661{4662child = node->getChild(i);4663wasRestricted |= restrictCandidates(child, node, MakeObjectReferenced);4664}4665}4666if (wasRestricted)4667{4668if (trace())4669{4670/////printf("secs Object referenced via %s in %s\n", node->getOpCode().getName(), comp()->signature());4671traceMsg(comp(), "Object referenced via %s\n", node->getOpCode().getName());4672}4673}4674}467546764677bool4678SniffCallCache::isInCache(TR_LinkHead<SniffCallCache> *sniffCacheList, TR_ResolvedMethod *vmMethod, bool isCold, int32_t &bytecodeSize)4679{4680SniffCallCache *sniffCallCache;4681for (sniffCallCache = sniffCacheList->getFirst(); sniffCallCache; sniffCallCache = sniffCallCache->getNext())4682{4683if (vmMethod->isSameMethod(sniffCallCache->_vmMethod) &&4684isCold == sniffCallCache->_isCold)4685{4686bytecodeSize = sniffCallCache->_bytecodeSize;4687return true;4688}4689}4690return false;4691}46924693TR::SymbolReference*4694SymRefCache::findSymRef(TR_LinkHead<SymRefCache> *symRefList, TR_ResolvedMethod *resolvedMethod)4695{4696SymRefCache *symRefCache;4697for (symRefCache = symRefList->getFirst(); symRefCache; symRefCache = symRefCache->getNext())4698{4699if (resolvedMethod->isSameMethod(symRefCache->getMethod()))4700{4701return symRefCache->getSymRef();4702}4703}4704return NULL;4705}47064707void TR_EscapeAnalysis::checkEscapeViaCall(TR::Node *node, TR::NodeChecklist& visited, bool & ignoreRecursion)4708{4709int32_t nodeVN;4710TR::Node *value;47114712visited.add(node);47134714TR::ResolvedMethodSymbol *methodSymbol = node->getSymbol()->getResolvedMethodSymbol();4715Candidate *candidate, *next;4716bool needToSniff = false;47174718// In Java9 sun_misc_Unsafe_putInt might be the wrapper which could potentially be redefined,4719// so add a check for isNative to be conservative.4720if (methodSymbol && _methodSymbol &&4721(_methodSymbol->getRecognizedMethod() == TR::java_math_BigDecimal_longString1C) &&4722(methodSymbol->getRecognizedMethod() == TR::sun_misc_Unsafe_putInt_jlObjectII_V) &&4723(methodSymbol->isNative()))4724{4725if (trace())4726traceMsg(comp(), "Ignoring escapes via call [%p] \n", node);4727return;4728}47294730for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())4731{4732if ( methodSymbol4733&& methodSymbol->getRecognizedMethod() == TR::java_lang_Integer_init4734&& candidate->_dememoizedConstructorCall4735&& candidate->_dememoizedConstructorCall->getNode()->getFirstChild() == node)4736{4737if (trace())4738traceMsg(comp(), "Ignoring escapes via call [%p] that will either be inlined or rememoized\n", node);4739return;4740}4741}47424743for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())4744{4745candidate->setArgToCall(_sniffDepth, false);4746candidate->setNonThisArgToCall(_sniffDepth, false);4747}47484749int32_t thisVN = -1;4750int32_t firstArgIndex = node->getFirstArgumentIndex();4751for (int32_t arg = firstArgIndex; arg < node->getNumChildren() && !_candidates.isEmpty(); arg++)4752{4753checkEscapeViaNonCall(node->getChild(arg), visited);4754value = resolveSniffedNode(node->getChild(arg));4755if (!value)4756continue;47574758// Method arguments are always escapes when method enter/exit hooks are enabled4759// because the agent can ask for method receivers and return values, and inspect them.4760// be conservative in checking for method exit hook: if an argument is returned by the callee exit hook would make it escape4761//4762if (TR::Compiler->vm.canMethodEnterEventBeHooked(comp()) || TR::Compiler->vm.canMethodExitEventBeHooked(comp()))4763{4764forceEscape(node->getChild(arg), node, true);4765continue;4766}47674768nodeVN = _valueNumberInfo->getValueNumber(value);4769if (arg == firstArgIndex)4770thisVN = nodeVN;47714772for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())4773{4774if (usesValueNumber(candidate, nodeVN))4775{4776// Remember calls to fillInStackTrace and printStackTrace. These4777// are methods of Throwable. The call to fillInStackTrace is very4778// expensive, and if it can be proved that the stack trace is not4779// used (via a call to printStackTrace) then the calls to4780// fillInStackTrace can be removed.4781//4782if (arg == firstArgIndex && methodSymbol && (!node->getOpCode().isIndirect() || !methodSymbol->getResolvedMethod()->virtualMethodIsOverridden()))4783{4784TR::RecognizedMethod methodId = methodSymbol->getRecognizedMethod();4785if (methodId == TR::java_lang_Throwable_fillInStackTrace)4786{4787// No escape via this method, and don't make this call the4788// reason for making the object contiguous.4789//4790if (candidate->_valueNumbers->element(0) == nodeVN)4791candidate->setFillsInStackTrace();4792continue;4793}47944795if (methodId == TR::java_lang_Throwable_printStackTrace)4796{4797// Uses stack trace, so fillInStackTrace can't be avoided.4798// Force the object to be contiguous and sniff this method to4799// check for escape.4800//4801candidate->setUsesStackTrace();4802candidate->setMustBeContiguousAllocation();4803if (trace())4804traceMsg(comp(), " Make [%p] contiguous because of setUsesStackTrace\n", candidate->_node);4805}4806}48074808// Ignore calls to jitCheckIfFinalizeObject, the argument cannot escape via such calls4809//4810if (1)4811{4812TR::SymbolReference *finalizeSymRef = comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_jitCheckIfFinalizeObject, true, true, true);4813if (node->getSymbolReference() == finalizeSymRef)4814{4815if (trace())4816traceMsg(comp(), "Candidate [%p] cannot escape because of node [%p]\n", candidate->_node, node);4817continue;4818}4819}482048214822// We can't sniff JNI methods. Check if this is a JNI call, in which4823// case use the table of trusted methods to see if the argument can escape from4824// this call4825//4826if (!node->getOpCode().isIndirect() && methodSymbol && methodSymbol->getResolvedMethod()->isJNINative())4827{4828if (methodSymbol && !comp()->fej9()->argumentCanEscapeMethodCall(methodSymbol, arg-firstArgIndex))4829{4830// The candidate will have to be kept as a contiguous4831// allocation, since it is passed to another method.4832//4833candidate->setMustBeContiguousAllocation();4834if (trace())4835traceMsg(comp(), " Make [%p] contiguous because of node [%p]\n", candidate->_node, node);4836continue;4837}4838}48394840// Otherwise we need to sniff the method. If we can't sniff it for4841// some reason then assume that this candidate can escape.4842//4843needToSniff = true;48444845// Remember that this child is an affected candidate4846//4847candidate->setArgToCall(_sniffDepth);4848if (node->getOpCode().isIndirect())4849{4850if (arg != firstArgIndex)4851candidate->setNonThisArgToCall(_sniffDepth);4852}48534854if (arg == (firstArgIndex+1) && methodSymbol && !node->getOpCode().isIndirect())4855{4856TR::RecognizedMethod methodId = methodSymbol->getRecognizedMethod();4857if (methodId == TR::java_lang_String_init_String)4858{4859char *sig = methodSymbol->getResolvedMethod()->signatureChars();4860if (!strncmp(sig, "(Ljava/lang/String;)", 20))4861{4862candidate->setCallsStringCopyConstructor();4863}4864}4865}4866}4867}4868}48694870if (needToSniff)4871{4872if (methodSymbol)4873dumpOptDetails(comp(), "Sniff call %p called %s\n", node, methodSymbol->getMethod()->signature(trMemory()));4874TR_LinkHead<SniffCallCache> sniffCacheList;4875sniffCacheList.setFirst(NULL);4876bool sniffCallInCache;48774878bool oldIgnoreRecursion = ignoreRecursion;4879int32_t bytecodeSize = sniffCall(node, methodSymbol, false, _inColdBlock, ignoreRecursion);4880int32_t originalBytecodeSize = bytecodeSize;4881for (candidate = _candidates.getFirst(); candidate; candidate = next)4882{4883bool refinedSniff = false;4884next = candidate->getNext();4885bytecodeSize = originalBytecodeSize;4886TR::SymbolReference *symRef = node->getSymbolReference();4887if (candidate->isArgToCall(_sniffDepth))4888{4889if (!candidate->isNonThisArgToCall(_sniffDepth) &&4890node->getOpCode().isIndirect() &&4891((candidate->_node->getOpCodeValue() == TR::New)) &&4892(thisVN > -1) &&4893usesValueNumber(candidate, thisVN))4894{4895TR_ResolvedMethod *owningMethod = symRef->getOwningMethod(comp());4896TR_ResolvedMethod *resolvedMethod = NULL;4897TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();4898TR::Method * originalMethod = sym->getMethod();4899int32_t len = originalMethod->classNameLength();4900char *s = TR::Compiler->cls.classNameToSignature(originalMethod->classNameChars(), len, comp());4901TR_OpaqueClassBlock *originalMethodClass = comp()->fej9()->getClassFromSignature(s, len, owningMethod);4902TR_OpaqueClassBlock *thisType = (TR_OpaqueClassBlock *) candidate->_node->getFirstChild()->getSymbol()->castToStaticSymbol()->getStaticAddress();4903int32_t offset = -1;49044905bool resolvedMethodMustExist = false;4906if (originalMethodClass &&4907thisType)4908{4909if (comp()->fej9()->isInstanceOf(thisType, originalMethodClass, true) == TR_yes)4910resolvedMethodMustExist = true;4911}49124913// The 2nd check below is to account for the rare case when we can4914// have a virtual (non interface) call that has an interface method4915// as the callee in the IL. This can happen in cases when an abstract class4916// implements an interface but doesn't even declare one of the methods in the4917// interface. In this case, the vft slot for the abstract class actually4918// has the interface method and this can lead to strange behaviour when we look4919// up the method (code guarded by below if). The strange case is if4920// there is some other class implementing the interface unrelated to the abstract class4921// and we try and look up the method in that class (because its an instance of4922// the interface) and get a completely unrelated method.4923//4924if (resolvedMethodMustExist &&4925(sym->isInterface() || !TR::Compiler->cls.isInterfaceClass(comp(), originalMethodClass)))4926{4927if (sym->isInterface() &&4928originalMethodClass)4929{4930int32_t cpIndex = symRef->getCPIndex();4931resolvedMethod = owningMethod->getResolvedInterfaceMethod(comp(), thisType, cpIndex);4932if (resolvedMethod)4933offset = owningMethod->getResolvedInterfaceMethodOffset(thisType, cpIndex);4934}4935else if (sym->isVirtual()4936&& !symRef->isUnresolved()4937&& sym->getRecognizedMethod() != TR::java_lang_Object_newInstancePrototype) // 166813: Temporary fix4938{4939offset = symRef->getOffset();4940resolvedMethod = owningMethod->getResolvedVirtualMethod(comp(), thisType, offset);4941}4942}49434944if (resolvedMethod)4945{4946// try to use cached result (_curTree, bytecodeSize) before sniffing into the call4947sniffCallInCache = SniffCallCache::isInCache(&sniffCacheList, resolvedMethod, _inColdBlock, bytecodeSize);4948dumpOptDetails(comp(), "Refined sniff call %p called %s, cached=%s\n",4949node, resolvedMethod->signature(trMemory()), sniffCallInCache ? "true" : "false");4950if (!sniffCallInCache)4951{4952TR::SymbolReference * newSymRef;4953// we want to reuse the IL if we're sniffing the same method4954newSymRef = SymRefCache::findSymRef(&(getOptData()->_symRefList), resolvedMethod);4955if (!newSymRef)4956{4957newSymRef = getSymRefTab()->findOrCreateMethodSymbol(symRef->getOwningMethodIndex(), -1, resolvedMethod, TR::MethodSymbol::Virtual);4958SymRefCache *symRefCache = new (trHeapMemory()) SymRefCache(newSymRef, resolvedMethod);4959getOptData()->_symRefList.add(symRefCache);4960newSymRef->copyAliasSets(symRef, getSymRefTab());4961newSymRef->setOffset(offset);4962}4963TR::MethodSymbol *newMethodSymbol = newSymRef->getSymbol()->castToMethodSymbol();49644965ignoreRecursion = oldIgnoreRecursion;4966bytecodeSize = sniffCall(node, newMethodSymbol->getResolvedMethodSymbol(), true, _inColdBlock, ignoreRecursion);4967SniffCallCache *sniffCallCache = new (trStackMemory()) SniffCallCache(newMethodSymbol->getResolvedMethodSymbol()->getResolvedMethod(), _inColdBlock, bytecodeSize);4968sniffCacheList.add(sniffCallCache);4969}4970refinedSniff = true;4971//printf("bytecodeSize = %d original bytecodeSize = %d method %s\n", bytecodeSize, originalBytecodeSize, resolvedMethod->signature());4972}4973}49744975if ((bytecodeSize > 0) && (!node->getOpCode().isIndirect() || !node->isTheVirtualCallNodeForAGuardedInlinedCall()) &&4976(!symRef->isUnresolved() ||4977!refinedSniff) )4978{4979// The sniff was successful.4980// If this is the top-level call site, remember that it4981// references the candidate. If we cannot inline the call site4982// then the candidate will have to be a contiguous allocation4983// in order for it to be passed to the callee.4984//4985candidate->setArgToCall(_sniffDepth, false);4986candidate->setNonThisArgToCall(_sniffDepth, false);49874988if (!symRef->isUnresolved() ||4989!refinedSniff)4990{4991// The sniff was successful.4992// If this is the top-level call site, remember that it4993// references the candidate. If we cannot inline the call site4994// then the candidate will have to be a contiguous allocation4995// in order for it to be passed to the callee.4996//49974998if (_sniffDepth == 0)4999{5000candidate->addCallSite(_curTree);5001if (!refinedSniff && node->getOpCode().isIndirect() && (methodSymbol && !methodSymbol->getResolvedMethod()->virtualMethodIsOverridden()))5002candidate->addVirtualCallSiteToBeFixed(_curTree);5003}50045005if (_sniffDepth > candidate->_maxInlineDepth)5006candidate->_maxInlineDepth = _sniffDepth;5007candidate->_inlineBytecodeSize += bytecodeSize;50085009}5010else5011candidate->setMustBeContiguousAllocation();50125013if (trace())5014traceMsg(comp(), " Make [%p] contiguous because of call node [%p]\n", candidate->_node, node);5015}5016else5017{5018// If the escape point is cold, this will not5019// prevent us from stack allocating it. We will compensate5020// for this later5021//5022if (checkIfEscapePointIsCold(candidate, node))5023continue;50245025// Force5026if(candidate->forceLocalAllocation())5027{5028if (trace())5029traceMsg(comp(), " Normally [%p] would fail because child of call [%p] to %s, but user wants it locally allocated\n",5030candidate->_node, node,5031node->getSymbol()->getMethodSymbol()->getMethod()5032? node->getSymbol()->getMethodSymbol()->getMethod()->signature(trMemory())5033: "[Unknown method]");5034continue;5035}5036// The sniff could not be done. Remove this candidate.5037//50385039if (trace())5040traceMsg(comp(), " Fail [%p] because child of call [%p]\n",5041candidate->_node, node);50425043rememoize(candidate);5044_candidates.remove(candidate);5045}5046}5047//else5048// traceMsg(comp(), "NOT is arg to call at node %p\n", node);5049}5050}5051}50525053int32_t TR_EscapeAnalysis::sniffCall(TR::Node *callNode, TR::ResolvedMethodSymbol *methodSymbol, bool ignoreOpCode, bool isCold, bool & ignoreRecursion)5054{5055if (_sniffDepth >= _maxSniffDepth)5056return 0;5057if (!methodSymbol)5058return 0;5059if (!ignoreOpCode &&5060(callNode->getOpCode().isIndirect() &&5061(methodSymbol->getResolvedMethod()->virtualMethodIsOverridden() || isCold || (_sniffDepth !=0) || (manager()->numPassesCompleted() == _maxPassNumber))))5062return 0;50635064// Avoid attempting to devirtualize a computed call5065if (methodSymbol->isComputed())5066return 0;50675068TR_ResolvedMethod *method = methodSymbol->getResolvedMethod();5069if (!method)5070return 0;50715072if (!method->isCompilable(trMemory()) || method->isJNINative())5073return 0;50745075uint32_t bytecodeSize = method->maxBytecodeIndex();5076if (bytecodeSize > MAX_SNIFF_BYTECODE_SIZE)5077return 0;50785079getOptData()->_totalPeekedBytecodeSize += bytecodeSize;5080if (getOptData()->_totalPeekedBytecodeSize > _maxPeekedBytecodeSize)5081return 0;50825083TR::ResolvedMethodSymbol *owningMethodSymbol = callNode->getSymbolReference()->getOwningMethodSymbol(comp());5084TR_ResolvedMethod* owningMethod = owningMethodSymbol->getResolvedMethod();5085TR_ResolvedMethod* calleeMethod = methodSymbol->getResolvedMethod();50865087if (owningMethod->isSameMethod(calleeMethod) &&5088(comp()->getJittedMethodSymbol() != owningMethodSymbol))5089{5090if (ignoreRecursion)5091return bytecodeSize;5092else5093ignoreRecursion = true;5094}50955096if (trace())5097traceMsg(comp(), "\nDepth %d sniffing into call at [%p] to %s\n", _sniffDepth, callNode, method->signature(trMemory()));50985099vcount_t visitCount = comp()->getVisitCount();5100if (!methodSymbol->getFirstTreeTop())5101{5102//comp()->setVisitCount(1);51035104dumpOptDetails(comp(), "O^O ESCAPE ANALYSIS: Peeking into the IL to check for escaping objects \n");51055106bool ilgenFailed = false;5107bool isPeekableCall = ((PersistentData *)manager()->getOptData())->_peekableCalls->get(callNode->getGlobalIndex());5108if (isPeekableCall)5109ilgenFailed = (NULL == methodSymbol->getResolvedMethod()->genMethodILForPeekingEvenUnderMethodRedefinition(methodSymbol, comp()));5110else5111ilgenFailed = (NULL == methodSymbol->getResolvedMethod()->genMethodILForPeeking(methodSymbol, comp()));5112//comp()->setVisitCount(visitCount);51135114/*5115* Under HCR we cannot generally peek methods because the method could be5116* redefined and any assumptions we made about the contents of the method5117* would no longer hold. Peeking is only safe when we add a compensation5118* path that would handle potential escape of candidates if a method were5119* redefined.5120*5121* Under OSR we know the live locals from the OSR book keeping information5122* so can construct a helper call which appears to make those calls escape.5123* Such a call will force heapification of any candidates ahead of the5124* helper call.5125*5126* We, therefore, queue this call node to be protected if we are in a mode5127* where protection is possible (voluntary OSR, HCR on). The actual code5128* transformation is delayed to the end of EA since it will disrupt value5129* numbering. The transform will insert an HCR guard with an escape helper5130* call as follows:5131*5132* | ... | | ... |5133* | call m | => | hcr guard (m) |5134* | ... | +---------------+5135* | \5136* | +-(cold)-------------------+5137* | | call eaEscapeHelper |5138* | | <loads of live locals> |5139* | +--------------------------+5140* V /5141* +---------------+5142* | call m |5143* | ... |5144*5145* Once EA finishes the postEscapeAnalysis pass will clean-up all5146* eaEscapeHelper calls. Code will only remain in the taken side of the5147* guard if candidtes were stack allocated and required heapficiation.5148*5149* This code transformation is protected with a perform transformation at5150* the site of tree manipulation at the end of this pass of EA.5151* Protecting any call is considered a reason to enable another pass of5152* EA if we have not yet reached the enable limit.5153*5154* Note that the result of the call can continue to participate in5155* commoning with the above design. If we duplicated the call on both5156* sides of the guard the result could not participate in commoning.5157*5158*/5159if (ilgenFailed)5160{5161if (trace())5162traceMsg(comp(), " (IL generation failed)\n");5163static char *disableHCRCallPeeking = feGetEnv("TR_disableEAHCRCallPeeking");5164if (!isPeekableCall5165&& disableHCRCallPeeking == NULL5166&& comp()->getOSRMode() == TR::voluntaryOSR5167&& comp()->getHCRMode() == TR::osr5168&& !_candidates.isEmpty()5169&& !((TR_EscapeAnalysis::PersistentData*)manager()->getOptData())->_processedCalls->get(callNode->getGlobalIndex()))5170{5171dumpOptDetails(comp(), "%sAdding call [%p] n%dn to list of calls to protect for peeking to increase opportunities for stack allocation\n", OPT_DETAILS, callNode, callNode->getGlobalIndex());5172TR_BitVector *candidateNodes = new (comp()->trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc);5173NodeDeque *loads = new (comp()->trMemory()->currentStackRegion()) NodeDeque(NodeDequeAllocator(comp()->trMemory()->currentStackRegion()));5174for (int32_t arg = callNode->getFirstArgumentIndex(); arg < callNode->getNumChildren(); ++arg)5175{5176TR::Node *child = callNode->getChild(arg);5177int32_t valueNumber = _valueNumberInfo->getValueNumber(child);5178for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())5179{5180if (usesValueNumber(candidate, valueNumber))5181{5182candidateNodes->set(candidate->_node->getGlobalIndex());5183ListIterator<TR::SymbolReference> itr(candidate->getSymRefs());5184for (TR::SymbolReference *symRef = itr.getFirst(); symRef; symRef = itr.getNext())5185loads->push_back(TR::Node::createWithSymRef(TR::aload, 0, symRef));5186}5187}5188}5189(*_callsToProtect)[callNode] = std::make_pair(candidateNodes, loads);5190}5191return 0;5192}51935194if (trace())5195{5196//comp()->setVisitCount(1);5197for (TR::TreeTop *tt = methodSymbol->getFirstTreeTop(); tt; tt = tt->getNextTreeTop())5198getDebug()->print(comp()->getOutFile(), tt);5199//comp()->setVisitCount(visitCount);5200}5201}5202else5203{5204if (trace())5205traceMsg(comp(), " (trees already dumped)\n");5206}52075208int32_t firstArgIndex = callNode->getFirstArgumentIndex();5209TR_Array<TR::Node*> *newParms = new (trStackMemory()) TR_Array<TR::Node*>(trMemory(), callNode->getNumChildren() - firstArgIndex, false, stackAlloc);5210for (int32_t i = firstArgIndex; i < callNode->getNumChildren(); ++i)5211{5212newParms->add(resolveSniffedNode(callNode->getChild(i)));5213}52145215TR_Array<TR::Node*> *oldParms = _parms;5216_parms = newParms;5217TR::TreeTop *curTree = _curTree;5218bool inColdBlock = _inColdBlock;5219//TR::Node *curNode = _curNode;5220++_sniffDepth;52215222TR::ResolvedMethodSymbol *oldMethodSymbol = _methodSymbol;52235224bool oldInBigDecimalAdd = _inBigDecimalAdd;5225if (_methodSymbol && (_methodSymbol->getRecognizedMethod() == TR::java_math_BigDecimal_add))5226_inBigDecimalAdd = true;5227else5228_inBigDecimalAdd = false;52295230_methodSymbol = methodSymbol;52315232checkEscape(methodSymbol->getFirstTreeTop(), isCold, ignoreRecursion);52335234_methodSymbol = oldMethodSymbol;5235_inBigDecimalAdd = oldInBigDecimalAdd;52365237_curTree = curTree;5238///// FIXME : This line should be uncommented5239////// It is checked in commented out only temporarily5240//////5241/////5242_inColdBlock = inColdBlock;5243_parms = oldParms;5244--_sniffDepth;52455246#if CHECK_MONITORS5247/* monitors */5248if (_removeMonitors)5249{5250TR_MonitorStructureChecker inspector;5251if (inspector.checkMonitorStructure(methodSymbol->getFlowGraph()))5252{5253_removeMonitors = false;5254if (trace())5255traceMsg(comp(), "Disallowing monitor-removal because of strange monitor structure in sniffed method %s\n",5256methodSymbol->getMethod()->signature(trMemory()));5257}5258}5259#endif52605261return bytecodeSize;5262}52635264// Check for size limits, both on individual object sizes and on total5265// object allocation size.5266// FIXME: need to modify this method to give priority to non-array objects5267//5268void TR_EscapeAnalysis::checkObjectSizes()5269{5270int32_t totalSize = 0;5271int32_t i;5272Candidate *candidate, *next;52735274for (candidate = _candidates.getFirst(); candidate; candidate = next)5275{5276next = candidate->getNext();5277if (!candidate->isLocalAllocation())5278continue;52795280// Make sure contiguous objects are not too big5281//5282if (candidate->isContiguousAllocation())5283{5284if (candidate->_size > MAX_SIZE_FOR_ONE_CONTIGUOUS_OBJECT)5285{5286if (trace())5287/////printf("secs Fail [%p] because object size is too big in %s\n", candidate->_node, comp()->signature());5288;5289if (trace())5290traceMsg(comp(), " Fail [%p] because object size %d is too big\n", candidate->_node, candidate->_size);52915292candidate->setLocalAllocation(false);5293}5294else5295totalSize += candidate->_size;5296}5297else5298{5299if (candidate->_fields)5300{5301// Size of non-contiguous object is the sum of its referenced fields5302//5303for (i = candidate->_fields->size()-1; i >= 0; i--)5304candidate->_fieldSize += candidate->_fields->element(i)._size;5305totalSize += candidate->_fieldSize;5306}5307}5308}53095310// If total size for local allocation is too big, remove candidates until the5311// total size becomes reasonable.5312//5313while (totalSize > MAX_SIZE_FOR_ALL_OBJECTS)5314{5315// Remove the largest contiguous allocation. If there is none, remove5316// the largest non-contiguous allocation.5317//5318int32_t largestContiguousObjectSize = -1;5319Candidate *largestContiguousObject = NULL;5320int32_t largestNonContiguousObjectSize = -1;5321Candidate *largestNonContiguousObject = NULL;53225323for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())5324{5325if (!candidate->isLocalAllocation())5326continue;53275328if (candidate->isContiguousAllocation())5329{5330if (candidate->_size > largestContiguousObjectSize)5331{5332largestContiguousObjectSize = candidate->_size;5333largestContiguousObject = candidate;5334}5335}5336else5337{5338if (candidate->_fieldSize > largestNonContiguousObjectSize)5339{5340largestNonContiguousObjectSize = candidate->_fieldSize;5341largestNonContiguousObject = candidate;5342}5343}5344}5345if (largestContiguousObjectSize > 0)5346{5347candidate = largestContiguousObject;5348totalSize -= largestContiguousObjectSize;5349}5350else5351{5352candidate = largestNonContiguousObject;5353totalSize -= largestNonContiguousObjectSize;5354}53555356if (trace())5357{5358/////printf("secs Fail [%p] because total object size is too big in %s\n", candidate->_node, comp()->signature());5359traceMsg(comp(), " Fail [%p] because total object size is too big\n", candidate->_node);5360}53615362// Mark the candidate as not available for local allocation5363//5364candidate->setLocalAllocation(false);5365}5366}53675368void TR_EscapeAnalysis::anchorCandidateReference(Candidate *candidate, TR::Node *reference)5369{5370// If this candidate reference (which is about to be removed) may be5371// referenced later in the block, insert an anchoring treetop for it after5372// the current treetop.5373//5374if (reference->getReferenceCount() > 1 &&5375_curTree->getNextTreeTop()->getNode()->getOpCodeValue() != TR::BBEnd &&5376(candidate->isContiguousAllocation() || candidate->objectIsReferenced()))5377{5378// Anchor the child5379//5380TR::TreeTop::create(comp(), _curTree, TR::Node::create(TR::treetop, 1, reference));5381}5382}53835384void TR_EscapeAnalysis::fixupTrees()5385{5386TR::NodeChecklist visited (comp());5387TR::TreeTop *treeTop, *nextTree;5388for (treeTop = comp()->getStartTree(); treeTop; treeTop = nextTree)5389{5390nextTree = treeTop->getNextTreeTop();5391_curTree = treeTop;5392TR::Node *node = treeTop->getNode();53935394if (node->getOpCodeValue() == TR::BBStart)5395_curBlock = node->getBlock();5396else if (!visited.contains(node))5397{5398if (fixupNode(node, NULL, visited))5399{5400dumpOptDetails(comp(), "%sRemoving tree rooted at [%p]\n",OPT_DETAILS, node);5401_somethingChanged=true;5402TR::TransformUtil::removeTree(comp(), treeTop);5403}5404}5405}5406}54075408static bool shouldRemoveTree(Candidate *candidate, TR::Block *block)5409{5410ListIterator<TR_ColdBlockEscapeInfo> coldBlkInfoIt(candidate->getColdBlockEscapeInfo());5411TR_ColdBlockEscapeInfo *info;5412for (info = coldBlkInfoIt.getFirst(); info != NULL; info = coldBlkInfoIt.getNext())5413{5414TR::Block *coldBlk = info->getBlock();5415if (block == coldBlk)5416return false;5417}54185419return true;5420}542154225423// Fix up the node if it is a reference to a field of a local allocation.5424// Return true if the node is to be removed.5425//5426bool TR_EscapeAnalysis::fixupNode(TR::Node *node, TR::Node *parent, TR::NodeChecklist& visited)5427{5428int32_t i;5429int32_t valueNumber;5430Candidate *candidate;5431TR::Node *child;54325433visited.add(node);54345435bool removeThisNode = false;5436TR::ResolvedMethodSymbol *calledMethod = NULL;54375438// Look for indirect loads or stores for fields of local allocations.5439//5440if (node->getOpCode().isIndirect() &&5441node->getOpCode().isLoadVarOrStore() &&5442!comp()->suppressAllocationInlining())5443{5444if (node->getSymbol()->isArrayShadowSymbol() &&5445node->getFirstChild()->getOpCode().isArrayRef())5446child = node->getFirstChild()->getFirstChild();5447else5448child = node->getFirstChild();54495450valueNumber = _valueNumberInfo->getValueNumber(child);5451for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())5452{5453if (comp()->generateArraylets() && (candidate->_kind != TR::New))5454continue;54555456bool usesValueNum = usesValueNumber(candidate, valueNumber);54575458// Check if this is a class load for a finalizable test5459if (usesValueNum &&5460node->getSymbolReference()->getOffset() < (int32_t)comp()->fej9()->getObjectHeaderSizeInBytes() &&5461node->getSymbolReference()->getSymbol()->isClassObject() &&5462node->getOpCode().isLoadIndirect() &&5463isFinalizableInlineTest(comp(), node->getFirstChild(), _curTree->getNode(), node))5464{5465// This transformation is optional for candidates that can't be stack-allocated and contiguous allocations,5466// but required for discontiguous allocations because the class field will no longer exist5467if (!candidate->isLocalAllocation() || candidate->isContiguousAllocation())5468{5469if (performTransformation(comp(), "%sRemoving inline finalizable test [%p] for candidate [%p]\n", OPT_DETAILS, _curTree->getNode(), candidate->_node))5470removeThisNode = true;5471}5472else5473{5474if (trace())5475traceMsg(comp(), "Removing inline finalizable test [%p] for discontiguous candidate [%p]\n", _curTree->getNode(), candidate->_node);5476removeThisNode = true;5477}54785479if (removeThisNode)5480{5481// The isFinalizable test results in zero because the candidate5482// has no finalizer, so we can turn it into a const 0.5483//5484// NOTE: Normally you'd want to anchor children here. However,5485// one child is a const whose evaluation point doesn't matter.5486// The other is a dereference chain from the candidate. If the5487// candidate is noncontiguously allocated, we must remove all5488// references, so it would be incorrect to anchor. If the5489// candidate is contiguous, it will turn into a loadaddr, whose5490// evaluation point doesn't matter. Since anchoring is5491// sometimes wrong and never necessary, we just don't do it.5492//5493TR::Node *andNode = _curTree->getNode()->getFirstChild();5494andNode->removeAllChildren();549554965497// In 64-bit mode the isFinalizable test will start out using5498// long operations, but subsequent optimization might reduce5499// them to int operations, so be prepared to replace the and5500// operation with a zero of the appropriate size5501if (andNode->getOpCodeValue() == TR::land)5502{5503TR::Node::recreate(andNode, TR::lconst);5504andNode->setLongInt(0);5505}5506else if (andNode->getOpCodeValue() == TR::iand)5507{5508TR::Node::recreate(andNode, TR::iconst);5509andNode->setInt(0);5510}5511else5512{5513TR_ASSERT_FATAL(false, "Expected iand or land in isFinalizable test");5514}5515}55165517return false;5518}55195520if (candidate->isLocalAllocation() && usesValueNum)5521{5522int32_t fieldOffset = node->getSymbolReference()->getOffset();5523if (candidate->_origKind == TR::New)5524{5525TR::SymbolReference *symRef = node->getSymbolReference();5526fieldOffset = symRef->getOffset();5527}5528else5529{5530TR::Node *offsetNode = NULL;5531if (node->getFirstChild()->getOpCode().isArrayRef())5532offsetNode = node->getFirstChild()->getSecondChild();55335534if (offsetNode && offsetNode->getOpCode().isLoadConst())5535{5536if (offsetNode->getType().isInt64())5537fieldOffset = (int32_t) offsetNode->getLongInt();5538else5539fieldOffset = offsetNode->getInt();5540}5541}55425543// For a noncontiguous allocation, we can't leave behind any5544// dereferences of the candidate, so we must transform this5545// dereference. If it's accessing a field that is not present in5546// the candidate, the code is already wrong (and presumably must5547// never run!), so we're ok to replace it with different code that5548// is also wrong. Hence, we'll vandalize the tree into an iconst 0.5549//5550// NOTE: it would be cleaner to turn a field load into a const of5551// the right type, and a store into a treetop, rather than changing5552// the base pointer into an iconst 0. However, we have done this5553// for years, so we'll leave it alone to reduce risk because we're5554// about to ship Java 8.5555//5556bool mustRemoveDereferences = !candidate->isContiguousAllocation();5557bool fieldIsPresentInObject = true;55585559int32_t j;5560for (j = candidate->_fields->size()-1; j >= 0; j--)5561{5562if ((candidate->_fields->element(j)._offset == fieldOffset) &&5563(!candidate->_fields->element(j).symRefIsForFieldInAllocatedClass(node->getSymbolReference())))5564{5565if (mustRemoveDereferences)5566{5567child->decReferenceCount();5568child = TR::Node::create(child, TR::iconst, 0, 0);5569if (trace())5570{5571traceMsg(comp(), "Change illegal deref %s [%p] to use dummy base %s [%p] in place of %s [%p]\n",5572node->getOpCode().getName(), node,5573child->getOpCode().getName(), child,5574node->getChild(0)->getOpCode().getName(), node->getChild(0));5575}5576node->setAndIncChild(0, child);55775578// A wrtbari can also have the object as the last child.5579// If we're vandalizing the wrtbari, it's because we've5580// proven it's changing the candidate, and in that case,5581// the third child must be a pointer to the candidate. We5582// can safely drop that child with no further checking.5583//5584static char *disableWrtbarFixing = feGetEnv("TR_disableWrtbarFixing");5585if (node->getOpCode().isWrtBar() && !disableWrtbarFixing)5586{5587if (trace())5588{5589traceMsg(comp(), " -> Change %s [%p] into astorei, removing child %s [%p]\n",5590node->getOpCode().getName(), node, node->getChild(2)->getOpCode().getName(), node->getChild(2));5591}5592node->getAndDecChild(2);5593node->setNumChildren(2);5594TR::Node::recreate(node, TR::astorei);5595node->setFlags(0);55965597if (parent->getOpCode().isCheck() || parent->getOpCodeValue() == TR::compressedRefs)5598{5599if (trace())5600traceMsg(comp(), " -> Eliminate %s [%p]\n", parent->getOpCode().getName(), parent);5601TR::Node::recreate(parent, TR::treetop);5602parent->setFlags(0);5603}5604}5605}5606fieldIsPresentInObject = false;5607break;5608}5609}56105611if (fieldIsPresentInObject)5612{5613// For a candidate that is escaping in a cold block, keep track5614// of fields that are referenced so they can be initialized.5615// Otherwise, rewrite field references (in else branch_.5616// Special case handling of stores to fields of immutable objects5617// that are not contiguously allocated - their field references5618// are also rewritten (in else branch), but the original stores5619// still preserved.5620//5621if (candidate->escapesInColdBlock(_curBlock)5622&& (!isImmutableObject(candidate)5623|| candidate->isContiguousAllocation()5624|| node->getOpCode().isLoadVar()))5625{5626// Uh, why are we re-calculating the fieldOffset? Didn't we just do that above?5627//5628int32_t fieldOffset = node->getSymbolReference()->getOffset();5629if (candidate->_origKind == TR::New)5630{5631TR::SymbolReference *symRef = node->getSymbolReference();5632fieldOffset = symRef->getOffset();5633}5634else5635{5636TR::Node *offsetNode = NULL;5637if (node->getFirstChild()->getOpCode().isArrayRef())5638offsetNode = node->getFirstChild()->getSecondChild();56395640if (offsetNode && offsetNode->getOpCode().isLoadConst())5641{5642if (offsetNode->getType().isInt64())5643fieldOffset = (int32_t) offsetNode->getLongInt();5644else5645fieldOffset = offsetNode->getInt();5646}5647}56485649if (TR_yes == candidateHasField(candidate, node, fieldOffset, this))5650{5651// Remember the symbol reference of this field so that it can be used to5652// zero-initialize the object.5653//5654int32_t i;5655TR::SymbolReference *symRef = node->getSymbolReference();56565657int32_t nodeSize = node->getSize();5658if (comp()->useCompressedPointers() &&5659(node->getDataType() == TR::Address))5660nodeSize = TR::Compiler->om.sizeofReferenceField();56615662if (fieldOffset + nodeSize <= candidate->_size) // cmvc 200318: redundant but harmless -- leave in place to minimize disruption5663{5664for (i = candidate->_fields->size()-1; i >= 0; i--)5665{5666if (candidate->_fields->element(i)._offset == fieldOffset)5667{5668candidate->_fields->element(i).rememberFieldSymRef(node, fieldOffset, candidate, this);5669if (candidate->isContiguousAllocation())5670candidate->_fields->element(i)._symRef = symRef;5671candidate->_fields->element(i)._vectorElem = 0;56725673break;5674}5675}5676TR_ASSERT(i >= 0, "assertion failure");5677}5678}5679}56805681// For a candidate that is not escaping in a cold block, or that5682// is an immutable object that is non-contiguously allocated,5683// rewrite references5684//5685else // if (!candidate->escapesInColdBlock(_curBlock))5686// || (isImmutableObject(candidate)5687// && !candidate->isContiguousAllocation()))5688// && !node->getOpCode().isLoadVar()))5689{5690if (candidate->isContiguousAllocation())5691removeThisNode |= fixupFieldAccessForContiguousAllocation(node, candidate);5692else5693{5694removeThisNode |= fixupFieldAccessForNonContiguousAllocation(node, candidate, parent);5695break; // Can only be one matching candidate5696}5697}5698}5699else //There was a field outside the bound of an object5700if (!candidate->isContiguousAllocation())5701break; // Can only be one matching candidate5702}5703}57045705if (removeThisNode)5706return true;5707}57085709// Look for call to Throwable::fillInStackTrace that can be removed5710// (Note this has to be done before processing the children, since the5711// children will go away with the call.5712//5713if (node->getOpCode().isCall())5714{5715calledMethod = node->getSymbol()->getResolvedMethodSymbol();5716if (calledMethod && (!calledMethod->getResolvedMethod()->virtualMethodIsOverridden() || !node->getOpCode().isIndirect()))5717{5718if (calledMethod->getRecognizedMethod() == TR::java_lang_Throwable_fillInStackTrace)5719{5720child = node->getChild(node->getFirstArgumentIndex());5721valueNumber= _valueNumberInfo->getValueNumber(child);5722candidate = findCandidate(valueNumber);5723if (candidate && candidate->fillsInStackTrace() && !candidate->usesStackTrace() &&5724candidate->isLocalAllocation() && !candidate->escapesInColdBlocks() && performTransformation(comp(), "%sRemoving call node [%p] to fillInStackTrace\n",OPT_DETAILS, node))5725{5726//printf("Removing fillInStackTrace call in %s\n", comp()->signature());57275728// If the result of the call is not used, just remove the tree.5729// Otherwise replace the call with aconst 05730//5731anchorCandidateReference(candidate, child);5732if (optimizer()->prepareForNodeRemoval(node, /* deferInvalidatingUseDefInfo = */ true))5733_invalidateUseDefInfo = true;5734if (node->getReferenceCount() == 1)5735return true;5736node->removeAllChildren();5737TR::Node::recreate(node, TR::aconst);5738node->setInt(0);5739node->setIsNonNull(false);5740node->setIsNull(true);5741return false;5742}5743}5744}5745}57465747// Handle some standard constant propagation cases that reference candidate5748// objects. Since we may be inlining and then doing another pass of escape5749// analysis without doing constant propagation in between, these cases may5750// appear even though constant propagation would have simplified them.5751// They are handled here so that extraneous references to the candidates are5752// removed.5753//5754else if (node->getOpCodeValue() == TR::NULLCHK)5755{5756// If the reference child of the NULLCHK is a candidate, replace the5757// NULLCHK node by a treetop.5758//5759child = node->getNullCheckReference();5760valueNumber = _valueNumberInfo->getValueNumber(child);5761candidate = findCandidate(valueNumber);5762if (candidate)5763{5764TR::Node::recreate(node, TR::treetop);5765}5766}57675768else if (node->getOpCode().isArrayLength())5769{5770// If the child of the arraylength node is a candidate, replace the5771// arraylength node by the (constant) bound from the allocation node.5772//5773child = node->getFirstChild();5774valueNumber = _valueNumberInfo->getValueNumber(child);5775candidate = findCandidate(valueNumber);5776if (candidate &&5777performTransformation(comp(), "%sReplacing arraylength [%p] by constant %d\n", OPT_DETAILS, node, candidate->_node->getFirstChild()->getInt()))5778{5779//TR_ASSERT((candidate->_node->getOpCodeValue() != TR::New) && (candidate->_node->getOpCodeValue() != TR::newStructRef), "assertion failure");5780anchorCandidateReference(candidate, child);5781if (optimizer()->prepareForNodeRemoval(node, /* deferInvalidatingUseDefInfo = */ true))5782_invalidateUseDefInfo = true;5783node->removeAllChildren();5784TR::Node::recreate(node, TR::iconst);5785if (candidate->_node->getOpCodeValue() == TR::New)5786{5787// Dead code: can't ever execute an arraylength on a TR_New5788//see ArrayLest.test_getLTR::java_lang_ObjectI for an example5789node->setInt(0xdeadc0de);5790}5791else5792{5793node->setInt(candidate->_node->getFirstChild()->getInt());5794}5795// No need to look at children5796//5797return false;5798}5799}58005801else if (node->getOpCode().isCheckCast() ||5802node->getOpCodeValue() == TR::instanceof)5803{5804// If the first child is a candidate, decide if the test will succeed or5805// fail and change the node accordingly5806//5807child = node->getFirstChild();5808TR::Node *classNode = node->getSecondChild();5809valueNumber = _valueNumberInfo->getValueNumber(child);5810candidate = findCandidate(valueNumber);5811if (candidate && isConstantClass(classNode, this))5812{5813anchorCandidateReference(candidate, child);5814if (optimizer()->prepareForNodeRemoval(node, /* deferInvalidatingUseDefInfo = */ true))5815_invalidateUseDefInfo = true;5816if (comp()->fej9()->isInstanceOf((TR_OpaqueClassBlock *) candidate->_class, (TR_OpaqueClassBlock*)classNode->getSymbol()->castToStaticSymbol()->getStaticAddress(), true) == TR_yes)5817{5818if (node->getOpCodeValue() == TR::instanceof)5819{5820if (performTransformation(comp(), "%sReplacing instanceof [%p] by constant 1\n", OPT_DETAILS, node))5821{5822node->removeAllChildren();5823TR::Node::recreate(node, TR::iconst);5824node->setInt(1);5825}5826}5827else5828{5829if (performTransformation(comp(), "%sReplacing %s [%p] by TR::treetop\n", OPT_DETAILS, node->getOpCode().getName(), node))5830{5831optimizer()->getEliminatedCheckcastNodes().add(node);5832optimizer()->getClassPointerNodes().add(classNode);5833requestOpt(OMR::catchBlockRemoval);5834removeThisNode = true;5835}5836}5837}5838else5839{5840if (node->getOpCodeValue() == TR::instanceof)5841{5842if (performTransformation(comp(), "%sReplacing instanceof [%p] by constant 0\n", OPT_DETAILS, node))5843{5844node->removeAllChildren();5845TR::Node::recreate(node, TR::iconst);5846node->setInt(0);5847}5848}5849else5850{5851// The checkcast is ok as-is, so long as we still have an object5852// around to do the checkcast on.5853//5854TR_ASSERT(!candidate->isLocalAllocation() || candidate->isContiguousAllocation() || candidate->objectIsReferenced(), "assertion failure");5855}5856}58575858// No need to look at children5859//5860return removeThisNode;5861}5862}58635864else if (node->getOpCodeValue() == TR::ifacmpeq || node->getOpCodeValue() == TR::ifacmpne)5865{5866// If one of the children is a candidate we may be able to determine if5867// the comparison will succeed or fail5868//5869int32_t firstValue = _valueNumberInfo->getValueNumber(node->getFirstChild());5870int32_t secondValue = _valueNumberInfo->getValueNumber(node->getSecondChild());5871int32_t compareValue = -1;5872if (firstValue == secondValue)5873{5874compareValue = 0;58755876createGuardSiteForRemovedGuard(comp(), node);5877}5878else5879{5880bool notEqual = false;5881candidate = findCandidate(firstValue);5882if (candidate && ((!candidate->_seenSelfStore && !candidate->_seenStoreToLocalObject && !candidate->escapesInColdBlocks() && !usesValueNumber(candidate, secondValue)) || (node->getSecondChild()->getOpCodeValue() == TR::aconst)))5883notEqual = true;5884else5885{5886candidate = findCandidate(secondValue);5887if (candidate && ((!candidate->_seenSelfStore && !candidate->_seenStoreToLocalObject && !candidate->escapesInColdBlocks() && !usesValueNumber(candidate, firstValue)) || (node->getSecondChild()->getOpCodeValue() == TR::aconst)))5888notEqual = true;5889}5890if (notEqual)5891compareValue = 1;5892}58935894if (compareValue >= 0 &&5895performTransformation(comp(), "%sChanging compare node [%p] so that constant propagation can predict it\n", OPT_DETAILS, node))5896{5897// The comparison is bound to succeed or fail.5898// Since it is complicated to remove code at this point, we simply5899// change the arguments so that constant propagation can predict that5900// the comparison will succeed or fail, and change the code accordingly5901//5902node->removeAllChildren();5903node->setNumChildren(2);5904node->setAndIncChild(0, TR::Node::aconst(node, 0));5905node->setAndIncChild(1, TR::Node::aconst(node, compareValue));5906_somethingChanged = true;59075908// No need to look at children5909//5910return false;5911}5912}5913// Get rid of compressed ref anchors for loads/stores to fields of objects that have been made non-contiguous5914else if (comp()->useCompressedPointers() &&5915node->getOpCodeValue() == TR::compressedRefs)5916{5917TR::Node *loadOrStore = node->getFirstChild();5918bool treeAsExpected = false;5919if (loadOrStore &&5920(loadOrStore->getOpCode().isLoadVarOrStore() || loadOrStore->getOpCode().isLoadConst()))5921treeAsExpected = true;59225923if (!treeAsExpected || (loadOrStore->getOpCode().hasSymbolReference() && loadOrStore->getSymbolReference()->getSymbol()->isAuto()))5924{5925TR::Node::recreate(node, TR::treetop);5926node->getSecondChild()->decReferenceCount();5927node->setSecond(NULL);5928node->setNumChildren(1);5929if (loadOrStore->getOpCode().isStore())5930{5931// Explicitly remove stores; some opts (e.g. DSE) don't expect commoned stores.5932node->setFirst(loadOrStore->getFirstChild());5933if (loadOrStore->getReferenceCount() > 1)5934{5935TR_ASSERT(loadOrStore->getFirstChild(), "Expecting store to have a child.");5936loadOrStore->getFirstChild()->incReferenceCount();5937}5938loadOrStore->decReferenceCount();5939if (trace())5940traceMsg(comp(), "Changing orphaned compressed ref anchor [%p] to auto to a treetop and removing store [%p].\n", node, loadOrStore);5941}5942else5943{5944if (trace())5945traceMsg(comp(), "Changing orphaned compressed ref anchor [%p] to auto to a treetop.\n", node);5946}5947return false;5948}5949}59505951// Look for opportunities to de-synchronize references to a candidate.5952//5953TR::Node * synchronizedObject = 0;5954#if CHECK_MONITORS5955if (_removeMonitors &&5956(node->getOpCodeValue() == TR::monent ||5957node->getOpCodeValue() == TR::monexit))5958synchronizedObject = node->getFirstChild();5959#else5960if (node->getOpCodeValue() == TR::monent ||5961node->getOpCodeValue() == TR::monexit)5962synchronizedObject = node->getFirstChild();5963#endif5964else if (node->getOpCodeValue() == TR::allocationFence)5965synchronizedObject = node->getAllocation();5966else if (calledMethod && calledMethod->isSynchronised() && !calledMethod->isStatic())5967synchronizedObject = node->getChild(node->getFirstArgumentIndex());59685969if (synchronizedObject)5970{5971valueNumber = _valueNumberInfo->getValueNumber(synchronizedObject);5972candidate = findCandidate(valueNumber);5973if (candidate &&5974!candidate->escapesInColdBlocks())5975{5976if (calledMethod)5977{5978if (_desynchronizeCalls)5979{5980if (trace())5981{5982/////printf("sec Opportunity to desynchronize call to %s (size %d) in %s\n", calledMethod->getResolvedMethod()->signature(trMemory()), maxBytecodeIndex(calledMethod->getResolvedMethod()), comp()->signature());5983traceMsg(comp(), "Mark call node [%p] as desynchronized\n", node);5984}5985node->setDesynchronizeCall(true);5986if (!_inlineCallSites.find(_curTree))5987_inlineCallSites.add(_curTree);5988}5989}5990else5991{5992#if CHECK_MONITORS5993if (trace())5994traceMsg(comp(), "Remove redundant monitor node [%p]\n", node);5995removeThisNode = true;5996#else5997if (node->getOpCodeValue() == TR::allocationFence)5998{5999if (candidate->isLocalAllocation())6000{6001if (trace())6002traceMsg(comp(), "Redundant flush node [%p] found! Set omitSync flag on redundant flush node.\n", node);60036004node->setOmitSync(true);6005node->setAllocation(NULL);6006//removeThisNode = true;6007}6008}6009else if (candidate->isLocalAllocation())6010{6011// Mark the node as being a monitor on a local object and let6012// redundant monitor elimination get rid of it.6013//6014node->setLocalObjectMonitor(true);6015requestOpt(OMR::redundantMonitorElimination);6016if (trace())6017traceMsg(comp(), "Mark monitor node [%p] as local object monitor\n", node);6018}6019#endif6020}6021}60226023else if(candidate && candidate->escapesInColdBlocks() &&6024node->getOpCodeValue() == TR::allocationFence &&6025candidate->isLocalAllocation())6026{6027ListIterator<TR_ColdBlockEscapeInfo> coldBlkInfoIt(candidate->getColdBlockEscapeInfo());6028TR_ColdBlockEscapeInfo *info;6029for (info = coldBlkInfoIt.getFirst(); info != NULL; info = coldBlkInfoIt.getNext())6030{6031TR::Block *coldBlk = info->getBlock();6032if (!hasFlushOnEntry(coldBlk->getNumber()))6033{6034TR::TreeTop *insertionPoint = coldBlk->getEntry();6035TR::Node *flush = TR::Node::createAllocationFence(candidate->_node, candidate->_node);6036flush->setAllocation(NULL);6037TR::TreeTop *flushTT = TR::TreeTop::create(comp(), flush, NULL, NULL);6038TR::TreeTop *afterInsertionPoint = insertionPoint->getNextTreeTop();6039flushTT->join(afterInsertionPoint);6040insertionPoint->join(flushTT);6041if (trace())6042traceMsg(comp(), "Adding flush node %p to cold block_%d\n", flush,coldBlk->getNumber());6043setHasFlushOnEntry(coldBlk->getNumber());6044}6045}6046if (trace())6047traceMsg(comp(), "Remove redundant flush node [%p]\n", node);6048removeThisNode = true;60496050}60516052}60536054for (i = node->getNumChildren()-1; i >= 0; i--)6055{6056TR::Node *child = node->getChild(i);6057if (!visited.contains(child))6058{6059if (fixupNode(child, node, visited))6060removeThisNode = true;6061}6062}60636064if (removeThisNode)6065return true;60666067// If no local object is to be created remove all nodes that refer to the6068// original allocation.6069//6070candidate = findCandidate(_valueNumberInfo->getValueNumber(node));6071if (candidate &&6072candidate->isLocalAllocation() &&6073!candidate->isContiguousAllocation() &&6074//shouldRemoveTree(candidate, _curBlock) &&6075!candidate->objectIsReferenced() &&6076!comp()->suppressAllocationInlining())6077{6078// Remove trees (other than the allocation tree itself) that6079// refer to the allocation node.6080//6081if (_curTree != candidate->_treeTop)6082{6083// special handling for stores to the monitoredObject slot6084// if the object is going to be non-contiguously allocated,6085// then turn the store into a store of NULL. the store cannot be6086// removed because this would lead to an imbalance of the monitorStack6087// during liveMonitor propagation6088//6089if (_curTree->getNode()->getOpCode().isStore() &&6090(_curTree->getNode()->getSymbol()->holdsMonitoredObject() ||6091(_curTree->getNode()->getSymbolReference() == comp()->getSymRefTab()->findThisRangeExtensionSymRef())))6092{6093_curTree->getNode()->getFirstChild()->decReferenceCount();6094TR::Node *aconstNode = TR::Node::aconst(_curTree->getNode(), 0);6095_curTree->getNode()->setAndIncChild(0, aconstNode);6096if (trace())6097traceMsg(comp(), "%sFixed up liveMonitor store [%p] for candidate [%p]\n", OPT_DETAILS, _curTree->getNode(), candidate->_node);6098removeThisNode = false;6099}6100else6101{6102removeThisNode = true;61036104if (trace())6105traceMsg(comp(), "Remove tree [%p] with direct reference to candidate [%p]\n", _curTree->getNode(), candidate->_node);6106}6107}61086109// Reset the visit count on this node so that subsequent uses6110// are also removed.6111//6112visited.remove(node);6113}61146115return removeThisNode;6116}611761186119bool TR_EscapeAnalysis::fixupFieldAccessForContiguousAllocation(TR::Node *node, Candidate *candidate)6120{6121// Ignore stores to the generic int shadow for nodes that are already6122// explicitly initialized. These are the initializing stores and are going to6123// be left as they are (except maybe to insert real field symbol references6124// later if we can).6125//6126if (candidate->isExplicitlyInitialized() &&6127node->getSymbol() == getSymRefTab()->findGenericIntShadowSymbol())6128{6129return false;6130}61316132// If the local allocation is the only object that can be the base6133// of a write barrier store, change it into a simple indirect store.6134// We should be able to do this for arrays as well, however, IA32 TreeEvaluator needs to be6135// fixed in order to support this. FIXME6136//6137if (node->getOpCode().isWrtBar() &&6138!candidate->escapesInColdBlocks() &&6139_valueNumberInfo->getValueNumber(node->getFirstChild()) == _valueNumberInfo->getValueNumber(candidate->_node))6140{6141if (candidate->_origKind == TR::New)6142{6143TR::Node::recreate(node, TR::astorei);6144node->getChild(2)->recursivelyDecReferenceCount();6145node->setNumChildren(2);6146_repeatAnalysis = true;6147if (trace())6148traceMsg(comp(), "Change node [%p] from write barrier to regular store\n", node);6149}6150else6151{6152// We do not remove the wrtbars yet - but atleast remove the bits from6153// them indicating that they are non-heap wrtbars6154//6155node->setIsHeapObjectWrtBar(false);6156node->setIsNonHeapObjectWrtBar(true);6157}6158}61596160int32_t fieldOffset = node->getSymbolReference()->getOffset();6161if (candidate->_origKind == TR::New)6162{6163TR::SymbolReference *symRef = node->getSymbolReference();6164fieldOffset = symRef->getOffset();6165}6166else6167{6168TR::Node *offsetNode = NULL;6169if (node->getFirstChild()->getOpCode().isArrayRef())6170offsetNode = node->getFirstChild()->getSecondChild();61716172if (offsetNode && offsetNode->getOpCode().isLoadConst())6173{6174if (offsetNode->getType().isInt64())6175fieldOffset = (int32_t) offsetNode->getLongInt();6176else6177fieldOffset = offsetNode->getInt();6178}6179}61806181// Remember the symbol reference of this field so that it can be used to6182// zero-initialize the object.6183// Only do this for fields whose offsets are within the bounds of the object.6184// It is possible to reach uses which (via downcasting) are referencing a6185// derived class from the candidate class. At run time, the local allocation6186// should never reach these program points.6187//6188if (TR_yes == candidateHasField(candidate, node, fieldOffset, this))6189{6190// Remember the symbol reference of this field so that it can be used to6191// zero-initialize the object.6192//6193int32_t i;6194TR::SymbolReference *symRef = node->getSymbolReference();61956196int32_t nodeSize = node->getSize();6197if (comp()->useCompressedPointers() &&6198(node->getDataType() == TR::Address))6199nodeSize = TR::Compiler->om.sizeofReferenceField();62006201if (fieldOffset + nodeSize <= candidate->_size) // cmvc 200318: redundant but harmless -- leave in place to minimize disruption6202{6203for (i = candidate->_fields->size()-1; i >= 0; i--)6204{6205if (candidate->_fields->element(i)._offset == fieldOffset)6206{6207candidate->_fields->element(i).rememberFieldSymRef(node, fieldOffset, candidate, this);6208candidate->_fields->element(i)._symRef = symRef;6209candidate->_fields->element(i)._vectorElem = 0;6210break;6211}6212}6213TR_ASSERT(i >= 0, "candidate [%p] must have field (%s) at offset %d due to %p. Scan for escapes missed a field reference!\n", candidate->_node, comp()->getDebug()->getName(symRef), fieldOffset, node);6214}6215}6216return false;6217}62186219//We should provide a bound for the following array6220//Where are the following hard-coded constants coming from anyway?6221static TR::DataType convertArrayTypeToDataType[] =6222{6223TR::NoType, //06224TR::NoType, //16225TR::NoType, //26226TR::NoType, //36227TR::Int8, //46228TR::Int16, //56229TR::Float, //66230TR::Double, //76231TR::Int8, //86232TR::Int16,//96233TR::Int32, //106234TR::Int646235};62366237TR::Node *TR_EscapeAnalysis::createConst(TR::Compilation *comp, TR::Node *node, TR::DataType type, int value)6238{6239TR::Node *result;62406241if (type.isVector())6242{6243result = TR::Node::create(node, TR::vsplats, 1);6244result->setAndIncChild(0, TR::Node::create(node, comp->il.opCodeForConst(type), value));6245}6246else6247{6248result = TR::Node::create(node, comp->il.opCodeForConst(type), value);6249}6250return result;6251}625262536254bool TR_EscapeAnalysis::fixupFieldAccessForNonContiguousAllocation(TR::Node *node, Candidate *candidate, TR::Node *parent)6255{6256int32_t i;6257int32_t fieldOffset = (candidate->_origKind == TR::New) ?6258comp()->fej9()->getObjectHeaderSizeInBytes() : TR::Compiler->om.contiguousArrayHeaderSizeInBytes();6259TR::DataType fieldType = TR::NoType; // or array element type62606261// If this is a store to the generic int shadow, it is zero-initializing the6262// object. Remember which words are being zero-initialized; only fields that6263// intersect with these words will have to be explicitly zero-initialized.6264// These initializing stores can then be thrown away.6265//6266if (candidate->isExplicitlyInitialized() &&6267node->getOpCode().isStore() &&6268node->getSymbol() == getSymRefTab()->findGenericIntShadowSymbol())6269{6270if (!candidate->_initializedWords)6271candidate->_initializedWords = new (trStackMemory()) TR_BitVector(candidate->_size, trMemory(), stackAlloc);62726273for (i = 3; i >= 0; i--)6274candidate->_initializedWords->set(node->getSymbolReference()->getOffset()+i);62756276if (trace())6277traceMsg(comp(), "Remove explicit new initialization node [%p]\n", node);6278return true;6279}62806281if (candidate->_origKind == TR::New)6282{6283TR::SymbolReference *symRef = node->getSymbolReference();6284fieldOffset = symRef->getOffset();6285fieldType = symRef->getSymbol()->getDataType();6286}6287else6288{6289TR_ASSERT(node->getSymbolReference()->getSymbol()->isArrayShadowSymbol(), "expecting store to an array shadow");6290fieldOffset = node->getSymbolReference()->getOffset();6291TR::Node *typeNode = candidate->_node->getSecondChild();6292TR::Node *offsetNode = NULL;6293if (node->getFirstChild()->getOpCode().isArrayRef())6294offsetNode = node->getFirstChild()->getSecondChild();62956296if (offsetNode && offsetNode->getOpCode().isLoadConst())6297{6298if (offsetNode->getType().isInt64())6299fieldOffset = (int32_t) offsetNode->getLongInt();6300else6301fieldOffset = offsetNode->getInt();6302}63036304if (candidate->_origKind == TR::newarray)6305fieldType = convertArrayTypeToDataType[typeNode->getInt()];6306else6307fieldType = TR::Address;6308}63096310// This can happen for a vft-symbol which has no type6311//6312if (fieldType == TR::NoType)6313fieldType = TR::Address;63146315// Find or create the auto that is to replace this field reference6316//6317TR::SymbolReference *autoSymRef = NULL;6318for (i = candidate->_fields->size()-1; i >= 0; i--)6319{6320if (candidate->_fields->element(i)._offset == fieldOffset)6321{6322autoSymRef = candidate->_fields->element(i)._symRef;6323break;6324}6325}63266327//TR_ASSERT(i >= 0, "assertion failure");63286329if (i >= 0)6330{6331// Change the load or store to be a direct load or store of the6332// auto. We may have to introduce a conversion if the opcode type for the6333// direct store is different from the opcode type for the indirect store6334//6335TR::DataType nodeType = node->getDataType();6336TR::ILOpCodes newOpCode;6337if (node->getOpCode().isLoadVar())6338newOpCode = comp()->il.opCodeForDirectLoad(nodeType);6339else6340newOpCode = comp()->il.opCodeForDirectStore(nodeType);6341TR::DataType newOpType = comp()->fej9()->dataTypeForLoadOrStore(nodeType);6342TR::ILOpCodes conversionOp;63436344int elem = candidate->_fields->element(i)._vectorElem;6345if (elem != 0)6346{6347fieldOffset = fieldOffset - TR::Symbol::convertTypeToSize(nodeType)*(elem-1);6348autoSymRef = NULL;6349for (i = candidate->_fields->size()-1; i >= 0; i--)6350{6351if (candidate->_fields->element(i)._offset == fieldOffset)6352{6353autoSymRef = candidate->_fields->element(i)._symRef;6354break;6355}6356}6357TR_ASSERT(i >= 0, "element 0 should exist\n");63586359if (!newOpType.isVector())6360newOpType = newOpType.scalarToVector();63616362TR_ASSERT(newOpType != TR::NoType, "wrong type at node %p\n", node);6363}63646365if (!autoSymRef)6366{6367autoSymRef = getSymRefTab()->createTemporary(comp()->getMethodSymbol(), newOpType);6368autoSymRef->getSymbol()->setBehaveLikeNonTemp();6369candidate->_fields->element(i).rememberFieldSymRef(node, fieldOffset, candidate, this);6370candidate->_fields->element(i)._symRef = autoSymRef;6371}63726373if (node->getOpCode().isLoadVar())6374{6375node->removeAllChildren();6376conversionOp = TR::ILOpCode::getProperConversion(newOpType, nodeType, false /* !wantZeroExtension */);63776378if (conversionOp != TR::BadILOp)6379{6380TR::Node::recreate(node, conversionOp);6381node->setAndIncChild(0, TR::Node::createWithSymRef(node, newOpCode, 0, autoSymRef));6382node->setNumChildren(1);6383}6384else6385{6386TR::Node::recreate(node, newOpCode);6387node->setSymbolReference(autoSymRef);6388}6389if (autoSymRef->getSymbol()->getDataType().isVector() &&6390!node->getDataType().isVector())6391{6392TR::Node::recreate(node, node->getDataType() == TR::VectorDouble ? TR::vdgetelem : TR::vigetelem);6393node->setAndIncChild(0, TR::Node::create(node, TR::vload, 0));6394node->setNumChildren(2);6395node->getFirstChild()->setSymbolReference(autoSymRef);6396node->setAndIncChild(1, TR::Node::create(node, TR::iconst, 0, elem-1));6397}6398}6399else6400{6401conversionOp = TR::ILOpCode::getProperConversion(nodeType, newOpType, false /* !wantZeroExtension */);64026403TR::Node *valueChild;6404if (conversionOp != TR::BadILOp)6405valueChild = TR::Node::create(conversionOp, 1, node->getSecondChild());6406else6407valueChild = node->getSecondChild();64086409// Special case of non-contiguous immutable object that escapes in6410// a cold block: need to ensure the store to the original object6411// is preserved for heapification; otherwise, replace the old store6412// completely6413if (candidate->escapesInColdBlock(_curBlock)6414&& isImmutableObject(candidate) && !candidate->isContiguousAllocation())6415{6416TR::Node *newStore = TR::Node::createWithSymRef(newOpCode, 1, 1, valueChild, autoSymRef);6417TR::TreeTop *newTree = TR::TreeTop::create(comp(), newStore);6418TR::TreeTop *prev = _curTree->getPrevTreeTop();6419prev->join(newTree);6420newTree->join(_curTree);64216422if (trace())6423traceMsg(comp(), "Preserve old node [%p] for store to non-contiguous immutable object that escapes in cold block; create new tree [%p] for direct store\n", node, newTree);6424}6425else6426{6427valueChild->incReferenceCount();6428node->removeAllChildren();6429node->setFirst(valueChild);6430node->setNumChildren(1);6431TR::Node::recreate(node, newOpCode);6432node->setSymbolReference(autoSymRef);6433}64346435if (autoSymRef->getSymbol()->getDataType().isVector() &&6436!node->getDataType().isVector())6437{6438TR::Node::recreate(node, TR::vstore);6439TR::Node *value = node->getFirstChild();6440TR::Node *newValue = TR::Node::create(node, node->getDataType() == TR::VectorDouble ? TR::vdsetelem : TR::visetelem, 3);6441newValue->setAndIncChild(0, TR::Node::create(node, TR::vload, 0));6442newValue->getFirstChild()->setSymbolReference(autoSymRef);6443newValue->setChild(1, value);6444newValue->setAndIncChild(2, TR::Node::create(node, TR::iconst, 0, elem-1));6445node->setAndIncChild(0, newValue);6446}6447}6448if (trace())6449traceMsg(comp(), "Change node [%p] into a direct load or store of #%d (%d bytes) field %d cand %p\n", node, autoSymRef->getReferenceNumber(), autoSymRef->getSymbol()->getSize(), i, candidate);64506451if (parent)6452{6453if (parent->getOpCode().isNullCheck())6454TR::Node::recreate(parent, TR::treetop);6455else if (parent->getOpCode().isSpineCheck() && (parent->getFirstChild() == node))6456{6457TR::TreeTop *prev = _curTree->getPrevTreeTop();64586459int32_t i = 1;6460while (i < parent->getNumChildren())6461{6462TR::TreeTop *tt = TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, parent->getChild(i)));6463parent->getChild(i)->recursivelyDecReferenceCount();6464prev->join(tt);6465tt->join(_curTree);6466prev = tt;6467i++;6468}64696470TR::Node::recreate(parent, TR::treetop);6471parent->setNumChildren(1);6472}6473else if (parent->getOpCodeValue() == TR::ArrayStoreCHK)6474{6475TR::Node::recreate(parent, TR::treetop);64766477// we need to prepend a _special_ check-cast node to make sure that the store6478// would be valid at runtime. The checkcast is special only because it throws6479// ArrayStoreException instead of ClassCastException.6480//6481TR::Node *typeNode = TR::Node::copy(candidate->_node->getSecondChild()); // loadaddr of array type6482typeNode->setReferenceCount(0);6483TR::Node *source = node->getFirstChild();6484TR::Node *checkNode =6485TR::Node::createWithSymRef(TR::checkcast, 2, 2, source, typeNode,6486getSymRefTab()->findOrCreateCheckCastForArrayStoreSymbolRef(0));64876488TR::TreeTop *prev = _curTree->getPrevTreeTop();6489TR::TreeTop *tt = TR::TreeTop::create(comp(), checkNode);6490prev->join(tt);6491tt->join(_curTree);6492}6493else if (parent->getOpCode().isAnchor())6494{6495TR::Node::recreate(parent, TR::treetop);6496parent->getSecondChild()->recursivelyDecReferenceCount();6497parent->setNumChildren(1);6498}6499}6500}6501else6502{6503// The load/store is in an unreachable portion of6504// the method. If it is a store we get rid of the treetop completely,6505// otherwise change the indirect load to be a constant of the6506// correct type6507//6508if (node->getOpCode().isStore())6509return true;6510else6511{6512TR::Node::recreate(node, comp()->il.opCodeForConst(node->getDataType()));6513if (node->getNumChildren() > 0)6514node->getFirstChild()->recursivelyDecReferenceCount();6515node->setLongInt(0);6516node->setNumChildren(0);6517if (trace())6518traceMsg(comp(), "Change node [%p] into a constant\n", node);6519}6520}65216522return false;6523}652465256526void TR_EscapeAnalysis::makeLocalObject(Candidate *candidate)6527{6528int32_t i;6529TR::SymbolReference *symRef;6530TR::Node *allocationNode = candidate->_node;65316532// Change the "new" node into a load address of a local object/array6533//6534int32_t *referenceSlots = NULL;6535if (candidate->_kind == TR::New)6536{6537symRef = getSymRefTab()->createLocalObject(candidate->_size, comp()->getMethodSymbol(), allocationNode->getFirstChild()->getSymbolReference());65386539#if LOCAL_OBJECTS_COLLECTABLE6540if (candidate->isContiguousAllocation())6541referenceSlots = comp()->fej9()->getReferenceSlotsInClass(comp(), (TR_OpaqueClassBlock *)candidate->_node->getFirstChild()->getSymbol()->getStaticSymbol()->getStaticAddress());6542#endif6543if (!referenceSlots)6544symRef->getSymbol()->setNotCollected();6545else6546symRef->getSymbol()->getLocalObjectSymbol()->setReferenceSlots(referenceSlots);6547}6548else if (candidate->_kind == TR::anewarray)6549{6550symRef = getSymRefTab()->createLocalAddrArray(candidate->_size, comp()->getMethodSymbol(), allocationNode->getSecondChild()->getSymbolReference());6551symRef->setStackAllocatedArrayAccess();65526553// Set up the array of reference slots6554//6555int32_t numSlots = 0;6556#if LOCAL_OBJECTS_COLLECTABLE6557if (candidate->isContiguousAllocation())6558////numSlots = (candidate->_size - TR::Compiler->om.contiguousArrayHeaderSizeInBytes()) / _cg->sizeOfJavaPointer();6559numSlots = (candidate->_size - TR::Compiler->om.contiguousArrayHeaderSizeInBytes()) / TR::Compiler->om.sizeofReferenceField();6560#endif6561if (numSlots == 0)6562symRef->getSymbol()->setNotCollected();6563else6564{6565referenceSlots = (int32_t *)trMemory()->allocateHeapMemory((numSlots+1)*4, TR_Memory::EscapeAnalysis);6566////int32_t hdrSlots = TR::Compiler->om.contiguousArrayHeaderSizeInBytes()/_cg->sizeOfJavaPointer();6567int32_t hdrSlots = TR::Compiler->om.contiguousArrayHeaderSizeInBytes()/TR::Compiler->om.sizeofReferenceField();6568for (i = 0; i < numSlots; i++)6569referenceSlots[i] = hdrSlots + i;6570referenceSlots[numSlots] = 0;6571symRef->getSymbol()->getLocalObjectSymbol()->setReferenceSlots(referenceSlots);6572}6573}6574else6575{6576symRef = getSymRefTab()->createLocalPrimArray(candidate->_size, comp()->getMethodSymbol(), allocationNode->getSecondChild()->getInt());6577symRef->setStackAllocatedArrayAccess();6578}65796580if (trace() && referenceSlots)6581{6582traceMsg(comp(), " Reference slots for candidate [%p] : {",candidate->_node);6583for (i = 0; referenceSlots[i]; i++)6584{6585traceMsg(comp(), " %d", referenceSlots[i]);6586}6587traceMsg(comp(), " }\n");6588}65896590// Initialize the header of the local object6591//6592TR::Node *nodeToUseInInit = allocationNode->duplicateTree();6593TR::TreeTop *insertionPoint = comp()->getStartTree();65946595if (candidate->_kind == TR::New)6596comp()->fej9()->initializeLocalObjectHeader(comp(), nodeToUseInInit, insertionPoint);6597else6598comp()->fej9()->initializeLocalArrayHeader(comp(), nodeToUseInInit, insertionPoint);65996600allocationNode->removeAllChildren();6601TR::Node::recreate(allocationNode, TR::loadaddr);6602allocationNode->setSymbolReference(symRef);66036604if (candidate->_seenArrayCopy || candidate->_argToCall || candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)6605{6606allocationNode->setCannotTrackLocalUses(true);6607if (candidate->callsStringCopyConstructor())6608allocationNode->setCannotTrackLocalStringUses(true);6609}66106611if (nodeToUseInInit != allocationNode)6612{6613nodeToUseInInit->removeAllChildren();6614TR::Node::recreate(nodeToUseInInit, TR::loadaddr);6615nodeToUseInInit->setSymbolReference(symRef);6616if (candidate->escapesInColdBlocks() || candidate->_seenArrayCopy || candidate->_argToCall || candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)6617{6618if (candidate->escapesInColdBlocks())6619nodeToUseInInit->setEscapesInColdBlock(true);6620nodeToUseInInit->setCannotTrackLocalUses(true);6621if (candidate->callsStringCopyConstructor())6622nodeToUseInInit->setCannotTrackLocalStringUses(true);6623}6624}6625}6626662766286629void TR_EscapeAnalysis::avoidStringCopyAllocation(Candidate *candidate)6630{6631if (comp()->suppressAllocationInlining())6632return;66336634TR::Node *allocationNode = candidate->_node;66356636dumpOptDetails(comp(), "%sReplacing new (String) node [%p] with the String that was used in the copy constructor\n",OPT_DETAILS, candidate->_node);66376638if (trace() || debug ("traceContiguousESC"))6639{6640traceMsg(comp(), "secs (%d) String (copy) allocation of size %d found in %s\n", manager()->numPassesCompleted(), candidate->_size, comp()->signature());6641}664266436644TR::TreeTop *insertionPoint = candidate->_treeTop;6645TR::DataType dataType = candidate->_stringCopyNode->getDataType();6646TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dataType);6647TR::Node *initNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(candidate->_stringCopyNode->getDataType()), 1, 1, candidate->_stringCopyNode, newSymbolReference);6648TR::TreeTop *initTree = TR::TreeTop::create(comp(), initNode, 0, 0);6649TR::TreeTop *prevTree = insertionPoint->getPrevTreeTop();6650prevTree->join(initTree);6651initTree->join(insertionPoint);665266536654allocationNode->removeAllChildren();6655allocationNode->setNumChildren(0);6656TR::Node::recreate(allocationNode, comp()->il.opCodeForDirectLoad(candidate->_stringCopyNode->getDataType()));6657allocationNode->setSymbolReference(newSymbolReference);66586659TR::TreeTop *stringInitCall = candidate->_stringCopyCallTree;66606661if (stringInitCall)6662{6663TR::Node *stringInitCallNode = stringInitCall->getNode();6664stringInitCallNode->recursivelyDecReferenceCount();66656666prevTree = stringInitCall->getPrevTreeTop();6667TR::TreeTop *nextTree = stringInitCall->getNextTreeTop();6668prevTree->join(nextTree);6669}6670}66716672/** \details6673* This function will fully zero initialize the given candidate, meaning that aside from the header the entirety6674* of the stack allocated object will be zero initialized. This function can handle both objects and arrays.6675*/6676bool TR_EscapeAnalysis::tryToZeroInitializeUsingArrayset(Candidate* candidate, TR::TreeTop* precedingTreeTop)6677{6678if (cg()->getSupportsArraySet())6679{6680int32_t candidateHeaderSizeInBytes = candidate->_origKind == TR::New ? comp()->fej9()->getObjectHeaderSizeInBytes() : TR::Compiler->om.contiguousArrayHeaderSizeInBytes();66816682// Size of the object without the header6683int32_t candidateObjectSizeInBytes = candidate->_size - candidateHeaderSizeInBytes;66846685if (candidateObjectSizeInBytes > 0)6686{6687TR::Node* allocationNode = candidate->_node;66886689if (performTransformation(comp(), "%sUse arrayset to initialize [%p]\n", OPT_DETAILS, allocationNode))6690{6691TR::SymbolReference* allocationSymRef = allocationNode->getSymbolReference();66926693TR::Node* arrayset = TR::Node::createWithSymRef(TR::arrayset, 3, 3,6694TR::Node::createWithSymRef(allocationNode, TR::loadaddr, 0, new (trHeapMemory()) TR::SymbolReference(comp()->getSymRefTab(), allocationSymRef->getSymbol(), allocationSymRef->getOffset() + candidateHeaderSizeInBytes)),6695TR::Node::bconst(allocationNode, 0),6696TR::Node::iconst(allocationNode, candidateObjectSizeInBytes),6697comp()->getSymRefTab()->findOrCreateArraySetSymbol());66986699TR::TreeTop* arraysetTreeTop = TR::TreeTop::create(comp(), precedingTreeTop, TR::Node::create(TR::treetop, 1, arrayset));67006701TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "escapeAnalysis/zeroInitializeArrayset/%s", comp()->signature()), arraysetTreeTop);67026703return true;6704}6705}6706}67076708return false;6709}67106711void TR_EscapeAnalysis::makeContiguousLocalAllocation(Candidate *candidate)6712{6713int32_t i,j;6714int32_t offset;6715TR::Node *node;6716TR::Symbol *sym;6717TR::TreeTop *initTree, *next;67186719if (comp()->suppressAllocationInlining())6720return;67216722if (comp()->generateArraylets() && candidate->_kind != TR::New)6723return;67246725dumpOptDetails(comp(), "%sMaking %s node [%p] into a local object of size %d\n",OPT_DETAILS, candidate->_node->getOpCode().getName(), candidate->_node, candidate->_size);67266727if (trace() || debug ("traceContiguousESC"))6728{6729traceMsg(comp(), "secs (%d) Contiguous allocation of size %d found in %s\n", manager()->numPassesCompleted(), candidate->_size, comp()->signature());6730}67316732if (candidate->escapesInColdBlocks())6733candidate->_originalAllocationNode = candidate->_node->duplicateTree();67346735bool skipZeroInit = false;6736if ((candidate->_node->getOpCodeValue() != TR::New) &&6737candidate->_node->canSkipZeroInitialization())6738skipZeroInit = true;67396740makeLocalObject(candidate);67416742if (skipZeroInit)6743return;67446745TR::Node *allocationNode = candidate->_node;6746TR::SymbolReference *symRef = allocationNode->getSymbolReference();6747int32_t *referenceSlots = symRef->getSymbol()->getLocalObjectSymbol()->getReferenceSlots();67486749if (candidate->isExplicitlyInitialized())6750{6751// Find all the explicit zero-initializations and see if any of the6752// generic int shadows can be replaced by real field references.6753#if LOCAL_OBJECTS_COLLECTABLE6754// Any zero-initializations for collectable fields are removed.6755// These fields must be zero-initialized at the start of the method6756// instead of at the point of allocation, since liveness is not easily6757// predictable for these objects.6758#endif6759//6760for (initTree = candidate->_treeTop->getNextTreeTop(); initTree; initTree = next)6761{6762next = initTree->getNextTreeTop();6763node = initTree->getNode();6764if (node->getOpCodeValue() != TR::istorei ||6765node->getSymbol() != getSymRefTab()->findGenericIntShadowSymbol() ||6766node->getFirstChild() != candidate->_node)6767break;67686769int32_t zeroInitOffset = node->getSymbolReference()->getOffset();67706771// If this is a zero-initialization for a collectable field, remove6772// it since the initialization will be done at the start of the6773// method. Don't do this for allocations that are inside loops, since6774// for these allocations the initialization must happen every time6775// round the loop.6776//6777if (referenceSlots && !candidate->isInsideALoop())6778{6779for (j = 0; referenceSlots[j]; j++)6780{6781////if (zeroInitOffset == referenceSlots[j]*_cg->sizeOfJavaPointer())6782if (zeroInitOffset == referenceSlots[j]*TR::Compiler->om.sizeofReferenceField())6783{6784TR::TransformUtil::removeTree(comp(), initTree);6785break;6786}6787}6788if (referenceSlots[j])6789continue;6790}67916792if (candidate->_fields && candidate->_origKind == TR::New)6793{6794for (i = candidate->_fields->size()-1; i >= 0; i--)6795{6796FieldInfo &field = candidate->_fields->element(i);6797offset = field._offset;6798if (field._symRef &&6799offset == node->getSymbolReference()->getOffset())6800{6801node->getSecondChild()->recursivelyDecReferenceCount();6802sym = field._symRef->getSymbol();6803TR::DataType type = sym->getDataType();6804node->setAndIncChild(1, createConst(comp(), node, type, 0));6805node->setSymbolReference(field._symRef);6806TR::Node::recreate(node, comp()->il.opCodeForIndirectStore(type));6807break;6808}6809}6810}6811}6812}6813else6814{6815// Zero-initialize all the non-collectable slots, using field symbol6816// references where possible. For news that are inside loops, also initialize6817// the collectable slots (in addition to their initialization at method entry)6818//6819initTree = candidate->_treeTop;68206821if (candidate->_kind == TR::newarray)6822{6823// TODO (Task 118458): We need to investigate the effect of using arrayset on small number of elements. This involves verifying the instruction6824// sequences each individual codegen will generate and only if the codegens can handle arraysets of small number of elements in a performant manner6825// can we enable this optimization.6826const bool enableNewArrayArraySetPendingInvestigation = false;68276828// Non-collectable slots should be initialized with arrayset since they do not have field symrefs6829if (enableNewArrayArraySetPendingInvestigation && tryToZeroInitializeUsingArrayset(candidate, initTree))6830{6831TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "escapeAnalysis/zeroInitializeArrayset/%s/primitive", comp()->signature()), initTree->getNextTreeTop());68326833return;6834}6835}68366837int32_t headerSize = (candidate->_kind == TR::New) ?6838comp()->fej9()->getObjectHeaderSizeInBytes() :6839TR::Compiler->om.contiguousArrayHeaderSizeInBytes();6840int32_t refSlotIndex = 0;6841// Changes for new 64-bit object model6842i = headerSize;6843//for (i = headerSize; i < candidate->_size; i += _cg->sizeOfJavaPointer())6844int32_t refIncrVal = TR::Compiler->om.sizeofReferenceField();////TR::Symbol::convertTypeToSize(TR::Address);6845int32_t intIncrVal = 4; //TR::Symbol::convertTypeToSize(TR_SInt32)68466847while (i < candidate->_size)6848{6849if (!candidate->isInsideALoop() && referenceSlots && i == referenceSlots[refSlotIndex]*TR::Compiler->om.sizeofReferenceField())6850{6851refSlotIndex++;6852i += refIncrVal;6853continue;6854}68556856// See if the slot can be initialized using a field reference6857//6858if (candidate->_fields && candidate->_origKind == TR::New)6859{6860for (j = candidate->_fields->size()-1; j >= 0; j--)6861{6862FieldInfo &field = candidate->_fields->element(j);6863if (field._offset == i && field._symRef)6864{6865TR::DataType type = field._symRef->getSymbol()->getDataType();6866node = createConst(comp(), allocationNode, type, 0);6867node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, allocationNode, node, field._symRef);6868initTree = TR::TreeTop::create(comp(), initTree, node);6869i += field._size;6870TR_ASSERT(field._size != 0, "assertion failure");6871break;6872}6873}6874if (j >= 0)6875continue;6876}68776878// If we have no field reference, we have to initialize using a generic int shadow.6879// Since we don't know the type, we have to initialize only a 4byte slot.6880//6881node = TR::Node::create(allocationNode, TR::iconst, 0);6882node = TR::Node::createWithSymRef(TR::istorei, 2, 2, allocationNode, node, (candidate->_origKind == TR::New)6883? getSymRefTab()->findOrCreateGenericIntNonArrayShadowSymbolReference(i) : getSymRefTab()->findOrCreateGenericIntArrayShadowSymbolReference(i));6884initTree = TR::TreeTop::create(comp(), initTree, node);6885i += intIncrVal;6886}6887}68886889// Now go through the collectable reference slots and initialize them at the6890// start of the method6891//6892if (referenceSlots)6893{6894initTree = comp()->getStartTree();68956896if (tryToZeroInitializeUsingArrayset(candidate, initTree))6897{6898TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "escapeAnalysis/zeroInitializeArrayset/%s/reference", comp()->signature()), initTree->getNextTreeTop());68996900return;6901}69026903TR::Node *baseNode = NULL;69046905for (i = 0; referenceSlots[i]; i++)6906{6907////int32_t offset = referenceSlots[i] * _cg->sizeOfJavaPointer();6908int32_t offset = referenceSlots[i] * TR::Compiler->om.sizeofReferenceField();69096910// See if the slot can be initialized using a field reference6911//6912if (!baseNode)6913{6914baseNode = TR::Node::createWithSymRef(allocationNode, TR::loadaddr, 0, symRef);6915if (candidate->escapesInColdBlocks() || candidate->_seenArrayCopy || candidate->_argToCall || candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)6916{6917if (candidate->escapesInColdBlocks())6918baseNode->setEscapesInColdBlock(true);6919baseNode->setCannotTrackLocalUses(true);6920if (candidate->callsStringCopyConstructor())6921baseNode->setCannotTrackLocalStringUses(true);6922}6923}69246925if (candidate->_fields && candidate->_origKind == TR::New)6926{6927for (j = candidate->_fields->size()-1; j >= 0; j--)6928{6929FieldInfo &field = candidate->_fields->element(j);6930if (field._offset == offset && field._symRef)6931{6932TR::DataType type = field._symRef->getSymbol()->getDataType();6933node = createConst(comp(), allocationNode, type, 0);6934node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, baseNode, node, field._symRef);6935if (comp()->useCompressedPointers())6936initTree = TR::TreeTop::create(comp(), initTree, TR::Node::createCompressedRefsAnchor(node));6937else6938initTree = TR::TreeTop::create(comp(), initTree, node);6939break;6940}6941}6942if (j >= 0)6943continue;6944}69456946// If not, use a generic int shadow to zero-initialize.6947//6948node = TR::Node::aconst(allocationNode, 0);6949//symRef = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(offset);6950TR::Node *storeNode = TR::Node::createWithSymRef(TR::astorei, 2, 2,baseNode,node, (candidate->_origKind == TR::New) ?6951getSymRefTab()->findOrCreateGenericIntNonArrayShadowSymbolReference(offset) :6952getSymRefTab()->findOrCreateGenericIntArrayShadowSymbolReference(offset));6953if (comp()->useCompressedPointers())6954initTree = TR::TreeTop::create(comp(), initTree, TR::Node::createCompressedRefsAnchor(storeNode));6955else6956initTree = TR::TreeTop::create(comp(), initTree, storeNode);6957}6958}6959}69606961void TR_EscapeAnalysis::makeNonContiguousLocalAllocation(Candidate *candidate)6962{6963if (comp()->suppressAllocationInlining())6964return;69656966if (comp()->generateArraylets() && (candidate->_kind != TR::New))6967return;69686969if (candidate->objectIsReferenced())6970{6971dumpOptDetails(comp(), "%sMaking %s node [%p] into separate local fields and a local object\n",OPT_DETAILS, candidate->_node->getOpCode().getName(), candidate->_node);6972}6973else6974{6975dumpOptDetails(comp(), "%sMaking %s node [%p] into separate local fields\n",OPT_DETAILS, candidate->_node->getOpCode().getName(), candidate->_node);6976}69776978if (trace())6979{6980traceMsg(comp(),"Pass: (%d) Non-contiguous allocation found in %s\n", manager()->numPassesCompleted(), comp()->signature());6981//printf("Pass: (%d) Non-contiguous allocation found in %s\n", manager()->numPassesCompleted(), comp()->signature());6982}69836984// Zero-initialize all the fields6985//6986if (candidate->_fields)6987{6988for (int32_t i = candidate->_fields->size()-1; i >= 0; i--)6989{6990FieldInfo &autoField = candidate->_fields->element(i);6991if (!autoField._symRef || !autoField._symRef->getSymbol()->isAuto())6992continue;69936994// If there was explicit zero-initialization of this object, only6995// initialize this field if it intersects the explicit zero-initialization6996//6997if (candidate->isExplicitlyInitialized())6998{6999if (!candidate->_initializedWords)7000continue;7001int32_t j;7002for (j = autoField._size-1; j >= 0; j--)7003{7004if (candidate->_initializedWords->get(autoField._offset+j))7005break;7006}7007if (j < 0)7008continue;7009}70107011TR::DataType type = autoField._symRef->getSymbol()->getDataType();7012TR::Node *node = createConst(comp(), candidate->_node, type, 0);7013node = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(type), 1, 1, node, autoField._symRef);7014TR::TreeTop::create(comp(), candidate->_treeTop, node);70157016}7017}70187019if (candidate->escapesInColdBlocks())7020{7021candidate->_originalAllocationNode = candidate->_node->duplicateTree();7022}70237024// If the object was referenced we will need to create a local object for it7025// too. In this case, a local object of type "java/lang/Object" is created.7026//7027if (candidate->objectIsReferenced())7028{7029if (candidate->_kind != TR::New)7030{7031candidate->_origSize = candidate->_size;7032candidate->_origKind = candidate->_kind;70337034// Zero length hybrid arrays have a discontiguous shape.7035//7036candidate->_size = TR::Compiler->om.discontiguousArrayHeaderSizeInBytes();70377038TR::Node *sizeChild = candidate->_node->getFirstChild();7039TR_ASSERT(sizeChild->getOpCodeValue() == TR::iconst, "The size of non-contiguous stack allocated array object should be constant\n");7040if (sizeChild->getReferenceCount() == 1)7041sizeChild->setInt(0);7042else7043{7044TR::Node *newSizeChild = TR::Node::create(sizeChild, TR::iconst, 0);7045newSizeChild->setInt(0);7046candidate->_node->setAndIncChild(0, newSizeChild);7047sizeChild->decReferenceCount();7048}7049}7050else7051{7052// Change the node so that it allocates a java/lang/Object object7053//7054TR::ResolvedMethodSymbol *owningMethodSymbol = candidate->_node->getSymbolReference()->getOwningMethodSymbol(comp());7055TR_OpaqueClassBlock *classObject = comp()->getObjectClassPointer();7056////the call to findOrCreateClassSymbol is safe even though we pass CPI of -1 it is guarded by another check (see the first occurrence of findOrCreateClassSymbol in EA; dememoizedConstructorCall7057TR::SymbolReference *classSymRef = getSymRefTab()->findOrCreateClassSymbol(owningMethodSymbol, -1, classObject, false);7058TR::Node *classNode = TR::Node::createWithSymRef(candidate->_node, TR::loadaddr, 0, classSymRef);7059candidate->_node->removeAllChildren();7060candidate->_node->setAndIncChild(0, classNode);7061TR::Node::recreate(candidate->_node, TR::New);7062candidate->_node->setNumChildren(1);7063candidate->_class = classObject;7064candidate->_origSize = candidate->_size;7065candidate->_origKind = candidate->_kind;7066candidate->_size = comp()->fej9()->getObjectHeaderSizeInBytes() + TR::Compiler->cls.classInstanceSize(classObject);7067candidate->_kind = TR::New;7068}7069candidate->setExplicitlyInitialized(false);7070makeLocalObject(candidate);7071}70727073else7074{7075// Remove the tree containing the allocation node. All uses of the node7076// should have been removed by now7077//7078TR_ASSERT(candidate->_node->getReferenceCount() == 1, "assertion failure");7079TR::TransformUtil::removeTree(comp(), candidate->_treeTop);7080}7081}7082708370847085void TR_EscapeAnalysis::heapifyForColdBlocks(Candidate *candidate)7086{7087static char *disableSelectOpForEA = feGetEnv("TR_disableSelectOpForEA");7088bool useSelectOp = !disableSelectOpForEA && cg()->getSupportsSelect();70897090if (comp()->suppressAllocationInlining())7091return;70927093if (trace())7094{7095traceMsg(comp(),"Found candidate allocated with cold block compensation in %s numBlocks compensated = %d\n", comp()->signature(), candidate->getColdBlockEscapeInfo()->getSize());7096//printf("Found candidate allocated with cold block compensation in %s numBlocks compensated = %d\n", comp()->signature(), candidate->getColdBlockEscapeInfo()->getSize());7097}70987099TR::SymbolReference *heapSymRef = getSymRefTab()->createTemporary(comp()->getMethodSymbol(), TR::Address);71007101TR::TreeTop *allocationTree = candidate->_treeTop;7102TR::TreeTop *nextTree = allocationTree->getNextTreeTop();7103TR::Node *heapSymRefStore = TR::Node::createWithSymRef(TR::astore, 1, 1, candidate->_node, heapSymRef);7104TR::TreeTop *heapSymRefStoreTree = TR::TreeTop::create(comp(), heapSymRefStore, NULL, NULL);7105allocationTree->join(heapSymRefStoreTree);7106heapSymRefStoreTree->join(nextTree);71077108if (candidate->isContiguousAllocation())7109{7110candidate->_node->setCannotTrackLocalUses(true);7111candidate->_node->setEscapesInColdBlock(true);7112if (candidate->callsStringCopyConstructor())7113candidate->_node->setCannotTrackLocalStringUses(true);7114//if (candidate->_originalAllocationNode)7115// candidate->_originalAllocationNode->setCannotTrackLocalUses(true);7116}71177118ListIterator<TR_ColdBlockEscapeInfo> coldBlockInfoIt(candidate->getColdBlockEscapeInfo());7119TR_ColdBlockEscapeInfo *info;7120TR::CFG *cfg = comp()->getFlowGraph();7121for (info = coldBlockInfoIt.getFirst(); info != NULL; info = coldBlockInfoIt.getNext())7122{7123// Invalidate structure if adding blocks; can be repaired probably in this7124// case if needed in the future7125//7126comp()->getFlowGraph()->setStructure(NULL);712771287129// Create the heap allocation7130//7131TR::Block *coldBlock = info->getBlock();7132TR::TreeTop *insertionPoint = coldBlock->getEntry();7133TR::TreeTop *treeBeforeInsertionPoint = insertionPoint->getPrevTreeTop();7134TR::Node *heapAllocation = TR::Node::create(TR::treetop, 1, candidate->_originalAllocationNode->duplicateTree());7135heapAllocation->getFirstChild()->setHeapificationAlloc(true);71367137if (trace())7138traceMsg(comp(), "heapifying %p b1 %d b2 %d\n", candidate->_node, candidate->isContiguousAllocation(), candidate->_dememoizedMethodSymRef);71397140if (!candidate->isContiguousAllocation() && _dememoizedAllocs.find(candidate->_node))7141{7142heapAllocation->getFirstChild()->getFirstChild()->recursivelyDecReferenceCount(); // remove loadaddr of class71437144TR::SymbolReference *autoSymRefForValue = NULL;7145if (candidate->_fields)7146{7147int32_t j;7148int32_t fieldSize = 0;7149for (j = candidate->_fields->size()-1; j >= 0; j--)7150{7151FieldInfo &field = candidate->_fields->element(j);7152fieldSize = field._size;7153if (field._symRef &&7154field._symRef->getSymbol()->isAuto() &&7155(candidate->_origKind == TR::New))7156{7157autoSymRefForValue = field._symRef;7158break;7159}7160}7161}71627163TR::Node *stackFieldLoad = NULL;7164if (autoSymRefForValue)7165stackFieldLoad = TR::Node::createWithSymRef(heapAllocation, comp()->il.opCodeForDirectLoad(autoSymRefForValue->getSymbol()->getDataType()), 0, autoSymRefForValue);7166else7167stackFieldLoad = TR::Node::create(heapAllocation, TR::iconst, 0, 0);71687169heapAllocation->getFirstChild()->setAndIncChild(0, stackFieldLoad);7170TR::Node::recreate(heapAllocation->getFirstChild(), TR::acall);7171heapAllocation->getFirstChild()->setSymbolReference(_dememoizationSymRef);7172}7173717471757176TR::TreeTop *heapAllocationTree = TR::TreeTop::create(comp(), heapAllocation, NULL, NULL);7177TR::Node *heapStore = TR::Node::createWithSymRef(TR::astore, 1, 1, heapAllocation->getFirstChild(), heapSymRef);7178TR::TreeTop *heapStoreTree = TR::TreeTop::create(comp(), heapStore, NULL, NULL);7179TR::Block *heapAllocationBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(heapAllocation, comp(), coldBlock->getFrequency())));7180heapAllocationBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());718171827183// Check if a heap object has been created for this stack allocated7184// candidate before7185//7186TR::Node *tempLoad = TR::Node::createWithSymRef(heapAllocation, comp()->il.opCodeForDirectLoad(TR::Address), 0, heapSymRef);7187TR::Node *heapComparisonNode = TR::Node::createif(TR::ifacmpne, tempLoad, candidate->_node->duplicateTree(), NULL);7188TR::TreeTop *heapComparisonTree = TR::TreeTop::create(comp(), heapComparisonNode, NULL, NULL);7189TR::Block *heapComparisonBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(heapComparisonNode, comp(), coldBlock->getFrequency())));7190heapComparisonBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());71917192TR::TreeTop *heapComparisonEntryTree = heapComparisonBlock->getEntry();7193TR::TreeTop *heapComparisonExitTree = heapComparisonBlock->getExit();7194heapComparisonEntryTree->join(heapComparisonTree);7195heapComparisonTree->join(heapComparisonExitTree);71967197heapComparisonExitTree->join(insertionPoint);71987199if (treeBeforeInsertionPoint)7200treeBeforeInsertionPoint->join(heapComparisonEntryTree);7201else7202comp()->setStartTree(heapComparisonEntryTree);72037204treeBeforeInsertionPoint = heapComparisonExitTree;72057206//cfg->addEdge(heapComparisonBlock, firstComparisonBlock);7207cfg->addEdge(heapComparisonBlock, heapAllocationBlock);72087209// Copy the contents into newly created heap allocation7210//7211TR::TreeTop *heapAllocationEntryTree = heapAllocationBlock->getEntry();7212TR::TreeTop *heapAllocationExitTree = heapAllocationBlock->getExit();7213heapAllocationEntryTree->join(heapAllocationTree);7214heapAllocationTree->join(heapStoreTree);7215heapStoreTree->join(heapAllocationExitTree);72167217heapAllocationExitTree->join(insertionPoint);72187219if (treeBeforeInsertionPoint)7220treeBeforeInsertionPoint->join(heapAllocationEntryTree);7221else7222comp()->setStartTree(heapAllocationEntryTree);72237224treeBeforeInsertionPoint = heapStoreTree;7225TR::Node *stackAllocation = candidate->_node->duplicateTree();72267227// Copy all the slots, using field symbol references where possible.7228//7229int32_t headerSize = (candidate->_origKind == TR::New) ?7230comp()->fej9()->getObjectHeaderSizeInBytes() :7231TR::Compiler->om.contiguousArrayHeaderSizeInBytes();7232int32_t i;7233int32_t size = candidate->_size;7234if (!candidate->isContiguousAllocation())7235size = candidate->_origSize;7236// Changes for new 64-bit object model7237int32_t refIncrVal = TR::Symbol::convertTypeToSize(TR::Address);7238int32_t intIncrVal = 4; // TR::Symbol::convertTypeToSize(TR_SInt32);7239i = headerSize;7240//for (i = headerSize; i < size; i += _cg->sizeOfJavaPointer())7241while (i < size)7242{7243//7244// See if the slot can be initialized using a field reference7245//7246if (candidate->_fields)7247{7248int32_t j;7249int32_t fieldSize = 0;7250for (j = candidate->_fields->size()-1; j >= 0; j--)7251{7252FieldInfo &field = candidate->_fields->element(j);7253fieldSize = field._size;7254if (field._offset == i &&7255field._symRef &&7256(candidate->isContiguousAllocation() || field._symRef->getSymbol()->isAuto()) &&7257candidate->_origKind == TR::New)7258{7259TR::DataType type = field._symRef->getSymbol()->getDataType();72607261TR::Node *stackFieldLoad = NULL;7262if (!candidate->isContiguousAllocation())7263stackFieldLoad = TR::Node::createWithSymRef(heapAllocation, comp()->il.opCodeForDirectLoad(type), 0, field._symRef);7264else7265stackFieldLoad = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(type), 1, 1, stackAllocation, field._symRef);72667267TR::Node *heapFieldStore = NULL;7268TR::TreeTop *translateTT = NULL;7269if (stackFieldLoad->getDataType() == TR::Address)7270{7271heapFieldStore = TR::Node::createWithSymRef(TR::awrtbari, 3, 3, heapAllocation->getFirstChild(), stackFieldLoad, heapAllocation->getFirstChild(), field.fieldSymRef());7272if (comp()->useCompressedPointers())7273{7274translateTT = TR::TreeTop::create(comp(), TR::Node::createCompressedRefsAnchor(heapFieldStore), NULL, NULL);7275}7276}7277else7278heapFieldStore = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, heapAllocation->getFirstChild(), stackFieldLoad, field.fieldSymRef());7279TR::TreeTop *heapFieldStoreTree = NULL;7280//comp()->useCompressedPointers()7281if (translateTT)7282heapFieldStoreTree = translateTT;7283else7284heapFieldStoreTree = TR::TreeTop::create(comp(), heapFieldStore, NULL, NULL);7285treeBeforeInsertionPoint->join(heapFieldStoreTree);7286heapFieldStoreTree->join(heapAllocationExitTree);7287treeBeforeInsertionPoint = heapFieldStoreTree;7288break;7289}7290}7291if (j >= 0)7292{7293i += fieldSize;7294continue;7295}7296}72977298// If not, use a generic int shadow to initialize.7299//7300// don't exceed the object size7301// if ((i + refIncrVal) <= size)7302// {7303// TR::SymbolReference *intShadow = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(i);73047305// TR::Node *stackFieldLoad = NULL;7306// if (candidate->isContiguousAllocation())7307// stackFieldLoad = TR::Node::create(TR::aloadi, 1, stackAllocation, intShadow);7308// else7309// stackFieldLoad = TR::Node::aconst(heapAllocation, 0);73107311// TR::Node *heapFieldStore = TR::Node::create(TR::astorei, 2, heapAllocation->getFirstChild(), stackFieldLoad, intShadow);7312// TR::TreeTop *heapFieldStoreTree = TR::TreeTop::create(comp(), heapFieldStore, NULL, NULL);7313// treeBeforeInsertionPoint->join(heapFieldStoreTree);7314// heapFieldStoreTree->join(heapAllocationExitTree);7315// treeBeforeInsertionPoint = heapFieldStoreTree;7316// i += refIncrVal;7317// }7318// else7319// {7320TR::SymbolReference *intShadow;7321if (candidate->_origKind == TR::New)7322intShadow = getSymRefTab()->findOrCreateGenericIntNonArrayShadowSymbolReference(i);7323else7324intShadow = getSymRefTab()->findOrCreateGenericIntArrayShadowSymbolReference(i);73257326TR::Node *stackFieldLoad = NULL;7327if (candidate->isContiguousAllocation())7328stackFieldLoad = TR::Node::createWithSymRef(TR::iloadi, 1, 1, stackAllocation, intShadow);7329else7330stackFieldLoad = TR::Node::create(heapAllocation, TR::iconst, 0);7331TR::Node *heapFieldStore = TR::Node::createWithSymRef(TR::istorei, 2, 2, heapAllocation->getFirstChild(), stackFieldLoad, intShadow);7332TR::TreeTop *heapFieldStoreTree = TR::TreeTop::create(comp(), heapFieldStore, NULL, NULL);7333treeBeforeInsertionPoint->join(heapFieldStoreTree);7334heapFieldStoreTree->join(heapAllocationExitTree);7335treeBeforeInsertionPoint = heapFieldStoreTree;7336i += intIncrVal;7337// }7338}73397340insertionPoint = coldBlock->getEntry();7341treeBeforeInsertionPoint = insertionPoint->getPrevTreeTop();7342TR::Block *targetBlock = coldBlock;7343ListIterator<TR::Node> nodesIt(info->getNodes());7344ListIterator<TR::TreeTop> treesIt(info->getTrees());7345TR::Node *escapeNode;7346TR::TreeTop *escapeTree = treesIt.getFirst();7347TR::Block *lastComparisonBlock = NULL, *lastStoreBlock = NULL;7348for (escapeNode = nodesIt.getFirst(); escapeNode != NULL; escapeNode = nodesIt.getNext(), escapeTree = treesIt.getNext())7349{7350bool skipStores = false;7351if (escapeTree->getNode()->getOpCode().isReturn())7352skipStores = true;7353else if (escapeTree->getNode()->getOpCodeValue() == TR::treetop ||7354escapeTree->getNode()->getOpCode().isNullCheck())7355{7356TR::Node *firstChild = escapeTree->getNode()->getFirstChild();7357if (firstChild->getOpCodeValue() == TR::athrow)7358skipStores = true;7359}73607361if ((!candidate->isContiguousAllocation()) && !skipStores && !isImmutableObject(candidate) )7362{7363//7364// Store back into all the temp slots, using field symbol references where possible.7365//73667367//TR::TreeTop *coldBlockTree = coldBlock->getLastRealTreeTop();7368//TR::Node *coldBlockNode = coldBlockTree->getNode();73697370//if (coldBlockNode->getOpCodeValue() == TR::treetop)7371// coldBlockNode = coldBlockNode->getFirstChild();73727373//if (coldBlockNode->getOpCode().isBranch() ||7374// coldBlockNode->getOpCode().isSwitch() ||7375// coldBlockNode->getOpCode().isReturn() ||7376// coldBlockNode->getOpCodeValue() == TR::athrow)7377// coldBlockTree = coldBlockTree->getPrevTreeTop();7378//7379TR::TreeTop *coldBlockTree = escapeTree;73807381int32_t headerSize = (candidate->_origKind == TR::New) ?7382comp()->fej9()->getObjectHeaderSizeInBytes() :7383TR::Compiler->om.contiguousArrayHeaderSizeInBytes();7384int32_t size = candidate->_origSize;7385// Changes for new 64-bit object model7386// instead of _cg->sizeOfJavaPointer(), increment by field size7387//for (i = headerSize; i < size; i += incrVal)7388int32_t i = headerSize;7389int32_t incrVal = 4; // TR::Symbol::convertTypeToSize(TR_SInt32)7390while (i < size)7391{7392//7393// See if the slot can be initialized using a field reference7394//7395TR::TreeTop *nextTreeInColdBlock = coldBlockTree->getNextTreeTop();7396if (candidate->_fields)7397{7398int32_t j;7399for (j = candidate->_fields->size()-1; j >= 0; j--)7400{7401FieldInfo &field = candidate->_fields->element(j);7402if (field._offset == i &&7403field._symRef && field._symRef->getSymbol()->isAuto() /* &&7404field._size == TR::Symbol::convertTypeToSize(TR_SInt32)*/)7405{7406TR::DataType type = field._symRef->getSymbol()->getDataType();74077408TR::Node *heapFieldLoad = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(type), 1, 1, escapeNode, field.fieldSymRef());7409TR::TreeTop *translateTT = NULL;7410if (comp()->useCompressedPointers()7411&& (type == TR::Address))7412{7413translateTT = TR::TreeTop::create(comp(), TR::Node::createCompressedRefsAnchor(heapFieldLoad), NULL, NULL);7414}7415TR::Node *stackStore = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(type), 1, 1, heapFieldLoad, field._symRef);7416TR::TreeTop *stackStoreTree = TR::TreeTop::create(comp(), stackStore, NULL, NULL);7417if (trace())7418traceMsg(comp(), "Emitting stack store back %p cold %p next %p\n", stackStore, coldBlockTree->getNode(), nextTreeInColdBlock->getNode());7419coldBlockTree->join(stackStoreTree);7420stackStoreTree->join(nextTreeInColdBlock);7421// comp()->useCompressedPointers()7422if (translateTT)7423{7424coldBlockTree->join(translateTT);7425translateTT->join(stackStoreTree);7426}7427coldBlockTree = stackStoreTree;7428// increment by data type size7429i += field._size;7430break;7431}7432}7433if (j >= 0)7434continue;7435}7436i += incrVal;7437}7438}7439}74407441TR::TreeTop *insertSymRefStoresAfter = NULL;74427443// If using aselect to perform comparisons, all compares and stores are7444// inserted directly at the start of the cold block7445if (useSelectOp)7446{7447insertSymRefStoresAfter = coldBlock->getEntry();7448}74497450ListIterator<TR::SymbolReference> symRefsIt(candidate->getSymRefs());7451TR::SymbolReference *symRef;7452bool generatedReusedOperations = false;7453TR::Node *heapTempLoad = NULL;7454TR::Node *candidateStackAddrLoad = NULL;74557456for (symRef = symRefsIt.getFirst(); symRef; symRef = symRefsIt.getNext())7457{7458//7459// Now create the compares (one for each node) and stores7460//7461if (useSelectOp)7462{7463// Reload address of object on heap just once for this block7464if (!heapTempLoad)7465{7466heapTempLoad = TR::Node::createWithSymRef(candidate->_node, TR::aload, 0, heapSymRef);7467candidateStackAddrLoad = candidate->_node->duplicateTree();7468}74697470// If variable has address of the stack allocated object, replace7471// with the value of the heap allocated object; otherwise, keep the7472// current value7473//7474// astore <object-temp>7475// aselect7476// acmpeq7477// aload <object-temp>7478// loadaddr <stack-obj>7479// aload <heap-allocated-obj>7480// aload <object-temp>7481//7482TR::Node *symLoad = TR::Node::createWithSymRef(candidate->_node, TR::aload, 0, symRef);7483TR::Node *addrCompareNode = TR::Node::create(candidate->_node, TR::acmpeq, 2, symLoad, candidateStackAddrLoad);7484TR::Node *chooseAddrNode = TR::Node::create(TR::aselect, 3, addrCompareNode, heapTempLoad, symLoad);74857486TR::TreeTop *storeTree = storeHeapifiedToTemp(candidate, chooseAddrNode, symRef);74877488storeTree->join(insertSymRefStoresAfter->getNextTreeTop());7489insertSymRefStoresAfter->join(storeTree);7490}7491else7492{7493TR::Node *comparisonNode = TR::Node::createif(TR::ifacmpne, TR::Node::createWithSymRef(candidate->_node, TR::aload, 0, symRef), candidate->_node->duplicateTree(), targetBlock->getEntry());7494TR::TreeTop *comparisonTree = TR::TreeTop::create(comp(), comparisonNode, NULL, NULL);7495TR::Block *comparisonBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(comparisonNode, comp(), coldBlock->getFrequency())));7496comparisonBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());74977498TR::TreeTop *comparisonEntryTree = comparisonBlock->getEntry();7499TR::TreeTop *comparisonExitTree = comparisonBlock->getExit();7500comparisonEntryTree->join(comparisonTree);7501comparisonTree->join(comparisonExitTree);75027503comparisonExitTree->join(insertionPoint);75047505if (treeBeforeInsertionPoint)7506treeBeforeInsertionPoint->join(comparisonEntryTree);7507else7508comp()->setStartTree(comparisonEntryTree);75097510TR::Node *heapifiedObjAddrLoad = TR::Node::createWithSymRef(comparisonNode, TR::aload, 0, heapSymRef);75117512TR::TreeTop *storeTree = storeHeapifiedToTemp(candidate, heapifiedObjAddrLoad, symRef);75137514TR::Block *storeBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(storeTree->getNode(), comp(), coldBlock->getFrequency())));7515storeBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());75167517cfg->addEdge(comparisonBlock, storeBlock);7518cfg->addEdge(comparisonBlock, targetBlock);7519cfg->addEdge(storeBlock, targetBlock);7520if (targetBlock == coldBlock)7521{7522lastComparisonBlock = comparisonBlock;7523lastStoreBlock = storeBlock;7524}75257526TR::TreeTop *storeEntryTree = storeBlock->getEntry();7527TR::TreeTop *storeExitTree = storeBlock->getExit();75287529comparisonExitTree->join(storeEntryTree);7530storeEntryTree->join(storeTree);7531storeTree->join(storeExitTree);7532storeExitTree->join(insertionPoint);75337534insertionPoint = comparisonEntryTree;7535treeBeforeInsertionPoint = insertionPoint->getPrevTreeTop();7536targetBlock = comparisonBlock;7537}7538}75397540cfg->addEdge(heapAllocationBlock, targetBlock);7541cfg->addEdge(heapComparisonBlock, targetBlock);7542heapComparisonNode->setBranchDestination(targetBlock->getEntry());75437544for (auto pred = coldBlock->getPredecessors().begin(); pred != coldBlock->getPredecessors().end();)7545{7546TR::CFGNode *predNode = (*pred)->getFrom();7547/* might be removed, keep reference to next object in list */7548pred++;7549if ((useSelectOp && (predNode != heapComparisonBlock)7550&& (predNode != heapAllocationBlock))7551|| (!useSelectOp && (predNode != lastComparisonBlock)7552&& (predNode != lastStoreBlock))7553|| coldBlock->isCatchBlock())7554{7555TR::Block *predBlock = toBlock(predNode);7556if (!coldBlock->isCatchBlock() &&7557(predBlock->getLastRealTreeTop()->getNode()->getOpCode().isBranch() ||7558predBlock->getLastRealTreeTop()->getNode()->getOpCode().isSwitch()))7559{7560TR::TreeTop *lastTree = predBlock->getLastRealTreeTop();7561TR::Node *lastNode = lastTree->getNode();7562if (lastNode->getOpCode().isBranch() &&7563(lastNode->getBranchDestination() == coldBlock->getEntry()))7564predBlock->changeBranchDestination(heapComparisonBlock->getEntry(), cfg);7565else7566{7567if (lastNode->getOpCode().isSwitch())7568lastTree->adjustBranchOrSwitchTreeTop(comp(), coldBlock->getEntry(), heapComparisonBlock->getEntry());75697570cfg->addEdge(predNode, heapComparisonBlock);7571cfg->removeEdge(predNode, coldBlock);7572}7573}7574else7575{7576cfg->addEdge(predNode, heapComparisonBlock);7577cfg->removeEdge(predNode, coldBlock);7578}7579}7580}75817582if (coldBlock->isCatchBlock())7583{7584TR::TreeTop *coldBlockEntry = coldBlock->getEntry();7585TR::TreeTop *coldBlockExit = coldBlock->getExit();7586coldBlock->setEntry(heapComparisonEntryTree);7587coldBlock->setExit(heapComparisonExitTree);7588heapComparisonBlock->setEntry(coldBlockEntry);7589heapComparisonBlock->setExit(coldBlockExit);7590heapComparisonEntryTree->getNode()->setBlock(coldBlock);7591heapComparisonExitTree->getNode()->setBlock(coldBlock);7592coldBlockEntry->getNode()->setBlock(heapComparisonBlock);7593coldBlockExit->getNode()->setBlock(heapComparisonBlock);75947595TR_ScratchList<TR::CFGEdge> coldSuccessors(trMemory()), coldExceptionSuccessors(trMemory());75967597for (auto succ = coldBlock->getSuccessors().begin(); succ != coldBlock->getSuccessors().end(); ++succ)7598coldSuccessors.add(*succ);75997600for (auto succ = coldBlock->getExceptionSuccessors().begin(); succ != coldBlock->getExceptionSuccessors().end(); ++succ)7601coldExceptionSuccessors.add(*succ);76027603for (auto succ = heapComparisonBlock->getSuccessors().begin(); succ != heapComparisonBlock->getSuccessors().end();)7604{7605if (!coldBlock->hasSuccessor((*succ)->getTo()))7606cfg->addEdge(coldBlock, (*succ)->getTo());7607cfg->removeEdge(heapComparisonBlock, (*(succ++))->getTo());7608}76097610for (auto succ = heapComparisonBlock->getExceptionSuccessors().begin(); succ != heapComparisonBlock->getExceptionSuccessors().end();)7611{7612if (!coldBlock->hasExceptionSuccessor((*succ)->getTo()))7613cfg->addExceptionEdge(coldBlock, (*succ)->getTo());7614cfg->removeEdge(heapComparisonBlock, (*(succ++))->getTo());7615}7616ListIterator<TR::CFGEdge> bi;7617bi.set(&(coldSuccessors));7618for (TR::CFGEdge* succ = bi.getFirst(); succ != NULL; succ = bi.getNext())7619{7620if (!heapComparisonBlock->hasSuccessor(succ->getTo()))7621cfg->addEdge(heapComparisonBlock, succ->getTo());7622cfg->removeEdge(coldBlock, succ->getTo());7623}76247625bi.set(&(coldExceptionSuccessors));7626for (TR::CFGEdge* succ = bi.getFirst(); succ != NULL; succ = bi.getNext())7627{7628if (!heapComparisonBlock->hasExceptionSuccessor(succ->getTo()))7629cfg->addExceptionEdge(heapComparisonBlock, succ->getTo());7630cfg->removeEdge(coldBlock, succ->getTo());7631}76327633TR::TreeTop *firstTreeTop = coldBlockEntry->getNextTreeTop();7634TR::Node *firstTree = firstTreeTop->getNode();7635while (firstTree->getOpCodeValue() == TR::allocationFence)7636{7637firstTreeTop = firstTreeTop->getNextTreeTop();7638firstTree = firstTreeTop->getNode();7639}76407641bool recognizedCatch = true;7642if (!firstTree->getOpCode().isStoreDirect() ||7643!firstTree->getSymbol()->isAuto() ||7644!firstTree->getFirstChild()->getOpCode().hasSymbolReference() ||7645(firstTree->getFirstChild()->getSymbolReference() != comp()->getSymRefTab()->findOrCreateExcpSymbolRef()))7646recognizedCatch = false;76477648TR_ASSERT(recognizedCatch, "Catch block is not in recognized form for heapification");76497650if (recognizedCatch)7651{7652TR::Node *firstChild = firstTree->getFirstChild();7653TR::TreeTop *excTree = firstTreeTop;7654TR::TreeTop *prevExcTree = excTree->getPrevTreeTop();7655TR::TreeTop *nextExcTree = excTree->getNextTreeTop();7656TR::TreeTop *changedPrevExcTree = heapComparisonEntryTree;7657TR::TreeTop *changedNextExcTree = heapComparisonEntryTree->getNextTreeTop();765876597660TR::Node *dupFirstChild = firstChild->duplicateTree();7661firstTree->setAndIncChild(0, dupFirstChild);7662firstChild->setSymbolReference(firstTree->getSymbolReference());7663firstChild->decReferenceCount();76647665prevExcTree->join(nextExcTree);7666changedPrevExcTree->join(excTree);7667excTree->join(changedNextExcTree);7668}7669}7670}7671}767276737674TR::TreeTop *TR_EscapeAnalysis::storeHeapifiedToTemp(Candidate *candidate, TR::Node *value, TR::SymbolReference *symRef)7675{7676TR::Node *storeNode = TR::Node::createWithSymRef(TR::astore, 1, 1, value, symRef);7677TR::TreeTop *storeTree = TR::TreeTop::create(comp(), storeNode, NULL, NULL);76787679if (symRef->getSymbol()->holdsMonitoredObject())7680{7681storeNode->setLiveMonitorInitStore(true);7682}7683storeNode->setHeapificationStore(true);76847685if (!symRef->getSymbol()->isParm())7686{7687TR::Node *initStoreNode = TR::Node::createWithSymRef(TR::astore, 1, 1, TR::Node::aconst(candidate->_node, 0), symRef);7688if (symRef->getSymbol()->holdsMonitoredObject())7689initStoreNode->setLiveMonitorInitStore(true);7690TR::TreeTop *initStoreTree = TR::TreeTop::create(comp(), initStoreNode, NULL, NULL);7691TR::TreeTop *startTree = comp()->getStartTree();7692TR::TreeTop *nextToStart = startTree->getNextTreeTop();7693startTree->join(initStoreTree);7694initStoreTree->join(nextToStart);7695}76967697return storeTree;7698}769977007701bool TR_EscapeAnalysis::devirtualizeCallSites()7702{7703bool devirtualizedSomething = false;7704while (!_devirtualizedCallSites.isEmpty())7705{7706TR::TreeTop *callSite = _devirtualizedCallSites.popHead();77077708devirtualizedSomething = true;77097710TR::Node *callNode = callSite->getNode();7711if (callNode->getOpCode().isCheck() || callNode->getOpCodeValue() == TR::treetop)7712callNode = callNode->getFirstChild();7713TR::ResolvedMethodSymbol *calledMethod = callNode->getSymbol()->getResolvedMethodSymbol();7714if (calledMethod && (!(calledMethod->getResolvedMethod()->virtualMethodIsOverridden()) && callNode->getOpCode().isIndirect()))7715{7716TR::Block *block = callSite->getEnclosingBlock();7717TR::Node *guardNode = TR_VirtualGuard::createNonoverriddenGuard(TR_NonoverriddenGuard, comp(),7718callNode->getByteCodeInfo().getCallerIndex(),7719callNode,7720NULL,7721callNode->getSymbol()->getResolvedMethodSymbol(),false);7722dumpOptDetails(comp(), "new guard=%p added for callsite =%p (%p)\n",guardNode,callSite,callNode);7723//create empty tree and let the splitter fix the callNode and then duplicate it.7724TR::TreeTop *compareTree = TR::TreeTop::create(comp(), guardNode);7725TR::TreeTop *directCallTree = TR::TreeTop::create(comp());7726TR::TreeTop *coldTree = TR::TreeTop::create(comp());7727TR::Block * remainder = block->createConditionalBlocksBeforeTree(callSite, compareTree, coldTree, directCallTree, comp()->getFlowGraph(),false);77287729TR::Node * directCall = callNode->duplicateTree();77307731TR::Node * directCallTreeNode;77327733if (callSite->getNode()->getOpCode().hasSymbolReference())7734directCallTreeNode = TR::Node::createWithSymRef(callSite->getNode()->getOpCodeValue(), 1, 1, directCall, callSite->getNode()->getSymbolReference());7735else7736directCallTreeNode = TR::Node::create(callSite->getNode()->getOpCodeValue(), 1, directCall);77377738directCallTree->setNode(directCallTreeNode);77397740directCall->devirtualizeCall(directCallTree);774177427743TR::Node * coldCall = callNode->duplicateTree();77447745TR::Node * coldTreeNode;7746if (callSite->getNode()->getOpCode().hasSymbolReference())7747coldTreeNode = TR::Node::createWithSymRef(callSite->getNode()->getOpCodeValue(), 1, 1, coldCall, callSite->getNode()->getSymbolReference());7748else7749coldTreeNode = TR::Node::create(callSite->getNode()->getOpCodeValue(), 1, coldCall);7750coldTree->setNode(coldTreeNode);77517752if (callNode->getReferenceCount() >= 1)7753{7754//need to fixup references to the original call7755//store return value to temp (after direct call and after cold call)7756//load it back (instead of the references)77577758TR::DataType dt = callNode->getDataType();77597760TR::SymbolReference * temp1 = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dt);77617762TR::TreeTop *newStoreTree1 = TR::TreeTop::create(comp(), TR::Node::createStore(temp1, directCall));77637764newStoreTree1->join(directCallTree->getNextTreeTop());7765directCallTree->join(newStoreTree1);77667767//add store of return val after cold call7768TR::TreeTop *newStoreTree2 = TR::TreeTop::create(comp(), TR::Node::createStore(temp1, coldCall));7769newStoreTree2->join(coldTree->getNextTreeTop());7770coldTree->join(newStoreTree2);77717772//replace all references of the orig call in the remainder with load of return val7773callNode->removeAllChildren();7774TR::Node::recreate(callNode, comp()->il.opCodeForDirectLoad(dt));7775callNode->setNumChildren(0);7776callNode->setSymbolReference(temp1);7777}7778}7779}77807781return devirtualizedSomething;7782}778377847785778677877788bool TR_EscapeAnalysis::inlineCallSites()7789{7790scanForExtraCallsToInline();77917792bool inlinedSomething = false;7793while (!_inlineCallSites.isEmpty())7794{7795TR::TreeTop *treeTop = _inlineCallSites.popHead();7796TR::ResolvedMethodSymbol *methodSym = treeTop->getNode()->getFirstChild()->getSymbol()->getResolvedMethodSymbol();7797TR_ResolvedMethod *method = methodSym->getResolvedMethod();7798int32_t size = method->maxBytecodeIndex();77997800//The inliner might remove unreachable regions/blocks - check if the remaining calls to inline exist in the remaining trees.7801TR::TreeTop *entryTree = comp()->getStartTree();7802TR::TreeTop *exitTree = comp()->getMethodSymbol()->getLastTreeTop();7803TR::TreeTop *tt;7804for (tt = entryTree->getNextTreeTop(); tt != exitTree; tt = tt->getNextTreeTop())7805{7806if ((tt->getNode()->getNumChildren() > 0) &&7807tt->getNode()->getFirstChild() == treeTop->getNode()->getFirstChild())7808break;7809}7810if (tt == exitTree)7811{7812if (trace())7813traceMsg(comp(), "attempt to inline call %p failed because the block was removed\n",treeTop->getNode()->getFirstChild());7814continue;7815}78167817if (!alwaysWorthInlining(treeTop->getNode()->getFirstChild()))7818{7819// Check size thresholds so we don't inline the universe7820//7821if (getOptData()->_totalInlinedBytecodeSize + size > _maxInlinedBytecodeSize)7822{7823dumpOptDetails(comp(), "\nNOT inlining method %s into treetop at [%p], total inlined size = %d\n", method->signature(trMemory()), treeTop->getNode(), getOptData()->_totalInlinedBytecodeSize + size);7824return false;7825}7826}78277828if (trace())7829{7830/////printf("secs Inlining method %s in %s\n", method->signature(trMemory()), comp()->signature());7831traceMsg(comp(), "\nInlining method %s into treetop at [%p], total inlined size = %d\n", method->signature(trMemory()), treeTop->getNode(), getOptData()->_totalInlinedBytecodeSize+size);7832}78337834// Now inline the call7835//78367837bool toInlineFully = (treeTop->getNode()->getFirstChild()->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_lang_Integer_init) || (treeTop->getNode()->getFirstChild()->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_lang_Integer_valueOf);7838if (performTransformation(comp(), "%sAttempting to inline call [%p]%s\n", OPT_DETAILS, treeTop->getNode(), toInlineFully?" fully":""))7839{7840TR_InlineCall newInlineCall(optimizer(), this);7841newInlineCall.setSizeThreshold(size+100);7842bool inlineOK = newInlineCall.inlineCall(treeTop, 0, toInlineFully);78437844if (inlineOK)7845{7846getOptData()->_totalInlinedBytecodeSize += size;7847inlinedSomething = true;7848if (trace())7849traceMsg(comp(), "inlined succeeded\n");7850}7851}7852}7853return inlinedSomething;7854}78557856static bool alreadyGoingToInline(TR::Node *callNode, TR_ScratchList<TR::TreeTop> &listOfCallTrees)7857{7858// A given callNode can appear under multiple treetops, so we can't just7859// compare treetop identities if we want to make sure we don't try to inline7860// the same function twice.7861//7862ListIterator<TR::TreeTop> iter(&listOfCallTrees);7863for (TR::TreeTop *callTree = iter.getFirst(); callTree; callTree = iter.getNext())7864{7865if (callTree->getNode()->getFirstChild() == callNode)7866return true;7867}7868return false;7869}78707871void TR_EscapeAnalysis::scanForExtraCallsToInline()7872{7873if (!_repeatAnalysis)7874{7875// This is the last pass of EA. If there are any calls that we had7876// previously declined to inline to benefit EA, we longer need to7877// restrain ourselves, and can inline them now.7878//7879for (TR::TreeTop *tt = comp()->getStartTree(); tt; tt = tt->getNextTreeTop())7880{7881if ( tt->getNode()->getOpCodeValue() == TR::BBStart7882&& tt->getNode()->getBlock()->isCold())7883{7884// Don't bother inlining calls in cold blocks7885//7886tt = tt->getNode()->getBlock()->getExit();7887continue;7888}78897890TR::TreeTop *callTreeToInline = NULL;7891TR::Node *callNode = NULL;7892char *reason = "??";7893if ( tt->getNode()->getNumChildren() >= 17894&& tt->getNode()->getFirstChild()->getOpCode().isCall()7895&& tt->getNode()->getFirstChild()->getSymbol()->isResolvedMethod())7896{7897callNode = tt->getNode()->getFirstChild();7898if (!callNode->isTheVirtualCallNodeForAGuardedInlinedCall())7899{7900switch (callNode->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod())7901{7902case TR::java_lang_Integer_valueOf:7903callTreeToInline = tt;7904reason = "dememoization did not eliminate it";7905break;7906default:7907break;7908}7909}7910}7911if (callTreeToInline && !alreadyGoingToInline(callNode, _inlineCallSites))7912{7913_inlineCallSites.add(callTreeToInline);7914if (trace())7915traceMsg(comp(), "Consider inlining %s n%dn [%p] of %s because %s\n", callNode->getOpCode().getName(), callNode->getGlobalIndex(), callNode, callNode->getSymbolReference()->getName(comp()->getDebug()), reason);7916}7917}7918}7919}79207921bool TR_EscapeAnalysis::alwaysWorthInlining(TR::Node *callNode)7922{7923// If this gets any more sophisticated, it should probably start sharing7924// code with alwaysWorthInlining from the inliner.7925//7926TR::ResolvedMethodSymbol *callee = callNode->getSymbol()->getResolvedMethodSymbol();7927if (callee) switch (callee->getRecognizedMethod())7928{7929case TR::java_lang_Integer_valueOf:7930return true;7931default:7932break;7933}7934return false;7935}79367937//TR::TreeTop * TR_EscapeAnalysis::findCallSiteFixed(TR::TreeTop * virtualCallSite)7938bool TR_EscapeAnalysis::findCallSiteFixed(TR::TreeTop * virtualCallSite)7939{7940for (TR_CallSitesFixedMapper *cur = _fixedVirtualCallSites.getFirst(); cur; cur = cur->getNext())7941{7942if (cur->_vCallSite == virtualCallSite)7943{7944//return cur->_dCallSite;7945return true;7946}7947}79487949//return NULL;7950return false;7951}79527953795479557956void TR_EscapeAnalysis::printCandidates(char *title)7957{7958if (title)7959traceMsg(comp(), "\n%s\n", title);79607961int32_t index = 0;7962for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())7963{7964traceMsg(comp(), "Candidate %d:\n", index++);7965candidate->print();7966}7967}79687969static void printSymRefList(TR_ScratchList<TR::SymbolReference> *list, TR::Compilation *comp)7970{7971ListIterator<TR::SymbolReference> iter(list);7972char *sep = "";7973for (TR::SymbolReference *symRef = iter.getFirst(); symRef; symRef = iter.getNext())7974{7975traceMsg(comp, "%s#%d", sep, symRef->getReferenceNumber());7976sep = ",";7977}7978}79797980void Candidate::print()7981{7982traceMsg(comp(), " Node = %p, contiguous = %d, local = %d\n", _node, isContiguousAllocation(), isLocalAllocation());7983traceMsg(comp(), " Value numbers = {");7984for (uint32_t j = 0; j <_valueNumbers->size(); j++)7985traceMsg(comp(), " %d", _valueNumbers->element(j));7986traceMsg(comp(), " }\n");7987if (isLocalAllocation() && hasCallSites())7988{7989traceMsg(comp(), " Max inline depth = %d, inline bytecode size = %d\n", _maxInlineDepth, _inlineBytecodeSize);7990traceMsg(comp(), " Call sites to be inlined:\n");7991ListIterator<TR::TreeTop> callSites(getCallSites());7992for (TR::TreeTop *callSite = callSites.getFirst(); callSite; callSite = callSites.getNext())7993{7994TR::Node *node = callSite->getNode()->getFirstChild();7995traceMsg(comp(), " [%p] %s\n", node, node->getSymbol()->getMethodSymbol()->getMethod()->signature(trMemory()));7996}7997}7998if (_fields)7999{8000traceMsg(comp(), " %d fields:\n", _fields->size());8001for (int32_t i = 0; i < _fields->size(); i++)8002{8003FieldInfo &field = _fields->element(i);8004traceMsg(comp(), " %2d: offset=%-3d size=%-2d vectorElem=%-2d ",8005i, field._offset, field._size, field._vectorElem);8006if (field._symRef)8007traceMsg(comp(), "symRef=#%-4d ", field._symRef->getReferenceNumber());8008else8009traceMsg(comp(), "symRef=null ");8010traceMsg(comp(), "good={");8011printSymRefList(field._goodFieldSymrefs, comp());8012traceMsg(comp(), "} bad={");8013printSymRefList(field._badFieldSymrefs, comp());8014traceMsg(comp(), "}\n");8015}8016}8017}8018801980208021#if CHECK_MONITORS8022/* monitors */80238024// The following code is temporary fix for a problem with illegal monitor state exceptions.8025// Escape Analysis must be careful about removing monent/monexit trees if there is a possibility8026// of illegal monitor state. This pass (conservatively) checks if the monitor structure may be8027// illegal, returns true if it so.8028//8029// The real fix for this problem is to create the header-only object and let RedundantMonitorElimination8030// deal with it, but that fix will be added in the next release (post R20).8031//803280338034bool TR_MonitorStructureChecker::checkMonitorStructure(TR::CFG *cfg)8035{8036TR::StackMemoryRegion stackMemoryRegion(*trMemory());80378038_foundIllegalStructure = false;8039int32_t numBlocks = cfg->getNextNodeNumber();8040_seenNodes = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);8041_blockInfo = (int32_t *) trMemory()->allocateStackMemory(numBlocks * sizeof(int32_t), TR_Memory::EscapeAnalysis);8042memset(_blockInfo, -1, numBlocks * sizeof(int32_t));80438044TR::CFGNode *start = cfg->getStart();8045TR::CFGNode *end = cfg->getEnd();8046_blockInfo[start->getNumber()] = 0;8047_blockInfo[end ->getNumber()] = 0;80488049// Walk reverse post-order8050//8051TR_ScratchList<TR::CFGNode> stack;8052stack.add(start);8053while (!stack.isEmpty() && !_foundIllegalStructure)8054{8055TR::CFGNode *node = stack.popHead();80568057if (_seenNodes->isSet(node->getNumber()))8058continue;80598060if (node != start)8061{8062bool notDone = false;8063TR_PredecessorIterator pit(node);8064for (TR::CFGEdge *edge = pit.getFirst(); edge && !notDone; edge = pit.getNext())8065{8066TR::CFGNode *pred = edge->getFrom();8067if (!_seenNodes->isSet(pred->getNumber()))8068notDone = true;8069}80708071if (notDone)8072continue;8073}80748075_seenNodes->set(node->getNumber());8076processBlock(toBlock(node));80778078if (node != end)8079{8080TR_SuccessorIterator sit(node);8081for (TR::CFGEdge *edge = sit.getFirst(); edge; edge = sit.getNext())8082{8083TR::CFGNode *succ = edge->getTo();8084stack.add(succ);8085}8086}8087}80888089return _foundIllegalStructure;8090}80918092void TR_MonitorStructureChecker::processBlock(TR::Block *block)8093{8094TR::TreeTop *exitTT = block->getExit();80958096int32_t myInfo = _blockInfo[block->getNumber()];8097TR_ASSERT(myInfo != -1, "cfg walk failure"); // the cfg is a connected graph80988099for (TR::TreeTop *tt = block->getEntry();8100tt != exitTT && !_foundIllegalStructure;8101tt = tt->getNextTreeTop())8102{8103TR::Node *node = tt->getNode();81048105uint32_t exceptions = node->exceptionsRaised();8106if (exceptions)8107{8108for (auto edge = block->getExceptionSuccessors().begin(); edge != block->getExceptionSuccessors().end(); ++edge)8109{8110TR::Block *succ = toBlock((*edge)->getTo());8111if (succ->canCatchExceptions(exceptions))8112propagateInfoTo(succ, myInfo);8113}8114}81158116if (node->getOpCodeValue() == TR::treetop ||8117node->getOpCodeValue() == TR::NULLCHK)8118node = node->getFirstChild();81198120if (node->getOpCodeValue() == TR::monent)8121myInfo++;81228123if (node->getOpCodeValue() == TR::monexit)8124myInfo--;8125}81268127TR_SuccessorIterator sit(block);8128for (TR::CFGEdge *edge = sit.getFirst(); edge; edge = sit.getNext())8129{8130TR::CFGNode *succ = edge->getTo();8131propagateInfoTo(toBlock(succ), myInfo);8132}8133}81348135void TR_MonitorStructureChecker::propagateInfoTo(TR::Block *block, int32_t inInfo)8136{8137if (inInfo < 0)8138_foundIllegalStructure = true;8139else8140{8141int32_t thisInfo = _blockInfo[block->getNumber()];8142if (thisInfo == -1)8143_blockInfo[block->getNumber()] = inInfo;8144else8145if (inInfo != thisInfo)8146_foundIllegalStructure = true;8147}8148}8149#endif81508151static TR_DependentAllocations *getDependentAllocationsFor(Candidate *c, List<TR_DependentAllocations> *dependentAllocations)8152{8153ListIterator<TR_DependentAllocations> dependentIt(dependentAllocations);8154TR_DependentAllocations *info;8155for (info = dependentIt.getFirst(); info; info=dependentIt.getNext())8156{8157if (info->getAllocation() == c)8158return info;8159}8160return NULL;8161}8162816381648165static Candidate *getCandidate(TR_LinkHead<Candidate> *candidates, FlushCandidate *flushCandidate)8166{8167Candidate *candidate = flushCandidate->getCandidate();8168if (candidate || flushCandidate->getIsKnownToLackCandidate())8169{8170return candidate;8171}81728173for (candidate = candidates->getFirst(); candidate; candidate = candidate->getNext())8174{8175if (flushCandidate->getAllocation() == candidate->_node)8176{8177flushCandidate->setCandidate(candidate);8178break;8179}8180}81818182if (!candidate)8183{8184flushCandidate->setIsKnownToLackCandidate(true);8185}81868187return candidate;8188}818981908191TR_DataFlowAnalysis::Kind TR_FlowSensitiveEscapeAnalysis::getKind()8192{8193return FlowSensitiveEscapeAnalysis;8194}81958196TR_FlowSensitiveEscapeAnalysis *TR_FlowSensitiveEscapeAnalysis::asFlowSensitiveEscapeAnalysis()8197{8198return this;8199}82008201bool TR_FlowSensitiveEscapeAnalysis::supportsGenAndKillSets()8202{8203return false;8204}82058206int32_t TR_FlowSensitiveEscapeAnalysis::getNumberOfBits()8207{8208return _numAllocations;8209}821082118212bool TR_FlowSensitiveEscapeAnalysis::getCFGBackEdgesAndLoopEntryBlocks(TR_Structure *structure)8213{8214if (!structure->asBlock())8215{8216TR_RegionStructure *region = structure->asRegion();8217bool isLoop = region->isNaturalLoop();82188219//if (!isLoop &&8220// !region->isAcyclic())8221// return true;82228223if (isLoop)8224{8225collectCFGBackEdges(region->getEntry());8226_loopEntryBlocks->set(region->getEntry()->getNumber());8227if (trace())8228traceMsg(comp(), "Block numbered %d is loop entry\n", region->getEntry()->getNumber());8229}82308231TR_StructureSubGraphNode *subNode;8232TR_Structure *subStruct = NULL;8233TR_RegionStructure::Cursor si(*region);8234for (subNode = si.getCurrent(); subNode != NULL; subNode = si.getNext())8235{8236subStruct = subNode->getStructure();8237if (getCFGBackEdgesAndLoopEntryBlocks(subStruct))8238return true;8239}8240}8241else8242{8243if (structure->asBlock()->getBlock()->isCatchBlock())8244_catchBlocks->set(structure->getNumber());8245}82468247return false;8248}8249825082518252void TR_FlowSensitiveEscapeAnalysis::collectCFGBackEdges(TR_StructureSubGraphNode *loopEntry)8253{8254for (auto edge = loopEntry->getPredecessors().begin(); edge != loopEntry->getPredecessors().end(); ++edge)8255{8256TR_Structure *pred = toStructureSubGraphNode((*edge)->getFrom())->getStructure();8257pred->collectCFGEdgesTo(loopEntry->getNumber(), &_cfgBackEdges);8258}8259}826082618262TR_FlowSensitiveEscapeAnalysis::TR_FlowSensitiveEscapeAnalysis(TR::Compilation *comp, TR::Optimizer *optimizer, TR_Structure *rootStructure, TR_EscapeAnalysis *escapeAnalysis)8263: TR_IntersectionBitVectorAnalysis(comp, comp->getFlowGraph(), optimizer, escapeAnalysis->trace()),8264_cfgBackEdges(comp->trMemory()),8265_flushEdges(comp->trMemory()),8266_splitBlocks(comp->trMemory())8267{8268if (trace())8269traceMsg(comp, "Starting FlowSensitiveEscapeAnalysis analysis\n");82708271if (comp->getVisitCount() > 8000)8272comp->resetVisitCounts(1);82738274// Find the number of allocations and assign an index to each8275//8276_escapeAnalysis = escapeAnalysis;8277_candidates = &(escapeAnalysis->_candidates);8278_numAllocations = 0;8279_newlyAllocatedObjectWasLocked = false;8280_cfgBackEdges.deleteAll();8281_flushEdges.deleteAll();8282_splitBlocks.deleteAll();82838284_flushCandidates = new (trStackMemory()) TR_LinkHead<FlushCandidate>;8285_flushCandidates->setFirst(NULL);82868287Candidate *candidate, *next;8288for (candidate = _candidates->getFirst(); candidate; candidate = next)8289{8290next = candidate->getNext();8291if (trace())8292traceMsg(comp, "Allocation node %p is represented by bit position %d\n", candidate->_node, _numAllocations);8293candidate->_index = _numAllocations++;8294}82958296if (trace())8297traceMsg(comp, "_numAllocations = %d\n", _numAllocations);82988299if (_numAllocations == 0)8300return; // Nothing to do if there are no allocations83018302// Allocate the block info before setting the stack mark - it will be used by8303// the caller8304//8305initializeBlockInfo();83068307// After this point all stack allocation will die when the function returns8308TR::StackMemoryRegion stackMemoryRegion(*trMemory());83098310if (!performAnalysis(rootStructure, false))8311{8312return;8313}83148315int32_t i;8316if (trace())8317{8318for (i = 1; i < _numberOfNodes; ++i)8319{8320if (_blockAnalysisInfo[i])8321{8322traceMsg(comp, "\nSolution for block_%d: ",i);8323_blockAnalysisInfo[i]->print(comp);8324}8325}8326traceMsg(comp, "\nEnding FlowSensitiveEscapeAnalysis analysis\n");8327}83288329int32_t blockNum = -1;8330TR::TreeTop *treeTop;8331TR_BitVector *blockInfo = NULL;8332for (treeTop = comp->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())8333{8334TR::Node *node = treeTop->getNode();8335if (node->getOpCodeValue() == TR::BBStart)8336{8337blockNum = node->getBlock()->getNumber();8338blockInfo = _blockAnalysisInfo[blockNum];83398340//if (_blocksWithFlushes->get(blockNum) &&8341// blockInfo &&8342// !blockInfo->isEmpty())8343// {8344// printf("%d allocation(s) reached allocation in block_%d in method %s\n", blockInfo->elementCount(), blockNum, comp->signature();8345// blockInfo->print(comp);8346// fflush(stdout);8347// }83488349continue;8350}83518352if (node->getOpCode().isNullCheck() ||8353node->getOpCode().isResolveCheck() ||8354(node->getOpCodeValue() == TR::treetop))8355node = node->getFirstChild();83568357if ((node->getOpCodeValue() == TR::monent) || (node->getOpCodeValue() == TR::monexit))8358{8359Candidate *candidate;8360for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())8361{8362if (escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node) == escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()))8363{8364if (blockInfo &&8365blockInfo->get(candidate->_index) &&8366performTransformation(comp, "%sMark monitor node [%p] as a local object monitor (flow sensitive escape analysis)\n",OPT_DETAILS, node))8367{8368//if (!node->isSyncMethodMonitor())8369{8370node->setLocalObjectMonitor(true);8371optimizer->setRequestOptimization(OMR::redundantMonitorElimination);8372//printf("Eliminating monitor in %s\n", comp->signature());8373}8374//else8375// {8376//printf("Removing monitor from %s\n", comp->signature());8377// if (treeTop->getNode() == node)8378// TR::Node::recreate(node, TR::treetop);8379// else8380// TR::Node::recreate(node, TR::PassThrough);8381// }8382}8383break;8384}8385}8386}8387}83888389if (_flushCandidates->isEmpty())8390{8391return;8392}83938394if (trace())8395traceMsg(comp, "\nStarting local flush elimination \n");83968397TR_LocalFlushElimination localFlushElimination(_escapeAnalysis, _numAllocations);8398localFlushElimination.perform();83998400if (trace())8401traceMsg(comp, "\nStarting global flush elimination \n");84028403if (comp->getFlowGraph()->getStructure()->markStructuresWithImproperRegions())8404{8405return;8406}84078408int32_t numBlocks = comp->getFlowGraph()->getNextNodeNumber();8409_successorInfo = (TR_BitVector **) trMemory()->allocateStackMemory(numBlocks* sizeof(TR_BitVector *));8410memset(_successorInfo, 0, numBlocks * sizeof(TR_BitVector *));8411_predecessorInfo = (TR_BitVector **) trMemory()->allocateStackMemory(numBlocks* sizeof(TR_BitVector *));8412memset(_predecessorInfo, 0, numBlocks * sizeof(TR_BitVector *));8413for (TR::CFGNode *node = comp->getFlowGraph()->getFirstNode(); node; node = node->getNext())8414{8415_successorInfo[node->getNumber()] = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);8416_predecessorInfo[node->getNumber()] = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);8417}84188419TR_BitVector *visitedNodes = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);8420_loopEntryBlocks = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);8421_catchBlocks = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);8422getCFGBackEdgesAndLoopEntryBlocks(comp->getFlowGraph()->getStructure());8423TR::MonitorElimination::collectPredsAndSuccs(comp->getFlowGraph()->getStart(), visitedNodes, _predecessorInfo, _successorInfo, &_cfgBackEdges, _loopEntryBlocks, comp);84248425_scratch2 = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);84268427_scratch = visitedNodes;8428_scratch->empty();8429//_scratch2 = _loopEntryBlocks;8430*_scratch2 = *_loopEntryBlocks;8431*_scratch2 |= *_catchBlocks;8432//_scratch2->empty();84338434TR_BitVector *movedToBlocks = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);84358436FlushCandidate *flushCandidate;8437for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())8438{8439candidate = getCandidate(_candidates, flushCandidate);84408441if (!candidate)8442continue;844384448445//TR::Block *block = candidate->_block;8446//int32_t blockNum = block->getNumber();8447int32_t blockNum = flushCandidate->getBlockNum();84488449if (trace())8450traceMsg(comp, "\nConsidering Flush for allocation %p (index %d) in block_%d\n", candidate->_node, candidate->_index, blockNum);84518452TR_BitVector *successors = _successorInfo[blockNum];84538454if (trace())8455{8456traceMsg(comp, "Successors : \n");8457successors->print(comp);8458traceMsg(comp, "\n");8459}84608461TR_BitVectorIterator succIt(*successors);8462while (succIt.hasMoreElements())8463{8464int32_t nextSucc = succIt.getNextElement();8465TR_BitVector *succInfo = _blockAnalysisInfo[nextSucc];84668467*_scratch2 = *_loopEntryBlocks;8468*_scratch2 |= *_catchBlocks;84698470if (trace())8471traceMsg(comp, "Successor %d being examined\n", nextSucc);84728473if ((_blocksWithFlushes->get(nextSucc) ||8474_blocksWithSyncs->get(nextSucc)) &&8475succInfo &&8476succInfo->get(candidate->_index))8477{8478if (trace())8479traceMsg(comp, "Current allocation %d reaches successor %d\n", candidate->_index, nextSucc);84808481TR_BitVector *preds = _predecessorInfo[nextSucc];84828483if (trace())8484{8485traceMsg(comp, "Predecessors of next succ %d : \n", nextSucc);8486preds->print(comp);8487traceMsg(comp, "\n");8488}84898490*_scratch = *preds;8491*_scratch &= *successors;84928493if (_scratch2->get(nextSucc))8494continue;84958496*_scratch2 &= *_scratch;8497if (!_scratch2->isEmpty())8498continue;84998500_scratch->set(blockNum);85018502bool postDominated = true;8503TR::CFG *cfg = comp->getFlowGraph();8504TR::CFGNode *nextNode;8505for (nextNode = cfg->getFirstNode(); nextNode; nextNode = nextNode->getNext())8506{8507if (_scratch->get(nextNode->getNumber()))8508{8509for (auto succ = nextNode->getSuccessors().begin(); succ != nextNode->getSuccessors().end(); ++succ)8510{8511if (trace())8512traceMsg(comp, "Checking succ edge from %d to %d\n", nextNode->getNumber(), (*succ)->getTo()->getNumber());85138514if (!_scratch->get((*succ)->getTo()->getNumber()) &&8515((*succ)->getTo()->getNumber() != nextSucc))8516{8517postDominated = false;8518_flushEdges.add(new (trStackMemory()) TR_CFGEdgeAllocationPair(*succ, candidate));8519if (trace())8520traceMsg(comp, "Adding flush edge from %d to %d\n", nextNode->getNumber(), (*succ)->getTo()->getNumber());8521}8522}8523}8524}85258526if (trace())8527{8528traceMsg(comp, "Scratch : \n");8529_scratch->print(comp);8530traceMsg(comp, "\n");8531}85328533//if (postDominated)8534{8535if (trace())8536traceMsg(comp, "Current allocation %d is post dominated by allocation in successor %d\n", candidate->_index, nextSucc);85378538Candidate *succCandidate = NULL;8539FlushCandidate *succFlushCandidate = NULL;8540if (!_blocksWithSyncs->get(nextSucc))8541{8542for (succFlushCandidate = _flushCandidates->getFirst(); succFlushCandidate; succFlushCandidate = succFlushCandidate->getNext())8543//for (succCandidate = _candidates->getFirst(); succCandidate; succCandidate = succCandidate->getNext())8544{8545succCandidate = getCandidate(_candidates, succFlushCandidate);8546if (!succCandidate)8547continue;85488549//TR::Block *succBlock = succCandidate->_block;8550int32_t succBlockNum = succFlushCandidate->getBlockNum();85518552//if (trace())8553// traceMsg(comp, "succCandidate %p succCandidate num %d succCandidate Flush reqd %d succBlockNum %d\n", succCandidate, succCandidate->_index, succCandidate->_flushRequired, succBlockNum);85548555if ((succBlockNum == nextSucc) &&8556succCandidate->_flushRequired)8557{8558bool nextAllocCanReach = true;85598560ListIterator<Candidate> candIt(&candidate->_flushMovedFrom);8561for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())8562{8563if (!succInfo->get(dependentCandidate->_index))8564{8565nextAllocCanReach = false;8566break;8567}8568}85698570//if (trace())8571// traceMsg(comp, "succ candidate %p nextAllocCanReach %d\n", succCandidate, nextAllocCanReach);85728573if (nextAllocCanReach)8574{8575if (succCandidate != candidate)8576{8577succCandidate->_flushMovedFrom.add(candidate);8578ListIterator<Candidate> candIt(&candidate->_flushMovedFrom);8579for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())8580succCandidate->_flushMovedFrom.add(candidate);8581}8582break;8583}8584}8585}8586}85878588//if (trace())8589// traceMsg(comp, "succCandidate %p _blocksWithSyncs bit %d\n", succCandidate, _blocksWithSyncs->get(nextSucc));85908591if (_blocksWithSyncs->get(nextSucc) ||8592succCandidate)8593{8594movedToBlocks->set(nextSucc);8595candidate->_flushRequired = false;8596TR::TreeTop *flushTree = flushCandidate->getFlush();8597TR::TreeTop *prevTree = flushTree->getPrevTreeTop();8598TR::TreeTop *nextTree = flushTree->getNextTreeTop();8599if ((prevTree->getNextTreeTop() == flushTree) &&8600(nextTree->getPrevTreeTop() == flushTree))8601{8602if (flushTree->getNode()->getOpCodeValue() == TR::allocationFence)8603{8604flushTree->getNode()->setOmitSync(true);8605flushTree->getNode()->setAllocation(NULL);8606}8607//prevTree->join(nextTree);8608}86098610//if (trace())8611// {8612// traceMsg(comp, "0reaching candidate %p index %d does not need Flush\n", candidate, candidate->_index);8613// }86148615if (trace())8616{8617if (succCandidate)8618{8619traceMsg(comp, "Flush for current allocation %d is post dominated by (and moved to) Flush for allocation %d\n", candidate->_index, succCandidate->_index);8620//printf("Moved flush for allocation %p in block_%d to allocation %p in succ block_%d in method %s\n", candidate->_node, blockNum, succCandidate->_node, nextSucc, comp->signature());8621}8622else8623{8624traceMsg(comp, "Flush for current allocation %d is post dominated by (and moved to) real sync for in succ %d\n", candidate->_index, nextSucc);8625//printf("Moved flush for allocation %p in block_%d to real sync in succ %d in method %s\n", candidate->_node, blockNum, nextSucc, comp->signature());8626}8627fflush(stdout);8628}8629//break;8630}8631}8632}8633}86348635ListElement<TR_CFGEdgeAllocationPair> *listElem;8636ListElement<TR_CFGEdgeAllocationPair> *nextListElem = NULL, *prevListElem = NULL;8637TR_CFGEdgeAllocationPair *pair = NULL;8638for (listElem = _flushEdges.getListHead(); listElem != NULL;)8639{8640nextListElem = listElem->getNextElement();8641TR_CFGEdgeAllocationPair *pair = listElem->getData();8642if (trace())8643{8644traceMsg(comp, "Processing flush edge from %d to %d\n", pair->getEdge()->getFrom()->getNumber(), pair->getEdge()->getTo()->getNumber());8645traceMsg(comp, "Processing flush alloc %p vs candidate %p\n", pair->getAllocation(), candidate);8646}86478648if (pair->getAllocation() == candidate)8649{8650bool edgeSplitRequired = true;8651int32_t toNum = pair->getEdge()->getTo()->getNumber();8652if (movedToBlocks->get(toNum))8653edgeSplitRequired = false;86548655if (!edgeSplitRequired)8656{8657if (prevListElem)8658prevListElem->setNextElement(nextListElem);8659else8660_flushEdges.setListHead(nextListElem);8661listElem = nextListElem;8662continue;8663}8664}86658666prevListElem = listElem;8667listElem = nextListElem;8668}8669}867086718672ListIterator<TR_CFGEdgeAllocationPair> pairIt(&_flushEdges);8673for (TR_CFGEdgeAllocationPair *pair = pairIt.getFirst(); pair; pair = pairIt.getNext())8674{8675TR::CFGNode *to = pair->getEdge()->getTo();8676TR::Block *splitBlock = NULL;8677if (to == comp->getFlowGraph()->getEnd())8678{8679splitBlock = toBlock(pair->getEdge()->getFrom());8680}8681else if ((to->getPredecessors().size() == 1))8682{8683splitBlock = toBlock(to);8684if (trace())8685{8686traceMsg(comp, "For edge %d->%d adding Flush in block_%d for candidate %p index %d\n", pair->getEdge()->getFrom()->getNumber(), pair->getEdge()->getTo()->getNumber(), splitBlock->getNumber(), pair->getAllocation(), pair->getAllocation()->_index);8687//printf("For edge %d->%d adding Flush in block_%d for candidate %p index %d\n", pair->getEdge()->getFrom()->getNumber(), pair->getEdge()->getTo()->getNumber(), splitBlock->getNumber(), pair->getAllocation(), pair->getAllocation()->_index);8688}8689}8690else8691{8692splitBlock = findOrSplitEdge(toBlock(pair->getEdge()->getFrom()), toBlock(to));8693if (trace())8694{8695traceMsg(comp, "Splitting edge %d->%d with block_%d for candidate %p index %d\n", pair->getEdge()->getFrom()->getNumber(), pair->getEdge()->getTo()->getNumber(), splitBlock->getNumber(), pair->getAllocation(), pair->getAllocation()->_index);8696//printf("Splitting edge %d->%d with block_%d for candidate %p index %d\n", pair->getEdge()->getFrom()->getNumber(), pair->getEdge()->getTo()->getNumber(), splitBlock->getNumber(), pair->getAllocation(), pair->getAllocation()->_index);8697}8698}86998700TR::Node *firstNode = splitBlock->getFirstRealTreeTop()->getNode();8701if (firstNode->getOpCodeValue() == TR::allocationFence)8702firstNode->setAllocation(NULL);8703else8704splitBlock->prepend(TR::TreeTop::create(comp, TR::Node::createAllocationFence(pair->getAllocation()->_node, pair->getAllocation()->_node), NULL, NULL));8705}87068707for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())8708{8709candidate = getCandidate(_candidates, flushCandidate);87108711if (!candidate)8712continue;87138714if (!candidate->_flushMovedFrom.isEmpty())8715{8716flushCandidate->getFlush()->getNode()->setAllocation(NULL);8717}8718}8719}87208721bool TR_FlowSensitiveEscapeAnalysis::postInitializationProcessing()8722{8723_blocksWithSyncs = new (trStackMemory()) TR_BitVector(_numberOfNodes, trMemory(), stackAlloc);8724int32_t blockNum = -1;8725TR::TreeTop *treeTop = NULL;8726for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())8727{8728TR::Node *node = treeTop->getNode();8729if (node->getOpCodeValue() == TR::BBStart)8730{8731blockNum = node->getBlock()->getNumber();8732continue;8733}87348735if ((node->getOpCodeValue() == TR::allocationFence) &&8736node->getAllocation())8737{8738FlushCandidate *candidate = new (trStackMemory()) FlushCandidate(treeTop, node->getAllocation(), blockNum);8739_flushCandidates->add(candidate);8740}87418742if (node->getOpCode().isNullCheck() ||8743node->getOpCode().isResolveCheck() ||8744(node->getOpCodeValue() == TR::treetop))8745node = node->getFirstChild();87468747if (node->getOpCodeValue() == TR::monent)8748{8749Candidate *candidate;8750for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())8751{8752if (_escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()) == _escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node))8753_newlyAllocatedObjectWasLocked = true;8754}8755}8756else if ((node->getOpCodeValue() == TR::monexit) ||8757(node->getOpCode().isCall() &&8758!node->hasUnresolvedSymbolReference() &&8759node->getSymbolReference()->getSymbol()->castToMethodSymbol()->isSynchronised()))8760{8761bool syncPresent = true;8762if (node->getOpCodeValue() == TR::monexit)8763{8764Candidate *candidate;8765for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())8766{8767if (_escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()) == _escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node))8768{8769syncPresent = false;8770break;8771}8772}8773}87748775if (syncPresent)8776_blocksWithSyncs->set(blockNum);8777}8778}87798780int32_t i;87818782if (!_newlyAllocatedObjectWasLocked &&8783_flushCandidates->isEmpty())8784{8785return false;8786}87878788_blocksWithFlushes = new (trStackMemory()) TR_BitVector(_numberOfNodes, trMemory(), stackAlloc);8789FlushCandidate *flushCandidate;8790for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())8791_blocksWithFlushes->set(flushCandidate->getBlockNum());87928793//_blocksThatNeedFlush = new (trStackMemory()) TR_BitVector(_numberOfNodes, trMemory(), stackAlloc, growable);8794return true;8795}879687978798TR::Block *TR_FlowSensitiveEscapeAnalysis::findOrSplitEdge(TR::Block *from, TR::Block *to)8799{8800TR::Block *splitBlock = NULL;8801if (!from->hasSuccessor(to))8802{8803for (auto edge2 = to->getPredecessors().begin(); edge2 != to->getPredecessors().end(); ++edge2)8804{8805if (_splitBlocks.find((*edge2)->getFrom()) &&8806from->hasSuccessor((*edge2)->getFrom()))8807{8808splitBlock = toBlock((*edge2)->getFrom());8809break;8810}8811}8812}8813else8814{8815splitBlock = from->splitEdge(from, to, comp());8816_splitBlocks.add(splitBlock);8817}88188819return splitBlock;8820}88218822882388248825void TR_FlowSensitiveEscapeAnalysis::analyzeTreeTopsInBlockStructure(TR_BlockStructure *blockStructure)8826{8827TR::Block *block = blockStructure->getBlock();8828if ((block == comp()->getFlowGraph()->getStart()) ||8829(block == comp()->getFlowGraph()->getEnd()))8830return;88318832int32_t blockNum = block->getNumber();8833bool seenException = false;88348835comp()->incVisitCount(); //@TODO: slightly untrivial as it requires either a change to API (i.e. analyzeNode)8836//or an extra field needs to be declared in TR_FlowSensitiveEscapeAnalysis8837//so let's leave this use as is for the next iteration8838TR::TreeTop *lastTree = block->getExit()->getNextTreeTop();8839for (TR::TreeTop *treeTop = block->getEntry(); treeTop != lastTree; treeTop = treeTop->getNextTreeTop())8840{8841TR::Node *node = treeTop->getNode();88428843if (node->getOpCodeValue() == TR::BBStart)8844continue;88458846#if DEBUG8847if (node->getOpCodeValue() == TR::BBEnd && trace())8848{8849traceMsg(comp(), "\n Block %d:\n", blockNum);8850traceMsg(comp(), " Normal set ");8851if (_regularInfo)8852_regularInfo->print(comp());8853else8854traceMsg(comp(), "{}");8855traceMsg(comp(), "\n Exception set ");8856if (_exceptionInfo)8857_exceptionInfo->print(comp());8858else8859traceMsg(comp(), "{}");8860}8861#endif88628863analyzeNode(node, seenException, blockNum, NULL);88648865if (!seenException && treeHasChecks(treeTop))8866seenException = true;8867}8868copyFromInto(_regularInfo, _blockAnalysisInfo[blockStructure->getNumber()]);8869}887088718872void TR_FlowSensitiveEscapeAnalysis::analyzeNode(TR::Node *node, bool seenException, int32_t blockNum, TR::Node *parent)8873{8874// Update gen and kill info for nodes in this subtree8875//8876int32_t i;88778878if (node->getVisitCount() == comp()->getVisitCount())8879return;8880node->setVisitCount(comp()->getVisitCount());88818882// Process the children first8883//8884for (i = node->getNumChildren()-1; i >= 0; --i)8885{8886analyzeNode(node->getChild(i), seenException, blockNum, node);8887}888888898890TR::ILOpCode &opCode = node->getOpCode();8891if (opCode.hasSymbolReference())8892{8893TR::SymbolReference *symReference = node->getSymbolReference();8894if (symReference->getSymbol()->isVolatile())8895_blocksWithSyncs->set(blockNum);8896}88978898//traceMsg(comp(), "Node %p is being examined\n", node);88998900TR_EscapeAnalysis *escapeAnalysis = _escapeAnalysis;8901if (!node->getOpCode().isCall())8902{8903int32_t valueNumber = 0;8904Candidate *candidate = NULL;8905TR::Node *child = NULL;8906TR_DependentAllocations *dependencies = NULL;89078908if ((node->getOpCodeValue() == TR::areturn) ||8909(node->getOpCodeValue() == TR::athrow))8910child = node->getFirstChild();8911else if (node->getOpCode().isStoreIndirect())8912{8913child = node->getSecondChild();89148915TR::Node *base = node->getFirstChild();8916int32_t baseValueNumber = escapeAnalysis->_valueNumberInfo->getValueNumber(base);8917Candidate *candidate;8918for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())8919{8920if (escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node) == baseValueNumber)8921{8922if (_regularInfo->get(candidate->_index))8923{8924//child = NULL;8925dependencies = getDependentAllocationsFor(candidate, &(_escapeAnalysis->_dependentAllocations));8926if (!dependencies)8927{8928dependencies = new (trStackMemory()) TR_DependentAllocations(candidate, 0, trMemory());8929_escapeAnalysis->_dependentAllocations.add(dependencies);8930}8931}8932break;8933}8934}8935}8936else if (node->getOpCode().isStore() &&8937node->getSymbolReference()->getSymbol()->isStatic())8938child = node->getFirstChild();89398940if (child)8941{8942// If we are in a called method, returning a candidate to the caller8943// escapes, since we don't track what happens to the returned value.8944//8945valueNumber = escapeAnalysis->_valueNumberInfo->getValueNumber(child);8946}89478948for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())8949{8950if (child &&8951escapeAnalysis->usesValueNumber(candidate, valueNumber))8952{8953if (!dependencies)8954{8955_regularInfo->reset(candidate->_index);8956if (seenException)8957_exceptionInfo->reset(candidate->_index);89588959TR_DependentAllocations *deps = getDependentAllocationsFor(candidate, &(escapeAnalysis->_dependentAllocations));8960if (deps)8961{8962ListIterator<Candidate> candIt(deps->getDependentAllocations());8963for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())8964{8965_regularInfo->reset(dependentCandidate->_index);8966if (seenException)8967_exceptionInfo->reset(dependentCandidate->_index);8968}8969}8970}8971else8972dependencies->addDependentAllocation(candidate);8973}89748975if (node == candidate->_node)8976{8977_regularInfo->set(candidate->_index);8978if (!seenException)8979_exceptionInfo->set(candidate->_index);8980}8981}8982}8983else8984{8985int32_t firstArgIndex = node->getFirstArgumentIndex();8986for (int32_t arg = firstArgIndex; arg < node->getNumChildren(); arg++)8987{8988TR::Node *child = node->getChild(arg);8989int32_t valueNumber = escapeAnalysis->_valueNumberInfo->getValueNumber(child);8990Candidate *candidate;8991for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())8992{8993if (escapeAnalysis->usesValueNumber(candidate, valueNumber))8994{8995_regularInfo->reset(candidate->_index);8996if (seenException)8997_exceptionInfo->reset(candidate->_index);89988999TR_DependentAllocations *deps = getDependentAllocationsFor(candidate, &(escapeAnalysis->_dependentAllocations));9000if (deps)9001{9002ListIterator<Candidate> candIt(deps->getDependentAllocations());9003for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())9004{9005_regularInfo->reset(dependentCandidate->_index);9006if (seenException)9007_exceptionInfo->reset(dependentCandidate->_index);9008}9009}9010}9011}9012}9013}9014}9015901690179018TR_LocalFlushElimination::TR_LocalFlushElimination(TR_EscapeAnalysis *escapeAnalysis, int32_t numAllocations)9019: _dependentAllocations(escapeAnalysis->trMemory())9020{9021_escapeAnalysis = escapeAnalysis;9022_numAllocations = numAllocations;9023}90249025int32_t TR_LocalFlushElimination::perform()9026{9027if (_escapeAnalysis)9028_candidates = &(_escapeAnalysis->_candidates);9029else9030{9031_candidates = new (trStackMemory()) TR_LinkHead<Candidate>;9032_numAllocations = -1;9033}90349035_flushCandidates = new (trStackMemory()) TR_LinkHead<FlushCandidate>;9036_flushCandidates->setFirst(NULL);90379038TR::NodeChecklist visited(comp());9039TR::TreeTop *treeTop;9040TR::Block *block = NULL;9041_dependentAllocations.deleteAll();90429043if (_numAllocations < 0)9044{9045_numAllocations = 0;9046for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextRealTreeTop())9047{9048// Get information about this block9049//9050TR::Node *node = treeTop->getNode();9051if (node->getOpCodeValue() == TR::BBStart)9052block = node->getBlock();90539054if ((node->getOpCodeValue() == TR::treetop) &&9055((node->getFirstChild()->getOpCodeValue() == TR::New) ||9056(node->getFirstChild()->getOpCodeValue() == TR::newarray) ||9057(node->getFirstChild()->getOpCodeValue() == TR::anewarray)))9058{9059Candidate *candidate = new (trStackMemory()) Candidate(node, treeTop, block, -1, NULL, comp());9060_candidates->add(candidate);9061candidate->_index = _numAllocations++;9062}9063}9064}90659066_allocationInfo = new (trStackMemory()) TR_BitVector(_numAllocations, trMemory(), stackAlloc);9067_temp = new (trStackMemory()) TR_BitVector(_numAllocations, trMemory(), stackAlloc);90689069for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextRealTreeTop())9070{9071// Get information about this block9072//9073TR::Node *node = treeTop->getNode();9074if (node->getOpCodeValue() == TR::BBStart)9075block = node->getBlock();90769077if ((node->getOpCodeValue() == TR::allocationFence) &&9078node->getAllocation())9079{9080FlushCandidate *candidate = new (trStackMemory()) FlushCandidate(treeTop, node->getAllocation(), block->getNumber());9081_flushCandidates->add(candidate);9082}9083}90849085// Process each block in treetop order9086//9087for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextRealTreeTop())9088{9089// Get information about this block9090//9091TR::Node *node = treeTop->getNode();9092if (node->getOpCodeValue() == TR::BBStart)9093{9094block = node->getBlock();9095_allocationInfo->empty();9096}90979098examineNode(node, visited);9099}91009101FlushCandidate *flushCandidate;9102for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())9103{9104Candidate *candidate = getCandidate(_candidates, flushCandidate);91059106if (!candidate)9107continue;91089109if (!candidate->_flushMovedFrom.isEmpty())9110{9111flushCandidate->getFlush()->getNode()->setAllocation(NULL);9112}9113}91149115return 1; // actual cost9116}911791189119bool TR_LocalFlushElimination::examineNode(TR::Node *node, TR::NodeChecklist& visited)9120{9121if (visited.contains(node))9122return true;9123visited.add(node);91249125TR::ILOpCode &opCode = node->getOpCode();91269127if (!opCode.isCall())9128{9129int32_t valueNumber = -1;9130Candidate *candidate;9131TR::Node *child = NULL;9132TR_DependentAllocations *dependencies = NULL;9133if ((node->getOpCodeValue() == TR::areturn) ||9134(node->getOpCodeValue() == TR::athrow))9135child = node->getFirstChild();9136else if (node->getOpCode().isStoreIndirect())9137{9138child = node->getSecondChild();91399140TR::Node *base = node->getFirstChild();91419142//if (_escapeAnalysis)9143{9144int32_t baseValueNumber = -1;9145if (_escapeAnalysis)9146baseValueNumber = _escapeAnalysis->_valueNumberInfo->getValueNumber(base);9147Candidate *candidate;9148for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())9149{9150if ((_escapeAnalysis &&9151(_escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node) == baseValueNumber)) ||9152!_escapeAnalysis)9153{9154if (_allocationInfo->get(candidate->_index))9155{9156TR_ScratchList<TR_DependentAllocations> *list = NULL;9157if (_escapeAnalysis)9158list = &(_escapeAnalysis->_dependentAllocations);9159else9160list = &_dependentAllocations;9161dependencies = getDependentAllocationsFor(candidate, list);9162if (!dependencies)9163{9164dependencies = new (trStackMemory()) TR_DependentAllocations(candidate, 0, trMemory());9165list->add(dependencies);9166}9167}9168//child = NULL;9169break;9170}9171}9172}9173}9174else if (node->getOpCode().isStore() &&9175node->getSymbolReference()->getSymbol()->isStatic())9176child = node->getFirstChild();917791789179if (_escapeAnalysis)9180{9181if (child)9182{9183// If we are in a called method, returning a candidate to the caller9184// escapes, since we don't track what happens to the returned value.9185//9186valueNumber = _escapeAnalysis->_valueNumberInfo->getValueNumber(child);9187}9188}91899190bool nodeHasSync = false;9191if (node->getOpCodeValue() == TR::monexit)9192{9193bool syncPresent = true;9194if (_escapeAnalysis)9195{9196Candidate *candidate;9197for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())9198{9199if (_escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()) == _escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node))9200{9201syncPresent = false;9202break;9203}9204}9205}92069207if (syncPresent)9208nodeHasSync = true;9209}9210else9211{9212TR::ILOpCode &opCode = node->getOpCode();9213if (opCode.hasSymbolReference())9214{9215TR::SymbolReference *symReference = node->getSymbolReference();9216if (symReference->getSymbol()->isVolatile())9217nodeHasSync = true;9218}92199220if (opCode.isCall() &&9221!node->hasUnresolvedSymbolReference() &&9222node->getSymbolReference()->getSymbol()->castToMethodSymbol()->isSynchronised())9223nodeHasSync = true;9224}92259226bool notAnalyzedSync = true;9227FlushCandidate *flushCandidate;9228for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())9229//for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())9230{9231candidate = getCandidate(_candidates, flushCandidate);9232if (!candidate)9233continue;92349235if (child &&9236((_escapeAnalysis &&9237_escapeAnalysis->usesValueNumber(candidate, valueNumber)) ||9238!_escapeAnalysis))9239{9240if (!dependencies)9241{9242_allocationInfo->reset(candidate->_index);9243TR_DependentAllocations *deps = NULL;9244if (_escapeAnalysis)9245deps = getDependentAllocationsFor(candidate, &(_escapeAnalysis->_dependentAllocations));9246else9247deps = getDependentAllocationsFor(candidate, &_dependentAllocations);92489249if (deps)9250{9251ListIterator<Candidate> candIt(deps->getDependentAllocations());9252for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())9253_allocationInfo->reset(dependentCandidate->_index);9254}9255}9256else9257dependencies->addDependentAllocation(candidate);9258}92599260if (((node == flushCandidate->getFlush()->getNode()) &&9261candidate->_flushRequired) ||9262(nodeHasSync &&9263notAnalyzedSync))9264{9265notAnalyzedSync = false;9266if (trace())9267{9268traceMsg(comp(), "\nConsidering Flush for allocation %p (index %d)\n", candidate->_node, candidate->_index);9269traceMsg(comp(), "Allocation info at this stage : \n");9270_allocationInfo->print(comp());9271traceMsg(comp(), "\n");9272}92739274_temp->empty();9275TR_BitVectorIterator allocIt(*_allocationInfo);9276while (allocIt.hasMoreElements())9277{9278int32_t nextAlloc = allocIt.getNextElement();9279//if (nextAlloc == candidate->_index)9280// continue;92819282//if (trace())9283// {9284// traceMsg(comp(), "nextAlloc %d\n", nextAlloc);9285// printf("nextAlloc %d\n", nextAlloc);9286// fflush(stdout);9287// }92889289bool nextAllocCanReach = true;9290Candidate *reachingCandidate = NULL;9291FlushCandidate *reachingFlushCandidate = NULL;9292for (reachingFlushCandidate = _flushCandidates->getFirst(); reachingFlushCandidate; reachingFlushCandidate = reachingFlushCandidate->getNext())9293//for (reachingCandidate = _candidates->getFirst(); reachingCandidate; reachingCandidate = reachingCandidate->getNext())9294{9295reachingCandidate = getCandidate(_candidates, reachingFlushCandidate);9296if (!reachingCandidate)9297continue;92989299if ((reachingCandidate->_index == nextAlloc) &&9300(reachingFlushCandidate != flushCandidate) &&9301reachingFlushCandidate->getFlush() &&9302visited.contains(reachingFlushCandidate->getFlush()->getNode()))9303{9304ListIterator<Candidate> candIt(&reachingCandidate->_flushMovedFrom);9305for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())9306{9307if (!_allocationInfo->get(dependentCandidate->_index))9308{9309nextAllocCanReach = false;9310break;9311}9312}9313break;9314}9315}93169317if (!reachingFlushCandidate || !reachingCandidate)9318continue;93199320if (nextAllocCanReach)9321{9322reachingCandidate->_flushRequired = false;93239324TR::TreeTop *flushTree = reachingFlushCandidate->getFlush();9325TR::TreeTop *prevTree = flushTree->getPrevTreeTop();9326TR::TreeTop *nextTree = flushTree->getNextTreeTop();9327if ((prevTree->getNextTreeTop() == flushTree) &&9328(nextTree->getPrevTreeTop() == flushTree))9329{9330if (flushTree->getNode()->getOpCodeValue() == TR::allocationFence)9331{9332flushTree->getNode()->setOmitSync(true);9333flushTree->getNode()->setAllocation(NULL);9334}9335//prevTree->join(nextTree);9336}93379338//if (trace())9339// {9340// traceMsg(comp(), "1reaching candidate %p index %d does not need Flush\n", reachingCandidate, reachingCandidate->_index);9341// }93429343if (!nodeHasSync)9344{9345if (reachingCandidate != candidate)9346{9347if (!_temp->get(reachingCandidate->_index))9348{9349_temp->set(reachingCandidate->_index);9350candidate->_flushMovedFrom.add(reachingCandidate);9351}93529353ListIterator<Candidate> candIt(&reachingCandidate->_flushMovedFrom);9354for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())9355{9356if (!_temp->get(dependentCandidate->_index))9357{9358_temp->set(dependentCandidate->_index);9359candidate->_flushMovedFrom.add(dependentCandidate);9360}9361}9362}9363}93649365if (trace())9366{9367if (!nodeHasSync)9368{9369traceMsg(comp(), "Flush for current allocation %d is post dominated by (and moved to) Flush for allocation %d\n", reachingCandidate->_index, candidate->_index);9370//printf("Moved flush for allocation %p to allocation %p locally in method %s\n", reachingCandidate->_node, candidate->_node, comp()->signature());9371}9372else9373{9374traceMsg(comp(), "Flush for current allocation %d is post dominated by (and moved to) sync in the same block\n", reachingCandidate->_index);9375//printf("Moved flush for allocation %p to real sync node %p locally in method %s\n", reachingCandidate->_node, node, comp()->signature());9376}93779378fflush(stdout);9379}9380}9381}93829383if (!nodeHasSync)9384_allocationInfo->set(candidate->_index);9385}93869387//if (node == candidate->_node)9388// _allocationInfo->set(candidate->_index);9389}9390}9391else9392{9393//if (_escapeAnalysis)9394{9395int32_t firstArgIndex = node->getFirstArgumentIndex();9396for (int32_t arg = firstArgIndex; arg < node->getNumChildren(); arg++)9397{9398TR::Node *child = node->getChild(arg);9399int32_t valueNumber = -1;9400if (_escapeAnalysis)9401valueNumber = _escapeAnalysis->_valueNumberInfo->getValueNumber(child);9402Candidate *candidate;9403for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())9404{9405if ((_escapeAnalysis &&9406_escapeAnalysis->usesValueNumber(candidate, valueNumber)) ||9407!_escapeAnalysis)9408{9409_allocationInfo->reset(candidate->_index);94109411TR_DependentAllocations *deps = NULL;9412if (_escapeAnalysis)9413deps = getDependentAllocationsFor(candidate, &(_escapeAnalysis->_dependentAllocations));9414else9415deps = getDependentAllocationsFor(candidate, &_dependentAllocations);94169417if (deps)9418{9419ListIterator<Candidate> candIt(deps->getDependentAllocations());9420for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())9421_allocationInfo->reset(dependentCandidate->_index);9422}9423}9424}9425}9426}9427}94289429int32_t i = 0;9430for (i = 0; i < node->getNumChildren(); i++)9431{9432TR::Node *child = node->getChild(i);94339434if (!examineNode(child, visited))9435return false;9436}94379438return true;9439}944094419442