Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/J9CFGSimplifier.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2019, 2020 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
#include "compile/Method.hpp"
24
#include "optimizer/CFGSimplifier.hpp"
25
#include "optimizer/Optimization_inlines.hpp"
26
#include "optimizer/TransformUtil.hpp"
27
#include "il/Block.hpp"
28
#include "il/Node.hpp"
29
#include "il/Node_inlines.hpp"
30
#include "il/StaticSymbol.hpp"
31
#include "il/Symbol.hpp"
32
33
#define OPT_DETAILS "O^O CFG SIMPLIFICATION: "
34
35
bool J9::CFGSimplifier::simplifyIfPatterns(bool needToDuplicateTree)
36
{
37
static char *enableCFGSimplification = feGetEnv("TR_enableCFGSimplificaiton");
38
if (enableCFGSimplification == NULL)
39
return false;
40
41
return OMR::CFGSimplifier::simplifyIfPatterns(needToDuplicateTree)
42
|| simplifyResolvedRequireNonNull(needToDuplicateTree)
43
|| simplifyUnresolvedRequireNonNull(needToDuplicateTree)
44
;
45
}
46
47
// Look for pattern of the form:
48
//
49
// ifacmpeq block_A
50
// ... some ref
51
// aconst NULL
52
//
53
// OR
54
//
55
// ifacmpne block_A
56
// ... some ref
57
// aconst NULL
58
//
59
// Where block_A looks like:
60
// ResolveCHK
61
// loadaddr
62
// treetop
63
// new
64
// => loadaddr
65
// ResolveAndNULLCHK
66
// call java/lang/NullPointerException.<init>();
67
// => new
68
// NULLCHK
69
// athrow
70
// => new
71
72
bool J9::CFGSimplifier::simplifyUnresolvedRequireNonNull(bool needToDuplicateTree)
73
{
74
static char *disableSimplifyExplicitNULLTest = feGetEnv("TR_disableSimplifyExplicitNULLTest");
75
static char *disableSimplifyUnresolvedRequireNonNull = feGetEnv("TR_disableSimplifyUnresolvedRequireNonNull");
76
if (disableSimplifyExplicitNULLTest != NULL || disableSimplifyUnresolvedRequireNonNull != NULL)
77
return false;
78
79
if (comp()->getOSRMode() == TR::involuntaryOSR)
80
return false;
81
82
if (trace())
83
traceMsg(comp(), "Start simplifyUnresolvedRequireNonNull\n");
84
85
// This block must end in an ifacmpeq or ifacmpne against aconst NULLa
86
TR::TreeTop *compareTreeTop = getLastRealTreetop(_block);
87
TR::Node *compareNode = compareTreeTop->getNode();
88
if (compareNode->getOpCodeValue() != TR::ifacmpeq
89
&& compareNode->getOpCodeValue() != TR::ifacmpne)
90
return false;
91
92
if (trace())
93
traceMsg(comp(), " Found an ifacmp[eq/ne] n%dn\n", compareNode->getGlobalIndex());
94
95
if (compareNode->getSecondChild()->getOpCodeValue() != TR::aconst
96
|| compareNode->getSecondChild()->getAddress() != 0)
97
return false;
98
99
// _next1 is fall through so grab the block where the value is NULL
100
TR::Block *nullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next2 : _next1;
101
TR::Block *nonnullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next1 : _next2;
102
103
if (trace())
104
traceMsg(comp(), " Matched nullBlock %d\n", nullBlock->getNumber());
105
106
TR::TreeTop *nullBlockCursor = nullBlock->getEntry()->getNextTreeTop();
107
108
if (nullBlockCursor->getNode()->getOpCodeValue() != TR::ResolveCHK
109
|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::loadaddr)
110
return false;
111
112
if (trace())
113
traceMsg(comp(), " Match ResolveCHK of loadaddr\n");
114
115
TR::Node *loadaddr = nullBlockCursor->getNode()->getFirstChild();
116
nullBlockCursor = nullBlockCursor->getNextTreeTop();
117
118
if (nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop
119
|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::New
120
|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != loadaddr)
121
return false;
122
123
TR::Node *exceptionNode = nullBlockCursor->getNode()->getFirstChild();
124
125
if (trace())
126
traceMsg(comp(), " Matched new of loadaddr\n");
127
128
nullBlockCursor = nullBlockCursor->getNextTreeTop();
129
130
// optionally match pending push store
131
if (nullBlockCursor->getNode()->getOpCodeValue() == TR::astore
132
&& nullBlockCursor->getNode()->getFirstChild() == exceptionNode
133
&& nullBlockCursor->getNode()->getSymbol()->isPendingPush())
134
nullBlockCursor = nullBlockCursor->getNextTreeTop();
135
136
if (nullBlockCursor->getNode()->getOpCodeValue() != TR::ResolveAndNULLCHK
137
|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::call
138
|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)
139
return false;
140
141
TR::Node *initCall = nullBlockCursor->getNode()->getFirstChild();
142
143
if (trace())
144
traceMsg(comp(), " Matched call node %d\n", initCall->getGlobalIndex());
145
146
if (!initCall->getSymbolReference()->isUnresolved())
147
return false;
148
149
TR::Method *calleeMethod = initCall->getSymbol()->castToMethodSymbol()->getMethod();
150
if (trace())
151
traceMsg(comp(), " Matched calleeMethod %s %s %s\n", calleeMethod->classNameChars(), calleeMethod->nameChars(), calleeMethod->signatureChars());
152
if (strncmp(calleeMethod->nameChars(), "<init>", 6) != 0
153
|| strncmp(calleeMethod->classNameChars(), "java/lang/NullPointerException", 30) != 0
154
|| strncmp(calleeMethod->signatureChars(), "()V", 3) != 0)
155
return false;
156
157
158
if (trace())
159
traceMsg(comp(), " Matched NPE init\n");
160
161
nullBlockCursor = nullBlockCursor->getNextTreeTop();
162
if ((nullBlockCursor->getNode()->getOpCodeValue() != TR::NULLCHK
163
&& nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop)
164
|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::athrow
165
|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)
166
return false;
167
168
if (trace())
169
traceMsg(comp(), " Matched throw\n");
170
171
TR::Node *throwNode = nullBlockCursor->getNode()->getFirstChild();
172
173
nullBlockCursor = nullBlockCursor->getNextTreeTop();
174
if (nullBlockCursor != nullBlock->getExit())
175
return false;
176
177
if (!performTransformation(comp(), "%sReplace ifacmpeq/ifacmpne of NULL node [%p] to throw of an NPE exception with NULLCHK\n", OPT_DETAILS, compareNode))
178
return false;
179
180
_cfg->invalidateStructure();
181
182
TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "cfgSimpNULLCHK/unresolvedNonNull/(%s)", comp()->signature()));
183
184
TR::Block *checkBlock = _block;
185
if (hasExceptionPoint(_block, compareTreeTop))
186
checkBlock = _block->split(compareTreeTop, _cfg, true, false);
187
188
if (!nullBlock->getExceptionSuccessors().empty())
189
{
190
for (auto itr = nullBlock->getExceptionSuccessors().begin(), end = nullBlock->getExceptionSuccessors().end(); itr != end; ++itr)
191
{
192
_cfg->addExceptionEdge(checkBlock, (*itr)->getTo());
193
}
194
}
195
196
TR::Node *passthroughNode = TR::Node::create(throwNode, TR::PassThrough, 1);
197
passthroughNode->setAndIncChild(0, compareNode->getFirstChild());
198
TR::SymbolReference *symRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());
199
TR::Node *nullchkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, symRef);
200
if (trace())
201
traceMsg(comp(), "End simplifyUnresolvedRequireNonNull. Generated NULLCHK node n%dn\n", nullchkNode->getGlobalIndex());
202
TR::TreeTop *nullchkTree = TR::TreeTop::create(comp(), nullchkNode);
203
checkBlock->getEntry()->insertAfter(nullchkTree);
204
205
_cfg->removeEdge(checkBlock, nullBlock);
206
TR::TransformUtil::removeTree(comp(), compareTreeTop);
207
208
if (checkBlock->getNextBlock() != nonnullBlock)
209
{
210
TR::Node *gotoNode = TR::Node::create(nullchkNode, TR::Goto, 0);
211
gotoNode->setBranchDestination(nonnullBlock->getEntry());
212
checkBlock->append(TR::TreeTop::create(comp(), gotoNode));
213
}
214
215
return true;
216
}
217
218
// Look for pattern of the form:
219
//
220
// ifacmpeq block_A
221
// ... some ref
222
// aconst NULL
223
//
224
// OR
225
//
226
// ifacmpne block_A
227
// ... some ref
228
// aconst NULL
229
//
230
// Where block_A looks like:
231
// treetop
232
// new
233
// loadaddr java/lang/NullPointerException
234
// treetop | NULLCHK
235
// call java/lang/NullPointerException.<init>();
236
// => new
237
// treetop | NULLCHK
238
// athrow
239
// => new
240
//
241
// Replace the branch with a NULLCHK PassThrough of some ref
242
//
243
bool J9::CFGSimplifier::simplifyResolvedRequireNonNull(bool needToDuplicateTree)
244
{
245
static char *disableSimplifyExplicitNULLTest = feGetEnv("TR_disableSimplifyExplicitNULLTest");
246
static char *disableSimplifyResolvedRequireNonNull = feGetEnv("TR_disableSimplifyResolvedRequireNonNull");
247
if (disableSimplifyExplicitNULLTest != NULL || disableSimplifyResolvedRequireNonNull != NULL)
248
return false;
249
250
if (comp()->getOSRMode() == TR::involuntaryOSR)
251
return false;
252
253
if (trace())
254
traceMsg(comp(), "Start simplifyResolvedRequireNonNull\n");
255
256
// This block must end in an ifacmpeq or ifacmpne against aconst NULL
257
TR::TreeTop *compareTreeTop = getLastRealTreetop(_block);
258
TR::Node *compareNode = compareTreeTop->getNode();
259
if (compareNode->getOpCodeValue() != TR::ifacmpeq
260
&& compareNode->getOpCodeValue() != TR::ifacmpne)
261
return false;
262
263
if (trace())
264
traceMsg(comp(), " Found an ifacmp[eq/ne] n%dn\n", compareNode->getGlobalIndex());
265
266
if (compareNode->getSecondChild()->getOpCodeValue() != TR::aconst
267
|| compareNode->getSecondChild()->getAddress() != 0)
268
return false;
269
270
// _next1 is fall through so grab the block where the value is NULL
271
TR::Block *nullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next2 : _next1;
272
TR::Block *nonnullBlock = compareNode->getOpCodeValue() == TR::ifacmpeq ? _next1 : _next2;
273
274
traceMsg(comp(), " Found nullBlock %d\n", nullBlock->getNumber());
275
276
TR::TreeTop *nullBlockCursor = nullBlock->getEntry()->getNextTreeTop();
277
if (nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop
278
|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::New
279
|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild()->getOpCodeValue() != TR::loadaddr)
280
return false;
281
282
if (trace())
283
traceMsg(comp(), " Matched new tree\n");
284
285
TR::Node *exceptionNode = nullBlockCursor->getNode()->getFirstChild();
286
TR::Node *loadaddr = nullBlockCursor->getNode()->getFirstChild()->getFirstChild();
287
// check for java/lang/NullPointerException as the loadaddr
288
TR_OpaqueClassBlock *NPEclazz = comp()->fej9()->getSystemClassFromClassName("java/lang/NullPointerException", strlen("java/lang/NullPointerException"));
289
if (loadaddr->getSymbolReference()->isUnresolved()
290
|| loadaddr->getSymbolReference()->getSymbol()->castToStaticSymbol()->getStaticAddress() != NPEclazz)
291
return false;
292
293
if (trace())
294
traceMsg(comp(), " Matched new tree class\n");
295
296
nullBlockCursor = nullBlockCursor->getNextTreeTop();
297
298
// optionally match pending push store
299
if (nullBlockCursor->getNode()->getOpCodeValue() == TR::astore
300
&& nullBlockCursor->getNode()->getFirstChild() == exceptionNode
301
&& nullBlockCursor->getNode()->getSymbol()->isPendingPush())
302
nullBlockCursor = nullBlockCursor->getNextTreeTop();
303
304
if ((nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop
305
&& nullBlockCursor->getNode()->getOpCodeValue() != TR::NULLCHK)
306
|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::call
307
|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)
308
return false;
309
310
if (trace())
311
traceMsg(comp(), " Matched exceptionNode\n");
312
313
TR::Node *initCall = nullBlockCursor->getNode()->getFirstChild();
314
if (initCall->getSymbolReference()->isUnresolved())
315
return false;
316
317
TR_ResolvedMethod *calleeMethod = initCall->getSymbol()->castToResolvedMethodSymbol()->getResolvedMethod();
318
if (trace())
319
traceMsg(comp(), " Matched calleeMethod %s %s %s\n", calleeMethod->classNameChars(), calleeMethod->nameChars(), calleeMethod->signatureChars());
320
if (strncmp(calleeMethod->nameChars(), "<init>", 6) != 0
321
|| strncmp(calleeMethod->classNameChars(), "java/lang/Throwable", 19) != 0
322
|| strncmp(calleeMethod->signatureChars(), "()V", 3) != 0)
323
return false;
324
325
if (trace())
326
traceMsg(comp(), " Matched exceptionNode call\n");
327
328
nullBlockCursor = nullBlockCursor->getNextTreeTop();
329
if ((nullBlockCursor->getNode()->getOpCodeValue() != TR::treetop
330
&& nullBlockCursor->getNode()->getOpCodeValue() != TR::NULLCHK)
331
|| nullBlockCursor->getNode()->getFirstChild()->getOpCodeValue() != TR::athrow
332
|| nullBlockCursor->getNode()->getFirstChild()->getFirstChild() != exceptionNode)
333
return false;
334
335
if (trace())
336
traceMsg(comp(), " Matched exception throw\n");
337
338
TR::Node *throwNode = nullBlockCursor->getNode()->getFirstChild();
339
340
nullBlockCursor = nullBlockCursor->getNextTreeTop();
341
if (nullBlockCursor != nullBlock->getExit())
342
return false;
343
344
if (!performTransformation(comp(), "%sReplace ifacmpeq/ifacmpne of NULL node [%p] to throw of an NPE exception with NULLCHK\n", OPT_DETAILS, compareNode))
345
return false;
346
347
_cfg->invalidateStructure();
348
349
TR::DebugCounter::incStaticDebugCounter(comp(), TR::DebugCounter::debugCounterName(comp(), "cfgSimpNULLCHK/resolvedNonNull/(%s)", comp()->signature()));
350
351
TR::Block *checkBlock = _block;
352
if (hasExceptionPoint(_block, compareTreeTop))
353
checkBlock = _block->split(compareTreeTop, _cfg, true, false);
354
355
if (!nullBlock->getExceptionSuccessors().empty())
356
{
357
for (auto itr = nullBlock->getExceptionSuccessors().begin(), end = nullBlock->getExceptionSuccessors().end(); itr != end; ++itr)
358
{
359
_cfg->addExceptionEdge(checkBlock, (*itr)->getTo());
360
}
361
}
362
363
TR::Node *passthroughNode = TR::Node::create(throwNode, TR::PassThrough, 1);
364
passthroughNode->setAndIncChild(0, compareNode->getFirstChild());
365
TR::SymbolReference *symRef = comp()->getSymRefTab()->findOrCreateNullCheckSymbolRef(comp()->getMethodSymbol());
366
TR::Node *nullchkNode = TR::Node::createWithSymRef(TR::NULLCHK, 1, 1, passthroughNode, symRef);
367
if (trace())
368
traceMsg(comp(), "End simplifyResolvedRequireNonNull. Generated NULLCHK node n%dn\n", nullchkNode->getGlobalIndex());
369
TR::TreeTop *nullchkTree = TR::TreeTop::create(comp(), nullchkNode);
370
checkBlock->getEntry()->insertAfter(nullchkTree);
371
372
_cfg->removeEdge(checkBlock, nullBlock);
373
TR::TransformUtil::removeTree(comp(), compareTreeTop);
374
375
if (checkBlock->getNextBlock() != nonnullBlock)
376
{
377
TR::Node *gotoNode = TR::Node::create(nullchkNode, TR::Goto, 0);
378
gotoNode->setBranchDestination(nonnullBlock->getEntry());
379
checkBlock->append(TR::TreeTop::create(comp(), gotoNode));
380
}
381
382
return true;
383
}
384
385