Path: blob/master/runtime/compiler/optimizer/EscapeAnalysis.hpp
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#ifndef ESCAPEANALYSIS_INCL23#define ESCAPEANALYSIS_INCL2425#include <stddef.h>26#include <stdint.h>27#include "compile/Compilation.hpp"28#include "env/TRMemory.hpp"29#include "il/DataTypes.hpp"30#include "il/ILOpCodes.hpp"31#include "il/Node.hpp"32#include "infra/BitVector.hpp"33#include "infra/Flags.hpp"34#include "infra/Link.hpp"35#include "infra/List.hpp"36#include "optimizer/Optimization.hpp"37#include "optimizer/Optimization_inlines.hpp"38#include "optimizer/OptimizationManager.hpp"3940class TR_EscapeAnalysis;41class TR_FlowSensitiveEscapeAnalysis;42class TR_LocalFlushElimination;43class TR_OpaqueClassBlock;44class TR_ResolvedMethod;45class TR_UseDefInfo;46class TR_ValueNumberInfo;47namespace TR { class Block; }48namespace TR { class BlockChecklist; }49namespace TR { class CFGEdge; }50namespace TR { class NodeChecklist; }51namespace TR { class Optimizer; }52namespace TR { class ResolvedMethodSymbol; }53namespace TR { class SymbolReference; }54namespace TR { class TreeTop; }55template <class T> class TR_Array;5657typedef TR::typed_allocator<TR::Node *, TR::Region &> NodeDequeAllocator;58typedef std::deque<TR::Node *, NodeDequeAllocator> NodeDeque;5960typedef TR::typed_allocator<std::pair<TR::Node* const, std::pair<TR_BitVector *, NodeDeque*> >, TR::Region&> CallLoadMapAllocator;61typedef std::less<TR::Node *> CallLoadMapComparator;62typedef std::map<TR::Node *, std::pair<TR_BitVector *, NodeDeque *>, CallLoadMapComparator, CallLoadMapAllocator> CallLoadMap;6364typedef TR::typed_allocator<std::pair<TR::Node *const, int32_t>, TR::Region&> RemainingUseCountMapAllocator;65typedef std::less<TR::Node *> RemainingUseCountMapComparator;66typedef std::map<TR::Node *, int32_t, RemainingUseCountMapComparator, RemainingUseCountMapAllocator> RemainingUseCountMap;6768// Escape analysis69//70// Find object allocations that are either method local or thread local.71//72// Requires value numbering and use/def information.73//7475class TR_ColdBlockEscapeInfo76{77public:78TR_ALLOC(TR_Memory::EscapeAnalysis)7980TR_ColdBlockEscapeInfo(TR::Block *block, TR::Node *node, TR::TreeTop *tree, TR_Memory * m)81: _block(block), _escapeTrees(m), _nodes(m)82{83_nodes.add(node);84_escapeTrees.add(tree);85}8687TR_ScratchList<TR::Node> *getNodes() {return &_nodes;}88TR_ScratchList<TR::TreeTop> *getTrees() {return &_escapeTrees;}8990void addNode(TR::Node *node, TR::TreeTop *tree)91{92if (!_nodes.find(node))93{94_nodes.add(node);95//if (!_escapeTrees.find(tree))96_escapeTrees.add(tree);97}98}99TR::Block *getBlock() {return _block;}100void setBlock(TR::Block *block) {_block = block;}101102private:103TR_ScratchList<TR::TreeTop> _escapeTrees;104TR::Block *_block;105TR_ScratchList<TR::Node> _nodes;106};107108109class Candidate;110111112struct FieldInfo113{114int32_t _offset;115int32_t _size;116TR::SymbolReference *_symRef;117TR_ScratchList<TR::SymbolReference> *_goodFieldSymrefs;118TR_ScratchList<TR::SymbolReference> *_badFieldSymrefs;119char _vectorElem;120121void rememberFieldSymRef(TR::Node *node, int32_t fieldOffset, Candidate *candidate, TR_EscapeAnalysis *ea);122bool symRefIsForFieldInAllocatedClass(TR::SymbolReference *symRef);123bool hasBadFieldSymRef();124TR::SymbolReference *fieldSymRef(); // Any arbitrary good field symref125};126127128class Candidate : public TR_Link<Candidate>129{130public:131Candidate(TR::Node *node, TR::TreeTop *treeTop, TR::Block *block, int32_t size, void *classInfo, TR::Compilation * c)132: _kind(node->getOpCodeValue()), _node(node), _treeTop(treeTop), _origKind(node->getOpCodeValue()), _stringCopyNode(NULL), _stringCopyCallTree(NULL),133_block(block),134_class(classInfo),135_size(size), _fieldSize(0), _valueNumbers(0), _fields(0), _origSize(size),136_initializedWords(0),137_maxInlineDepth(0), _inlineBytecodeSize(0), _seenFieldStore(false), _seenSelfStore(false), _seenStoreToLocalObject(false), _seenArrayCopy(false), _argToCall(false), _usedInNonColdBlock(false), _lockedInNonColdBlock(false),_isImmutable(false),138_originalAllocationNode(0), _lockedObject(false), _index(-1), _flushRequired(true),139_comp(c), _trMemory(c->trMemory()),140_flushMovedFrom(c->trMemory()),141_symRefs(c->trMemory()),142_callSites(c->trMemory()),143_dememoizedMethodSymRef(NULL),144_dememoizedConstructorCall(NULL),145_virtualCallSitesToBeFixed(c->trMemory()),146_coldBlockEscapeInfo(c->trMemory())147{148static const char *forceContinguousAllocation = feGetEnv("TR_forceContinguousAllocation");149if (forceContinguousAllocation)150setMustBeContiguousAllocation();151}152153TR::Compilation * comp() { return _comp; }154155TR_Memory * trMemory() { return _trMemory; }156TR_StackMemory trStackMemory() { return _trMemory; }157TR_HeapMemory trHeapMemory() { return _trMemory; }158TR_PersistentMemory * trPersistentMemory() { return _trMemory->trPersistentMemory(); }159160bool isLocalAllocation() {return _flags.testAny(LocalAllocation);}161bool isContiguousAllocation() {return mustBeContiguousAllocation() || hasCallSites();}162bool mustBeContiguousAllocation() {return _flags.testAny(MustBeContiguous);}163bool isExplicitlyInitialized() {return _flags.testAny(ExplicitlyInitialized);}164bool objectIsReferenced() {return _flags.testAny(ObjectIsReferenced);}165bool fillsInStackTrace() {return _flags.testAny(FillsInStackTrace);}166bool callsStringCopyConstructor() {return _flags.testAny(CallsStringCopy);}167bool isInsideALoop() {return _flags.testAny(InsideALoop);}168bool isInAColdBlock() {return _flags.testAny(InAColdBlock);}169bool isProfileOnly() {return _flags.testAny(ProfileOnly);}170171bool usesStackTrace() {return _flags.testAny(UsesStackTrace);}172bool isArgToCall(int32_t depth) {return _argToCallFlags.testAny(1<<depth);}173bool isNonThisArgToCall(int32_t depth) {return _nonThisArgToCallFlags.testAny(1<<(depth));}174bool forceLocalAllocation() { return _flags.testAny(ForceLocalAllocation);}175176void setForceLocalAllocation(bool v = true) {_flags.set(ForceLocalAllocation, v);}177void setLocalAllocation(bool v = true) {_flags.set(LocalAllocation, v);}178void setMustBeContiguousAllocation(bool v = true) {_flags.set(MustBeContiguous, v);}179void setExplicitlyInitialized(bool v = true) {_flags.set(ExplicitlyInitialized, v);}180void setObjectIsReferenced(bool v = true) {_flags.set(ObjectIsReferenced, v);}181void setFillsInStackTrace(bool v = true) {_flags.set(FillsInStackTrace, v);}182void setCallsStringCopyConstructor(bool v = true) {_flags.set(CallsStringCopy, v);}183void setInsideALoop(bool v = true) {_flags.set(InsideALoop, v); }184void setInAColdBlock(bool v = true) {_flags.set(InAColdBlock, v); }185void setProfileOnly(bool v = true) {_flags.set(ProfileOnly, v); }186187void setUsesStackTrace(bool v = true) {_flags.set(UsesStackTrace, v);}188void setArgToCall(int32_t depth, bool v = true) {_argToCallFlags.set(1<<depth, v); if (v == true) _argToCall = true;}189void setNonThisArgToCall(int32_t depth, bool v = true) {_nonThisArgToCallFlags.set(1<<depth, v);}190191192TR::Node *getStringCopyNode() {return _stringCopyNode; }193void setStringCopyNode(TR::Node *n) { _stringCopyNode = n; }194195bool isLockedObject() { return _lockedObject; }196void setLockedObject(bool b) {_lockedObject = b;}197198bool usedInNonColdBlock() { return _usedInNonColdBlock; }199void setUsedInNonColdBlock(bool b = true) { _usedInNonColdBlock = b; }200201bool lockedInNonColdBlock() { return _lockedInNonColdBlock; }202void setLockedInNonColdBlock(bool b = true) { _lockedInNonColdBlock = b; }203204TR_ScratchList<TR::SymbolReference> *getSymRefs() { return &_symRefs; }205void addSymRef(TR::SymbolReference *symRef) { _symRefs.add(symRef); }206207bool hasCallSites() { return !_callSites.isEmpty(); }208TR_ScratchList<TR::TreeTop> *getCallSites() { return &_callSites; }209void addCallSite(TR::TreeTop *treeTop) { _callSites.add(treeTop); }210211bool hasVirtualCallsToBeFixed() {return !_virtualCallSitesToBeFixed.isEmpty();}212TR_ScratchList<TR::TreeTop> *getVirtualCallSitesToBeFixed() { return &_virtualCallSitesToBeFixed; }213void addVirtualCallSiteToBeFixed(TR::TreeTop *treeTop) { _virtualCallSitesToBeFixed.add(treeTop); }214bool escapesInColdBlocks() { return !_coldBlockEscapeInfo.isEmpty(); }215216bool escapesInColdBlock(TR::Block *block)217{218ListElement<TR_ColdBlockEscapeInfo> *curColdBlockInfo = _coldBlockEscapeInfo.getListHead();219while (curColdBlockInfo)220{221if (curColdBlockInfo->getData()->getBlock() == block)222return true;223curColdBlockInfo = curColdBlockInfo->getNextElement();224}225return false;226}227228TR_ScratchList<TR_ColdBlockEscapeInfo> *getColdBlockEscapeInfo() { return &_coldBlockEscapeInfo; }229void addColdBlockEscapeInfo(TR::Block *block, TR::Node *node, TR::TreeTop *tree)230{231ListElement<TR_ColdBlockEscapeInfo> *curColdBlockInfo = _coldBlockEscapeInfo.getListHead();232while (curColdBlockInfo)233{234if (curColdBlockInfo->getData()->getBlock() == block)235break;236curColdBlockInfo = curColdBlockInfo->getNextElement();237}238239if (curColdBlockInfo)240{241curColdBlockInfo->getData()->addNode(node, tree);242}243else244{245TR_ColdBlockEscapeInfo *coldBlockInfo = new (trStackMemory()) TR_ColdBlockEscapeInfo(block, node, tree, trMemory());246_coldBlockEscapeInfo.add(coldBlockInfo);247}248}249250void print();251252TR::ILOpCodes _kind;253TR::ILOpCodes _origKind;254TR::Node *_node;255TR::TreeTop *_treeTop;256TR::Block *_block;257TR_Array<int32_t> *_valueNumbers;258TR_Array<FieldInfo> *_fields;259TR_BitVector *_initializedWords;260void *_class;261TR::Node *_originalAllocationNode;262TR::Compilation * _comp;263TR_Memory * _trMemory;264TR::Node *_stringCopyNode;265266TR::TreeTop *_stringCopyCallTree;267268TR::SymbolReference *_dememoizedMethodSymRef;269TR::TreeTop *_dememoizedConstructorCall;270271TR_ScratchList<Candidate> _flushMovedFrom;272273int32_t _size;274int32_t _fieldSize;275int32_t _origSize;276int32_t _maxInlineDepth;277int32_t _inlineBytecodeSize;278bool _seenFieldStore;279bool _seenSelfStore;280281bool _seenStoreToLocalObject;282bool _seenArrayCopy;283bool _argToCall;284bool _isImmutable;285286bool _lockedObject;287bool _flushRequired;288bool _usedInNonColdBlock;289bool _lockedInNonColdBlock;290int32_t _index;291292protected:293294TR_ScratchList<TR::SymbolReference> _symRefs;295TR_ScratchList<TR::TreeTop> _callSites;296TR_ScratchList<TR::TreeTop> _virtualCallSitesToBeFixed;297TR_ScratchList<TR_ColdBlockEscapeInfo> _coldBlockEscapeInfo;298flags32_t _flags;299flags16_t _nonThisArgToCallFlags;300flags16_t _argToCallFlags;301302enum // flag bits303{304LocalAllocation = 0x80000000,305MustBeContiguous = 0x40000000,306ExplicitlyInitialized = 0x20000000,307ObjectIsReferenced = 0x10000000,308309// Flags used for Throwable objects310//311FillsInStackTrace = 0x08000000,312UsesStackTrace = 0x04000000,313314// Object that is being allocated inside a loop315//316InsideALoop = 0x02000000,317318// Object that is in a cold block319//320InAColdBlock = 0x01000000,321322// Object is an array whose length is not a constant, so we can't do323// anything with it in this EA pass, but continue analyzing it because324// if the unknown size is the ONLY reason we can't stack-allocate it,325// then we should add profiling trees.326//327ProfileOnly = 0x00800000,328329330// Object whose class has been annotated by user that331// any instance should be locally allocated (X10)332ForceLocalAllocation = 0x00100000,333334CallsStringCopy = 0x00200000,335};336};337338339class FlushCandidate : public TR_Link<FlushCandidate>340{341public:342FlushCandidate(TR::TreeTop *flushNode, TR::Node *node, int32_t blockNum, Candidate *candidate = 0)343: _flushNode(flushNode), _node(node), _blockNum(blockNum), _candidate(candidate), _isKnownToLackCandidate(false)344{345}346347TR::Node *getAllocation() {return _node;}348void setAllocation(TR::Node *node) {_node = node;}349350TR::TreeTop *getFlush() {return _flushNode;}351void setFlush(TR::TreeTop *node) {_flushNode = node;}352353int32_t getBlockNum() {return _blockNum;}354void setBlockNum(int32_t n) {_blockNum = n;}355356Candidate *getCandidate() { return _candidate;}357void setCandidate(Candidate *c) {_candidate = c;}358359/**360* \brief Indicates whether this \c FlushCandidate is known to have no361* candidate for stack allocation associated with it. That is, that362* the \ref getCandidate() method will always return \c NULL.363*364* \return \c true if this \c FlushCandidate is known to have no365* candidate for stack allocation associated with it;366* \c false if this \c FlushCandidate is known to have a candidate367* for stack allocation associated with it, or if it has not yet368* been determined whether there is a candidate for stack allocation369* associated with it.370*/371bool getIsKnownToLackCandidate() { return _isKnownToLackCandidate;}372373/**374* \brief Sets the status of this \c FlushCandidate, indicating whether375* it is known to have no candidate for stack allocation associated with it.376*377* \param setting The updated status indicating whether this \c FlushCandidate378* is known to have no candidate for stack allocation associated with it379*/380void setIsKnownToLackCandidate(bool setting) {_isKnownToLackCandidate = setting;}381382private:383TR::Node *_node;384TR::TreeTop *_flushNode;385int32_t _blockNum;386Candidate *_candidate;387bool _isKnownToLackCandidate;388};389390391class TR_DependentAllocations392{393public:394TR_ALLOC(TR_Memory::EscapeAnalysis)395396TR_DependentAllocations(Candidate *allocNode, Candidate *dependentNode, TR_Memory * m)397: _allocNode(allocNode), _dependentNodes(m)398{399addDependentAllocation(dependentNode);400}401402TR_ScratchList<Candidate> *getDependentAllocations() {return &_dependentNodes;}403void addDependentAllocation(Candidate *c)404{405if (c && !_dependentNodes.find(c))406_dependentNodes.add(c);407}408409Candidate *getAllocation() {return _allocNode;}410void setAllocation(Candidate *node) {_allocNode = node;}411412private:413Candidate *_allocNode;414TR_ScratchList<Candidate> _dependentNodes;415};416417418class TR_CFGEdgeAllocationPair419{420public:421TR_ALLOC(TR_Memory::EscapeAnalysis)422423TR_CFGEdgeAllocationPair(TR::CFGEdge *edge, Candidate *allocNode)424: _allocNode(allocNode),425_edge(edge)426{427}428429Candidate *getAllocation() {return _allocNode;}430void setAllocation(Candidate *node) {_allocNode = node;}431432TR::CFGEdge *getEdge() {return _edge;}433void setEdge(TR::CFGEdge *edge) {_edge = edge;}434435private:436Candidate *_allocNode;437TR::CFGEdge *_edge;438};439440441class SniffCallCache : public TR_Link<SniffCallCache>442{443public:444SniffCallCache(TR_ResolvedMethod *vmMethod, bool isCold, int32_t bytecodeSize)445: _vmMethod(vmMethod), _isCold(isCold), _bytecodeSize(bytecodeSize)446{447}448static bool isInCache(TR_LinkHead<SniffCallCache> *sniffCacheList, TR_ResolvedMethod *vmMethod, bool isCold, int32_t &bytecodeSize);449private:450TR_ResolvedMethod *_vmMethod;451bool _isCold;452int32_t _bytecodeSize;453};454455class SymRefCache : public TR_Link<SymRefCache>456{457public:458SymRefCache(TR::SymbolReference *symRef, TR_ResolvedMethod *resolvedMethod)459: _symRef(symRef), _vmMethod(resolvedMethod)460{461}462static TR::SymbolReference* findSymRef(TR_LinkHead<SymRefCache> *symRefList, TR_ResolvedMethod *resolvedMethod);463TR::SymbolReference *getSymRef() {return _symRef;}464TR_ResolvedMethod *getMethod() {return _vmMethod;}465private:466TR::SymbolReference *_symRef;467TR_ResolvedMethod *_vmMethod;468};469470class TR_EscapeAnalysis : public TR::Optimization471{472public:473474TR_EscapeAnalysis(TR::OptimizationManager *manager);475static TR::Optimization *create(TR::OptimizationManager *manager)476{477return new (manager->allocator()) TR_EscapeAnalysis(manager);478}479480virtual int32_t perform();481virtual const char * optDetailString() const throw();482483protected:484485enum restrictionType { MakeNonLocal, MakeContiguous, MakeObjectReferenced };486487int32_t performAnalysisOnce();488void findCandidates();489void findIgnoreableUses();490void findIgnoreableUses(TR::Node *node, TR::NodeChecklist& visited);491void findLocalObjectsValueNumbers();492void findLocalObjectsValueNumbers(TR::Node *node, TR::NodeChecklist& visited);493494Candidate *createCandidateIfValid(TR::Node *node, TR_OpaqueClassBlock *&classInfo,bool);495//int32_t checkForValidCandidate(TR::Node *node, TR_OpaqueClassBlock *&classInfo,bool);496bool collectValueNumbersOfIndirectAccessesToObject(TR::Node *node, Candidate *candidate, TR::Node *indirectStore, TR::NodeChecklist& visited, int32_t baseChildVN = -1);497void checkDefsAndUses();498bool checkDefsAndUses(TR::Node *node, Candidate *candidate);499500/**501* Walk through trees looking for \c aselect operations. For the502* value operands of an \c aselect, populate \ref _nodeUsesThroughAselect503* with an entry mapping from the operand to a list containing the504* \c aselect nodes that refer to it.505*506* \see _nodeUsesThroughAselect507*/508void gatherUsesThroughAselect(void);509510/**511* Recursive implementation method for \ref gatherUsesThroughAselect512*513* \param[in] node The root of the subtree that is to be processed514* \param[inout] visited A bit vector indicating whether a node has515* already been visited516*/517void gatherUsesThroughAselectImpl(TR::Node *node, TR::NodeChecklist& visited);518519/**520* Add an entry to \ref _nodeUsesThroughAselect mapping from the child node521* of \c aselectNode at the specified index to the \c aselectNode itself.522*523* \param[in] aselectNode A node whose opcode is an \c aselect operation524* \param[in] idx The index of a child of \c aselectNode525*/526void associateAselectWithChild(TR::Node *aselectNode, int32_t idx);527528/**529* Trace contents of \ref _nodeUsesThroughAselect530*/531void printUsesThroughAselect(void);532533/**534* Check whether \c node, which is a use of the candidate for stack535* allocation, \c candidate, is itself used as one of the value operands536* in an \c aselect operation, as found in \ref _nodeUsesThroughAselect.537* If it is, the value number of any such \c aselect is added to the list538* of value numbers associated with the candidate.539*540* \param[in] node The use of \c candidate that is under consideration541* \param[in] candidate A candidate for stack allocation542*/543bool checkUsesThroughAselect(TR::Node *node, Candidate *candidate);544bool checkOtherDefsOfLoopAllocation(TR::Node *useNode, Candidate *candidate, bool isImmediateUse);545bool checkOverlappingLoopAllocation(TR::Node *useNode, Candidate *candidate);546bool checkOverlappingLoopAllocation(TR::Node *node, TR::Node *useNode, TR::Node *allocNode, rcount_t &numReferences);547548/**549* Visit nodes in the subtree, keeping track of those visited in550* @ref _visitedNodes551* @param[in] node The subtree that is to be visited552*/553void visitTree(TR::Node *node);554555/**556* Collect aliases of an allocation node in the specified subtree557* in @ref _aliasesOfOtherAllocNode558* Nodes in the subtree that are visited are tracked in559* @ref _visitedNodes, and those that have been marked as already visited560* are skipped.561* @param[in] node The subtree that is to be visited562* @param[in] allocNode The allocation node whose aliases are to be collected563*/564void collectAliasesOfAllocations(TR::Node *node, TR::Node *allocNode);565566bool checkAllNewsOnRHSInLoop(TR::Node *defNode, TR::Node *useNode, Candidate *candidate);567bool checkAllNewsOnRHSInLoopWithAliasing(int32_t defIndex, TR::Node *useNode, Candidate *candidate);568bool usesValueNumber(Candidate *candidate, int32_t valueNumber);569Candidate *findCandidate(int32_t valueNumber);570571572bool detectStringCopy(TR::Node *node);573void markCandidatesUsedInNonColdBlock(TR::Node *node);574575bool checkIfUseIsInLoopAndOverlapping(Candidate *candidate, TR::TreeTop *defTree, TR::Node *useNode);576bool checkIfUseIsInLoopAndOverlapping(TR::TreeTop *start, TR::TreeTop *end, TR::TreeTop *defTree, TR::Node *useNode, TR::NodeChecklist& visited, TR::BlockChecklist& vBlocks, bool & decisionMade);577bool checkUse(TR::Node *node, TR::Node *useNode, TR::NodeChecklist& visited);578bool checkIfUseIsInSameLoopAsDef(TR::TreeTop *defTree, TR::Node *useNode);579580bool isEscapePointCold(Candidate *candidate, TR::Node *node);581bool checkIfEscapePointIsCold(Candidate *candidate, TR::Node *node);582void forceEscape(TR::Node *node, TR::Node *reason, bool forceFail = false);583bool restrictCandidates(TR::Node *node, TR::Node *reason, restrictionType);584//void referencedField(TR::Node *base, TR::Node *field, bool isStore, bool seenSelfStore = false);585void referencedField(TR::Node *base, TR::Node *field, bool isStore, bool seenSelfStore = false, bool seenStoreToLocalObject = false);586TR::Node *resolveSniffedNode(TR::Node *node);587void checkEscape(TR::TreeTop *firstTree, bool isCold, bool & ignoreRecursion);588void checkEscapeViaNonCall(TR::Node *node, TR::NodeChecklist& visited);589void checkEscapeViaCall(TR::Node *node, TR::NodeChecklist& visited, bool & ignoreRecursion);590int32_t sniffCall(TR::Node *callNode, TR::ResolvedMethodSymbol *methodSymbol, bool ignoreOpCode, bool isCold, bool & ignoreRecursion);591void checkObjectSizes();592void fixupTrees();593void anchorCandidateReference(Candidate *candidate, TR::Node *reference);594bool fixupNode(TR::Node *node, TR::Node *parent, TR::NodeChecklist& visited);595bool fixupFieldAccessForContiguousAllocation(TR::Node *node, Candidate *candidate);596bool fixupFieldAccessForNonContiguousAllocation(TR::Node *node, Candidate *candidate, TR::Node *parent);597void makeLocalObject(Candidate *candidate);598void avoidStringCopyAllocation(Candidate *candidate);599600/** \brief601* Attempts to zero initialize a stack allocated candidate using TR::arrayset.602*603* \param candidate604* The candidate to zero initialize.605*606* \param precedingTreeTop607* The preceding tree top to which the TR::arrayset will be attached to.608*609* \return610* true if a TR::arrayset was emitted to zero initialize the candidate; false otherwise.611*/612bool tryToZeroInitializeUsingArrayset(Candidate* candidate, TR::TreeTop* precedingTreeTop);613614void makeContiguousLocalAllocation(Candidate *candidate);615void makeNonContiguousLocalAllocation(Candidate *candidate);616void heapifyForColdBlocks(Candidate *candidate);617618/**619* \brief Store the supplied address to the specified temporary620*621* \param candidate622* The candidate that is being heapified623*624* \param addr625* The address of the possibly heapified object626*627* \param symRef628* The \ref TR::SymbolReference for the temporay629*630* \return A pointer to the \ref TR::TreeTop containing the store631*/632TR::TreeTop *storeHeapifiedToTemp(Candidate *candidate, TR::Node *addr, TR::SymbolReference *symRef);633bool inlineCallSites();634void scanForExtraCallsToInline();635bool alwaysWorthInlining(TR::Node *callNode);636bool devirtualizeCallSites();637bool hasFlushOnEntry(int32_t blockNum) {if (_blocksWithFlushOnEntry->get(blockNum)) return true; return false;}638void setHasFlushOnEntry(int32_t blockNum) {_blocksWithFlushOnEntry->set(blockNum);}639void rememoize(Candidate *c, bool mayDememoizeNextTime=false);640641void printCandidates(char *);642643char *getClassName(TR::Node *classNode);644645bool isImmutableObject(TR::Node *node);646bool isImmutableObject(Candidate *candidate);647648TR::Node *createConst(TR::Compilation *comp, TR::Node *node, TR::DataType type, int value);649650struct TR_CallSitesFixedMapper : public TR_Link<TR_CallSitesFixedMapper>651{652TR_CallSitesFixedMapper(TR::TreeTop * virtualCallSite, TR::TreeTop * directCallSite)653: _vCallSite(virtualCallSite), _dCallSite(directCallSite){ }654655TR::TreeTop * _vCallSite;656TR::TreeTop * _dCallSite;657};658659class PersistentData : public TR::OptimizationData660{661public:662PersistentData(TR::Compilation *comp)663: TR::OptimizationData(comp),664_totalInlinedBytecodeSize(0),665_totalPeekedBytecodeSize(0)666{667_symRefList.setFirst(NULL);668_peekableCalls = new (comp->trHeapMemory()) TR_BitVector(0, comp->trMemory(), heapAlloc);669_processedCalls = new (comp->trHeapMemory()) TR_BitVector(0, comp->trMemory(), heapAlloc);670}671672int32_t _totalInlinedBytecodeSize;673int32_t _totalPeekedBytecodeSize;674TR_BitVector *_peekableCalls;675TR_BitVector *_processedCalls;676TR_LinkHead<SymRefCache> _symRefList;677};678679PersistentData * getOptData() { return (PersistentData *) manager()->getOptData(); }680681//TR::TreeTop *findCallSiteFixed(TR::TreeTop * virtualCallSite);682bool findCallSiteFixed(TR::TreeTop * virtualCallSite);683684TR::SymbolReference *_newObjectNoZeroInitSymRef;685TR::SymbolReference *_newArrayNoZeroInitSymRef;686TR::SymbolReference *_aNewArrayNoZeroInitSymRef;687TR_UseDefInfo *_useDefInfo;688bool _invalidateUseDefInfo;689TR_BitVector *_otherDefsForLoopAllocation;690TR_BitVector *_ignoreableUses;691TR_BitVector *_nonColdLocalObjectsValueNumbers;692TR_BitVector *_allLocalObjectsValueNumbers;693TR_BitVector *_notOptimizableLocalObjectsValueNumbers;694TR_BitVector *_notOptimizableLocalStringObjectsValueNumbers;695TR_BitVector *_blocksWithFlushOnEntry;696TR_BitVector *_visitedNodes;697698CallLoadMap *_callsToProtect;699700/**701* Contains sym refs that are just aliases for a fresh allocation702* i.e., it is used to track allocations in cases such as703* ...704* a = new A()705* ...706* b = a707* ...708* c = b709*710* In this case a, b and c will all be considered aliases of an alloc node711* and so a load of any of those sym refs will be treated akin to how the712* fresh allocation would be treated713*/714TR_BitVector *_aliasesOfAllocNode;715716/**717* Contains sym refs that are just aliases for a second fresh allocation718* that is under consideration, as with @ref _aliasesOfAllocNode719*/720TR_BitVector *_aliasesOfOtherAllocNode;721TR_ValueNumberInfo *_valueNumberInfo;722TR_LinkHead<Candidate> _candidates;723TR_Array<TR::Node*> *_parms;724TR_ScratchList<TR::TreeTop> _inlineCallSites;725TR_ScratchList<TR::TreeTop> _devirtualizedCallSites;726TR_LinkHead<TR_CallSitesFixedMapper> _fixedVirtualCallSites;727728List<TR::Node> _dememoizedAllocs;729TR::SymbolReference *_dememoizationSymRef;730731TR::Block *_curBlock;732TR::TreeTop *_curTree;733int32_t _sniffDepth;734int32_t _maxSniffDepth;735int32_t _maxPassNumber;736TR::ResolvedMethodSymbol *_methodSymbol;737bool _inBigDecimalAdd;738int32_t _maxInlinedBytecodeSize;739int32_t _maxPeekedBytecodeSize;740bool _inColdBlock;741bool _createStackAllocations;742bool _createLocalObjects;743bool _desynchronizeCalls;744bool _classObjectLoadForVirtualCall;745#if CHECK_MONITORS746bool _removeMonitors;747#endif748bool _repeatAnalysis;749bool _somethingChanged;750bool _doLoopAllocationAliasChecking;751TR_ScratchList<TR_DependentAllocations> _dependentAllocations;752TR_BitVector * _vnTemp;753TR_BitVector * _vnTemp2;754755typedef TR::typed_allocator<TR::Node *, TR::Region &> NodeDequeAllocator;756typedef std::deque<TR::Node *, NodeDequeAllocator> NodeDeque;757758typedef TR::typed_allocator<std::pair<TR::Node* const, NodeDeque*>, TR::Region&> NodeToNodeDequeMapAllocator;759typedef std::less<TR::Node*> NodeComparator;760typedef std::map<TR::Node*, NodeDeque*, NodeComparator, NodeToNodeDequeMapAllocator> NodeToNodeDequeMap;761762/**763* A mapping from nodes to a \c deque of \c aselect nodes that directly764* reference them.765*/766NodeToNodeDequeMap * _nodeUsesThroughAselect;767768friend class TR_FlowSensitiveEscapeAnalysis;769friend class TR_LocalFlushElimination;770friend struct FieldInfo;771};772773//class Candidate;774//class TR_EscapeAnalysis;775//class TR_DependentAllocations;776777class TR_LocalFlushElimination778{779public:780TR_ALLOC(TR_Memory::LocalOpts)781TR_LocalFlushElimination(TR_EscapeAnalysis *, int32_t numAllocations);782783virtual int32_t perform();784bool examineNode(TR::Node *, TR::NodeChecklist& visited);785786TR::Optimizer * optimizer() { return _escapeAnalysis->optimizer(); }787TR::Compilation * comp() { return _escapeAnalysis->comp(); }788789TR_Memory * trMemory() { return comp()->trMemory(); }790TR_StackMemory trStackMemory() { return comp()->trStackMemory(); }791792bool trace() { return _escapeAnalysis->trace(); }793794private:795TR_LinkHead<Candidate> *_candidates;796TR_LinkHead<FlushCandidate> *_flushCandidates;797TR_EscapeAnalysis *_escapeAnalysis;798int32_t _numAllocations;799TR_BitVector *_allocationInfo;800TR_BitVector *_temp;801TR_ScratchList<TR_DependentAllocations> _dependentAllocations;802};803804805806#if CHECK_MONITORS807class TR_MonitorStructureChecker808{809public:810TR_ALLOC(TR_Memory::EscapeAnalysis)811TR_MonitorStructureChecker() {}812813// returns true if illegal structure is found814bool checkMonitorStructure(TR::CFG *cfg);815816private:817void processBlock(TR::Block *block);818void propagateInfoTo(TR::Block *block, int32_t inInfo);819820int32_t *_blockInfo;821TR_BitVector *_seenNodes;822bool _foundIllegalStructure;823};824825#endif826#endif827828829830831832833834835836837838