Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/HCRGuardAnalysis.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2019 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
#include <stddef.h>
23
#include <stdint.h>
24
#include "optimizer/HCRGuardAnalysis.hpp"
25
#include "env/StackMemoryRegion.hpp"
26
#include "codegen/CodeGenerator.hpp"
27
#include "compile/Compilation.hpp"
28
#include "control/Options.hpp"
29
#include "control/Options_inlines.hpp"
30
#include "env/TRMemory.hpp"
31
#include "il/Node.hpp"
32
#include "il/Node_inlines.hpp"
33
#include "infra/Assert.hpp"
34
#include "infra/BitVector.hpp"
35
#include "infra/Checklist.hpp"
36
#include "optimizer/FearPointAnalysis.hpp"
37
38
static bool containsPrepareForOSR(TR::Block *block)
39
{
40
for (TR::TreeTop *tt = block->getEntry(); tt != block->getExit(); tt = tt->getNextTreeTop())
41
{
42
if (tt->getNode()->getOpCode().isCheck() || tt->getNode()->getOpCodeValue() == TR::treetop)
43
{
44
if (tt->getNode()->getFirstChild()->getOpCode().isCall()
45
&& tt->getNode()->getFirstChild()->getSymbolReference()->getReferenceNumber() == TR_prepareForOSR)
46
return true;
47
}
48
}
49
return false;
50
}
51
52
int32_t TR_HCRGuardAnalysis::getNumberOfBits() { return 1; }
53
54
bool TR_HCRGuardAnalysis::supportsGenAndKillSets() { return true; }
55
56
TR_DataFlowAnalysis::Kind TR_HCRGuardAnalysis::getKind() { return HCRGuardAnalysis; }
57
58
void TR_HCRGuardAnalysis::analyzeNode(TR::Node *node, vcount_t visitCount, TR_BlockStructure *block, TR_SingleBitContainer *bv)
59
{
60
}
61
62
void TR_HCRGuardAnalysis::analyzeTreeTopsInBlockStructure(TR_BlockStructure *block)
63
{
64
}
65
66
TR_HCRGuardAnalysis::TR_HCRGuardAnalysis(TR::Compilation *comp, TR::Optimizer *optimizer, TR_Structure *rootStructure) :
67
TR_UnionSingleBitContainerAnalysis(comp, comp->getFlowGraph(), optimizer, false/*comp->getOption(TR_TraceFearPointAnalysis)*/)
68
{
69
//_traceFearPointAnalysis = comp->getOption(TR_TraceFearPointAnalysis);
70
if (comp->getVisitCount() > 8000)
71
comp->resetVisitCounts(1);
72
73
// Allocate the block info before setting the stack mark - it will be used by
74
// the caller
75
//
76
initializeBlockInfo();
77
78
{
79
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
80
performAnalysis(rootStructure, false);
81
}
82
83
}
84
85
bool TR_HCRGuardAnalysis::shouldSkipBlock(TR::Block *block)
86
{
87
return block->isOSRCatchBlock() || block->isOSRCodeBlock() || containsPrepareForOSR(block);
88
}
89
90
void TR_HCRGuardAnalysis::initializeGenAndKillSetInfo()
91
{
92
int32_t numBits = getNumberOfBits();
93
for (int32_t i = 0; i < comp()->getFlowGraph()->getNextNodeNumber(); ++i)
94
{
95
_regularGenSetInfo[i] = new (trStackMemory()) TR_SingleBitContainer(numBits,trMemory(), stackAlloc);
96
_exceptionGenSetInfo[i] = new (trStackMemory()) TR_SingleBitContainer(numBits,trMemory(), stackAlloc);
97
_regularKillSetInfo[i] = new (trStackMemory()) TR_SingleBitContainer(numBits,trMemory(), stackAlloc);
98
_exceptionKillSetInfo[i] = new (trStackMemory()) TR_SingleBitContainer(numBits,trMemory(), stackAlloc);
99
}
100
101
TR::Block *currentBlock = NULL;
102
int32_t blockId = -1;
103
TR::NodeChecklist checklist(comp());
104
TR::NodeChecklist exceptionNodelist(comp());
105
bool isGen; /* If current state is gen */
106
bool isKill; /* If current state is kill */
107
bool hasExceptionGen; /* If there exists an exception that gens*/
108
bool hasExceptionKill; /* If there exists an exception that kills*/
109
bool hasExceptionNotKill; /* If there exists an exception that doesn't kill*/
110
bool isYieldPoint;
111
112
TR_ByteCodeInfo nodeBCI;
113
nodeBCI.setCallerIndex(-1);
114
nodeBCI.setByteCodeIndex(0);
115
nodeBCI.setDoNotProfile(false);
116
currentBlock = comp()->getStartTree()->getEnclosingBlock();
117
if (!comp()->getMethodSymbol()->supportsInduceOSR(nodeBCI, currentBlock, comp()))
118
_regularGenSetInfo[currentBlock->getNumber()]->setAll(numBits);
119
120
for (TR::TreeTop *treeTop = comp()->getStartTree(); treeTop; treeTop = treeTop->getNextTreeTop())
121
{
122
TR::Node* ttNode = treeTop->getNode();
123
TR::Node* osrNode = NULL;
124
isYieldPoint = false;
125
if (ttNode->getOpCodeValue() == TR::BBStart)
126
{
127
currentBlock = treeTop->getEnclosingBlock();
128
blockId = currentBlock->getNumber();
129
// Reset the walk state at the beginning of each block
130
isGen = false;
131
isKill = false;
132
hasExceptionGen = false;
133
hasExceptionKill = false;
134
hasExceptionNotKill = false;
135
if (shouldSkipBlock(currentBlock))
136
{
137
_regularKillSetInfo[blockId]->setAll(numBits);
138
_regularGenSetInfo[blockId]->empty();
139
_exceptionKillSetInfo[blockId]->setAll(numBits);
140
_exceptionGenSetInfo[blockId]->empty();
141
142
treeTop = currentBlock->getExit();
143
}
144
continue;
145
}
146
else if (ttNode->getOpCodeValue() == TR::BBEnd)
147
{
148
// Gen and kill are exclusive, so isGen and isKill cannot be true at the same time
149
if (isGen)
150
{
151
TR_ASSERT(!isKill, "isGen and isKill cannot be true at the same time");
152
_regularGenSetInfo[blockId]->setAll(numBits);
153
_regularKillSetInfo[blockId]->empty();
154
}
155
else if (isKill)
156
{
157
TR_ASSERT(!isGen, "isGen and isKill cannot be true at the same time");
158
_regularKillSetInfo[blockId]->setAll(numBits);
159
_regularGenSetInfo[blockId]->empty();
160
}
161
162
// Gen should win if there exists one exception point that is or can be reached by gen
163
if (hasExceptionGen)
164
{
165
_exceptionGenSetInfo[blockId]->setAll(numBits);
166
_exceptionKillSetInfo[blockId]->empty();
167
}
168
else if (hasExceptionKill && !hasExceptionNotKill) /* All exception points have to be kill in order to kill along the exception path */
169
{
170
_exceptionKillSetInfo[blockId]->setAll(numBits);
171
_exceptionGenSetInfo[blockId]->empty();
172
}
173
174
continue;
175
}
176
177
if (comp()->isPotentialOSRPoint(ttNode, &osrNode) && !checklist.contains(osrNode))
178
{
179
checklist.add(osrNode);
180
isYieldPoint = true;
181
bool supportsOSR = comp()->isPotentialOSRPointWithSupport(treeTop);
182
if (supportsOSR)
183
{
184
isKill = true;
185
isGen = false;
186
}
187
else
188
{
189
isGen = true;
190
isKill = false;
191
}
192
}
193
else if (ttNode->isTheVirtualGuardForAGuardedInlinedCall()
194
&& TR_FearPointAnalysis::virtualGuardsKillFear()
195
&& comp()->cg()->supportsMergingGuards())
196
{
197
TR_VirtualGuard *guardInfo = comp()->findVirtualGuardInfo(ttNode);
198
if (guardInfo->getKind() != TR_HCRGuard)
199
{
200
// Theoretically, the guard should only kill its inlined path. However, making it right require adding
201
// complications to the data flow and/or optimizations using the result of the analysis. Based on the
202
// fact that there is few optimization opportunities on the taken side and optimizing it has little benefit,
203
// we require optimizations that can generate fear stay away from taken side such that considering a guard
204
// to be a kill for the taken side is safe.
205
//
206
isKill = true;
207
isGen = false;
208
}
209
}
210
211
bool canNodeRaiseException = false;
212
if (ttNode->getOpCode().canRaiseException())
213
{
214
canNodeRaiseException = true;
215
}
216
else
217
{
218
// Non-treetop nodes that can raise exceptions
219
if (ttNode->getOpCodeValue() == TR::treetop && ttNode->getNumChildren() > 0)
220
{
221
TR::Node* node = ttNode->getFirstChild();
222
if (!exceptionNodelist.contains(node) && node->getOpCode().canRaiseException())
223
{
224
canNodeRaiseException = true;
225
exceptionNodelist.add(node);
226
}
227
}
228
}
229
230
if (canNodeRaiseException)
231
{
232
// If the exception point is also a yield point, it has to be a gen.
233
// It's possible for the tree to yield, allowing assumptions to be invalidated,
234
// and then throw afterward. An OSR guard (if one is necessary) would only run
235
// after non-exceptional completion of the tree, so it wouldn't stop control from
236
// reaching the exception handler.
237
if (isYieldPoint)
238
{
239
hasExceptionGen = true;
240
}
241
else
242
{
243
hasExceptionGen = hasExceptionGen || isGen;
244
hasExceptionKill = hasExceptionKill || isKill;
245
hasExceptionNotKill = hasExceptionNotKill || !isKill;
246
}
247
}
248
249
}
250
}
251
252
bool TR_HCRGuardAnalysis::postInitializationProcessing()
253
{
254
return true;
255
}
256
257