Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/optimizer/BoolArrayStoreTransformer.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2018, 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
#ifdef J9ZTPF
24
#define __TPF_DO_NOT_MAP_ATOE_REMOVE
25
#endif
26
27
#include "optimizer/BoolArrayStoreTransformer.hpp"
28
#include "compiler/il/OMRTreeTop_inlines.hpp"
29
#include "il/AutomaticSymbol.hpp"
30
#include "il/Block.hpp"
31
#include "il/Node.hpp"
32
#include "il/Node_inlines.hpp"
33
#include "il/TreeTop.hpp"
34
#include "infra/Cfg.hpp"
35
#include "infra/ILWalk.hpp"
36
#include <deque>
37
#include <stack>
38
39
/*
40
* This transformer is used to make sure the behavior of bastore in JIT code
41
* complies with JVM specs:
42
*
43
* If the arrayref refers to an array whose components are of type boolean,
44
* then the int value is narrowed by taking the bitwise AND of value and 1;
45
* the result is stored as the component of the array indexed by index
46
*
47
* bastore can be array store to either boolean or byte array. To
48
* figure out which bastore is for boolean array, the following steps are taken:
49
*
50
* 1. Normal IL generation pass solves the cases where the array base node is parm
51
* ,field, or call. It also collects info about if there are stores of boolean
52
* or bytes array type to any autos. If only one type of array or multi dimension
53
* array ever appears in the IL trees, the bstorei nodes can only be this one type.
54
* 2. If arrays of both types exist in the IL trees, the transformer do a traverse
55
* of the CFG and tries to propagate auto types as best effort. This
56
* approach might still leave some array's type unknown when there are stores of NULL
57
* to an auto, or there are loops, or the base array node is from a multinewarray.
58
* 3. A runtime check is added for the array base node if the type is still unknown
59
* for any bstorei nodes after the above steps. The check will very likely be folded
60
* away by global value propagation and the overhead for important method body
61
* should be minimum.
62
*/
63
64
#define OPT_DETAILS "O^O BOOL ARRAY STORE TRANSFORMER: "
65
66
static char * getTypeName(TR_YesNoMaybe type, char * buffer)
67
{
68
switch (type)
69
{
70
case TR_yes:
71
strcpy(buffer, "[Z");
72
break;
73
case TR_no:
74
strcpy(buffer, "[B");
75
break;
76
case TR_maybe:
77
strcpy(buffer, "unknown type");
78
break;
79
}
80
return buffer;
81
}
82
83
static void printTypeInfo(TR_BoolArrayStoreTransformer::TypeInfo *typeInfo, TR::Compilation *comp)
84
{
85
int localIndex = 0;
86
for (auto it = typeInfo->begin(); it != typeInfo->end(); it++)
87
{
88
if (*it != TR_maybe)
89
{
90
char buffer[15];
91
traceMsg(comp, "( local #%2d: %s ) ", localIndex, getTypeName(*it, buffer));
92
}
93
localIndex++;
94
}
95
}
96
97
TR_BoolArrayStoreTransformer::TR_BoolArrayStoreTransformer(NodeSet *bstoreiUnknownArrayTypeNodes, NodeSet *bstoreiBoolArrayTypeNodes)
98
:
99
_bstoreiUnknownArrayTypeNodes(bstoreiUnknownArrayTypeNodes),
100
_bstoreiBoolArrayTypeNodes(bstoreiBoolArrayTypeNodes),
101
_hasBoolArrayAutoOrCheckCast(false),
102
_hasByteArrayAutoOrCheckCast(false),
103
_hasVariantArgs(false),
104
_numLocals(0)
105
{
106
_comp = TR::comp();
107
}
108
109
void TR_BoolArrayStoreTransformer::perform()
110
{
111
if (comp()->getOption(TR_TraceILGen))
112
traceMsg(comp(), "<BoolArrayStoreTransformer>\n");
113
114
if (!_hasVariantArgs)
115
{
116
// There is no store to args and bstorei nodes with argument as array base have known type
117
for (auto it = _bstoreiUnknownArrayTypeNodes->begin(); it != _bstoreiUnknownArrayTypeNodes->end();)
118
{
119
TR::Node *bstoreiNode = *it;
120
it++;
121
TR::Node *arrayBaseNode = bstoreiNode->getFirstChild()->getFirstChild();
122
if (arrayBaseNode->getOpCode().hasSymbolReference() && arrayBaseNode->getSymbolReference()->getSymbol()->isParm())
123
{
124
if (isBoolArrayNode(arrayBaseNode, false /* parmAsAuto */))
125
{
126
if (comp()->getOption(TR_TraceILGen))
127
traceMsg(comp(), "bstorei node n%dn is [Z from parm type signature\n", bstoreiNode->getGlobalIndex());
128
_bstoreiBoolArrayTypeNodes->insert(bstoreiNode);
129
_bstoreiUnknownArrayTypeNodes->erase(bstoreiNode);
130
}
131
else if (isByteArrayNode(arrayBaseNode, false /* parmAsAuto */))
132
{
133
if (comp()->getOption(TR_TraceILGen))
134
traceMsg(comp(), "bstorei node n%dn is [B from parm type signature\n", bstoreiNode->getGlobalIndex());
135
_bstoreiUnknownArrayTypeNodes->erase(bstoreiNode);
136
}
137
}
138
}
139
}
140
else
141
{
142
// parm are treated as auto as well
143
ListIterator<TR::ParameterSymbol> parms(&comp()->getMethodSymbol()->getParameterList());
144
for (TR::ParameterSymbol * p = parms.getFirst(); p; p = parms.getNext())
145
{
146
if (isAnyDimensionBoolArrayParm(p))
147
_hasBoolArrayAutoOrCheckCast = true;
148
else if (isAnyDimensionByteArrayParm(p))
149
_hasByteArrayAutoOrCheckCast = true;
150
}
151
}
152
153
if (!_bstoreiUnknownArrayTypeNodes->empty())
154
{
155
if (_hasByteArrayAutoOrCheckCast && _hasBoolArrayAutoOrCheckCast) // only need to iterate CFG if both byte and boolean array exist
156
findBoolArrayStoreNodes();
157
else
158
{
159
if (_hasBoolArrayAutoOrCheckCast) // if only boolean array exist then all the bstorei nodes are operating on boolean array
160
{
161
if (comp()->getOption(TR_TraceILGen))
162
traceMsg(comp(), "only boolean array exist as auto or checkcast type\n");
163
_bstoreiBoolArrayTypeNodes->insert(_bstoreiUnknownArrayTypeNodes->begin(), _bstoreiUnknownArrayTypeNodes->end());
164
}
165
else
166
{
167
if (comp()->getOption(TR_TraceILGen))
168
traceMsg(comp(), "only byte array exist as auto or checkcast type\n");
169
}
170
_bstoreiUnknownArrayTypeNodes->clear();
171
}
172
}
173
174
if (!_bstoreiBoolArrayTypeNodes->empty())
175
transformBoolArrayStoreNodes();
176
177
if (!_bstoreiUnknownArrayTypeNodes->empty())
178
transformUnknownTypeArrayStore();
179
180
if (comp()->getOption(TR_TraceILGen))
181
traceMsg(comp(), "</BoolArrayStoreTransformer>\n");
182
}
183
184
void TR_BoolArrayStoreTransformer::collectLocals(TR_Array<List<TR::SymbolReference>> *autosListArray)
185
{
186
for (int i = 0; autosListArray && i < autosListArray->size(); i++)
187
{
188
List<TR::SymbolReference> autosList = (*autosListArray)[i];
189
ListIterator<TR::SymbolReference> autosIt(&autosList);
190
for (TR::SymbolReference* symRef = autosIt.getFirst(); symRef; symRef = autosIt.getNext())
191
{
192
TR::AutomaticSymbol *p = symRef->getSymbol()->getAutoSymbol();
193
if (p && p->getDataType() == TR::Address)
194
{
195
if (comp()->getOption(TR_TraceILGen))
196
traceMsg(comp(), "Local #%2d is symbol %p [#n%dn]\n", _numLocals, p, symRef->getReferenceNumber());
197
p->setLocalIndex(_numLocals++);
198
}
199
}
200
}
201
}
202
203
/*
204
* Merge second type info into first one if it has more concrete type for any auto
205
*/
206
void TR_BoolArrayStoreTransformer::mergeTypeInfo(TypeInfo *first, TypeInfo *second)
207
{
208
bool traceIt = comp()->getOption(TR_TraceILGen);
209
if (traceIt)
210
{
211
traceMsg(comp(), "before merging: ");
212
printTypeInfo(first, comp());
213
traceMsg(comp(), "\n");
214
}
215
216
bool changed = false;
217
for (int i = 0; i < _numLocals; i++)
218
{
219
TR_YesNoMaybe firstType = (*first)[i];
220
TR_YesNoMaybe secondType = (*second)[i];
221
if (secondType != TR_maybe)
222
{
223
if (firstType == TR_maybe)
224
{
225
(*first)[i] = secondType;
226
changed = true;
227
}
228
else if (firstType != secondType )
229
{
230
// It doesn't matter which type wins because there must be a checkcast
231
// or another kill with specific type later on every path reaching a bstorei
232
if (traceIt)
233
{
234
char firstTypeBuffer[15];
235
char secondTypeBuffer[15];
236
traceMsg(comp(), "local #%2d has conflict types keep the first type for now: firstType %s, secondType %s\n", i, getTypeName(firstType, firstTypeBuffer), getTypeName(secondType, secondTypeBuffer));
237
}
238
}
239
}
240
}
241
242
if (changed && traceIt)
243
{
244
traceMsg(comp(), "after merging: ");
245
printTypeInfo(first, comp());
246
traceMsg(comp(), "\n");
247
}
248
}
249
250
void TR_BoolArrayStoreTransformer::findBoolArrayStoreNodes()
251
{
252
TR::Region currentRegion(comp()->region());
253
254
ListIterator<TR::ParameterSymbol> parms(&comp()->getMethodSymbol()->getParameterList());
255
for (TR::ParameterSymbol * p = parms.getFirst(); p; p = parms.getNext())
256
{
257
if (p->getDataType() == TR::Address)
258
{
259
if (comp()->getOption(TR_TraceILGen))
260
traceMsg(comp(), "Local #%2d is symbol %p <parm %d>\n", _numLocals, p, p->getSlot());
261
p->setLocalIndex(_numLocals++);
262
}
263
}
264
collectLocals(comp()->getMethodSymbol()->getAutoSymRefs());
265
collectLocals(comp()->getMethodSymbol()->getPendingPushSymRefs());
266
267
typedef TR::typed_allocator<std::pair<const int32_t, TypeInfo *>, TR::Region &> ResultAllocator;
268
typedef std::map<int32_t, TypeInfo *, std::less<int32_t>, ResultAllocator> BlockResultMap;
269
BlockResultMap blockStartTypeInfos(std::less<int32_t>(), comp()->trMemory()->currentStackRegion());
270
271
/*
272
* Do a reverse post-order traversal of the CFG as the best effort to figure out types in one traverse
273
*/
274
TR::ReversePostorderSnapshotBlockIterator blockIt (comp()->getFlowGraph(), comp());
275
//Initialize type info for parms for the entry block
276
if (blockIt.currentBlock())
277
{
278
TR::Block *firstBlock = blockIt.currentBlock();
279
ListIterator<TR::ParameterSymbol> parms(&comp()->getMethodSymbol()->getParameterList());
280
TypeInfo * typeInfo = NULL;
281
for (TR::ParameterSymbol * p = parms.getFirst(); p; p = parms.getNext())
282
{
283
if (p->getDataType() == TR::Address)
284
{
285
TR_YesNoMaybe type = TR_maybe;
286
if (isBoolArrayParm(p))
287
type = TR_yes;
288
else if (isByteArrayParm(p))
289
type = TR_no;
290
291
if (type != TR_maybe)
292
{
293
if (!typeInfo)
294
typeInfo = new (comp()->trMemory()->currentStackRegion()) TypeInfo(_numLocals, TR_maybe, comp()->trMemory()->currentStackRegion());
295
(*typeInfo)[p->getLocalIndex()] = type;
296
}
297
}
298
}
299
300
if (typeInfo)
301
{
302
blockStartTypeInfos[firstBlock->getNumber()] = typeInfo;
303
if (comp()->getOption(TR_TraceILGen))
304
{
305
traceMsg(comp(), "Entry Block (block_%d) type Info: ", firstBlock->getNumber());
306
printTypeInfo(typeInfo, comp());
307
traceMsg(comp(), "\n");
308
}
309
}
310
}
311
312
TR::BlockChecklist visitedBlock(comp());
313
_NumOfBstoreiNodesToVisit = _bstoreiUnknownArrayTypeNodes->size();
314
while (blockIt.currentBlock() && _NumOfBstoreiNodesToVisit > 0)
315
{
316
TR::Block *block = blockIt.currentBlock();
317
int32_t blockNum = block->getNumber();
318
TypeInfo *blockStartTypeInfo = blockStartTypeInfos.find(blockNum) != blockStartTypeInfos.end()? blockStartTypeInfos[blockNum]: NULL;
319
TypeInfo *blockEndTypeInfo = processBlock(block, blockStartTypeInfo);
320
visitedBlock.add(block);
321
TR_SuccessorIterator bi(block);
322
for (TR::CFGEdge *edge = bi.getFirst(); edge != NULL; edge = bi.getNext())
323
{
324
TR::Block *nextBlock = toBlock(edge->getTo());
325
int32_t nextBlockNum = nextBlock->getNumber();
326
//propagate auto type info to successor
327
//if the type info exist for the successor merge with the new one
328
if (blockEndTypeInfo && !visitedBlock.contains(nextBlock))
329
{
330
if (blockStartTypeInfos.find(nextBlockNum) != blockStartTypeInfos.end())
331
{
332
if (comp()->getOption(TR_TraceILGen))
333
traceMsg(comp(), "merging into type info of successor block_%d\n", nextBlockNum);
334
mergeTypeInfo(blockStartTypeInfos[nextBlockNum], blockEndTypeInfo);
335
}
336
else
337
blockStartTypeInfos[nextBlockNum] = new (currentRegion) TypeInfo(*blockEndTypeInfo);
338
}
339
}
340
++blockIt;
341
}
342
}
343
344
/*
345
* Answer includes multi dimension boolean array
346
*/
347
bool TR_BoolArrayStoreTransformer::isAnyDimensionBoolArrayNode(TR::Node *node)
348
{
349
return getArrayDimension(node, true /*boolType*/, false /* parmAsAuto*/) >= 1;
350
}
351
352
/*
353
* Answer includes multi dimension byte array
354
*/
355
bool TR_BoolArrayStoreTransformer::isAnyDimensionByteArrayNode(TR::Node *node)
356
{
357
return getArrayDimension(node, false /*boolType*/, false /* parmAsAuto */) >= 1;
358
}
359
360
361
/*
362
* Answer includes multi dimension boolean array
363
*/
364
bool TR_BoolArrayStoreTransformer::isAnyDimensionBoolArrayParm(TR::ParameterSymbol *symbol)
365
{
366
int length;
367
const char *signature = symbol->getTypeSignature(length);
368
return getArrayDimension(signature, length, true /*boolType*/) >= 1;
369
}
370
371
/*
372
* Answer includes multi dimension byte array
373
*/
374
bool TR_BoolArrayStoreTransformer::isAnyDimensionByteArrayParm(TR::ParameterSymbol *symbol)
375
{
376
int length;
377
const char *signature = symbol->getTypeSignature(length);
378
return getArrayDimension(signature, length, false /*boolType*/) >= 1;
379
}
380
381
/*
382
* \brief
383
* Answer includes one dimension boolean array only
384
*
385
* \parm node
386
*
387
* \parm parmAsAuto
388
* For a \parm node with parm symbol, the API is used in two different ways because the slot for dead
389
* parm symbol can be reused for variables of any type. When \parm parmAsAuto is true, parm is
390
* treated as other auto and the type signature is ignored. When \parm parmAsAuto is false, the
391
* type signature of the parm is used for telling the actual type.
392
*/
393
bool TR_BoolArrayStoreTransformer::isBoolArrayNode(TR::Node *node, bool parmAsAuto)
394
{
395
if (parmAsAuto && node->getOpCode().hasSymbolReference() && node->getSymbolReference()->getSymbol()->isParm())
396
return false;
397
return getArrayDimension(node, true /*boolType*/, parmAsAuto) == 1;
398
}
399
400
/*
401
* \brief
402
* Answer includes one dimension byte array only
403
*
404
* \parm node
405
*
406
* \parm parmAsAuto
407
* For a \parm node with parm symbol, the API is used in two different ways because the slot for dead
408
* parm symbol can be reused for variables of any type. When \parm parmAsAuto is true, parm is
409
* treated as other auto and the type signature is ignored. When \parm parmAsAuto is false, the
410
* type signature of the parm is used for telling the actual type.
411
*/
412
bool TR_BoolArrayStoreTransformer::isByteArrayNode(TR::Node *node, bool parmAsAuto)
413
{
414
if (parmAsAuto && node->getOpCode().hasSymbolReference() && node->getSymbolReference()->getSymbol()->isParm())
415
return false;
416
return getArrayDimension(node, false /*boolType*/, parmAsAuto) == 1;
417
}
418
419
/*
420
* Answer includes one dimension boolean array only
421
*/
422
bool TR_BoolArrayStoreTransformer::isBoolArrayParm(TR::ParameterSymbol *symbol)
423
{
424
int length;
425
const char *signature = symbol->getTypeSignature(length);
426
return getArrayDimension(signature, length, true /*boolType*/) == 1;
427
}
428
429
/*
430
* Answer includes one dimension byte array only
431
*/
432
bool TR_BoolArrayStoreTransformer::isByteArrayParm(TR::ParameterSymbol *symbol)
433
{
434
int length;
435
const char *signature = symbol->getTypeSignature(length);
436
return getArrayDimension(signature, length, false /*boolType*/) == 1;
437
}
438
439
int TR_BoolArrayStoreTransformer::getArrayDimension(const char * signature, int length, bool boolType)
440
{
441
char expectedTypeChar = boolType? 'Z' : 'B';
442
return (signature && length >= 2 && signature[length-1] == expectedTypeChar && signature[length-2] == '[') ? length-1: -1;
443
}
444
445
/*
446
* \brief
447
* Get dimension of the array of given type
448
*
449
* \parm node
450
* The node to look at
451
*
452
* \parm boolType
453
* True if asking for boolean array and false if asking for byte array
454
*
455
* \return
456
* The dimension of the array of given type. Return -1 if the node is not the
457
* given type.
458
*/
459
int TR_BoolArrayStoreTransformer::getArrayDimension(TR::Node *node, bool boolType, bool parmAsAuto)
460
{
461
int nodeArrayDimension = -1;
462
if (node->getOpCodeValue() == TR::newarray)
463
{
464
int32_t expectedTypeValue = boolType ? 4: 8;
465
TR::Node *arrayTypeNode = node->getSecondChild();
466
TR_ASSERT(arrayTypeNode->getOpCode().isLoadConst(), "expect the second child of TR::newarray to be constant " POINTER_PRINTF_FORMAT, arrayTypeNode);
467
if (arrayTypeNode->getInt() == expectedTypeValue)
468
nodeArrayDimension = 1;
469
}
470
else
471
{
472
int length;
473
const char * signature = node->getTypeSignature(length, stackAlloc, parmAsAuto);
474
nodeArrayDimension = getArrayDimension(signature, length, boolType);
475
}
476
return nodeArrayDimension;
477
}
478
479
/*
480
* \brief
481
* Find all the loads of autos or parms in a subtree and figure out its type
482
* first time the load is referenced.
483
*
484
* \parm node
485
* The subtree to look at
486
*
487
* \parm typeInfo
488
* The type information of each auto at the current subtree
489
*
490
* \parm boolArrayNodes
491
* Load of autos or parms that are [Z
492
*
493
* \parm byteArrayNodes
494
* Load of autos or parms that are [B
495
*
496
* \parm visitedNodes
497
* All the nodes in the containing block. A node is added to this list the first time seen in the trees
498
*/
499
void TR_BoolArrayStoreTransformer::findLoadAddressAutoAndFigureOutType(TR::Node *node, TypeInfo * typeInfo, TR::NodeChecklist &boolArrayNodes, TR::NodeChecklist &byteArrayNodes, TR::NodeChecklist &visitedNodes)
500
{
501
if (visitedNodes.contains(node))
502
return;
503
504
for (int i = 0; i < node->getNumChildren(); i++)
505
findLoadAddressAutoAndFigureOutType(node->getChild(i), typeInfo, boolArrayNodes, byteArrayNodes, visitedNodes);
506
507
if (node->getType() == TR::Address && node->getOpCode().isLoadDirect() && node->getOpCode().hasSymbolReference() &&
508
node->getSymbolReference()->getSymbol()->isAutoOrParm() && !visitedNodes.contains(node))
509
{
510
TR_YesNoMaybe type = (*typeInfo)[node->getSymbolReference()->getSymbol()->getLocalIndex()];
511
if (type == TR_yes)
512
boolArrayNodes.add(node);
513
else if (type == TR_no)
514
byteArrayNodes.add(node);
515
}
516
visitedNodes.add(node);
517
}
518
519
/*
520
* \brief
521
* This function calculcates the type info of each auto and figure out whether a
522
* bstorei node is for boolean array
523
*
524
* \parm block
525
* The block to process
526
*
527
* \parm blockStartTypeInfo
528
* The auto type info at block start
529
*
530
* \return currentTypeInfo
531
* The working auto type info
532
*
533
* \note
534
* For each load of auto, record whether the type is boolean array (TR_yes), byte array type
535
* (TR_no), other or unknown type (TR_maybe). For each store of auto, propagate the type from
536
* right hand side to the left hand side auto.
537
*/
538
TR_BoolArrayStoreTransformer::TypeInfo * TR_BoolArrayStoreTransformer::processBlock(TR::Block *block, TR_BoolArrayStoreTransformer::TypeInfo *blockStartTypeInfo)
539
{
540
TR_BoolArrayStoreTransformer::TypeInfo *currentTypeInfo = blockStartTypeInfo;
541
TR::NodeChecklist boolArrayNodes(comp());
542
TR::NodeChecklist byteArrayNodes(comp());
543
TR::NodeChecklist visitedNodes(comp());
544
545
if (comp()->getOption(TR_TraceILGen))
546
{
547
traceMsg(comp(), "start processing block_%d: ", block->getNumber());
548
if (currentTypeInfo)
549
printTypeInfo(currentTypeInfo, comp());
550
traceMsg(comp(), "\n");
551
}
552
553
for (TR::TreeTop *tt = block->getEntry(); tt != block->getExit(); tt = tt->getNextTreeTop())
554
{
555
TR::Node *node = tt->getNode();
556
// find all aload auto from the current tree top first
557
if (currentTypeInfo)
558
findLoadAddressAutoAndFigureOutType(node, currentTypeInfo, boolArrayNodes, byteArrayNodes, visitedNodes);
559
560
if (node->getOpCode().isStoreDirect() && node->getSymbolReference()->getSymbol()->isAutoOrParm())
561
{
562
TR::Node *rhs = node->getFirstChild();
563
TR::Symbol *local = node->getSymbolReference()->getSymbol();
564
if (rhs->getDataType().isAddress())
565
{
566
TR_YesNoMaybe newType = TR_maybe;
567
if (isBoolArrayNode(rhs, _hasVariantArgs) || boolArrayNodes.contains(rhs))
568
newType = TR_yes;
569
else if (isByteArrayNode(rhs, _hasVariantArgs) || byteArrayNodes.contains(rhs))
570
newType = TR_no;
571
572
if (newType != TR_maybe || currentTypeInfo)
573
{
574
if (!currentTypeInfo)
575
currentTypeInfo = new (comp()->trMemory()->currentStackRegion()) TypeInfo(_numLocals, TR_maybe, comp()->trMemory()->currentStackRegion());
576
if (comp()->getOption(TR_TraceILGen))
577
{
578
char newTypeBuffer[15];
579
char oldTypeBuffer[15];
580
TR_YesNoMaybe oldType = (*currentTypeInfo)[local->getLocalIndex()];
581
traceMsg(comp(), "Local #%2d %s -> %s at node n%dn\n", local->getLocalIndex(), getTypeName(oldType, oldTypeBuffer), getTypeName(newType, newTypeBuffer), node->getGlobalIndex());
582
}
583
(*currentTypeInfo)[local->getLocalIndex()] = newType;
584
}
585
}
586
}
587
else if (node->getOpCodeValue() == TR::bstorei && (_bstoreiUnknownArrayTypeNodes->find(node) != _bstoreiUnknownArrayTypeNodes->end()))
588
{
589
_NumOfBstoreiNodesToVisit--;
590
TR_ASSERT(node->getFirstChild()->isInternalPointer(), "node in _bstoreiUnknownArrayTypeNodes can only be array store");
591
TR::Node *arrayBaseNode = node->getFirstChild()->getFirstChild();
592
if (boolArrayNodes.contains(arrayBaseNode))
593
{
594
if (comp()->getOption(TR_TraceILGen))
595
{
596
char buffer[15];
597
traceMsg(comp(), "bstorei node n%dn is %s\n", node->getGlobalIndex(), getTypeName(TR_yes, buffer));
598
}
599
_bstoreiUnknownArrayTypeNodes->erase(node);
600
_bstoreiBoolArrayTypeNodes->insert(node);
601
}
602
else if (byteArrayNodes.contains(arrayBaseNode))
603
{
604
if (comp()->getOption(TR_TraceILGen))
605
{
606
char buffer[15];
607
traceMsg(comp(), "bstorei node n%dn is %s\n", node->getGlobalIndex(), getTypeName(TR_no, buffer));
608
}
609
_bstoreiUnknownArrayTypeNodes->erase(node);
610
}
611
}
612
else if (node->getOpCode().isCheckCast())
613
{
614
TR::Node *typeNode = node->getSecondChild();
615
TR::Node *checkcastedNode = node->getFirstChild();
616
if (isBoolArrayNode(typeNode))
617
{
618
if (byteArrayNodes.contains(checkcastedNode)) // this can happen when [Z and [B are merged at one point
619
byteArrayNodes.remove(checkcastedNode);
620
if (comp()->getOption(TR_TraceILGen))
621
traceMsg(comp(), "checkcast node n%dn force node n%dn to be [Z\n", node->getGlobalIndex(), checkcastedNode->getGlobalIndex());
622
boolArrayNodes.add(checkcastedNode);
623
}
624
else if (isByteArrayNode(typeNode))
625
{
626
if (boolArrayNodes.contains(checkcastedNode)) // this can happen when [Z and [B are merged at one point
627
boolArrayNodes.remove(checkcastedNode);
628
if (comp()->getOption(TR_TraceILGen))
629
traceMsg(comp(), "checkcast node n%dn force node n%dn to be [B\n", node->getGlobalIndex(), checkcastedNode->getGlobalIndex());
630
byteArrayNodes.add(checkcastedNode);
631
}
632
}
633
}
634
635
if (comp()->getOption(TR_TraceILGen))
636
{
637
traceMsg(comp(), "end processing block_%d: ", block->getNumber());
638
if (currentTypeInfo)
639
printTypeInfo(currentTypeInfo, comp());
640
traceMsg(comp(), "\n");
641
}
642
643
return currentTypeInfo;
644
}
645
646
/* \brief
647
* Generating nodes to and the value to be stored to the array with the provided mask
648
*
649
* \parm bstoreiNode
650
*
651
* \parm int mask
652
*
653
* \note
654
* Transform bstorei node from:
655
* bstorei
656
* aladd (internal pointer)
657
* ...
658
* value node
659
*
660
* to:
661
* bstorei
662
* aladd (internal pointer)
663
* ...
664
* i2b
665
* iand
666
* b2i
667
* value node
668
* mask node
669
*/
670
static void generateiAndNode(TR::Node *bstoreiNode, TR::Node *mask, TR::Compilation *comp)
671
{
672
if (comp->getOption(TR_TraceILGen))
673
traceMsg(comp, "truncating mask node n%dn\n", mask->getGlobalIndex());
674
TR::Node *bValueChild = bstoreiNode->getSecondChild();
675
TR::Node *iValueChild = TR::Node::create(bstoreiNode, TR::b2i, 1, bValueChild);
676
TR::Node *iandNode = TR::Node::create(bstoreiNode, TR::iand, 2, iValueChild, mask);
677
TR::Node *i2bNode = TR::Node::create(bstoreiNode, TR::i2b, 1, iandNode);
678
bstoreiNode->setAndIncChild(1, i2bNode);
679
bValueChild->decReferenceCount();
680
}
681
682
/*
683
* \brief
684
* For bstorei with unknown type info, and the value to be stored with a mask.
685
*
686
* \note
687
* The mask value is calculated based on runtime array type info:
688
* mask = (class of array base node == J9class of [Z ? 1: 0)*2 - 1. It's 1 for
689
* boolean array and -1 (0xFFFFFFFF) for byte array.
690
691
* Mask calculation in tree:
692
* iadd
693
* ishl
694
* acmpeq
695
* aloadi <vft-symbol>
696
* => array base node
697
* aconst [Z J9Class
698
* 2
699
* iconst -1 (0xffffffff)
700
*/
701
void TR_BoolArrayStoreTransformer::transformUnknownTypeArrayStore()
702
{
703
TR_J9VMBase *fej9 = (TR_J9VMBase *)(comp()->fe());
704
// this check should be deleted after the new AOT work is delivered
705
if (fej9->isAOT_DEPRECATED_DO_NOT_USE())
706
return;
707
//get j9class of [Z
708
uintptr_t j9class = (uintptr_t) fej9->getClassFromNewArrayType(4);
709
for (auto it = _bstoreiUnknownArrayTypeNodes->begin(); it != _bstoreiUnknownArrayTypeNodes->end(); it++)
710
{
711
TR::Node *bstoreiNode = *it;
712
dumpOptDetails(comp(), "%s transform value child of bstorei node of unknown type n%dn\n", OPT_DETAILS, bstoreiNode->getGlobalIndex());
713
TR::Node *arrayBaseNode = bstoreiNode->getFirstChild()->getFirstChild();
714
TR::Node *vft = TR::Node::createWithSymRef(TR::aloadi, 1, 1, arrayBaseNode, comp()->getSymRefTab()->findOrCreateVftSymbolRef());
715
TR::Node *aconstNode = TR::Node::aconst(bstoreiNode, j9class);
716
aconstNode->setIsClassPointerConstant(true);
717
TR::Node *compareNode = TR::Node::create(arrayBaseNode, TR::acmpeq, 2, vft, aconstNode);
718
TR::Node *shift1Node = TR::Node::create(TR::ishl, 2 , compareNode, TR::Node::iconst(bstoreiNode, 1));
719
TR::Node *iandMaskNode = TR::Node::create(TR::iadd, 2 , shift1Node, TR::Node::iconst(bstoreiNode, -1));
720
generateiAndNode(bstoreiNode, iandMaskNode, comp());
721
}
722
}
723
724
void TR_BoolArrayStoreTransformer::transformBoolArrayStoreNodes()
725
{
726
for (auto it = _bstoreiBoolArrayTypeNodes->begin(); it != _bstoreiBoolArrayTypeNodes->end(); it++)
727
{
728
TR::Node *node = *it;
729
dumpOptDetails(comp(), "%s truncate value child of bstorei node n%dn to 1 bit\n", OPT_DETAILS, node->getGlobalIndex());
730
generateiAndNode(node, TR::Node::iconst(node, 1), comp());
731
}
732
}
733
734