Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/EscapeAnalysis.hpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2021 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#ifndef ESCAPEANALYSIS_INCL
24
#define ESCAPEANALYSIS_INCL
25
26
#include <stddef.h>
27
#include <stdint.h>
28
#include "compile/Compilation.hpp"
29
#include "env/TRMemory.hpp"
30
#include "il/DataTypes.hpp"
31
#include "il/ILOpCodes.hpp"
32
#include "il/Node.hpp"
33
#include "infra/BitVector.hpp"
34
#include "infra/Flags.hpp"
35
#include "infra/Link.hpp"
36
#include "infra/List.hpp"
37
#include "optimizer/Optimization.hpp"
38
#include "optimizer/Optimization_inlines.hpp"
39
#include "optimizer/OptimizationManager.hpp"
40
41
class TR_EscapeAnalysis;
42
class TR_FlowSensitiveEscapeAnalysis;
43
class TR_LocalFlushElimination;
44
class TR_OpaqueClassBlock;
45
class TR_ResolvedMethod;
46
class TR_UseDefInfo;
47
class TR_ValueNumberInfo;
48
namespace TR { class Block; }
49
namespace TR { class BlockChecklist; }
50
namespace TR { class CFGEdge; }
51
namespace TR { class NodeChecklist; }
52
namespace TR { class Optimizer; }
53
namespace TR { class ResolvedMethodSymbol; }
54
namespace TR { class SymbolReference; }
55
namespace TR { class TreeTop; }
56
template <class T> class TR_Array;
57
58
typedef TR::typed_allocator<TR::Node *, TR::Region &> NodeDequeAllocator;
59
typedef std::deque<TR::Node *, NodeDequeAllocator> NodeDeque;
60
61
typedef TR::typed_allocator<std::pair<TR::Node* const, std::pair<TR_BitVector *, NodeDeque*> >, TR::Region&> CallLoadMapAllocator;
62
typedef std::less<TR::Node *> CallLoadMapComparator;
63
typedef std::map<TR::Node *, std::pair<TR_BitVector *, NodeDeque *>, CallLoadMapComparator, CallLoadMapAllocator> CallLoadMap;
64
65
typedef TR::typed_allocator<std::pair<TR::Node *const, int32_t>, TR::Region&> RemainingUseCountMapAllocator;
66
typedef std::less<TR::Node *> RemainingUseCountMapComparator;
67
typedef std::map<TR::Node *, int32_t, RemainingUseCountMapComparator, RemainingUseCountMapAllocator> RemainingUseCountMap;
68
69
// Escape analysis
70
//
71
// Find object allocations that are either method local or thread local.
72
//
73
// Requires value numbering and use/def information.
74
//
75
76
class TR_ColdBlockEscapeInfo
77
{
78
public:
79
TR_ALLOC(TR_Memory::EscapeAnalysis)
80
81
TR_ColdBlockEscapeInfo(TR::Block *block, TR::Node *node, TR::TreeTop *tree, TR_Memory * m)
82
: _block(block), _escapeTrees(m), _nodes(m)
83
{
84
_nodes.add(node);
85
_escapeTrees.add(tree);
86
}
87
88
TR_ScratchList<TR::Node> *getNodes() {return &_nodes;}
89
TR_ScratchList<TR::TreeTop> *getTrees() {return &_escapeTrees;}
90
91
void addNode(TR::Node *node, TR::TreeTop *tree)
92
{
93
if (!_nodes.find(node))
94
{
95
_nodes.add(node);
96
//if (!_escapeTrees.find(tree))
97
_escapeTrees.add(tree);
98
}
99
}
100
TR::Block *getBlock() {return _block;}
101
void setBlock(TR::Block *block) {_block = block;}
102
103
private:
104
TR_ScratchList<TR::TreeTop> _escapeTrees;
105
TR::Block *_block;
106
TR_ScratchList<TR::Node> _nodes;
107
};
108
109
110
class Candidate;
111
112
113
struct FieldInfo
114
{
115
int32_t _offset;
116
int32_t _size;
117
TR::SymbolReference *_symRef;
118
TR_ScratchList<TR::SymbolReference> *_goodFieldSymrefs;
119
TR_ScratchList<TR::SymbolReference> *_badFieldSymrefs;
120
char _vectorElem;
121
122
void rememberFieldSymRef(TR::Node *node, int32_t fieldOffset, Candidate *candidate, TR_EscapeAnalysis *ea);
123
bool symRefIsForFieldInAllocatedClass(TR::SymbolReference *symRef);
124
bool hasBadFieldSymRef();
125
TR::SymbolReference *fieldSymRef(); // Any arbitrary good field symref
126
};
127
128
129
class Candidate : public TR_Link<Candidate>
130
{
131
public:
132
Candidate(TR::Node *node, TR::TreeTop *treeTop, TR::Block *block, int32_t size, void *classInfo, TR::Compilation * c)
133
: _kind(node->getOpCodeValue()), _node(node), _treeTop(treeTop), _origKind(node->getOpCodeValue()), _stringCopyNode(NULL), _stringCopyCallTree(NULL),
134
_block(block),
135
_class(classInfo),
136
_size(size), _fieldSize(0), _valueNumbers(0), _fields(0), _origSize(size),
137
_initializedWords(0),
138
_maxInlineDepth(0), _inlineBytecodeSize(0), _seenFieldStore(false), _seenSelfStore(false), _seenStoreToLocalObject(false), _seenArrayCopy(false), _argToCall(false), _usedInNonColdBlock(false), _lockedInNonColdBlock(false),_isImmutable(false),
139
_originalAllocationNode(0), _lockedObject(false), _index(-1), _flushRequired(true),
140
_comp(c), _trMemory(c->trMemory()),
141
_flushMovedFrom(c->trMemory()),
142
_symRefs(c->trMemory()),
143
_callSites(c->trMemory()),
144
_dememoizedMethodSymRef(NULL),
145
_dememoizedConstructorCall(NULL),
146
_virtualCallSitesToBeFixed(c->trMemory()),
147
_coldBlockEscapeInfo(c->trMemory())
148
{
149
static const char *forceContinguousAllocation = feGetEnv("TR_forceContinguousAllocation");
150
if (forceContinguousAllocation)
151
setMustBeContiguousAllocation();
152
}
153
154
TR::Compilation * comp() { return _comp; }
155
156
TR_Memory * trMemory() { return _trMemory; }
157
TR_StackMemory trStackMemory() { return _trMemory; }
158
TR_HeapMemory trHeapMemory() { return _trMemory; }
159
TR_PersistentMemory * trPersistentMemory() { return _trMemory->trPersistentMemory(); }
160
161
bool isLocalAllocation() {return _flags.testAny(LocalAllocation);}
162
bool isContiguousAllocation() {return mustBeContiguousAllocation() || hasCallSites();}
163
bool mustBeContiguousAllocation() {return _flags.testAny(MustBeContiguous);}
164
bool isExplicitlyInitialized() {return _flags.testAny(ExplicitlyInitialized);}
165
bool objectIsReferenced() {return _flags.testAny(ObjectIsReferenced);}
166
bool fillsInStackTrace() {return _flags.testAny(FillsInStackTrace);}
167
bool callsStringCopyConstructor() {return _flags.testAny(CallsStringCopy);}
168
bool isInsideALoop() {return _flags.testAny(InsideALoop);}
169
bool isInAColdBlock() {return _flags.testAny(InAColdBlock);}
170
bool isProfileOnly() {return _flags.testAny(ProfileOnly);}
171
172
bool usesStackTrace() {return _flags.testAny(UsesStackTrace);}
173
bool isArgToCall(int32_t depth) {return _argToCallFlags.testAny(1<<depth);}
174
bool isNonThisArgToCall(int32_t depth) {return _nonThisArgToCallFlags.testAny(1<<(depth));}
175
bool forceLocalAllocation() { return _flags.testAny(ForceLocalAllocation);}
176
177
void setForceLocalAllocation(bool v = true) {_flags.set(ForceLocalAllocation, v);}
178
void setLocalAllocation(bool v = true) {_flags.set(LocalAllocation, v);}
179
void setMustBeContiguousAllocation(bool v = true) {_flags.set(MustBeContiguous, v);}
180
void setExplicitlyInitialized(bool v = true) {_flags.set(ExplicitlyInitialized, v);}
181
void setObjectIsReferenced(bool v = true) {_flags.set(ObjectIsReferenced, v);}
182
void setFillsInStackTrace(bool v = true) {_flags.set(FillsInStackTrace, v);}
183
void setCallsStringCopyConstructor(bool v = true) {_flags.set(CallsStringCopy, v);}
184
void setInsideALoop(bool v = true) {_flags.set(InsideALoop, v); }
185
void setInAColdBlock(bool v = true) {_flags.set(InAColdBlock, v); }
186
void setProfileOnly(bool v = true) {_flags.set(ProfileOnly, v); }
187
188
void setUsesStackTrace(bool v = true) {_flags.set(UsesStackTrace, v);}
189
void setArgToCall(int32_t depth, bool v = true) {_argToCallFlags.set(1<<depth, v); if (v == true) _argToCall = true;}
190
void setNonThisArgToCall(int32_t depth, bool v = true) {_nonThisArgToCallFlags.set(1<<depth, v);}
191
192
193
TR::Node *getStringCopyNode() {return _stringCopyNode; }
194
void setStringCopyNode(TR::Node *n) { _stringCopyNode = n; }
195
196
bool isLockedObject() { return _lockedObject; }
197
void setLockedObject(bool b) {_lockedObject = b;}
198
199
bool usedInNonColdBlock() { return _usedInNonColdBlock; }
200
void setUsedInNonColdBlock(bool b = true) { _usedInNonColdBlock = b; }
201
202
bool lockedInNonColdBlock() { return _lockedInNonColdBlock; }
203
void setLockedInNonColdBlock(bool b = true) { _lockedInNonColdBlock = b; }
204
205
TR_ScratchList<TR::SymbolReference> *getSymRefs() { return &_symRefs; }
206
void addSymRef(TR::SymbolReference *symRef) { _symRefs.add(symRef); }
207
208
bool hasCallSites() { return !_callSites.isEmpty(); }
209
TR_ScratchList<TR::TreeTop> *getCallSites() { return &_callSites; }
210
void addCallSite(TR::TreeTop *treeTop) { _callSites.add(treeTop); }
211
212
bool hasVirtualCallsToBeFixed() {return !_virtualCallSitesToBeFixed.isEmpty();}
213
TR_ScratchList<TR::TreeTop> *getVirtualCallSitesToBeFixed() { return &_virtualCallSitesToBeFixed; }
214
void addVirtualCallSiteToBeFixed(TR::TreeTop *treeTop) { _virtualCallSitesToBeFixed.add(treeTop); }
215
bool escapesInColdBlocks() { return !_coldBlockEscapeInfo.isEmpty(); }
216
217
bool escapesInColdBlock(TR::Block *block)
218
{
219
ListElement<TR_ColdBlockEscapeInfo> *curColdBlockInfo = _coldBlockEscapeInfo.getListHead();
220
while (curColdBlockInfo)
221
{
222
if (curColdBlockInfo->getData()->getBlock() == block)
223
return true;
224
curColdBlockInfo = curColdBlockInfo->getNextElement();
225
}
226
return false;
227
}
228
229
TR_ScratchList<TR_ColdBlockEscapeInfo> *getColdBlockEscapeInfo() { return &_coldBlockEscapeInfo; }
230
void addColdBlockEscapeInfo(TR::Block *block, TR::Node *node, TR::TreeTop *tree)
231
{
232
ListElement<TR_ColdBlockEscapeInfo> *curColdBlockInfo = _coldBlockEscapeInfo.getListHead();
233
while (curColdBlockInfo)
234
{
235
if (curColdBlockInfo->getData()->getBlock() == block)
236
break;
237
curColdBlockInfo = curColdBlockInfo->getNextElement();
238
}
239
240
if (curColdBlockInfo)
241
{
242
curColdBlockInfo->getData()->addNode(node, tree);
243
}
244
else
245
{
246
TR_ColdBlockEscapeInfo *coldBlockInfo = new (trStackMemory()) TR_ColdBlockEscapeInfo(block, node, tree, trMemory());
247
_coldBlockEscapeInfo.add(coldBlockInfo);
248
}
249
}
250
251
void print();
252
253
TR::ILOpCodes _kind;
254
TR::ILOpCodes _origKind;
255
TR::Node *_node;
256
TR::TreeTop *_treeTop;
257
TR::Block *_block;
258
TR_Array<int32_t> *_valueNumbers;
259
TR_Array<FieldInfo> *_fields;
260
TR_BitVector *_initializedWords;
261
void *_class;
262
TR::Node *_originalAllocationNode;
263
TR::Compilation * _comp;
264
TR_Memory * _trMemory;
265
TR::Node *_stringCopyNode;
266
267
TR::TreeTop *_stringCopyCallTree;
268
269
TR::SymbolReference *_dememoizedMethodSymRef;
270
TR::TreeTop *_dememoizedConstructorCall;
271
272
TR_ScratchList<Candidate> _flushMovedFrom;
273
274
int32_t _size;
275
int32_t _fieldSize;
276
int32_t _origSize;
277
int32_t _maxInlineDepth;
278
int32_t _inlineBytecodeSize;
279
bool _seenFieldStore;
280
bool _seenSelfStore;
281
282
bool _seenStoreToLocalObject;
283
bool _seenArrayCopy;
284
bool _argToCall;
285
bool _isImmutable;
286
287
bool _lockedObject;
288
bool _flushRequired;
289
bool _usedInNonColdBlock;
290
bool _lockedInNonColdBlock;
291
int32_t _index;
292
293
protected:
294
295
TR_ScratchList<TR::SymbolReference> _symRefs;
296
TR_ScratchList<TR::TreeTop> _callSites;
297
TR_ScratchList<TR::TreeTop> _virtualCallSitesToBeFixed;
298
TR_ScratchList<TR_ColdBlockEscapeInfo> _coldBlockEscapeInfo;
299
flags32_t _flags;
300
flags16_t _nonThisArgToCallFlags;
301
flags16_t _argToCallFlags;
302
303
enum // flag bits
304
{
305
LocalAllocation = 0x80000000,
306
MustBeContiguous = 0x40000000,
307
ExplicitlyInitialized = 0x20000000,
308
ObjectIsReferenced = 0x10000000,
309
310
// Flags used for Throwable objects
311
//
312
FillsInStackTrace = 0x08000000,
313
UsesStackTrace = 0x04000000,
314
315
// Object that is being allocated inside a loop
316
//
317
InsideALoop = 0x02000000,
318
319
// Object that is in a cold block
320
//
321
InAColdBlock = 0x01000000,
322
323
// Object is an array whose length is not a constant, so we can't do
324
// anything with it in this EA pass, but continue analyzing it because
325
// if the unknown size is the ONLY reason we can't stack-allocate it,
326
// then we should add profiling trees.
327
//
328
ProfileOnly = 0x00800000,
329
330
331
// Object whose class has been annotated by user that
332
// any instance should be locally allocated (X10)
333
ForceLocalAllocation = 0x00100000,
334
335
CallsStringCopy = 0x00200000,
336
};
337
};
338
339
340
class FlushCandidate : public TR_Link<FlushCandidate>
341
{
342
public:
343
FlushCandidate(TR::TreeTop *flushNode, TR::Node *node, int32_t blockNum, Candidate *candidate = 0)
344
: _flushNode(flushNode), _node(node), _blockNum(blockNum), _candidate(candidate), _isKnownToLackCandidate(false)
345
{
346
}
347
348
TR::Node *getAllocation() {return _node;}
349
void setAllocation(TR::Node *node) {_node = node;}
350
351
TR::TreeTop *getFlush() {return _flushNode;}
352
void setFlush(TR::TreeTop *node) {_flushNode = node;}
353
354
int32_t getBlockNum() {return _blockNum;}
355
void setBlockNum(int32_t n) {_blockNum = n;}
356
357
Candidate *getCandidate() { return _candidate;}
358
void setCandidate(Candidate *c) {_candidate = c;}
359
360
/**
361
* \brief Indicates whether this \c FlushCandidate is known to have no
362
* candidate for stack allocation associated with it. That is, that
363
* the \ref getCandidate() method will always return \c NULL.
364
*
365
* \return \c true if this \c FlushCandidate is known to have no
366
* candidate for stack allocation associated with it;
367
* \c false if this \c FlushCandidate is known to have a candidate
368
* for stack allocation associated with it, or if it has not yet
369
* been determined whether there is a candidate for stack allocation
370
* associated with it.
371
*/
372
bool getIsKnownToLackCandidate() { return _isKnownToLackCandidate;}
373
374
/**
375
* \brief Sets the status of this \c FlushCandidate, indicating whether
376
* it is known to have no candidate for stack allocation associated with it.
377
*
378
* \param setting The updated status indicating whether this \c FlushCandidate
379
* is known to have no candidate for stack allocation associated with it
380
*/
381
void setIsKnownToLackCandidate(bool setting) {_isKnownToLackCandidate = setting;}
382
383
private:
384
TR::Node *_node;
385
TR::TreeTop *_flushNode;
386
int32_t _blockNum;
387
Candidate *_candidate;
388
bool _isKnownToLackCandidate;
389
};
390
391
392
class TR_DependentAllocations
393
{
394
public:
395
TR_ALLOC(TR_Memory::EscapeAnalysis)
396
397
TR_DependentAllocations(Candidate *allocNode, Candidate *dependentNode, TR_Memory * m)
398
: _allocNode(allocNode), _dependentNodes(m)
399
{
400
addDependentAllocation(dependentNode);
401
}
402
403
TR_ScratchList<Candidate> *getDependentAllocations() {return &_dependentNodes;}
404
void addDependentAllocation(Candidate *c)
405
{
406
if (c && !_dependentNodes.find(c))
407
_dependentNodes.add(c);
408
}
409
410
Candidate *getAllocation() {return _allocNode;}
411
void setAllocation(Candidate *node) {_allocNode = node;}
412
413
private:
414
Candidate *_allocNode;
415
TR_ScratchList<Candidate> _dependentNodes;
416
};
417
418
419
class TR_CFGEdgeAllocationPair
420
{
421
public:
422
TR_ALLOC(TR_Memory::EscapeAnalysis)
423
424
TR_CFGEdgeAllocationPair(TR::CFGEdge *edge, Candidate *allocNode)
425
: _allocNode(allocNode),
426
_edge(edge)
427
{
428
}
429
430
Candidate *getAllocation() {return _allocNode;}
431
void setAllocation(Candidate *node) {_allocNode = node;}
432
433
TR::CFGEdge *getEdge() {return _edge;}
434
void setEdge(TR::CFGEdge *edge) {_edge = edge;}
435
436
private:
437
Candidate *_allocNode;
438
TR::CFGEdge *_edge;
439
};
440
441
442
class SniffCallCache : public TR_Link<SniffCallCache>
443
{
444
public:
445
SniffCallCache(TR_ResolvedMethod *vmMethod, bool isCold, int32_t bytecodeSize)
446
: _vmMethod(vmMethod), _isCold(isCold), _bytecodeSize(bytecodeSize)
447
{
448
}
449
static bool isInCache(TR_LinkHead<SniffCallCache> *sniffCacheList, TR_ResolvedMethod *vmMethod, bool isCold, int32_t &bytecodeSize);
450
private:
451
TR_ResolvedMethod *_vmMethod;
452
bool _isCold;
453
int32_t _bytecodeSize;
454
};
455
456
class SymRefCache : public TR_Link<SymRefCache>
457
{
458
public:
459
SymRefCache(TR::SymbolReference *symRef, TR_ResolvedMethod *resolvedMethod)
460
: _symRef(symRef), _vmMethod(resolvedMethod)
461
{
462
}
463
static TR::SymbolReference* findSymRef(TR_LinkHead<SymRefCache> *symRefList, TR_ResolvedMethod *resolvedMethod);
464
TR::SymbolReference *getSymRef() {return _symRef;}
465
TR_ResolvedMethod *getMethod() {return _vmMethod;}
466
private:
467
TR::SymbolReference *_symRef;
468
TR_ResolvedMethod *_vmMethod;
469
};
470
471
class TR_EscapeAnalysis : public TR::Optimization
472
{
473
public:
474
475
TR_EscapeAnalysis(TR::OptimizationManager *manager);
476
static TR::Optimization *create(TR::OptimizationManager *manager)
477
{
478
return new (manager->allocator()) TR_EscapeAnalysis(manager);
479
}
480
481
virtual int32_t perform();
482
virtual const char * optDetailString() const throw();
483
484
protected:
485
486
enum restrictionType { MakeNonLocal, MakeContiguous, MakeObjectReferenced };
487
488
int32_t performAnalysisOnce();
489
void findCandidates();
490
void findIgnoreableUses();
491
void findIgnoreableUses(TR::Node *node, TR::NodeChecklist& visited);
492
void findLocalObjectsValueNumbers();
493
void findLocalObjectsValueNumbers(TR::Node *node, TR::NodeChecklist& visited);
494
495
Candidate *createCandidateIfValid(TR::Node *node, TR_OpaqueClassBlock *&classInfo,bool);
496
//int32_t checkForValidCandidate(TR::Node *node, TR_OpaqueClassBlock *&classInfo,bool);
497
bool collectValueNumbersOfIndirectAccessesToObject(TR::Node *node, Candidate *candidate, TR::Node *indirectStore, TR::NodeChecklist& visited, int32_t baseChildVN = -1);
498
void checkDefsAndUses();
499
bool checkDefsAndUses(TR::Node *node, Candidate *candidate);
500
501
/**
502
* Walk through trees looking for \c aselect operations. For the
503
* value operands of an \c aselect, populate \ref _nodeUsesThroughAselect
504
* with an entry mapping from the operand to a list containing the
505
* \c aselect nodes that refer to it.
506
*
507
* \see _nodeUsesThroughAselect
508
*/
509
void gatherUsesThroughAselect(void);
510
511
/**
512
* Recursive implementation method for \ref gatherUsesThroughAselect
513
*
514
* \param[in] node The root of the subtree that is to be processed
515
* \param[inout] visited A bit vector indicating whether a node has
516
* already been visited
517
*/
518
void gatherUsesThroughAselectImpl(TR::Node *node, TR::NodeChecklist& visited);
519
520
/**
521
* Add an entry to \ref _nodeUsesThroughAselect mapping from the child node
522
* of \c aselectNode at the specified index to the \c aselectNode itself.
523
*
524
* \param[in] aselectNode A node whose opcode is an \c aselect operation
525
* \param[in] idx The index of a child of \c aselectNode
526
*/
527
void associateAselectWithChild(TR::Node *aselectNode, int32_t idx);
528
529
/**
530
* Trace contents of \ref _nodeUsesThroughAselect
531
*/
532
void printUsesThroughAselect(void);
533
534
/**
535
* Check whether \c node, which is a use of the candidate for stack
536
* allocation, \c candidate, is itself used as one of the value operands
537
* in an \c aselect operation, as found in \ref _nodeUsesThroughAselect.
538
* If it is, the value number of any such \c aselect is added to the list
539
* of value numbers associated with the candidate.
540
*
541
* \param[in] node The use of \c candidate that is under consideration
542
* \param[in] candidate A candidate for stack allocation
543
*/
544
bool checkUsesThroughAselect(TR::Node *node, Candidate *candidate);
545
bool checkOtherDefsOfLoopAllocation(TR::Node *useNode, Candidate *candidate, bool isImmediateUse);
546
bool checkOverlappingLoopAllocation(TR::Node *useNode, Candidate *candidate);
547
bool checkOverlappingLoopAllocation(TR::Node *node, TR::Node *useNode, TR::Node *allocNode, rcount_t &numReferences);
548
549
/**
550
* Visit nodes in the subtree, keeping track of those visited in
551
* @ref _visitedNodes
552
* @param[in] node The subtree that is to be visited
553
*/
554
void visitTree(TR::Node *node);
555
556
/**
557
* Collect aliases of an allocation node in the specified subtree
558
* in @ref _aliasesOfOtherAllocNode
559
* Nodes in the subtree that are visited are tracked in
560
* @ref _visitedNodes, and those that have been marked as already visited
561
* are skipped.
562
* @param[in] node The subtree that is to be visited
563
* @param[in] allocNode The allocation node whose aliases are to be collected
564
*/
565
void collectAliasesOfAllocations(TR::Node *node, TR::Node *allocNode);
566
567
bool checkAllNewsOnRHSInLoop(TR::Node *defNode, TR::Node *useNode, Candidate *candidate);
568
bool checkAllNewsOnRHSInLoopWithAliasing(int32_t defIndex, TR::Node *useNode, Candidate *candidate);
569
bool usesValueNumber(Candidate *candidate, int32_t valueNumber);
570
Candidate *findCandidate(int32_t valueNumber);
571
572
573
bool detectStringCopy(TR::Node *node);
574
void markCandidatesUsedInNonColdBlock(TR::Node *node);
575
576
bool checkIfUseIsInLoopAndOverlapping(Candidate *candidate, TR::TreeTop *defTree, TR::Node *useNode);
577
bool checkIfUseIsInLoopAndOverlapping(TR::TreeTop *start, TR::TreeTop *end, TR::TreeTop *defTree, TR::Node *useNode, TR::NodeChecklist& visited, TR::BlockChecklist& vBlocks, bool & decisionMade);
578
bool checkUse(TR::Node *node, TR::Node *useNode, TR::NodeChecklist& visited);
579
bool checkIfUseIsInSameLoopAsDef(TR::TreeTop *defTree, TR::Node *useNode);
580
581
bool isEscapePointCold(Candidate *candidate, TR::Node *node);
582
bool checkIfEscapePointIsCold(Candidate *candidate, TR::Node *node);
583
void forceEscape(TR::Node *node, TR::Node *reason, bool forceFail = false);
584
bool restrictCandidates(TR::Node *node, TR::Node *reason, restrictionType);
585
//void referencedField(TR::Node *base, TR::Node *field, bool isStore, bool seenSelfStore = false);
586
void referencedField(TR::Node *base, TR::Node *field, bool isStore, bool seenSelfStore = false, bool seenStoreToLocalObject = false);
587
TR::Node *resolveSniffedNode(TR::Node *node);
588
void checkEscape(TR::TreeTop *firstTree, bool isCold, bool & ignoreRecursion);
589
void checkEscapeViaNonCall(TR::Node *node, TR::NodeChecklist& visited);
590
void checkEscapeViaCall(TR::Node *node, TR::NodeChecklist& visited, bool & ignoreRecursion);
591
int32_t sniffCall(TR::Node *callNode, TR::ResolvedMethodSymbol *methodSymbol, bool ignoreOpCode, bool isCold, bool & ignoreRecursion);
592
void checkObjectSizes();
593
void fixupTrees();
594
void anchorCandidateReference(Candidate *candidate, TR::Node *reference);
595
bool fixupNode(TR::Node *node, TR::Node *parent, TR::NodeChecklist& visited);
596
bool fixupFieldAccessForContiguousAllocation(TR::Node *node, Candidate *candidate);
597
bool fixupFieldAccessForNonContiguousAllocation(TR::Node *node, Candidate *candidate, TR::Node *parent);
598
void makeLocalObject(Candidate *candidate);
599
void avoidStringCopyAllocation(Candidate *candidate);
600
601
/** \brief
602
* Attempts to zero initialize a stack allocated candidate using TR::arrayset.
603
*
604
* \param candidate
605
* The candidate to zero initialize.
606
*
607
* \param precedingTreeTop
608
* The preceding tree top to which the TR::arrayset will be attached to.
609
*
610
* \return
611
* true if a TR::arrayset was emitted to zero initialize the candidate; false otherwise.
612
*/
613
bool tryToZeroInitializeUsingArrayset(Candidate* candidate, TR::TreeTop* precedingTreeTop);
614
615
void makeContiguousLocalAllocation(Candidate *candidate);
616
void makeNonContiguousLocalAllocation(Candidate *candidate);
617
void heapifyForColdBlocks(Candidate *candidate);
618
619
/**
620
* \brief Store the supplied address to the specified temporary
621
*
622
* \param candidate
623
* The candidate that is being heapified
624
*
625
* \param addr
626
* The address of the possibly heapified object
627
*
628
* \param symRef
629
* The \ref TR::SymbolReference for the temporay
630
*
631
* \return A pointer to the \ref TR::TreeTop containing the store
632
*/
633
TR::TreeTop *storeHeapifiedToTemp(Candidate *candidate, TR::Node *addr, TR::SymbolReference *symRef);
634
bool inlineCallSites();
635
void scanForExtraCallsToInline();
636
bool alwaysWorthInlining(TR::Node *callNode);
637
bool devirtualizeCallSites();
638
bool hasFlushOnEntry(int32_t blockNum) {if (_blocksWithFlushOnEntry->get(blockNum)) return true; return false;}
639
void setHasFlushOnEntry(int32_t blockNum) {_blocksWithFlushOnEntry->set(blockNum);}
640
void rememoize(Candidate *c, bool mayDememoizeNextTime=false);
641
642
void printCandidates(char *);
643
644
char *getClassName(TR::Node *classNode);
645
646
bool isImmutableObject(TR::Node *node);
647
bool isImmutableObject(Candidate *candidate);
648
649
TR::Node *createConst(TR::Compilation *comp, TR::Node *node, TR::DataType type, int value);
650
651
struct TR_CallSitesFixedMapper : public TR_Link<TR_CallSitesFixedMapper>
652
{
653
TR_CallSitesFixedMapper(TR::TreeTop * virtualCallSite, TR::TreeTop * directCallSite)
654
: _vCallSite(virtualCallSite), _dCallSite(directCallSite){ }
655
656
TR::TreeTop * _vCallSite;
657
TR::TreeTop * _dCallSite;
658
};
659
660
class PersistentData : public TR::OptimizationData
661
{
662
public:
663
PersistentData(TR::Compilation *comp)
664
: TR::OptimizationData(comp),
665
_totalInlinedBytecodeSize(0),
666
_totalPeekedBytecodeSize(0)
667
{
668
_symRefList.setFirst(NULL);
669
_peekableCalls = new (comp->trHeapMemory()) TR_BitVector(0, comp->trMemory(), heapAlloc);
670
_processedCalls = new (comp->trHeapMemory()) TR_BitVector(0, comp->trMemory(), heapAlloc);
671
}
672
673
int32_t _totalInlinedBytecodeSize;
674
int32_t _totalPeekedBytecodeSize;
675
TR_BitVector *_peekableCalls;
676
TR_BitVector *_processedCalls;
677
TR_LinkHead<SymRefCache> _symRefList;
678
};
679
680
PersistentData * getOptData() { return (PersistentData *) manager()->getOptData(); }
681
682
//TR::TreeTop *findCallSiteFixed(TR::TreeTop * virtualCallSite);
683
bool findCallSiteFixed(TR::TreeTop * virtualCallSite);
684
685
TR::SymbolReference *_newObjectNoZeroInitSymRef;
686
TR::SymbolReference *_newArrayNoZeroInitSymRef;
687
TR::SymbolReference *_aNewArrayNoZeroInitSymRef;
688
TR_UseDefInfo *_useDefInfo;
689
bool _invalidateUseDefInfo;
690
TR_BitVector *_otherDefsForLoopAllocation;
691
TR_BitVector *_ignoreableUses;
692
TR_BitVector *_nonColdLocalObjectsValueNumbers;
693
TR_BitVector *_allLocalObjectsValueNumbers;
694
TR_BitVector *_notOptimizableLocalObjectsValueNumbers;
695
TR_BitVector *_notOptimizableLocalStringObjectsValueNumbers;
696
TR_BitVector *_blocksWithFlushOnEntry;
697
TR_BitVector *_visitedNodes;
698
699
CallLoadMap *_callsToProtect;
700
701
/**
702
* Contains sym refs that are just aliases for a fresh allocation
703
* i.e., it is used to track allocations in cases such as
704
* ...
705
* a = new A()
706
* ...
707
* b = a
708
* ...
709
* c = b
710
*
711
* In this case a, b and c will all be considered aliases of an alloc node
712
* and so a load of any of those sym refs will be treated akin to how the
713
* fresh allocation would be treated
714
*/
715
TR_BitVector *_aliasesOfAllocNode;
716
717
/**
718
* Contains sym refs that are just aliases for a second fresh allocation
719
* that is under consideration, as with @ref _aliasesOfAllocNode
720
*/
721
TR_BitVector *_aliasesOfOtherAllocNode;
722
TR_ValueNumberInfo *_valueNumberInfo;
723
TR_LinkHead<Candidate> _candidates;
724
TR_Array<TR::Node*> *_parms;
725
TR_ScratchList<TR::TreeTop> _inlineCallSites;
726
TR_ScratchList<TR::TreeTop> _devirtualizedCallSites;
727
TR_LinkHead<TR_CallSitesFixedMapper> _fixedVirtualCallSites;
728
729
List<TR::Node> _dememoizedAllocs;
730
TR::SymbolReference *_dememoizationSymRef;
731
732
TR::Block *_curBlock;
733
TR::TreeTop *_curTree;
734
int32_t _sniffDepth;
735
int32_t _maxSniffDepth;
736
int32_t _maxPassNumber;
737
TR::ResolvedMethodSymbol *_methodSymbol;
738
bool _inBigDecimalAdd;
739
int32_t _maxInlinedBytecodeSize;
740
int32_t _maxPeekedBytecodeSize;
741
bool _inColdBlock;
742
bool _createStackAllocations;
743
bool _createLocalObjects;
744
bool _desynchronizeCalls;
745
bool _classObjectLoadForVirtualCall;
746
#if CHECK_MONITORS
747
bool _removeMonitors;
748
#endif
749
bool _repeatAnalysis;
750
bool _somethingChanged;
751
bool _doLoopAllocationAliasChecking;
752
TR_ScratchList<TR_DependentAllocations> _dependentAllocations;
753
TR_BitVector * _vnTemp;
754
TR_BitVector * _vnTemp2;
755
756
typedef TR::typed_allocator<TR::Node *, TR::Region &> NodeDequeAllocator;
757
typedef std::deque<TR::Node *, NodeDequeAllocator> NodeDeque;
758
759
typedef TR::typed_allocator<std::pair<TR::Node* const, NodeDeque*>, TR::Region&> NodeToNodeDequeMapAllocator;
760
typedef std::less<TR::Node*> NodeComparator;
761
typedef std::map<TR::Node*, NodeDeque*, NodeComparator, NodeToNodeDequeMapAllocator> NodeToNodeDequeMap;
762
763
/**
764
* A mapping from nodes to a \c deque of \c aselect nodes that directly
765
* reference them.
766
*/
767
NodeToNodeDequeMap * _nodeUsesThroughAselect;
768
769
friend class TR_FlowSensitiveEscapeAnalysis;
770
friend class TR_LocalFlushElimination;
771
friend struct FieldInfo;
772
};
773
774
//class Candidate;
775
//class TR_EscapeAnalysis;
776
//class TR_DependentAllocations;
777
778
class TR_LocalFlushElimination
779
{
780
public:
781
TR_ALLOC(TR_Memory::LocalOpts)
782
TR_LocalFlushElimination(TR_EscapeAnalysis *, int32_t numAllocations);
783
784
virtual int32_t perform();
785
bool examineNode(TR::Node *, TR::NodeChecklist& visited);
786
787
TR::Optimizer * optimizer() { return _escapeAnalysis->optimizer(); }
788
TR::Compilation * comp() { return _escapeAnalysis->comp(); }
789
790
TR_Memory * trMemory() { return comp()->trMemory(); }
791
TR_StackMemory trStackMemory() { return comp()->trStackMemory(); }
792
793
bool trace() { return _escapeAnalysis->trace(); }
794
795
private:
796
TR_LinkHead<Candidate> *_candidates;
797
TR_LinkHead<FlushCandidate> *_flushCandidates;
798
TR_EscapeAnalysis *_escapeAnalysis;
799
int32_t _numAllocations;
800
TR_BitVector *_allocationInfo;
801
TR_BitVector *_temp;
802
TR_ScratchList<TR_DependentAllocations> _dependentAllocations;
803
};
804
805
806
807
#if CHECK_MONITORS
808
class TR_MonitorStructureChecker
809
{
810
public:
811
TR_ALLOC(TR_Memory::EscapeAnalysis)
812
TR_MonitorStructureChecker() {}
813
814
// returns true if illegal structure is found
815
bool checkMonitorStructure(TR::CFG *cfg);
816
817
private:
818
void processBlock(TR::Block *block);
819
void propagateInfoTo(TR::Block *block, int32_t inInfo);
820
821
int32_t *_blockInfo;
822
TR_BitVector *_seenNodes;
823
bool _foundIllegalStructure;
824
};
825
826
#endif
827
#endif
828
829
830
831
832
833
834
835
836
837
838