-
Notifications
You must be signed in to change notification settings - Fork 747
/
Copy pathLiveVariablesForGC.cpp
295 lines (263 loc) · 11.1 KB
/
LiveVariablesForGC.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/*******************************************************************************
* Copyright IBM Corp. and others 2000
*
* This program and the accompanying materials are made available under
* the terms of the Eclipse Public License 2.0 which accompanies this
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
* or the Apache License, Version 2.0 which accompanies this distribution and
* is available at https://www.apache.org/licenses/LICENSE-2.0.
*
* This Source Code may also be made available under the following
* Secondary Licenses when the conditions for such availability set
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
* General Public License, version 2 with the GNU Classpath
* Exception [1] and GNU General Public License, version 2 with the
* OpenJDK Assembly Exception [2].
*
* [1] https://www.gnu.org/software/classpath/license.html
* [2] https://openjdk.org/legal/assembly-exception.html
*
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
*******************************************************************************/
#include "optimizer/LiveVariablesForGC.hpp"
#include <stddef.h>
#include "codegen/CodeGenerator.hpp"
#include "compile/Compilation.hpp"
#include "compile/OSRData.hpp"
#include "control/Options.hpp"
#include "control/Options_inlines.hpp"
#include "env/StackMemoryRegion.hpp"
#include "env/TRMemory.hpp"
#include "il/AutomaticSymbol.hpp"
#include "il/Block.hpp"
#include "il/ILOpCodes.hpp"
#include "il/Node.hpp"
#include "il/ResolvedMethodSymbol.hpp"
#include "il/Symbol.hpp"
#include "il/SymbolReference.hpp"
#include "il/TreeTop.hpp"
#include "il/TreeTop_inlines.hpp"
#include "infra/BitVector.hpp"
#include "infra/Cfg.hpp"
#include "infra/List.hpp"
#include "infra/TRCfgEdge.hpp"
#include "infra/TRCfgNode.hpp"
#include "optimizer/Optimization.hpp"
#include "optimizer/DataFlowAnalysis.hpp"
// Local live variables for GC
//
// Determine which locals containing collected references need to be initialized
// during the method prologue.
#define OPT_DETAILS "O^O LIVE VARIABLES FOR GC: "
TR_LocalLiveVariablesForGC::TR_LocalLiveVariablesForGC(TR::OptimizationManager *manager)
: TR::Optimization(manager)
{}
int32_t TR_LocalLiveVariablesForGC::perform()
{
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
// The CFG is followed to the first GC point on each path. Any locals that can
// reach a GC point without being initialized must be initialized to NULL during
// the prologue of the method.
//
// Assign an index to each local that is a collected reference
//
_numLocals = 0;
TR::AutomaticSymbol *p;
ListIterator<TR::AutomaticSymbol> locals(&comp()->getMethodSymbol()->getAutomaticList());
for (p = locals.getFirst(); p != NULL; p = locals.getNext())
{
if (p->isCollectedReference())
{
if (debug("traceGCRefs"))
dumpOptDetails(comp(), "Local #%2d is symbol at 0x%p\n",_numLocals,p);
p->setLiveLocalIndex(_numLocals++, fe());
}
}
if (_numLocals == 0)
{
return 0; // actual cost
}
comp()->incVisitCount();
TR_BitVector localsToBeInitialized(_numLocals,trMemory(), stackAlloc);
localsToBeInitialized.setAll(_numLocals);
findGCPointInBlock(toBlock(comp()->getFlowGraph()->getStart()), localsToBeInitialized);
// If any locals were initialized at all GC points, mark their symbols as
// being initialized; they need not be initialized during method prologue.
//
locals.reset();
for (p = locals.getFirst(); p != NULL; p = locals.getNext())
{
if (p->isCollectedReference() &&
(!comp()->getOption(TR_MimicInterpreterFrameShape) ||
!comp()->areSlotsSharedByRefAndNonRef() ||
p->isSlotSharedByRefAndNonRef()) &&
!localsToBeInitialized.get(p->getLiveLocalIndex()))
{
if (performTransformation(comp(), "%sRemoving prologue initialization of local [%p]\n", OPT_DETAILS, p))
p->setInitializedReference();
}
}
return 1; // actual cost
}
const char *
TR_LocalLiveVariablesForGC::optDetailString() const throw()
{
return "O^O LOCAL LIVE VARIABLES FOR GC: ";
}
void TR_LocalLiveVariablesForGC::findGCPointInBlock(TR::Block *block, TR_BitVector &localsToBeInitialized)
{
if (block->getVisitCount() == comp()->getVisitCount())
return;
block->setVisitCount(comp()->getVisitCount());
for (TR::TreeTop *treeTop = block->getEntry(); treeTop != block->getExit(); treeTop = treeTop->getNextTreeTop())
{
TR::Node *node = treeTop->getNode();
if (node->canCauseGC())
{
// The state of the locals at this GC safe point represents the state
// for all successors too.
//
return;
}
if (node->getOpCodeValue() == TR::astore)
{
TR::AutomaticSymbol *local = node->getSymbolReference()->getSymbol()->getAutoSymbol();
if (local && local->isCollectedReference())
localsToBeInitialized.reset(local->getLiveLocalIndex());
}
}
// If we have reached the end of the block without finding a GC safe point,
// visit the successors.
//
TR_BitVector myLocalsToBeInitialized(_numLocals,trMemory(), stackAlloc);
TR_BitVector succLocalsToBeInitialized(_numLocals,trMemory(), stackAlloc);
for (auto succ = block->getSuccessors().begin(); succ != block->getSuccessors().end(); ++succ)
{
succLocalsToBeInitialized = localsToBeInitialized;
findGCPointInBlock(toBlock((*succ)->getTo()),succLocalsToBeInitialized);
myLocalsToBeInitialized |= succLocalsToBeInitialized;
if (myLocalsToBeInitialized == localsToBeInitialized)
return; // Nothing more to be discovered
}
for (auto succ = block->getExceptionSuccessors().begin(); succ != block->getExceptionSuccessors().end(); ++succ)
{
succLocalsToBeInitialized = localsToBeInitialized;
findGCPointInBlock(toBlock((*succ)->getTo()),succLocalsToBeInitialized);
myLocalsToBeInitialized |= succLocalsToBeInitialized;
if (myLocalsToBeInitialized == localsToBeInitialized)
return; // Nothing more to be discovered
}
localsToBeInitialized = myLocalsToBeInitialized;
}
// Global live variables for GC
//
// Determine which locals are live at the start of each basic block. This will be
// used by code generation to build GC stack maps.
TR_GlobalLiveVariablesForGC::TR_GlobalLiveVariablesForGC(TR::OptimizationManager *manager)
: TR::Optimization(manager)
{}
int32_t TR_GlobalLiveVariablesForGC::perform()
{
if (comp()->getOption(TR_MimicInterpreterFrameShape) && !comp()->areSlotsSharedByRefAndNonRef())
{
return 0;
}
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
// Temporary until register maps are implemented - spill temps must be
// included in the liveness analysis.
//
if (!comp()->useRegisterMaps())
{
cg()->lowerTrees();
cg()->findAndFixCommonedReferences();
}
// Because only live locals are mapped for GC, there is normally no need to
// make sure locals are cleared to NULL during method prologue.
// However, we can have cases where GC-collected locals are live at the start
// of the method. These locals will have to be cleared to NULL during method
// prologue.
// This can happen because of the way we treat non-inlined jsrs.
//
int32_t numLocals = 0;
TR::AutomaticSymbol *p;
ListIterator<TR::AutomaticSymbol> locals(&comp()->getMethodSymbol()->getAutomaticList());
for (p = locals.getFirst(); p != NULL; p = locals.getNext())
{
// Mark collected locals as initialized. We will reset this property for
// any locals that are live at the start of the method.
//
if (p->isCollectedReference() &&
(!comp()->getOption(TR_MimicInterpreterFrameShape) ||
!comp()->areSlotsSharedByRefAndNonRef() ||
p->isSlotSharedByRefAndNonRef()))
p->setInitializedReference();
++numLocals;
}
if (comp()->getOption(TR_EnableAggressiveLiveness))
{
TR::ParameterSymbol *pp;
ListIterator<TR::ParameterSymbol> parms(&comp()->getMethodSymbol()->getParameterList());
for (pp = parms.getFirst(); pp != NULL; pp = parms.getNext())
++numLocals;
}
// Nothing to do if there are no locals
//
if (numLocals == 0)
{
return 0; // actual cost
}
TR_BitVector *liveVars = NULL;
if ((comp()->getOption(TR_EnableOSR) && (comp()->getHCRMode() == TR::osr || comp()->getOption(TR_FullSpeedDebug))) || !cg()->getLiveLocals()) // under OSR existing live locals is likely computed without ignoring OSR uses
{
// Perform liveness analysis
//
bool ignoreOSRuses = false; // Used to be set to true but we cannot set this to true because a variable may not be live in compiled code but may still be needed (live) in the interpreter
/* for mimicInterpreterShape, because OSR points can extend the live range of autos
* autos sharing the same slot in interpreter might end up with overlapped
* live range if OSRUses are not ignored
*/
if (comp()->getOption(TR_MimicInterpreterFrameShape))
ignoreOSRuses = true;
TR_Liveness *liveLocals = new (stackMemoryRegion) TR_Liveness(comp(), optimizer(), comp()->getFlowGraph()->getStructure(), ignoreOSRuses, NULL, false, comp()->getOption(TR_EnableAggressiveLiveness));
liveLocals->perform(comp()->getFlowGraph()->getStructure());
for (TR::CFGNode *cfgNode = comp()->getFlowGraph()->getFirstNode(); cfgNode; cfgNode = cfgNode->getNext())
{
TR::Block *block = toBlock(cfgNode);
int32_t blockNum = block->getNumber();
if (blockNum > 0 && liveLocals->_blockAnalysisInfo[blockNum])
{
liveVars = new (trHeapMemory()) TR_BitVector(numLocals, trMemory());
*liveVars = *(liveLocals->_blockAnalysisInfo[blockNum]);
block->setLiveLocals(liveVars);
}
}
// Make sure the code generator knows there are live locals for blocks, and
// create a bit vector of the correct size for it.
//
liveVars = new (trHeapMemory()) TR_BitVector(numLocals, trMemory());
cg()->setLiveLocals(liveVars);
}
// See if any collected reference locals are live at the start of the block.
// These will need to be initialized at method prologue.
//
liveVars = comp()->getStartBlock()->getLiveLocals();
if (liveVars && !liveVars->isEmpty())
{
locals.reset();
for (p = locals.getFirst(); p != NULL; p = locals.getNext())
{
if (p->isCollectedReference() &&
liveVars->get(p->getLiveLocalIndex()))
{
if (performTransformation(comp(), "%s Local #%d is live at the start of the method\n",OPT_DETAILS, p->getLiveLocalIndex()))
p->setUninitializedReference();
}
}
}
return 10; // actual cost
}
const char *
TR_GlobalLiveVariablesForGC::optDetailString() const throw()
{
return "O^O GLOBAL LIVE VARIABLES FOR GC: ";
}