@@ -284,20 +284,23 @@ static void moveBlockAfterDest(TR::CFG *cfg, TR::Block *toMove, TR::Block *dest)
284
284
}
285
285
286
286
// This opt tries to reduce merge backs from cold code that are the result of inliner
287
- // gnerated nopable virtual guards
287
+ // generated nopable virtual guards
288
288
// It looks for one basic pattern
289
289
//
290
290
// guard1 -> cold1
291
291
// BBEND
292
292
// BBSTART
293
293
// guard2 -> cold2
294
- // if guard1 is the guard for a method which calls the method guard2 protects or cold1 is
295
- // a predecessor of cold2 (a situation commonly greated by virtual guard tail splitter) we
296
- // can transform the guards as follows when guard1 and guard2 a
294
+ //
295
+ // If guard1 is the guard for a method which calls the method guard2 protects or cold1 is
296
+ // a predecessor of cold2 (a situation commonly created by virtual guard tail splitter) we
297
+ // can transform the guards as follows:
298
+ //
297
299
// guard1 -> cold1
298
300
// BBEND
299
301
// BBSTART
300
302
// guard2 -> cold1
303
+ //
301
304
// This is safe because there are no trees between the guards and calling the caller will
302
305
// result in the call to the callee if we need to patch guard2. cold2 and its mergebacks
303
306
// can then be eliminated
@@ -383,6 +386,14 @@ int32_t TR_VirtualGuardHeadMerger::perform() {
383
386
// scan for candidate guards to merge with guard1 identified above
384
387
for (TR::Block *nextBlock = block->getNextBlock (); nextBlock; nextBlock = nextBlock->getNextBlock ())
385
388
{
389
+ if (block->nodeIsRemoved () || nextBlock->nodeIsRemoved ())
390
+ {
391
+ if (trace ())
392
+ traceMsg (comp (), " block block_%d %p (%d) or nextBlock block_%d %p (%d) has been removed\n " ,
393
+ block->getNumber (), block, block->nodeIsRemoved (), nextBlock->getNumber (), nextBlock, nextBlock->nodeIsRemoved ());
394
+ break ;
395
+ }
396
+
386
397
if (!(nextBlock->getPredecessors ().size () == 1 ) ||
387
398
!nextBlock->hasPredecessor (block))
388
399
{
@@ -467,6 +478,22 @@ int32_t TR_VirtualGuardHeadMerger::perform() {
467
478
if (guard2->getBranchDestination () != guard1->getBranchDestination ())
468
479
guard2Block->changeBranchDestination (guard1->getBranchDestination (), cfg);
469
480
481
+ // changeBranchDestination tries to remove unreachable blocks after the removal of the old edge
482
+ // from guard2 to cold2. Rarely, a previous transformation in this pass could have made
483
+ // guard2Block unreachable without removing it, in which case it might have been removed just now.
484
+ // Normally, if all relevant blocks are removed, later moveBlockAfterDest will not cause any issue
485
+ // since it will be just moving around all unreachable blocks. However, in an even more rare case,
486
+ // if some of the blocks are removed and some of them are not (eg, guard2Block and the previous block
487
+ // of guard2Block are removed but the next block of guard2Block is still valid), moveBlockAfterDest
488
+ // could end up joining an invalid/removed block with a valid block. Therefore, if guard2Block
489
+ // is no longer valid, it should not proceed.
490
+ if (guard2Block->nodeIsRemoved ())
491
+ {
492
+ if (trace ())
493
+ traceMsg (comp (), " guard2Block block_%d %p has been removed after changeBranchDestination\n " , guard2Block->getNumber (), guard2Block);
494
+ break ;
495
+ }
496
+
470
497
if (guard2Tree != guard2Block->getFirstRealTreeTop ())
471
498
{
472
499
cfg->setStructure (NULL );
@@ -477,7 +504,7 @@ int32_t TR_VirtualGuardHeadMerger::perform() {
477
504
// 2, it might contain live monitor, moving it up above a guard can affect the monitor's live range
478
505
if (!isStopTheWorldGuard (guard2))
479
506
{
480
- // the block created above guard2 contains only privarg treetops or monitor stores if
507
+ // the block created above guard2 contains only privarg treetops or monitor stores if
481
508
// guard2 is a runtime-patchable guard and is safe to merge. We need to move the priv
482
509
// args up to the runtime insert point and leave the monitor stores in place
483
510
// It's safe to do so because there is no data dependency between the monitor store and
0 commit comments