Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/EscapeAnalysis.cpp
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
#ifdef J9ZTPF
24
#define __TPF_DO_NOT_MAP_ATOE_REMOVE
25
#endif
26
27
#include "optimizer/EscapeAnalysis.hpp"
28
#include "optimizer/EscapeAnalysisTools.hpp"
29
30
#include <algorithm>
31
#include <stdint.h>
32
#include <stdio.h>
33
#include <string.h>
34
#include "codegen/CodeGenerator.hpp"
35
#include "env/FrontEnd.hpp"
36
#include "codegen/RecognizedMethods.hpp"
37
#include "compile/Compilation.hpp"
38
#include "compile/CompilationTypes.hpp"
39
#include "compile/Method.hpp"
40
#include "compile/ResolvedMethod.hpp"
41
#include "compile/SymbolReferenceTable.hpp"
42
#include "compile/VirtualGuard.hpp"
43
#include "control/Options.hpp"
44
#include "control/Options_inlines.hpp"
45
#include "control/Recompilation.hpp"
46
#include "control/RecompilationInfo.hpp"
47
#include "cs2/bitvectr.h"
48
#include "env/CompilerEnv.hpp"
49
#include "env/ObjectModel.hpp"
50
#include "env/TRMemory.hpp"
51
#include "env/jittypes.h"
52
#include "env/VMAccessCriticalSection.hpp"
53
#include "env/VMJ9.h"
54
#include "il/AliasSetInterface.hpp"
55
#include "il/AutomaticSymbol.hpp"
56
#include "il/Block.hpp"
57
#include "il/DataTypes.hpp"
58
#include "il/ILOpCodes.hpp"
59
#include "il/ILOps.hpp"
60
#include "il/MethodSymbol.hpp"
61
#include "il/Node.hpp"
62
#include "il/Node_inlines.hpp"
63
#include "il/ParameterSymbol.hpp"
64
#include "il/ResolvedMethodSymbol.hpp"
65
#include "il/StaticSymbol.hpp"
66
#include "il/Symbol.hpp"
67
#include "il/SymbolReference.hpp"
68
#include "il/TreeTop.hpp"
69
#include "il/TreeTop_inlines.hpp"
70
#include "infra/Array.hpp"
71
#include "infra/Assert.hpp"
72
#include "infra/BitVector.hpp"
73
#include "infra/Cfg.hpp"
74
#include "infra/Checklist.hpp"
75
#include "infra/Link.hpp"
76
#include "infra/List.hpp"
77
#include "infra/SimpleRegex.hpp"
78
#include "infra/TRCfgEdge.hpp"
79
#include "infra/TRCfgNode.hpp"
80
#include "optimizer/Inliner.hpp"
81
#include "optimizer/Optimization.hpp"
82
#include "optimizer/OptimizationManager.hpp"
83
#include "optimizer/Optimizations.hpp"
84
#include "optimizer/Optimizer.hpp"
85
#include "optimizer/Structure.hpp"
86
#include "optimizer/TransformUtil.hpp"
87
#include "optimizer/DataFlowAnalysis.hpp"
88
#include "optimizer/UseDefInfo.hpp"
89
#include "optimizer/ValueNumberInfo.hpp"
90
#include "optimizer/LocalOpts.hpp"
91
#include "optimizer/MonitorElimination.hpp"
92
#include "ras/Debug.hpp"
93
#include "runtime/J9Profiler.hpp"
94
#include "runtime/J9Runtime.hpp"
95
96
#define OPT_DETAILS "O^O ESCAPE ANALYSIS: "
97
98
#define MAX_SIZE_FOR_ONE_CONTIGUOUS_OBJECT 2416 // Increased from 72
99
#define MAX_SIZE_FOR_ALL_OBJECTS 3000 // Increased from 500
100
#define MAX_SNIFF_BYTECODE_SIZE 1600
101
102
#define LOCAL_OBJECTS_COLLECTABLE 1
103
104
extern void createGuardSiteForRemovedGuard(TR::Compilation *comp, TR::Node* ifNode);
105
106
static bool blockIsInLoop(TR::Block *block)
107
{
108
for (TR_Structure *s = block->getStructureOf()->getParent(); s; s = s->getParent())
109
{
110
TR_RegionStructure *region = s->asRegion();
111
if (region->isNaturalLoop() || region->containsInternalCycles())
112
return true;
113
}
114
return false;
115
}
116
117
TR_EscapeAnalysis::TR_EscapeAnalysis(TR::OptimizationManager *manager)
118
: TR::Optimization(manager),
119
_newObjectNoZeroInitSymRef(NULL),
120
_newArrayNoZeroInitSymRef(NULL),
121
_dependentAllocations(manager->comp()->trMemory()),
122
_inlineCallSites(manager->comp()->trMemory()),
123
_dememoizedAllocs(manager->comp()->trMemory()),
124
_devirtualizedCallSites(manager->comp()->trMemory()),
125
_aNewArrayNoZeroInitSymRef(NULL)
126
{
127
128
_newObjectNoZeroInitSymRef = comp()->getSymRefTab()->findOrCreateNewObjectNoZeroInitSymbolRef(0);
129
_newArrayNoZeroInitSymRef = comp()->getSymRefTab()->findOrCreateNewArrayNoZeroInitSymbolRef(0);
130
_aNewArrayNoZeroInitSymRef = comp()->getSymRefTab()->findOrCreateANewArrayNoZeroInitSymbolRef(0);
131
_maxPassNumber = 0;
132
133
_dememoizationSymRef = NULL;
134
135
_createStackAllocations = true;
136
_createLocalObjects = cg()->supportsStackAllocations();
137
_desynchronizeCalls = true;
138
#if CHECK_MONITORS
139
/* monitors */
140
_removeMonitors = true;
141
#endif
142
143
static char *disableLoopAliasAllocationChecking = feGetEnv("TR_disableEALoopAliasAllocationChecking");
144
_doLoopAllocationAliasChecking = (disableLoopAliasAllocationChecking == NULL);
145
}
146
147
char *TR_EscapeAnalysis::getClassName(TR::Node *classNode)
148
{
149
char *className = NULL;
150
151
if (classNode->getOpCodeValue() == TR::loadaddr)
152
{
153
TR::SymbolReference *symRef = classNode->getSymbolReference();
154
155
if (symRef->getSymbol()->isClassObject())
156
{
157
int32_t classNameLength;
158
char *classNameChars = TR::Compiler->cls.classNameChars(comp(), symRef, classNameLength);
159
160
if (NULL != classNameChars)
161
{
162
className = (char *)trMemory()->allocateStackMemory(classNameLength+1, TR_Memory::EscapeAnalysis);
163
memcpy(className, classNameChars, classNameLength);
164
className[classNameLength] = 0;
165
}
166
}
167
}
168
return className;
169
}
170
171
bool TR_EscapeAnalysis::isImmutableObject(TR::Node *node)
172
{
173
// For debugging issues with the special handling of immutable objects
174
// that allows them to be discontiguously allocated even if they escape
175
static char *disableImmutableObjectHandling = feGetEnv("TR_disableEAImmutableObjectHandling");
176
177
if (disableImmutableObjectHandling)
178
{
179
return false;
180
}
181
182
if (node->getOpCodeValue() != TR::New)
183
{
184
return false;
185
}
186
187
char *className = getClassName(node->getFirstChild());
188
189
if (NULL != className &&
190
!strncmp("java/lang/", className, 10) &&
191
(!strcmp("Integer", &className[10]) ||
192
!strcmp("Long", &className[10]) ||
193
!strcmp("Short", &className[10]) ||
194
!strcmp("Byte", &className[10]) ||
195
!strcmp("Boolean", &className[10]) ||
196
!strcmp("Character", &className[10]) ||
197
!strcmp("Double", &className[10]) ||
198
!strcmp("Float", &className[10])))
199
{
200
return true;
201
}
202
203
204
return false;
205
}
206
207
bool TR_EscapeAnalysis::isImmutableObject(Candidate *candidate)
208
{
209
if (candidate->_isImmutable)
210
return true;
211
212
bool b = isImmutableObject(candidate->_node);
213
candidate->_isImmutable = b;
214
return b;
215
}
216
217
218
219
int32_t TR_EscapeAnalysis::perform()
220
{
221
if (comp()->isOptServer() && (comp()->getMethodHotness() <= warm))
222
return 0;
223
224
// EA generates direct stores/loads to instance field which is different
225
// from a normal instance field read/write. Field watch would need special handling
226
// for stores/loads generated by EA.
227
if (comp()->incompleteOptimizerSupportForReadWriteBarriers())
228
return 0;
229
230
static char *doESCNonQuiet = feGetEnv("TR_ESCAPENONQUIET");
231
if (doESCNonQuiet && comp()->getOutFile() == NULL)
232
return 0;
233
234
int32_t nodeCount = 0;
235
vcount_t visitCount = comp()->incVisitCount(); //@TODO: needs a change to TR_Node's
236
//countNumberOfNodesInSubtree
237
//we should probably leave it as is
238
//for the next iteration
239
TR::TreeTop *tt = comp()->getStartTree();
240
for (; tt; tt = tt->getNextTreeTop())
241
nodeCount += tt->getNode()->countNumberOfNodesInSubtree(visitCount);
242
243
// Set thresholds depending on the method's hotness
244
//
245
TR_Hotness methodHotness = comp()->getMethodHotness();
246
if (methodHotness > hot)
247
{
248
_maxPassNumber = 6;
249
_maxSniffDepth = 8;
250
_maxInlinedBytecodeSize = 5000 - nodeCount;
251
}
252
else
253
{
254
_maxPassNumber = 3;
255
//_maxPassNumber = (methodHotness < hot) ? 2 : 3;
256
_maxSniffDepth = 4;
257
_maxInlinedBytecodeSize = 4000 - nodeCount;
258
}
259
260
// under HCR we can protect the top level sniff with an HCR guard
261
// nested sniffs are not currently supported
262
if (comp()->getHCRMode() != TR::none)
263
_maxSniffDepth = 1;
264
265
TR_ASSERT_FATAL(_maxSniffDepth < 16, "The argToCall and nonThisArgToCall flags are 16 bits - a depth limit greater than 16 will not fit in these flags");
266
267
if (getLastRun())
268
_maxPassNumber = 0; // Notwithstanding our heuristics, if this is the last run, our max "pass number" is zero (which is the first pass)
269
270
_maxPeekedBytecodeSize = comp()->getMaxPeekedBytecodeSize();
271
272
// Escape analysis is organized so that it may decide another pass of
273
// the analysis is required immediately after the current one. It leaves
274
// it up to the optimization strategy to re-invoke the analysis, but we
275
// keep track here of the number of passes through the analysis so we
276
// can restrict the number of passes. Each time we end the local loop of
277
// passes the current pass number is reset to zero in case escape analysis
278
// is called again later in the optimization strategy.
279
//
280
if (manager()->numPassesCompleted() == 0)
281
{
282
//
283
void *data = manager()->getOptData();
284
TR_BitVector *peekableCalls = NULL;
285
if (data != NULL)
286
{
287
peekableCalls = ((TR_EscapeAnalysis::PersistentData *)data)->_peekableCalls;
288
delete ((TR_EscapeAnalysis::PersistentData *) data) ;
289
manager()->setOptData(NULL);
290
}
291
manager()->setOptData(new (comp()->allocator()) TR_EscapeAnalysis::PersistentData(comp()));
292
if (peekableCalls != NULL)
293
((TR_EscapeAnalysis::PersistentData *)manager()->getOptData())->_peekableCalls = peekableCalls;
294
}
295
else
296
{
297
if (trace())
298
{
299
/////printf("secs Performing pass %d of Escape Analysis for %s\n", _currentPass, comp()->signature());
300
}
301
}
302
303
int32_t cost = 0;
304
305
{
306
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
307
_callsToProtect = new (trStackMemory()) CallLoadMap(CallLoadMapComparator(), comp()->trMemory()->currentStackRegion());
308
309
#if CHECK_MONITORS
310
/* monitors */
311
TR_MonitorStructureChecker inspector;
312
if (inspector.checkMonitorStructure(comp()->getFlowGraph()))
313
{
314
_removeMonitors = false;
315
if (trace())
316
traceMsg(comp(), "Disallowing monitor-removal because of strange monitor structure\n");
317
}
318
#endif
319
320
cost = performAnalysisOnce();
321
322
if (!_callsToProtect->empty() && manager()->numPassesCompleted() < _maxPassNumber)
323
{
324
TR::CFG *cfg = comp()->getFlowGraph();
325
TR::Block *block = NULL;
326
TR::TreeTop *lastTree = comp()->findLastTree();
327
TR_EscapeAnalysisTools tools(comp());
328
RemainingUseCountMap *remainingUseCount = new (comp()->trStackMemory()) RemainingUseCountMap(RemainingUseCountMapComparator(), comp()->trMemory()->currentStackRegion());
329
for (TR::TreeTop *tt = comp()->findLastTree(); tt != NULL; tt = tt->getPrevTreeTop())
330
{
331
TR::Node *node = tt->getNode();
332
if (node->getOpCodeValue() == TR::BBEnd)
333
block = node->getBlock();
334
else if (node->getStoreNode() && node->getStoreNode()->getOpCode().isStoreDirect())
335
node = node->getStoreNode()->getFirstChild();
336
else if (node->getOpCode().isCheck() || node->getOpCode().isAnchor() || node->getOpCodeValue() == TR::treetop)
337
node = node->getFirstChild();
338
339
auto nodeLookup = _callsToProtect->find(node);
340
if (nodeLookup == _callsToProtect->end()
341
|| TR_EscapeAnalysisTools::isFakeEscape(node)
342
|| node->getSymbol() == NULL
343
|| node->getSymbol()->getResolvedMethodSymbol() == NULL
344
|| node->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod() == NULL)
345
continue;
346
347
if (node->getReferenceCount() > 1)
348
{
349
auto useCount = remainingUseCount->find(node);
350
if (useCount == remainingUseCount->end())
351
{
352
(*remainingUseCount)[node] = node->getReferenceCount() - 1;
353
continue;
354
}
355
if (useCount->second > 1)
356
{
357
useCount->second -= 1;
358
continue;
359
}
360
}
361
362
if (!performTransformation(comp(), "%sHCR CALL PEEKING: Protecting call [%p] n%dn with an HCR guard and escape helper\n", OPT_DETAILS, node, node->getGlobalIndex()))
363
continue;
364
365
((TR_EscapeAnalysis::PersistentData*)manager()->getOptData())->_processedCalls->set(node->getGlobalIndex());
366
367
_repeatAnalysis = true;
368
369
optimizer()->setValueNumberInfo(NULL);
370
cfg->invalidateStructure();
371
372
TR::TreeTop *prevTT = tt->getPrevTreeTop();
373
TR::Block *callBlock = block->split(tt, comp()->getFlowGraph(), true, true);
374
375
// check uncommoned nodes for stores of the candidate - if so we need to add the new temp to the
376
// list of loads
377
for (TR::TreeTop *itr = block->getExit(); itr != prevTT; itr = itr->getPrevTreeTop())
378
{
379
TR::Node *storeNode = itr->getNode()->getStoreNode();
380
if (storeNode
381
&& storeNode->getOpCodeValue() == TR::astore
382
&& nodeLookup->second.first->get(storeNode->getFirstChild()->getGlobalIndex()))
383
nodeLookup->second.second->push_back(TR::Node::createWithSymRef(TR::aload, 0, storeNode->getSymbolReference()));
384
}
385
386
TR::Node *guard = TR_VirtualGuard::createHCRGuard(comp(),
387
node->getByteCodeInfo().getCallerIndex(),
388
node,
389
NULL,
390
node->getSymbol()->getResolvedMethodSymbol(),
391
node->getSymbol()->getResolvedMethodSymbol()->getResolvedMethod()->classOfMethod());
392
block->getExit()->insertBefore(TR::TreeTop::create(comp(), guard));
393
394
TR::Block *heapificationBlock = TR::Block::createEmptyBlock(node, comp(), MAX_COLD_BLOCK_COUNT);
395
heapificationBlock->getExit()->join(lastTree->getNextTreeTop());
396
lastTree->join(heapificationBlock->getEntry());
397
lastTree = heapificationBlock->getExit();
398
heapificationBlock->setIsCold();
399
400
guard->setBranchDestination(heapificationBlock->getEntry());
401
cfg->addNode(heapificationBlock);
402
cfg->addEdge(block, heapificationBlock);
403
cfg->addEdge(heapificationBlock, callBlock);
404
405
heapificationBlock->getExit()->insertBefore(TR::TreeTop::create(comp(), TR::Node::create(node, TR::Goto, 0, callBlock->getEntry())));
406
tools.insertFakeEscapeForLoads(heapificationBlock, node, nodeLookup->second.second);
407
traceMsg(comp(), "Created heapification block_%d\n", heapificationBlock->getNumber());
408
409
((TR_EscapeAnalysis::PersistentData*)manager()->getOptData())->_peekableCalls->set(node->getGlobalIndex());
410
_callsToProtect->erase(nodeLookup);
411
tt = prevTT->getNextTreeTop();
412
}
413
}
414
} // scope of the stack memory region
415
416
if (_repeatAnalysis && manager()->numPassesCompleted() < _maxPassNumber)
417
{
418
// Ask the optimizer to repeat this analysis
419
//
420
requestOpt(OMR::eachEscapeAnalysisPassGroup);
421
manager()->incNumPassesCompleted();
422
}
423
else
424
{
425
// Don't repeat this analysis, reset the pass count for next time
426
//
427
manager()->setNumPassesCompleted(0);
428
}
429
430
return cost;
431
}
432
433
const char *
434
TR_EscapeAnalysis::optDetailString() const throw()
435
{
436
return "O^O ESCAPE ANALYSIS: ";
437
}
438
439
void TR_EscapeAnalysis::rememoize(Candidate *candidate, bool mayDememoizeNextTime)
440
{
441
if (!candidate->_dememoizedConstructorCall)
442
return;
443
444
TR_ASSERT(candidate->_treeTop->getEnclosingBlock() == candidate->_dememoizedConstructorCall->getEnclosingBlock(),
445
"Dememoized constructor call %p must be in the same block as allocation %p", candidate->_treeTop->getNode(), candidate->_dememoizedConstructorCall->getNode());
446
if (trace())
447
traceMsg(comp(), " Rememoizing%s [%p] using constructor call [%p]\n", mayDememoizeNextTime?"":" and inlining", candidate->_node, candidate->_dememoizedConstructorCall->getNode()->getFirstChild());
448
449
// Change trees back
450
//
451
candidate->_node->getFirstChild()->recursivelyDecReferenceCount(); // remove loadaddr of class
452
candidate->_node->setAndIncChild(0, candidate->_dememoizedConstructorCall->getNode()->getFirstChild()->getSecondChild()); // original call argument
453
TR::Node::recreate(candidate->_node, TR::acall);
454
candidate->_node->setSymbolReference(candidate->_dememoizedMethodSymRef);
455
candidate->_dememoizedConstructorCall->unlink(true);
456
457
// Only rememoize once
458
//
459
_inlineCallSites.remove(candidate->_dememoizedConstructorCall);
460
candidate->_dememoizedConstructorCall = NULL;
461
candidate->_dememoizedMethodSymRef = NULL;
462
463
if (!mayDememoizeNextTime)
464
{
465
// Inline the memoization method so we can apply EA to it even though dememoization failed.
466
// This also prevents us from re-trying dememoization when it's hopeless.
467
//
468
_inlineCallSites.add(candidate->_treeTop);
469
}
470
}
471
472
static const char *ynmString(TR_YesNoMaybe arg)
473
{
474
switch (arg)
475
{
476
case TR_yes:
477
return "yes";
478
case TR_no:
479
return "no";
480
case TR_maybe:
481
return "maybe";
482
}
483
return "";
484
}
485
486
static TR_YesNoMaybe ynmOr(TR_YesNoMaybe left, TR_YesNoMaybe right)
487
{
488
switch (left)
489
{
490
case TR_yes:
491
return TR_yes;
492
case TR_no:
493
return right;
494
case TR_maybe:
495
return (right == TR_yes)? TR_yes : TR_maybe;
496
}
497
return TR_maybe;
498
}
499
500
static TR_YesNoMaybe candidateHasField(Candidate *candidate, TR::Node *fieldNode, int32_t fieldOffset, TR_EscapeAnalysis *ea)
501
{
502
TR::Compilation *comp = ea->comp();
503
TR::SymbolReference *fieldSymRef = fieldNode->getSymbolReference();
504
int32_t fieldSize = fieldNode->getSize();
505
506
int32_t minHeaderSize, maxHeaderSize;
507
if (candidate->_origKind == TR::New)
508
{
509
minHeaderSize = maxHeaderSize = comp->fej9()->getObjectHeaderSizeInBytes();
510
}
511
else
512
{
513
minHeaderSize = std::min(TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), TR::Compiler->om.discontiguousArrayHeaderSizeInBytes());
514
maxHeaderSize = std::max(TR::Compiler->om.contiguousArrayHeaderSizeInBytes(), TR::Compiler->om.discontiguousArrayHeaderSizeInBytes());
515
}
516
517
TR_YesNoMaybe withinObjectBound = TR_maybe;
518
TR_YesNoMaybe withinObjectHeader = TR_maybe;
519
TR_YesNoMaybe belongsToAllocatedClass = TR_maybe;
520
TR_YesNoMaybe result = TR_maybe;
521
522
if (fieldOffset + fieldSize <= candidate->_size)
523
withinObjectBound = TR_yes;
524
else
525
withinObjectBound = TR_no;
526
527
if (fieldOffset + fieldSize <= minHeaderSize)
528
withinObjectHeader = TR_yes;
529
else if (fieldOffset > maxHeaderSize)
530
withinObjectHeader = TR_no;
531
else
532
withinObjectHeader = TR_maybe;
533
534
// Test a few conditions to try to avoid calling getDeclaringClassFromFieldOrStatic
535
// because that requires VM access.
536
//
537
static char *debugEAFieldValidityCheck = feGetEnv("TR_debugEAFieldValidityCheck");
538
if (withinObjectHeader == TR_yes)
539
{
540
result = TR_yes;
541
}
542
else
543
{
544
TR_OpaqueClassBlock *fieldClassInCP = fieldSymRef->getOwningMethod(comp)->getClassFromFieldOrStatic(comp, fieldSymRef->getCPIndex());
545
if ( fieldClassInCP
546
&& TR_yes == comp->fej9()->isInstanceOf((TR_OpaqueClassBlock*)candidate->_class, fieldClassInCP, true))
547
{
548
// Short cut: There's no need to look up the declaring class of the
549
// field because we already know the candidate's class contains the
550
// field since it inherits the class we're using to access the field
551
// in the constant pool.
552
//
553
if (!debugEAFieldValidityCheck
554
|| performTransformation(comp, "%sQuick Using candidateHasField=yes (withinObjectBound=%s) for candidate [%p] field access [%p]\n",
555
OPT_DETAILS, ynmString(withinObjectBound), candidate->_node, fieldNode))
556
{
557
belongsToAllocatedClass = TR_yes;
558
result = TR_yes;
559
}
560
}
561
}
562
563
// If we're still not sure, go ahead and try getDeclaringClassFromFieldOrStatic
564
//
565
if (result == TR_maybe)
566
{
567
TR::VMAccessCriticalSection candidateHasFieldCriticalSection(comp->fej9(),
568
TR::VMAccessCriticalSection::tryToAcquireVMAccess,
569
comp);
570
571
if (candidateHasFieldCriticalSection.hasVMAccess())
572
{
573
TR_OpaqueClassBlock *fieldDeclaringClass = fieldSymRef->getOwningMethod(comp)->getDeclaringClassFromFieldOrStatic(comp, fieldSymRef->getCPIndex());
574
if (fieldDeclaringClass)
575
belongsToAllocatedClass = comp->fej9()->isInstanceOf((TR_OpaqueClassBlock*)candidate->_class, fieldDeclaringClass, true);
576
577
result = ynmOr(withinObjectHeader, belongsToAllocatedClass);
578
579
if (debugEAFieldValidityCheck)
580
{
581
if (!performTransformation(comp, "%sUsing candidateHasField=%s (withinObjectBound=%s) for candidate [%p] field access [%p]\n",
582
OPT_DETAILS, ynmString(result), ynmString(withinObjectBound), candidate->_node, fieldNode))
583
{
584
// Conservatively return TR_no.
585
// We do the performTransformation even if result is already TR_no
586
// just to support countOptTransformations.
587
//
588
result = TR_no;
589
}
590
}
591
}
592
else if (ea->trace())
593
{
594
traceMsg(comp, " Unable to acquire vm access; conservatively assume field [%p] does not belong to candidate [%p]\n", fieldNode, candidate->_node);
595
}
596
}
597
598
if (debugEAFieldValidityCheck)
599
{
600
if ( (withinObjectBound != result)
601
&& !performTransformation(comp, "%sSubstituting candidateHasField=%s (withinObjectBound=%s) for candidate [%p] field access [%p]\n",
602
OPT_DETAILS, ynmString(result), ynmString(withinObjectBound), candidate->_node, fieldNode))
603
{
604
// Use old logic for debugging purposes
605
// Note: This is not necessarily correct, hence the env var guard.
606
// Once we have confidence in the newer logic, this withinObjectBound
607
// logic can eventually be deleted.
608
//
609
result = withinObjectBound;
610
}
611
}
612
613
if (ea->trace())
614
traceMsg(comp, " Candidate [%p] field access [%p] candidateHasField=%s (withinObjectBound=%s withinObjectHeader=%s belongsToAllocatedClass=%s)\n",
615
candidate->_node, fieldNode,
616
ynmString(result),
617
ynmString(withinObjectBound),
618
ynmString(withinObjectHeader),
619
ynmString(belongsToAllocatedClass));
620
621
return result;
622
}
623
624
//
625
// Hack markers
626
//
627
628
// PR 78801: Currently, BCD shadows don't have reliable size information, and
629
// BCD temps require size information. This makes it hard to create BCD temps
630
// from shadows.
631
//
632
#define CANT_CREATE_BCD_TEMPS (1)
633
634
int32_t TR_EscapeAnalysis::performAnalysisOnce()
635
{
636
int32_t cost = 0;
637
Candidate *candidate, *next;
638
639
if (trace())
640
{
641
traceMsg(comp(), "Starting Escape Analysis pass %d\n", manager()->numPassesCompleted());
642
comp()->dumpMethodTrees("Trees before Escape Analysis");
643
}
644
645
_useDefInfo = NULL; // Build these only if required
646
_invalidateUseDefInfo = false;
647
_valueNumberInfo = NULL;
648
_otherDefsForLoopAllocation = NULL;
649
_methodSymbol = NULL;
650
_nodeUsesThroughAselect = NULL;
651
_repeatAnalysis = false;
652
_somethingChanged = false;
653
_inBigDecimalAdd = false;
654
_candidates.setFirst(NULL);
655
_inlineCallSites.deleteAll();
656
_dependentAllocations.deleteAll();
657
_fixedVirtualCallSites.setFirst(NULL);
658
659
_parms = NULL;
660
_ignoreableUses = NULL;
661
_nonColdLocalObjectsValueNumbers = NULL;
662
_allLocalObjectsValueNumbers = NULL;
663
_visitedNodes = NULL;
664
_aliasesOfAllocNode = NULL;
665
_aliasesOfOtherAllocNode = NULL;
666
_notOptimizableLocalObjectsValueNumbers = NULL;
667
_notOptimizableLocalStringObjectsValueNumbers = NULL;
668
669
// Walk the trees and find the "new" nodes.
670
// Any that are candidates for local allocation or desynchronization are
671
// added to the list of candidates.
672
//
673
findCandidates();
674
cost++;
675
676
if (!_candidates.isEmpty())
677
{
678
_useDefInfo = optimizer()->getUseDefInfo();
679
_blocksWithFlushOnEntry = new (trStackMemory()) TR_BitVector(comp()->getFlowGraph()->getNextNodeNumber(), trMemory(), stackAlloc);
680
_visitedNodes = new (trStackMemory()) TR_BitVector(comp()->getNodeCount(), trMemory(), stackAlloc, growable);
681
_aliasesOfAllocNode =
682
_doLoopAllocationAliasChecking
683
? new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable) : NULL;
684
_aliasesOfOtherAllocNode =
685
_doLoopAllocationAliasChecking
686
? new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc, growable) : NULL;
687
688
if (!_useDefInfo)
689
{
690
if (trace())
691
traceMsg(comp(), "Can't do Escape Analysis, no use/def information\n");
692
_candidates.setFirst(NULL);
693
}
694
695
_valueNumberInfo = optimizer()->getValueNumberInfo();
696
if (!_valueNumberInfo)
697
{
698
if (trace())
699
traceMsg(comp(), "Can't do Escape Analysis, no value number information\n");
700
_candidates.setFirst(NULL);
701
}
702
else
703
{
704
_ignoreableUses = new (trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc);
705
_nonColdLocalObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);
706
_allLocalObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);
707
_notOptimizableLocalObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);
708
_notOptimizableLocalStringObjectsValueNumbers = new (trStackMemory()) TR_BitVector(_valueNumberInfo->getNumberOfValues(), trMemory(), stackAlloc);
709
}
710
}
711
712
if ( !_candidates.isEmpty())
713
{
714
findLocalObjectsValueNumbers();
715
findIgnoreableUses();
716
}
717
718
// Complete the candidate info by finding all uses and defs that are reached
719
// from each candidate.
720
//
721
if (!_candidates.isEmpty())
722
{
723
checkDefsAndUses();
724
cost++;
725
}
726
727
if (trace())
728
printCandidates("Initial candidates");
729
730
// Look through the trees to see which candidates escape the method. This
731
// may involve sniffing into called methods.
732
//
733
_sniffDepth = 0;
734
_parms = NULL;
735
if (!_candidates.isEmpty())
736
{
737
//if (comp()->getMethodSymbol()->mayContainMonitors())
738
if (cg()->getEnforceStoreOrder())
739
{
740
TR_FlowSensitiveEscapeAnalysis flowSensitiveAnalysis(comp(), optimizer(), comp()->getFlowGraph()->getStructure(), this);
741
}
742
743
bool ignoreRecursion = false;
744
checkEscape(comp()->getStartTree(), false, ignoreRecursion);
745
cost++;
746
}
747
748
//fixup those who have virtual calls
749
for (candidate = _candidates.getFirst(); candidate; candidate = next)
750
{
751
next = candidate->getNext();
752
753
if (!candidate->isLocalAllocation())
754
continue;
755
756
if (!candidate->hasVirtualCallsToBeFixed())
757
continue;
758
759
dumpOptDetails(comp(), "Fixup indirect calls sniffed for candidate =%p\n",candidate->_node);
760
TR::TreeTop *callSite, *callSiteNext = NULL;
761
762
ListIterator<TR::TreeTop> it(candidate->getVirtualCallSitesToBeFixed());
763
for (callSite = it.getFirst(); callSite; callSite = callSiteNext)
764
{
765
//TR::TreeTop *directCallTree = findCallSiteFixed(callSite);
766
bool found = findCallSiteFixed(callSite);
767
callSiteNext = it.getNext();
768
if (!found)
769
{
770
if (!_devirtualizedCallSites.find(callSite))
771
_devirtualizedCallSites.add(callSite);
772
773
_fixedVirtualCallSites.add(new (trStackMemory()) TR_EscapeAnalysis::TR_CallSitesFixedMapper(callSite, NULL));
774
dumpOptDetails(comp(), "adding Map:vCall = %p direct = %p\n",callSite, NULL);
775
_repeatAnalysis = true;
776
_somethingChanged = true;
777
778
candidate->getCallSites()->remove(callSite);
779
//candidate->getCallSites()->add(directCallTree);
780
}
781
else
782
{
783
dumpOptDetails(comp(), "found MAp for %p\n",callSite);
784
//fixup the callSite list
785
candidate->getCallSites()->remove(callSite);
786
//candidate->getCallSites()->add(directCallTree);
787
}
788
}
789
790
candidate->setLocalAllocation(false);
791
if (trace())
792
traceMsg(comp(), " Make [%p] non-local because we'll try it again in another pass\n", candidate->_node);
793
794
}
795
796
//fixup those callSite which were devirtualize
797
//fixup the coldBlockInfo too
798
for (candidate = _candidates.getFirst(); candidate; candidate = next)
799
{
800
next = candidate->getNext();
801
if (!candidate->isLocalAllocation())
802
continue;
803
804
TR::TreeTop *callSite, *callSiteNext = NULL;
805
806
ListIterator<TR::TreeTop> it(candidate->getCallSites());
807
for (callSite = it.getFirst(); callSite; callSite = callSiteNext)
808
{
809
callSiteNext = it.getNext();
810
//TR::TreeTop *directCallTree = findCallSiteFixed(callSite);
811
bool found = findCallSiteFixed(callSite);
812
if (found)
813
{
814
if (trace())
815
traceMsg(comp(), "replacing callsite %p for candidate %p with it's direct call\n",callSite,candidate->_node);
816
candidate->getCallSites()->remove(callSite);
817
candidate->setLocalAllocation(false);
818
//candidate->getCallSites()->add(directCallTree);
819
}
820
}
821
822
ListIterator<TR_ColdBlockEscapeInfo> coldBlockInfoIt(candidate->getColdBlockEscapeInfo());
823
for (TR_ColdBlockEscapeInfo *info = coldBlockInfoIt.getFirst(); info != NULL; info = coldBlockInfoIt.getNext())
824
{
825
ListIterator<TR::TreeTop> treesIt(info->getTrees());
826
for (TR::TreeTop *escapeTree = treesIt.getFirst(); escapeTree != NULL; escapeTree = treesIt.getNext())
827
{
828
if (findCallSiteFixed(escapeTree))
829
{
830
candidate->setLocalAllocation(false);
831
break;
832
}
833
}
834
if (!candidate->isLocalAllocation())
835
break;
836
}
837
}
838
839
// Check whether tentative dememoization can proceed
840
//
841
bool shouldRepeatDueToDememoization = false;
842
for (candidate = _candidates.getFirst(); candidate; candidate = next)
843
{
844
next = candidate->getNext();
845
846
if (candidate->_dememoizedConstructorCall)
847
{
848
if ( candidate->isLocalAllocation()
849
&& !candidate->mustBeContiguousAllocation()
850
&& candidate->getCallSites()->isSingleton()
851
&& candidate->getCallSites()->find(candidate->_dememoizedConstructorCall)
852
&& performTransformation(comp(), "%sDememoizing [%p]\n", OPT_DETAILS, candidate->_node))
853
{
854
// Dememoization worked!
855
// Inline the constructor and catch this candidate on the next pass
856
candidate->setLocalAllocation(false);
857
858
if (trace())
859
traceMsg(comp(), "2 setting local alloc %p to false\n", candidate->_node);
860
861
_inlineCallSites.add(candidate->_dememoizedConstructorCall);
862
_repeatAnalysis = true;
863
}
864
else
865
{
866
// Dememoization failed on this pass; must re-memoize instead
867
868
bool mayDememoizeNextTime = true;
869
870
// allow the call to be inlined at least in the last pass
871
// and prevent from dememoizing the call again
872
//
873
if (candidate->isLocalAllocation())
874
_repeatAnalysis = true;
875
876
if (_repeatAnalysis)
877
{
878
if (manager()->numPassesCompleted() == _maxPassNumber-1)
879
mayDememoizeNextTime = false;
880
else
881
shouldRepeatDueToDememoization = true;
882
}
883
else
884
mayDememoizeNextTime = false;
885
886
if (trace())
887
{
888
traceMsg(comp(), " Fail [%p] because dememoization failed; will%s attempt again on next EA pass\n", candidate->_node, mayDememoizeNextTime? "":" NOT");
889
traceMsg(comp(), " Fail [%p] because dememoization failed; will%s attempt dememoization again on next EA pass\n", candidate->_node, mayDememoizeNextTime? "":" NOT");
890
traceMsg(comp(), " 4 booleans are %d %d %d %d\n", candidate->isLocalAllocation(), candidate->mustBeContiguousAllocation(), candidate->getCallSites()->isSingleton(), candidate->getCallSites()->find(candidate->_dememoizedConstructorCall));
891
}
892
893
// if mayDememoizeNextTime is false, then the following call to
894
// rememoize will add valueOf to the list of calls to be inlined
895
//
896
rememoize(candidate, mayDememoizeNextTime);
897
if (trace())
898
traceMsg(comp(), "8 removing cand %p to false\n", candidate->_node);
899
}
900
_candidates.remove(candidate);
901
}
902
}
903
904
// Decide whether or not another pass of escape analysis is appropriate.
905
// If we are allowed to do another pass and there are candidates which are
906
// contiguous only because they are arguments to calls and those calls can
907
// be inlined, then inline the calls and mark the candidates so that they
908
// are not replaced in this pass.
909
// This should result in the candidates being found to be non-contiguous
910
// candidates in a later pass.
911
//
912
if (manager()->numPassesCompleted() < _maxPassNumber)
913
{
914
for (candidate = _candidates.getFirst(); candidate; candidate = next)
915
{
916
next = candidate->getNext();
917
if (!candidate->isLocalAllocation())
918
continue;
919
920
if (trace())
921
traceMsg(comp(), " 0 Look at [%p] must be %d\n", candidate->_node, candidate->mustBeContiguousAllocation());
922
923
if (candidate->mustBeContiguousAllocation() || !candidate->hasCallSites() ||
924
(candidate->_stringCopyNode && (candidate->_stringCopyNode != candidate->_node) &&
925
!candidate->escapesInColdBlocks() &&
926
!candidate->isLockedObject() &&
927
!candidate->_seenSelfStore &&
928
!candidate->_seenStoreToLocalObject))
929
continue;
930
931
932
if (trace())
933
traceMsg(comp(), " 0.5 Look at [%p]\n", candidate->_node);
934
935
// If any of the call sites for this parm is a guarded virtual call - there would be nothing
936
// gained by inlining any of them - we will still end up with a call and will have to make
937
// it contiguous
938
//
939
TR::TreeTop *callSite;
940
bool seenGuardedCall = false;
941
ListIterator<TR::TreeTop> it(candidate->getCallSites());
942
for (callSite = it.getFirst(); callSite; callSite = it.getNext())
943
{
944
TR::Node *callNode = callSite->getNode();
945
if (callNode->isTheVirtualCallNodeForAGuardedInlinedCall())
946
{
947
seenGuardedCall = true;
948
break;
949
}
950
}
951
952
if (trace())
953
traceMsg(comp(), " 1 Look at [%p]\n", candidate->_node);
954
955
// If any of the calls is a guarded virtual call or
956
// If the depth of inlining required is greater than the number of
957
// passes left, or if the number of bytecodes needed to be inlined
958
// will exceed the maximum, enough inlining can't be done.
959
// In this case force the candidate to be contiguous.
960
//
961
if (seenGuardedCall ||
962
candidate->_maxInlineDepth >= (_maxPassNumber-manager()->numPassesCompleted()) ||
963
candidate->_inlineBytecodeSize > (_maxInlinedBytecodeSize-getOptData()->_totalInlinedBytecodeSize))
964
{
965
candidate->setMustBeContiguousAllocation();
966
if (trace())
967
traceMsg(comp(), " Make [%p] contiguous because we can't inline enough\n", candidate->_node);
968
continue;
969
}
970
971
// Take each call site that needs to be inlined and add it to the
972
// list of inlined call sites
973
//
974
while ((callSite = candidate->getCallSites()->popHead()))
975
{
976
TR::Node *node = callSite->getNode();
977
if (node->getOpCode().isTreeTop())
978
node = node->getFirstChild();
979
980
//traceMsg(comp(), "For alloc node %p call site %p\n", candidate->_node, node);
981
//if (node->isTheVirtualCallNodeForAGuardedInlinedCall())
982
if (!_inlineCallSites.find(callSite))
983
{
984
if (comp()->getMethodHotness() <= warm)
985
{
986
// Up to warm, inlining at this point can interfere with existing
987
// profiling and compilation heuristics, causing us to miss even
988
// better inlining opportunities in subsequent hot and scorching
989
// compiles. Only inline selected methods where the benefit of
990
// profiling heuristics is outweighed by the cost of not inlining
991
// at warm.
992
//
993
// TODO: There must be a similar heuristic in the inliner for this
994
// sort of thing? They ought to share code.
995
//
996
switch (node->getSymbol()->castToMethodSymbol()->getRecognizedMethod())
997
{
998
case TR::java_lang_Object_init:
999
break;
1000
default:
1001
candidate->setMustBeContiguousAllocation();
1002
if (trace())
1003
traceMsg(comp(), " Make [%p] contiguous because we can't inline it at %s\n", candidate->_node, comp()->getHotnessName());
1004
continue;
1005
}
1006
}
1007
1008
_inlineCallSites.add(callSite);
1009
}
1010
}
1011
1012
_repeatAnalysis = true;
1013
candidate->setLocalAllocation(false);
1014
if (trace())
1015
traceMsg(comp(), " Make [%p] non-local because we'll try it again in another pass\n", candidate->_node);
1016
}
1017
}
1018
1019
// Apply filters to candidates
1020
//
1021
for (candidate = _candidates.getFirst(); candidate; candidate = next)
1022
{
1023
next = candidate->getNext();
1024
1025
if (candidate->_kind == TR::New)
1026
{
1027
static bool doEAOpt = feGetEnv("TR_DisableEAOpt") ? false : true;
1028
if (!doEAOpt &&
1029
comp()->useCompressedPointers())
1030
{
1031
if (candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)
1032
{
1033
candidate->setLocalAllocation(false);
1034
if (trace())
1035
traceMsg(comp(), " Make [%p] non-local because self store seen in compressed pointers mode\n", candidate->_node);
1036
}
1037
}
1038
1039
if ( CANT_CREATE_BCD_TEMPS
1040
&& candidate->isLocalAllocation()
1041
&& !candidate->isContiguousAllocation()
1042
&& candidate->_fields)
1043
{
1044
for (int32_t i = candidate->_fields->size()-1; i >= 0; i--)
1045
{
1046
TR::SymbolReference *field = candidate->_fields->element(i).fieldSymRef();
1047
if (field && field->getSymbol()->getDataType().isBCD())
1048
{
1049
candidate->setMustBeContiguousAllocation();
1050
if (trace())
1051
traceMsg(comp(), " Make [%p] contiguous because we can't create temp for BCD field #%d\n", candidate->_node, field->getReferenceNumber());
1052
break;
1053
}
1054
}
1055
}
1056
1057
if (candidate->isLocalAllocation() && candidate->isContiguousAllocation())
1058
{
1059
if (!_createLocalObjects)
1060
{
1061
candidate->setLocalAllocation(false);
1062
if (trace())
1063
traceMsg(comp(), " Make [%p] non-local because we can't create local objects\n", candidate->_node);
1064
}
1065
}
1066
1067
1068
if (candidate->isLocalAllocation() &&
1069
candidate->escapesInColdBlocks() &&
1070
(candidate->isLockedObject() ||
1071
candidate->_seenSelfStore ||
1072
candidate->_seenStoreToLocalObject))
1073
{
1074
candidate->setLocalAllocation(false);
1075
if (trace())
1076
traceMsg(comp(), " Make [%p] non-local because we can't have locking when candidate escapes in cold blocks\n", candidate->_node);
1077
}
1078
1079
// Value type fields of objects created with a NEW bytecode must be initialized
1080
// with their default values. EA is not yet set up to perform such iniitialization
1081
// if the value type's own fields have not been inlined into the class that
1082
// has a field of that type, so remove the candidate from consideration.
1083
if (candidate->_kind == TR::New)
1084
{
1085
TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock *)candidate->_node->getFirstChild()->getSymbol()->getStaticSymbol()->getStaticAddress();
1086
1087
if (!TR::Compiler->cls.isZeroInitializable(clazz))
1088
{
1089
if (trace())
1090
traceMsg(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);
1091
rememoize(candidate);
1092
_candidates.remove(candidate);
1093
continue;
1094
}
1095
}
1096
1097
// If a contiguous candidate has reference slots, then stack-allocating it means putting
1098
// stores in the first block of the method. If the first block is really hot, those stores
1099
// are expensive, and stack-allocation is probably not worthwhile.
1100
//
1101
bool objectHasReferenceFields = false;
1102
#if LOCAL_OBJECTS_COLLECTABLE
1103
switch (candidate->_kind)
1104
{
1105
case TR::New:
1106
if (comp()->fej9()->getReferenceSlotsInClass(comp(), (TR_OpaqueClassBlock *)candidate->_node->getFirstChild()->getSymbol()->getStaticSymbol()->getStaticAddress()))
1107
objectHasReferenceFields = true;
1108
break;
1109
case TR::anewarray:
1110
objectHasReferenceFields = true;
1111
break;
1112
default:
1113
break;
1114
}
1115
#endif
1116
if (candidate->isLocalAllocation() &&
1117
(candidate->isInAColdBlock() ||
1118
( objectHasReferenceFields
1119
&& candidate->isContiguousAllocation()
1120
&& (comp()->getStartBlock()->getFrequency() > 4*candidate->_block->getFrequency())))
1121
&& !candidate->usedInNonColdBlock())
1122
//((candidate->isContiguousAllocation() && !candidate->lockedInNonColdBlock()) ||
1123
// (!candidate->isContiguousAllocation() && !candidate->usedInNonColdBlock())))
1124
{
1125
candidate->setLocalAllocation(false);
1126
if (trace())
1127
traceMsg(comp(), " Make [%p] non-local because the uses are not in hot enough blocks\n", candidate->_node);
1128
}
1129
1130
// If the candidate has more than one value number, and a suspicious
1131
// field, reject the candidate to preserve r13 behaviour. For
1132
// candidates with one value number, we can reach definite conclusions
1133
// about what to do with them because there's only one possibility.
1134
// (They're usually non-contiguous.)
1135
//
1136
if (candidate->_valueNumbers->size()> 1 && candidate->_fields)
1137
{
1138
for (int32_t i = candidate->_fields->size()-1; i >= 0; i--)
1139
{
1140
if (candidate->_fields->element(i).hasBadFieldSymRef())
1141
{
1142
if (trace())
1143
traceMsg(comp(), " Fail [%p] because candidate is dereferenced via a field that does not belong to allocated class\n", candidate->_node);
1144
rememoize(candidate);
1145
_candidates.remove(candidate);
1146
break;
1147
}
1148
}
1149
}
1150
1151
if (candidate->_stringCopyNode && (candidate->_stringCopyNode != candidate->_node))
1152
{
1153
if (!candidate->escapesInColdBlocks() &&
1154
!candidate->isLockedObject() &&
1155
!candidate->_seenSelfStore &&
1156
!candidate->_seenStoreToLocalObject)
1157
candidate->setMustBeContiguousAllocation();
1158
else
1159
candidate->_stringCopyNode = NULL;
1160
}
1161
1162
if (candidate->_dememoizedMethodSymRef && candidate->isContiguousAllocation())
1163
{
1164
if (trace())
1165
traceMsg(comp(), " Fail [%p] because dememoized allocations must be non-contiguous\n", candidate->_node);
1166
rememoize(candidate);
1167
_candidates.remove(candidate);
1168
}
1169
1170
continue;
1171
}
1172
1173
if (candidate->_kind == TR::anewarray)
1174
{
1175
// Array Candidates for contiguous allocation that have unresolved
1176
// base classes must be rejected, since we cannot initialize the array
1177
// header. If the component type is a value type, reject the array
1178
// as we can't initialize the elements to the default value yet.
1179
//
1180
if (candidate->isContiguousAllocation())
1181
{
1182
TR::Node *classNode = candidate->_node->getSecondChild();
1183
if (classNode->getOpCodeValue() != TR::loadaddr ||
1184
classNode->getSymbolReference()->isUnresolved())
1185
{
1186
if (trace())
1187
traceMsg(comp(), " Fail [%p] because base class is unresolved\n", candidate->_node);
1188
rememoize(candidate);
1189
_candidates.remove(candidate);
1190
}
1191
else
1192
{
1193
TR_OpaqueClassBlock *clazz = (TR_OpaqueClassBlock*)classNode->getSymbol()->castToStaticSymbol()->getStaticAddress();
1194
1195
if (TR::Compiler->cls.isValueTypeClass(clazz))
1196
{
1197
if (trace())
1198
traceMsg(comp(), " Fail [%p] because array has value type elements\n", candidate->_node);
1199
rememoize(candidate);
1200
_candidates.remove(candidate);
1201
}
1202
}
1203
}
1204
}
1205
1206
if (candidate->isProfileOnly() && candidate->isLocalAllocation())
1207
{
1208
candidate->setLocalAllocation(false);
1209
1210
if (trace())
1211
traceMsg(comp(), "3 setting local alloc %p to false\n", candidate->_node);
1212
1213
if (performTransformation(comp(), "%sInitiate value profiling for length of %s [%p]\n",OPT_DETAILS,
1214
candidate->_node->getOpCode().getName(),
1215
candidate->_node))
1216
{
1217
if (optimizer()->switchToProfiling())
1218
{
1219
TR::Recompilation *recomp = comp()->getRecompilationInfo();
1220
TR_ValueProfiler *valueProfiler = recomp? recomp->getValueProfiler() : NULL;
1221
TR::Node *numElementsNode = candidate->_node->getFirstChild();
1222
1223
TR_ByteCodeInfo originalBcInfo = TR_ProfiledNodeVersioning::temporarilySetProfilingBcInfoOnNewArrayLengthChild(candidate->_node, comp());
1224
valueProfiler->addProfilingTrees(numElementsNode, candidate->_treeTop, 5);
1225
numElementsNode->setByteCodeInfo(originalBcInfo);
1226
}
1227
else if (trace())
1228
{
1229
traceMsg(comp(), " Unable to switch to profiling mode; no profiling trees added for [%p]\n", candidate->_node);
1230
}
1231
}
1232
}
1233
1234
// Remove all array candidates that are not locally allocatable
1235
//
1236
if (!candidate->isLocalAllocation())
1237
{
1238
if (trace())
1239
traceMsg(comp(), " Fail [%p] array candidate is not locally allocatable\n", candidate->_node);
1240
rememoize(candidate);
1241
_candidates.remove(candidate);
1242
continue;
1243
}
1244
}
1245
1246
// Check for size limits on total object allocation size.
1247
//
1248
if (!_candidates.isEmpty())
1249
{
1250
checkObjectSizes();
1251
cost++;
1252
}
1253
1254
if (trace())
1255
printCandidates("Final candidates");
1256
1257
// When we do stack allocation we generate number of stores
1258
// in the first block of the method, so that we can initialize the
1259
// stack allocated object correctly. However, if the first block ends up
1260
// being in a loop, those stores end up resetting the stack allocated object
1261
// even though the new might be under an if later on.
1262
if (comp()->getStartBlock() && !_candidates.isEmpty())
1263
{
1264
TR::Block *block = comp()->getStartBlock();
1265
1266
if (blockIsInLoop(block))
1267
{
1268
comp()->getFlowGraph()->setStructure(NULL);
1269
TR::Block *firstBlockReplacement = toBlock(comp()->getFlowGraph()->addNode(
1270
TR::Block::createEmptyBlock(block->getEntry()->getNode(), comp(), std::max(MAX_COLD_BLOCK_COUNT+1, block->getFrequency()/10))));
1271
firstBlockReplacement->getExit()->join(block->getEntry());
1272
comp()->setStartTree(firstBlockReplacement->getEntry());
1273
1274
TR::CFGEdge *edgeToRemove = comp()->getFlowGraph()->getStart()->asBlock()->getSuccessors().front();
1275
1276
comp()->getFlowGraph()->addEdge(TR::CFGEdge::createEdge(comp()->getFlowGraph()->getStart()->asBlock(), firstBlockReplacement, trMemory()));
1277
comp()->getFlowGraph()->addEdge(TR::CFGEdge::createEdge(firstBlockReplacement, block, trMemory()));
1278
1279
comp()->getFlowGraph()->removeEdge(edgeToRemove);
1280
}
1281
}
1282
1283
// Now each remaining candidate is known not to escape the method.
1284
// All synchronizations on the objects can be removed, and those
1285
// marked for local allocation can be locally allocated.
1286
// Go through the trees one more time, fixing up loads and stores for
1287
// the object.
1288
//
1289
if (!_candidates.isEmpty())
1290
{
1291
fixupTrees();
1292
cost++;
1293
}
1294
1295
int32_t nonContiguousAllocations = 0;
1296
int32_t tempsCreatedForColdEscapePoints = 0;
1297
1298
// Now fix up the new nodes themselves and insert any initialization code
1299
// that is necessary.
1300
//
1301
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
1302
{
1303
if (candidate->isLocalAllocation())
1304
{
1305
if (performTransformation(comp(), "%sStack allocating candidate [%p]\n",OPT_DETAILS, candidate->_node))
1306
{
1307
//printf("stack allocation in %s %s\n",comp()->signature(),comp()->getHotnessName(comp()->getMethodHotness()));fflush(stdout);
1308
1309
if (candidate->isContiguousAllocation())
1310
{
1311
if (candidate->_stringCopyNode && (candidate->_stringCopyNode != candidate->_node))
1312
avoidStringCopyAllocation(candidate);
1313
else
1314
makeContiguousLocalAllocation(candidate);
1315
}
1316
else
1317
{
1318
makeNonContiguousLocalAllocation(candidate);
1319
++nonContiguousAllocations;
1320
}
1321
1322
if (candidate->escapesInColdBlocks())
1323
{
1324
heapifyForColdBlocks(candidate);
1325
if (candidate->_fields)
1326
{
1327
int32_t i;
1328
for (i = candidate->_fields->size()-1; i >= 0; i--)
1329
{
1330
if (((*candidate->_fields)[i]._symRef == NULL) &&
1331
!(*candidate->_fields)[i].hasBadFieldSymRef())
1332
{
1333
//printf("Conservative aliasing reqd in %s\n", comp()->signature()); fflush(stdout);
1334
comp()->getSymRefTab()->aliasBuilder.setConservativeGenericIntShadowAliasing(true);
1335
}
1336
}
1337
}
1338
else
1339
comp()->getSymRefTab()->aliasBuilder.setConservativeGenericIntShadowAliasing(true);
1340
1341
tempsCreatedForColdEscapePoints++;
1342
}
1343
1344
if (candidate->_seenFieldStore)
1345
_repeatAnalysis = true;
1346
1347
1348
_somethingChanged = true;
1349
}
1350
}
1351
}
1352
1353
_somethingChanged |= devirtualizeCallSites();
1354
1355
// If there are any call sites to be inlined, do it now
1356
//
1357
_somethingChanged |= inlineCallSites();
1358
1359
// Use/def and value number information must be recalculated for later
1360
// optimization passes.
1361
//
1362
if (_somethingChanged || _invalidateUseDefInfo)
1363
{
1364
optimizer()->setUseDefInfo(NULL);
1365
_useDefInfo = NULL;
1366
}
1367
if (_somethingChanged)
1368
{
1369
optimizer()->setValueNumberInfo(NULL);
1370
requestOpt(OMR::treeSimplification);
1371
requestOpt(OMR::globalValuePropagation);
1372
}
1373
else
1374
{
1375
if (!shouldRepeatDueToDememoization)
1376
_repeatAnalysis = false;
1377
else
1378
{
1379
// fast forward the current pass to the n-2th pass because
1380
// in performAnalysisOnce, _currentPass is inc'ed before
1381
// calling EA again
1382
// (we really want to inline in the n-1th pass)
1383
manager()->setNumPassesCompleted(_maxPassNumber-2);
1384
_repeatAnalysis = true; // should already be true, just being paranoid
1385
}
1386
}
1387
1388
// If we created non-contiguous allocations, and the method contains
1389
// catch blocks, the alias sets must be marked as non-valid.
1390
//
1391
if ((nonContiguousAllocations > 0) ||
1392
(tempsCreatedForColdEscapePoints > 0))
1393
{
1394
bool containsCatchBlocks = false;
1395
for (TR::CFGNode *node = comp()->getFlowGraph()->getFirstNode(); !containsCatchBlocks && node; node = node->getNext())
1396
if (!((TR::Block *)node)->getExceptionPredecessors().empty())
1397
containsCatchBlocks = true;
1398
1399
if (containsCatchBlocks)
1400
optimizer()->setAliasSetsAreValid(false);
1401
}
1402
1403
1404
if (trace())
1405
{
1406
comp()->dumpMethodTrees("Trees after Escape Analysis");
1407
traceMsg(comp(), "Ending Escape Analysis");
1408
}
1409
1410
return cost; // actual cost
1411
}
1412
1413
void TR_EscapeAnalysis::findIgnoreableUses()
1414
{
1415
if (comp()->getOSRMode() != TR::voluntaryOSR)
1416
return;
1417
1418
TR::NodeChecklist visited(comp());
1419
bool inOSRCodeBlock = false;
1420
1421
// Gather all uses under fake prepareForOSR calls - they will be tracked as ignoreable
1422
for (TR::TreeTop *treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())
1423
{
1424
if (treeTop->getNode()->getOpCodeValue() == TR::BBStart)
1425
inOSRCodeBlock = treeTop->getNode()->getBlock()->isOSRCodeBlock();
1426
else if (inOSRCodeBlock
1427
&& treeTop->getNode()->getNumChildren() > 0
1428
&& treeTop->getNode()->getFirstChild()->getOpCodeValue() == TR::call
1429
&& treeTop->getNode()->getFirstChild()->getSymbolReference()->getReferenceNumber() == TR_prepareForOSR)
1430
{
1431
TR::Node *callNode = treeTop->getNode()->getFirstChild();
1432
for (int i = 0; i < callNode->getNumChildren(); ++i)
1433
findIgnoreableUses(callNode->getChild(i), visited);
1434
}
1435
}
1436
}
1437
1438
void TR_EscapeAnalysis::findIgnoreableUses(TR::Node *node, TR::NodeChecklist &visited)
1439
{
1440
if (visited.contains(node))
1441
return;
1442
visited.add(node);
1443
if (trace())
1444
traceMsg(comp(), "Marking n%dn as an ignoreable use\n", node->getGlobalIndex());
1445
_ignoreableUses->set(node->getGlobalIndex());
1446
1447
int32_t i;
1448
for (i = 0; i < node->getNumChildren(); i++)
1449
{
1450
TR::Node *child = node->getChild(i);
1451
findIgnoreableUses(child, visited);
1452
}
1453
}
1454
1455
void TR_EscapeAnalysis::findLocalObjectsValueNumbers()
1456
{
1457
TR::NodeChecklist visited(comp());
1458
TR::TreeTop *treeTop;
1459
1460
for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())
1461
{
1462
TR::Node *node = treeTop->getNode();
1463
findLocalObjectsValueNumbers(node, visited);
1464
}
1465
}
1466
1467
void TR_EscapeAnalysis::findLocalObjectsValueNumbers(TR::Node *node, TR::NodeChecklist& visited)
1468
{
1469
if (visited.contains(node))
1470
return;
1471
visited.add(node);
1472
1473
if (node->getOpCode().hasSymbolReference() &&
1474
node->getSymbolReference()->getSymbol()->isLocalObject())
1475
{
1476
_allLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));
1477
if (!node->escapesInColdBlock())
1478
{
1479
_nonColdLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));
1480
if (node->cannotTrackLocalUses())
1481
{
1482
if (!_notOptimizableLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(node)))
1483
{
1484
//dumpOptDetails(comp(), "Local object %p value number %d detected\n", node, _valueNumberInfo->getValueNumber(node));
1485
1486
_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));
1487
}
1488
1489
if (node->cannotTrackLocalStringUses())
1490
{
1491
if (!_notOptimizableLocalStringObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(node)))
1492
{
1493
//dumpOptDetails(comp(), "Local object %p value number %d detected\n", node, _valueNumberInfo->getValueNumber(node));
1494
1495
_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(node));
1496
}
1497
}
1498
}
1499
}
1500
}
1501
1502
int32_t i;
1503
for (i = 0; i < node->getNumChildren(); i++)
1504
{
1505
TR::Node *child = node->getChild(i);
1506
findLocalObjectsValueNumbers(child, visited);
1507
}
1508
}
1509
1510
1511
void TR_EscapeAnalysis::findCandidates()
1512
{
1513
TR::NodeChecklist visited (comp());
1514
int32_t i;
1515
bool foundUserAnnotation=false;
1516
const char *className = NULL;
1517
for (_curTree = comp()->getStartTree(); _curTree; _curTree = _curTree->getNextTreeTop())
1518
{
1519
TR::Node *node = _curTree->getNode();
1520
1521
if (visited.contains(node))
1522
continue;
1523
visited.add(node);
1524
1525
if (node->getOpCodeValue() == TR::BBStart)
1526
{
1527
_curBlock = node->getBlock();
1528
continue;
1529
}
1530
1531
if (!node->getNumChildren())
1532
continue;
1533
1534
node = node->getFirstChild();
1535
1536
if (visited.contains(node))
1537
continue;
1538
visited.add(node);
1539
1540
if (node->getOpCode().isNew() && node->isHeapificationAlloc())
1541
{
1542
if (trace())
1543
traceMsg(comp(), "Reject candidate %s n%dn [%p] because it is for heapification\n", node->getOpCode().getName(), node->getGlobalIndex(), node);
1544
continue;
1545
}
1546
1547
TR::SymbolReference *dememoizedMethodSymRef = NULL;
1548
TR::TreeTop *dememoizedConstructorCall = NULL;
1549
if (!comp()->fej9()->callTargetsNeedRelocations() && node->getOpCodeValue() == TR::acall
1550
&& node->getSymbol()->getMethodSymbol()->getRecognizedMethod() == TR::java_lang_Integer_valueOf
1551
&& !node->isTheVirtualCallNodeForAGuardedInlinedCall()
1552
&& manager()->numPassesCompleted() < _maxPassNumber)
1553
{
1554
// Dememoization: Let's look for a constructor call we could use instead
1555
//
1556
_dememoizationSymRef = node->getSymbolReference();
1557
1558
if (trace()) traceMsg(comp(), "Attempt dememoize on %p\n", node);
1559
TR_OpaqueMethodBlock *constructor = comp()->getOption(TR_DisableDememoization)? NULL : comp()->fej9()->getMethodFromName("java/lang/Integer", "<init>", "(I)V");
1560
if ( constructor
1561
&& performTransformation(comp(), "%sTry dememoizing %p\n", OPT_DETAILS, node))
1562
{
1563
// Replace this call with a allocation+constructor and hope for the best.
1564
//
1565
// NOTE! This is not actually correct unless subsequent analysis
1566
// can prove it's correct; if it's not, we must rememoize this.
1567
//
1568
dememoizedMethodSymRef = node->getSymbolReference();
1569
TR::SymbolReference *constructorSymRef = comp()->getSymRefTab()->findOrCreateMethodSymbol(JITTED_METHOD_INDEX, -1,
1570
comp()->fej9()->createResolvedMethod(trMemory(), constructor), TR::MethodSymbol::Special);
1571
dememoizedConstructorCall = TR::TreeTop::create(comp(), _curTree,
1572
TR::Node::create(TR::treetop, 1,
1573
TR::Node::createWithSymRef(TR::call, 2, 2,
1574
node,
1575
node->getFirstChild(),
1576
constructorSymRef)));
1577
node->getFirstChild()->decReferenceCount();
1578
node->setAndIncChild(0,
1579
TR::Node::createWithSymRef(node, TR::loadaddr, 0,
1580
comp()->getSymRefTab()->findOrCreateClassSymbol(comp()->getMethodSymbol(), -1,
1581
comp()->fej9()->getClassFromSignature("java/lang/Integer", 17, comp()->getCurrentMethod(), true))));
1582
TR::Node::recreate(node, TR::New);
1583
if (!_dememoizedAllocs.find(node))
1584
_dememoizedAllocs.add(node);
1585
node->setSymbolReference(comp()->getSymRefTab()->findOrCreateNewObjectSymbolRef(comp()->getMethodSymbol()));
1586
}
1587
}
1588
1589
1590
if (node->getOpCodeValue() != TR::New &&
1591
node->getOpCodeValue() != TR::newarray &&
1592
node->getOpCodeValue() != TR::anewarray)
1593
continue;
1594
1595
static char *noEscapeArrays = feGetEnv("TR_NOESCAPEARRAY");
1596
if (noEscapeArrays)
1597
{
1598
if (node->getOpCodeValue() != TR::New)
1599
continue;
1600
}
1601
1602
1603
// Found a "new" opcode. See if it is a candidate for local allocation.
1604
//
1605
//
1606
bool inAColdBlock = false;
1607
if (_curBlock->isCold() ||
1608
_curBlock->isCatchBlock() ||
1609
(_curBlock->getFrequency() == (MAX_COLD_BLOCK_COUNT+1)))
1610
inAColdBlock = true;
1611
1612
if (trace())
1613
{
1614
if (node->getOpCodeValue() == TR::New)
1615
{
1616
const char *className = getClassName(node->getFirstChild());
1617
traceMsg(comp(), "Found [%p] new %s\n", node,
1618
className ? className : "<Missing class name>");
1619
}
1620
else if (node->getOpCodeValue() == TR::newarray)
1621
traceMsg(comp(), "Found [%p] newarray of type %d\n", node, node->getSecondChild()->getInt());
1622
else
1623
{
1624
const char *className = getClassName(node->getSecondChild());
1625
traceMsg(comp(), "Found [%p] anewarray %s\n", node,
1626
className ? className : "<Missing class name>");
1627
}
1628
}
1629
1630
foundUserAnnotation=false;
1631
1632
// Make this a candidate for local allocation and/or desynchronization.
1633
// Checks for escape are done after the candidates have been collected.
1634
//
1635
TR_OpaqueClassBlock *classInfo = 0;
1636
Candidate *candidate = createCandidateIfValid(node, classInfo,foundUserAnnotation);
1637
if (!candidate)
1638
continue;
1639
if (dememoizedConstructorCall)
1640
{
1641
candidate->_dememoizedMethodSymRef = dememoizedMethodSymRef;
1642
candidate->_dememoizedConstructorCall = dememoizedConstructorCall;
1643
//candidate->setObjectIsReferenced();
1644
candidate->getCallSites()->add(dememoizedConstructorCall);
1645
}
1646
1647
// candidate->_size is:
1648
// -1 if it is not a valid candidate.
1649
// 0 if it is a valid candidate for desynchronizing only.
1650
// allocation size otherwise.
1651
//
1652
candidate->setLocalAllocation(_createStackAllocations && (candidate->_size > 0));
1653
if (trace())
1654
traceMsg(comp(), "4 setting local alloc %p to %s\n", candidate->_node, candidate->isLocalAllocation()? "true":"false");
1655
1656
if(foundUserAnnotation)
1657
{
1658
candidate->setForceLocalAllocation(true);
1659
candidate->setObjectIsReferenced();
1660
if (trace())
1661
traceMsg(comp(), " Force [%p] to be locally allocated due to annotation of %s\n", node, className);
1662
}
1663
1664
if (candidate->isLocalAllocation())
1665
{
1666
if (node->getSymbolReference() == _newObjectNoZeroInitSymRef ||
1667
node->getSymbolReference() == _newArrayNoZeroInitSymRef ||
1668
node->getSymbolReference() == _aNewArrayNoZeroInitSymRef)
1669
{
1670
candidate->setExplicitlyInitialized();
1671
}
1672
1673
if (blockIsInLoop(_curBlock))
1674
candidate->setInsideALoop();
1675
1676
if (inAColdBlock)
1677
candidate->setInAColdBlock(true);
1678
}
1679
1680
1681
_candidates.add(candidate);
1682
}
1683
1684
if (trace())
1685
{
1686
comp()->dumpMethodTrees("Trees after finding candidates");
1687
}
1688
}
1689
1690
1691
Candidate *TR_EscapeAnalysis::createCandidateIfValid(TR::Node *node, TR_OpaqueClassBlock *&classInfo,bool foundUserAnnotation)
1692
{
1693
// If user has annotated this objects class, force it to be on the stack
1694
if(!foundUserAnnotation)
1695
{
1696
// The only case where an object allocation can automatically escape is when
1697
// it implements the "Runnable" interface. Check for that first and dismiss
1698
// it immediately. If the class is unresolved, we don't know so we have to
1699
// assume the worst.
1700
//
1701
if (node->getOpCodeValue() == TR::New)
1702
{
1703
TR::Node *classNode = node->getFirstChild();
1704
if (classNode->getOpCodeValue() != TR::loadaddr)
1705
{
1706
if (trace())
1707
traceMsg(comp(), " Node [%p] failed: child is not TR::loadaddr\n", node);
1708
return NULL;
1709
}
1710
1711
if (classNode->getSymbolReference()->isUnresolved())
1712
{
1713
if (trace())
1714
traceMsg(comp(), " Node [%p] failed: class is unresolved\n", node);
1715
return NULL;
1716
}
1717
1718
TR::StaticSymbol *classSym = classNode->getSymbol()->castToStaticSymbol();
1719
1720
// Removed assume, does not make sense when doing aot -- ALI
1721
// TR_ASSERT(comp()->getRunnableClassPointer(), "Need access to java/lang/Runnable");
1722
if (comp()->getRunnableClassPointer() &&
1723
comp()->fej9()->isInstanceOf((TR_OpaqueClassBlock *)classSym->getStaticAddress(), comp()->getRunnableClassPointer(), true) == TR_yes)
1724
{
1725
if (trace())
1726
{
1727
const char *className = getClassName(classNode);
1728
traceMsg(comp(), "secs Class %s implements Runnable in %s\n",
1729
className ? className : "<Missing class name>",
1730
comp()->signature());
1731
traceMsg(comp(), " Node [%p] failed: class implements the Runnable interface\n", node);
1732
}
1733
return NULL;
1734
}
1735
}
1736
// Don't convert double-word arrays if platform does not have double-word aligned stacks
1737
// will handle stack alignment later
1738
else if (!comp()->cg()->getHasDoubleWordAlignedStack() &&
1739
node->getOpCodeValue() == TR::newarray && !comp()->getOption(TR_EnableSIMDLibrary))
1740
{
1741
TR::Node *typeNode = node->getSecondChild();
1742
if (typeNode->getInt() == 7 || typeNode->getInt() == 11)
1743
{
1744
if (trace())
1745
traceMsg(comp(), " Node [%p] failed: double-size array\n", node);
1746
return NULL;
1747
}
1748
}
1749
}
1750
1751
1752
if (comp()->cg()->getSupportsStackAllocationOfArraylets())
1753
{
1754
if (node->getOpCodeValue() != TR::New)
1755
{
1756
if (trace())
1757
traceMsg(comp(), " Node [%p] failed: arraylet\n", node);
1758
1759
return NULL;
1760
}
1761
}
1762
1763
bool profileOnly = false;
1764
1765
// See if the VM thinks it is valid to eliminate this allocation node. If not
1766
// the allocation can't be made into a stack allocation. If it is an object
1767
// allocation we can still look for desynchronization opportunities.
1768
//
1769
int32_t size = comp()->canAllocateInlineOnStack(node, classInfo);
1770
1771
if (((node->getOpCodeValue() == TR::newarray) || (node->getOpCodeValue() == TR::anewarray)) &&
1772
(node->getFirstChild()->getOpCodeValue() == TR::iconst))
1773
{
1774
if (node->getFirstChild()->getInt() == 0)
1775
return NULL;
1776
}
1777
1778
if (classInfo &&
1779
!TR::Compiler->cls.sameClassLoaders(comp(), classInfo, comp()->getJittedMethodSymbol()->getResolvedMethod()->containingClass()) &&
1780
!comp()->fej9()->isClassLoadedBySystemClassLoader(classInfo))
1781
return NULL;
1782
1783
if (size <= 0)
1784
{
1785
if (trace())
1786
traceMsg(comp(), " Node [%p] failed: VM can't skip allocation (code %d, class %p)\n", node, size, classInfo);
1787
1788
if ( size == 0
1789
&& classInfo
1790
&& (manager()->numPassesCompleted() == 0)
1791
&& optimizer()->isEnabled(OMR::profiledNodeVersioning)
1792
&& !_curBlock->isCold())
1793
{
1794
TR::Node *numElementsNode = NULL;
1795
switch (node->getOpCodeValue())
1796
{
1797
case TR::newarray:
1798
case TR::anewarray:
1799
numElementsNode = node->getFirstChild();
1800
break;
1801
case TR::New:
1802
case TR::multianewarray:
1803
// Can't do anything with these yet
1804
break;
1805
default:
1806
break;
1807
}
1808
1809
TR::Recompilation *recomp = comp()->getRecompilationInfo();
1810
TR_ValueProfiler *valueProfiler = recomp? recomp->getValueProfiler() : NULL;
1811
1812
if ( numElementsNode
1813
&& valueProfiler
1814
&& performTransformation(comp(), "%sContinue analyzing %s node %s for size-profiling opportunity\n", OPT_DETAILS,
1815
node->getOpCode().getName(),
1816
comp()->getDebug()->getName(node)))
1817
{
1818
profileOnly = true;
1819
size = TR::Compiler->om.contiguousArrayHeaderSizeInBytes(); // Must be at least this big
1820
}
1821
else
1822
{
1823
return NULL;
1824
}
1825
}
1826
else if (node->getOpCodeValue() == TR::New && classInfo)
1827
size = 0;
1828
else
1829
return NULL;
1830
}
1831
else
1832
{
1833
// j/l/Reference objects are no longer enqueued by a native call in the constructor.
1834
// This native was preventing j/l/Reference objects from being stack allocated, but
1835
// we now need to explicitly prevent j/l/Reference (and its subclasses) from being
1836
// stack allocated because the GC can't discover them during scanning (this is non-
1837
// trivial to do apparently).
1838
//
1839
TR_OpaqueClassBlock *jlReference = comp()->getReferenceClassPointer();
1840
TR_OpaqueClassBlock *jlObject = comp()->getObjectClassPointer();
1841
TR_OpaqueClassBlock *currentClass = classInfo;
1842
1843
while (currentClass && currentClass != jlObject)
1844
{
1845
if (currentClass == jlReference)
1846
{
1847
if (trace())
1848
traceMsg(comp(), " Node [%p] failed: class %p is subclass of j/l/r/Reference\n", node, classInfo);
1849
1850
return NULL;
1851
}
1852
else
1853
{
1854
currentClass = comp()->fej9()->getSuperClass(currentClass);
1855
}
1856
}
1857
}
1858
1859
Candidate *result = NULL;
1860
result = new (trStackMemory()) Candidate(node, _curTree, _curBlock, size, classInfo, comp());
1861
result->setProfileOnly(profileOnly);
1862
return result;
1863
}
1864
1865
1866
1867
bool TR_EscapeAnalysis::isEscapePointCold(Candidate *candidate, TR::Node *node)
1868
{
1869
static const char *disableColdEsc = feGetEnv("TR_DisableColdEscape");
1870
if (!disableColdEsc &&
1871
(_inColdBlock ||
1872
(candidate->isInsideALoop() &&
1873
(candidate->_block->getFrequency() > 4*_curBlock->getFrequency()))) &&
1874
(candidate->_origKind == TR::New))
1875
return true;
1876
1877
return false;
1878
}
1879
1880
1881
void TR_EscapeAnalysis::checkDefsAndUses()
1882
{
1883
Candidate *candidate, *next;
1884
1885
gatherUsesThroughAselect();
1886
1887
for (candidate = _candidates.getFirst(); candidate; candidate = next)
1888
{
1889
next = candidate->getNext();
1890
TR::Node *node = candidate->_node;
1891
int32_t newVN = _valueNumberInfo->getValueNumber(node);
1892
candidate->_valueNumbers = new (trStackMemory()) TR_Array<int32_t>(trMemory(), 8, false, stackAlloc);
1893
candidate->_valueNumbers->add(newVN);
1894
1895
// Accumulate the set of value numbers that can be reached by this
1896
// allocation. This also checks that it is valid to allocate on the stack.
1897
//
1898
if (candidate->isInsideALoop())
1899
{
1900
if (_otherDefsForLoopAllocation)
1901
_otherDefsForLoopAllocation->empty();
1902
else
1903
_otherDefsForLoopAllocation= new (trStackMemory()) TR_BitVector(_useDefInfo->getNumDefNodes(), trMemory(), stackAlloc);
1904
}
1905
1906
if (comp()->getOptions()->realTimeGC() &&
1907
comp()->compilationShouldBeInterrupted(ESC_CHECK_DEFSUSES_CONTEXT))
1908
{
1909
comp()->failCompilation<TR::CompilationInterrupted>("interrupted in Escape Analysis");
1910
}
1911
1912
if (checkDefsAndUses(node, candidate))
1913
{
1914
if (candidate->_valueNumbers->size() > 1)
1915
{
1916
candidate->setMustBeContiguousAllocation();
1917
if (trace())
1918
traceMsg(comp(), " Make [%p] contiguous because its uses can be reached from other defs\n", candidate->_node);
1919
}
1920
}
1921
else
1922
{
1923
candidate->setLocalAllocation(false);
1924
if (trace())
1925
traceMsg(comp(), "5 setting local alloc %p to false\n", candidate->_node);
1926
}
1927
}
1928
1929
_vnTemp = new (trStackMemory()) TR_BitVector( optimizer()->getValueNumberInfo()->getNumberOfNodes(), trMemory(), stackAlloc, notGrowable);
1930
_vnTemp2 = new (trStackMemory()) TR_BitVector(optimizer()->getValueNumberInfo()->getNumberOfNodes(), trMemory(), stackAlloc, notGrowable);
1931
1932
TR::TreeTop *tt = comp()->getStartTree();
1933
for (; tt; tt = tt->getNextTreeTop())
1934
{
1935
bool storeOfObjectIntoField = false;
1936
TR::Node *node = tt->getNode();
1937
if (!node->getOpCode().isStore())
1938
{
1939
if (node->getNumChildren() > 0)
1940
node = node->getFirstChild();
1941
}
1942
1943
bool storeIntoOtherLocalObject = false;
1944
int32_t baseChildVN = -1;
1945
if (node->getOpCode().isStoreIndirect() ||
1946
(node->getOpCodeValue() == TR::arraycopy))
1947
{
1948
TR::Node *baseObject = node;
1949
1950
if (node->getSymbol()->isArrayShadowSymbol() &&
1951
node->getFirstChild()->getOpCode().isArrayRef())
1952
baseObject = node->getFirstChild();
1953
else if (node->getOpCodeValue() == TR::arraycopy)
1954
{
1955
if (node->getNumChildren() == 5)
1956
baseObject = node->getChild(3);
1957
else if (node->getFirstChild()->getOpCode().isArrayRef())
1958
baseObject = node->getFirstChild();
1959
}
1960
1961
if (node->getOpCode().isStoreIndirect() &&
1962
(baseObject->getFirstChild() == node->getSecondChild()))
1963
storeOfObjectIntoField = true;
1964
else
1965
{
1966
TR::Node *baseChild = baseObject;
1967
1968
if ((node->getOpCodeValue() != TR::arraycopy) ||
1969
(node->getNumChildren() != 5))
1970
baseChild = baseObject->getFirstChild();
1971
1972
baseChild = resolveSniffedNode(baseChild);
1973
1974
if ((baseChild && (baseChild->getOpCodeValue() == TR::loadaddr) &&
1975
baseChild->getSymbolReference()->getSymbol()->isAuto() &&
1976
baseChild->getSymbolReference()->getSymbol()->isLocalObject())
1977
)
1978
{
1979
baseChildVN = _valueNumberInfo->getValueNumber(baseChild);
1980
if (node->getOpCodeValue() == TR::arraycopy)
1981
{
1982
_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);
1983
_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);
1984
storeOfObjectIntoField = false;
1985
if (trace())
1986
traceMsg(comp(), "Reached 0 with baseChild %p VN %d\n", baseChild, baseChildVN);
1987
}
1988
else
1989
{
1990
if (!baseChild->cannotTrackLocalUses())
1991
{
1992
storeOfObjectIntoField = true;
1993
storeIntoOtherLocalObject = true;
1994
if (trace())
1995
traceMsg(comp(), "Reached 1 with baseChild %p VN %d\n", baseChild, baseChildVN);
1996
}
1997
else
1998
{
1999
_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);
2000
_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);
2001
storeOfObjectIntoField = false;
2002
}
2003
}
2004
}
2005
else if (baseChild && _useDefInfo)
2006
{
2007
uint16_t baseIndex = baseChild->getUseDefIndex();
2008
if (_useDefInfo->isUseIndex(baseIndex))
2009
{
2010
TR_UseDefInfo::BitVector defs(comp()->allocator());
2011
_useDefInfo->getUseDef(defs, baseIndex);
2012
if (!defs.IsZero())
2013
{
2014
TR_UseDefInfo::BitVector::Cursor cursor(defs);
2015
for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())
2016
{
2017
int32_t defIndex = cursor;
2018
2019
if (defIndex < _useDefInfo->getFirstRealDefIndex())
2020
{
2021
storeOfObjectIntoField = false;
2022
break;
2023
}
2024
2025
TR::TreeTop *defTree = _useDefInfo->getTreeTop(defIndex);
2026
TR::Node *defNode = defTree->getNode();
2027
2028
if (defNode &&
2029
(defNode->getOpCodeValue() == TR::astore) &&
2030
(defNode->getNumChildren() > 0))
2031
{
2032
TR::Node *defChild = defNode->getFirstChild();
2033
2034
if (defChild && (defChild->getOpCodeValue() == TR::loadaddr) &&
2035
defChild->getSymbolReference()->getSymbol()->isAuto() &&
2036
defChild->getSymbolReference()->getSymbol()->isLocalObject() &&
2037
!defChild->cannotTrackLocalUses())
2038
{
2039
if (node->getOpCode().isStoreIndirect() &&
2040
(_valueNumberInfo->getValueNumber(defChild) == _valueNumberInfo->getValueNumber(baseChild)))
2041
{
2042
baseChildVN = _valueNumberInfo->getValueNumber(baseChild);
2043
storeOfObjectIntoField = true;
2044
storeIntoOtherLocalObject = true;
2045
}
2046
else
2047
{
2048
_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));
2049
_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));
2050
_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));
2051
_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));
2052
storeOfObjectIntoField = false;
2053
break;
2054
}
2055
}
2056
else
2057
{
2058
_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));
2059
_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));
2060
_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(baseChild));
2061
_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(defChild));
2062
storeOfObjectIntoField = false;
2063
break;
2064
}
2065
}
2066
}
2067
}
2068
}
2069
}
2070
}
2071
}
2072
2073
if (storeOfObjectIntoField)
2074
{
2075
int32_t valueNumber = _valueNumberInfo->getValueNumber(node->getSecondChild());
2076
Candidate *candidate, *next;
2077
bool foundAccess = false;
2078
for (candidate = _candidates.getFirst(); candidate; candidate = next)
2079
{
2080
next = candidate->getNext();
2081
if (usesValueNumber(candidate, valueNumber))
2082
{
2083
TR::NodeChecklist visited (comp());
2084
TR::TreeTop *cursorTree = comp()->getStartTree();
2085
for (; cursorTree; cursorTree = cursorTree->getNextTreeTop())
2086
{
2087
TR::Node *cursorNode = cursorTree->getNode();
2088
if (!storeIntoOtherLocalObject)
2089
{
2090
if (collectValueNumbersOfIndirectAccessesToObject(cursorNode, candidate, node, visited))
2091
foundAccess = true;
2092
}
2093
else
2094
{
2095
if (collectValueNumbersOfIndirectAccessesToObject(cursorNode, candidate, node, visited, baseChildVN))
2096
foundAccess = true;
2097
}
2098
}
2099
}
2100
}
2101
}
2102
2103
2104
if (node->getOpCode().isCall() &&
2105
(node->getSymbol()->getResolvedMethodSymbol()) &&
2106
(node->getReferenceCount() > 1) &&
2107
(node->getNumChildren() > 0))
2108
{
2109
TR::ResolvedMethodSymbol *methodSymbol = node->getSymbol()->getResolvedMethodSymbol();
2110
switch (methodSymbol->getRecognizedMethod())
2111
{
2112
case TR::java_lang_Throwable_fillInStackTrace:
2113
case TR::java_math_BigDecimal_possibleClone:
2114
{
2115
int32_t firstArgIndex = node->getFirstArgumentIndex();
2116
int32_t nodeVN = _valueNumberInfo->getValueNumber(node->getChild(firstArgIndex));
2117
for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
2118
{
2119
if (usesValueNumber(candidate, nodeVN))
2120
{
2121
// Remember the value number of the fillInStackTrace call itself
2122
// It's return value can be assigned to a local and the local can be used
2123
// which would mean we cannot eliminate the fillInStackTrace.
2124
//
2125
if (methodSymbol && (!methodSymbol->getResolvedMethod()->virtualMethodIsOverridden() || !node->getOpCode().isIndirect()))
2126
{
2127
candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));
2128
}
2129
}
2130
}
2131
}
2132
default:
2133
break;
2134
}
2135
}
2136
}
2137
}
2138
2139
void TR_EscapeAnalysis::printUsesThroughAselect(void)
2140
{
2141
if (trace())
2142
{
2143
if (_nodeUsesThroughAselect)
2144
{
2145
traceMsg(comp(), "\nNodes used through aselect operations\n");
2146
2147
for (auto mi = _nodeUsesThroughAselect->begin(); mi != _nodeUsesThroughAselect->end(); mi++)
2148
{
2149
TR::Node *key = mi->first;
2150
int32_t nodeIdx = key->getGlobalIndex();
2151
2152
traceMsg(comp(), " node [%p] n%dn is used by {", key, nodeIdx);
2153
2154
bool first = true;
2155
2156
for (auto di = mi->second->begin(), end = mi->second->end(); di != end; di++)
2157
{
2158
TR::Node *aselectNode = *di;
2159
traceMsg(comp(), "%s[%p] n%dn", (first ? "" : ", "), aselectNode,
2160
aselectNode->getGlobalIndex());
2161
first = false;
2162
}
2163
2164
traceMsg(comp(), "}\n");
2165
}
2166
}
2167
else
2168
{
2169
traceMsg(comp(), "\nNo nodes used through aselect operations\n");
2170
}
2171
}
2172
}
2173
2174
void TR_EscapeAnalysis::gatherUsesThroughAselect(void)
2175
{
2176
TR::NodeChecklist visited(comp());
2177
TR::TreeTop *tt = comp()->getStartTree();
2178
2179
for (; tt; tt = tt->getNextTreeTop())
2180
{
2181
TR::Node *node = tt->getNode();
2182
gatherUsesThroughAselectImpl(node, visited);
2183
}
2184
2185
if (trace())
2186
{
2187
printUsesThroughAselect();
2188
}
2189
}
2190
2191
void TR_EscapeAnalysis::gatherUsesThroughAselectImpl(TR::Node *node, TR::NodeChecklist& visited)
2192
{
2193
if (visited.contains(node))
2194
{
2195
return;
2196
}
2197
visited.add(node);
2198
2199
for (int32_t i=0; i<node->getNumChildren(); i++)
2200
{
2201
gatherUsesThroughAselectImpl(node->getChild(i), visited);
2202
}
2203
2204
// If this is an aselect operation, for each of its child operands (other than
2205
// the condition) add the aselect node to the array of nodes that use that child
2206
if (node->getOpCode().isSelect() && node->getDataType() == TR::Address)
2207
{
2208
associateAselectWithChild(node, 1);
2209
associateAselectWithChild(node, 2);
2210
}
2211
}
2212
2213
void TR_EscapeAnalysis::associateAselectWithChild(TR::Node *aselectNode, int32_t idx)
2214
{
2215
TR::Region &stackMemoryRegion = trMemory()->currentStackRegion();
2216
TR::Node *child = aselectNode->getChild(idx);
2217
2218
NodeDeque *currChildUses;
2219
2220
if (NULL == _nodeUsesThroughAselect)
2221
{
2222
_nodeUsesThroughAselect =
2223
new (trStackMemory()) NodeToNodeDequeMap((NodeComparator()),
2224
NodeToNodeDequeMapAllocator(stackMemoryRegion));
2225
}
2226
2227
auto search = _nodeUsesThroughAselect->find(child);
2228
bool nodeAlreadyMapsToAselect = false;
2229
2230
if (_nodeUsesThroughAselect->end() != search)
2231
{
2232
currChildUses = search->second;
2233
2234
// Does NodeDeque already contain this aselect node?
2235
nodeAlreadyMapsToAselect =
2236
(std::find(search->second->begin(), search->second->end(),
2237
aselectNode) != search->second->end());
2238
}
2239
else
2240
{
2241
currChildUses = new (trStackMemory()) NodeDeque(stackMemoryRegion);
2242
(*_nodeUsesThroughAselect)[child] = currChildUses;
2243
}
2244
2245
if (!nodeAlreadyMapsToAselect)
2246
{
2247
currChildUses->push_back(aselectNode);
2248
}
2249
}
2250
2251
bool TR_EscapeAnalysis::collectValueNumbersOfIndirectAccessesToObject(TR::Node *node, Candidate *candidate, TR::Node *indirectStore, TR::NodeChecklist& visited, int32_t baseChildVN)
2252
{
2253
if (visited.contains(node))
2254
return false;
2255
visited.add(node);
2256
2257
bool foundAccess = false;
2258
2259
if (node->getOpCode().isLoadIndirect())
2260
{
2261
bool sameSymbol = false;
2262
if (node->getSymbolReference()->getReferenceNumber() == indirectStore->getSymbolReference()->getReferenceNumber())
2263
sameSymbol = true;
2264
else if (indirectStore->getSymbolReference()->sharesSymbol())
2265
{
2266
if (indirectStore->getSymbolReference()->getUseDefAliases().contains(node->getSymbolReference(), comp()))
2267
sameSymbol = true;
2268
}
2269
2270
if (trace())
2271
traceMsg(comp(), "store node %p load node %p candidate %p baseChildVN %d\n", indirectStore, node, candidate->_node, baseChildVN);
2272
2273
if (sameSymbol)
2274
{
2275
TR::Node *base = node->getFirstChild();
2276
2277
if (/* node->getSymbol()->isArrayShadowSymbol() && */
2278
base->getOpCode().isArrayRef())
2279
base = base->getFirstChild();
2280
2281
int32_t baseVN = _valueNumberInfo->getValueNumber(base);
2282
2283
//traceMsg(comp(), "store node %p load node %p candidate %p baseChildVN %d baseVN %d\n", indirectStore, node, candidate->_node, baseChildVN, baseVN);
2284
2285
if (candidate->_valueNumbers)
2286
{
2287
if ((baseChildVN == -1) && usesValueNumber(candidate, baseVN))
2288
{
2289
candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));
2290
if (checkDefsAndUses(node, candidate))
2291
foundAccess = true;
2292
else
2293
{
2294
TR::Node *resolvedBaseObject = resolveSniffedNode(indirectStore->getFirstChild());
2295
if (resolvedBaseObject)
2296
{
2297
_notOptimizableLocalObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(resolvedBaseObject));
2298
_notOptimizableLocalStringObjectsValueNumbers->set(_valueNumberInfo->getValueNumber(resolvedBaseObject));
2299
}
2300
}
2301
}
2302
else if (baseChildVN != -1)
2303
{
2304
if (baseChildVN == baseVN)
2305
{
2306
candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));
2307
if (checkDefsAndUses(node, candidate))
2308
foundAccess = true;
2309
else
2310
{
2311
_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);
2312
_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);
2313
}
2314
}
2315
else
2316
{
2317
TR::Node *storeBase = indirectStore->getFirstChild();
2318
if (/* indirectStore->getSymbol()->isArrayShadowSymbol() && */
2319
storeBase->getOpCode().isArrayRef())
2320
storeBase = storeBase->getFirstChild();
2321
2322
2323
if (base->getOpCode().hasSymbolReference() && base->getSymbolReference()->getSymbol()->isAuto())
2324
{
2325
if (_useDefInfo)
2326
{
2327
uint16_t baseIndex = base->getUseDefIndex();
2328
//uint16_t storeBaseIndex = storeBase->getUseDefIndex();
2329
TR_UseDefInfo::BitVector baseDefs(comp()->allocator());
2330
_useDefInfo->getUseDef(baseDefs, baseIndex);
2331
//TR_UseDefInfo::BitVector storeBaseDefs(comp()->allocator());
2332
//_useDefInfo->getUseDef(storeBaseDefs, storeBaseIndex);
2333
//traceMsg(comp(), "store base index %d store base %p base index %p base %p\n", storeBaseIndex, storeBase, baseIndex, base);
2334
2335
_vnTemp->set(_valueNumberInfo->getValueNumber(storeBase));
2336
while (*_vnTemp2 != *_vnTemp)
2337
{
2338
_vnTemp->print(comp());
2339
*_vnTemp2 = *_vnTemp;
2340
int32_t i;
2341
for (i = _useDefInfo->getNumDefOnlyNodes()-1; i >= 0; --i)
2342
{
2343
int32_t useDefIndex = i + _useDefInfo->getFirstDefIndex();
2344
TR::Node *defNode = _useDefInfo->getNode(useDefIndex);
2345
//traceMsg(comp(), "def node %p\n", defNode);
2346
2347
if (defNode && defNode->getOpCode().isStore())
2348
{
2349
if (_vnTemp->get(_valueNumberInfo->getValueNumber(defNode)))
2350
{
2351
TR_UseDefInfo::BitVector usesOfThisDef(comp()->allocator());
2352
_useDefInfo->getUsesFromDef(usesOfThisDef, defNode->getUseDefIndex()+_useDefInfo->getFirstDefIndex());
2353
if (!usesOfThisDef.IsZero())
2354
{
2355
TR_UseDefInfo::BitVector::Cursor cursor(usesOfThisDef);
2356
for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())
2357
{
2358
int32_t useIndex = cursor;
2359
TR::Node *useNode = _useDefInfo->getNode(useIndex+_useDefInfo->getFirstUseIndex());
2360
int32_t useNodeVN = _valueNumberInfo->getValueNumber(useNode);
2361
//traceMsg(comp(), "use node %p vn %d\n", useNode, useNodeVN);
2362
2363
_vnTemp->set(useNodeVN);
2364
}
2365
}
2366
}
2367
}
2368
}
2369
}
2370
2371
TR_UseDefInfo::BitVector::Cursor cursor(baseDefs);
2372
for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())
2373
{
2374
int32_t defIndex = _useDefInfo->getFirstDefIndex() + (int32_t) cursor;
2375
//TODO: Temporary fix to overcome case when defIndex = 0
2376
if (defIndex < _useDefInfo->getFirstRealDefIndex())
2377
continue;
2378
2379
TR::Node *defNode = _useDefInfo->getNode(defIndex);
2380
if (_vnTemp->get(_valueNumberInfo->getValueNumber(defNode)))
2381
{
2382
candidate->_valueNumbers->add(_valueNumberInfo->getValueNumber(node));
2383
break;
2384
}
2385
}
2386
}
2387
}
2388
2389
_notOptimizableLocalObjectsValueNumbers->set(baseChildVN);
2390
_notOptimizableLocalStringObjectsValueNumbers->set(baseChildVN);
2391
}
2392
}
2393
}
2394
}
2395
}
2396
2397
2398
int32_t i;
2399
for (i=0;i<node->getNumChildren(); i++)
2400
{
2401
if (collectValueNumbersOfIndirectAccessesToObject(node->getChild(i), candidate, indirectStore, visited, baseChildVN))
2402
foundAccess = true;
2403
}
2404
return foundAccess;
2405
}
2406
2407
2408
bool TR_EscapeAnalysis::checkUsesThroughAselect(TR::Node *node, Candidate *candidate)
2409
{
2410
bool returnValue = true;
2411
2412
if (_nodeUsesThroughAselect)
2413
{
2414
auto search = _nodeUsesThroughAselect->find(node);
2415
2416
// Is this node referenced directly by any aselect nodes?
2417
if (_nodeUsesThroughAselect->end() != search)
2418
{
2419
for (auto di = search->second->begin(), end = search->second->end(); di != end; di++)
2420
{
2421
TR::Node* aselectNode = *di;
2422
int32_t aselectVN = _valueNumberInfo->getValueNumber(aselectNode);
2423
int32_t i;
2424
2425
// Check whether this aselect has already been accounted for with this candidate
2426
for (i = candidate->_valueNumbers->size()-1; i >= 0; i--)
2427
{
2428
if (candidate->_valueNumbers->element(i) == aselectVN)
2429
{
2430
break;
2431
}
2432
}
2433
2434
// If this aselect has not been accounted for with this candidate, check for its uses
2435
if (i < 0)
2436
{
2437
candidate->_valueNumbers->add(aselectVN);
2438
2439
if (trace())
2440
{
2441
traceMsg(comp(), " Checking uses of node %p through aselect operation %p for candidate %p\n", node, aselectNode, candidate->_node);
2442
}
2443
2444
if (!checkDefsAndUses(aselectNode, candidate))
2445
{
2446
returnValue = false;
2447
}
2448
}
2449
}
2450
}
2451
}
2452
2453
return returnValue;
2454
}
2455
2456
2457
bool TR_EscapeAnalysis::checkDefsAndUses(TR::Node *node, Candidate *candidate)
2458
{
2459
TR::Node *next;
2460
_useDefInfo->buildDefUseInfo();
2461
bool returnValue = true;
2462
2463
if (_nodeUsesThroughAselect && !checkUsesThroughAselect(node, candidate))
2464
{
2465
returnValue = false;
2466
}
2467
2468
for (next = _valueNumberInfo->getNext(node); next != node; next = _valueNumberInfo->getNext(next))
2469
{
2470
int32_t udIndex = next->getUseDefIndex();
2471
2472
if (_useDefInfo->isDefIndex(udIndex))
2473
{
2474
if (next->getOpCode().isStore() && next->getSymbol()->isAutoOrParm())
2475
{
2476
TR::SymbolReference *symRef = next->getSymbolReference();
2477
if (!candidate->getSymRefs()->find(symRef))
2478
candidate->addSymRef(symRef);
2479
2480
// Find all uses of this def and see if their value numbers are
2481
// already known in the array of value numbers.
2482
// If not, add the new value number and recurse to find value
2483
// numbers of nodes reachable from this use.
2484
//
2485
2486
TR_UseDefInfo::BitVector defUse(comp()->allocator());
2487
_useDefInfo->getUsesFromDef(defUse, udIndex-_useDefInfo->getFirstDefIndex());
2488
if (!defUse.IsZero())
2489
{
2490
TR_UseDefInfo::BitVector::Cursor cursor(defUse);
2491
for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())
2492
{
2493
int32_t useIndex = cursor;
2494
TR::Node *useNode = _useDefInfo->getNode(useIndex+_useDefInfo->getFirstUseIndex());
2495
2496
// Only add this value number if it's not to be ignored
2497
if (_ignoreableUses->get(useNode->getGlobalIndex()))
2498
{
2499
continue;
2500
}
2501
2502
int32_t useNodeVN = _valueNumberInfo->getValueNumber(useNode);
2503
int32_t i;
2504
2505
for (i = candidate->_valueNumbers->size()-1; i >= 0; i--)
2506
{
2507
if (candidate->_valueNumbers->element(i) == useNodeVN)
2508
{
2509
break;
2510
}
2511
}
2512
2513
if (i < 0)
2514
{
2515
candidate->_valueNumbers->add(useNodeVN);
2516
2517
if (candidate->isInsideALoop())
2518
{
2519
static char *p = feGetEnv("TR_NoLoopAlloc");
2520
if (!p)
2521
{
2522
// For an allocation inside a loop we must make sure
2523
// that two generations of the allocation can't
2524
// co-exist.
2525
// There are 2 ways this can happen - check them.
2526
//
2527
if (trace())
2528
traceMsg(comp(), " Look at other defs for use node %p of candidate %p\n", useNode, candidate->_node);
2529
////_otherDefsForLoopAllocation->set(udIndex);
2530
2531
if (!checkOverlappingLoopAllocation(useNode, candidate))
2532
{
2533
if (trace())
2534
traceMsg(comp(), " Make [%p] non-local because it overlaps with use [%p]\n", candidate->_node, useNode);
2535
/////printf("secs Overlapping loop allocation in %s\n", comp()->signature());
2536
returnValue = false;
2537
}
2538
if (!checkOtherDefsOfLoopAllocation(useNode, candidate, (next->getFirstChild() == candidate->_node)))
2539
{
2540
if (trace())
2541
traceMsg(comp(), " Make [%p] non-local because multiple defs to node [%p]\n", candidate->_node, useNode);
2542
returnValue = false;
2543
}
2544
}
2545
else
2546
returnValue = false;
2547
}
2548
if (!checkDefsAndUses(useNode, candidate))
2549
returnValue = false;
2550
}
2551
}
2552
}
2553
}
2554
}
2555
2556
if (_useDefInfo->isUseIndex(udIndex))
2557
{
2558
if (_nodeUsesThroughAselect && !checkUsesThroughAselect(next, candidate))
2559
{
2560
returnValue = false;
2561
}
2562
}
2563
}
2564
return returnValue;
2565
}
2566
2567
bool TR_EscapeAnalysis::checkOtherDefsOfLoopAllocation(TR::Node *useNode, Candidate *candidate, bool isImmediateUse)
2568
{
2569
// The allocation is inside a loop and a use has been found that has other
2570
// defs too. Find all the possible defs for this use and make sure none of
2571
// them lead back to the allocation. If they do, it means that generations
2572
// of the allocation from different loop iterations may be alive at the same
2573
// time, so the allocation must be done from the heap and not the stack.
2574
//
2575
// In some limited cases, we can be sure that an object from a prior loop iteration
2576
// was not live at the same time as an object from the next loop iteration without expensive analysis.
2577
// One such "special" case is when all defs for uses reached by our candidate for stack allocation
2578
// were fed by allocations; in this case it's easy to see that it was not an object from a prior iteration
2579
// since it is a fresh allocation being done at that program point.
2580
//
2581
// There is one other special case dealt with in the code below related to a java/lang/Integer cache
2582
// where again it's trivial to prove that the value cannot be a candidate allocation from a prior loop iteration
2583
//
2584
// There may be other such examples that can be added in the future, e.g. if the value is an already stack allocated
2585
// object from a prior pass of escape analysis, it obviously cannot be a candidate for stack allocation in this pass.
2586
//
2587
int32_t useIndex = useNode->getUseDefIndex();
2588
if (useIndex <= 0)
2589
return true;
2590
2591
TR_UseDefInfo::BitVector defs(comp()->allocator());
2592
_useDefInfo->getUseDef(defs, useIndex);
2593
TR_UseDefInfo::BitVector::Cursor cursor(defs);
2594
for (cursor.SetToFirstOne(); cursor.Valid(); cursor.SetToNextOne())
2595
{
2596
int32_t defIndex = cursor;
2597
if (defIndex < _useDefInfo->getFirstRealDefIndex() /* || _otherDefsForLoopAllocation->get(defIndex) */)
2598
{
2599
continue;
2600
}
2601
2602
bool seenOtherDef = false;
2603
if (_otherDefsForLoopAllocation->get(defIndex))
2604
seenOtherDef = true;
2605
2606
// Ignore the def that is the one that caused us to look at this use in
2607
// the first place
2608
//
2609
TR::Node *defNode = _useDefInfo->getNode(defIndex);
2610
if (!seenOtherDef &&
2611
isImmediateUse &&
2612
_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(candidate->_node))
2613
///_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(useNode))
2614
{
2615
if (trace())
2616
traceMsg(comp(), " Ignoring def node [%p] for use node [%p]\n", defNode, useNode);
2617
continue;
2618
}
2619
2620
_otherDefsForLoopAllocation->set(defIndex);
2621
2622
if (trace())
2623
traceMsg(comp(), " Look at def node [%p] for use node [%p]\n", defNode, useNode);
2624
2625
bool allnewsonrhs;
2626
2627
if (_doLoopAllocationAliasChecking)
2628
{
2629
allnewsonrhs = checkAllNewsOnRHSInLoopWithAliasing(defIndex, useNode, candidate);
2630
}
2631
else
2632
{
2633
allnewsonrhs = checkAllNewsOnRHSInLoop(defNode, useNode, candidate);
2634
}
2635
2636
2637
if (!allnewsonrhs &&
2638
!(defNode->getOpCode().isStoreDirect() &&
2639
((defNode->getFirstChild()->getOpCodeValue() == TR::aconst) ||
2640
(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)
2641
(defNode->getFirstChild()->getSymbol()->isStatic() ||
2642
(defNode->getFirstChild()->getSymbol()->isShadow() &&
2643
(defNode->getFirstChild()->getSymbol()->isArrayShadowSymbol() ||
2644
!_nonColdLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(defNode->getFirstChild()->getFirstChild())))))))))
2645
{
2646
if (_valueNumberInfo->getValueNumber(defNode) != _valueNumberInfo->getValueNumber(useNode))
2647
{
2648
// If the use is outside the loop, make sure that there are stores to temp t on all possible
2649
// paths from the allocation to the use (load of temp t). This will ensure that a prior iteration's
2650
// allocation is not what is pointed at by temp t when we reach the use of temp t.
2651
//
2652
if (checkIfUseIsInSameLoopAsDef(_useDefInfo->getTreeTop(defIndex), useNode) ||
2653
checkIfUseIsInLoopAndOverlapping(candidate, _useDefInfo->getTreeTop(defIndex), useNode))
2654
{
2655
if (trace())
2656
traceMsg(comp(), " Def node [%p] same as candidate [%p]\n", defNode, candidate->_node);
2657
return false;
2658
}
2659
}
2660
}
2661
2662
if (!seenOtherDef && defNode->getOpCode().isStore() && defNode->getSymbol()->isAutoOrParm())
2663
{
2664
if (!checkOtherDefsOfLoopAllocation(defNode->getFirstChild(), candidate, false))
2665
return false;
2666
}
2667
2668
if (trace())
2669
traceMsg(comp(), " Def node [%p] not the same as candidate [%p]\n", defNode, candidate->_node);
2670
}
2671
return true;
2672
}
2673
2674
bool TR_EscapeAnalysis::checkAllNewsOnRHSInLoopWithAliasing(int32_t defIndex, TR::Node *useNode, Candidate *candidate)
2675
{
2676
TR_ASSERT(_doLoopAllocationAliasChecking, "Reached checkAllNewsOnRHSInLoopWithAliasing unexpectedly");
2677
2678
// _aliasesOfAllocNode contains sym refs that are just aliases for a fresh allocation
2679
// i.e. it is just a simple attempt at tracking allocations in cases such as :
2680
// ...
2681
// a = new A()
2682
// ...
2683
// b = a
2684
// ...
2685
// c = b
2686
//
2687
// In this case a, b and c will all be considered aliases of an alloc node and so a load of
2688
// any of those sym refs will be treated akin to how the fresh allocation would have been in the below logic
2689
//
2690
2691
TR::Node *defNode = _useDefInfo->getNode(defIndex);
2692
int32_t useIndex = useNode->getUseDefIndex();
2693
bool allnewsonrhs = false;
2694
2695
if ((defNode->getFirstChild() == candidate->_node) &&
2696
(_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(useNode)))
2697
{
2698
if (trace())
2699
{
2700
traceMsg(comp(), " Value numbers match for def node [%p] with use node [%p]\n", defNode, useNode);
2701
}
2702
allnewsonrhs = true;
2703
}
2704
else if ((_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(candidate->_node)) &&
2705
(_useDefInfo->getTreeTop(defIndex)->getEnclosingBlock() == candidate->_block) &&
2706
_aliasesOfAllocNode->get(defNode->getSymbolReference()->getReferenceNumber()))
2707
{
2708
if (trace())
2709
{
2710
traceMsg(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);
2711
}
2712
allnewsonrhs = true;
2713
}
2714
else
2715
{
2716
allnewsonrhs = true;
2717
TR_UseDefInfo::BitVector defs2(comp()->allocator());
2718
_useDefInfo->getUseDef(defs2, useIndex);
2719
TR_UseDefInfo::BitVector::Cursor cursor2(defs2);
2720
2721
// Loop over definitions for this use and over all the candidate
2722
// allocations. If the definition comes directly from a candidate
2723
// for stack allocation, it's harmless; if it's copied from a
2724
// variable that's aliased with a candidate for stack allocation
2725
// that was allocated in the same block, it's harmless
2726
for (cursor2.SetToFirstOne(); cursor2.Valid(); cursor2.SetToNextOne())
2727
{
2728
int32_t defIndex2 = cursor2;
2729
if (defIndex2 == 0)
2730
{
2731
allnewsonrhs = false;
2732
break;
2733
}
2734
2735
TR::Node *defNode2 = _useDefInfo->getNode(defIndex2);
2736
TR::Node *firstChild = defNode2->getFirstChild();
2737
2738
// Is RHS for this reaching definition harmless? I.e., not a
2739
// definition that can escape the loop. It is considered harmless if
2740
// it is a candidate for stack allocation, an alias of a candidate
2741
// or it is an entry in the cache for java.lang.Integer, et al.
2742
bool rhsIsHarmless = false;
2743
2744
for (Candidate *otherAllocNode = _candidates.getFirst(); otherAllocNode; otherAllocNode = otherAllocNode->getNext())
2745
{
2746
// A reaching definition that is an allocation node for a candidate
2747
// for stack allocation is harmless. Also, a reaching definition
2748
// that has the value number of a candidate allocation, other than the
2749
// current candidate, is harmless. The added restriction in the
2750
// second case avoids allowing the current candidate through from a
2751
// a previous loop iteration.
2752
if (otherAllocNode->_node == firstChild
2753
|| (candidate->_node != otherAllocNode->_node
2754
&& _valueNumberInfo->getValueNumber(otherAllocNode->_node)
2755
== _valueNumberInfo->getValueNumber(firstChild)))
2756
{
2757
rhsIsHarmless = true;
2758
break;
2759
}
2760
2761
if (trace())
2762
{
2763
traceMsg(comp(), " Look at defNode2 [%p] with otherAllocNode [%p]\n", defNode2, otherAllocNode);
2764
}
2765
2766
if (!rhsIsHarmless &&
2767
(_valueNumberInfo->getValueNumber(defNode2) == _valueNumberInfo->getValueNumber(otherAllocNode->_node)))
2768
{
2769
TR::TreeTop *treeTop;
2770
bool collectAliases = false;
2771
_aliasesOfOtherAllocNode->empty();
2772
_visitedNodes->empty();
2773
for (treeTop = otherAllocNode->_treeTop->getEnclosingBlock()->getEntry(); treeTop; treeTop = treeTop->getNextTreeTop())
2774
{
2775
TR::Node *node = treeTop->getNode();
2776
if (node->getOpCodeValue() == TR::BBEnd)
2777
break;
2778
2779
// Until we reach otherAllocNode, call visitTree to
2780
// ignore nodes in those trees. After we've reached
2781
// otherAllocNode, call collectAliasesOfAllocations to
2782
// track its aliases in _aliasesOfOtherAllocNode
2783
if (!collectAliases)
2784
{
2785
visitTree(treeTop->getNode());
2786
}
2787
else
2788
{
2789
collectAliasesOfAllocations(treeTop->getNode(), otherAllocNode->_node);
2790
}
2791
2792
if (treeTop == otherAllocNode->_treeTop)
2793
{
2794
collectAliases = true;
2795
}
2796
}
2797
2798
if ((_useDefInfo->getTreeTop(defIndex2)->getEnclosingBlock() == otherAllocNode->_block) &&
2799
_aliasesOfOtherAllocNode->get(defNode2->getSymbolReference()->getReferenceNumber()))
2800
{
2801
if (trace())
2802
{
2803
traceMsg(comp(), " rhs is harmless for defNode2 [%p] with otherAllocNode [%p]\n", defNode2, otherAllocNode);
2804
}
2805
rhsIsHarmless = true;
2806
break;
2807
}
2808
}
2809
}
2810
2811
if (!rhsIsHarmless)
2812
{
2813
if (trace())
2814
{
2815
traceMsg(comp(), " defNode2 vn=%d is local %d\n", _valueNumberInfo->getValueNumber(defNode2), _allLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(defNode2)));
2816
}
2817
2818
// References to objects that were previously made local are also harmless
2819
if (_allLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(defNode2)))
2820
{
2821
rhsIsHarmless = true;
2822
}
2823
}
2824
2825
if (!rhsIsHarmless)
2826
{
2827
// Another special case when it is certain that the rhs of the def is not a candidate allocation from a prior iteration
2828
// In this case we are loading a value from an Integer cache anyway and that should be an allocation that has already escaped
2829
// that has nothing to do with the candidate allocation
2830
//
2831
if (firstChild->getOpCode().hasSymbolReference() &&
2832
firstChild->getSymbol()->isArrayShadowSymbol())
2833
{
2834
TR::Node *addr = firstChild->getFirstChild();
2835
if (addr->getOpCode().isArrayRef())
2836
{
2837
TR::Node *underlyingArray = addr->getFirstChild();
2838
2839
int32_t fieldNameLen = -1;
2840
char *fieldName = NULL;
2841
if (underlyingArray && underlyingArray->getOpCode().hasSymbolReference() &&
2842
underlyingArray->getSymbolReference()->getSymbol()->isStaticField())
2843
{
2844
fieldName = underlyingArray->getSymbolReference()->getOwningMethod(comp())->staticName(underlyingArray->getSymbolReference()->getCPIndex(), fieldNameLen, comp()->trMemory());
2845
}
2846
2847
if (fieldName && (fieldNameLen > 10) &&
2848
!strncmp("java/lang/", fieldName, 10) &&
2849
(!strncmp("Integer$IntegerCache.cache", &fieldName[10], 26) ||
2850
!strncmp("Long$LongCache.cache", &fieldName[10], 20) ||
2851
!strncmp("Short$ShortCache.cache", &fieldName[10], 22) ||
2852
!strncmp("Byte$ByteCache.cache", &fieldName[10], 20) ||
2853
!strncmp("Character$CharacterCache.cache", &fieldName[10], 30)))
2854
2855
{
2856
if (trace())
2857
{
2858
traceMsg(comp(), " rhs is harmless for defNode2 [%p] access of Integer cache\n", defNode2);
2859
}
2860
2861
rhsIsHarmless = true;
2862
}
2863
}
2864
}
2865
}
2866
2867
if (!rhsIsHarmless)
2868
{
2869
if (trace())
2870
{
2871
traceMsg(comp(), " rhs not harmless for defNode2 [%p]\n", defNode2);
2872
}
2873
2874
allnewsonrhs = false;
2875
break;
2876
}
2877
}
2878
}
2879
2880
return allnewsonrhs;
2881
}
2882
2883
bool TR_EscapeAnalysis::checkAllNewsOnRHSInLoop(TR::Node *defNode, TR::Node *useNode, Candidate *candidate)
2884
{
2885
TR_ASSERT(!_doLoopAllocationAliasChecking, "Reached checkAllNewsOnRHSInLoop unexpectedly");
2886
2887
int32_t useIndex = useNode->getUseDefIndex();
2888
bool allnewsonrhs = false;
2889
2890
if ((_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(candidate->_node)))
2891
{
2892
if ((defNode->getFirstChild() == candidate->_node) &&
2893
(_valueNumberInfo->getValueNumber(defNode) == _valueNumberInfo->getValueNumber(useNode)))
2894
allnewsonrhs = true;
2895
else
2896
{
2897
allnewsonrhs = true;
2898
TR_UseDefInfo::BitVector defs2(comp()->allocator());
2899
_useDefInfo->getUseDef(defs2, useIndex);
2900
TR_UseDefInfo::BitVector::Cursor cursor2(defs2);
2901
for (cursor2.SetToFirstOne(); cursor2.Valid(); cursor2.SetToNextOne())
2902
{
2903
int32_t defIndex2 = cursor2;
2904
if (defIndex2 == 0)
2905
{
2906
allnewsonrhs = false;
2907
break;
2908
}
2909
2910
TR::Node *defNode2 = _useDefInfo->getNode(defIndex2);
2911
TR::Node *firstChild = defNode2->getFirstChild();
2912
bool rhsIsHarmless = false;
2913
for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
2914
{
2915
if (candidate->_node == firstChild)
2916
{
2917
rhsIsHarmless = true;
2918
break;
2919
}
2920
}
2921
2922
2923
if (!rhsIsHarmless)
2924
{
2925
if (firstChild->getOpCode().hasSymbolReference() &&
2926
firstChild->getSymbol()->isArrayShadowSymbol())
2927
{
2928
TR::Node *addr = firstChild->getFirstChild();
2929
if (addr->getOpCode().isArrayRef())
2930
{
2931
TR::Node *underlyingArray = addr->getFirstChild();
2932
2933
int32_t fieldNameLen = -1;
2934
char *fieldName = NULL;
2935
if (underlyingArray && underlyingArray->getOpCode().hasSymbolReference() &&
2936
underlyingArray->getSymbolReference()->getSymbol()->isStaticField())
2937
{
2938
fieldName = underlyingArray->getSymbolReference()->getOwningMethod(comp())->staticName(underlyingArray->getSymbolReference()->getCPIndex(), fieldNameLen, comp()->trMemory());
2939
}
2940
2941
if (fieldName && (fieldNameLen > 0) &&
2942
!strncmp(fieldName, "java/lang/Integer$IntegerCache.cache", 36))
2943
rhsIsHarmless = true;
2944
}
2945
}
2946
}
2947
2948
if (!rhsIsHarmless)
2949
{
2950
allnewsonrhs = false;
2951
break;
2952
}
2953
}
2954
}
2955
}
2956
2957
return allnewsonrhs;
2958
}
2959
2960
bool TR_EscapeAnalysis::checkOverlappingLoopAllocation(TR::Node *useNode, Candidate *candidate)
2961
{
2962
// The allocation is inside a loop and a use has been found that has other
2963
// defs too. If the allocation can be used directly while the use node
2964
// holds a previous generation, the allocation cannot be made local.
2965
// To check this, walk forward from the candidate allocation to find the use
2966
// node. If it is found in the same extended block before the last use of the
2967
// allocation node the two can co-exist so the allocation cannot be local.
2968
//
2969
TR::TreeTop *treeTop;
2970
_visitedNodes->empty();
2971
if (_doLoopAllocationAliasChecking)
2972
{
2973
_aliasesOfAllocNode->empty();
2974
}
2975
rcount_t numReferences = 0; //candidate->_node->getReferenceCount()-1;
2976
for (treeTop = candidate->_treeTop->getEnclosingBlock()->getEntry(); treeTop; treeTop = treeTop->getNextTreeTop())
2977
{
2978
TR::Node *node = treeTop->getNode();
2979
if (node->getOpCodeValue() == TR::BBEnd)
2980
break;
2981
if (!checkOverlappingLoopAllocation(treeTop->getNode(), useNode, candidate->_node, numReferences))
2982
return false;
2983
if (treeTop == candidate->_treeTop)
2984
numReferences = candidate->_node->getReferenceCount();
2985
2986
//if (numReferences == 0)
2987
// break;
2988
}
2989
return true;
2990
}
2991
2992
bool TR_EscapeAnalysis::checkOverlappingLoopAllocation(TR::Node *node, TR::Node *useNode, TR::Node *allocNode, rcount_t &numReferences)
2993
{
2994
if (_visitedNodes->get(node->getGlobalIndex()))
2995
{
2996
return true;
2997
}
2998
2999
_visitedNodes->set(node->getGlobalIndex());
3000
3001
if (_doLoopAllocationAliasChecking
3002
&& node->getOpCode().isStore() && node->getSymbol()->isAutoOrParm())
3003
{
3004
if (node->getFirstChild() == allocNode)
3005
{
3006
_aliasesOfAllocNode->set(node->getSymbolReference()->getReferenceNumber());
3007
}
3008
else if (!_visitedNodes->get(node->getFirstChild()->getGlobalIndex())
3009
&& node->getFirstChild()->getOpCode().isLoadVarDirect()
3010
&& node->getFirstChild()->getSymbol()->isAutoOrParm()
3011
&& _aliasesOfAllocNode->get(node->getFirstChild()->getSymbolReference()->getReferenceNumber()))
3012
{
3013
_aliasesOfAllocNode->set(node->getSymbolReference()->getReferenceNumber());
3014
}
3015
else
3016
{
3017
_aliasesOfAllocNode->reset(node->getSymbolReference()->getReferenceNumber());
3018
}
3019
}
3020
3021
if ((node != allocNode)
3022
&& (_valueNumberInfo->getValueNumber(node) == _valueNumberInfo->getValueNumber(useNode)))
3023
{
3024
if (!_doLoopAllocationAliasChecking
3025
|| (!(node->getOpCode().isLoadVarDirect()
3026
&& _aliasesOfAllocNode->get(node->getSymbolReference()->getReferenceNumber()))
3027
&& (numReferences > 0)))
3028
{
3029
return false;
3030
}
3031
}
3032
//if (node == allocNode)
3033
// {
3034
// if (--numReferences == 0)
3035
// return true;
3036
// }
3037
for (int32_t i = 0; /* numReferences > 0 && */ i < node->getNumChildren(); i++)
3038
{
3039
if (!checkOverlappingLoopAllocation(node->getChild(i), useNode, allocNode, numReferences))
3040
return false;
3041
}
3042
return true;
3043
}
3044
3045
3046
void TR_EscapeAnalysis::visitTree(TR::Node *node)
3047
{
3048
if (_visitedNodes->get(node->getGlobalIndex()))
3049
{
3050
return;
3051
}
3052
3053
_visitedNodes->set(node->getGlobalIndex());
3054
3055
for (int32_t i = 0; i < node->getNumChildren(); i++)
3056
{
3057
visitTree(node->getChild(i));
3058
}
3059
}
3060
3061
void TR_EscapeAnalysis::collectAliasesOfAllocations(TR::Node *node, TR::Node *allocNode)
3062
{
3063
TR_ASSERT(_doLoopAllocationAliasChecking, "Reached collectAliasesOfAllocations unexpectedly");
3064
if (_visitedNodes->get(node->getGlobalIndex()))
3065
{
3066
return;
3067
}
3068
3069
_visitedNodes->set(node->getGlobalIndex());
3070
3071
if (node->getOpCode().isStore() && node->getSymbol()->isAutoOrParm())
3072
{
3073
if (node->getFirstChild() == allocNode)
3074
{
3075
_aliasesOfOtherAllocNode->set(node->getSymbolReference()->getReferenceNumber());
3076
}
3077
else if (!_visitedNodes->get(node->getFirstChild()->getGlobalIndex())
3078
&& node->getFirstChild()->getOpCode().isLoadVarDirect()
3079
&& node->getFirstChild()->getSymbol()->isAutoOrParm()
3080
&& _aliasesOfOtherAllocNode->get(node->getFirstChild()->getSymbolReference()->getReferenceNumber()))
3081
{
3082
_aliasesOfOtherAllocNode->set(node->getSymbolReference()->getReferenceNumber());
3083
}
3084
else
3085
{
3086
_aliasesOfOtherAllocNode->reset(node->getSymbolReference()->getReferenceNumber());
3087
}
3088
}
3089
3090
for (int32_t i = 0; i < node->getNumChildren(); i++)
3091
{
3092
collectAliasesOfAllocations(node->getChild(i), allocNode);
3093
}
3094
}
3095
3096
3097
bool TR_EscapeAnalysis::checkIfUseIsInSameLoopAsDef(TR::TreeTop *defTree, TR::Node *useNode)
3098
{
3099
TR::Block *block = defTree->getEnclosingBlock();
3100
TR_RegionStructure *highestCyclicStructure = NULL;
3101
TR_Structure *structure = block->getStructureOf()->getParent();
3102
while (structure)
3103
{
3104
if (!structure->asRegion()->isAcyclic())
3105
highestCyclicStructure = structure->asRegion();
3106
structure = structure->getParent();
3107
}
3108
3109
if (highestCyclicStructure)
3110
{
3111
TR::NodeChecklist visited (comp());
3112
TR_ScratchList<TR::Block> blocksInRegion(trMemory());
3113
highestCyclicStructure->getBlocks(&blocksInRegion);
3114
3115
ListIterator<TR::Block> blocksIt(&blocksInRegion);
3116
TR::Block *nextBlock;
3117
for (nextBlock = blocksIt.getCurrent(); nextBlock; nextBlock=blocksIt.getNext())
3118
{
3119
TR::TreeTop *currentTree = nextBlock->getEntry();
3120
TR::TreeTop *exitTree = nextBlock->getExit();
3121
while (currentTree &&
3122
(currentTree != exitTree))
3123
{
3124
if (checkUse(currentTree->getNode(), useNode, visited))
3125
return true;
3126
3127
currentTree = currentTree->getNextTreeTop();
3128
}
3129
}
3130
3131
return false;
3132
}
3133
else
3134
return true;
3135
3136
return true;
3137
}
3138
3139
3140
bool TR_EscapeAnalysis::checkIfUseIsInLoopAndOverlapping(Candidate *candidate, TR::TreeTop *defTree, TR::Node *useNode)
3141
{
3142
TR::NodeChecklist visited (comp());
3143
TR::BlockChecklist vBlocks (comp());
3144
TR::TreeTop *allocTree = candidate->_treeTop;
3145
if (trace())
3146
traceMsg(comp(), "Started checking for candidate %p\n", candidate->_node);
3147
bool decisionMade = false;
3148
bool b = checkIfUseIsInLoopAndOverlapping(allocTree->getNextTreeTop(), candidate->_block->getExit(), defTree, useNode, visited, vBlocks, decisionMade);
3149
if (trace())
3150
traceMsg(comp(), "Finished checking for candidate %p\n", candidate->_node);
3151
return b;
3152
}
3153
3154
3155
bool TR_EscapeAnalysis::checkIfUseIsInLoopAndOverlapping(TR::TreeTop *start, TR::TreeTop *end, TR::TreeTop *defTree, TR::Node *useNode, TR::NodeChecklist& visited, TR::BlockChecklist& vBlocks, bool & decisionMade)
3156
{
3157
TR::TreeTop *currentTree = start;
3158
while (currentTree && (currentTree != end))
3159
{
3160
if (checkUse(currentTree->getNode(), useNode, visited))
3161
{
3162
decisionMade = true;
3163
if (trace())
3164
traceMsg(comp(), "Returning TRUE at %p\n", currentTree->getNode());
3165
return true;
3166
}
3167
3168
if (currentTree == defTree)
3169
{
3170
if (trace())
3171
traceMsg(comp(), "Returning FALSE at %p\n", currentTree->getNode());
3172
decisionMade = true;
3173
return false;
3174
}
3175
3176
if (currentTree->getNode()->getOpCode().isStore() &&
3177
(currentTree->getNode()->getSymbolReference() == useNode->getSymbolReference()))
3178
{
3179
if (trace())
3180
traceMsg(comp(), "Returning FALSE at %p\n", currentTree->getNode());
3181
decisionMade = true;
3182
return false;
3183
}
3184
3185
if ((currentTree->getNode()->getNumChildren() > 0) &&
3186
currentTree->getNode()->getFirstChild()->getOpCode().isStore() &&
3187
(currentTree->getNode()->getFirstChild()->getSymbolReference() == useNode->getSymbolReference()))
3188
{
3189
if (trace())
3190
traceMsg(comp(), "Returning FALSE at %p\n", currentTree->getNode());
3191
decisionMade = true;
3192
return false;
3193
}
3194
3195
currentTree = currentTree->getNextTreeTop();
3196
}
3197
3198
TR::Block *block = end->getEnclosingBlock();
3199
vBlocks.add(block);
3200
TR::CFG *cfg = comp()->getFlowGraph();
3201
3202
for (auto nextEdge = block->getSuccessors().begin(); nextEdge != block->getSuccessors().end(); ++nextEdge)
3203
{
3204
TR::Block *next = toBlock((*nextEdge)->getTo());
3205
decisionMade = false;
3206
if (!vBlocks.contains(next) && (next != cfg->getEnd()))
3207
{
3208
if (trace())
3209
traceMsg(comp(), "Looking at block_%d\n", next->getNumber());
3210
bool b = checkIfUseIsInLoopAndOverlapping(next->getEntry(), next->getExit(), defTree, useNode, visited, vBlocks, decisionMade);
3211
if (decisionMade)
3212
{
3213
if (b)
3214
return true;
3215
}
3216
}
3217
else
3218
decisionMade = true;
3219
}
3220
3221
for (auto nextEdge = block->getExceptionSuccessors().begin(); nextEdge != block->getExceptionSuccessors().end(); ++nextEdge)
3222
{
3223
TR::Block *next = toBlock((*nextEdge)->getTo());
3224
decisionMade = false;
3225
if (!vBlocks.contains(next) && (next != cfg->getEnd()))
3226
{
3227
if (trace())
3228
traceMsg(comp(), "Looking at block_%d\n", next->getNumber());
3229
bool b = checkIfUseIsInLoopAndOverlapping(next->getEntry(), next->getExit(), defTree, useNode, visited, vBlocks, decisionMade);
3230
if (decisionMade)
3231
{
3232
if (b)
3233
return true;
3234
}
3235
}
3236
else
3237
decisionMade = true;
3238
}
3239
3240
if (trace())
3241
traceMsg(comp(), "Returning FALSE at block_%d\n", block->getNumber());
3242
return false;
3243
}
3244
3245
3246
bool TR_EscapeAnalysis::checkUse(TR::Node *node, TR::Node *useNode, TR::NodeChecklist& visited)
3247
{
3248
if (visited.contains(node))
3249
return false;
3250
visited.add(node);
3251
3252
if (node == useNode)
3253
return true;
3254
3255
int32_t i;
3256
for (i = 0; i < node->getNumChildren(); ++i)
3257
{
3258
if (checkUse(node->getChild(i), useNode, visited))
3259
return true;
3260
}
3261
3262
return false;
3263
}
3264
3265
3266
Candidate *TR_EscapeAnalysis::findCandidate(int32_t valueNumber)
3267
{
3268
for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
3269
{
3270
if (candidate->_valueNumbers->element(0) == valueNumber)
3271
return candidate;
3272
}
3273
return NULL;
3274
}
3275
3276
bool TR_EscapeAnalysis::usesValueNumber(Candidate *candidate, int32_t valueNumber)
3277
{
3278
for (int32_t i = candidate->_valueNumbers->size()-1; i >= 0; i--)
3279
{
3280
if (candidate->_valueNumbers->element(i) == valueNumber)
3281
return true;
3282
}
3283
return false;
3284
}
3285
3286
// Remove any candidates that match the given value number
3287
//
3288
void TR_EscapeAnalysis::forceEscape(TR::Node *node, TR::Node *reason, bool forceFail)
3289
{
3290
TR::Node *resolvedNode = resolveSniffedNode(node);
3291
if (!resolvedNode)
3292
return;
3293
3294
int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);
3295
Candidate *candidate, *next;
3296
for (candidate = _candidates.getFirst(); candidate; candidate = next)
3297
{
3298
next = candidate->getNext();
3299
if (usesValueNumber(candidate, valueNumber))
3300
{
3301
if (!forceFail && checkIfEscapePointIsCold(candidate, reason))
3302
{
3303
if (!isImmutableObject(candidate))
3304
{
3305
if (trace())
3306
traceMsg(comp(), " Make [%p] contiguous because of node [%p]\n", candidate->_node, reason);
3307
candidate->setMustBeContiguousAllocation();
3308
//candidate->setLocalAllocation(false);
3309
}
3310
else
3311
candidate->setObjectIsReferenced();
3312
}
3313
else
3314
{
3315
if(candidate->forceLocalAllocation())
3316
{
3317
if(trace())
3318
traceMsg(comp(), " Normally would fail [%p] because it escapes via node [%p] (cold %d), but user forces it to be local\n",
3319
candidate->_node, reason, _inColdBlock);
3320
continue;
3321
}
3322
3323
if (trace())
3324
traceMsg(comp(), " Fail [%p] because it escapes via node [%p] (cold %d)\n", candidate->_node, reason, _inColdBlock);
3325
3326
rememoize(candidate);
3327
_candidates.remove(candidate);
3328
}
3329
}
3330
}
3331
}
3332
3333
3334
void TR_EscapeAnalysis::markCandidatesUsedInNonColdBlock(TR::Node *node)
3335
{
3336
TR::Node *resolvedNode = resolveSniffedNode(node);
3337
if (!resolvedNode)
3338
return;
3339
3340
int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);
3341
Candidate *candidate, *next;
3342
for (candidate = _candidates.getFirst(); candidate; candidate = next)
3343
{
3344
next = candidate->getNext();
3345
if (!candidate->usedInNonColdBlock() && usesValueNumber(candidate, valueNumber))
3346
{
3347
candidate->setUsedInNonColdBlock();
3348
if (trace())
3349
traceMsg(comp(), " Mark [%p] used in non-cold block because of node [%p]\n", candidate->_node, node);
3350
}
3351
}
3352
}
3353
3354
3355
3356
bool TR_EscapeAnalysis::detectStringCopy(TR::Node *node)
3357
{
3358
TR::Node *baseNode = node->getFirstChild();
3359
TR::Node *valueNode = node->getSecondChild();
3360
3361
Candidate *candidate, *next;
3362
for (candidate = _candidates.getFirst(); candidate; candidate = next)
3363
{
3364
next = candidate->getNext();
3365
if ((baseNode == candidate->_node) &&
3366
(baseNode->getOpCodeValue() == TR::New) &&
3367
node->getOpCode().isIndirect() &&
3368
(baseNode->getFirstChild()->getSymbolReference()->getSymbol()->getStaticSymbol()->getStaticAddress() == comp()->getStringClassPointer()))
3369
{
3370
if (valueNode->getOpCode().isIndirect() &&
3371
(valueNode->getSymbolReference() == node->getSymbolReference()) &&
3372
(valueNode->getFirstChild()->getOpCode().isLoadVar() && !valueNode->getFirstChild()->getSymbolReference()->isUnresolved()) &&
3373
((valueNode->getFirstChild() == candidate->_stringCopyNode) ||
3374
(candidate->_stringCopyNode == NULL)))
3375
{
3376
bool fitsPattern = true;
3377
if (!candidate->_stringCopyNode)
3378
{
3379
TR::TreeTop *cursorTree = candidate->_treeTop->getNextTreeTop();
3380
while (cursorTree)
3381
{
3382
TR::Node *cursorNode = cursorTree->getNode();
3383
if ((cursorNode == node) ||
3384
(cursorNode->getOpCode().isAnchor() && (cursorNode->getFirstChild() == node)) ||
3385
(cursorNode->getOpCodeValue() == TR::BBEnd))
3386
break;
3387
3388
if (cursorNode->getOpCodeValue() == TR::treetop)
3389
{
3390
if (cursorNode->getFirstChild()->getOpCode().isCall() ||
3391
cursorNode->getFirstChild()->getOpCode().isStore())
3392
fitsPattern = false;
3393
}
3394
else if (cursorNode->getOpCodeValue() == TR::astore)
3395
{
3396
if ((cursorNode->getFirstChild() != baseNode) &&
3397
(cursorNode->getFirstChild() != valueNode->getFirstChild()))
3398
fitsPattern = false;
3399
}
3400
else if (cursorNode->getOpCodeValue() == TR::NULLCHK)
3401
{
3402
if (cursorNode->getFirstChild() != valueNode)
3403
fitsPattern = false;
3404
}
3405
else if (cursorNode->getOpCode().isAnchor())
3406
{
3407
// do nothing;
3408
}
3409
else
3410
fitsPattern = false;
3411
3412
if (!fitsPattern)
3413
break;
3414
3415
cursorTree = cursorTree->getNextTreeTop();
3416
}
3417
}
3418
3419
if (fitsPattern)
3420
{
3421
candidate->_stringCopyNode = valueNode->getFirstChild();
3422
return true;
3423
}
3424
else
3425
candidate->_stringCopyNode = baseNode;
3426
}
3427
else
3428
candidate->_stringCopyNode = baseNode;
3429
}
3430
}
3431
3432
return false;
3433
}
3434
3435
3436
3437
3438
3439
3440
// Restrict any candidates that match the given value number.
3441
// The restriction can be to prevent the local allocation or just to make it
3442
// a contiguous local allocation. Desynchronization is not affected.
3443
// Return "true" if any candidates were restricted.
3444
//
3445
bool TR_EscapeAnalysis::restrictCandidates(TR::Node *node, TR::Node *reason, restrictionType type)
3446
{
3447
TR::Node *resolvedNode = resolveSniffedNode(node);
3448
if (!resolvedNode)
3449
return false;
3450
3451
bool locked = false;
3452
if (reason &&
3453
((reason->getOpCodeValue() == TR::monent) ||
3454
(reason->getOpCodeValue() == TR::monexit)))
3455
locked = true;
3456
3457
int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);
3458
Candidate *candidate;
3459
bool wasRestricted = false;
3460
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
3461
{
3462
if (candidate->isLocalAllocation() && usesValueNumber(candidate, valueNumber))
3463
{
3464
if (reason->getOpCodeValue() == TR::arraycopy)
3465
candidate->_seenArrayCopy = true;
3466
3467
if (locked)
3468
{
3469
if (!_inColdBlock)
3470
{
3471
candidate->setLockedInNonColdBlock(true);
3472
candidate->setUsedInNonColdBlock(true);
3473
if (trace())
3474
traceMsg(comp(), " Mark [%p] used and locked in non-cold block because of node [%p]\n", candidate->_node, node);
3475
}
3476
3477
candidate->setLockedObject(true);
3478
int32_t lockedObjectValueNumber = _valueNumberInfo->getValueNumber(reason->getFirstChild());
3479
Candidate *lockedCandidate = findCandidate(lockedObjectValueNumber);
3480
if (!lockedCandidate)
3481
{
3482
if (trace())
3483
traceMsg(comp(), " Make [%p] non-local because of node [%p]\n", candidate->_node, reason);
3484
wasRestricted = true;
3485
//candidate->setLocalAllocation(false);
3486
forceEscape(reason->getFirstChild(), reason);
3487
continue;
3488
}
3489
3490
TR_J9VMBase *fej9 = (TR_J9VMBase *)(fe());
3491
if (_parms && fej9->hasTwoWordObjectHeader())
3492
{
3493
TR_ScratchList<TR_ResolvedMethod> resolvedMethodsInClass(trMemory());
3494
fej9->getResolvedMethods(trMemory(), (TR_OpaqueClassBlock *) candidate->_class, &resolvedMethodsInClass);
3495
bool containsSyncMethod = false;
3496
ListIterator<TR_ResolvedMethod> resolvedIt(&resolvedMethodsInClass);
3497
TR_ResolvedMethod *resolvedMethod;
3498
for (resolvedMethod = resolvedIt.getFirst(); resolvedMethod; resolvedMethod = resolvedIt.getNext())
3499
{
3500
if (resolvedMethod->isSynchronized())
3501
{
3502
containsSyncMethod = true;
3503
break;
3504
}
3505
}
3506
if (!containsSyncMethod)
3507
{
3508
if (trace())
3509
traceMsg(comp(), " Make [%p] non-local because of node [%p]\n", candidate->_node, reason);
3510
wasRestricted = true;
3511
candidate->setLocalAllocation(false);
3512
continue;
3513
}
3514
}
3515
}
3516
3517
if (type == MakeNonLocal)
3518
{
3519
if (checkIfEscapePointIsCold(candidate, reason))
3520
{
3521
//candidate->setObjectIsReferenced();
3522
if (trace())
3523
traceMsg(comp(), " Do not make [%p] non-local because of cold node [%p]\n", candidate->_node, reason);
3524
}
3525
else
3526
{
3527
if (trace())
3528
traceMsg(comp(), " Make [%p] non-local because of node [%p]\n", candidate->_node, reason);
3529
candidate->setLocalAllocation(false);
3530
}
3531
3532
if (!isImmutableObject(candidate))
3533
wasRestricted = true;
3534
}
3535
else
3536
{
3537
if (type == MakeContiguous)
3538
{
3539
// make contiguous
3540
//
3541
if (checkIfEscapePointIsCold(candidate, reason))
3542
{
3543
//candidate->setObjectIsReferenced();
3544
if (trace())
3545
traceMsg(comp(), " Do not make [%p] contiguous because of cold node [%p]\n", candidate->_node, reason);
3546
}
3547
else
3548
{
3549
if (trace())
3550
traceMsg(comp(), " Make [%p] contiguous because of node [%p]\n", candidate->_node, reason);
3551
candidate->setMustBeContiguousAllocation();
3552
}
3553
3554
if (!isImmutableObject(candidate))
3555
wasRestricted = true;
3556
}
3557
else if (!candidate->objectIsReferenced() &&
3558
!candidate->mustBeContiguousAllocation())
3559
{
3560
if (trace())
3561
traceMsg(comp(), " Make [%p] object-referenced because of node [%p]\n", candidate->_node, reason);
3562
candidate->setObjectIsReferenced();
3563
wasRestricted = true;
3564
}
3565
}
3566
}
3567
}
3568
return wasRestricted;
3569
}
3570
3571
3572
3573
3574
bool TR_EscapeAnalysis::checkIfEscapePointIsCold(Candidate *candidate, TR::Node *node)
3575
{
3576
if (_curBlock->isOSRCodeBlock() ||
3577
_curBlock->isOSRCatchBlock())
3578
return false;
3579
3580
if (isEscapePointCold(candidate, node))
3581
{
3582
int32_t j;
3583
bool canStoreToHeap = true;
3584
for(j=0;j<node->getNumChildren();j++)
3585
{
3586
TR::Node *child = node->getChild(j);
3587
TR::Node *resolvedChildAtTopLevel = resolveSniffedNode(child);
3588
if (!resolvedChildAtTopLevel)
3589
continue;
3590
3591
if (usesValueNumber(candidate, _valueNumberInfo->getValueNumber(resolvedChildAtTopLevel)))
3592
{
3593
if (resolvedChildAtTopLevel->getOpCode().isLoadVarDirect() &&
3594
(_curBlock != candidate->_block) &&
3595
(_curBlock != comp()->getStartBlock()))
3596
{
3597
bool recognizedCatch = true;
3598
if (_curBlock->isCatchBlock())
3599
{
3600
TR::Node *firstTree = _curBlock->getEntry()->getNextTreeTop()->getNode();
3601
if (!firstTree->getOpCode().isStoreDirect() ||
3602
!firstTree->getSymbol()->isAuto() ||
3603
!firstTree->getFirstChild()->getOpCode().hasSymbolReference() ||
3604
(firstTree->getFirstChild()->getSymbolReference() != comp()->getSymRefTab()->findOrCreateExcpSymbolRef()))
3605
recognizedCatch = false;
3606
}
3607
if (recognizedCatch)
3608
{
3609
if (trace())
3610
traceMsg(comp(), "Adding cold block info for child %p value number %d candidate %p\n", child, _valueNumberInfo->getValueNumber(resolvedChildAtTopLevel), candidate->_node);
3611
3612
candidate->addColdBlockEscapeInfo(_curBlock, resolvedChildAtTopLevel, _curTree);
3613
}
3614
else
3615
{
3616
if (trace())
3617
traceMsg(comp(), " For candidate [%p], seen an unexpected opcode in child [%p] of call [%p]\n", candidate->_node, child, node);
3618
3619
canStoreToHeap = false;
3620
}
3621
}
3622
else
3623
{
3624
if (trace())
3625
traceMsg(comp(), " For candidate [%p], seen an unexpected opcode in child [%p] of call [%p]\n", candidate->_node, child, node);
3626
3627
canStoreToHeap = false;
3628
}
3629
}
3630
}
3631
3632
if (canStoreToHeap)
3633
{
3634
candidate->setObjectIsReferenced();
3635
3636
if (!isImmutableObject(candidate) && (_parms || !node->getOpCode().isReturn()))
3637
{
3638
//candidate->setObjectIsReferenced();
3639
if (trace())
3640
traceMsg(comp(), " Make candidate [%p] contiguous to allow heapification\n", candidate->_node);
3641
candidate->setMustBeContiguousAllocation();
3642
}
3643
3644
return true;
3645
}
3646
}
3647
return false;
3648
}
3649
3650
3651
3652
3653
static void checkForDifferentSymRefs(Candidate *candidate, int32_t i, TR::SymbolReference *symRef, TR_EscapeAnalysis *ea, bool peeking)
3654
{
3655
static char *dontCheckForDifferentSymRefsInEA = feGetEnv("TR_dontCheckForDifferentSymRefsInEA");
3656
if (dontCheckForDifferentSymRefsInEA)
3657
{
3658
// We don't need this logic anymore generally. Leaving it in place for
3659
// Java8 release to reduce disruption and risk.
3660
//
3661
return;
3662
}
3663
3664
TR::Compilation *comp = TR::comp();
3665
TR::SymbolReference *memorizedSymRef = candidate->_fields->element(i).fieldSymRef();
3666
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
3667
3668
if (memorizedSymRef &&
3669
(memorizedSymRef != symRef) &&
3670
(symRef->isUnresolved() ||
3671
memorizedSymRef->isUnresolved() ||
3672
((symRef->getOffset() >= (int32_t) fej9->getObjectHeaderSizeInBytes()) &&
3673
(memorizedSymRef->getOffset() >= (int32_t) fej9->getObjectHeaderSizeInBytes()))))
3674
{
3675
if ( memorizedSymRef->getCPIndex() == -1
3676
|| symRef->getCPIndex() == -1
3677
|| !TR::Compiler->cls.jitFieldsAreSame(comp, memorizedSymRef->getOwningMethod(comp), memorizedSymRef->getCPIndex(), symRef->getOwningMethod(comp), symRef->getCPIndex(), symRef->getSymbol()->isStatic()))
3678
{
3679
bool aliasingIsSafe = false;
3680
if (peeking)
3681
{
3682
// Aliasing queries don't even work on peeked nodes because their
3683
// symRef numbers refer to a different symRef table, so aliasing
3684
// info can't possibly be required for correctness.
3685
//
3686
// Having said that, we'll use "false" here to be conservative.
3687
//
3688
aliasingIsSafe = false;
3689
}
3690
else
3691
{
3692
aliasingIsSafe = symRef->getUseDefAliases(false).contains(memorizedSymRef, comp);
3693
}
3694
if (!aliasingIsSafe)
3695
{
3696
if (ea->trace())
3697
{
3698
traceMsg(comp, "candidate n%dn %p excluded coz of ambiguous field symrefs #%d [%s] and [%s]\n",
3699
candidate->_node->getGlobalIndex(), candidate->_node,
3700
memorizedSymRef->getReferenceNumber(), memorizedSymRef->getName(comp->getDebug()),
3701
symRef->getName(comp->getDebug()));
3702
}
3703
//(*candidate->_fields)[i]._isPresentInAllocatedClass=false;
3704
candidate->setLocalAllocation(false);
3705
}
3706
}
3707
}
3708
}
3709
3710
3711
TR::SymbolReference *FieldInfo::fieldSymRef()
3712
{
3713
return _goodFieldSymrefs->getHeadData();
3714
}
3715
3716
bool FieldInfo::symRefIsForFieldInAllocatedClass(TR::SymbolReference *symRef)
3717
{
3718
if (_goodFieldSymrefs->find(symRef))
3719
return true;
3720
3721
if (_badFieldSymrefs->find(symRef))
3722
return false;
3723
3724
TR_ASSERT(0, "symRefIsForFieldInAllocatedClass expects symref #%d to have been remembered", symRef->getReferenceNumber());
3725
return true;
3726
}
3727
3728
bool FieldInfo::hasBadFieldSymRef()
3729
{
3730
return !_badFieldSymrefs->isEmpty();
3731
}
3732
3733
void FieldInfo::rememberFieldSymRef(TR::Node *fieldNode, int32_t fieldOffset, Candidate *candidate, TR_EscapeAnalysis *ea)
3734
{
3735
TR_ASSERT(!ea->_parms, "rememberFieldSymRef: cannot remember peeked field SymRefs");
3736
3737
TR::SymbolReference *symRef = fieldNode->getSymbolReference();
3738
if (_goodFieldSymrefs->find(symRef) || _badFieldSymrefs->find(symRef))
3739
{
3740
// Nothing to do
3741
}
3742
else
3743
{
3744
bool isGood = false;
3745
switch (candidateHasField(candidate, fieldNode, _offset, ea))
3746
{
3747
case TR_yes:
3748
isGood = true;
3749
break;
3750
case TR_no:
3751
isGood = false;
3752
break;
3753
default:
3754
// Older (questionable) r11-era logic based on object size bound
3755
isGood = (_offset + _size <= candidate->_size);
3756
break;
3757
}
3758
3759
if (isGood)
3760
{
3761
int32_t fieldSize = fieldNode->getSize();
3762
if (ea->comp()->useCompressedPointers() && fieldNode->getDataType() == TR::Address)
3763
fieldSize = TR::Compiler->om.sizeofReferenceField();
3764
_size = fieldSize;
3765
_goodFieldSymrefs->add(symRef);
3766
}
3767
else
3768
{
3769
_badFieldSymrefs->add(symRef);
3770
}
3771
}
3772
}
3773
3774
3775
// Remember the use of a field in any candidates that can match the given node.
3776
//
3777
void TR_EscapeAnalysis::referencedField(TR::Node *base, TR::Node *field, bool isStore, bool seenSelfStore, bool seenStoreToLocalObject)
3778
{
3779
TR::Node *resolvedNode = resolveSniffedNode(base);
3780
if (!resolvedNode)
3781
return;
3782
3783
TR::SymbolReference *symRef = field->getSymbolReference();
3784
if (symRef->isUnresolved())
3785
{
3786
forceEscape(base, field, true);
3787
return;
3788
}
3789
3790
bool usesStackTrace = false;
3791
if (!isStore)
3792
{
3793
if (symRef->getSymbol()->getRecognizedField() == TR::Symbol::Java_lang_Throwable_stackTrace)
3794
usesStackTrace = true;
3795
}
3796
int32_t valueNumber = _valueNumberInfo->getValueNumber(resolvedNode);
3797
int32_t storedValueNumber = -1;
3798
if (seenStoreToLocalObject)
3799
{
3800
TR::Node *resolvedStoredValueNode = resolveSniffedNode(field->getSecondChild());
3801
if (resolvedStoredValueNode)
3802
storedValueNumber = _valueNumberInfo->getValueNumber(resolvedStoredValueNode);
3803
else
3804
seenStoreToLocalObject = false;
3805
}
3806
3807
Candidate *candidate;
3808
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
3809
{
3810
if (seenStoreToLocalObject)
3811
{
3812
if (candidate->isLocalAllocation() && usesValueNumber(candidate, storedValueNumber))
3813
{
3814
if (candidate->isInsideALoop())
3815
{
3816
candidate->setLocalAllocation(false);
3817
if (trace())
3818
traceMsg(comp(), "7 setting local alloc %p to false\n", candidate->_node);
3819
}
3820
else
3821
candidate->_seenStoreToLocalObject = true;
3822
}
3823
}
3824
3825
if (candidate->isLocalAllocation() && usesValueNumber(candidate, valueNumber))
3826
{
3827
if (usesStackTrace)
3828
{
3829
candidate->setUsesStackTrace();
3830
candidate->setMustBeContiguousAllocation();
3831
if (trace())
3832
traceMsg(comp(), " Make [%p] contiguous because of setUsesStackTrace\n", candidate->_node);
3833
}
3834
3835
// Only remember fields that are actually present in the allocated
3836
// object. It is possible to reach uses which (via downcasting) are
3837
// referencing a derived class, or even an unrelated class. At run
3838
// time the local allocation would never reach these program points,
3839
// but they are still "reachable" from a dataflow perspective, so we
3840
// must be aware of them.
3841
//
3842
if (isStore)
3843
{
3844
candidate->_seenFieldStore = true;
3845
if (seenSelfStore)
3846
candidate->_seenSelfStore = true;
3847
}
3848
3849
int32_t fieldOffset = symRef->getOffset();
3850
if (candidate->_origKind == TR::New)
3851
{
3852
fieldOffset = symRef->getOffset();
3853
}
3854
else
3855
{
3856
TR::Node *offsetNode = NULL;
3857
if (field->getFirstChild()->getOpCode().isArrayRef())
3858
offsetNode = field->getFirstChild()->getSecondChild();
3859
3860
if (offsetNode && offsetNode->getOpCode().isLoadConst())
3861
{
3862
if (offsetNode->getType().isInt64())
3863
fieldOffset = (int32_t) offsetNode->getLongInt();
3864
else
3865
fieldOffset = offsetNode->getInt();
3866
}
3867
}
3868
3869
TR::DataType refType = symRef->getSymbol()->getDataType();
3870
TR::DataType fieldType = refType;
3871
int N = 1;
3872
if (refType.isVector())
3873
{
3874
fieldType = refType.vectorToScalar();
3875
N = TR::Symbol::convertTypeToSize(refType)/TR::Symbol::convertTypeToSize(fieldType) ;
3876
}
3877
for (int j = 0; j < N; j++)
3878
{
3879
const bool isPeeking = (_parms != NULL);
3880
3881
int32_t i;
3882
if (!candidate->_fields)
3883
{
3884
candidate->_fields = new (trStackMemory()) TR_Array<FieldInfo>(trMemory(), 8, false, stackAlloc);
3885
i = -1;
3886
}
3887
else
3888
{
3889
for (i = candidate->_fields->size()-1; i >= 0; i--)
3890
{
3891
if (candidate->_fields->element(i)._offset == fieldOffset)
3892
{
3893
checkForDifferentSymRefs(candidate, i, symRef, this, isPeeking);
3894
break;
3895
}
3896
}
3897
}
3898
if (i < 0)
3899
{
3900
i = candidate->_fields->size();
3901
(*candidate->_fields)[i]._offset = fieldOffset;
3902
int32_t fieldSize = field->getSize();
3903
if (comp()->useCompressedPointers() && field->getDataType() == TR::Address)
3904
fieldSize = TR::Compiler->om.sizeofReferenceField();
3905
(*candidate->_fields)[i]._symRef = NULL;
3906
(*candidate->_fields)[i]._size = fieldSize;
3907
(*candidate->_fields)[i]._vectorElem = 0;
3908
(*candidate->_fields)[i]._goodFieldSymrefs = new (trStackMemory()) TR_ScratchList<TR::SymbolReference>(trMemory());
3909
(*candidate->_fields)[i]._badFieldSymrefs = new (trStackMemory()) TR_ScratchList<TR::SymbolReference>(trMemory());
3910
}
3911
if (!isPeeking)
3912
(*candidate->_fields)[i].rememberFieldSymRef(field, fieldOffset, candidate, this);
3913
3914
if (N > 1) // vector
3915
{
3916
(*candidate->_fields)[i]._vectorElem = j+1;
3917
fieldOffset += TR::Symbol::convertTypeToSize(fieldType);
3918
}
3919
}
3920
}
3921
}
3922
}
3923
3924
3925
3926
// Resolve the node if it is a parameter reference
3927
//
3928
TR::Node *TR_EscapeAnalysis::resolveSniffedNode(TR::Node *node)
3929
{
3930
if (_parms == NULL)
3931
return node;
3932
if (!node->getOpCode().isLoadVarOrStore() &&
3933
(node->getOpCodeValue() != TR::loadaddr))
3934
return NULL;
3935
TR::Symbol *sym = node->getSymbol();
3936
if (!sym->isParm())
3937
return NULL;
3938
return _parms->element(sym->getParmSymbol()->getOrdinal());
3939
}
3940
3941
void TR_EscapeAnalysis::checkEscape(TR::TreeTop *firstTree, bool isCold, bool & ignoreRecursion)
3942
{
3943
TR::Node *node;
3944
TR::TreeTop *treeTop;
3945
3946
// Do string copy pattern matching first and fix value numbers accordingly
3947
for (treeTop = firstTree; treeTop && !_candidates.isEmpty(); treeTop = treeTop->getNextTreeTop())
3948
{
3949
node = treeTop->getNode();
3950
if (node->getOpCode().isStoreIndirect() && detectStringCopy(node))
3951
{
3952
TR::Node *baseNode = node->getFirstChild();
3953
int32_t baseNodeVN = _valueNumberInfo->getValueNumber(baseNode);
3954
TR::Node *copyNode = node->getSecondChild()->getFirstChild();
3955
int32_t copyNodeVN = _valueNumberInfo->getValueNumber(copyNode);
3956
Candidate *baseCandidate = findCandidate(baseNodeVN);
3957
Candidate *candidate = NULL;
3958
3959
TR_ASSERT(baseCandidate, "There must be a candidate corresponding to the base node VN");
3960
if (trace())
3961
traceMsg(comp(), "Base candidate: [%p], base node VN: %d, copy node VN: %d\n",
3962
baseCandidate->_node, baseNodeVN, copyNodeVN);
3963
3964
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
3965
{
3966
if (usesValueNumber(candidate, copyNodeVN))
3967
{
3968
for (int32_t i = baseCandidate->_valueNumbers->size()-1; i >= 0; i--)
3969
{
3970
int32_t valueNumber = baseCandidate->_valueNumbers->element(i);
3971
if (!candidate->_valueNumbers->contains(valueNumber))
3972
candidate->_valueNumbers->add(valueNumber);
3973
}
3974
}
3975
}
3976
}
3977
else if (0 && (node->getOpCodeValue() != TR::call) &&
3978
(node->getNumChildren() > 0))
3979
{
3980
node = node->getFirstChild();
3981
if ((node->getOpCodeValue() == TR::call) &&
3982
!node->getSymbolReference()->isUnresolved() &&
3983
!node->getSymbol()->castToMethodSymbol()->isHelper() &&
3984
(node->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod()->getRecognizedMethod() == TR::java_lang_String_init_String) &&
3985
(treeTop->getPrevTreeTop()->getNode()->getNumChildren() > 0) &&
3986
(node->getFirstChild()->getOpCodeValue() == TR::New) &&
3987
(node->getFirstChild() == treeTop->getPrevTreeTop()->getNode()->getFirstChild()))
3988
{
3989
TR::Node *baseNode = node->getFirstChild();
3990
Candidate *candidate, *next;
3991
for (candidate = _candidates.getFirst(); candidate; candidate = next)
3992
{
3993
next = candidate->getNext();
3994
3995
if ((candidate->_stringCopyNode == NULL) ||
3996
(candidate->_stringCopyNode == node->getSecondChild()))
3997
{
3998
if ((baseNode == candidate->_node) &&
3999
(baseNode->getOpCodeValue() == TR::New) &&
4000
(baseNode->getFirstChild()->getSymbolReference()->getSymbol()->getStaticSymbol()->getStaticAddress() == comp()->getStringClassPointer()) &&
4001
(candidate->_treeTop->getNextTreeTop() == treeTop))
4002
{
4003
candidate->_stringCopyCallTree = treeTop;
4004
candidate->_stringCopyNode = node->getSecondChild();
4005
//traceMsg(comp(), "11cand node %p string copy node %p and node %p\n", candidate->_node, candidate->_stringCopyNode, node);
4006
TR::Node *baseNode = node->getFirstChild();
4007
int32_t baseNodeVN = _valueNumberInfo->getValueNumber(baseNode);
4008
TR::Node *copyNode = node->getSecondChild();
4009
int32_t copyNodeVN = _valueNumberInfo->getValueNumber(copyNode);
4010
Candidate *baseCandidate = findCandidate(baseNodeVN);
4011
Candidate *candidate = NULL;
4012
4013
TR_ASSERT(baseCandidate, "There must be a candidate corresponding to the base node VN");
4014
if (trace())
4015
traceMsg(comp(), "Base candidate: [%p], base node VN: %d, copy node VN: %d\n",
4016
baseCandidate->_node, baseNodeVN, copyNodeVN);
4017
4018
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
4019
{
4020
if (usesValueNumber(candidate, copyNodeVN))
4021
{
4022
for (int32_t i = baseCandidate->_valueNumbers->size()-1; i >= 0; i--)
4023
{
4024
int32_t valueNumber = baseCandidate->_valueNumbers->element(i);
4025
if (!candidate->_valueNumbers->contains(valueNumber))
4026
candidate->_valueNumbers->add(valueNumber);
4027
}
4028
}
4029
}
4030
}
4031
else if (candidate->_node == node->getFirstChild())
4032
{
4033
candidate->_stringCopyNode = node->getFirstChild();
4034
//traceMsg(comp(), "22cand node %p string copy node %p and node %p\n", candidate->_node, candidate->_stringCopyNode, node);
4035
}
4036
}
4037
}
4038
}
4039
}
4040
}
4041
4042
// First eliminate all allocations that are not allowed because of nodes
4043
// other than calls, then go through again and eliminate the allocations
4044
// that are not allowed because of calls alone. This reduces the amount of
4045
// sniffing required into called methods.
4046
//
4047
_classObjectLoadForVirtualCall = false;
4048
TR::NodeChecklist vnsNoCall (comp());
4049
4050
for (treeTop = firstTree; treeTop && !_candidates.isEmpty(); treeTop = treeTop->getNextTreeTop())
4051
{
4052
node = treeTop->getNode();
4053
if (!_parms)
4054
{
4055
_curTree = treeTop;
4056
//_curNode = node;
4057
}
4058
4059
if (node->getOpCodeValue() == TR::BBStart)
4060
{
4061
if (!_parms || !_inColdBlock)
4062
{
4063
_inColdBlock = false;
4064
if (!_parms)
4065
_curBlock = node->getBlock();
4066
if (((_curBlock->isCold() ||
4067
_curBlock->isCatchBlock() ||
4068
//(_curBlock->getHotness(comp()->getFlowGraph()) == deadCold)) &&
4069
(_curBlock->getFrequency() == (MAX_COLD_BLOCK_COUNT+1))) &&
4070
!_parms) ||
4071
isCold)
4072
_inColdBlock = true;
4073
}
4074
}
4075
4076
if (!vnsNoCall.contains(node))
4077
checkEscapeViaNonCall(node, vnsNoCall);
4078
}
4079
4080
bool oldIgnoreRecursion = ignoreRecursion;
4081
TR::NodeChecklist vnsCall (comp());
4082
for (treeTop = firstTree; treeTop && !_candidates.isEmpty(); treeTop = treeTop->getNextTreeTop())
4083
{
4084
node = treeTop->getNode();
4085
if (!_parms)
4086
{
4087
_curTree = treeTop;
4088
//_curNode = node;
4089
}
4090
4091
if (node->getOpCodeValue() == TR::BBStart)
4092
{
4093
if (!_parms || !_inColdBlock)
4094
{
4095
_inColdBlock = false;
4096
if (!_parms)
4097
_curBlock = node->getBlock();
4098
if ((_curBlock->isCold() ||
4099
_curBlock->isCatchBlock() ||
4100
//(_curBlock->getHotness(comp()->getFlowGraph()) == deadCold)) &&
4101
(_curBlock->getFrequency() == (MAX_COLD_BLOCK_COUNT+1))) &&
4102
!_parms)
4103
_inColdBlock = true;
4104
}
4105
}
4106
4107
ignoreRecursion = oldIgnoreRecursion;
4108
if (node->getOpCode().isCheck() || node->getOpCodeValue() == TR::treetop)
4109
node = node->getFirstChild();
4110
if (node->getOpCode().isCall() && !vnsCall.contains(node))
4111
{
4112
if (node->getSymbolReference()->getReferenceNumber() != TR_prepareForOSR
4113
|| comp()->getOSRMode() != TR::voluntaryOSR
4114
|| _curBlock->isOSRInduceBlock())
4115
checkEscapeViaCall(node, vnsCall, ignoreRecursion);
4116
}
4117
}
4118
}
4119
4120
static bool isConstantClass(TR::Node *classNode, TR_EscapeAnalysis *ea)
4121
{
4122
bool result = false;
4123
TR::Compilation *comp = ea->comp();
4124
4125
// New logic.
4126
// If classNode represents a class address, return that class.
4127
//
4128
if ( classNode->getOpCodeValue() == TR::loadaddr
4129
&& classNode->getSymbol()->isStatic()
4130
&& !classNode->getSymbolReference()->isUnresolved()
4131
){
4132
result = true;
4133
}
4134
4135
if (ea->trace())
4136
traceMsg(comp, " isConstantClass(%p)=%s (supportsInliningOfIsInstance=%s)\n", classNode, result?"true":"false", comp->cg()->supportsInliningOfIsInstance()?"true":"false");
4137
return result;
4138
}
4139
4140
static bool isFinalizableInlineTest(TR::Compilation *comp, TR::Node *candidate, TR::Node *root, TR::Node *vftLoad)
4141
{
4142
TR_ASSERT(vftLoad->getOpCode().isLoadIndirect() &&
4143
vftLoad->getFirstChild() == candidate &&
4144
vftLoad->getSymbolReference()->getSymbol()->isClassObject() &&
4145
candidate->getOpCode().isRef(),
4146
"Expecting indirect load of class ptr off potential candidate reference");
4147
4148
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp->fe());
4149
4150
bool is64Bit = comp->target().is64Bit();
4151
4152
// root
4153
// r1 - first child of root
4154
// r11 - first child of first child of root
4155
// r12 - second child of first child of root
4156
// r2 - second child of root
4157
TR::Node *r1 = (root->getNumChildren() > 0) ? root->getFirstChild() : NULL;
4158
TR::Node *r2 = (root->getNumChildren() > 1) ? root->getSecondChild() : NULL;
4159
TR::Node *r11 = (r1 && r1->getNumChildren() > 0) ? r1->getFirstChild() : NULL;
4160
TR::Node *r12 = (r1 && r1->getNumChildren() > 1) ? r1->getSecondChild() : NULL;
4161
4162
bool castDownToInt = is64Bit && r11 && (r11->getOpCodeValue() == TR::l2i);
4163
bool usesLongOps = is64Bit && !castDownToInt;
4164
4165
TR::ILOpCodes ifOp = usesLongOps ? TR::iflcmpne : TR::ificmpne;
4166
TR::ILOpCodes andOp = usesLongOps ? TR::land : TR::iand;
4167
TR::ILOpCodes loadOp = is64Bit ? TR::lloadi : TR::iloadi;
4168
TR::ILOpCodes constOp = usesLongOps ? TR::lconst : TR::iconst;
4169
4170
TR::Node *loadNode = castDownToInt ? r11->getFirstChild() : r11;
4171
4172
/*
4173
Looking for a pattern of:
4174
4175
if[i/l]cmpne <root>
4176
[i/l]and <r1>
4177
[i/l]loadi <classAndDepthFlags> <r11/loadNode>
4178
aloadi <vft-symbol> <vftLoad>
4179
... <ref>
4180
[i/l]const <FlagValueForFinalizerCheck> <r12>
4181
[i/l]const 0 <r2>
4182
4183
or
4184
4185
ificmpne <root>
4186
iand <r1>
4187
l2i <r11>
4188
lloadi <classAndDepthFlags> <loadNode>
4189
aloadi <vft-symbol> <vftLoad>
4190
... <ref>
4191
iconst <FlagValueForFinalizerCheck> <r12>
4192
iconst 0 <r2>
4193
*/
4194
4195
return root->getOpCodeValue() == ifOp &&
4196
r1->getOpCodeValue() == andOp &&
4197
r2->getOpCodeValue() == constOp &&
4198
(usesLongOps ? r2->getLongInt() : r2->getInt() ) == 0 &&
4199
loadNode->getOpCodeValue() == loadOp &&
4200
r12->getOpCodeValue() == constOp &&
4201
(usesLongOps ? r12->getLongInt() : r12->getInt())
4202
== fej9->getFlagValueForFinalizerCheck() &&
4203
loadNode->getFirstChild() == vftLoad /*&& (implied by the above assume)
4204
root->getFirstChild()->getFirstChild()->getFirstChild()->getFirstChild() == candidate*/;
4205
}
4206
4207
void TR_EscapeAnalysis::checkEscapeViaNonCall(TR::Node *node, TR::NodeChecklist& visited)
4208
{
4209
visited.add(node);
4210
4211
int32_t i;
4212
int32_t valueNumber;
4213
Candidate *candidate;
4214
bool wasRestricted = false;
4215
TR::Node *child;
4216
4217
// Handle cases that can validly perform an array calculation via TR::aiadd and
4218
// that don't force the base candidate to be contiguous.
4219
// Other uses of TR::aiadd to address fields or access array elements will
4220
// be found during normal processing of checkEscapeViaNonCall and force the
4221
// base candidate to be contiguous.
4222
//
4223
if (node->getOpCode().isLoadVarOrStore() &&
4224
node->getSymbol()->isArrayShadowSymbol() &&
4225
node->getOpCode().isIndirect())
4226
{
4227
child = node->getFirstChild();
4228
if (child->getOpCode().isArrayRef())
4229
{
4230
TR::Node *arrayOffset = child->getSecondChild();
4231
if (arrayOffset->getOpCodeValue() == TR::iconst || arrayOffset->getOpCodeValue() == TR::lconst)
4232
{
4233
valueNumber = _valueNumberInfo->getValueNumber(child->getFirstChild());
4234
if (findCandidate(valueNumber))
4235
visited.add(child);
4236
}
4237
}
4238
}
4239
4240
if (node->getOpCode().isBooleanCompare() && node->getFirstChild()->getType().isAddress())
4241
{
4242
// If child is a candidate, prohibit dememoization
4243
//
4244
if (node->getSecondChild()->isNull())
4245
{
4246
// dememoization doesn't break compares with NULL
4247
}
4248
else
4249
{
4250
for (i = node->getNumChildren() - 1; i >= 0; i--)
4251
{
4252
child = node->getChild(i);
4253
candidate = findCandidate(_valueNumberInfo->getValueNumber(child));
4254
if (candidate && candidate->_dememoizedConstructorCall)
4255
{
4256
if (trace())
4257
traceMsg(comp(), "Rememoize [%p] due to [%p] under address compare [%p]\n", candidate->_node, child, node);
4258
rememoize(candidate);
4259
_candidates.remove(candidate);
4260
}
4261
}
4262
}
4263
}
4264
4265
bool classObjectLoadForVirtualCall = _classObjectLoadForVirtualCall;
4266
for (i = node->getNumChildren() - 1; i >= 0; i--)
4267
{
4268
child = node->getChild(i);
4269
if (!visited.contains(child))
4270
{
4271
if (node->getOpCode().isCallIndirect() &&
4272
(i < node->getFirstArgumentIndex()))
4273
_classObjectLoadForVirtualCall = true;
4274
else
4275
_classObjectLoadForVirtualCall = false;
4276
4277
checkEscapeViaNonCall(child, visited);
4278
4279
_classObjectLoadForVirtualCall = false;
4280
}
4281
}
4282
4283
if (node->getOpCodeValue() == TR::areturn)
4284
{
4285
static const char *noChar = feGetEnv("TR_NoChar");
4286
4287
if (_parms)
4288
{
4289
// In a called method, if we're returning an argument to the caller,
4290
// we can just add the call's value number to the bag of value numbers
4291
// for the candidate corresponding to the argument being returned.
4292
// If there is some reason to worry (eg. an assignment to the parm),
4293
// that will be rejected by other means.
4294
//
4295
// HOWEVER this logic has been disabled because at this stage it is
4296
// too late to add new value numbers to candidates. Much analysis has
4297
// already occurred, and won't be repeated for the newly added VNs.
4298
//
4299
TR::Node *argument = resolveSniffedNode(node->getFirstChild());
4300
TR::Node *callNode = _curTree->getNode()->getFirstChild();
4301
4302
bool doit = true;
4303
if (!_methodSymbol ||
4304
!_inBigDecimalAdd ||
4305
(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_possibleClone))
4306
doit = false;
4307
else
4308
{
4309
if (trace())
4310
traceMsg(comp(), "seen bd possible clone at node %p\n", callNode);
4311
}
4312
4313
if ( argument
4314
&& doit
4315
&& (callNode->getOpCodeValue() == TR::acall || callNode->getOpCodeValue() == TR::acalli)
4316
&& _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.
4317
&& performTransformation(comp(), "%sPeeked method call [%p] returning argument [%p] NOT considered an escape\n", OPT_DETAILS, callNode, argument))
4318
{
4319
// Bingo. Add the call node's value number to the bag for every
4320
// candidate for which argument is already in the bag.
4321
//
4322
if (trace())
4323
traceMsg(comp(), "call node is %p (depth %d) for which return opt was done\n", callNode, _sniffDepth);
4324
#if 0
4325
//
4326
//Note : It's too late anyway for this here...see above comment...so it is disabled
4327
//
4328
int32_t argumentValueNumber = _valueNumberInfo->getValueNumber(argument);
4329
int32_t callValueNumber = _valueNumberInfo->getValueNumber(callNode);
4330
4331
if (trace())
4332
traceMsg(comp(), " Adding call VN %d to all candidates that already have arg VN %d\n", callValueNumber, argumentValueNumber);
4333
4334
for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
4335
{
4336
if (candidate->_valueNumbers->contains(argumentValueNumber))
4337
{
4338
if (trace())
4339
traceMsg(comp(), " %s\n", comp()->getDebug()->getName(candidate->_node));
4340
candidate->_valueNumbers->add(callValueNumber);
4341
}
4342
}
4343
#endif
4344
}
4345
else
4346
{
4347
forceEscape(node->getFirstChild(), node, true);
4348
return;
4349
}
4350
}
4351
4352
// If a return is the only way this object escapes, we cannot make
4353
// it a local allocation but we can desynchronize it.
4354
//
4355
if (!_methodSymbol /* ||
4356
noChar ||
4357
( comp()->getJittedMethodSymbol()->getRecognizedMethod() == TR::java_math_BigDecimal_toString) ||
4358
(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_longString1) */)
4359
restrictCandidates(node->getFirstChild(), node, MakeNonLocal);
4360
return;
4361
}
4362
4363
if (node->getOpCodeValue() == TR::athrow)
4364
{
4365
forceEscape(node->getFirstChild(), node);
4366
return;
4367
}
4368
4369
if (node->getOpCode().hasSymbolReference() &&
4370
(node->getSymbolReference()->getSymbol() == comp()->getSymRefTab()->findGenericIntShadowSymbol() ||
4371
node->getSymbol()->isUnsafeShadowSymbol() ||
4372
node->getDataType().isBCD() ||
4373
node->getSymbolReference()->getSymbol()->getDataType().isBCD()))
4374
{
4375
// PR 80372: Don't take any chances with low-level symbols like GIS and
4376
// Unsafe. Reject the base object as a candidate, and continue processing
4377
// in case node is a store and we need to force the RHS to escape.
4378
//
4379
TR::Node *baseRef = node->getFirstChild();
4380
while (baseRef->getOpCode().isArrayRef())
4381
baseRef = baseRef->getFirstChild();
4382
4383
forceEscape(baseRef, node, true);
4384
}
4385
4386
if (node->getOpCode().isArrayRef())
4387
{
4388
// If the base of the address calculation is a candidate, it must be
4389
// contiguous
4390
//
4391
restrictCandidates(node->getFirstChild(), node, MakeContiguous);
4392
return;
4393
}
4394
4395
// Handle loads and stores
4396
//
4397
if (node->getOpCode().isLoadVarOrStore())
4398
{
4399
if (!_inColdBlock)
4400
markCandidatesUsedInNonColdBlock(node);
4401
4402
if (node->getOpCode().isIndirect())
4403
{
4404
bool seenSelfStore = false;
4405
bool seenStoreToLocalObject = false;
4406
4407
// Handle escapes via indirect store of a candidate
4408
//
4409
if (node->getOpCode().isStore())
4410
{
4411
TR::Node *baseObject = node->getFirstChild();
4412
if (node->getSymbol()->isArrayShadowSymbol() &&
4413
baseObject->getOpCode().isArrayRef())
4414
baseObject = baseObject->getFirstChild();
4415
4416
//detectStringCopy(node);
4417
4418
// TODO : the code related to local object value numbers
4419
// can be turned back on if value numbering gives same value numbers
4420
// to 2 loads of fields of local objects. This is currently not done
4421
// in value numbering. As a result,
4422
// <local_object>.f = <new_that_may_be_stack_allocated>
4423
// <static> = <local_object>.f
4424
// is a problematic case. We won't track the above escape point and
4425
// wrongly stack allocate the new. If we are able to track a local
4426
// object field's value numbers we can hope to see if it 'really' escapes
4427
// or not.
4428
//
4429
//if (!baseObject->getOpCode().hasSymbolReference() ||
4430
// (!(_nonColdlocalObjectsValueNumbers &&
4431
// _nonColdlocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(baseObject)))))
4432
4433
// java/lang/Throwable.cause addition in SC1411, which disables fillInStackTrace opt in javac
4434
if ((node->getSecondChild() != baseObject) &&
4435
(!baseObject->getOpCode().hasSymbolReference() ||
4436
!node->getSecondChild()->getOpCode().hasSymbolReference() ||
4437
((baseObject->getReferenceCount() != 1) &&
4438
(!((baseObject->getReferenceCount() == 2) && (node->getOpCodeValue() == TR::awrtbari) && (node->getChild(2) == baseObject)))) ||
4439
(node->getSecondChild()->getReferenceCount() != 1) ||
4440
(baseObject->getSymbolReference() != node->getSecondChild()->getSymbolReference())))
4441
{
4442
TR::Node *resolvedBaseObject = resolveSniffedNode(baseObject);
4443
bool stringCopyOwningMethod = false;
4444
TR::ResolvedMethodSymbol *owningMeth = node->getSymbolReference()->getOwningMethodSymbol(comp());
4445
TR::RecognizedMethod methodId = owningMeth->getRecognizedMethod();
4446
if (methodId == TR::java_lang_String_init_String)
4447
{
4448
char *sig = owningMeth->getResolvedMethod()->signatureChars();
4449
if (!strncmp(sig, "(Ljava/lang/String;)", 20))
4450
{
4451
stringCopyOwningMethod = true;
4452
}
4453
}
4454
4455
if ((!_nonColdLocalObjectsValueNumbers ||
4456
!_notOptimizableLocalObjectsValueNumbers ||
4457
!resolvedBaseObject ||
4458
(comp()->useCompressedPointers() && (TR::Compiler->om.compressedReferenceShift() > 3) && !cg()->supportsStackAllocations()) ||
4459
!resolvedBaseObject->getOpCode().hasSymbolReference() ||
4460
!_nonColdLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(resolvedBaseObject)) ||
4461
(((node->getSymbolReference()->getSymbol()->getRecognizedField() != TR::Symbol::Java_lang_String_value) ||
4462
stringCopyOwningMethod ||
4463
_notOptimizableLocalStringObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(resolvedBaseObject))) &&
4464
_notOptimizableLocalObjectsValueNumbers->get(_valueNumberInfo->getValueNumber(resolvedBaseObject)))))
4465
{
4466
forceEscape(node->getSecondChild(), node);
4467
}
4468
else
4469
{
4470
seenStoreToLocalObject = true;
4471
restrictCandidates(node->getSecondChild(), node, MakeContiguous);
4472
}
4473
}
4474
else
4475
{
4476
static char *allowSelfStoresToLocalObjects = feGetEnv("TR_allowSelfStoresToLocalObjects");
4477
if (allowSelfStoresToLocalObjects)
4478
{
4479
seenSelfStore = true;
4480
if (baseObject->getOpCode().hasSymbolReference())
4481
restrictCandidates(node->getSecondChild(), node, MakeContiguous);
4482
}
4483
else
4484
{
4485
forceEscape(node->getSecondChild(), node);
4486
}
4487
}
4488
}
4489
4490
child = node->getFirstChild();
4491
if (node->getSymbol()->isArrayShadowSymbol() &&
4492
child->getOpCode().isArrayRef())
4493
child = child->getFirstChild();
4494
4495
// Remember indirect loads or stores for fields of local allocations.
4496
//
4497
if (node->getOpCode().isStore())
4498
{
4499
//if (seenSelfStore)
4500
referencedField(child, node, true, seenSelfStore, seenStoreToLocalObject);
4501
//else
4502
// referencedField(child, node, true);
4503
}
4504
else
4505
referencedField(child, node, false);
4506
4507
// If the field is unresolved it must be left as a field reference, so
4508
// force the allocation to be contiguous.
4509
//
4510
if (node->getSymbolReference()->isUnresolved())
4511
restrictCandidates(child, node, MakeContiguous);
4512
// Similarly if the field is not a regular field make the allocation
4513
// contiguous (unless it's a class load for a vcall or inline finalizable test)
4514
// (If it's an inline finalizable test we have to clean the test up since the object will no longer exist)
4515
//
4516
else if (node->getSymbolReference()->getOffset() < (int32_t)comp()->fej9()->getObjectHeaderSizeInBytes() && !node->getSymbol()->isArrayShadowSymbol())
4517
{
4518
if (!node->getSymbolReference()->getSymbol()->isClassObject() || node->getOpCode().isStore() ||
4519
(!classObjectLoadForVirtualCall && !isFinalizableInlineTest(comp(), child, _curTree->getNode(), node)))
4520
{
4521
restrictCandidates(child, node, MakeContiguous);
4522
}
4523
}
4524
}
4525
4526
else // Direct load or store
4527
{
4528
if (node->getOpCode().isStore() &&
4529
(comp()->getSymRefTab()->findThisRangeExtensionSymRef() != node->getSymbolReference()))
4530
{
4531
// Handle escapes via direct store of a candidate.
4532
// In a sniffed method even a store into a local may escape since
4533
// we can't keep track of the local stored into (we have no value
4534
// number information for it).
4535
//
4536
if ((_parms || !node->getSymbol()->isAutoOrParm()) &&
4537
(!_methodSymbol ||
4538
(_parms && node->getSymbol()->isAutoOrParm() && !node->getFirstChild()->isThisPointer()) ||
4539
((_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_add) &&
4540
(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_longAdd) &&
4541
(_methodSymbol->getRecognizedMethod() != TR::java_math_BigDecimal_slAdd))))
4542
forceEscape(node->getFirstChild(), node);
4543
4544
// PR 93460
4545
if (node->getSymbolReference()->getSymbol()->isAuto() &&
4546
node->getSymbol()->castToAutoSymbol()->isPinningArrayPointer())
4547
restrictCandidates(node->getFirstChild(), node, MakeContiguous);
4548
4549
// Handle escapes via store into a parameter for a called method
4550
// (this is conservative, but hopefully it doesn't happen too often)
4551
//
4552
if (_parms)
4553
forceEscape(node, node);
4554
}
4555
}
4556
return;
4557
}
4558
4559
// Handle arraycopy nodes.
4560
// Any candidates being used for arraycopy must be allocated contiguously.
4561
//
4562
if (node->getOpCodeValue() == TR::arraycopy)
4563
{
4564
if (node->getNumChildren() == 5)
4565
{
4566
restrictCandidates(node->getFirstChild(), node, MakeContiguous);
4567
restrictCandidates(node->getSecondChild(), node, MakeContiguous);
4568
}
4569
4570
if (node->getNumChildren() == 3)
4571
{
4572
if (node->getFirstChild()->getOpCode().isArrayRef())
4573
restrictCandidates(node->getFirstChild()->getFirstChild(), node, MakeContiguous);
4574
if (node->getSecondChild()->getOpCode().isArrayRef())
4575
restrictCandidates(node->getSecondChild()->getFirstChild(), node, MakeContiguous);
4576
}
4577
4578
return;
4579
}
4580
4581
if (_sniffDepth > 0)
4582
return;
4583
4584
// Look for some direct references to candidates, and decide if a separate
4585
// object must be created for them to handle the references.
4586
//
4587
if (node->getOpCode().isCheckCast() ||
4588
node->getOpCodeValue() == TR::instanceof)
4589
{
4590
valueNumber = _valueNumberInfo->getValueNumber(node->getFirstChild());
4591
candidate = findCandidate(valueNumber);
4592
if (candidate)
4593
{
4594
TR::Node *classNode = node->getSecondChild();
4595
if (!isConstantClass(classNode, this))
4596
{
4597
// We don't know the class statically. The object must stay contiguous.
4598
//
4599
wasRestricted |= restrictCandidates(node->getFirstChild(), node, MakeContiguous);
4600
}
4601
else if (node->getOpCode().isCheckCast() &&
4602
comp()->fej9()->isInstanceOf((TR_OpaqueClassBlock *) candidate->_class, (TR_OpaqueClassBlock*)classNode->getSymbol()->castToStaticSymbol()->getStaticAddress(), true) != TR_yes)
4603
{
4604
// We will be able to predict the result of the cast. For instanceof and
4605
// for a succeeding checkcast we will remove this candidate reference.
4606
// For a failing checkcast the candidate reference will remain, but can
4607
// become a separate "java/lang/Object" object.
4608
//
4609
wasRestricted |= restrictCandidates(node->getFirstChild(), node, MakeObjectReferenced);
4610
}
4611
}
4612
}
4613
4614
else if (node->getOpCodeValue() == TR::ifacmpeq ||
4615
node->getOpCodeValue() == TR::ifacmpne)
4616
{
4617
// If one of the children is a candidate we may be able to determine if
4618
// the comparison will succeed or fail
4619
//
4620
int32_t firstValue = _valueNumberInfo->getValueNumber(node->getFirstChild());
4621
int32_t secondValue = _valueNumberInfo->getValueNumber(node->getSecondChild());
4622
bool predictResult = false;
4623
if (firstValue == secondValue)
4624
predictResult = true;
4625
else
4626
{
4627
candidate = findCandidate(firstValue);
4628
if (candidate && !usesValueNumber(candidate, secondValue))
4629
predictResult = true;
4630
else
4631
{
4632
candidate = findCandidate(secondValue);
4633
if (candidate && !usesValueNumber(candidate, firstValue))
4634
predictResult = true;
4635
}
4636
}
4637
4638
if (!predictResult)
4639
{
4640
wasRestricted = restrictCandidates(node->getFirstChild(), node, MakeObjectReferenced);
4641
wasRestricted |= restrictCandidates(node->getSecondChild(), node, MakeObjectReferenced);
4642
}
4643
}
4644
4645
else if (node->getOpCodeValue() != TR::treetop &&
4646
!node->getOpCode().isArrayRef() &&
4647
node->getOpCodeValue() != TR::PassThrough &&
4648
!node->getOpCode().isArrayLength() &&
4649
node->getOpCodeValue() != TR::NULLCHK &&
4650
node->getOpCodeValue() != TR::ResolveCHK &&
4651
node->getOpCodeValue() != TR::ResolveAndNULLCHK &&
4652
node->getOpCodeValue() != TR::instanceof &&
4653
#if CHECK_MONITORS
4654
((node->getOpCodeValue() != TR::monent && node->getOpCodeValue() != TR::monexit) || !_removeMonitors) &&
4655
#endif
4656
!node->getOpCode().isCall())
4657
{
4658
// Any other direct reference to a candidate means that there must be a
4659
// local object even if the fields are allocated non-contiguously
4660
//
4661
for (i = node->getNumChildren()-1; i >= 0; i--)
4662
{
4663
child = node->getChild(i);
4664
wasRestricted |= restrictCandidates(child, node, MakeObjectReferenced);
4665
}
4666
}
4667
if (wasRestricted)
4668
{
4669
if (trace())
4670
{
4671
/////printf("secs Object referenced via %s in %s\n", node->getOpCode().getName(), comp()->signature());
4672
traceMsg(comp(), "Object referenced via %s\n", node->getOpCode().getName());
4673
}
4674
}
4675
}
4676
4677
4678
bool
4679
SniffCallCache::isInCache(TR_LinkHead<SniffCallCache> *sniffCacheList, TR_ResolvedMethod *vmMethod, bool isCold, int32_t &bytecodeSize)
4680
{
4681
SniffCallCache *sniffCallCache;
4682
for (sniffCallCache = sniffCacheList->getFirst(); sniffCallCache; sniffCallCache = sniffCallCache->getNext())
4683
{
4684
if (vmMethod->isSameMethod(sniffCallCache->_vmMethod) &&
4685
isCold == sniffCallCache->_isCold)
4686
{
4687
bytecodeSize = sniffCallCache->_bytecodeSize;
4688
return true;
4689
}
4690
}
4691
return false;
4692
}
4693
4694
TR::SymbolReference*
4695
SymRefCache::findSymRef(TR_LinkHead<SymRefCache> *symRefList, TR_ResolvedMethod *resolvedMethod)
4696
{
4697
SymRefCache *symRefCache;
4698
for (symRefCache = symRefList->getFirst(); symRefCache; symRefCache = symRefCache->getNext())
4699
{
4700
if (resolvedMethod->isSameMethod(symRefCache->getMethod()))
4701
{
4702
return symRefCache->getSymRef();
4703
}
4704
}
4705
return NULL;
4706
}
4707
4708
void TR_EscapeAnalysis::checkEscapeViaCall(TR::Node *node, TR::NodeChecklist& visited, bool & ignoreRecursion)
4709
{
4710
int32_t nodeVN;
4711
TR::Node *value;
4712
4713
visited.add(node);
4714
4715
TR::ResolvedMethodSymbol *methodSymbol = node->getSymbol()->getResolvedMethodSymbol();
4716
Candidate *candidate, *next;
4717
bool needToSniff = false;
4718
4719
// In Java9 sun_misc_Unsafe_putInt might be the wrapper which could potentially be redefined,
4720
// so add a check for isNative to be conservative.
4721
if (methodSymbol && _methodSymbol &&
4722
(_methodSymbol->getRecognizedMethod() == TR::java_math_BigDecimal_longString1C) &&
4723
(methodSymbol->getRecognizedMethod() == TR::sun_misc_Unsafe_putInt_jlObjectII_V) &&
4724
(methodSymbol->isNative()))
4725
{
4726
if (trace())
4727
traceMsg(comp(), "Ignoring escapes via call [%p] \n", node);
4728
return;
4729
}
4730
4731
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
4732
{
4733
if ( methodSymbol
4734
&& methodSymbol->getRecognizedMethod() == TR::java_lang_Integer_init
4735
&& candidate->_dememoizedConstructorCall
4736
&& candidate->_dememoizedConstructorCall->getNode()->getFirstChild() == node)
4737
{
4738
if (trace())
4739
traceMsg(comp(), "Ignoring escapes via call [%p] that will either be inlined or rememoized\n", node);
4740
return;
4741
}
4742
}
4743
4744
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
4745
{
4746
candidate->setArgToCall(_sniffDepth, false);
4747
candidate->setNonThisArgToCall(_sniffDepth, false);
4748
}
4749
4750
int32_t thisVN = -1;
4751
int32_t firstArgIndex = node->getFirstArgumentIndex();
4752
for (int32_t arg = firstArgIndex; arg < node->getNumChildren() && !_candidates.isEmpty(); arg++)
4753
{
4754
checkEscapeViaNonCall(node->getChild(arg), visited);
4755
value = resolveSniffedNode(node->getChild(arg));
4756
if (!value)
4757
continue;
4758
4759
// Method arguments are always escapes when method enter/exit hooks are enabled
4760
// because the agent can ask for method receivers and return values, and inspect them.
4761
// be conservative in checking for method exit hook: if an argument is returned by the callee exit hook would make it escape
4762
//
4763
if (TR::Compiler->vm.canMethodEnterEventBeHooked(comp()) || TR::Compiler->vm.canMethodExitEventBeHooked(comp()))
4764
{
4765
forceEscape(node->getChild(arg), node, true);
4766
continue;
4767
}
4768
4769
nodeVN = _valueNumberInfo->getValueNumber(value);
4770
if (arg == firstArgIndex)
4771
thisVN = nodeVN;
4772
4773
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
4774
{
4775
if (usesValueNumber(candidate, nodeVN))
4776
{
4777
// Remember calls to fillInStackTrace and printStackTrace. These
4778
// are methods of Throwable. The call to fillInStackTrace is very
4779
// expensive, and if it can be proved that the stack trace is not
4780
// used (via a call to printStackTrace) then the calls to
4781
// fillInStackTrace can be removed.
4782
//
4783
if (arg == firstArgIndex && methodSymbol && (!node->getOpCode().isIndirect() || !methodSymbol->getResolvedMethod()->virtualMethodIsOverridden()))
4784
{
4785
TR::RecognizedMethod methodId = methodSymbol->getRecognizedMethod();
4786
if (methodId == TR::java_lang_Throwable_fillInStackTrace)
4787
{
4788
// No escape via this method, and don't make this call the
4789
// reason for making the object contiguous.
4790
//
4791
if (candidate->_valueNumbers->element(0) == nodeVN)
4792
candidate->setFillsInStackTrace();
4793
continue;
4794
}
4795
4796
if (methodId == TR::java_lang_Throwable_printStackTrace)
4797
{
4798
// Uses stack trace, so fillInStackTrace can't be avoided.
4799
// Force the object to be contiguous and sniff this method to
4800
// check for escape.
4801
//
4802
candidate->setUsesStackTrace();
4803
candidate->setMustBeContiguousAllocation();
4804
if (trace())
4805
traceMsg(comp(), " Make [%p] contiguous because of setUsesStackTrace\n", candidate->_node);
4806
}
4807
}
4808
4809
// Ignore calls to jitCheckIfFinalizeObject, the argument cannot escape via such calls
4810
//
4811
if (1)
4812
{
4813
TR::SymbolReference *finalizeSymRef = comp()->getSymRefTab()->findOrCreateRuntimeHelper(TR_jitCheckIfFinalizeObject, true, true, true);
4814
if (node->getSymbolReference() == finalizeSymRef)
4815
{
4816
if (trace())
4817
traceMsg(comp(), "Candidate [%p] cannot escape because of node [%p]\n", candidate->_node, node);
4818
continue;
4819
}
4820
}
4821
4822
4823
// We can't sniff JNI methods. Check if this is a JNI call, in which
4824
// case use the table of trusted methods to see if the argument can escape from
4825
// this call
4826
//
4827
if (!node->getOpCode().isIndirect() && methodSymbol && methodSymbol->getResolvedMethod()->isJNINative())
4828
{
4829
if (methodSymbol && !comp()->fej9()->argumentCanEscapeMethodCall(methodSymbol, arg-firstArgIndex))
4830
{
4831
// The candidate will have to be kept as a contiguous
4832
// allocation, since it is passed to another method.
4833
//
4834
candidate->setMustBeContiguousAllocation();
4835
if (trace())
4836
traceMsg(comp(), " Make [%p] contiguous because of node [%p]\n", candidate->_node, node);
4837
continue;
4838
}
4839
}
4840
4841
// Otherwise we need to sniff the method. If we can't sniff it for
4842
// some reason then assume that this candidate can escape.
4843
//
4844
needToSniff = true;
4845
4846
// Remember that this child is an affected candidate
4847
//
4848
candidate->setArgToCall(_sniffDepth);
4849
if (node->getOpCode().isIndirect())
4850
{
4851
if (arg != firstArgIndex)
4852
candidate->setNonThisArgToCall(_sniffDepth);
4853
}
4854
4855
if (arg == (firstArgIndex+1) && methodSymbol && !node->getOpCode().isIndirect())
4856
{
4857
TR::RecognizedMethod methodId = methodSymbol->getRecognizedMethod();
4858
if (methodId == TR::java_lang_String_init_String)
4859
{
4860
char *sig = methodSymbol->getResolvedMethod()->signatureChars();
4861
if (!strncmp(sig, "(Ljava/lang/String;)", 20))
4862
{
4863
candidate->setCallsStringCopyConstructor();
4864
}
4865
}
4866
}
4867
}
4868
}
4869
}
4870
4871
if (needToSniff)
4872
{
4873
if (methodSymbol)
4874
dumpOptDetails(comp(), "Sniff call %p called %s\n", node, methodSymbol->getMethod()->signature(trMemory()));
4875
TR_LinkHead<SniffCallCache> sniffCacheList;
4876
sniffCacheList.setFirst(NULL);
4877
bool sniffCallInCache;
4878
4879
bool oldIgnoreRecursion = ignoreRecursion;
4880
int32_t bytecodeSize = sniffCall(node, methodSymbol, false, _inColdBlock, ignoreRecursion);
4881
int32_t originalBytecodeSize = bytecodeSize;
4882
for (candidate = _candidates.getFirst(); candidate; candidate = next)
4883
{
4884
bool refinedSniff = false;
4885
next = candidate->getNext();
4886
bytecodeSize = originalBytecodeSize;
4887
TR::SymbolReference *symRef = node->getSymbolReference();
4888
if (candidate->isArgToCall(_sniffDepth))
4889
{
4890
if (!candidate->isNonThisArgToCall(_sniffDepth) &&
4891
node->getOpCode().isIndirect() &&
4892
((candidate->_node->getOpCodeValue() == TR::New)) &&
4893
(thisVN > -1) &&
4894
usesValueNumber(candidate, thisVN))
4895
{
4896
TR_ResolvedMethod *owningMethod = symRef->getOwningMethod(comp());
4897
TR_ResolvedMethod *resolvedMethod = NULL;
4898
TR::MethodSymbol *sym = symRef->getSymbol()->castToMethodSymbol();
4899
TR::Method * originalMethod = sym->getMethod();
4900
int32_t len = originalMethod->classNameLength();
4901
char *s = TR::Compiler->cls.classNameToSignature(originalMethod->classNameChars(), len, comp());
4902
TR_OpaqueClassBlock *originalMethodClass = comp()->fej9()->getClassFromSignature(s, len, owningMethod);
4903
TR_OpaqueClassBlock *thisType = (TR_OpaqueClassBlock *) candidate->_node->getFirstChild()->getSymbol()->castToStaticSymbol()->getStaticAddress();
4904
int32_t offset = -1;
4905
4906
bool resolvedMethodMustExist = false;
4907
if (originalMethodClass &&
4908
thisType)
4909
{
4910
if (comp()->fej9()->isInstanceOf(thisType, originalMethodClass, true) == TR_yes)
4911
resolvedMethodMustExist = true;
4912
}
4913
4914
// The 2nd check below is to account for the rare case when we can
4915
// have a virtual (non interface) call that has an interface method
4916
// as the callee in the IL. This can happen in cases when an abstract class
4917
// implements an interface but doesn't even declare one of the methods in the
4918
// interface. In this case, the vft slot for the abstract class actually
4919
// has the interface method and this can lead to strange behaviour when we look
4920
// up the method (code guarded by below if). The strange case is if
4921
// there is some other class implementing the interface unrelated to the abstract class
4922
// and we try and look up the method in that class (because its an instance of
4923
// the interface) and get a completely unrelated method.
4924
//
4925
if (resolvedMethodMustExist &&
4926
(sym->isInterface() || !TR::Compiler->cls.isInterfaceClass(comp(), originalMethodClass)))
4927
{
4928
if (sym->isInterface() &&
4929
originalMethodClass)
4930
{
4931
int32_t cpIndex = symRef->getCPIndex();
4932
resolvedMethod = owningMethod->getResolvedInterfaceMethod(comp(), thisType, cpIndex);
4933
if (resolvedMethod)
4934
offset = owningMethod->getResolvedInterfaceMethodOffset(thisType, cpIndex);
4935
}
4936
else if (sym->isVirtual()
4937
&& !symRef->isUnresolved()
4938
&& sym->getRecognizedMethod() != TR::java_lang_Object_newInstancePrototype) // 166813: Temporary fix
4939
{
4940
offset = symRef->getOffset();
4941
resolvedMethod = owningMethod->getResolvedVirtualMethod(comp(), thisType, offset);
4942
}
4943
}
4944
4945
if (resolvedMethod)
4946
{
4947
// try to use cached result (_curTree, bytecodeSize) before sniffing into the call
4948
sniffCallInCache = SniffCallCache::isInCache(&sniffCacheList, resolvedMethod, _inColdBlock, bytecodeSize);
4949
dumpOptDetails(comp(), "Refined sniff call %p called %s, cached=%s\n",
4950
node, resolvedMethod->signature(trMemory()), sniffCallInCache ? "true" : "false");
4951
if (!sniffCallInCache)
4952
{
4953
TR::SymbolReference * newSymRef;
4954
// we want to reuse the IL if we're sniffing the same method
4955
newSymRef = SymRefCache::findSymRef(&(getOptData()->_symRefList), resolvedMethod);
4956
if (!newSymRef)
4957
{
4958
newSymRef = getSymRefTab()->findOrCreateMethodSymbol(symRef->getOwningMethodIndex(), -1, resolvedMethod, TR::MethodSymbol::Virtual);
4959
SymRefCache *symRefCache = new (trHeapMemory()) SymRefCache(newSymRef, resolvedMethod);
4960
getOptData()->_symRefList.add(symRefCache);
4961
newSymRef->copyAliasSets(symRef, getSymRefTab());
4962
newSymRef->setOffset(offset);
4963
}
4964
TR::MethodSymbol *newMethodSymbol = newSymRef->getSymbol()->castToMethodSymbol();
4965
4966
ignoreRecursion = oldIgnoreRecursion;
4967
bytecodeSize = sniffCall(node, newMethodSymbol->getResolvedMethodSymbol(), true, _inColdBlock, ignoreRecursion);
4968
SniffCallCache *sniffCallCache = new (trStackMemory()) SniffCallCache(newMethodSymbol->getResolvedMethodSymbol()->getResolvedMethod(), _inColdBlock, bytecodeSize);
4969
sniffCacheList.add(sniffCallCache);
4970
}
4971
refinedSniff = true;
4972
//printf("bytecodeSize = %d original bytecodeSize = %d method %s\n", bytecodeSize, originalBytecodeSize, resolvedMethod->signature());
4973
}
4974
}
4975
4976
if ((bytecodeSize > 0) && (!node->getOpCode().isIndirect() || !node->isTheVirtualCallNodeForAGuardedInlinedCall()) &&
4977
(!symRef->isUnresolved() ||
4978
!refinedSniff) )
4979
{
4980
// The sniff was successful.
4981
// If this is the top-level call site, remember that it
4982
// references the candidate. If we cannot inline the call site
4983
// then the candidate will have to be a contiguous allocation
4984
// in order for it to be passed to the callee.
4985
//
4986
candidate->setArgToCall(_sniffDepth, false);
4987
candidate->setNonThisArgToCall(_sniffDepth, false);
4988
4989
if (!symRef->isUnresolved() ||
4990
!refinedSniff)
4991
{
4992
// The sniff was successful.
4993
// If this is the top-level call site, remember that it
4994
// references the candidate. If we cannot inline the call site
4995
// then the candidate will have to be a contiguous allocation
4996
// in order for it to be passed to the callee.
4997
//
4998
4999
if (_sniffDepth == 0)
5000
{
5001
candidate->addCallSite(_curTree);
5002
if (!refinedSniff && node->getOpCode().isIndirect() && (methodSymbol && !methodSymbol->getResolvedMethod()->virtualMethodIsOverridden()))
5003
candidate->addVirtualCallSiteToBeFixed(_curTree);
5004
}
5005
5006
if (_sniffDepth > candidate->_maxInlineDepth)
5007
candidate->_maxInlineDepth = _sniffDepth;
5008
candidate->_inlineBytecodeSize += bytecodeSize;
5009
5010
}
5011
else
5012
candidate->setMustBeContiguousAllocation();
5013
5014
if (trace())
5015
traceMsg(comp(), " Make [%p] contiguous because of call node [%p]\n", candidate->_node, node);
5016
}
5017
else
5018
{
5019
// If the escape point is cold, this will not
5020
// prevent us from stack allocating it. We will compensate
5021
// for this later
5022
//
5023
if (checkIfEscapePointIsCold(candidate, node))
5024
continue;
5025
5026
// Force
5027
if(candidate->forceLocalAllocation())
5028
{
5029
if (trace())
5030
traceMsg(comp(), " Normally [%p] would fail because child of call [%p] to %s, but user wants it locally allocated\n",
5031
candidate->_node, node,
5032
node->getSymbol()->getMethodSymbol()->getMethod()
5033
? node->getSymbol()->getMethodSymbol()->getMethod()->signature(trMemory())
5034
: "[Unknown method]");
5035
continue;
5036
}
5037
// The sniff could not be done. Remove this candidate.
5038
//
5039
5040
if (trace())
5041
traceMsg(comp(), " Fail [%p] because child of call [%p]\n",
5042
candidate->_node, node);
5043
5044
rememoize(candidate);
5045
_candidates.remove(candidate);
5046
}
5047
}
5048
//else
5049
// traceMsg(comp(), "NOT is arg to call at node %p\n", node);
5050
}
5051
}
5052
}
5053
5054
int32_t TR_EscapeAnalysis::sniffCall(TR::Node *callNode, TR::ResolvedMethodSymbol *methodSymbol, bool ignoreOpCode, bool isCold, bool & ignoreRecursion)
5055
{
5056
if (_sniffDepth >= _maxSniffDepth)
5057
return 0;
5058
if (!methodSymbol)
5059
return 0;
5060
if (!ignoreOpCode &&
5061
(callNode->getOpCode().isIndirect() &&
5062
(methodSymbol->getResolvedMethod()->virtualMethodIsOverridden() || isCold || (_sniffDepth !=0) || (manager()->numPassesCompleted() == _maxPassNumber))))
5063
return 0;
5064
5065
// Avoid attempting to devirtualize a computed call
5066
if (methodSymbol->isComputed())
5067
return 0;
5068
5069
TR_ResolvedMethod *method = methodSymbol->getResolvedMethod();
5070
if (!method)
5071
return 0;
5072
5073
if (!method->isCompilable(trMemory()) || method->isJNINative())
5074
return 0;
5075
5076
uint32_t bytecodeSize = method->maxBytecodeIndex();
5077
if (bytecodeSize > MAX_SNIFF_BYTECODE_SIZE)
5078
return 0;
5079
5080
getOptData()->_totalPeekedBytecodeSize += bytecodeSize;
5081
if (getOptData()->_totalPeekedBytecodeSize > _maxPeekedBytecodeSize)
5082
return 0;
5083
5084
TR::ResolvedMethodSymbol *owningMethodSymbol = callNode->getSymbolReference()->getOwningMethodSymbol(comp());
5085
TR_ResolvedMethod* owningMethod = owningMethodSymbol->getResolvedMethod();
5086
TR_ResolvedMethod* calleeMethod = methodSymbol->getResolvedMethod();
5087
5088
if (owningMethod->isSameMethod(calleeMethod) &&
5089
(comp()->getJittedMethodSymbol() != owningMethodSymbol))
5090
{
5091
if (ignoreRecursion)
5092
return bytecodeSize;
5093
else
5094
ignoreRecursion = true;
5095
}
5096
5097
if (trace())
5098
traceMsg(comp(), "\nDepth %d sniffing into call at [%p] to %s\n", _sniffDepth, callNode, method->signature(trMemory()));
5099
5100
vcount_t visitCount = comp()->getVisitCount();
5101
if (!methodSymbol->getFirstTreeTop())
5102
{
5103
//comp()->setVisitCount(1);
5104
5105
dumpOptDetails(comp(), "O^O ESCAPE ANALYSIS: Peeking into the IL to check for escaping objects \n");
5106
5107
bool ilgenFailed = false;
5108
bool isPeekableCall = ((PersistentData *)manager()->getOptData())->_peekableCalls->get(callNode->getGlobalIndex());
5109
if (isPeekableCall)
5110
ilgenFailed = (NULL == methodSymbol->getResolvedMethod()->genMethodILForPeekingEvenUnderMethodRedefinition(methodSymbol, comp()));
5111
else
5112
ilgenFailed = (NULL == methodSymbol->getResolvedMethod()->genMethodILForPeeking(methodSymbol, comp()));
5113
//comp()->setVisitCount(visitCount);
5114
5115
/*
5116
* Under HCR we cannot generally peek methods because the method could be
5117
* redefined and any assumptions we made about the contents of the method
5118
* would no longer hold. Peeking is only safe when we add a compensation
5119
* path that would handle potential escape of candidates if a method were
5120
* redefined.
5121
*
5122
* Under OSR we know the live locals from the OSR book keeping information
5123
* so can construct a helper call which appears to make those calls escape.
5124
* Such a call will force heapification of any candidates ahead of the
5125
* helper call.
5126
*
5127
* We, therefore, queue this call node to be protected if we are in a mode
5128
* where protection is possible (voluntary OSR, HCR on). The actual code
5129
* transformation is delayed to the end of EA since it will disrupt value
5130
* numbering. The transform will insert an HCR guard with an escape helper
5131
* call as follows:
5132
*
5133
* | ... | | ... |
5134
* | call m | => | hcr guard (m) |
5135
* | ... | +---------------+
5136
* | \
5137
* | +-(cold)-------------------+
5138
* | | call eaEscapeHelper |
5139
* | | <loads of live locals> |
5140
* | +--------------------------+
5141
* V /
5142
* +---------------+
5143
* | call m |
5144
* | ... |
5145
*
5146
* Once EA finishes the postEscapeAnalysis pass will clean-up all
5147
* eaEscapeHelper calls. Code will only remain in the taken side of the
5148
* guard if candidtes were stack allocated and required heapficiation.
5149
*
5150
* This code transformation is protected with a perform transformation at
5151
* the site of tree manipulation at the end of this pass of EA.
5152
* Protecting any call is considered a reason to enable another pass of
5153
* EA if we have not yet reached the enable limit.
5154
*
5155
* Note that the result of the call can continue to participate in
5156
* commoning with the above design. If we duplicated the call on both
5157
* sides of the guard the result could not participate in commoning.
5158
*
5159
*/
5160
if (ilgenFailed)
5161
{
5162
if (trace())
5163
traceMsg(comp(), " (IL generation failed)\n");
5164
static char *disableHCRCallPeeking = feGetEnv("TR_disableEAHCRCallPeeking");
5165
if (!isPeekableCall
5166
&& disableHCRCallPeeking == NULL
5167
&& comp()->getOSRMode() == TR::voluntaryOSR
5168
&& comp()->getHCRMode() == TR::osr
5169
&& !_candidates.isEmpty()
5170
&& !((TR_EscapeAnalysis::PersistentData*)manager()->getOptData())->_processedCalls->get(callNode->getGlobalIndex()))
5171
{
5172
dumpOptDetails(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());
5173
TR_BitVector *candidateNodes = new (comp()->trStackMemory()) TR_BitVector(0, trMemory(), stackAlloc);
5174
NodeDeque *loads = new (comp()->trMemory()->currentStackRegion()) NodeDeque(NodeDequeAllocator(comp()->trMemory()->currentStackRegion()));
5175
for (int32_t arg = callNode->getFirstArgumentIndex(); arg < callNode->getNumChildren(); ++arg)
5176
{
5177
TR::Node *child = callNode->getChild(arg);
5178
int32_t valueNumber = _valueNumberInfo->getValueNumber(child);
5179
for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
5180
{
5181
if (usesValueNumber(candidate, valueNumber))
5182
{
5183
candidateNodes->set(candidate->_node->getGlobalIndex());
5184
ListIterator<TR::SymbolReference> itr(candidate->getSymRefs());
5185
for (TR::SymbolReference *symRef = itr.getFirst(); symRef; symRef = itr.getNext())
5186
loads->push_back(TR::Node::createWithSymRef(TR::aload, 0, symRef));
5187
}
5188
}
5189
}
5190
(*_callsToProtect)[callNode] = std::make_pair(candidateNodes, loads);
5191
}
5192
return 0;
5193
}
5194
5195
if (trace())
5196
{
5197
//comp()->setVisitCount(1);
5198
for (TR::TreeTop *tt = methodSymbol->getFirstTreeTop(); tt; tt = tt->getNextTreeTop())
5199
getDebug()->print(comp()->getOutFile(), tt);
5200
//comp()->setVisitCount(visitCount);
5201
}
5202
}
5203
else
5204
{
5205
if (trace())
5206
traceMsg(comp(), " (trees already dumped)\n");
5207
}
5208
5209
int32_t firstArgIndex = callNode->getFirstArgumentIndex();
5210
TR_Array<TR::Node*> *newParms = new (trStackMemory()) TR_Array<TR::Node*>(trMemory(), callNode->getNumChildren() - firstArgIndex, false, stackAlloc);
5211
for (int32_t i = firstArgIndex; i < callNode->getNumChildren(); ++i)
5212
{
5213
newParms->add(resolveSniffedNode(callNode->getChild(i)));
5214
}
5215
5216
TR_Array<TR::Node*> *oldParms = _parms;
5217
_parms = newParms;
5218
TR::TreeTop *curTree = _curTree;
5219
bool inColdBlock = _inColdBlock;
5220
//TR::Node *curNode = _curNode;
5221
++_sniffDepth;
5222
5223
TR::ResolvedMethodSymbol *oldMethodSymbol = _methodSymbol;
5224
5225
bool oldInBigDecimalAdd = _inBigDecimalAdd;
5226
if (_methodSymbol && (_methodSymbol->getRecognizedMethod() == TR::java_math_BigDecimal_add))
5227
_inBigDecimalAdd = true;
5228
else
5229
_inBigDecimalAdd = false;
5230
5231
_methodSymbol = methodSymbol;
5232
5233
checkEscape(methodSymbol->getFirstTreeTop(), isCold, ignoreRecursion);
5234
5235
_methodSymbol = oldMethodSymbol;
5236
_inBigDecimalAdd = oldInBigDecimalAdd;
5237
5238
_curTree = curTree;
5239
///// FIXME : This line should be uncommented
5240
////// It is checked in commented out only temporarily
5241
//////
5242
/////
5243
_inColdBlock = inColdBlock;
5244
_parms = oldParms;
5245
--_sniffDepth;
5246
5247
#if CHECK_MONITORS
5248
/* monitors */
5249
if (_removeMonitors)
5250
{
5251
TR_MonitorStructureChecker inspector;
5252
if (inspector.checkMonitorStructure(methodSymbol->getFlowGraph()))
5253
{
5254
_removeMonitors = false;
5255
if (trace())
5256
traceMsg(comp(), "Disallowing monitor-removal because of strange monitor structure in sniffed method %s\n",
5257
methodSymbol->getMethod()->signature(trMemory()));
5258
}
5259
}
5260
#endif
5261
5262
return bytecodeSize;
5263
}
5264
5265
// Check for size limits, both on individual object sizes and on total
5266
// object allocation size.
5267
// FIXME: need to modify this method to give priority to non-array objects
5268
//
5269
void TR_EscapeAnalysis::checkObjectSizes()
5270
{
5271
int32_t totalSize = 0;
5272
int32_t i;
5273
Candidate *candidate, *next;
5274
5275
for (candidate = _candidates.getFirst(); candidate; candidate = next)
5276
{
5277
next = candidate->getNext();
5278
if (!candidate->isLocalAllocation())
5279
continue;
5280
5281
// Make sure contiguous objects are not too big
5282
//
5283
if (candidate->isContiguousAllocation())
5284
{
5285
if (candidate->_size > MAX_SIZE_FOR_ONE_CONTIGUOUS_OBJECT)
5286
{
5287
if (trace())
5288
/////printf("secs Fail [%p] because object size is too big in %s\n", candidate->_node, comp()->signature());
5289
;
5290
if (trace())
5291
traceMsg(comp(), " Fail [%p] because object size %d is too big\n", candidate->_node, candidate->_size);
5292
5293
candidate->setLocalAllocation(false);
5294
}
5295
else
5296
totalSize += candidate->_size;
5297
}
5298
else
5299
{
5300
if (candidate->_fields)
5301
{
5302
// Size of non-contiguous object is the sum of its referenced fields
5303
//
5304
for (i = candidate->_fields->size()-1; i >= 0; i--)
5305
candidate->_fieldSize += candidate->_fields->element(i)._size;
5306
totalSize += candidate->_fieldSize;
5307
}
5308
}
5309
}
5310
5311
// If total size for local allocation is too big, remove candidates until the
5312
// total size becomes reasonable.
5313
//
5314
while (totalSize > MAX_SIZE_FOR_ALL_OBJECTS)
5315
{
5316
// Remove the largest contiguous allocation. If there is none, remove
5317
// the largest non-contiguous allocation.
5318
//
5319
int32_t largestContiguousObjectSize = -1;
5320
Candidate *largestContiguousObject = NULL;
5321
int32_t largestNonContiguousObjectSize = -1;
5322
Candidate *largestNonContiguousObject = NULL;
5323
5324
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
5325
{
5326
if (!candidate->isLocalAllocation())
5327
continue;
5328
5329
if (candidate->isContiguousAllocation())
5330
{
5331
if (candidate->_size > largestContiguousObjectSize)
5332
{
5333
largestContiguousObjectSize = candidate->_size;
5334
largestContiguousObject = candidate;
5335
}
5336
}
5337
else
5338
{
5339
if (candidate->_fieldSize > largestNonContiguousObjectSize)
5340
{
5341
largestNonContiguousObjectSize = candidate->_fieldSize;
5342
largestNonContiguousObject = candidate;
5343
}
5344
}
5345
}
5346
if (largestContiguousObjectSize > 0)
5347
{
5348
candidate = largestContiguousObject;
5349
totalSize -= largestContiguousObjectSize;
5350
}
5351
else
5352
{
5353
candidate = largestNonContiguousObject;
5354
totalSize -= largestNonContiguousObjectSize;
5355
}
5356
5357
if (trace())
5358
{
5359
/////printf("secs Fail [%p] because total object size is too big in %s\n", candidate->_node, comp()->signature());
5360
traceMsg(comp(), " Fail [%p] because total object size is too big\n", candidate->_node);
5361
}
5362
5363
// Mark the candidate as not available for local allocation
5364
//
5365
candidate->setLocalAllocation(false);
5366
}
5367
}
5368
5369
void TR_EscapeAnalysis::anchorCandidateReference(Candidate *candidate, TR::Node *reference)
5370
{
5371
// If this candidate reference (which is about to be removed) may be
5372
// referenced later in the block, insert an anchoring treetop for it after
5373
// the current treetop.
5374
//
5375
if (reference->getReferenceCount() > 1 &&
5376
_curTree->getNextTreeTop()->getNode()->getOpCodeValue() != TR::BBEnd &&
5377
(candidate->isContiguousAllocation() || candidate->objectIsReferenced()))
5378
{
5379
// Anchor the child
5380
//
5381
TR::TreeTop::create(comp(), _curTree, TR::Node::create(TR::treetop, 1, reference));
5382
}
5383
}
5384
5385
void TR_EscapeAnalysis::fixupTrees()
5386
{
5387
TR::NodeChecklist visited (comp());
5388
TR::TreeTop *treeTop, *nextTree;
5389
for (treeTop = comp()->getStartTree(); treeTop; treeTop = nextTree)
5390
{
5391
nextTree = treeTop->getNextTreeTop();
5392
_curTree = treeTop;
5393
TR::Node *node = treeTop->getNode();
5394
5395
if (node->getOpCodeValue() == TR::BBStart)
5396
_curBlock = node->getBlock();
5397
else if (!visited.contains(node))
5398
{
5399
if (fixupNode(node, NULL, visited))
5400
{
5401
dumpOptDetails(comp(), "%sRemoving tree rooted at [%p]\n",OPT_DETAILS, node);
5402
_somethingChanged=true;
5403
TR::TransformUtil::removeTree(comp(), treeTop);
5404
}
5405
}
5406
}
5407
}
5408
5409
static bool shouldRemoveTree(Candidate *candidate, TR::Block *block)
5410
{
5411
ListIterator<TR_ColdBlockEscapeInfo> coldBlkInfoIt(candidate->getColdBlockEscapeInfo());
5412
TR_ColdBlockEscapeInfo *info;
5413
for (info = coldBlkInfoIt.getFirst(); info != NULL; info = coldBlkInfoIt.getNext())
5414
{
5415
TR::Block *coldBlk = info->getBlock();
5416
if (block == coldBlk)
5417
return false;
5418
}
5419
5420
return true;
5421
}
5422
5423
5424
// Fix up the node if it is a reference to a field of a local allocation.
5425
// Return true if the node is to be removed.
5426
//
5427
bool TR_EscapeAnalysis::fixupNode(TR::Node *node, TR::Node *parent, TR::NodeChecklist& visited)
5428
{
5429
int32_t i;
5430
int32_t valueNumber;
5431
Candidate *candidate;
5432
TR::Node *child;
5433
5434
visited.add(node);
5435
5436
bool removeThisNode = false;
5437
TR::ResolvedMethodSymbol *calledMethod = NULL;
5438
5439
// Look for indirect loads or stores for fields of local allocations.
5440
//
5441
if (node->getOpCode().isIndirect() &&
5442
node->getOpCode().isLoadVarOrStore() &&
5443
!comp()->suppressAllocationInlining())
5444
{
5445
if (node->getSymbol()->isArrayShadowSymbol() &&
5446
node->getFirstChild()->getOpCode().isArrayRef())
5447
child = node->getFirstChild()->getFirstChild();
5448
else
5449
child = node->getFirstChild();
5450
5451
valueNumber = _valueNumberInfo->getValueNumber(child);
5452
for (candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
5453
{
5454
if (comp()->generateArraylets() && (candidate->_kind != TR::New))
5455
continue;
5456
5457
bool usesValueNum = usesValueNumber(candidate, valueNumber);
5458
5459
// Check if this is a class load for a finalizable test
5460
if (usesValueNum &&
5461
node->getSymbolReference()->getOffset() < (int32_t)comp()->fej9()->getObjectHeaderSizeInBytes() &&
5462
node->getSymbolReference()->getSymbol()->isClassObject() &&
5463
node->getOpCode().isLoadIndirect() &&
5464
isFinalizableInlineTest(comp(), node->getFirstChild(), _curTree->getNode(), node))
5465
{
5466
// This transformation is optional for candidates that can't be stack-allocated and contiguous allocations,
5467
// but required for discontiguous allocations because the class field will no longer exist
5468
if (!candidate->isLocalAllocation() || candidate->isContiguousAllocation())
5469
{
5470
if (performTransformation(comp(), "%sRemoving inline finalizable test [%p] for candidate [%p]\n", OPT_DETAILS, _curTree->getNode(), candidate->_node))
5471
removeThisNode = true;
5472
}
5473
else
5474
{
5475
if (trace())
5476
traceMsg(comp(), "Removing inline finalizable test [%p] for discontiguous candidate [%p]\n", _curTree->getNode(), candidate->_node);
5477
removeThisNode = true;
5478
}
5479
5480
if (removeThisNode)
5481
{
5482
// The isFinalizable test results in zero because the candidate
5483
// has no finalizer, so we can turn it into a const 0.
5484
//
5485
// NOTE: Normally you'd want to anchor children here. However,
5486
// one child is a const whose evaluation point doesn't matter.
5487
// The other is a dereference chain from the candidate. If the
5488
// candidate is noncontiguously allocated, we must remove all
5489
// references, so it would be incorrect to anchor. If the
5490
// candidate is contiguous, it will turn into a loadaddr, whose
5491
// evaluation point doesn't matter. Since anchoring is
5492
// sometimes wrong and never necessary, we just don't do it.
5493
//
5494
TR::Node *andNode = _curTree->getNode()->getFirstChild();
5495
andNode->removeAllChildren();
5496
5497
5498
// In 64-bit mode the isFinalizable test will start out using
5499
// long operations, but subsequent optimization might reduce
5500
// them to int operations, so be prepared to replace the and
5501
// operation with a zero of the appropriate size
5502
if (andNode->getOpCodeValue() == TR::land)
5503
{
5504
TR::Node::recreate(andNode, TR::lconst);
5505
andNode->setLongInt(0);
5506
}
5507
else if (andNode->getOpCodeValue() == TR::iand)
5508
{
5509
TR::Node::recreate(andNode, TR::iconst);
5510
andNode->setInt(0);
5511
}
5512
else
5513
{
5514
TR_ASSERT_FATAL(false, "Expected iand or land in isFinalizable test");
5515
}
5516
}
5517
5518
return false;
5519
}
5520
5521
if (candidate->isLocalAllocation() && usesValueNum)
5522
{
5523
int32_t fieldOffset = node->getSymbolReference()->getOffset();
5524
if (candidate->_origKind == TR::New)
5525
{
5526
TR::SymbolReference *symRef = node->getSymbolReference();
5527
fieldOffset = symRef->getOffset();
5528
}
5529
else
5530
{
5531
TR::Node *offsetNode = NULL;
5532
if (node->getFirstChild()->getOpCode().isArrayRef())
5533
offsetNode = node->getFirstChild()->getSecondChild();
5534
5535
if (offsetNode && offsetNode->getOpCode().isLoadConst())
5536
{
5537
if (offsetNode->getType().isInt64())
5538
fieldOffset = (int32_t) offsetNode->getLongInt();
5539
else
5540
fieldOffset = offsetNode->getInt();
5541
}
5542
}
5543
5544
// For a noncontiguous allocation, we can't leave behind any
5545
// dereferences of the candidate, so we must transform this
5546
// dereference. If it's accessing a field that is not present in
5547
// the candidate, the code is already wrong (and presumably must
5548
// never run!), so we're ok to replace it with different code that
5549
// is also wrong. Hence, we'll vandalize the tree into an iconst 0.
5550
//
5551
// NOTE: it would be cleaner to turn a field load into a const of
5552
// the right type, and a store into a treetop, rather than changing
5553
// the base pointer into an iconst 0. However, we have done this
5554
// for years, so we'll leave it alone to reduce risk because we're
5555
// about to ship Java 8.
5556
//
5557
bool mustRemoveDereferences = !candidate->isContiguousAllocation();
5558
bool fieldIsPresentInObject = true;
5559
5560
int32_t j;
5561
for (j = candidate->_fields->size()-1; j >= 0; j--)
5562
{
5563
if ((candidate->_fields->element(j)._offset == fieldOffset) &&
5564
(!candidate->_fields->element(j).symRefIsForFieldInAllocatedClass(node->getSymbolReference())))
5565
{
5566
if (mustRemoveDereferences)
5567
{
5568
child->decReferenceCount();
5569
child = TR::Node::create(child, TR::iconst, 0, 0);
5570
if (trace())
5571
{
5572
traceMsg(comp(), "Change illegal deref %s [%p] to use dummy base %s [%p] in place of %s [%p]\n",
5573
node->getOpCode().getName(), node,
5574
child->getOpCode().getName(), child,
5575
node->getChild(0)->getOpCode().getName(), node->getChild(0));
5576
}
5577
node->setAndIncChild(0, child);
5578
5579
// A wrtbari can also have the object as the last child.
5580
// If we're vandalizing the wrtbari, it's because we've
5581
// proven it's changing the candidate, and in that case,
5582
// the third child must be a pointer to the candidate. We
5583
// can safely drop that child with no further checking.
5584
//
5585
static char *disableWrtbarFixing = feGetEnv("TR_disableWrtbarFixing");
5586
if (node->getOpCode().isWrtBar() && !disableWrtbarFixing)
5587
{
5588
if (trace())
5589
{
5590
traceMsg(comp(), " -> Change %s [%p] into astorei, removing child %s [%p]\n",
5591
node->getOpCode().getName(), node, node->getChild(2)->getOpCode().getName(), node->getChild(2));
5592
}
5593
node->getAndDecChild(2);
5594
node->setNumChildren(2);
5595
TR::Node::recreate(node, TR::astorei);
5596
node->setFlags(0);
5597
5598
if (parent->getOpCode().isCheck() || parent->getOpCodeValue() == TR::compressedRefs)
5599
{
5600
if (trace())
5601
traceMsg(comp(), " -> Eliminate %s [%p]\n", parent->getOpCode().getName(), parent);
5602
TR::Node::recreate(parent, TR::treetop);
5603
parent->setFlags(0);
5604
}
5605
}
5606
}
5607
fieldIsPresentInObject = false;
5608
break;
5609
}
5610
}
5611
5612
if (fieldIsPresentInObject)
5613
{
5614
// For a candidate that is escaping in a cold block, keep track
5615
// of fields that are referenced so they can be initialized.
5616
// Otherwise, rewrite field references (in else branch_.
5617
// Special case handling of stores to fields of immutable objects
5618
// that are not contiguously allocated - their field references
5619
// are also rewritten (in else branch), but the original stores
5620
// still preserved.
5621
//
5622
if (candidate->escapesInColdBlock(_curBlock)
5623
&& (!isImmutableObject(candidate)
5624
|| candidate->isContiguousAllocation()
5625
|| node->getOpCode().isLoadVar()))
5626
{
5627
// Uh, why are we re-calculating the fieldOffset? Didn't we just do that above?
5628
//
5629
int32_t fieldOffset = node->getSymbolReference()->getOffset();
5630
if (candidate->_origKind == TR::New)
5631
{
5632
TR::SymbolReference *symRef = node->getSymbolReference();
5633
fieldOffset = symRef->getOffset();
5634
}
5635
else
5636
{
5637
TR::Node *offsetNode = NULL;
5638
if (node->getFirstChild()->getOpCode().isArrayRef())
5639
offsetNode = node->getFirstChild()->getSecondChild();
5640
5641
if (offsetNode && offsetNode->getOpCode().isLoadConst())
5642
{
5643
if (offsetNode->getType().isInt64())
5644
fieldOffset = (int32_t) offsetNode->getLongInt();
5645
else
5646
fieldOffset = offsetNode->getInt();
5647
}
5648
}
5649
5650
if (TR_yes == candidateHasField(candidate, node, fieldOffset, this))
5651
{
5652
// Remember the symbol reference of this field so that it can be used to
5653
// zero-initialize the object.
5654
//
5655
int32_t i;
5656
TR::SymbolReference *symRef = node->getSymbolReference();
5657
5658
int32_t nodeSize = node->getSize();
5659
if (comp()->useCompressedPointers() &&
5660
(node->getDataType() == TR::Address))
5661
nodeSize = TR::Compiler->om.sizeofReferenceField();
5662
5663
if (fieldOffset + nodeSize <= candidate->_size) // cmvc 200318: redundant but harmless -- leave in place to minimize disruption
5664
{
5665
for (i = candidate->_fields->size()-1; i >= 0; i--)
5666
{
5667
if (candidate->_fields->element(i)._offset == fieldOffset)
5668
{
5669
candidate->_fields->element(i).rememberFieldSymRef(node, fieldOffset, candidate, this);
5670
if (candidate->isContiguousAllocation())
5671
candidate->_fields->element(i)._symRef = symRef;
5672
candidate->_fields->element(i)._vectorElem = 0;
5673
5674
break;
5675
}
5676
}
5677
TR_ASSERT(i >= 0, "assertion failure");
5678
}
5679
}
5680
}
5681
5682
// For a candidate that is not escaping in a cold block, or that
5683
// is an immutable object that is non-contiguously allocated,
5684
// rewrite references
5685
//
5686
else // if (!candidate->escapesInColdBlock(_curBlock))
5687
// || (isImmutableObject(candidate)
5688
// && !candidate->isContiguousAllocation()))
5689
// && !node->getOpCode().isLoadVar()))
5690
{
5691
if (candidate->isContiguousAllocation())
5692
removeThisNode |= fixupFieldAccessForContiguousAllocation(node, candidate);
5693
else
5694
{
5695
removeThisNode |= fixupFieldAccessForNonContiguousAllocation(node, candidate, parent);
5696
break; // Can only be one matching candidate
5697
}
5698
}
5699
}
5700
else //There was a field outside the bound of an object
5701
if (!candidate->isContiguousAllocation())
5702
break; // Can only be one matching candidate
5703
}
5704
}
5705
5706
if (removeThisNode)
5707
return true;
5708
}
5709
5710
// Look for call to Throwable::fillInStackTrace that can be removed
5711
// (Note this has to be done before processing the children, since the
5712
// children will go away with the call.
5713
//
5714
if (node->getOpCode().isCall())
5715
{
5716
calledMethod = node->getSymbol()->getResolvedMethodSymbol();
5717
if (calledMethod && (!calledMethod->getResolvedMethod()->virtualMethodIsOverridden() || !node->getOpCode().isIndirect()))
5718
{
5719
if (calledMethod->getRecognizedMethod() == TR::java_lang_Throwable_fillInStackTrace)
5720
{
5721
child = node->getChild(node->getFirstArgumentIndex());
5722
valueNumber= _valueNumberInfo->getValueNumber(child);
5723
candidate = findCandidate(valueNumber);
5724
if (candidate && candidate->fillsInStackTrace() && !candidate->usesStackTrace() &&
5725
candidate->isLocalAllocation() && !candidate->escapesInColdBlocks() && performTransformation(comp(), "%sRemoving call node [%p] to fillInStackTrace\n",OPT_DETAILS, node))
5726
{
5727
//printf("Removing fillInStackTrace call in %s\n", comp()->signature());
5728
5729
// If the result of the call is not used, just remove the tree.
5730
// Otherwise replace the call with aconst 0
5731
//
5732
anchorCandidateReference(candidate, child);
5733
if (optimizer()->prepareForNodeRemoval(node, /* deferInvalidatingUseDefInfo = */ true))
5734
_invalidateUseDefInfo = true;
5735
if (node->getReferenceCount() == 1)
5736
return true;
5737
node->removeAllChildren();
5738
TR::Node::recreate(node, TR::aconst);
5739
node->setInt(0);
5740
node->setIsNonNull(false);
5741
node->setIsNull(true);
5742
return false;
5743
}
5744
}
5745
}
5746
}
5747
5748
// Handle some standard constant propagation cases that reference candidate
5749
// objects. Since we may be inlining and then doing another pass of escape
5750
// analysis without doing constant propagation in between, these cases may
5751
// appear even though constant propagation would have simplified them.
5752
// They are handled here so that extraneous references to the candidates are
5753
// removed.
5754
//
5755
else if (node->getOpCodeValue() == TR::NULLCHK)
5756
{
5757
// If the reference child of the NULLCHK is a candidate, replace the
5758
// NULLCHK node by a treetop.
5759
//
5760
child = node->getNullCheckReference();
5761
valueNumber = _valueNumberInfo->getValueNumber(child);
5762
candidate = findCandidate(valueNumber);
5763
if (candidate)
5764
{
5765
TR::Node::recreate(node, TR::treetop);
5766
}
5767
}
5768
5769
else if (node->getOpCode().isArrayLength())
5770
{
5771
// If the child of the arraylength node is a candidate, replace the
5772
// arraylength node by the (constant) bound from the allocation node.
5773
//
5774
child = node->getFirstChild();
5775
valueNumber = _valueNumberInfo->getValueNumber(child);
5776
candidate = findCandidate(valueNumber);
5777
if (candidate &&
5778
performTransformation(comp(), "%sReplacing arraylength [%p] by constant %d\n", OPT_DETAILS, node, candidate->_node->getFirstChild()->getInt()))
5779
{
5780
//TR_ASSERT((candidate->_node->getOpCodeValue() != TR::New) && (candidate->_node->getOpCodeValue() != TR::newStructRef), "assertion failure");
5781
anchorCandidateReference(candidate, child);
5782
if (optimizer()->prepareForNodeRemoval(node, /* deferInvalidatingUseDefInfo = */ true))
5783
_invalidateUseDefInfo = true;
5784
node->removeAllChildren();
5785
TR::Node::recreate(node, TR::iconst);
5786
if (candidate->_node->getOpCodeValue() == TR::New)
5787
{
5788
// Dead code: can't ever execute an arraylength on a TR_New
5789
//see ArrayLest.test_getLTR::java_lang_ObjectI for an example
5790
node->setInt(0xdeadc0de);
5791
}
5792
else
5793
{
5794
node->setInt(candidate->_node->getFirstChild()->getInt());
5795
}
5796
// No need to look at children
5797
//
5798
return false;
5799
}
5800
}
5801
5802
else if (node->getOpCode().isCheckCast() ||
5803
node->getOpCodeValue() == TR::instanceof)
5804
{
5805
// If the first child is a candidate, decide if the test will succeed or
5806
// fail and change the node accordingly
5807
//
5808
child = node->getFirstChild();
5809
TR::Node *classNode = node->getSecondChild();
5810
valueNumber = _valueNumberInfo->getValueNumber(child);
5811
candidate = findCandidate(valueNumber);
5812
if (candidate && isConstantClass(classNode, this))
5813
{
5814
anchorCandidateReference(candidate, child);
5815
if (optimizer()->prepareForNodeRemoval(node, /* deferInvalidatingUseDefInfo = */ true))
5816
_invalidateUseDefInfo = true;
5817
if (comp()->fej9()->isInstanceOf((TR_OpaqueClassBlock *) candidate->_class, (TR_OpaqueClassBlock*)classNode->getSymbol()->castToStaticSymbol()->getStaticAddress(), true) == TR_yes)
5818
{
5819
if (node->getOpCodeValue() == TR::instanceof)
5820
{
5821
if (performTransformation(comp(), "%sReplacing instanceof [%p] by constant 1\n", OPT_DETAILS, node))
5822
{
5823
node->removeAllChildren();
5824
TR::Node::recreate(node, TR::iconst);
5825
node->setInt(1);
5826
}
5827
}
5828
else
5829
{
5830
if (performTransformation(comp(), "%sReplacing %s [%p] by TR::treetop\n", OPT_DETAILS, node->getOpCode().getName(), node))
5831
{
5832
optimizer()->getEliminatedCheckcastNodes().add(node);
5833
optimizer()->getClassPointerNodes().add(classNode);
5834
requestOpt(OMR::catchBlockRemoval);
5835
removeThisNode = true;
5836
}
5837
}
5838
}
5839
else
5840
{
5841
if (node->getOpCodeValue() == TR::instanceof)
5842
{
5843
if (performTransformation(comp(), "%sReplacing instanceof [%p] by constant 0\n", OPT_DETAILS, node))
5844
{
5845
node->removeAllChildren();
5846
TR::Node::recreate(node, TR::iconst);
5847
node->setInt(0);
5848
}
5849
}
5850
else
5851
{
5852
// The checkcast is ok as-is, so long as we still have an object
5853
// around to do the checkcast on.
5854
//
5855
TR_ASSERT(!candidate->isLocalAllocation() || candidate->isContiguousAllocation() || candidate->objectIsReferenced(), "assertion failure");
5856
}
5857
}
5858
5859
// No need to look at children
5860
//
5861
return removeThisNode;
5862
}
5863
}
5864
5865
else if (node->getOpCodeValue() == TR::ifacmpeq || node->getOpCodeValue() == TR::ifacmpne)
5866
{
5867
// If one of the children is a candidate we may be able to determine if
5868
// the comparison will succeed or fail
5869
//
5870
int32_t firstValue = _valueNumberInfo->getValueNumber(node->getFirstChild());
5871
int32_t secondValue = _valueNumberInfo->getValueNumber(node->getSecondChild());
5872
int32_t compareValue = -1;
5873
if (firstValue == secondValue)
5874
{
5875
compareValue = 0;
5876
5877
createGuardSiteForRemovedGuard(comp(), node);
5878
}
5879
else
5880
{
5881
bool notEqual = false;
5882
candidate = findCandidate(firstValue);
5883
if (candidate && ((!candidate->_seenSelfStore && !candidate->_seenStoreToLocalObject && !candidate->escapesInColdBlocks() && !usesValueNumber(candidate, secondValue)) || (node->getSecondChild()->getOpCodeValue() == TR::aconst)))
5884
notEqual = true;
5885
else
5886
{
5887
candidate = findCandidate(secondValue);
5888
if (candidate && ((!candidate->_seenSelfStore && !candidate->_seenStoreToLocalObject && !candidate->escapesInColdBlocks() && !usesValueNumber(candidate, firstValue)) || (node->getSecondChild()->getOpCodeValue() == TR::aconst)))
5889
notEqual = true;
5890
}
5891
if (notEqual)
5892
compareValue = 1;
5893
}
5894
5895
if (compareValue >= 0 &&
5896
performTransformation(comp(), "%sChanging compare node [%p] so that constant propagation can predict it\n", OPT_DETAILS, node))
5897
{
5898
// The comparison is bound to succeed or fail.
5899
// Since it is complicated to remove code at this point, we simply
5900
// change the arguments so that constant propagation can predict that
5901
// the comparison will succeed or fail, and change the code accordingly
5902
//
5903
node->removeAllChildren();
5904
node->setNumChildren(2);
5905
node->setAndIncChild(0, TR::Node::aconst(node, 0));
5906
node->setAndIncChild(1, TR::Node::aconst(node, compareValue));
5907
_somethingChanged = true;
5908
5909
// No need to look at children
5910
//
5911
return false;
5912
}
5913
}
5914
// Get rid of compressed ref anchors for loads/stores to fields of objects that have been made non-contiguous
5915
else if (comp()->useCompressedPointers() &&
5916
node->getOpCodeValue() == TR::compressedRefs)
5917
{
5918
TR::Node *loadOrStore = node->getFirstChild();
5919
bool treeAsExpected = false;
5920
if (loadOrStore &&
5921
(loadOrStore->getOpCode().isLoadVarOrStore() || loadOrStore->getOpCode().isLoadConst()))
5922
treeAsExpected = true;
5923
5924
if (!treeAsExpected || (loadOrStore->getOpCode().hasSymbolReference() && loadOrStore->getSymbolReference()->getSymbol()->isAuto()))
5925
{
5926
TR::Node::recreate(node, TR::treetop);
5927
node->getSecondChild()->decReferenceCount();
5928
node->setSecond(NULL);
5929
node->setNumChildren(1);
5930
if (loadOrStore->getOpCode().isStore())
5931
{
5932
// Explicitly remove stores; some opts (e.g. DSE) don't expect commoned stores.
5933
node->setFirst(loadOrStore->getFirstChild());
5934
if (loadOrStore->getReferenceCount() > 1)
5935
{
5936
TR_ASSERT(loadOrStore->getFirstChild(), "Expecting store to have a child.");
5937
loadOrStore->getFirstChild()->incReferenceCount();
5938
}
5939
loadOrStore->decReferenceCount();
5940
if (trace())
5941
traceMsg(comp(), "Changing orphaned compressed ref anchor [%p] to auto to a treetop and removing store [%p].\n", node, loadOrStore);
5942
}
5943
else
5944
{
5945
if (trace())
5946
traceMsg(comp(), "Changing orphaned compressed ref anchor [%p] to auto to a treetop.\n", node);
5947
}
5948
return false;
5949
}
5950
}
5951
5952
// Look for opportunities to de-synchronize references to a candidate.
5953
//
5954
TR::Node * synchronizedObject = 0;
5955
#if CHECK_MONITORS
5956
if (_removeMonitors &&
5957
(node->getOpCodeValue() == TR::monent ||
5958
node->getOpCodeValue() == TR::monexit))
5959
synchronizedObject = node->getFirstChild();
5960
#else
5961
if (node->getOpCodeValue() == TR::monent ||
5962
node->getOpCodeValue() == TR::monexit)
5963
synchronizedObject = node->getFirstChild();
5964
#endif
5965
else if (node->getOpCodeValue() == TR::allocationFence)
5966
synchronizedObject = node->getAllocation();
5967
else if (calledMethod && calledMethod->isSynchronised() && !calledMethod->isStatic())
5968
synchronizedObject = node->getChild(node->getFirstArgumentIndex());
5969
5970
if (synchronizedObject)
5971
{
5972
valueNumber = _valueNumberInfo->getValueNumber(synchronizedObject);
5973
candidate = findCandidate(valueNumber);
5974
if (candidate &&
5975
!candidate->escapesInColdBlocks())
5976
{
5977
if (calledMethod)
5978
{
5979
if (_desynchronizeCalls)
5980
{
5981
if (trace())
5982
{
5983
/////printf("sec Opportunity to desynchronize call to %s (size %d) in %s\n", calledMethod->getResolvedMethod()->signature(trMemory()), maxBytecodeIndex(calledMethod->getResolvedMethod()), comp()->signature());
5984
traceMsg(comp(), "Mark call node [%p] as desynchronized\n", node);
5985
}
5986
node->setDesynchronizeCall(true);
5987
if (!_inlineCallSites.find(_curTree))
5988
_inlineCallSites.add(_curTree);
5989
}
5990
}
5991
else
5992
{
5993
#if CHECK_MONITORS
5994
if (trace())
5995
traceMsg(comp(), "Remove redundant monitor node [%p]\n", node);
5996
removeThisNode = true;
5997
#else
5998
if (node->getOpCodeValue() == TR::allocationFence)
5999
{
6000
if (candidate->isLocalAllocation())
6001
{
6002
if (trace())
6003
traceMsg(comp(), "Redundant flush node [%p] found! Set omitSync flag on redundant flush node.\n", node);
6004
6005
node->setOmitSync(true);
6006
node->setAllocation(NULL);
6007
//removeThisNode = true;
6008
}
6009
}
6010
else if (candidate->isLocalAllocation())
6011
{
6012
// Mark the node as being a monitor on a local object and let
6013
// redundant monitor elimination get rid of it.
6014
//
6015
node->setLocalObjectMonitor(true);
6016
requestOpt(OMR::redundantMonitorElimination);
6017
if (trace())
6018
traceMsg(comp(), "Mark monitor node [%p] as local object monitor\n", node);
6019
}
6020
#endif
6021
}
6022
}
6023
6024
else if(candidate && candidate->escapesInColdBlocks() &&
6025
node->getOpCodeValue() == TR::allocationFence &&
6026
candidate->isLocalAllocation())
6027
{
6028
ListIterator<TR_ColdBlockEscapeInfo> coldBlkInfoIt(candidate->getColdBlockEscapeInfo());
6029
TR_ColdBlockEscapeInfo *info;
6030
for (info = coldBlkInfoIt.getFirst(); info != NULL; info = coldBlkInfoIt.getNext())
6031
{
6032
TR::Block *coldBlk = info->getBlock();
6033
if (!hasFlushOnEntry(coldBlk->getNumber()))
6034
{
6035
TR::TreeTop *insertionPoint = coldBlk->getEntry();
6036
TR::Node *flush = TR::Node::createAllocationFence(candidate->_node, candidate->_node);
6037
flush->setAllocation(NULL);
6038
TR::TreeTop *flushTT = TR::TreeTop::create(comp(), flush, NULL, NULL);
6039
TR::TreeTop *afterInsertionPoint = insertionPoint->getNextTreeTop();
6040
flushTT->join(afterInsertionPoint);
6041
insertionPoint->join(flushTT);
6042
if (trace())
6043
traceMsg(comp(), "Adding flush node %p to cold block_%d\n", flush,coldBlk->getNumber());
6044
setHasFlushOnEntry(coldBlk->getNumber());
6045
}
6046
}
6047
if (trace())
6048
traceMsg(comp(), "Remove redundant flush node [%p]\n", node);
6049
removeThisNode = true;
6050
6051
}
6052
6053
}
6054
6055
for (i = node->getNumChildren()-1; i >= 0; i--)
6056
{
6057
TR::Node *child = node->getChild(i);
6058
if (!visited.contains(child))
6059
{
6060
if (fixupNode(child, node, visited))
6061
removeThisNode = true;
6062
}
6063
}
6064
6065
if (removeThisNode)
6066
return true;
6067
6068
// If no local object is to be created remove all nodes that refer to the
6069
// original allocation.
6070
//
6071
candidate = findCandidate(_valueNumberInfo->getValueNumber(node));
6072
if (candidate &&
6073
candidate->isLocalAllocation() &&
6074
!candidate->isContiguousAllocation() &&
6075
//shouldRemoveTree(candidate, _curBlock) &&
6076
!candidate->objectIsReferenced() &&
6077
!comp()->suppressAllocationInlining())
6078
{
6079
// Remove trees (other than the allocation tree itself) that
6080
// refer to the allocation node.
6081
//
6082
if (_curTree != candidate->_treeTop)
6083
{
6084
// special handling for stores to the monitoredObject slot
6085
// if the object is going to be non-contiguously allocated,
6086
// then turn the store into a store of NULL. the store cannot be
6087
// removed because this would lead to an imbalance of the monitorStack
6088
// during liveMonitor propagation
6089
//
6090
if (_curTree->getNode()->getOpCode().isStore() &&
6091
(_curTree->getNode()->getSymbol()->holdsMonitoredObject() ||
6092
(_curTree->getNode()->getSymbolReference() == comp()->getSymRefTab()->findThisRangeExtensionSymRef())))
6093
{
6094
_curTree->getNode()->getFirstChild()->decReferenceCount();
6095
TR::Node *aconstNode = TR::Node::aconst(_curTree->getNode(), 0);
6096
_curTree->getNode()->setAndIncChild(0, aconstNode);
6097
if (trace())
6098
traceMsg(comp(), "%sFixed up liveMonitor store [%p] for candidate [%p]\n", OPT_DETAILS, _curTree->getNode(), candidate->_node);
6099
removeThisNode = false;
6100
}
6101
else
6102
{
6103
removeThisNode = true;
6104
6105
if (trace())
6106
traceMsg(comp(), "Remove tree [%p] with direct reference to candidate [%p]\n", _curTree->getNode(), candidate->_node);
6107
}
6108
}
6109
6110
// Reset the visit count on this node so that subsequent uses
6111
// are also removed.
6112
//
6113
visited.remove(node);
6114
}
6115
6116
return removeThisNode;
6117
}
6118
6119
6120
bool TR_EscapeAnalysis::fixupFieldAccessForContiguousAllocation(TR::Node *node, Candidate *candidate)
6121
{
6122
// Ignore stores to the generic int shadow for nodes that are already
6123
// explicitly initialized. These are the initializing stores and are going to
6124
// be left as they are (except maybe to insert real field symbol references
6125
// later if we can).
6126
//
6127
if (candidate->isExplicitlyInitialized() &&
6128
node->getSymbol() == getSymRefTab()->findGenericIntShadowSymbol())
6129
{
6130
return false;
6131
}
6132
6133
// If the local allocation is the only object that can be the base
6134
// of a write barrier store, change it into a simple indirect store.
6135
// We should be able to do this for arrays as well, however, IA32 TreeEvaluator needs to be
6136
// fixed in order to support this. FIXME
6137
//
6138
if (node->getOpCode().isWrtBar() &&
6139
!candidate->escapesInColdBlocks() &&
6140
_valueNumberInfo->getValueNumber(node->getFirstChild()) == _valueNumberInfo->getValueNumber(candidate->_node))
6141
{
6142
if (candidate->_origKind == TR::New)
6143
{
6144
TR::Node::recreate(node, TR::astorei);
6145
node->getChild(2)->recursivelyDecReferenceCount();
6146
node->setNumChildren(2);
6147
_repeatAnalysis = true;
6148
if (trace())
6149
traceMsg(comp(), "Change node [%p] from write barrier to regular store\n", node);
6150
}
6151
else
6152
{
6153
// We do not remove the wrtbars yet - but atleast remove the bits from
6154
// them indicating that they are non-heap wrtbars
6155
//
6156
node->setIsHeapObjectWrtBar(false);
6157
node->setIsNonHeapObjectWrtBar(true);
6158
}
6159
}
6160
6161
int32_t fieldOffset = node->getSymbolReference()->getOffset();
6162
if (candidate->_origKind == TR::New)
6163
{
6164
TR::SymbolReference *symRef = node->getSymbolReference();
6165
fieldOffset = symRef->getOffset();
6166
}
6167
else
6168
{
6169
TR::Node *offsetNode = NULL;
6170
if (node->getFirstChild()->getOpCode().isArrayRef())
6171
offsetNode = node->getFirstChild()->getSecondChild();
6172
6173
if (offsetNode && offsetNode->getOpCode().isLoadConst())
6174
{
6175
if (offsetNode->getType().isInt64())
6176
fieldOffset = (int32_t) offsetNode->getLongInt();
6177
else
6178
fieldOffset = offsetNode->getInt();
6179
}
6180
}
6181
6182
// Remember the symbol reference of this field so that it can be used to
6183
// zero-initialize the object.
6184
// Only do this for fields whose offsets are within the bounds of the object.
6185
// It is possible to reach uses which (via downcasting) are referencing a
6186
// derived class from the candidate class. At run time, the local allocation
6187
// should never reach these program points.
6188
//
6189
if (TR_yes == candidateHasField(candidate, node, fieldOffset, this))
6190
{
6191
// Remember the symbol reference of this field so that it can be used to
6192
// zero-initialize the object.
6193
//
6194
int32_t i;
6195
TR::SymbolReference *symRef = node->getSymbolReference();
6196
6197
int32_t nodeSize = node->getSize();
6198
if (comp()->useCompressedPointers() &&
6199
(node->getDataType() == TR::Address))
6200
nodeSize = TR::Compiler->om.sizeofReferenceField();
6201
6202
if (fieldOffset + nodeSize <= candidate->_size) // cmvc 200318: redundant but harmless -- leave in place to minimize disruption
6203
{
6204
for (i = candidate->_fields->size()-1; i >= 0; i--)
6205
{
6206
if (candidate->_fields->element(i)._offset == fieldOffset)
6207
{
6208
candidate->_fields->element(i).rememberFieldSymRef(node, fieldOffset, candidate, this);
6209
candidate->_fields->element(i)._symRef = symRef;
6210
candidate->_fields->element(i)._vectorElem = 0;
6211
break;
6212
}
6213
}
6214
TR_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);
6215
}
6216
}
6217
return false;
6218
}
6219
6220
//We should provide a bound for the following array
6221
//Where are the following hard-coded constants coming from anyway?
6222
static TR::DataType convertArrayTypeToDataType[] =
6223
{
6224
TR::NoType, //0
6225
TR::NoType, //1
6226
TR::NoType, //2
6227
TR::NoType, //3
6228
TR::Int8, //4
6229
TR::Int16, //5
6230
TR::Float, //6
6231
TR::Double, //7
6232
TR::Int8, //8
6233
TR::Int16,//9
6234
TR::Int32, //10
6235
TR::Int64
6236
};
6237
6238
TR::Node *TR_EscapeAnalysis::createConst(TR::Compilation *comp, TR::Node *node, TR::DataType type, int value)
6239
{
6240
TR::Node *result;
6241
6242
if (type.isVector())
6243
{
6244
result = TR::Node::create(node, TR::vsplats, 1);
6245
result->setAndIncChild(0, TR::Node::create(node, comp->il.opCodeForConst(type), value));
6246
}
6247
else
6248
{
6249
result = TR::Node::create(node, comp->il.opCodeForConst(type), value);
6250
}
6251
return result;
6252
}
6253
6254
6255
bool TR_EscapeAnalysis::fixupFieldAccessForNonContiguousAllocation(TR::Node *node, Candidate *candidate, TR::Node *parent)
6256
{
6257
int32_t i;
6258
int32_t fieldOffset = (candidate->_origKind == TR::New) ?
6259
comp()->fej9()->getObjectHeaderSizeInBytes() : TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
6260
TR::DataType fieldType = TR::NoType; // or array element type
6261
6262
// If this is a store to the generic int shadow, it is zero-initializing the
6263
// object. Remember which words are being zero-initialized; only fields that
6264
// intersect with these words will have to be explicitly zero-initialized.
6265
// These initializing stores can then be thrown away.
6266
//
6267
if (candidate->isExplicitlyInitialized() &&
6268
node->getOpCode().isStore() &&
6269
node->getSymbol() == getSymRefTab()->findGenericIntShadowSymbol())
6270
{
6271
if (!candidate->_initializedWords)
6272
candidate->_initializedWords = new (trStackMemory()) TR_BitVector(candidate->_size, trMemory(), stackAlloc);
6273
6274
for (i = 3; i >= 0; i--)
6275
candidate->_initializedWords->set(node->getSymbolReference()->getOffset()+i);
6276
6277
if (trace())
6278
traceMsg(comp(), "Remove explicit new initialization node [%p]\n", node);
6279
return true;
6280
}
6281
6282
if (candidate->_origKind == TR::New)
6283
{
6284
TR::SymbolReference *symRef = node->getSymbolReference();
6285
fieldOffset = symRef->getOffset();
6286
fieldType = symRef->getSymbol()->getDataType();
6287
}
6288
else
6289
{
6290
TR_ASSERT(node->getSymbolReference()->getSymbol()->isArrayShadowSymbol(), "expecting store to an array shadow");
6291
fieldOffset = node->getSymbolReference()->getOffset();
6292
TR::Node *typeNode = candidate->_node->getSecondChild();
6293
TR::Node *offsetNode = NULL;
6294
if (node->getFirstChild()->getOpCode().isArrayRef())
6295
offsetNode = node->getFirstChild()->getSecondChild();
6296
6297
if (offsetNode && offsetNode->getOpCode().isLoadConst())
6298
{
6299
if (offsetNode->getType().isInt64())
6300
fieldOffset = (int32_t) offsetNode->getLongInt();
6301
else
6302
fieldOffset = offsetNode->getInt();
6303
}
6304
6305
if (candidate->_origKind == TR::newarray)
6306
fieldType = convertArrayTypeToDataType[typeNode->getInt()];
6307
else
6308
fieldType = TR::Address;
6309
}
6310
6311
// This can happen for a vft-symbol which has no type
6312
//
6313
if (fieldType == TR::NoType)
6314
fieldType = TR::Address;
6315
6316
// Find or create the auto that is to replace this field reference
6317
//
6318
TR::SymbolReference *autoSymRef = NULL;
6319
for (i = candidate->_fields->size()-1; i >= 0; i--)
6320
{
6321
if (candidate->_fields->element(i)._offset == fieldOffset)
6322
{
6323
autoSymRef = candidate->_fields->element(i)._symRef;
6324
break;
6325
}
6326
}
6327
6328
//TR_ASSERT(i >= 0, "assertion failure");
6329
6330
if (i >= 0)
6331
{
6332
// Change the load or store to be a direct load or store of the
6333
// auto. We may have to introduce a conversion if the opcode type for the
6334
// direct store is different from the opcode type for the indirect store
6335
//
6336
TR::DataType nodeType = node->getDataType();
6337
TR::ILOpCodes newOpCode;
6338
if (node->getOpCode().isLoadVar())
6339
newOpCode = comp()->il.opCodeForDirectLoad(nodeType);
6340
else
6341
newOpCode = comp()->il.opCodeForDirectStore(nodeType);
6342
TR::DataType newOpType = comp()->fej9()->dataTypeForLoadOrStore(nodeType);
6343
TR::ILOpCodes conversionOp;
6344
6345
int elem = candidate->_fields->element(i)._vectorElem;
6346
if (elem != 0)
6347
{
6348
fieldOffset = fieldOffset - TR::Symbol::convertTypeToSize(nodeType)*(elem-1);
6349
autoSymRef = NULL;
6350
for (i = candidate->_fields->size()-1; i >= 0; i--)
6351
{
6352
if (candidate->_fields->element(i)._offset == fieldOffset)
6353
{
6354
autoSymRef = candidate->_fields->element(i)._symRef;
6355
break;
6356
}
6357
}
6358
TR_ASSERT(i >= 0, "element 0 should exist\n");
6359
6360
if (!newOpType.isVector())
6361
newOpType = newOpType.scalarToVector();
6362
6363
TR_ASSERT(newOpType != TR::NoType, "wrong type at node %p\n", node);
6364
}
6365
6366
if (!autoSymRef)
6367
{
6368
autoSymRef = getSymRefTab()->createTemporary(comp()->getMethodSymbol(), newOpType);
6369
autoSymRef->getSymbol()->setBehaveLikeNonTemp();
6370
candidate->_fields->element(i).rememberFieldSymRef(node, fieldOffset, candidate, this);
6371
candidate->_fields->element(i)._symRef = autoSymRef;
6372
}
6373
6374
if (node->getOpCode().isLoadVar())
6375
{
6376
node->removeAllChildren();
6377
conversionOp = TR::ILOpCode::getProperConversion(newOpType, nodeType, false /* !wantZeroExtension */);
6378
6379
if (conversionOp != TR::BadILOp)
6380
{
6381
TR::Node::recreate(node, conversionOp);
6382
node->setAndIncChild(0, TR::Node::createWithSymRef(node, newOpCode, 0, autoSymRef));
6383
node->setNumChildren(1);
6384
}
6385
else
6386
{
6387
TR::Node::recreate(node, newOpCode);
6388
node->setSymbolReference(autoSymRef);
6389
}
6390
if (autoSymRef->getSymbol()->getDataType().isVector() &&
6391
!node->getDataType().isVector())
6392
{
6393
TR::Node::recreate(node, node->getDataType() == TR::VectorDouble ? TR::vdgetelem : TR::vigetelem);
6394
node->setAndIncChild(0, TR::Node::create(node, TR::vload, 0));
6395
node->setNumChildren(2);
6396
node->getFirstChild()->setSymbolReference(autoSymRef);
6397
node->setAndIncChild(1, TR::Node::create(node, TR::iconst, 0, elem-1));
6398
}
6399
}
6400
else
6401
{
6402
conversionOp = TR::ILOpCode::getProperConversion(nodeType, newOpType, false /* !wantZeroExtension */);
6403
6404
TR::Node *valueChild;
6405
if (conversionOp != TR::BadILOp)
6406
valueChild = TR::Node::create(conversionOp, 1, node->getSecondChild());
6407
else
6408
valueChild = node->getSecondChild();
6409
6410
// Special case of non-contiguous immutable object that escapes in
6411
// a cold block: need to ensure the store to the original object
6412
// is preserved for heapification; otherwise, replace the old store
6413
// completely
6414
if (candidate->escapesInColdBlock(_curBlock)
6415
&& isImmutableObject(candidate) && !candidate->isContiguousAllocation())
6416
{
6417
TR::Node *newStore = TR::Node::createWithSymRef(newOpCode, 1, 1, valueChild, autoSymRef);
6418
TR::TreeTop *newTree = TR::TreeTop::create(comp(), newStore);
6419
TR::TreeTop *prev = _curTree->getPrevTreeTop();
6420
prev->join(newTree);
6421
newTree->join(_curTree);
6422
6423
if (trace())
6424
traceMsg(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);
6425
}
6426
else
6427
{
6428
valueChild->incReferenceCount();
6429
node->removeAllChildren();
6430
node->setFirst(valueChild);
6431
node->setNumChildren(1);
6432
TR::Node::recreate(node, newOpCode);
6433
node->setSymbolReference(autoSymRef);
6434
}
6435
6436
if (autoSymRef->getSymbol()->getDataType().isVector() &&
6437
!node->getDataType().isVector())
6438
{
6439
TR::Node::recreate(node, TR::vstore);
6440
TR::Node *value = node->getFirstChild();
6441
TR::Node *newValue = TR::Node::create(node, node->getDataType() == TR::VectorDouble ? TR::vdsetelem : TR::visetelem, 3);
6442
newValue->setAndIncChild(0, TR::Node::create(node, TR::vload, 0));
6443
newValue->getFirstChild()->setSymbolReference(autoSymRef);
6444
newValue->setChild(1, value);
6445
newValue->setAndIncChild(2, TR::Node::create(node, TR::iconst, 0, elem-1));
6446
node->setAndIncChild(0, newValue);
6447
}
6448
}
6449
if (trace())
6450
traceMsg(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);
6451
6452
if (parent)
6453
{
6454
if (parent->getOpCode().isNullCheck())
6455
TR::Node::recreate(parent, TR::treetop);
6456
else if (parent->getOpCode().isSpineCheck() && (parent->getFirstChild() == node))
6457
{
6458
TR::TreeTop *prev = _curTree->getPrevTreeTop();
6459
6460
int32_t i = 1;
6461
while (i < parent->getNumChildren())
6462
{
6463
TR::TreeTop *tt = TR::TreeTop::create(comp(), TR::Node::create(TR::treetop, 1, parent->getChild(i)));
6464
parent->getChild(i)->recursivelyDecReferenceCount();
6465
prev->join(tt);
6466
tt->join(_curTree);
6467
prev = tt;
6468
i++;
6469
}
6470
6471
TR::Node::recreate(parent, TR::treetop);
6472
parent->setNumChildren(1);
6473
}
6474
else if (parent->getOpCodeValue() == TR::ArrayStoreCHK)
6475
{
6476
TR::Node::recreate(parent, TR::treetop);
6477
6478
// we need to prepend a _special_ check-cast node to make sure that the store
6479
// would be valid at runtime. The checkcast is special only because it throws
6480
// ArrayStoreException instead of ClassCastException.
6481
//
6482
TR::Node *typeNode = TR::Node::copy(candidate->_node->getSecondChild()); // loadaddr of array type
6483
typeNode->setReferenceCount(0);
6484
TR::Node *source = node->getFirstChild();
6485
TR::Node *checkNode =
6486
TR::Node::createWithSymRef(TR::checkcast, 2, 2, source, typeNode,
6487
getSymRefTab()->findOrCreateCheckCastForArrayStoreSymbolRef(0));
6488
6489
TR::TreeTop *prev = _curTree->getPrevTreeTop();
6490
TR::TreeTop *tt = TR::TreeTop::create(comp(), checkNode);
6491
prev->join(tt);
6492
tt->join(_curTree);
6493
}
6494
else if (parent->getOpCode().isAnchor())
6495
{
6496
TR::Node::recreate(parent, TR::treetop);
6497
parent->getSecondChild()->recursivelyDecReferenceCount();
6498
parent->setNumChildren(1);
6499
}
6500
}
6501
}
6502
else
6503
{
6504
// The load/store is in an unreachable portion of
6505
// the method. If it is a store we get rid of the treetop completely,
6506
// otherwise change the indirect load to be a constant of the
6507
// correct type
6508
//
6509
if (node->getOpCode().isStore())
6510
return true;
6511
else
6512
{
6513
TR::Node::recreate(node, comp()->il.opCodeForConst(node->getDataType()));
6514
if (node->getNumChildren() > 0)
6515
node->getFirstChild()->recursivelyDecReferenceCount();
6516
node->setLongInt(0);
6517
node->setNumChildren(0);
6518
if (trace())
6519
traceMsg(comp(), "Change node [%p] into a constant\n", node);
6520
}
6521
}
6522
6523
return false;
6524
}
6525
6526
6527
void TR_EscapeAnalysis::makeLocalObject(Candidate *candidate)
6528
{
6529
int32_t i;
6530
TR::SymbolReference *symRef;
6531
TR::Node *allocationNode = candidate->_node;
6532
6533
// Change the "new" node into a load address of a local object/array
6534
//
6535
int32_t *referenceSlots = NULL;
6536
if (candidate->_kind == TR::New)
6537
{
6538
symRef = getSymRefTab()->createLocalObject(candidate->_size, comp()->getMethodSymbol(), allocationNode->getFirstChild()->getSymbolReference());
6539
6540
#if LOCAL_OBJECTS_COLLECTABLE
6541
if (candidate->isContiguousAllocation())
6542
referenceSlots = comp()->fej9()->getReferenceSlotsInClass(comp(), (TR_OpaqueClassBlock *)candidate->_node->getFirstChild()->getSymbol()->getStaticSymbol()->getStaticAddress());
6543
#endif
6544
if (!referenceSlots)
6545
symRef->getSymbol()->setNotCollected();
6546
else
6547
symRef->getSymbol()->getLocalObjectSymbol()->setReferenceSlots(referenceSlots);
6548
}
6549
else if (candidate->_kind == TR::anewarray)
6550
{
6551
symRef = getSymRefTab()->createLocalAddrArray(candidate->_size, comp()->getMethodSymbol(), allocationNode->getSecondChild()->getSymbolReference());
6552
symRef->setStackAllocatedArrayAccess();
6553
6554
// Set up the array of reference slots
6555
//
6556
int32_t numSlots = 0;
6557
#if LOCAL_OBJECTS_COLLECTABLE
6558
if (candidate->isContiguousAllocation())
6559
////numSlots = (candidate->_size - TR::Compiler->om.contiguousArrayHeaderSizeInBytes()) / _cg->sizeOfJavaPointer();
6560
numSlots = (candidate->_size - TR::Compiler->om.contiguousArrayHeaderSizeInBytes()) / TR::Compiler->om.sizeofReferenceField();
6561
#endif
6562
if (numSlots == 0)
6563
symRef->getSymbol()->setNotCollected();
6564
else
6565
{
6566
referenceSlots = (int32_t *)trMemory()->allocateHeapMemory((numSlots+1)*4, TR_Memory::EscapeAnalysis);
6567
////int32_t hdrSlots = TR::Compiler->om.contiguousArrayHeaderSizeInBytes()/_cg->sizeOfJavaPointer();
6568
int32_t hdrSlots = TR::Compiler->om.contiguousArrayHeaderSizeInBytes()/TR::Compiler->om.sizeofReferenceField();
6569
for (i = 0; i < numSlots; i++)
6570
referenceSlots[i] = hdrSlots + i;
6571
referenceSlots[numSlots] = 0;
6572
symRef->getSymbol()->getLocalObjectSymbol()->setReferenceSlots(referenceSlots);
6573
}
6574
}
6575
else
6576
{
6577
symRef = getSymRefTab()->createLocalPrimArray(candidate->_size, comp()->getMethodSymbol(), allocationNode->getSecondChild()->getInt());
6578
symRef->setStackAllocatedArrayAccess();
6579
}
6580
6581
if (trace() && referenceSlots)
6582
{
6583
traceMsg(comp(), " Reference slots for candidate [%p] : {",candidate->_node);
6584
for (i = 0; referenceSlots[i]; i++)
6585
{
6586
traceMsg(comp(), " %d", referenceSlots[i]);
6587
}
6588
traceMsg(comp(), " }\n");
6589
}
6590
6591
// Initialize the header of the local object
6592
//
6593
TR::Node *nodeToUseInInit = allocationNode->duplicateTree();
6594
TR::TreeTop *insertionPoint = comp()->getStartTree();
6595
6596
if (candidate->_kind == TR::New)
6597
comp()->fej9()->initializeLocalObjectHeader(comp(), nodeToUseInInit, insertionPoint);
6598
else
6599
comp()->fej9()->initializeLocalArrayHeader(comp(), nodeToUseInInit, insertionPoint);
6600
6601
allocationNode->removeAllChildren();
6602
TR::Node::recreate(allocationNode, TR::loadaddr);
6603
allocationNode->setSymbolReference(symRef);
6604
6605
if (candidate->_seenArrayCopy || candidate->_argToCall || candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)
6606
{
6607
allocationNode->setCannotTrackLocalUses(true);
6608
if (candidate->callsStringCopyConstructor())
6609
allocationNode->setCannotTrackLocalStringUses(true);
6610
}
6611
6612
if (nodeToUseInInit != allocationNode)
6613
{
6614
nodeToUseInInit->removeAllChildren();
6615
TR::Node::recreate(nodeToUseInInit, TR::loadaddr);
6616
nodeToUseInInit->setSymbolReference(symRef);
6617
if (candidate->escapesInColdBlocks() || candidate->_seenArrayCopy || candidate->_argToCall || candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)
6618
{
6619
if (candidate->escapesInColdBlocks())
6620
nodeToUseInInit->setEscapesInColdBlock(true);
6621
nodeToUseInInit->setCannotTrackLocalUses(true);
6622
if (candidate->callsStringCopyConstructor())
6623
nodeToUseInInit->setCannotTrackLocalStringUses(true);
6624
}
6625
}
6626
}
6627
6628
6629
6630
void TR_EscapeAnalysis::avoidStringCopyAllocation(Candidate *candidate)
6631
{
6632
if (comp()->suppressAllocationInlining())
6633
return;
6634
6635
TR::Node *allocationNode = candidate->_node;
6636
6637
dumpOptDetails(comp(), "%sReplacing new (String) node [%p] with the String that was used in the copy constructor\n",OPT_DETAILS, candidate->_node);
6638
6639
if (trace() || debug ("traceContiguousESC"))
6640
{
6641
traceMsg(comp(), "secs (%d) String (copy) allocation of size %d found in %s\n", manager()->numPassesCompleted(), candidate->_size, comp()->signature());
6642
}
6643
6644
6645
TR::TreeTop *insertionPoint = candidate->_treeTop;
6646
TR::DataType dataType = candidate->_stringCopyNode->getDataType();
6647
TR::SymbolReference *newSymbolReference = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dataType);
6648
TR::Node *initNode = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(candidate->_stringCopyNode->getDataType()), 1, 1, candidate->_stringCopyNode, newSymbolReference);
6649
TR::TreeTop *initTree = TR::TreeTop::create(comp(), initNode, 0, 0);
6650
TR::TreeTop *prevTree = insertionPoint->getPrevTreeTop();
6651
prevTree->join(initTree);
6652
initTree->join(insertionPoint);
6653
6654
6655
allocationNode->removeAllChildren();
6656
allocationNode->setNumChildren(0);
6657
TR::Node::recreate(allocationNode, comp()->il.opCodeForDirectLoad(candidate->_stringCopyNode->getDataType()));
6658
allocationNode->setSymbolReference(newSymbolReference);
6659
6660
TR::TreeTop *stringInitCall = candidate->_stringCopyCallTree;
6661
6662
if (stringInitCall)
6663
{
6664
TR::Node *stringInitCallNode = stringInitCall->getNode();
6665
stringInitCallNode->recursivelyDecReferenceCount();
6666
6667
prevTree = stringInitCall->getPrevTreeTop();
6668
TR::TreeTop *nextTree = stringInitCall->getNextTreeTop();
6669
prevTree->join(nextTree);
6670
}
6671
}
6672
6673
/** \details
6674
* This function will fully zero initialize the given candidate, meaning that aside from the header the entirety
6675
* of the stack allocated object will be zero initialized. This function can handle both objects and arrays.
6676
*/
6677
bool TR_EscapeAnalysis::tryToZeroInitializeUsingArrayset(Candidate* candidate, TR::TreeTop* precedingTreeTop)
6678
{
6679
if (cg()->getSupportsArraySet())
6680
{
6681
int32_t candidateHeaderSizeInBytes = candidate->_origKind == TR::New ? comp()->fej9()->getObjectHeaderSizeInBytes() : TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
6682
6683
// Size of the object without the header
6684
int32_t candidateObjectSizeInBytes = candidate->_size - candidateHeaderSizeInBytes;
6685
6686
if (candidateObjectSizeInBytes > 0)
6687
{
6688
TR::Node* allocationNode = candidate->_node;
6689
6690
if (performTransformation(comp(), "%sUse arrayset to initialize [%p]\n", OPT_DETAILS, allocationNode))
6691
{
6692
TR::SymbolReference* allocationSymRef = allocationNode->getSymbolReference();
6693
6694
TR::Node* arrayset = TR::Node::createWithSymRef(TR::arrayset, 3, 3,
6695
TR::Node::createWithSymRef(allocationNode, TR::loadaddr, 0, new (trHeapMemory()) TR::SymbolReference(comp()->getSymRefTab(), allocationSymRef->getSymbol(), allocationSymRef->getOffset() + candidateHeaderSizeInBytes)),
6696
TR::Node::bconst(allocationNode, 0),
6697
TR::Node::iconst(allocationNode, candidateObjectSizeInBytes),
6698
comp()->getSymRefTab()->findOrCreateArraySetSymbol());
6699
6700
TR::TreeTop* arraysetTreeTop = TR::TreeTop::create(comp(), precedingTreeTop, TR::Node::create(TR::treetop, 1, arrayset));
6701
6702
TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "escapeAnalysis/zeroInitializeArrayset/%s", comp()->signature()), arraysetTreeTop);
6703
6704
return true;
6705
}
6706
}
6707
}
6708
6709
return false;
6710
}
6711
6712
void TR_EscapeAnalysis::makeContiguousLocalAllocation(Candidate *candidate)
6713
{
6714
int32_t i,j;
6715
int32_t offset;
6716
TR::Node *node;
6717
TR::Symbol *sym;
6718
TR::TreeTop *initTree, *next;
6719
6720
if (comp()->suppressAllocationInlining())
6721
return;
6722
6723
if (comp()->generateArraylets() && candidate->_kind != TR::New)
6724
return;
6725
6726
dumpOptDetails(comp(), "%sMaking %s node [%p] into a local object of size %d\n",OPT_DETAILS, candidate->_node->getOpCode().getName(), candidate->_node, candidate->_size);
6727
6728
if (trace() || debug ("traceContiguousESC"))
6729
{
6730
traceMsg(comp(), "secs (%d) Contiguous allocation of size %d found in %s\n", manager()->numPassesCompleted(), candidate->_size, comp()->signature());
6731
}
6732
6733
if (candidate->escapesInColdBlocks())
6734
candidate->_originalAllocationNode = candidate->_node->duplicateTree();
6735
6736
bool skipZeroInit = false;
6737
if ((candidate->_node->getOpCodeValue() != TR::New) &&
6738
candidate->_node->canSkipZeroInitialization())
6739
skipZeroInit = true;
6740
6741
makeLocalObject(candidate);
6742
6743
if (skipZeroInit)
6744
return;
6745
6746
TR::Node *allocationNode = candidate->_node;
6747
TR::SymbolReference *symRef = allocationNode->getSymbolReference();
6748
int32_t *referenceSlots = symRef->getSymbol()->getLocalObjectSymbol()->getReferenceSlots();
6749
6750
if (candidate->isExplicitlyInitialized())
6751
{
6752
// Find all the explicit zero-initializations and see if any of the
6753
// generic int shadows can be replaced by real field references.
6754
#if LOCAL_OBJECTS_COLLECTABLE
6755
// Any zero-initializations for collectable fields are removed.
6756
// These fields must be zero-initialized at the start of the method
6757
// instead of at the point of allocation, since liveness is not easily
6758
// predictable for these objects.
6759
#endif
6760
//
6761
for (initTree = candidate->_treeTop->getNextTreeTop(); initTree; initTree = next)
6762
{
6763
next = initTree->getNextTreeTop();
6764
node = initTree->getNode();
6765
if (node->getOpCodeValue() != TR::istorei ||
6766
node->getSymbol() != getSymRefTab()->findGenericIntShadowSymbol() ||
6767
node->getFirstChild() != candidate->_node)
6768
break;
6769
6770
int32_t zeroInitOffset = node->getSymbolReference()->getOffset();
6771
6772
// If this is a zero-initialization for a collectable field, remove
6773
// it since the initialization will be done at the start of the
6774
// method. Don't do this for allocations that are inside loops, since
6775
// for these allocations the initialization must happen every time
6776
// round the loop.
6777
//
6778
if (referenceSlots && !candidate->isInsideALoop())
6779
{
6780
for (j = 0; referenceSlots[j]; j++)
6781
{
6782
////if (zeroInitOffset == referenceSlots[j]*_cg->sizeOfJavaPointer())
6783
if (zeroInitOffset == referenceSlots[j]*TR::Compiler->om.sizeofReferenceField())
6784
{
6785
TR::TransformUtil::removeTree(comp(), initTree);
6786
break;
6787
}
6788
}
6789
if (referenceSlots[j])
6790
continue;
6791
}
6792
6793
if (candidate->_fields && candidate->_origKind == TR::New)
6794
{
6795
for (i = candidate->_fields->size()-1; i >= 0; i--)
6796
{
6797
FieldInfo &field = candidate->_fields->element(i);
6798
offset = field._offset;
6799
if (field._symRef &&
6800
offset == node->getSymbolReference()->getOffset())
6801
{
6802
node->getSecondChild()->recursivelyDecReferenceCount();
6803
sym = field._symRef->getSymbol();
6804
TR::DataType type = sym->getDataType();
6805
node->setAndIncChild(1, createConst(comp(), node, type, 0));
6806
node->setSymbolReference(field._symRef);
6807
TR::Node::recreate(node, comp()->il.opCodeForIndirectStore(type));
6808
break;
6809
}
6810
}
6811
}
6812
}
6813
}
6814
else
6815
{
6816
// Zero-initialize all the non-collectable slots, using field symbol
6817
// references where possible. For news that are inside loops, also initialize
6818
// the collectable slots (in addition to their initialization at method entry)
6819
//
6820
initTree = candidate->_treeTop;
6821
6822
if (candidate->_kind == TR::newarray)
6823
{
6824
// TODO (Task 118458): We need to investigate the effect of using arrayset on small number of elements. This involves verifying the instruction
6825
// sequences each individual codegen will generate and only if the codegens can handle arraysets of small number of elements in a performant manner
6826
// can we enable this optimization.
6827
const bool enableNewArrayArraySetPendingInvestigation = false;
6828
6829
// Non-collectable slots should be initialized with arrayset since they do not have field symrefs
6830
if (enableNewArrayArraySetPendingInvestigation && tryToZeroInitializeUsingArrayset(candidate, initTree))
6831
{
6832
TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "escapeAnalysis/zeroInitializeArrayset/%s/primitive", comp()->signature()), initTree->getNextTreeTop());
6833
6834
return;
6835
}
6836
}
6837
6838
int32_t headerSize = (candidate->_kind == TR::New) ?
6839
comp()->fej9()->getObjectHeaderSizeInBytes() :
6840
TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
6841
int32_t refSlotIndex = 0;
6842
// Changes for new 64-bit object model
6843
i = headerSize;
6844
//for (i = headerSize; i < candidate->_size; i += _cg->sizeOfJavaPointer())
6845
int32_t refIncrVal = TR::Compiler->om.sizeofReferenceField();////TR::Symbol::convertTypeToSize(TR::Address);
6846
int32_t intIncrVal = 4; //TR::Symbol::convertTypeToSize(TR_SInt32)
6847
6848
while (i < candidate->_size)
6849
{
6850
if (!candidate->isInsideALoop() && referenceSlots && i == referenceSlots[refSlotIndex]*TR::Compiler->om.sizeofReferenceField())
6851
{
6852
refSlotIndex++;
6853
i += refIncrVal;
6854
continue;
6855
}
6856
6857
// See if the slot can be initialized using a field reference
6858
//
6859
if (candidate->_fields && candidate->_origKind == TR::New)
6860
{
6861
for (j = candidate->_fields->size()-1; j >= 0; j--)
6862
{
6863
FieldInfo &field = candidate->_fields->element(j);
6864
if (field._offset == i && field._symRef)
6865
{
6866
TR::DataType type = field._symRef->getSymbol()->getDataType();
6867
node = createConst(comp(), allocationNode, type, 0);
6868
node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, allocationNode, node, field._symRef);
6869
initTree = TR::TreeTop::create(comp(), initTree, node);
6870
i += field._size;
6871
TR_ASSERT(field._size != 0, "assertion failure");
6872
break;
6873
}
6874
}
6875
if (j >= 0)
6876
continue;
6877
}
6878
6879
// If we have no field reference, we have to initialize using a generic int shadow.
6880
// Since we don't know the type, we have to initialize only a 4byte slot.
6881
//
6882
node = TR::Node::create(allocationNode, TR::iconst, 0);
6883
node = TR::Node::createWithSymRef(TR::istorei, 2, 2, allocationNode, node, (candidate->_origKind == TR::New)
6884
? getSymRefTab()->findOrCreateGenericIntNonArrayShadowSymbolReference(i) : getSymRefTab()->findOrCreateGenericIntArrayShadowSymbolReference(i));
6885
initTree = TR::TreeTop::create(comp(), initTree, node);
6886
i += intIncrVal;
6887
}
6888
}
6889
6890
// Now go through the collectable reference slots and initialize them at the
6891
// start of the method
6892
//
6893
if (referenceSlots)
6894
{
6895
initTree = comp()->getStartTree();
6896
6897
if (tryToZeroInitializeUsingArrayset(candidate, initTree))
6898
{
6899
TR::DebugCounter::prependDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "escapeAnalysis/zeroInitializeArrayset/%s/reference", comp()->signature()), initTree->getNextTreeTop());
6900
6901
return;
6902
}
6903
6904
TR::Node *baseNode = NULL;
6905
6906
for (i = 0; referenceSlots[i]; i++)
6907
{
6908
////int32_t offset = referenceSlots[i] * _cg->sizeOfJavaPointer();
6909
int32_t offset = referenceSlots[i] * TR::Compiler->om.sizeofReferenceField();
6910
6911
// See if the slot can be initialized using a field reference
6912
//
6913
if (!baseNode)
6914
{
6915
baseNode = TR::Node::createWithSymRef(allocationNode, TR::loadaddr, 0, symRef);
6916
if (candidate->escapesInColdBlocks() || candidate->_seenArrayCopy || candidate->_argToCall || candidate->_seenSelfStore || candidate->_seenStoreToLocalObject)
6917
{
6918
if (candidate->escapesInColdBlocks())
6919
baseNode->setEscapesInColdBlock(true);
6920
baseNode->setCannotTrackLocalUses(true);
6921
if (candidate->callsStringCopyConstructor())
6922
baseNode->setCannotTrackLocalStringUses(true);
6923
}
6924
}
6925
6926
if (candidate->_fields && candidate->_origKind == TR::New)
6927
{
6928
for (j = candidate->_fields->size()-1; j >= 0; j--)
6929
{
6930
FieldInfo &field = candidate->_fields->element(j);
6931
if (field._offset == offset && field._symRef)
6932
{
6933
TR::DataType type = field._symRef->getSymbol()->getDataType();
6934
node = createConst(comp(), allocationNode, type, 0);
6935
node = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, baseNode, node, field._symRef);
6936
if (comp()->useCompressedPointers())
6937
initTree = TR::TreeTop::create(comp(), initTree, TR::Node::createCompressedRefsAnchor(node));
6938
else
6939
initTree = TR::TreeTop::create(comp(), initTree, node);
6940
break;
6941
}
6942
}
6943
if (j >= 0)
6944
continue;
6945
}
6946
6947
// If not, use a generic int shadow to zero-initialize.
6948
//
6949
node = TR::Node::aconst(allocationNode, 0);
6950
//symRef = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(offset);
6951
TR::Node *storeNode = TR::Node::createWithSymRef(TR::astorei, 2, 2,baseNode,node, (candidate->_origKind == TR::New) ?
6952
getSymRefTab()->findOrCreateGenericIntNonArrayShadowSymbolReference(offset) :
6953
getSymRefTab()->findOrCreateGenericIntArrayShadowSymbolReference(offset));
6954
if (comp()->useCompressedPointers())
6955
initTree = TR::TreeTop::create(comp(), initTree, TR::Node::createCompressedRefsAnchor(storeNode));
6956
else
6957
initTree = TR::TreeTop::create(comp(), initTree, storeNode);
6958
}
6959
}
6960
}
6961
6962
void TR_EscapeAnalysis::makeNonContiguousLocalAllocation(Candidate *candidate)
6963
{
6964
if (comp()->suppressAllocationInlining())
6965
return;
6966
6967
if (comp()->generateArraylets() && (candidate->_kind != TR::New))
6968
return;
6969
6970
if (candidate->objectIsReferenced())
6971
{
6972
dumpOptDetails(comp(), "%sMaking %s node [%p] into separate local fields and a local object\n",OPT_DETAILS, candidate->_node->getOpCode().getName(), candidate->_node);
6973
}
6974
else
6975
{
6976
dumpOptDetails(comp(), "%sMaking %s node [%p] into separate local fields\n",OPT_DETAILS, candidate->_node->getOpCode().getName(), candidate->_node);
6977
}
6978
6979
if (trace())
6980
{
6981
traceMsg(comp(),"Pass: (%d) Non-contiguous allocation found in %s\n", manager()->numPassesCompleted(), comp()->signature());
6982
//printf("Pass: (%d) Non-contiguous allocation found in %s\n", manager()->numPassesCompleted(), comp()->signature());
6983
}
6984
6985
// Zero-initialize all the fields
6986
//
6987
if (candidate->_fields)
6988
{
6989
for (int32_t i = candidate->_fields->size()-1; i >= 0; i--)
6990
{
6991
FieldInfo &autoField = candidate->_fields->element(i);
6992
if (!autoField._symRef || !autoField._symRef->getSymbol()->isAuto())
6993
continue;
6994
6995
// If there was explicit zero-initialization of this object, only
6996
// initialize this field if it intersects the explicit zero-initialization
6997
//
6998
if (candidate->isExplicitlyInitialized())
6999
{
7000
if (!candidate->_initializedWords)
7001
continue;
7002
int32_t j;
7003
for (j = autoField._size-1; j >= 0; j--)
7004
{
7005
if (candidate->_initializedWords->get(autoField._offset+j))
7006
break;
7007
}
7008
if (j < 0)
7009
continue;
7010
}
7011
7012
TR::DataType type = autoField._symRef->getSymbol()->getDataType();
7013
TR::Node *node = createConst(comp(), candidate->_node, type, 0);
7014
node = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(type), 1, 1, node, autoField._symRef);
7015
TR::TreeTop::create(comp(), candidate->_treeTop, node);
7016
7017
}
7018
}
7019
7020
if (candidate->escapesInColdBlocks())
7021
{
7022
candidate->_originalAllocationNode = candidate->_node->duplicateTree();
7023
}
7024
7025
// If the object was referenced we will need to create a local object for it
7026
// too. In this case, a local object of type "java/lang/Object" is created.
7027
//
7028
if (candidate->objectIsReferenced())
7029
{
7030
if (candidate->_kind != TR::New)
7031
{
7032
candidate->_origSize = candidate->_size;
7033
candidate->_origKind = candidate->_kind;
7034
7035
// Zero length hybrid arrays have a discontiguous shape.
7036
//
7037
candidate->_size = TR::Compiler->om.discontiguousArrayHeaderSizeInBytes();
7038
7039
TR::Node *sizeChild = candidate->_node->getFirstChild();
7040
TR_ASSERT(sizeChild->getOpCodeValue() == TR::iconst, "The size of non-contiguous stack allocated array object should be constant\n");
7041
if (sizeChild->getReferenceCount() == 1)
7042
sizeChild->setInt(0);
7043
else
7044
{
7045
TR::Node *newSizeChild = TR::Node::create(sizeChild, TR::iconst, 0);
7046
newSizeChild->setInt(0);
7047
candidate->_node->setAndIncChild(0, newSizeChild);
7048
sizeChild->decReferenceCount();
7049
}
7050
}
7051
else
7052
{
7053
// Change the node so that it allocates a java/lang/Object object
7054
//
7055
TR::ResolvedMethodSymbol *owningMethodSymbol = candidate->_node->getSymbolReference()->getOwningMethodSymbol(comp());
7056
TR_OpaqueClassBlock *classObject = comp()->getObjectClassPointer();
7057
////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; dememoizedConstructorCall
7058
TR::SymbolReference *classSymRef = getSymRefTab()->findOrCreateClassSymbol(owningMethodSymbol, -1, classObject, false);
7059
TR::Node *classNode = TR::Node::createWithSymRef(candidate->_node, TR::loadaddr, 0, classSymRef);
7060
candidate->_node->removeAllChildren();
7061
candidate->_node->setAndIncChild(0, classNode);
7062
TR::Node::recreate(candidate->_node, TR::New);
7063
candidate->_node->setNumChildren(1);
7064
candidate->_class = classObject;
7065
candidate->_origSize = candidate->_size;
7066
candidate->_origKind = candidate->_kind;
7067
candidate->_size = comp()->fej9()->getObjectHeaderSizeInBytes() + TR::Compiler->cls.classInstanceSize(classObject);
7068
candidate->_kind = TR::New;
7069
}
7070
candidate->setExplicitlyInitialized(false);
7071
makeLocalObject(candidate);
7072
}
7073
7074
else
7075
{
7076
// Remove the tree containing the allocation node. All uses of the node
7077
// should have been removed by now
7078
//
7079
TR_ASSERT(candidate->_node->getReferenceCount() == 1, "assertion failure");
7080
TR::TransformUtil::removeTree(comp(), candidate->_treeTop);
7081
}
7082
}
7083
7084
7085
7086
void TR_EscapeAnalysis::heapifyForColdBlocks(Candidate *candidate)
7087
{
7088
static char *disableSelectOpForEA = feGetEnv("TR_disableSelectOpForEA");
7089
bool useSelectOp = !disableSelectOpForEA && cg()->getSupportsSelect();
7090
7091
if (comp()->suppressAllocationInlining())
7092
return;
7093
7094
if (trace())
7095
{
7096
traceMsg(comp(),"Found candidate allocated with cold block compensation in %s numBlocks compensated = %d\n", comp()->signature(), candidate->getColdBlockEscapeInfo()->getSize());
7097
//printf("Found candidate allocated with cold block compensation in %s numBlocks compensated = %d\n", comp()->signature(), candidate->getColdBlockEscapeInfo()->getSize());
7098
}
7099
7100
TR::SymbolReference *heapSymRef = getSymRefTab()->createTemporary(comp()->getMethodSymbol(), TR::Address);
7101
7102
TR::TreeTop *allocationTree = candidate->_treeTop;
7103
TR::TreeTop *nextTree = allocationTree->getNextTreeTop();
7104
TR::Node *heapSymRefStore = TR::Node::createWithSymRef(TR::astore, 1, 1, candidate->_node, heapSymRef);
7105
TR::TreeTop *heapSymRefStoreTree = TR::TreeTop::create(comp(), heapSymRefStore, NULL, NULL);
7106
allocationTree->join(heapSymRefStoreTree);
7107
heapSymRefStoreTree->join(nextTree);
7108
7109
if (candidate->isContiguousAllocation())
7110
{
7111
candidate->_node->setCannotTrackLocalUses(true);
7112
candidate->_node->setEscapesInColdBlock(true);
7113
if (candidate->callsStringCopyConstructor())
7114
candidate->_node->setCannotTrackLocalStringUses(true);
7115
//if (candidate->_originalAllocationNode)
7116
// candidate->_originalAllocationNode->setCannotTrackLocalUses(true);
7117
}
7118
7119
ListIterator<TR_ColdBlockEscapeInfo> coldBlockInfoIt(candidate->getColdBlockEscapeInfo());
7120
TR_ColdBlockEscapeInfo *info;
7121
TR::CFG *cfg = comp()->getFlowGraph();
7122
for (info = coldBlockInfoIt.getFirst(); info != NULL; info = coldBlockInfoIt.getNext())
7123
{
7124
// Invalidate structure if adding blocks; can be repaired probably in this
7125
// case if needed in the future
7126
//
7127
comp()->getFlowGraph()->setStructure(NULL);
7128
7129
7130
// Create the heap allocation
7131
//
7132
TR::Block *coldBlock = info->getBlock();
7133
TR::TreeTop *insertionPoint = coldBlock->getEntry();
7134
TR::TreeTop *treeBeforeInsertionPoint = insertionPoint->getPrevTreeTop();
7135
TR::Node *heapAllocation = TR::Node::create(TR::treetop, 1, candidate->_originalAllocationNode->duplicateTree());
7136
heapAllocation->getFirstChild()->setHeapificationAlloc(true);
7137
7138
if (trace())
7139
traceMsg(comp(), "heapifying %p b1 %d b2 %d\n", candidate->_node, candidate->isContiguousAllocation(), candidate->_dememoizedMethodSymRef);
7140
7141
if (!candidate->isContiguousAllocation() && _dememoizedAllocs.find(candidate->_node))
7142
{
7143
heapAllocation->getFirstChild()->getFirstChild()->recursivelyDecReferenceCount(); // remove loadaddr of class
7144
7145
TR::SymbolReference *autoSymRefForValue = NULL;
7146
if (candidate->_fields)
7147
{
7148
int32_t j;
7149
int32_t fieldSize = 0;
7150
for (j = candidate->_fields->size()-1; j >= 0; j--)
7151
{
7152
FieldInfo &field = candidate->_fields->element(j);
7153
fieldSize = field._size;
7154
if (field._symRef &&
7155
field._symRef->getSymbol()->isAuto() &&
7156
(candidate->_origKind == TR::New))
7157
{
7158
autoSymRefForValue = field._symRef;
7159
break;
7160
}
7161
}
7162
}
7163
7164
TR::Node *stackFieldLoad = NULL;
7165
if (autoSymRefForValue)
7166
stackFieldLoad = TR::Node::createWithSymRef(heapAllocation, comp()->il.opCodeForDirectLoad(autoSymRefForValue->getSymbol()->getDataType()), 0, autoSymRefForValue);
7167
else
7168
stackFieldLoad = TR::Node::create(heapAllocation, TR::iconst, 0, 0);
7169
7170
heapAllocation->getFirstChild()->setAndIncChild(0, stackFieldLoad);
7171
TR::Node::recreate(heapAllocation->getFirstChild(), TR::acall);
7172
heapAllocation->getFirstChild()->setSymbolReference(_dememoizationSymRef);
7173
}
7174
7175
7176
7177
TR::TreeTop *heapAllocationTree = TR::TreeTop::create(comp(), heapAllocation, NULL, NULL);
7178
TR::Node *heapStore = TR::Node::createWithSymRef(TR::astore, 1, 1, heapAllocation->getFirstChild(), heapSymRef);
7179
TR::TreeTop *heapStoreTree = TR::TreeTop::create(comp(), heapStore, NULL, NULL);
7180
TR::Block *heapAllocationBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(heapAllocation, comp(), coldBlock->getFrequency())));
7181
heapAllocationBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());
7182
7183
7184
// Check if a heap object has been created for this stack allocated
7185
// candidate before
7186
//
7187
TR::Node *tempLoad = TR::Node::createWithSymRef(heapAllocation, comp()->il.opCodeForDirectLoad(TR::Address), 0, heapSymRef);
7188
TR::Node *heapComparisonNode = TR::Node::createif(TR::ifacmpne, tempLoad, candidate->_node->duplicateTree(), NULL);
7189
TR::TreeTop *heapComparisonTree = TR::TreeTop::create(comp(), heapComparisonNode, NULL, NULL);
7190
TR::Block *heapComparisonBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(heapComparisonNode, comp(), coldBlock->getFrequency())));
7191
heapComparisonBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());
7192
7193
TR::TreeTop *heapComparisonEntryTree = heapComparisonBlock->getEntry();
7194
TR::TreeTop *heapComparisonExitTree = heapComparisonBlock->getExit();
7195
heapComparisonEntryTree->join(heapComparisonTree);
7196
heapComparisonTree->join(heapComparisonExitTree);
7197
7198
heapComparisonExitTree->join(insertionPoint);
7199
7200
if (treeBeforeInsertionPoint)
7201
treeBeforeInsertionPoint->join(heapComparisonEntryTree);
7202
else
7203
comp()->setStartTree(heapComparisonEntryTree);
7204
7205
treeBeforeInsertionPoint = heapComparisonExitTree;
7206
7207
//cfg->addEdge(heapComparisonBlock, firstComparisonBlock);
7208
cfg->addEdge(heapComparisonBlock, heapAllocationBlock);
7209
7210
// Copy the contents into newly created heap allocation
7211
//
7212
TR::TreeTop *heapAllocationEntryTree = heapAllocationBlock->getEntry();
7213
TR::TreeTop *heapAllocationExitTree = heapAllocationBlock->getExit();
7214
heapAllocationEntryTree->join(heapAllocationTree);
7215
heapAllocationTree->join(heapStoreTree);
7216
heapStoreTree->join(heapAllocationExitTree);
7217
7218
heapAllocationExitTree->join(insertionPoint);
7219
7220
if (treeBeforeInsertionPoint)
7221
treeBeforeInsertionPoint->join(heapAllocationEntryTree);
7222
else
7223
comp()->setStartTree(heapAllocationEntryTree);
7224
7225
treeBeforeInsertionPoint = heapStoreTree;
7226
TR::Node *stackAllocation = candidate->_node->duplicateTree();
7227
7228
// Copy all the slots, using field symbol references where possible.
7229
//
7230
int32_t headerSize = (candidate->_origKind == TR::New) ?
7231
comp()->fej9()->getObjectHeaderSizeInBytes() :
7232
TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
7233
int32_t i;
7234
int32_t size = candidate->_size;
7235
if (!candidate->isContiguousAllocation())
7236
size = candidate->_origSize;
7237
// Changes for new 64-bit object model
7238
int32_t refIncrVal = TR::Symbol::convertTypeToSize(TR::Address);
7239
int32_t intIncrVal = 4; // TR::Symbol::convertTypeToSize(TR_SInt32);
7240
i = headerSize;
7241
//for (i = headerSize; i < size; i += _cg->sizeOfJavaPointer())
7242
while (i < size)
7243
{
7244
//
7245
// See if the slot can be initialized using a field reference
7246
//
7247
if (candidate->_fields)
7248
{
7249
int32_t j;
7250
int32_t fieldSize = 0;
7251
for (j = candidate->_fields->size()-1; j >= 0; j--)
7252
{
7253
FieldInfo &field = candidate->_fields->element(j);
7254
fieldSize = field._size;
7255
if (field._offset == i &&
7256
field._symRef &&
7257
(candidate->isContiguousAllocation() || field._symRef->getSymbol()->isAuto()) &&
7258
candidate->_origKind == TR::New)
7259
{
7260
TR::DataType type = field._symRef->getSymbol()->getDataType();
7261
7262
TR::Node *stackFieldLoad = NULL;
7263
if (!candidate->isContiguousAllocation())
7264
stackFieldLoad = TR::Node::createWithSymRef(heapAllocation, comp()->il.opCodeForDirectLoad(type), 0, field._symRef);
7265
else
7266
stackFieldLoad = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(type), 1, 1, stackAllocation, field._symRef);
7267
7268
TR::Node *heapFieldStore = NULL;
7269
TR::TreeTop *translateTT = NULL;
7270
if (stackFieldLoad->getDataType() == TR::Address)
7271
{
7272
heapFieldStore = TR::Node::createWithSymRef(TR::awrtbari, 3, 3, heapAllocation->getFirstChild(), stackFieldLoad, heapAllocation->getFirstChild(), field.fieldSymRef());
7273
if (comp()->useCompressedPointers())
7274
{
7275
translateTT = TR::TreeTop::create(comp(), TR::Node::createCompressedRefsAnchor(heapFieldStore), NULL, NULL);
7276
}
7277
}
7278
else
7279
heapFieldStore = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectStore(type), 2, 2, heapAllocation->getFirstChild(), stackFieldLoad, field.fieldSymRef());
7280
TR::TreeTop *heapFieldStoreTree = NULL;
7281
//comp()->useCompressedPointers()
7282
if (translateTT)
7283
heapFieldStoreTree = translateTT;
7284
else
7285
heapFieldStoreTree = TR::TreeTop::create(comp(), heapFieldStore, NULL, NULL);
7286
treeBeforeInsertionPoint->join(heapFieldStoreTree);
7287
heapFieldStoreTree->join(heapAllocationExitTree);
7288
treeBeforeInsertionPoint = heapFieldStoreTree;
7289
break;
7290
}
7291
}
7292
if (j >= 0)
7293
{
7294
i += fieldSize;
7295
continue;
7296
}
7297
}
7298
7299
// If not, use a generic int shadow to initialize.
7300
//
7301
// don't exceed the object size
7302
// if ((i + refIncrVal) <= size)
7303
// {
7304
// TR::SymbolReference *intShadow = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(i);
7305
7306
// TR::Node *stackFieldLoad = NULL;
7307
// if (candidate->isContiguousAllocation())
7308
// stackFieldLoad = TR::Node::create(TR::aloadi, 1, stackAllocation, intShadow);
7309
// else
7310
// stackFieldLoad = TR::Node::aconst(heapAllocation, 0);
7311
7312
// TR::Node *heapFieldStore = TR::Node::create(TR::astorei, 2, heapAllocation->getFirstChild(), stackFieldLoad, intShadow);
7313
// TR::TreeTop *heapFieldStoreTree = TR::TreeTop::create(comp(), heapFieldStore, NULL, NULL);
7314
// treeBeforeInsertionPoint->join(heapFieldStoreTree);
7315
// heapFieldStoreTree->join(heapAllocationExitTree);
7316
// treeBeforeInsertionPoint = heapFieldStoreTree;
7317
// i += refIncrVal;
7318
// }
7319
// else
7320
// {
7321
TR::SymbolReference *intShadow;
7322
if (candidate->_origKind == TR::New)
7323
intShadow = getSymRefTab()->findOrCreateGenericIntNonArrayShadowSymbolReference(i);
7324
else
7325
intShadow = getSymRefTab()->findOrCreateGenericIntArrayShadowSymbolReference(i);
7326
7327
TR::Node *stackFieldLoad = NULL;
7328
if (candidate->isContiguousAllocation())
7329
stackFieldLoad = TR::Node::createWithSymRef(TR::iloadi, 1, 1, stackAllocation, intShadow);
7330
else
7331
stackFieldLoad = TR::Node::create(heapAllocation, TR::iconst, 0);
7332
TR::Node *heapFieldStore = TR::Node::createWithSymRef(TR::istorei, 2, 2, heapAllocation->getFirstChild(), stackFieldLoad, intShadow);
7333
TR::TreeTop *heapFieldStoreTree = TR::TreeTop::create(comp(), heapFieldStore, NULL, NULL);
7334
treeBeforeInsertionPoint->join(heapFieldStoreTree);
7335
heapFieldStoreTree->join(heapAllocationExitTree);
7336
treeBeforeInsertionPoint = heapFieldStoreTree;
7337
i += intIncrVal;
7338
// }
7339
}
7340
7341
insertionPoint = coldBlock->getEntry();
7342
treeBeforeInsertionPoint = insertionPoint->getPrevTreeTop();
7343
TR::Block *targetBlock = coldBlock;
7344
ListIterator<TR::Node> nodesIt(info->getNodes());
7345
ListIterator<TR::TreeTop> treesIt(info->getTrees());
7346
TR::Node *escapeNode;
7347
TR::TreeTop *escapeTree = treesIt.getFirst();
7348
TR::Block *lastComparisonBlock = NULL, *lastStoreBlock = NULL;
7349
for (escapeNode = nodesIt.getFirst(); escapeNode != NULL; escapeNode = nodesIt.getNext(), escapeTree = treesIt.getNext())
7350
{
7351
bool skipStores = false;
7352
if (escapeTree->getNode()->getOpCode().isReturn())
7353
skipStores = true;
7354
else if (escapeTree->getNode()->getOpCodeValue() == TR::treetop ||
7355
escapeTree->getNode()->getOpCode().isNullCheck())
7356
{
7357
TR::Node *firstChild = escapeTree->getNode()->getFirstChild();
7358
if (firstChild->getOpCodeValue() == TR::athrow)
7359
skipStores = true;
7360
}
7361
7362
if ((!candidate->isContiguousAllocation()) && !skipStores && !isImmutableObject(candidate) )
7363
{
7364
//
7365
// Store back into all the temp slots, using field symbol references where possible.
7366
//
7367
7368
//TR::TreeTop *coldBlockTree = coldBlock->getLastRealTreeTop();
7369
//TR::Node *coldBlockNode = coldBlockTree->getNode();
7370
7371
//if (coldBlockNode->getOpCodeValue() == TR::treetop)
7372
// coldBlockNode = coldBlockNode->getFirstChild();
7373
7374
//if (coldBlockNode->getOpCode().isBranch() ||
7375
// coldBlockNode->getOpCode().isSwitch() ||
7376
// coldBlockNode->getOpCode().isReturn() ||
7377
// coldBlockNode->getOpCodeValue() == TR::athrow)
7378
// coldBlockTree = coldBlockTree->getPrevTreeTop();
7379
//
7380
TR::TreeTop *coldBlockTree = escapeTree;
7381
7382
int32_t headerSize = (candidate->_origKind == TR::New) ?
7383
comp()->fej9()->getObjectHeaderSizeInBytes() :
7384
TR::Compiler->om.contiguousArrayHeaderSizeInBytes();
7385
int32_t size = candidate->_origSize;
7386
// Changes for new 64-bit object model
7387
// instead of _cg->sizeOfJavaPointer(), increment by field size
7388
//for (i = headerSize; i < size; i += incrVal)
7389
int32_t i = headerSize;
7390
int32_t incrVal = 4; // TR::Symbol::convertTypeToSize(TR_SInt32)
7391
while (i < size)
7392
{
7393
//
7394
// See if the slot can be initialized using a field reference
7395
//
7396
TR::TreeTop *nextTreeInColdBlock = coldBlockTree->getNextTreeTop();
7397
if (candidate->_fields)
7398
{
7399
int32_t j;
7400
for (j = candidate->_fields->size()-1; j >= 0; j--)
7401
{
7402
FieldInfo &field = candidate->_fields->element(j);
7403
if (field._offset == i &&
7404
field._symRef && field._symRef->getSymbol()->isAuto() /* &&
7405
field._size == TR::Symbol::convertTypeToSize(TR_SInt32)*/)
7406
{
7407
TR::DataType type = field._symRef->getSymbol()->getDataType();
7408
7409
TR::Node *heapFieldLoad = TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(type), 1, 1, escapeNode, field.fieldSymRef());
7410
TR::TreeTop *translateTT = NULL;
7411
if (comp()->useCompressedPointers()
7412
&& (type == TR::Address))
7413
{
7414
translateTT = TR::TreeTop::create(comp(), TR::Node::createCompressedRefsAnchor(heapFieldLoad), NULL, NULL);
7415
}
7416
TR::Node *stackStore = TR::Node::createWithSymRef(comp()->il.opCodeForDirectStore(type), 1, 1, heapFieldLoad, field._symRef);
7417
TR::TreeTop *stackStoreTree = TR::TreeTop::create(comp(), stackStore, NULL, NULL);
7418
if (trace())
7419
traceMsg(comp(), "Emitting stack store back %p cold %p next %p\n", stackStore, coldBlockTree->getNode(), nextTreeInColdBlock->getNode());
7420
coldBlockTree->join(stackStoreTree);
7421
stackStoreTree->join(nextTreeInColdBlock);
7422
// comp()->useCompressedPointers()
7423
if (translateTT)
7424
{
7425
coldBlockTree->join(translateTT);
7426
translateTT->join(stackStoreTree);
7427
}
7428
coldBlockTree = stackStoreTree;
7429
// increment by data type size
7430
i += field._size;
7431
break;
7432
}
7433
}
7434
if (j >= 0)
7435
continue;
7436
}
7437
i += incrVal;
7438
}
7439
}
7440
}
7441
7442
TR::TreeTop *insertSymRefStoresAfter = NULL;
7443
7444
// If using aselect to perform comparisons, all compares and stores are
7445
// inserted directly at the start of the cold block
7446
if (useSelectOp)
7447
{
7448
insertSymRefStoresAfter = coldBlock->getEntry();
7449
}
7450
7451
ListIterator<TR::SymbolReference> symRefsIt(candidate->getSymRefs());
7452
TR::SymbolReference *symRef;
7453
bool generatedReusedOperations = false;
7454
TR::Node *heapTempLoad = NULL;
7455
TR::Node *candidateStackAddrLoad = NULL;
7456
7457
for (symRef = symRefsIt.getFirst(); symRef; symRef = symRefsIt.getNext())
7458
{
7459
//
7460
// Now create the compares (one for each node) and stores
7461
//
7462
if (useSelectOp)
7463
{
7464
// Reload address of object on heap just once for this block
7465
if (!heapTempLoad)
7466
{
7467
heapTempLoad = TR::Node::createWithSymRef(candidate->_node, TR::aload, 0, heapSymRef);
7468
candidateStackAddrLoad = candidate->_node->duplicateTree();
7469
}
7470
7471
// If variable has address of the stack allocated object, replace
7472
// with the value of the heap allocated object; otherwise, keep the
7473
// current value
7474
//
7475
// astore <object-temp>
7476
// aselect
7477
// acmpeq
7478
// aload <object-temp>
7479
// loadaddr <stack-obj>
7480
// aload <heap-allocated-obj>
7481
// aload <object-temp>
7482
//
7483
TR::Node *symLoad = TR::Node::createWithSymRef(candidate->_node, TR::aload, 0, symRef);
7484
TR::Node *addrCompareNode = TR::Node::create(candidate->_node, TR::acmpeq, 2, symLoad, candidateStackAddrLoad);
7485
TR::Node *chooseAddrNode = TR::Node::create(TR::aselect, 3, addrCompareNode, heapTempLoad, symLoad);
7486
7487
TR::TreeTop *storeTree = storeHeapifiedToTemp(candidate, chooseAddrNode, symRef);
7488
7489
storeTree->join(insertSymRefStoresAfter->getNextTreeTop());
7490
insertSymRefStoresAfter->join(storeTree);
7491
}
7492
else
7493
{
7494
TR::Node *comparisonNode = TR::Node::createif(TR::ifacmpne, TR::Node::createWithSymRef(candidate->_node, TR::aload, 0, symRef), candidate->_node->duplicateTree(), targetBlock->getEntry());
7495
TR::TreeTop *comparisonTree = TR::TreeTop::create(comp(), comparisonNode, NULL, NULL);
7496
TR::Block *comparisonBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(comparisonNode, comp(), coldBlock->getFrequency())));
7497
comparisonBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());
7498
7499
TR::TreeTop *comparisonEntryTree = comparisonBlock->getEntry();
7500
TR::TreeTop *comparisonExitTree = comparisonBlock->getExit();
7501
comparisonEntryTree->join(comparisonTree);
7502
comparisonTree->join(comparisonExitTree);
7503
7504
comparisonExitTree->join(insertionPoint);
7505
7506
if (treeBeforeInsertionPoint)
7507
treeBeforeInsertionPoint->join(comparisonEntryTree);
7508
else
7509
comp()->setStartTree(comparisonEntryTree);
7510
7511
TR::Node *heapifiedObjAddrLoad = TR::Node::createWithSymRef(comparisonNode, TR::aload, 0, heapSymRef);
7512
7513
TR::TreeTop *storeTree = storeHeapifiedToTemp(candidate, heapifiedObjAddrLoad, symRef);
7514
7515
TR::Block *storeBlock = toBlock(cfg->addNode(TR::Block::createEmptyBlock(storeTree->getNode(), comp(), coldBlock->getFrequency())));
7516
storeBlock->inheritBlockInfo(coldBlock, coldBlock->isCold());
7517
7518
cfg->addEdge(comparisonBlock, storeBlock);
7519
cfg->addEdge(comparisonBlock, targetBlock);
7520
cfg->addEdge(storeBlock, targetBlock);
7521
if (targetBlock == coldBlock)
7522
{
7523
lastComparisonBlock = comparisonBlock;
7524
lastStoreBlock = storeBlock;
7525
}
7526
7527
TR::TreeTop *storeEntryTree = storeBlock->getEntry();
7528
TR::TreeTop *storeExitTree = storeBlock->getExit();
7529
7530
comparisonExitTree->join(storeEntryTree);
7531
storeEntryTree->join(storeTree);
7532
storeTree->join(storeExitTree);
7533
storeExitTree->join(insertionPoint);
7534
7535
insertionPoint = comparisonEntryTree;
7536
treeBeforeInsertionPoint = insertionPoint->getPrevTreeTop();
7537
targetBlock = comparisonBlock;
7538
}
7539
}
7540
7541
cfg->addEdge(heapAllocationBlock, targetBlock);
7542
cfg->addEdge(heapComparisonBlock, targetBlock);
7543
heapComparisonNode->setBranchDestination(targetBlock->getEntry());
7544
7545
for (auto pred = coldBlock->getPredecessors().begin(); pred != coldBlock->getPredecessors().end();)
7546
{
7547
TR::CFGNode *predNode = (*pred)->getFrom();
7548
/* might be removed, keep reference to next object in list */
7549
pred++;
7550
if ((useSelectOp && (predNode != heapComparisonBlock)
7551
&& (predNode != heapAllocationBlock))
7552
|| (!useSelectOp && (predNode != lastComparisonBlock)
7553
&& (predNode != lastStoreBlock))
7554
|| coldBlock->isCatchBlock())
7555
{
7556
TR::Block *predBlock = toBlock(predNode);
7557
if (!coldBlock->isCatchBlock() &&
7558
(predBlock->getLastRealTreeTop()->getNode()->getOpCode().isBranch() ||
7559
predBlock->getLastRealTreeTop()->getNode()->getOpCode().isSwitch()))
7560
{
7561
TR::TreeTop *lastTree = predBlock->getLastRealTreeTop();
7562
TR::Node *lastNode = lastTree->getNode();
7563
if (lastNode->getOpCode().isBranch() &&
7564
(lastNode->getBranchDestination() == coldBlock->getEntry()))
7565
predBlock->changeBranchDestination(heapComparisonBlock->getEntry(), cfg);
7566
else
7567
{
7568
if (lastNode->getOpCode().isSwitch())
7569
lastTree->adjustBranchOrSwitchTreeTop(comp(), coldBlock->getEntry(), heapComparisonBlock->getEntry());
7570
7571
cfg->addEdge(predNode, heapComparisonBlock);
7572
cfg->removeEdge(predNode, coldBlock);
7573
}
7574
}
7575
else
7576
{
7577
cfg->addEdge(predNode, heapComparisonBlock);
7578
cfg->removeEdge(predNode, coldBlock);
7579
}
7580
}
7581
}
7582
7583
if (coldBlock->isCatchBlock())
7584
{
7585
TR::TreeTop *coldBlockEntry = coldBlock->getEntry();
7586
TR::TreeTop *coldBlockExit = coldBlock->getExit();
7587
coldBlock->setEntry(heapComparisonEntryTree);
7588
coldBlock->setExit(heapComparisonExitTree);
7589
heapComparisonBlock->setEntry(coldBlockEntry);
7590
heapComparisonBlock->setExit(coldBlockExit);
7591
heapComparisonEntryTree->getNode()->setBlock(coldBlock);
7592
heapComparisonExitTree->getNode()->setBlock(coldBlock);
7593
coldBlockEntry->getNode()->setBlock(heapComparisonBlock);
7594
coldBlockExit->getNode()->setBlock(heapComparisonBlock);
7595
7596
TR_ScratchList<TR::CFGEdge> coldSuccessors(trMemory()), coldExceptionSuccessors(trMemory());
7597
7598
for (auto succ = coldBlock->getSuccessors().begin(); succ != coldBlock->getSuccessors().end(); ++succ)
7599
coldSuccessors.add(*succ);
7600
7601
for (auto succ = coldBlock->getExceptionSuccessors().begin(); succ != coldBlock->getExceptionSuccessors().end(); ++succ)
7602
coldExceptionSuccessors.add(*succ);
7603
7604
for (auto succ = heapComparisonBlock->getSuccessors().begin(); succ != heapComparisonBlock->getSuccessors().end();)
7605
{
7606
if (!coldBlock->hasSuccessor((*succ)->getTo()))
7607
cfg->addEdge(coldBlock, (*succ)->getTo());
7608
cfg->removeEdge(heapComparisonBlock, (*(succ++))->getTo());
7609
}
7610
7611
for (auto succ = heapComparisonBlock->getExceptionSuccessors().begin(); succ != heapComparisonBlock->getExceptionSuccessors().end();)
7612
{
7613
if (!coldBlock->hasExceptionSuccessor((*succ)->getTo()))
7614
cfg->addExceptionEdge(coldBlock, (*succ)->getTo());
7615
cfg->removeEdge(heapComparisonBlock, (*(succ++))->getTo());
7616
}
7617
ListIterator<TR::CFGEdge> bi;
7618
bi.set(&(coldSuccessors));
7619
for (TR::CFGEdge* succ = bi.getFirst(); succ != NULL; succ = bi.getNext())
7620
{
7621
if (!heapComparisonBlock->hasSuccessor(succ->getTo()))
7622
cfg->addEdge(heapComparisonBlock, succ->getTo());
7623
cfg->removeEdge(coldBlock, succ->getTo());
7624
}
7625
7626
bi.set(&(coldExceptionSuccessors));
7627
for (TR::CFGEdge* succ = bi.getFirst(); succ != NULL; succ = bi.getNext())
7628
{
7629
if (!heapComparisonBlock->hasExceptionSuccessor(succ->getTo()))
7630
cfg->addExceptionEdge(heapComparisonBlock, succ->getTo());
7631
cfg->removeEdge(coldBlock, succ->getTo());
7632
}
7633
7634
TR::TreeTop *firstTreeTop = coldBlockEntry->getNextTreeTop();
7635
TR::Node *firstTree = firstTreeTop->getNode();
7636
while (firstTree->getOpCodeValue() == TR::allocationFence)
7637
{
7638
firstTreeTop = firstTreeTop->getNextTreeTop();
7639
firstTree = firstTreeTop->getNode();
7640
}
7641
7642
bool recognizedCatch = true;
7643
if (!firstTree->getOpCode().isStoreDirect() ||
7644
!firstTree->getSymbol()->isAuto() ||
7645
!firstTree->getFirstChild()->getOpCode().hasSymbolReference() ||
7646
(firstTree->getFirstChild()->getSymbolReference() != comp()->getSymRefTab()->findOrCreateExcpSymbolRef()))
7647
recognizedCatch = false;
7648
7649
TR_ASSERT(recognizedCatch, "Catch block is not in recognized form for heapification");
7650
7651
if (recognizedCatch)
7652
{
7653
TR::Node *firstChild = firstTree->getFirstChild();
7654
TR::TreeTop *excTree = firstTreeTop;
7655
TR::TreeTop *prevExcTree = excTree->getPrevTreeTop();
7656
TR::TreeTop *nextExcTree = excTree->getNextTreeTop();
7657
TR::TreeTop *changedPrevExcTree = heapComparisonEntryTree;
7658
TR::TreeTop *changedNextExcTree = heapComparisonEntryTree->getNextTreeTop();
7659
7660
7661
TR::Node *dupFirstChild = firstChild->duplicateTree();
7662
firstTree->setAndIncChild(0, dupFirstChild);
7663
firstChild->setSymbolReference(firstTree->getSymbolReference());
7664
firstChild->decReferenceCount();
7665
7666
prevExcTree->join(nextExcTree);
7667
changedPrevExcTree->join(excTree);
7668
excTree->join(changedNextExcTree);
7669
}
7670
}
7671
}
7672
}
7673
7674
7675
TR::TreeTop *TR_EscapeAnalysis::storeHeapifiedToTemp(Candidate *candidate, TR::Node *value, TR::SymbolReference *symRef)
7676
{
7677
TR::Node *storeNode = TR::Node::createWithSymRef(TR::astore, 1, 1, value, symRef);
7678
TR::TreeTop *storeTree = TR::TreeTop::create(comp(), storeNode, NULL, NULL);
7679
7680
if (symRef->getSymbol()->holdsMonitoredObject())
7681
{
7682
storeNode->setLiveMonitorInitStore(true);
7683
}
7684
storeNode->setHeapificationStore(true);
7685
7686
if (!symRef->getSymbol()->isParm())
7687
{
7688
TR::Node *initStoreNode = TR::Node::createWithSymRef(TR::astore, 1, 1, TR::Node::aconst(candidate->_node, 0), symRef);
7689
if (symRef->getSymbol()->holdsMonitoredObject())
7690
initStoreNode->setLiveMonitorInitStore(true);
7691
TR::TreeTop *initStoreTree = TR::TreeTop::create(comp(), initStoreNode, NULL, NULL);
7692
TR::TreeTop *startTree = comp()->getStartTree();
7693
TR::TreeTop *nextToStart = startTree->getNextTreeTop();
7694
startTree->join(initStoreTree);
7695
initStoreTree->join(nextToStart);
7696
}
7697
7698
return storeTree;
7699
}
7700
7701
7702
bool TR_EscapeAnalysis::devirtualizeCallSites()
7703
{
7704
bool devirtualizedSomething = false;
7705
while (!_devirtualizedCallSites.isEmpty())
7706
{
7707
TR::TreeTop *callSite = _devirtualizedCallSites.popHead();
7708
7709
devirtualizedSomething = true;
7710
7711
TR::Node *callNode = callSite->getNode();
7712
if (callNode->getOpCode().isCheck() || callNode->getOpCodeValue() == TR::treetop)
7713
callNode = callNode->getFirstChild();
7714
TR::ResolvedMethodSymbol *calledMethod = callNode->getSymbol()->getResolvedMethodSymbol();
7715
if (calledMethod && (!(calledMethod->getResolvedMethod()->virtualMethodIsOverridden()) && callNode->getOpCode().isIndirect()))
7716
{
7717
TR::Block *block = callSite->getEnclosingBlock();
7718
TR::Node *guardNode = TR_VirtualGuard::createNonoverriddenGuard(TR_NonoverriddenGuard, comp(),
7719
callNode->getByteCodeInfo().getCallerIndex(),
7720
callNode,
7721
NULL,
7722
callNode->getSymbol()->getResolvedMethodSymbol(),false);
7723
dumpOptDetails(comp(), "new guard=%p added for callsite =%p (%p)\n",guardNode,callSite,callNode);
7724
//create empty tree and let the splitter fix the callNode and then duplicate it.
7725
TR::TreeTop *compareTree = TR::TreeTop::create(comp(), guardNode);
7726
TR::TreeTop *directCallTree = TR::TreeTop::create(comp());
7727
TR::TreeTop *coldTree = TR::TreeTop::create(comp());
7728
TR::Block * remainder = block->createConditionalBlocksBeforeTree(callSite, compareTree, coldTree, directCallTree, comp()->getFlowGraph(),false);
7729
7730
TR::Node * directCall = callNode->duplicateTree();
7731
7732
TR::Node * directCallTreeNode;
7733
7734
if (callSite->getNode()->getOpCode().hasSymbolReference())
7735
directCallTreeNode = TR::Node::createWithSymRef(callSite->getNode()->getOpCodeValue(), 1, 1, directCall, callSite->getNode()->getSymbolReference());
7736
else
7737
directCallTreeNode = TR::Node::create(callSite->getNode()->getOpCodeValue(), 1, directCall);
7738
7739
directCallTree->setNode(directCallTreeNode);
7740
7741
directCall->devirtualizeCall(directCallTree);
7742
7743
7744
TR::Node * coldCall = callNode->duplicateTree();
7745
7746
TR::Node * coldTreeNode;
7747
if (callSite->getNode()->getOpCode().hasSymbolReference())
7748
coldTreeNode = TR::Node::createWithSymRef(callSite->getNode()->getOpCodeValue(), 1, 1, coldCall, callSite->getNode()->getSymbolReference());
7749
else
7750
coldTreeNode = TR::Node::create(callSite->getNode()->getOpCodeValue(), 1, coldCall);
7751
coldTree->setNode(coldTreeNode);
7752
7753
if (callNode->getReferenceCount() >= 1)
7754
{
7755
//need to fixup references to the original call
7756
//store return value to temp (after direct call and after cold call)
7757
//load it back (instead of the references)
7758
7759
TR::DataType dt = callNode->getDataType();
7760
7761
TR::SymbolReference * temp1 = comp()->getSymRefTab()->createTemporary(comp()->getMethodSymbol(), dt);
7762
7763
TR::TreeTop *newStoreTree1 = TR::TreeTop::create(comp(), TR::Node::createStore(temp1, directCall));
7764
7765
newStoreTree1->join(directCallTree->getNextTreeTop());
7766
directCallTree->join(newStoreTree1);
7767
7768
//add store of return val after cold call
7769
TR::TreeTop *newStoreTree2 = TR::TreeTop::create(comp(), TR::Node::createStore(temp1, coldCall));
7770
newStoreTree2->join(coldTree->getNextTreeTop());
7771
coldTree->join(newStoreTree2);
7772
7773
//replace all references of the orig call in the remainder with load of return val
7774
callNode->removeAllChildren();
7775
TR::Node::recreate(callNode, comp()->il.opCodeForDirectLoad(dt));
7776
callNode->setNumChildren(0);
7777
callNode->setSymbolReference(temp1);
7778
}
7779
}
7780
}
7781
7782
return devirtualizedSomething;
7783
}
7784
7785
7786
7787
7788
7789
bool TR_EscapeAnalysis::inlineCallSites()
7790
{
7791
scanForExtraCallsToInline();
7792
7793
bool inlinedSomething = false;
7794
while (!_inlineCallSites.isEmpty())
7795
{
7796
TR::TreeTop *treeTop = _inlineCallSites.popHead();
7797
TR::ResolvedMethodSymbol *methodSym = treeTop->getNode()->getFirstChild()->getSymbol()->getResolvedMethodSymbol();
7798
TR_ResolvedMethod *method = methodSym->getResolvedMethod();
7799
int32_t size = method->maxBytecodeIndex();
7800
7801
//The inliner might remove unreachable regions/blocks - check if the remaining calls to inline exist in the remaining trees.
7802
TR::TreeTop *entryTree = comp()->getStartTree();
7803
TR::TreeTop *exitTree = comp()->getMethodSymbol()->getLastTreeTop();
7804
TR::TreeTop *tt;
7805
for (tt = entryTree->getNextTreeTop(); tt != exitTree; tt = tt->getNextTreeTop())
7806
{
7807
if ((tt->getNode()->getNumChildren() > 0) &&
7808
tt->getNode()->getFirstChild() == treeTop->getNode()->getFirstChild())
7809
break;
7810
}
7811
if (tt == exitTree)
7812
{
7813
if (trace())
7814
traceMsg(comp(), "attempt to inline call %p failed because the block was removed\n",treeTop->getNode()->getFirstChild());
7815
continue;
7816
}
7817
7818
if (!alwaysWorthInlining(treeTop->getNode()->getFirstChild()))
7819
{
7820
// Check size thresholds so we don't inline the universe
7821
//
7822
if (getOptData()->_totalInlinedBytecodeSize + size > _maxInlinedBytecodeSize)
7823
{
7824
dumpOptDetails(comp(), "\nNOT inlining method %s into treetop at [%p], total inlined size = %d\n", method->signature(trMemory()), treeTop->getNode(), getOptData()->_totalInlinedBytecodeSize + size);
7825
return false;
7826
}
7827
}
7828
7829
if (trace())
7830
{
7831
/////printf("secs Inlining method %s in %s\n", method->signature(trMemory()), comp()->signature());
7832
traceMsg(comp(), "\nInlining method %s into treetop at [%p], total inlined size = %d\n", method->signature(trMemory()), treeTop->getNode(), getOptData()->_totalInlinedBytecodeSize+size);
7833
}
7834
7835
// Now inline the call
7836
//
7837
7838
bool toInlineFully = (treeTop->getNode()->getFirstChild()->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_lang_Integer_init) || (treeTop->getNode()->getFirstChild()->getSymbol()->castToMethodSymbol()->getRecognizedMethod() == TR::java_lang_Integer_valueOf);
7839
if (performTransformation(comp(), "%sAttempting to inline call [%p]%s\n", OPT_DETAILS, treeTop->getNode(), toInlineFully?" fully":""))
7840
{
7841
TR_InlineCall newInlineCall(optimizer(), this);
7842
newInlineCall.setSizeThreshold(size+100);
7843
bool inlineOK = newInlineCall.inlineCall(treeTop, 0, toInlineFully);
7844
7845
if (inlineOK)
7846
{
7847
getOptData()->_totalInlinedBytecodeSize += size;
7848
inlinedSomething = true;
7849
if (trace())
7850
traceMsg(comp(), "inlined succeeded\n");
7851
}
7852
}
7853
}
7854
return inlinedSomething;
7855
}
7856
7857
static bool alreadyGoingToInline(TR::Node *callNode, TR_ScratchList<TR::TreeTop> &listOfCallTrees)
7858
{
7859
// A given callNode can appear under multiple treetops, so we can't just
7860
// compare treetop identities if we want to make sure we don't try to inline
7861
// the same function twice.
7862
//
7863
ListIterator<TR::TreeTop> iter(&listOfCallTrees);
7864
for (TR::TreeTop *callTree = iter.getFirst(); callTree; callTree = iter.getNext())
7865
{
7866
if (callTree->getNode()->getFirstChild() == callNode)
7867
return true;
7868
}
7869
return false;
7870
}
7871
7872
void TR_EscapeAnalysis::scanForExtraCallsToInline()
7873
{
7874
if (!_repeatAnalysis)
7875
{
7876
// This is the last pass of EA. If there are any calls that we had
7877
// previously declined to inline to benefit EA, we longer need to
7878
// restrain ourselves, and can inline them now.
7879
//
7880
for (TR::TreeTop *tt = comp()->getStartTree(); tt; tt = tt->getNextTreeTop())
7881
{
7882
if ( tt->getNode()->getOpCodeValue() == TR::BBStart
7883
&& tt->getNode()->getBlock()->isCold())
7884
{
7885
// Don't bother inlining calls in cold blocks
7886
//
7887
tt = tt->getNode()->getBlock()->getExit();
7888
continue;
7889
}
7890
7891
TR::TreeTop *callTreeToInline = NULL;
7892
TR::Node *callNode = NULL;
7893
char *reason = "??";
7894
if ( tt->getNode()->getNumChildren() >= 1
7895
&& tt->getNode()->getFirstChild()->getOpCode().isCall()
7896
&& tt->getNode()->getFirstChild()->getSymbol()->isResolvedMethod())
7897
{
7898
callNode = tt->getNode()->getFirstChild();
7899
if (!callNode->isTheVirtualCallNodeForAGuardedInlinedCall())
7900
{
7901
switch (callNode->getSymbol()->getResolvedMethodSymbol()->getRecognizedMethod())
7902
{
7903
case TR::java_lang_Integer_valueOf:
7904
callTreeToInline = tt;
7905
reason = "dememoization did not eliminate it";
7906
break;
7907
default:
7908
break;
7909
}
7910
}
7911
}
7912
if (callTreeToInline && !alreadyGoingToInline(callNode, _inlineCallSites))
7913
{
7914
_inlineCallSites.add(callTreeToInline);
7915
if (trace())
7916
traceMsg(comp(), "Consider inlining %s n%dn [%p] of %s because %s\n", callNode->getOpCode().getName(), callNode->getGlobalIndex(), callNode, callNode->getSymbolReference()->getName(comp()->getDebug()), reason);
7917
}
7918
}
7919
}
7920
}
7921
7922
bool TR_EscapeAnalysis::alwaysWorthInlining(TR::Node *callNode)
7923
{
7924
// If this gets any more sophisticated, it should probably start sharing
7925
// code with alwaysWorthInlining from the inliner.
7926
//
7927
TR::ResolvedMethodSymbol *callee = callNode->getSymbol()->getResolvedMethodSymbol();
7928
if (callee) switch (callee->getRecognizedMethod())
7929
{
7930
case TR::java_lang_Integer_valueOf:
7931
return true;
7932
default:
7933
break;
7934
}
7935
return false;
7936
}
7937
7938
//TR::TreeTop * TR_EscapeAnalysis::findCallSiteFixed(TR::TreeTop * virtualCallSite)
7939
bool TR_EscapeAnalysis::findCallSiteFixed(TR::TreeTop * virtualCallSite)
7940
{
7941
for (TR_CallSitesFixedMapper *cur = _fixedVirtualCallSites.getFirst(); cur; cur = cur->getNext())
7942
{
7943
if (cur->_vCallSite == virtualCallSite)
7944
{
7945
//return cur->_dCallSite;
7946
return true;
7947
}
7948
}
7949
7950
//return NULL;
7951
return false;
7952
}
7953
7954
7955
7956
7957
void TR_EscapeAnalysis::printCandidates(char *title)
7958
{
7959
if (title)
7960
traceMsg(comp(), "\n%s\n", title);
7961
7962
int32_t index = 0;
7963
for (Candidate *candidate = _candidates.getFirst(); candidate; candidate = candidate->getNext())
7964
{
7965
traceMsg(comp(), "Candidate %d:\n", index++);
7966
candidate->print();
7967
}
7968
}
7969
7970
static void printSymRefList(TR_ScratchList<TR::SymbolReference> *list, TR::Compilation *comp)
7971
{
7972
ListIterator<TR::SymbolReference> iter(list);
7973
char *sep = "";
7974
for (TR::SymbolReference *symRef = iter.getFirst(); symRef; symRef = iter.getNext())
7975
{
7976
traceMsg(comp, "%s#%d", sep, symRef->getReferenceNumber());
7977
sep = ",";
7978
}
7979
}
7980
7981
void Candidate::print()
7982
{
7983
traceMsg(comp(), " Node = %p, contiguous = %d, local = %d\n", _node, isContiguousAllocation(), isLocalAllocation());
7984
traceMsg(comp(), " Value numbers = {");
7985
for (uint32_t j = 0; j <_valueNumbers->size(); j++)
7986
traceMsg(comp(), " %d", _valueNumbers->element(j));
7987
traceMsg(comp(), " }\n");
7988
if (isLocalAllocation() && hasCallSites())
7989
{
7990
traceMsg(comp(), " Max inline depth = %d, inline bytecode size = %d\n", _maxInlineDepth, _inlineBytecodeSize);
7991
traceMsg(comp(), " Call sites to be inlined:\n");
7992
ListIterator<TR::TreeTop> callSites(getCallSites());
7993
for (TR::TreeTop *callSite = callSites.getFirst(); callSite; callSite = callSites.getNext())
7994
{
7995
TR::Node *node = callSite->getNode()->getFirstChild();
7996
traceMsg(comp(), " [%p] %s\n", node, node->getSymbol()->getMethodSymbol()->getMethod()->signature(trMemory()));
7997
}
7998
}
7999
if (_fields)
8000
{
8001
traceMsg(comp(), " %d fields:\n", _fields->size());
8002
for (int32_t i = 0; i < _fields->size(); i++)
8003
{
8004
FieldInfo &field = _fields->element(i);
8005
traceMsg(comp(), " %2d: offset=%-3d size=%-2d vectorElem=%-2d ",
8006
i, field._offset, field._size, field._vectorElem);
8007
if (field._symRef)
8008
traceMsg(comp(), "symRef=#%-4d ", field._symRef->getReferenceNumber());
8009
else
8010
traceMsg(comp(), "symRef=null ");
8011
traceMsg(comp(), "good={");
8012
printSymRefList(field._goodFieldSymrefs, comp());
8013
traceMsg(comp(), "} bad={");
8014
printSymRefList(field._badFieldSymrefs, comp());
8015
traceMsg(comp(), "}\n");
8016
}
8017
}
8018
}
8019
8020
8021
8022
#if CHECK_MONITORS
8023
/* monitors */
8024
8025
// The following code is temporary fix for a problem with illegal monitor state exceptions.
8026
// Escape Analysis must be careful about removing monent/monexit trees if there is a possibility
8027
// of illegal monitor state. This pass (conservatively) checks if the monitor structure may be
8028
// illegal, returns true if it so.
8029
//
8030
// The real fix for this problem is to create the header-only object and let RedundantMonitorElimination
8031
// deal with it, but that fix will be added in the next release (post R20).
8032
//
8033
8034
8035
bool TR_MonitorStructureChecker::checkMonitorStructure(TR::CFG *cfg)
8036
{
8037
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
8038
8039
_foundIllegalStructure = false;
8040
int32_t numBlocks = cfg->getNextNodeNumber();
8041
_seenNodes = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8042
_blockInfo = (int32_t *) trMemory()->allocateStackMemory(numBlocks * sizeof(int32_t), TR_Memory::EscapeAnalysis);
8043
memset(_blockInfo, -1, numBlocks * sizeof(int32_t));
8044
8045
TR::CFGNode *start = cfg->getStart();
8046
TR::CFGNode *end = cfg->getEnd();
8047
_blockInfo[start->getNumber()] = 0;
8048
_blockInfo[end ->getNumber()] = 0;
8049
8050
// Walk reverse post-order
8051
//
8052
TR_ScratchList<TR::CFGNode> stack;
8053
stack.add(start);
8054
while (!stack.isEmpty() && !_foundIllegalStructure)
8055
{
8056
TR::CFGNode *node = stack.popHead();
8057
8058
if (_seenNodes->isSet(node->getNumber()))
8059
continue;
8060
8061
if (node != start)
8062
{
8063
bool notDone = false;
8064
TR_PredecessorIterator pit(node);
8065
for (TR::CFGEdge *edge = pit.getFirst(); edge && !notDone; edge = pit.getNext())
8066
{
8067
TR::CFGNode *pred = edge->getFrom();
8068
if (!_seenNodes->isSet(pred->getNumber()))
8069
notDone = true;
8070
}
8071
8072
if (notDone)
8073
continue;
8074
}
8075
8076
_seenNodes->set(node->getNumber());
8077
processBlock(toBlock(node));
8078
8079
if (node != end)
8080
{
8081
TR_SuccessorIterator sit(node);
8082
for (TR::CFGEdge *edge = sit.getFirst(); edge; edge = sit.getNext())
8083
{
8084
TR::CFGNode *succ = edge->getTo();
8085
stack.add(succ);
8086
}
8087
}
8088
}
8089
8090
return _foundIllegalStructure;
8091
}
8092
8093
void TR_MonitorStructureChecker::processBlock(TR::Block *block)
8094
{
8095
TR::TreeTop *exitTT = block->getExit();
8096
8097
int32_t myInfo = _blockInfo[block->getNumber()];
8098
TR_ASSERT(myInfo != -1, "cfg walk failure"); // the cfg is a connected graph
8099
8100
for (TR::TreeTop *tt = block->getEntry();
8101
tt != exitTT && !_foundIllegalStructure;
8102
tt = tt->getNextTreeTop())
8103
{
8104
TR::Node *node = tt->getNode();
8105
8106
uint32_t exceptions = node->exceptionsRaised();
8107
if (exceptions)
8108
{
8109
for (auto edge = block->getExceptionSuccessors().begin(); edge != block->getExceptionSuccessors().end(); ++edge)
8110
{
8111
TR::Block *succ = toBlock((*edge)->getTo());
8112
if (succ->canCatchExceptions(exceptions))
8113
propagateInfoTo(succ, myInfo);
8114
}
8115
}
8116
8117
if (node->getOpCodeValue() == TR::treetop ||
8118
node->getOpCodeValue() == TR::NULLCHK)
8119
node = node->getFirstChild();
8120
8121
if (node->getOpCodeValue() == TR::monent)
8122
myInfo++;
8123
8124
if (node->getOpCodeValue() == TR::monexit)
8125
myInfo--;
8126
}
8127
8128
TR_SuccessorIterator sit(block);
8129
for (TR::CFGEdge *edge = sit.getFirst(); edge; edge = sit.getNext())
8130
{
8131
TR::CFGNode *succ = edge->getTo();
8132
propagateInfoTo(toBlock(succ), myInfo);
8133
}
8134
}
8135
8136
void TR_MonitorStructureChecker::propagateInfoTo(TR::Block *block, int32_t inInfo)
8137
{
8138
if (inInfo < 0)
8139
_foundIllegalStructure = true;
8140
else
8141
{
8142
int32_t thisInfo = _blockInfo[block->getNumber()];
8143
if (thisInfo == -1)
8144
_blockInfo[block->getNumber()] = inInfo;
8145
else
8146
if (inInfo != thisInfo)
8147
_foundIllegalStructure = true;
8148
}
8149
}
8150
#endif
8151
8152
static TR_DependentAllocations *getDependentAllocationsFor(Candidate *c, List<TR_DependentAllocations> *dependentAllocations)
8153
{
8154
ListIterator<TR_DependentAllocations> dependentIt(dependentAllocations);
8155
TR_DependentAllocations *info;
8156
for (info = dependentIt.getFirst(); info; info=dependentIt.getNext())
8157
{
8158
if (info->getAllocation() == c)
8159
return info;
8160
}
8161
return NULL;
8162
}
8163
8164
8165
8166
static Candidate *getCandidate(TR_LinkHead<Candidate> *candidates, FlushCandidate *flushCandidate)
8167
{
8168
Candidate *candidate = flushCandidate->getCandidate();
8169
if (candidate || flushCandidate->getIsKnownToLackCandidate())
8170
{
8171
return candidate;
8172
}
8173
8174
for (candidate = candidates->getFirst(); candidate; candidate = candidate->getNext())
8175
{
8176
if (flushCandidate->getAllocation() == candidate->_node)
8177
{
8178
flushCandidate->setCandidate(candidate);
8179
break;
8180
}
8181
}
8182
8183
if (!candidate)
8184
{
8185
flushCandidate->setIsKnownToLackCandidate(true);
8186
}
8187
8188
return candidate;
8189
}
8190
8191
8192
TR_DataFlowAnalysis::Kind TR_FlowSensitiveEscapeAnalysis::getKind()
8193
{
8194
return FlowSensitiveEscapeAnalysis;
8195
}
8196
8197
TR_FlowSensitiveEscapeAnalysis *TR_FlowSensitiveEscapeAnalysis::asFlowSensitiveEscapeAnalysis()
8198
{
8199
return this;
8200
}
8201
8202
bool TR_FlowSensitiveEscapeAnalysis::supportsGenAndKillSets()
8203
{
8204
return false;
8205
}
8206
8207
int32_t TR_FlowSensitiveEscapeAnalysis::getNumberOfBits()
8208
{
8209
return _numAllocations;
8210
}
8211
8212
8213
bool TR_FlowSensitiveEscapeAnalysis::getCFGBackEdgesAndLoopEntryBlocks(TR_Structure *structure)
8214
{
8215
if (!structure->asBlock())
8216
{
8217
TR_RegionStructure *region = structure->asRegion();
8218
bool isLoop = region->isNaturalLoop();
8219
8220
//if (!isLoop &&
8221
// !region->isAcyclic())
8222
// return true;
8223
8224
if (isLoop)
8225
{
8226
collectCFGBackEdges(region->getEntry());
8227
_loopEntryBlocks->set(region->getEntry()->getNumber());
8228
if (trace())
8229
traceMsg(comp(), "Block numbered %d is loop entry\n", region->getEntry()->getNumber());
8230
}
8231
8232
TR_StructureSubGraphNode *subNode;
8233
TR_Structure *subStruct = NULL;
8234
TR_RegionStructure::Cursor si(*region);
8235
for (subNode = si.getCurrent(); subNode != NULL; subNode = si.getNext())
8236
{
8237
subStruct = subNode->getStructure();
8238
if (getCFGBackEdgesAndLoopEntryBlocks(subStruct))
8239
return true;
8240
}
8241
}
8242
else
8243
{
8244
if (structure->asBlock()->getBlock()->isCatchBlock())
8245
_catchBlocks->set(structure->getNumber());
8246
}
8247
8248
return false;
8249
}
8250
8251
8252
8253
void TR_FlowSensitiveEscapeAnalysis::collectCFGBackEdges(TR_StructureSubGraphNode *loopEntry)
8254
{
8255
for (auto edge = loopEntry->getPredecessors().begin(); edge != loopEntry->getPredecessors().end(); ++edge)
8256
{
8257
TR_Structure *pred = toStructureSubGraphNode((*edge)->getFrom())->getStructure();
8258
pred->collectCFGEdgesTo(loopEntry->getNumber(), &_cfgBackEdges);
8259
}
8260
}
8261
8262
8263
TR_FlowSensitiveEscapeAnalysis::TR_FlowSensitiveEscapeAnalysis(TR::Compilation *comp, TR::Optimizer *optimizer, TR_Structure *rootStructure, TR_EscapeAnalysis *escapeAnalysis)
8264
: TR_IntersectionBitVectorAnalysis(comp, comp->getFlowGraph(), optimizer, escapeAnalysis->trace()),
8265
_cfgBackEdges(comp->trMemory()),
8266
_flushEdges(comp->trMemory()),
8267
_splitBlocks(comp->trMemory())
8268
{
8269
if (trace())
8270
traceMsg(comp, "Starting FlowSensitiveEscapeAnalysis analysis\n");
8271
8272
if (comp->getVisitCount() > 8000)
8273
comp->resetVisitCounts(1);
8274
8275
// Find the number of allocations and assign an index to each
8276
//
8277
_escapeAnalysis = escapeAnalysis;
8278
_candidates = &(escapeAnalysis->_candidates);
8279
_numAllocations = 0;
8280
_newlyAllocatedObjectWasLocked = false;
8281
_cfgBackEdges.deleteAll();
8282
_flushEdges.deleteAll();
8283
_splitBlocks.deleteAll();
8284
8285
_flushCandidates = new (trStackMemory()) TR_LinkHead<FlushCandidate>;
8286
_flushCandidates->setFirst(NULL);
8287
8288
Candidate *candidate, *next;
8289
for (candidate = _candidates->getFirst(); candidate; candidate = next)
8290
{
8291
next = candidate->getNext();
8292
if (trace())
8293
traceMsg(comp, "Allocation node %p is represented by bit position %d\n", candidate->_node, _numAllocations);
8294
candidate->_index = _numAllocations++;
8295
}
8296
8297
if (trace())
8298
traceMsg(comp, "_numAllocations = %d\n", _numAllocations);
8299
8300
if (_numAllocations == 0)
8301
return; // Nothing to do if there are no allocations
8302
8303
// Allocate the block info before setting the stack mark - it will be used by
8304
// the caller
8305
//
8306
initializeBlockInfo();
8307
8308
// After this point all stack allocation will die when the function returns
8309
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
8310
8311
if (!performAnalysis(rootStructure, false))
8312
{
8313
return;
8314
}
8315
8316
int32_t i;
8317
if (trace())
8318
{
8319
for (i = 1; i < _numberOfNodes; ++i)
8320
{
8321
if (_blockAnalysisInfo[i])
8322
{
8323
traceMsg(comp, "\nSolution for block_%d: ",i);
8324
_blockAnalysisInfo[i]->print(comp);
8325
}
8326
}
8327
traceMsg(comp, "\nEnding FlowSensitiveEscapeAnalysis analysis\n");
8328
}
8329
8330
int32_t blockNum = -1;
8331
TR::TreeTop *treeTop;
8332
TR_BitVector *blockInfo = NULL;
8333
for (treeTop = comp->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())
8334
{
8335
TR::Node *node = treeTop->getNode();
8336
if (node->getOpCodeValue() == TR::BBStart)
8337
{
8338
blockNum = node->getBlock()->getNumber();
8339
blockInfo = _blockAnalysisInfo[blockNum];
8340
8341
//if (_blocksWithFlushes->get(blockNum) &&
8342
// blockInfo &&
8343
// !blockInfo->isEmpty())
8344
// {
8345
// printf("%d allocation(s) reached allocation in block_%d in method %s\n", blockInfo->elementCount(), blockNum, comp->signature();
8346
// blockInfo->print(comp);
8347
// fflush(stdout);
8348
// }
8349
8350
continue;
8351
}
8352
8353
if (node->getOpCode().isNullCheck() ||
8354
node->getOpCode().isResolveCheck() ||
8355
(node->getOpCodeValue() == TR::treetop))
8356
node = node->getFirstChild();
8357
8358
if ((node->getOpCodeValue() == TR::monent) || (node->getOpCodeValue() == TR::monexit))
8359
{
8360
Candidate *candidate;
8361
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
8362
{
8363
if (escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node) == escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()))
8364
{
8365
if (blockInfo &&
8366
blockInfo->get(candidate->_index) &&
8367
performTransformation(comp, "%sMark monitor node [%p] as a local object monitor (flow sensitive escape analysis)\n",OPT_DETAILS, node))
8368
{
8369
//if (!node->isSyncMethodMonitor())
8370
{
8371
node->setLocalObjectMonitor(true);
8372
optimizer->setRequestOptimization(OMR::redundantMonitorElimination);
8373
//printf("Eliminating monitor in %s\n", comp->signature());
8374
}
8375
//else
8376
// {
8377
//printf("Removing monitor from %s\n", comp->signature());
8378
// if (treeTop->getNode() == node)
8379
// TR::Node::recreate(node, TR::treetop);
8380
// else
8381
// TR::Node::recreate(node, TR::PassThrough);
8382
// }
8383
}
8384
break;
8385
}
8386
}
8387
}
8388
}
8389
8390
if (_flushCandidates->isEmpty())
8391
{
8392
return;
8393
}
8394
8395
if (trace())
8396
traceMsg(comp, "\nStarting local flush elimination \n");
8397
8398
TR_LocalFlushElimination localFlushElimination(_escapeAnalysis, _numAllocations);
8399
localFlushElimination.perform();
8400
8401
if (trace())
8402
traceMsg(comp, "\nStarting global flush elimination \n");
8403
8404
if (comp->getFlowGraph()->getStructure()->markStructuresWithImproperRegions())
8405
{
8406
return;
8407
}
8408
8409
int32_t numBlocks = comp->getFlowGraph()->getNextNodeNumber();
8410
_successorInfo = (TR_BitVector **) trMemory()->allocateStackMemory(numBlocks* sizeof(TR_BitVector *));
8411
memset(_successorInfo, 0, numBlocks * sizeof(TR_BitVector *));
8412
_predecessorInfo = (TR_BitVector **) trMemory()->allocateStackMemory(numBlocks* sizeof(TR_BitVector *));
8413
memset(_predecessorInfo, 0, numBlocks * sizeof(TR_BitVector *));
8414
for (TR::CFGNode *node = comp->getFlowGraph()->getFirstNode(); node; node = node->getNext())
8415
{
8416
_successorInfo[node->getNumber()] = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8417
_predecessorInfo[node->getNumber()] = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8418
}
8419
8420
TR_BitVector *visitedNodes = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8421
_loopEntryBlocks = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8422
_catchBlocks = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8423
getCFGBackEdgesAndLoopEntryBlocks(comp->getFlowGraph()->getStructure());
8424
TR::MonitorElimination::collectPredsAndSuccs(comp->getFlowGraph()->getStart(), visitedNodes, _predecessorInfo, _successorInfo, &_cfgBackEdges, _loopEntryBlocks, comp);
8425
8426
_scratch2 = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8427
8428
_scratch = visitedNodes;
8429
_scratch->empty();
8430
//_scratch2 = _loopEntryBlocks;
8431
*_scratch2 = *_loopEntryBlocks;
8432
*_scratch2 |= *_catchBlocks;
8433
//_scratch2->empty();
8434
8435
TR_BitVector *movedToBlocks = new (trStackMemory()) TR_BitVector(numBlocks, trMemory(), stackAlloc, notGrowable);
8436
8437
FlushCandidate *flushCandidate;
8438
for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())
8439
{
8440
candidate = getCandidate(_candidates, flushCandidate);
8441
8442
if (!candidate)
8443
continue;
8444
8445
8446
//TR::Block *block = candidate->_block;
8447
//int32_t blockNum = block->getNumber();
8448
int32_t blockNum = flushCandidate->getBlockNum();
8449
8450
if (trace())
8451
traceMsg(comp, "\nConsidering Flush for allocation %p (index %d) in block_%d\n", candidate->_node, candidate->_index, blockNum);
8452
8453
TR_BitVector *successors = _successorInfo[blockNum];
8454
8455
if (trace())
8456
{
8457
traceMsg(comp, "Successors : \n");
8458
successors->print(comp);
8459
traceMsg(comp, "\n");
8460
}
8461
8462
TR_BitVectorIterator succIt(*successors);
8463
while (succIt.hasMoreElements())
8464
{
8465
int32_t nextSucc = succIt.getNextElement();
8466
TR_BitVector *succInfo = _blockAnalysisInfo[nextSucc];
8467
8468
*_scratch2 = *_loopEntryBlocks;
8469
*_scratch2 |= *_catchBlocks;
8470
8471
if (trace())
8472
traceMsg(comp, "Successor %d being examined\n", nextSucc);
8473
8474
if ((_blocksWithFlushes->get(nextSucc) ||
8475
_blocksWithSyncs->get(nextSucc)) &&
8476
succInfo &&
8477
succInfo->get(candidate->_index))
8478
{
8479
if (trace())
8480
traceMsg(comp, "Current allocation %d reaches successor %d\n", candidate->_index, nextSucc);
8481
8482
TR_BitVector *preds = _predecessorInfo[nextSucc];
8483
8484
if (trace())
8485
{
8486
traceMsg(comp, "Predecessors of next succ %d : \n", nextSucc);
8487
preds->print(comp);
8488
traceMsg(comp, "\n");
8489
}
8490
8491
*_scratch = *preds;
8492
*_scratch &= *successors;
8493
8494
if (_scratch2->get(nextSucc))
8495
continue;
8496
8497
*_scratch2 &= *_scratch;
8498
if (!_scratch2->isEmpty())
8499
continue;
8500
8501
_scratch->set(blockNum);
8502
8503
bool postDominated = true;
8504
TR::CFG *cfg = comp->getFlowGraph();
8505
TR::CFGNode *nextNode;
8506
for (nextNode = cfg->getFirstNode(); nextNode; nextNode = nextNode->getNext())
8507
{
8508
if (_scratch->get(nextNode->getNumber()))
8509
{
8510
for (auto succ = nextNode->getSuccessors().begin(); succ != nextNode->getSuccessors().end(); ++succ)
8511
{
8512
if (trace())
8513
traceMsg(comp, "Checking succ edge from %d to %d\n", nextNode->getNumber(), (*succ)->getTo()->getNumber());
8514
8515
if (!_scratch->get((*succ)->getTo()->getNumber()) &&
8516
((*succ)->getTo()->getNumber() != nextSucc))
8517
{
8518
postDominated = false;
8519
_flushEdges.add(new (trStackMemory()) TR_CFGEdgeAllocationPair(*succ, candidate));
8520
if (trace())
8521
traceMsg(comp, "Adding flush edge from %d to %d\n", nextNode->getNumber(), (*succ)->getTo()->getNumber());
8522
}
8523
}
8524
}
8525
}
8526
8527
if (trace())
8528
{
8529
traceMsg(comp, "Scratch : \n");
8530
_scratch->print(comp);
8531
traceMsg(comp, "\n");
8532
}
8533
8534
//if (postDominated)
8535
{
8536
if (trace())
8537
traceMsg(comp, "Current allocation %d is post dominated by allocation in successor %d\n", candidate->_index, nextSucc);
8538
8539
Candidate *succCandidate = NULL;
8540
FlushCandidate *succFlushCandidate = NULL;
8541
if (!_blocksWithSyncs->get(nextSucc))
8542
{
8543
for (succFlushCandidate = _flushCandidates->getFirst(); succFlushCandidate; succFlushCandidate = succFlushCandidate->getNext())
8544
//for (succCandidate = _candidates->getFirst(); succCandidate; succCandidate = succCandidate->getNext())
8545
{
8546
succCandidate = getCandidate(_candidates, succFlushCandidate);
8547
if (!succCandidate)
8548
continue;
8549
8550
//TR::Block *succBlock = succCandidate->_block;
8551
int32_t succBlockNum = succFlushCandidate->getBlockNum();
8552
8553
//if (trace())
8554
// traceMsg(comp, "succCandidate %p succCandidate num %d succCandidate Flush reqd %d succBlockNum %d\n", succCandidate, succCandidate->_index, succCandidate->_flushRequired, succBlockNum);
8555
8556
if ((succBlockNum == nextSucc) &&
8557
succCandidate->_flushRequired)
8558
{
8559
bool nextAllocCanReach = true;
8560
8561
ListIterator<Candidate> candIt(&candidate->_flushMovedFrom);
8562
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
8563
{
8564
if (!succInfo->get(dependentCandidate->_index))
8565
{
8566
nextAllocCanReach = false;
8567
break;
8568
}
8569
}
8570
8571
//if (trace())
8572
// traceMsg(comp, "succ candidate %p nextAllocCanReach %d\n", succCandidate, nextAllocCanReach);
8573
8574
if (nextAllocCanReach)
8575
{
8576
if (succCandidate != candidate)
8577
{
8578
succCandidate->_flushMovedFrom.add(candidate);
8579
ListIterator<Candidate> candIt(&candidate->_flushMovedFrom);
8580
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
8581
succCandidate->_flushMovedFrom.add(candidate);
8582
}
8583
break;
8584
}
8585
}
8586
}
8587
}
8588
8589
//if (trace())
8590
// traceMsg(comp, "succCandidate %p _blocksWithSyncs bit %d\n", succCandidate, _blocksWithSyncs->get(nextSucc));
8591
8592
if (_blocksWithSyncs->get(nextSucc) ||
8593
succCandidate)
8594
{
8595
movedToBlocks->set(nextSucc);
8596
candidate->_flushRequired = false;
8597
TR::TreeTop *flushTree = flushCandidate->getFlush();
8598
TR::TreeTop *prevTree = flushTree->getPrevTreeTop();
8599
TR::TreeTop *nextTree = flushTree->getNextTreeTop();
8600
if ((prevTree->getNextTreeTop() == flushTree) &&
8601
(nextTree->getPrevTreeTop() == flushTree))
8602
{
8603
if (flushTree->getNode()->getOpCodeValue() == TR::allocationFence)
8604
{
8605
flushTree->getNode()->setOmitSync(true);
8606
flushTree->getNode()->setAllocation(NULL);
8607
}
8608
//prevTree->join(nextTree);
8609
}
8610
8611
//if (trace())
8612
// {
8613
// traceMsg(comp, "0reaching candidate %p index %d does not need Flush\n", candidate, candidate->_index);
8614
// }
8615
8616
if (trace())
8617
{
8618
if (succCandidate)
8619
{
8620
traceMsg(comp, "Flush for current allocation %d is post dominated by (and moved to) Flush for allocation %d\n", candidate->_index, succCandidate->_index);
8621
//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());
8622
}
8623
else
8624
{
8625
traceMsg(comp, "Flush for current allocation %d is post dominated by (and moved to) real sync for in succ %d\n", candidate->_index, nextSucc);
8626
//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());
8627
}
8628
fflush(stdout);
8629
}
8630
//break;
8631
}
8632
}
8633
}
8634
}
8635
8636
ListElement<TR_CFGEdgeAllocationPair> *listElem;
8637
ListElement<TR_CFGEdgeAllocationPair> *nextListElem = NULL, *prevListElem = NULL;
8638
TR_CFGEdgeAllocationPair *pair = NULL;
8639
for (listElem = _flushEdges.getListHead(); listElem != NULL;)
8640
{
8641
nextListElem = listElem->getNextElement();
8642
TR_CFGEdgeAllocationPair *pair = listElem->getData();
8643
if (trace())
8644
{
8645
traceMsg(comp, "Processing flush edge from %d to %d\n", pair->getEdge()->getFrom()->getNumber(), pair->getEdge()->getTo()->getNumber());
8646
traceMsg(comp, "Processing flush alloc %p vs candidate %p\n", pair->getAllocation(), candidate);
8647
}
8648
8649
if (pair->getAllocation() == candidate)
8650
{
8651
bool edgeSplitRequired = true;
8652
int32_t toNum = pair->getEdge()->getTo()->getNumber();
8653
if (movedToBlocks->get(toNum))
8654
edgeSplitRequired = false;
8655
8656
if (!edgeSplitRequired)
8657
{
8658
if (prevListElem)
8659
prevListElem->setNextElement(nextListElem);
8660
else
8661
_flushEdges.setListHead(nextListElem);
8662
listElem = nextListElem;
8663
continue;
8664
}
8665
}
8666
8667
prevListElem = listElem;
8668
listElem = nextListElem;
8669
}
8670
}
8671
8672
8673
ListIterator<TR_CFGEdgeAllocationPair> pairIt(&_flushEdges);
8674
for (TR_CFGEdgeAllocationPair *pair = pairIt.getFirst(); pair; pair = pairIt.getNext())
8675
{
8676
TR::CFGNode *to = pair->getEdge()->getTo();
8677
TR::Block *splitBlock = NULL;
8678
if (to == comp->getFlowGraph()->getEnd())
8679
{
8680
splitBlock = toBlock(pair->getEdge()->getFrom());
8681
}
8682
else if ((to->getPredecessors().size() == 1))
8683
{
8684
splitBlock = toBlock(to);
8685
if (trace())
8686
{
8687
traceMsg(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);
8688
//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);
8689
}
8690
}
8691
else
8692
{
8693
splitBlock = findOrSplitEdge(toBlock(pair->getEdge()->getFrom()), toBlock(to));
8694
if (trace())
8695
{
8696
traceMsg(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);
8697
//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);
8698
}
8699
}
8700
8701
TR::Node *firstNode = splitBlock->getFirstRealTreeTop()->getNode();
8702
if (firstNode->getOpCodeValue() == TR::allocationFence)
8703
firstNode->setAllocation(NULL);
8704
else
8705
splitBlock->prepend(TR::TreeTop::create(comp, TR::Node::createAllocationFence(pair->getAllocation()->_node, pair->getAllocation()->_node), NULL, NULL));
8706
}
8707
8708
for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())
8709
{
8710
candidate = getCandidate(_candidates, flushCandidate);
8711
8712
if (!candidate)
8713
continue;
8714
8715
if (!candidate->_flushMovedFrom.isEmpty())
8716
{
8717
flushCandidate->getFlush()->getNode()->setAllocation(NULL);
8718
}
8719
}
8720
}
8721
8722
bool TR_FlowSensitiveEscapeAnalysis::postInitializationProcessing()
8723
{
8724
_blocksWithSyncs = new (trStackMemory()) TR_BitVector(_numberOfNodes, trMemory(), stackAlloc);
8725
int32_t blockNum = -1;
8726
TR::TreeTop *treeTop = NULL;
8727
for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())
8728
{
8729
TR::Node *node = treeTop->getNode();
8730
if (node->getOpCodeValue() == TR::BBStart)
8731
{
8732
blockNum = node->getBlock()->getNumber();
8733
continue;
8734
}
8735
8736
if ((node->getOpCodeValue() == TR::allocationFence) &&
8737
node->getAllocation())
8738
{
8739
FlushCandidate *candidate = new (trStackMemory()) FlushCandidate(treeTop, node->getAllocation(), blockNum);
8740
_flushCandidates->add(candidate);
8741
}
8742
8743
if (node->getOpCode().isNullCheck() ||
8744
node->getOpCode().isResolveCheck() ||
8745
(node->getOpCodeValue() == TR::treetop))
8746
node = node->getFirstChild();
8747
8748
if (node->getOpCodeValue() == TR::monent)
8749
{
8750
Candidate *candidate;
8751
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
8752
{
8753
if (_escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()) == _escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node))
8754
_newlyAllocatedObjectWasLocked = true;
8755
}
8756
}
8757
else if ((node->getOpCodeValue() == TR::monexit) ||
8758
(node->getOpCode().isCall() &&
8759
!node->hasUnresolvedSymbolReference() &&
8760
node->getSymbolReference()->getSymbol()->castToMethodSymbol()->isSynchronised()))
8761
{
8762
bool syncPresent = true;
8763
if (node->getOpCodeValue() == TR::monexit)
8764
{
8765
Candidate *candidate;
8766
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
8767
{
8768
if (_escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()) == _escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node))
8769
{
8770
syncPresent = false;
8771
break;
8772
}
8773
}
8774
}
8775
8776
if (syncPresent)
8777
_blocksWithSyncs->set(blockNum);
8778
}
8779
}
8780
8781
int32_t i;
8782
8783
if (!_newlyAllocatedObjectWasLocked &&
8784
_flushCandidates->isEmpty())
8785
{
8786
return false;
8787
}
8788
8789
_blocksWithFlushes = new (trStackMemory()) TR_BitVector(_numberOfNodes, trMemory(), stackAlloc);
8790
FlushCandidate *flushCandidate;
8791
for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())
8792
_blocksWithFlushes->set(flushCandidate->getBlockNum());
8793
8794
//_blocksThatNeedFlush = new (trStackMemory()) TR_BitVector(_numberOfNodes, trMemory(), stackAlloc, growable);
8795
return true;
8796
}
8797
8798
8799
TR::Block *TR_FlowSensitiveEscapeAnalysis::findOrSplitEdge(TR::Block *from, TR::Block *to)
8800
{
8801
TR::Block *splitBlock = NULL;
8802
if (!from->hasSuccessor(to))
8803
{
8804
for (auto edge2 = to->getPredecessors().begin(); edge2 != to->getPredecessors().end(); ++edge2)
8805
{
8806
if (_splitBlocks.find((*edge2)->getFrom()) &&
8807
from->hasSuccessor((*edge2)->getFrom()))
8808
{
8809
splitBlock = toBlock((*edge2)->getFrom());
8810
break;
8811
}
8812
}
8813
}
8814
else
8815
{
8816
splitBlock = from->splitEdge(from, to, comp());
8817
_splitBlocks.add(splitBlock);
8818
}
8819
8820
return splitBlock;
8821
}
8822
8823
8824
8825
8826
void TR_FlowSensitiveEscapeAnalysis::analyzeTreeTopsInBlockStructure(TR_BlockStructure *blockStructure)
8827
{
8828
TR::Block *block = blockStructure->getBlock();
8829
if ((block == comp()->getFlowGraph()->getStart()) ||
8830
(block == comp()->getFlowGraph()->getEnd()))
8831
return;
8832
8833
int32_t blockNum = block->getNumber();
8834
bool seenException = false;
8835
8836
comp()->incVisitCount(); //@TODO: slightly untrivial as it requires either a change to API (i.e. analyzeNode)
8837
//or an extra field needs to be declared in TR_FlowSensitiveEscapeAnalysis
8838
//so let's leave this use as is for the next iteration
8839
TR::TreeTop *lastTree = block->getExit()->getNextTreeTop();
8840
for (TR::TreeTop *treeTop = block->getEntry(); treeTop != lastTree; treeTop = treeTop->getNextTreeTop())
8841
{
8842
TR::Node *node = treeTop->getNode();
8843
8844
if (node->getOpCodeValue() == TR::BBStart)
8845
continue;
8846
8847
#if DEBUG
8848
if (node->getOpCodeValue() == TR::BBEnd && trace())
8849
{
8850
traceMsg(comp(), "\n Block %d:\n", blockNum);
8851
traceMsg(comp(), " Normal set ");
8852
if (_regularInfo)
8853
_regularInfo->print(comp());
8854
else
8855
traceMsg(comp(), "{}");
8856
traceMsg(comp(), "\n Exception set ");
8857
if (_exceptionInfo)
8858
_exceptionInfo->print(comp());
8859
else
8860
traceMsg(comp(), "{}");
8861
}
8862
#endif
8863
8864
analyzeNode(node, seenException, blockNum, NULL);
8865
8866
if (!seenException && treeHasChecks(treeTop))
8867
seenException = true;
8868
}
8869
copyFromInto(_regularInfo, _blockAnalysisInfo[blockStructure->getNumber()]);
8870
}
8871
8872
8873
void TR_FlowSensitiveEscapeAnalysis::analyzeNode(TR::Node *node, bool seenException, int32_t blockNum, TR::Node *parent)
8874
{
8875
// Update gen and kill info for nodes in this subtree
8876
//
8877
int32_t i;
8878
8879
if (node->getVisitCount() == comp()->getVisitCount())
8880
return;
8881
node->setVisitCount(comp()->getVisitCount());
8882
8883
// Process the children first
8884
//
8885
for (i = node->getNumChildren()-1; i >= 0; --i)
8886
{
8887
analyzeNode(node->getChild(i), seenException, blockNum, node);
8888
}
8889
8890
8891
TR::ILOpCode &opCode = node->getOpCode();
8892
if (opCode.hasSymbolReference())
8893
{
8894
TR::SymbolReference *symReference = node->getSymbolReference();
8895
if (symReference->getSymbol()->isVolatile())
8896
_blocksWithSyncs->set(blockNum);
8897
}
8898
8899
//traceMsg(comp(), "Node %p is being examined\n", node);
8900
8901
TR_EscapeAnalysis *escapeAnalysis = _escapeAnalysis;
8902
if (!node->getOpCode().isCall())
8903
{
8904
int32_t valueNumber = 0;
8905
Candidate *candidate = NULL;
8906
TR::Node *child = NULL;
8907
TR_DependentAllocations *dependencies = NULL;
8908
8909
if ((node->getOpCodeValue() == TR::areturn) ||
8910
(node->getOpCodeValue() == TR::athrow))
8911
child = node->getFirstChild();
8912
else if (node->getOpCode().isStoreIndirect())
8913
{
8914
child = node->getSecondChild();
8915
8916
TR::Node *base = node->getFirstChild();
8917
int32_t baseValueNumber = escapeAnalysis->_valueNumberInfo->getValueNumber(base);
8918
Candidate *candidate;
8919
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
8920
{
8921
if (escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node) == baseValueNumber)
8922
{
8923
if (_regularInfo->get(candidate->_index))
8924
{
8925
//child = NULL;
8926
dependencies = getDependentAllocationsFor(candidate, &(_escapeAnalysis->_dependentAllocations));
8927
if (!dependencies)
8928
{
8929
dependencies = new (trStackMemory()) TR_DependentAllocations(candidate, 0, trMemory());
8930
_escapeAnalysis->_dependentAllocations.add(dependencies);
8931
}
8932
}
8933
break;
8934
}
8935
}
8936
}
8937
else if (node->getOpCode().isStore() &&
8938
node->getSymbolReference()->getSymbol()->isStatic())
8939
child = node->getFirstChild();
8940
8941
if (child)
8942
{
8943
// If we are in a called method, returning a candidate to the caller
8944
// escapes, since we don't track what happens to the returned value.
8945
//
8946
valueNumber = escapeAnalysis->_valueNumberInfo->getValueNumber(child);
8947
}
8948
8949
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
8950
{
8951
if (child &&
8952
escapeAnalysis->usesValueNumber(candidate, valueNumber))
8953
{
8954
if (!dependencies)
8955
{
8956
_regularInfo->reset(candidate->_index);
8957
if (seenException)
8958
_exceptionInfo->reset(candidate->_index);
8959
8960
TR_DependentAllocations *deps = getDependentAllocationsFor(candidate, &(escapeAnalysis->_dependentAllocations));
8961
if (deps)
8962
{
8963
ListIterator<Candidate> candIt(deps->getDependentAllocations());
8964
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
8965
{
8966
_regularInfo->reset(dependentCandidate->_index);
8967
if (seenException)
8968
_exceptionInfo->reset(dependentCandidate->_index);
8969
}
8970
}
8971
}
8972
else
8973
dependencies->addDependentAllocation(candidate);
8974
}
8975
8976
if (node == candidate->_node)
8977
{
8978
_regularInfo->set(candidate->_index);
8979
if (!seenException)
8980
_exceptionInfo->set(candidate->_index);
8981
}
8982
}
8983
}
8984
else
8985
{
8986
int32_t firstArgIndex = node->getFirstArgumentIndex();
8987
for (int32_t arg = firstArgIndex; arg < node->getNumChildren(); arg++)
8988
{
8989
TR::Node *child = node->getChild(arg);
8990
int32_t valueNumber = escapeAnalysis->_valueNumberInfo->getValueNumber(child);
8991
Candidate *candidate;
8992
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
8993
{
8994
if (escapeAnalysis->usesValueNumber(candidate, valueNumber))
8995
{
8996
_regularInfo->reset(candidate->_index);
8997
if (seenException)
8998
_exceptionInfo->reset(candidate->_index);
8999
9000
TR_DependentAllocations *deps = getDependentAllocationsFor(candidate, &(escapeAnalysis->_dependentAllocations));
9001
if (deps)
9002
{
9003
ListIterator<Candidate> candIt(deps->getDependentAllocations());
9004
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
9005
{
9006
_regularInfo->reset(dependentCandidate->_index);
9007
if (seenException)
9008
_exceptionInfo->reset(dependentCandidate->_index);
9009
}
9010
}
9011
}
9012
}
9013
}
9014
}
9015
}
9016
9017
9018
9019
TR_LocalFlushElimination::TR_LocalFlushElimination(TR_EscapeAnalysis *escapeAnalysis, int32_t numAllocations)
9020
: _dependentAllocations(escapeAnalysis->trMemory())
9021
{
9022
_escapeAnalysis = escapeAnalysis;
9023
_numAllocations = numAllocations;
9024
}
9025
9026
int32_t TR_LocalFlushElimination::perform()
9027
{
9028
if (_escapeAnalysis)
9029
_candidates = &(_escapeAnalysis->_candidates);
9030
else
9031
{
9032
_candidates = new (trStackMemory()) TR_LinkHead<Candidate>;
9033
_numAllocations = -1;
9034
}
9035
9036
_flushCandidates = new (trStackMemory()) TR_LinkHead<FlushCandidate>;
9037
_flushCandidates->setFirst(NULL);
9038
9039
TR::NodeChecklist visited(comp());
9040
TR::TreeTop *treeTop;
9041
TR::Block *block = NULL;
9042
_dependentAllocations.deleteAll();
9043
9044
if (_numAllocations < 0)
9045
{
9046
_numAllocations = 0;
9047
for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextRealTreeTop())
9048
{
9049
// Get information about this block
9050
//
9051
TR::Node *node = treeTop->getNode();
9052
if (node->getOpCodeValue() == TR::BBStart)
9053
block = node->getBlock();
9054
9055
if ((node->getOpCodeValue() == TR::treetop) &&
9056
((node->getFirstChild()->getOpCodeValue() == TR::New) ||
9057
(node->getFirstChild()->getOpCodeValue() == TR::newarray) ||
9058
(node->getFirstChild()->getOpCodeValue() == TR::anewarray)))
9059
{
9060
Candidate *candidate = new (trStackMemory()) Candidate(node, treeTop, block, -1, NULL, comp());
9061
_candidates->add(candidate);
9062
candidate->_index = _numAllocations++;
9063
}
9064
}
9065
}
9066
9067
_allocationInfo = new (trStackMemory()) TR_BitVector(_numAllocations, trMemory(), stackAlloc);
9068
_temp = new (trStackMemory()) TR_BitVector(_numAllocations, trMemory(), stackAlloc);
9069
9070
for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextRealTreeTop())
9071
{
9072
// Get information about this block
9073
//
9074
TR::Node *node = treeTop->getNode();
9075
if (node->getOpCodeValue() == TR::BBStart)
9076
block = node->getBlock();
9077
9078
if ((node->getOpCodeValue() == TR::allocationFence) &&
9079
node->getAllocation())
9080
{
9081
FlushCandidate *candidate = new (trStackMemory()) FlushCandidate(treeTop, node->getAllocation(), block->getNumber());
9082
_flushCandidates->add(candidate);
9083
}
9084
}
9085
9086
// Process each block in treetop order
9087
//
9088
for (treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextRealTreeTop())
9089
{
9090
// Get information about this block
9091
//
9092
TR::Node *node = treeTop->getNode();
9093
if (node->getOpCodeValue() == TR::BBStart)
9094
{
9095
block = node->getBlock();
9096
_allocationInfo->empty();
9097
}
9098
9099
examineNode(node, visited);
9100
}
9101
9102
FlushCandidate *flushCandidate;
9103
for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())
9104
{
9105
Candidate *candidate = getCandidate(_candidates, flushCandidate);
9106
9107
if (!candidate)
9108
continue;
9109
9110
if (!candidate->_flushMovedFrom.isEmpty())
9111
{
9112
flushCandidate->getFlush()->getNode()->setAllocation(NULL);
9113
}
9114
}
9115
9116
return 1; // actual cost
9117
}
9118
9119
9120
bool TR_LocalFlushElimination::examineNode(TR::Node *node, TR::NodeChecklist& visited)
9121
{
9122
if (visited.contains(node))
9123
return true;
9124
visited.add(node);
9125
9126
TR::ILOpCode &opCode = node->getOpCode();
9127
9128
if (!opCode.isCall())
9129
{
9130
int32_t valueNumber = -1;
9131
Candidate *candidate;
9132
TR::Node *child = NULL;
9133
TR_DependentAllocations *dependencies = NULL;
9134
if ((node->getOpCodeValue() == TR::areturn) ||
9135
(node->getOpCodeValue() == TR::athrow))
9136
child = node->getFirstChild();
9137
else if (node->getOpCode().isStoreIndirect())
9138
{
9139
child = node->getSecondChild();
9140
9141
TR::Node *base = node->getFirstChild();
9142
9143
//if (_escapeAnalysis)
9144
{
9145
int32_t baseValueNumber = -1;
9146
if (_escapeAnalysis)
9147
baseValueNumber = _escapeAnalysis->_valueNumberInfo->getValueNumber(base);
9148
Candidate *candidate;
9149
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
9150
{
9151
if ((_escapeAnalysis &&
9152
(_escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node) == baseValueNumber)) ||
9153
!_escapeAnalysis)
9154
{
9155
if (_allocationInfo->get(candidate->_index))
9156
{
9157
TR_ScratchList<TR_DependentAllocations> *list = NULL;
9158
if (_escapeAnalysis)
9159
list = &(_escapeAnalysis->_dependentAllocations);
9160
else
9161
list = &_dependentAllocations;
9162
dependencies = getDependentAllocationsFor(candidate, list);
9163
if (!dependencies)
9164
{
9165
dependencies = new (trStackMemory()) TR_DependentAllocations(candidate, 0, trMemory());
9166
list->add(dependencies);
9167
}
9168
}
9169
//child = NULL;
9170
break;
9171
}
9172
}
9173
}
9174
}
9175
else if (node->getOpCode().isStore() &&
9176
node->getSymbolReference()->getSymbol()->isStatic())
9177
child = node->getFirstChild();
9178
9179
9180
if (_escapeAnalysis)
9181
{
9182
if (child)
9183
{
9184
// If we are in a called method, returning a candidate to the caller
9185
// escapes, since we don't track what happens to the returned value.
9186
//
9187
valueNumber = _escapeAnalysis->_valueNumberInfo->getValueNumber(child);
9188
}
9189
}
9190
9191
bool nodeHasSync = false;
9192
if (node->getOpCodeValue() == TR::monexit)
9193
{
9194
bool syncPresent = true;
9195
if (_escapeAnalysis)
9196
{
9197
Candidate *candidate;
9198
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
9199
{
9200
if (_escapeAnalysis->_valueNumberInfo->getValueNumber(node->getFirstChild()) == _escapeAnalysis->_valueNumberInfo->getValueNumber(candidate->_node))
9201
{
9202
syncPresent = false;
9203
break;
9204
}
9205
}
9206
}
9207
9208
if (syncPresent)
9209
nodeHasSync = true;
9210
}
9211
else
9212
{
9213
TR::ILOpCode &opCode = node->getOpCode();
9214
if (opCode.hasSymbolReference())
9215
{
9216
TR::SymbolReference *symReference = node->getSymbolReference();
9217
if (symReference->getSymbol()->isVolatile())
9218
nodeHasSync = true;
9219
}
9220
9221
if (opCode.isCall() &&
9222
!node->hasUnresolvedSymbolReference() &&
9223
node->getSymbolReference()->getSymbol()->castToMethodSymbol()->isSynchronised())
9224
nodeHasSync = true;
9225
}
9226
9227
bool notAnalyzedSync = true;
9228
FlushCandidate *flushCandidate;
9229
for (flushCandidate = _flushCandidates->getFirst(); flushCandidate; flushCandidate = flushCandidate->getNext())
9230
//for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
9231
{
9232
candidate = getCandidate(_candidates, flushCandidate);
9233
if (!candidate)
9234
continue;
9235
9236
if (child &&
9237
((_escapeAnalysis &&
9238
_escapeAnalysis->usesValueNumber(candidate, valueNumber)) ||
9239
!_escapeAnalysis))
9240
{
9241
if (!dependencies)
9242
{
9243
_allocationInfo->reset(candidate->_index);
9244
TR_DependentAllocations *deps = NULL;
9245
if (_escapeAnalysis)
9246
deps = getDependentAllocationsFor(candidate, &(_escapeAnalysis->_dependentAllocations));
9247
else
9248
deps = getDependentAllocationsFor(candidate, &_dependentAllocations);
9249
9250
if (deps)
9251
{
9252
ListIterator<Candidate> candIt(deps->getDependentAllocations());
9253
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
9254
_allocationInfo->reset(dependentCandidate->_index);
9255
}
9256
}
9257
else
9258
dependencies->addDependentAllocation(candidate);
9259
}
9260
9261
if (((node == flushCandidate->getFlush()->getNode()) &&
9262
candidate->_flushRequired) ||
9263
(nodeHasSync &&
9264
notAnalyzedSync))
9265
{
9266
notAnalyzedSync = false;
9267
if (trace())
9268
{
9269
traceMsg(comp(), "\nConsidering Flush for allocation %p (index %d)\n", candidate->_node, candidate->_index);
9270
traceMsg(comp(), "Allocation info at this stage : \n");
9271
_allocationInfo->print(comp());
9272
traceMsg(comp(), "\n");
9273
}
9274
9275
_temp->empty();
9276
TR_BitVectorIterator allocIt(*_allocationInfo);
9277
while (allocIt.hasMoreElements())
9278
{
9279
int32_t nextAlloc = allocIt.getNextElement();
9280
//if (nextAlloc == candidate->_index)
9281
// continue;
9282
9283
//if (trace())
9284
// {
9285
// traceMsg(comp(), "nextAlloc %d\n", nextAlloc);
9286
// printf("nextAlloc %d\n", nextAlloc);
9287
// fflush(stdout);
9288
// }
9289
9290
bool nextAllocCanReach = true;
9291
Candidate *reachingCandidate = NULL;
9292
FlushCandidate *reachingFlushCandidate = NULL;
9293
for (reachingFlushCandidate = _flushCandidates->getFirst(); reachingFlushCandidate; reachingFlushCandidate = reachingFlushCandidate->getNext())
9294
//for (reachingCandidate = _candidates->getFirst(); reachingCandidate; reachingCandidate = reachingCandidate->getNext())
9295
{
9296
reachingCandidate = getCandidate(_candidates, reachingFlushCandidate);
9297
if (!reachingCandidate)
9298
continue;
9299
9300
if ((reachingCandidate->_index == nextAlloc) &&
9301
(reachingFlushCandidate != flushCandidate) &&
9302
reachingFlushCandidate->getFlush() &&
9303
visited.contains(reachingFlushCandidate->getFlush()->getNode()))
9304
{
9305
ListIterator<Candidate> candIt(&reachingCandidate->_flushMovedFrom);
9306
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
9307
{
9308
if (!_allocationInfo->get(dependentCandidate->_index))
9309
{
9310
nextAllocCanReach = false;
9311
break;
9312
}
9313
}
9314
break;
9315
}
9316
}
9317
9318
if (!reachingFlushCandidate || !reachingCandidate)
9319
continue;
9320
9321
if (nextAllocCanReach)
9322
{
9323
reachingCandidate->_flushRequired = false;
9324
9325
TR::TreeTop *flushTree = reachingFlushCandidate->getFlush();
9326
TR::TreeTop *prevTree = flushTree->getPrevTreeTop();
9327
TR::TreeTop *nextTree = flushTree->getNextTreeTop();
9328
if ((prevTree->getNextTreeTop() == flushTree) &&
9329
(nextTree->getPrevTreeTop() == flushTree))
9330
{
9331
if (flushTree->getNode()->getOpCodeValue() == TR::allocationFence)
9332
{
9333
flushTree->getNode()->setOmitSync(true);
9334
flushTree->getNode()->setAllocation(NULL);
9335
}
9336
//prevTree->join(nextTree);
9337
}
9338
9339
//if (trace())
9340
// {
9341
// traceMsg(comp(), "1reaching candidate %p index %d does not need Flush\n", reachingCandidate, reachingCandidate->_index);
9342
// }
9343
9344
if (!nodeHasSync)
9345
{
9346
if (reachingCandidate != candidate)
9347
{
9348
if (!_temp->get(reachingCandidate->_index))
9349
{
9350
_temp->set(reachingCandidate->_index);
9351
candidate->_flushMovedFrom.add(reachingCandidate);
9352
}
9353
9354
ListIterator<Candidate> candIt(&reachingCandidate->_flushMovedFrom);
9355
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
9356
{
9357
if (!_temp->get(dependentCandidate->_index))
9358
{
9359
_temp->set(dependentCandidate->_index);
9360
candidate->_flushMovedFrom.add(dependentCandidate);
9361
}
9362
}
9363
}
9364
}
9365
9366
if (trace())
9367
{
9368
if (!nodeHasSync)
9369
{
9370
traceMsg(comp(), "Flush for current allocation %d is post dominated by (and moved to) Flush for allocation %d\n", reachingCandidate->_index, candidate->_index);
9371
//printf("Moved flush for allocation %p to allocation %p locally in method %s\n", reachingCandidate->_node, candidate->_node, comp()->signature());
9372
}
9373
else
9374
{
9375
traceMsg(comp(), "Flush for current allocation %d is post dominated by (and moved to) sync in the same block\n", reachingCandidate->_index);
9376
//printf("Moved flush for allocation %p to real sync node %p locally in method %s\n", reachingCandidate->_node, node, comp()->signature());
9377
}
9378
9379
fflush(stdout);
9380
}
9381
}
9382
}
9383
9384
if (!nodeHasSync)
9385
_allocationInfo->set(candidate->_index);
9386
}
9387
9388
//if (node == candidate->_node)
9389
// _allocationInfo->set(candidate->_index);
9390
}
9391
}
9392
else
9393
{
9394
//if (_escapeAnalysis)
9395
{
9396
int32_t firstArgIndex = node->getFirstArgumentIndex();
9397
for (int32_t arg = firstArgIndex; arg < node->getNumChildren(); arg++)
9398
{
9399
TR::Node *child = node->getChild(arg);
9400
int32_t valueNumber = -1;
9401
if (_escapeAnalysis)
9402
valueNumber = _escapeAnalysis->_valueNumberInfo->getValueNumber(child);
9403
Candidate *candidate;
9404
for (candidate = _candidates->getFirst(); candidate; candidate = candidate->getNext())
9405
{
9406
if ((_escapeAnalysis &&
9407
_escapeAnalysis->usesValueNumber(candidate, valueNumber)) ||
9408
!_escapeAnalysis)
9409
{
9410
_allocationInfo->reset(candidate->_index);
9411
9412
TR_DependentAllocations *deps = NULL;
9413
if (_escapeAnalysis)
9414
deps = getDependentAllocationsFor(candidate, &(_escapeAnalysis->_dependentAllocations));
9415
else
9416
deps = getDependentAllocationsFor(candidate, &_dependentAllocations);
9417
9418
if (deps)
9419
{
9420
ListIterator<Candidate> candIt(deps->getDependentAllocations());
9421
for (Candidate *dependentCandidate = candIt.getFirst(); dependentCandidate; dependentCandidate = candIt.getNext())
9422
_allocationInfo->reset(dependentCandidate->_index);
9423
}
9424
}
9425
}
9426
}
9427
}
9428
}
9429
9430
int32_t i = 0;
9431
for (i = 0; i < node->getNumChildren(); i++)
9432
{
9433
TR::Node *child = node->getChild(i);
9434
9435
if (!examineNode(child, visited))
9436
return false;
9437
}
9438
9439
return true;
9440
}
9441
9442