Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/DynamicLiteralPool.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
#include "optimizer/DynamicLiteralPool.hpp"
24
25
#include <limits.h>
26
#include <math.h>
27
#include <stddef.h>
28
#include <stdint.h>
29
#include <stdio.h>
30
#include <stdlib.h>
31
#include <string.h>
32
#include "codegen/CodeGenerator.hpp"
33
#include "env/FrontEnd.hpp"
34
#include "compile/Compilation.hpp"
35
#include "compile/Method.hpp"
36
#include "compile/SymbolReferenceTable.hpp"
37
#include "compile/VirtualGuard.hpp"
38
#include "control/Options.hpp"
39
#include "control/Options_inlines.hpp"
40
#include "env/CompilerEnv.hpp"
41
#include "env/PersistentInfo.hpp"
42
#include "env/StackMemoryRegion.hpp"
43
#include "env/TRMemory.hpp"
44
#include "env/jittypes.h"
45
#include "il/AliasSetInterface.hpp"
46
#include "il/Block.hpp"
47
#include "il/DataTypes.hpp"
48
#include "il/ILOpCodes.hpp"
49
#include "il/ILOps.hpp"
50
#include "il/Node.hpp"
51
#include "il/NodePool.hpp"
52
#include "il/Node_inlines.hpp"
53
#include "il/MethodSymbol.hpp"
54
#include "il/StaticSymbol.hpp"
55
#include "il/Symbol.hpp"
56
#include "il/SymbolReference.hpp"
57
#include "il/TreeTop.hpp"
58
#include "il/TreeTop_inlines.hpp"
59
#include "infra/Assert.hpp"
60
#include "infra/Cfg.hpp"
61
#include "infra/ILWalk.hpp"
62
#include "infra/Stack.hpp"
63
#include "infra/TRCfgEdge.hpp"
64
#include "infra/TRCfgNode.hpp"
65
#include "optimizer/Optimization.hpp"
66
#include "optimizer/Optimization_inlines.hpp"
67
#include "optimizer/OptimizationManager.hpp"
68
#include "optimizer/Optimizations.hpp"
69
#include "optimizer/Optimizer.hpp"
70
#include "optimizer/Structure.hpp"
71
#include "ras/Debug.hpp"
72
#include "runtime/J9Runtime.hpp"
73
74
75
TR_DynamicLiteralPool::TR_DynamicLiteralPool(TR::OptimizationManager *manager)
76
: TR::Optimization(manager)
77
{
78
_litPoolAddressSym=NULL;
79
setAloadFromCurrentBlock(NULL);
80
_changed = false;
81
}
82
83
int32_t TR_DynamicLiteralPool::perform()
84
{
85
if (!cg()->supportsOnDemandLiteralPool())
86
return 1;
87
88
{
89
TR::StackMemoryRegion stackMemoryRegion(*trMemory());
90
91
process(comp()->getStartTree(), NULL);
92
93
if (performTransformation(comp(), "%s free reserved literal pool register\n", optDetailString()))
94
{
95
if (cg()->supportsOnDemandLiteralPool())
96
{
97
cg()->setOnDemandLiteralPoolRun(true);
98
cg()->enableLiteralPoolRegisterForGRA();
99
}
100
}
101
102
postPerformOnBlocks();
103
} // scope of the stack memory region
104
105
if (_changed)
106
{
107
optimizer()->setUseDefInfo(NULL);
108
optimizer()->setValueNumberInfo(NULL);
109
optimizer()->setAliasSetsAreValid(false);
110
requestOpt(OMR::localCSE, true);
111
}
112
// need that to remove the astore if no literal pool is required
113
requestOpt(OMR::localDeadStoreElimination, true);
114
115
return 1;
116
}
117
118
119
int32_t TR_DynamicLiteralPool::performOnBlock(TR::Block *block)
120
{
121
if (block->getEntry())
122
process(block->getEntry(), block->getEntry()->getExtendedBlockExitTreeTop()->getNextTreeTop());
123
return 0;
124
}
125
126
127
void TR_DynamicLiteralPool::initLiteralPoolBase()
128
{
129
TR::Node *tempValue;
130
TR::TreeTop *storeToTempTT;
131
TR::Node *firstNode,*storeToTemp;
132
TR::Block *firstBlock;
133
TR::SymbolReference * tempStaticSym;
134
135
firstNode = comp()->getStartTree()->getNode();
136
firstBlock = firstNode->getBlock();
137
tempStaticSym = getSymRefTab()->createKnownStaticDataSymbolRef(0, TR::Address);
138
_litPoolAddressSym = getSymRefTab()->createTemporary(comp()->getMethodSymbol(), TR::Address);
139
140
tempValue = TR::Node::createWithSymRef(firstNode, TR::aload, 0, tempStaticSym);
141
storeToTemp = TR::Node::createWithSymRef(TR::astore, 1, 1, tempValue, _litPoolAddressSym);
142
143
tempStaticSym->setLiteralPoolAddress();
144
_litPoolAddressSym->setFromLiteralPool();
145
146
// make sure GC knows about the two symbols, otherwise
147
// GC will examine the memory pointed to by the temp/static
148
// and will crash because the memory (i.e. the literal pool) is not a J9Object
149
tempStaticSym->getSymbol()->setNotCollected();
150
getLitPoolAddressSym()->getSymbol()->setNotCollected();
151
152
storeToTempTT = TR::TreeTop::create(comp(), storeToTemp);
153
firstBlock->prepend(storeToTempTT);
154
_changed = true;
155
dumpOptDetails(comp(), "Literal pool base pointer initialized to %p \n", storeToTemp);
156
157
}
158
159
int32_t TR_DynamicLiteralPool::process(TR::TreeTop *startTree, TR::TreeTop *endTree)
160
{
161
TR::TreeTop *tt, *exitTree;
162
vcount_t visitCount = comp()->incVisitCount();
163
for (tt = startTree; (tt != endTree); tt = exitTree->getNextRealTreeTop())
164
{
165
TR::Block *block = tt->getNode()->getBlock();
166
_currentBlock=block;
167
exitTree = block->getEntry()->getExtendedBlockExitTreeTop();
168
processBlock(block, visitCount);
169
}
170
return 1;
171
}
172
173
bool TR_DynamicLiteralPool::processBlock(TR::Block *block, vcount_t visitCount)
174
{
175
TR::TreeTop *exit = block->getEntry()->getExtendedBlockExitTreeTop();
176
setAloadFromCurrentBlock(NULL);
177
178
for (TR::TreeTop *tt = block->getEntry(); tt != exit; tt = tt->getNextRealTreeTop())
179
{
180
setNumChild(-1);
181
visitTreeTop(tt, 0, 0, tt->getNode(), visitCount);
182
}
183
return true;
184
}
185
186
bool TR_DynamicLiteralPool::visitTreeTop(TR::TreeTop * tt, TR::Node *grandParent, TR::Node *parent, TR::Node *node, vcount_t visitCount)
187
{
188
int32_t firstChild = 0;
189
190
if (node->getVisitCount() == visitCount)
191
return true;
192
node->setVisitCount(visitCount);
193
194
TR::ILOpCode opCode = node->getOpCode();
195
TR::ILOpCodes opCodeValue = opCode.getOpCodeValue();
196
197
TR_OpaqueClassBlock * classInfo = 0;
198
199
if (cg()->supportsOnDemandLiteralPool())
200
{
201
// do work on this node
202
if (opCode.isLoadConst())
203
{
204
// reset visitcount to make sure all parents see this child
205
if (node->getReferenceCount()>1) node->setVisitCount(visitCount-1);
206
207
dumpOptDetails(comp(), "looking at const node %p (%s)\n", node, opCode.getName());
208
transformLitPoolConst(grandParent, parent,node);
209
}
210
else if (opCode.hasSymbolReference() &&
211
node->getSymbol()->isStatic() &&
212
!node->getSymbolReference()->isLiteralPoolAddress() &&
213
(node->getSymbolReference() != comp()->getSymRefTab()->findThisRangeExtensionSymRef()))
214
{
215
dumpOptDetails(comp(), "looking at the static symref for node %p (%s)\n", node, opCode.getName());
216
transformStaticSymRefToIndirectLoad(tt, parent, node);
217
}
218
219
// add extra aload child for CurrentTimeMaxPrecision call
220
if (opCode.isCall() &&
221
comp()->getSymRefTab()->isNonHelper(node->getSymbolReference(), TR::SymbolReferenceTable::currentTimeMaxPrecisionSymbol))
222
{
223
addNewAloadChild(node);
224
}
225
// add extra aload child for float conversions
226
else if (opCodeValue==TR::fbits2i || opCodeValue==TR::dbits2l)
227
{
228
addNewAloadChild(node);
229
}
230
}
231
232
for (int32_t i = firstChild; i < node->getNumChildren(); ++i)
233
{
234
setNumChild(i);
235
visitTreeTop(0, parent, node, node->getChild(i), visitCount);
236
}
237
return true;
238
}
239
240
bool TR_DynamicLiteralPool::transformLitPoolConst(TR::Node *grandParent, TR::Node *parent, TR::Node *child)
241
{
242
switch (child->getOpCodeValue())
243
{
244
case TR::fconst:
245
if (performTransformation(comp(), "%s Float Constant\n", optDetailString()))
246
{
247
_changed = true;
248
transformConstToIndirectLoad(parent, child);
249
}
250
else
251
return false;
252
break;
253
case TR::dconst:
254
// LZDR can be used to load floating point zero
255
if (child->getDouble() != 0.0 && performTransformation(comp(), "%s Double Constant\n", optDetailString()))
256
{
257
_changed = true;
258
transformConstToIndirectLoad(parent, child);
259
}
260
else
261
return false;
262
break;
263
case TR::aconst:
264
if (child->isClassUnloadingConst())
265
return false;
266
case TR::iconst:
267
case TR::lconst:
268
case TR::bconst:
269
case TR::sconst:
270
if (transformNeeded(grandParent, parent, child))
271
{
272
if (performTransformation(comp(), "%s Large non-float Constant\n", optDetailString()))
273
{
274
_changed = true;
275
transformConstToIndirectLoad(parent, child);
276
}
277
else
278
{
279
return false;
280
}
281
}
282
break;
283
default:
284
if (child->getDataType().isBCD() || child->getDataType() == TR::Aggregate)
285
return false;
286
else
287
TR_ASSERT(false,"Unknown const %p (type %s)\n",child,child->getDataType().toString());
288
break;
289
}
290
return true;
291
}
292
293
bool TR_DynamicLiteralPool::transformNeeded(TR::Node *grandParent, TR::Node *parent, TR::Node *child)
294
{
295
TR::ILOpCode parentOpCode = parent->getOpCode();
296
TR::ILOpCodes parentOpCodeValue = parentOpCode.getOpCodeValue();
297
298
// need to ensure a constant setsign can be retrieved
299
if (parentOpCode.isSetSign())
300
return false;
301
302
if (child->getType().isIntegral() && parentOpCode.skipDynamicLitPoolOnInts())
303
return false;
304
305
// If the hardware supports relative fixed point loads/stores from the literal pool,
306
// i.e. On z10 or higher, LRL/LGRL/STRL/STGRL, then do not transform to use literal pool
307
// base register.
308
if ( (child->getType().isIntegral() || child->getType().isAddress()) &&
309
cg()->supportsDirectIntegralLoadStoresFromLiteralPool())
310
return false;
311
312
// don't modify const children of multiplication or division to
313
// allow strength reduction to happen. The check bellow could be
314
// more precise, but the logic to determine if strength reduction
315
// is possible is quite complex and if we have it here, it needs
316
// be kept in sync with the logic in evaluators.
317
// In the worst case, when constant actually needs to go lit pool
318
// the code wiil insert extra LARL pre-loading lit pool entry
319
// The cost of this LARL is negligible considering the cost of MULT or DIV
320
if (parentOpCode.isMul() || parentOpCode.isDiv()) return false;
321
// If this looks like a pattern that could be evaluated to a test under mask type instruction
322
// then do not use the lit pool as this will obfuscate the pattern in the evaluator.
323
if (cg()->getSupportsTestUnderMask() &&
324
parentOpCode.isIf() &&
325
parent->getNumChildren() == 2 &&
326
parent->getSecondChild()->getOpCode().isLoadConst() &&
327
isPowerOf2(parent->getSecondChild()->get64bitIntegralValue()))
328
{
329
return false;
330
}
331
if (cg()->getSupportsTestUnderMask() &&
332
grandParent && grandParent->getOpCode().isIf() &&
333
parentOpCode.isAnd() &&
334
parent->getNumChildren() == 2 &&
335
parent->getSecondChild()->getOpCode().isLoadConst() &&
336
isPowerOf2(parent->getSecondChild()->get64bitIntegralValue()))
337
{
338
return false;
339
}
340
341
// Check for arithmetic operations for add, sub, and non-guard compares.
342
// Guarded if-stmts might contain class pointers will may be unloaded. Such
343
// scenarios will be handled by constLoadNeedsLitPool below.
344
if (parentOpCode.isAdd() || parentOpCode.isSub() ||
345
(parentOpCode.isBooleanCompare() && !parent->isTheVirtualGuardForAGuardedInlinedCall()))
346
{
347
if (child->getOpCode().isLong() && (comp()->target().is32Bit()))
348
return false; //avasilev: to be handled better
349
else
350
{
351
TR::ILOpCodes oldOpCode = child->getOpCodeValue();
352
bool needs = (cg()->arithmeticNeedsLiteralFromPool(child));
353
TR::Node::recreate(child, oldOpCode);
354
return needs;
355
}
356
}
357
if (parentOpCode.isAnd() || parentOpCode.isOr() || parentOpCode.isXor() || parentOpCode.isNeg())
358
{
359
if (child->getOpCode().isLong() && (comp()->target().is32Bit()))
360
return false; // to be handled better
361
else
362
return (cg()->bitwiseOpNeedsLiteralFromPool(parent,child));
363
}
364
if (parentOpCode.isLeftShift() || parentOpCode.isRightShift() || parentOpCode.isShiftLogical())
365
return false;
366
367
// TR::arraytranslateAndTest may throw AIOB, but that is taken care of by the evaluator. Also, the
368
// iconst may be the character to search.
369
if (parentOpCode.isBndCheck() && parentOpCodeValue != TR::arraytranslateAndTest)
370
return false;
371
372
// TR::arrayset evaluator expects to see const child, and it's evaluated
373
// specially. Don't modify const children of TR::arrayset. See 74553
374
if (parentOpCodeValue == TR::arrayset) return false;
375
376
if (child->isClassUnloadingConst()) return false;
377
378
// TODO: This function can be simplified because the context in which it is used the following call will always result yield false.
379
// As such many paths through this function that return false are effectively dead and can be removed. There is only one path that
380
// does not return false, and this is the only path that needs to exist, though my intuition is that this path too should be verified
381
// as it may no longer be applicable.
382
return (cg()->constLoadNeedsLiteralFromPool(child));
383
}
384
385
bool TR_DynamicLiteralPool::transformConstToIndirectLoad(TR::Node *parent, TR::Node *child)
386
{
387
//TR::Node *loadLiteralFromThePool;
388
//TR::Node *loadLiteralPoolAddress;
389
TR::Node *constCopy, *indirectLoad;
390
TR::SymbolReference *shadow;
391
392
dumpOptDetails(comp(), "transforming const %p (%s)\n", child, child->getOpCode().getName());
393
394
TR::Node *addrNode;
395
addrNode = getAloadFromCurrentBlock(parent);
396
397
constCopy =TR::Node::copy(child);
398
shadow = getSymRefTab()->findOrCreateImmutableGenericIntShadowSymbolReference((intptr_t)constCopy);
399
shadow->setLiteralPoolAddress();
400
401
if (child->getReferenceCount() > 1) // rematerialize the const by creating new indirect load node
402
{
403
indirectLoad=TR::Node::createWithSymRef(comp()->il.opCodeForIndirectLoad(child->getDataType()), 1, 1, addrNode, shadow);
404
dumpOptDetails(comp(), "New node created %p, refcount of const child was %d\n",indirectLoad,child->getReferenceCount());
405
parent->setAndIncChild(getNumChild(),indirectLoad);
406
child->decReferenceCount();
407
}
408
else
409
{
410
//convert const node to indirect load node
411
child->setNumChildren(1);
412
child = TR::Node::recreateWithSymRef(child, comp()->il.opCodeForIndirectLoad(child->getDataType()), shadow);
413
child->setAndIncChild(0, addrNode);
414
}
415
416
return true;
417
}
418
419
bool TR_DynamicLiteralPool::transformStaticSymRefToIndirectLoad(TR::TreeTop * tt, TR::Node *parent, TR::Node * & child)
420
{
421
// Only transform direct references
422
if (child->getOpCode().isIndirect())
423
return false;
424
425
TR::SymbolReference * childSymRef = child->getSymbolReference();
426
//childSymRef->setFromLiteralPool();
427
TR::ILOpCode childOpcode=child->getOpCode();
428
TR::ILOpCodes childOpcodeValue=child->getOpCodeValue();
429
430
if (childOpcodeValue==TR::loadaddr)
431
{
432
return false;
433
}
434
else
435
{
436
TR::SymbolReference *intChildShadow = NULL;
437
438
if (childSymRef->isUnresolved())
439
{
440
if (cg()->supportsDirectIntegralLoadStoresFromLiteralPool())
441
{
442
return false;
443
}
444
445
childSymRef->setFromLiteralPool();
446
447
if (performTransformation(comp(), "%s unresolved static ref for node %p (%s)\n", optDetailString(), child, child->getOpCode().getName()))
448
{
449
_changed = true;
450
intChildShadow = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(0);
451
}
452
else
453
{
454
return false;
455
}
456
}
457
else
458
{
459
return false;
460
}
461
462
intChildShadow->setFromLiteralPool();
463
getSymRefTab()->aliasBuilder.setLitPoolGenericIntShadowHasBeenCreated();
464
465
TR::Node * loadLiteralFromThePool = TR::Node::createWithSymRef(TR::aloadi, 1, 1, getAloadFromCurrentBlock(child), childSymRef);
466
loadLiteralFromThePool->getSymbol()->setNotCollected();
467
if (childOpcodeValue==TR::awrtbar)
468
{
469
child->getFirstChild()->decReferenceCount();
470
child->getSecondChild()->decReferenceCount();
471
child = TR::Node::create(TR::awrtbari, 3, loadLiteralFromThePool, child->getFirstChild(), child->getSecondChild());
472
if (parent)
473
parent->setAndIncChild(0, child);
474
else
475
tt->setNode(child);
476
}
477
else
478
{
479
//TR::DataType type = childSymRef->getSymbol()->castToStaticSymbol()->getDataType();
480
TR::DataType type = child->getDataType();
481
if (childOpcode.isStore())
482
{
483
child->setSecond(child->getFirstChild());
484
TR::Node::recreate(child, comp()->il.opCodeForIndirectStore(type));
485
}
486
else if (childOpcode.isLoad())
487
{
488
TR::Node::recreate(child, comp()->il.opCodeForIndirectLoad(type));
489
}
490
else
491
{
492
TR_ASSERT(0,"not Load or Store, what is it ?\n");
493
}
494
child->setAndIncChild(0, loadLiteralFromThePool);
495
child->setNumChildren(child->getNumChildren()+1);
496
}
497
child->setSymbolReference(intChildShadow);
498
499
dumpOptDetails(comp(), "created TR::aloadi %p from child %p\n", loadLiteralFromThePool, child);
500
}
501
502
return true;
503
}
504
505
bool TR_DynamicLiteralPool::addNewAloadChild(TR::Node *node)
506
{
507
if (!performTransformation(comp(), "%s creating new aload child for node %p (%s) %p \n", optDetailString(),node,node->getOpCode().getName()))
508
return false;
509
_changed = true;
510
node->setAndIncChild(node->getNumChildren(),getAloadFromCurrentBlock(node));
511
node->setNumChildren(node->getNumChildren()+1);
512
return true;
513
}
514
515
516
bool TR_DynamicLiteralPool::handleNodeUsingVMThread(TR::TreeTop * tt, TR::Node *parent, TR::Node *node, vcount_t visitCount)
517
{
518
/*
519
if (node->getOpCode().isLoadVarOrStore())
520
{
521
TR::SymbolReference *symRef = node->getSymbolReference();
522
if (symRef->isUnresolved())
523
{
524
}
525
else
526
{
527
if (symRef->getSymbol()->isMethodMetaData())
528
{
529
TR_ASSERT(node->getOpCode().isDirect(), "Load/store from meta data should use a direct opcode\n");
530
TR::SymbolReference *metaDataShadow = getSymRefTab()->findOrCreateGenericIntShadowSymbolReference(symRef->getOffset());
531
TR::Node * loadVMThreadFromTheStack = getVMThreadAloadFromCurrentBlock(node);
532
TR::DataType type = node->getDataType();
533
if (node->getOpCode().isStore())
534
{
535
node->setSecond(node->getFirstChild());
536
TR::Node::recreate(node, comp()->il.opCodeForIndirectStore(type));
537
}
538
else if (node->getOpCode().isLoad())
539
{
540
TR::Node::recreate(node, comp()->il.opCodeForIndirectLoad(type));
541
}
542
else
543
{
544
TR_ASSERT(0,"not Load or Store, what is it ?\n");
545
}
546
node->setAndIncChild(0, loadVMThreadFromTheStack);
547
node->setNumChildren(node->getNumChildren()+1);
548
node->setSymbolReference(metaDataShadow);
549
}
550
551
if (node->getOpCode().isWrtBar())
552
{
553
}
554
}
555
}
556
*/
557
558
return true;
559
}
560
561
562
bool TR_DynamicLiteralPool::handleNodeUsingSystemStack(TR::TreeTop * tt, TR::Node *parent, TR::Node *node, vcount_t visitCount)
563
{
564
return true;
565
}
566
567
568
TR::SymbolReference * getVMThreadSym()
569
{
570
return NULL;
571
}
572
573
TR::Node *TR_DynamicLiteralPool::getVMThreadAloadFromCurrentBlock(TR::Node *parent)
574
{
575
if (_vmThreadAloadFromCurrentBlock==NULL)
576
{
577
setVMThreadAloadFromCurrentBlock(TR::Node::createWithSymRef(parent, TR::aload, 0, getVMThreadSym()));
578
dumpOptDetails(comp(), "New VM thread aload needed, it is: %p!\n", _vmThreadAloadFromCurrentBlock);
579
}
580
else
581
{
582
dumpOptDetails(comp(), "Can re-use VM thread aload %p!\n",_vmThreadAloadFromCurrentBlock);
583
}
584
return _vmThreadAloadFromCurrentBlock;
585
}
586
587
const char *
588
TR_DynamicLiteralPool::optDetailString() const throw()
589
{
590
return "O^O DYNAMIC LITERAL POOL: ";
591
}
592
593