@@ -1371,10 +1371,27 @@ inline int Parse::repush_if_args() {
1371
1371
return bc_depth;
1372
1372
}
1373
1373
1374
+ // Used by StressUnstableIfTraps
1375
+ static volatile int _trap_stress_counter = 0 ;
1376
+
1377
+ void Parse::increment_trap_stress_counter (Node*& counter, Node*& incr_store) {
1378
+ Node* counter_addr = makecon (TypeRawPtr::make ((address)&_trap_stress_counter));
1379
+ counter = make_load (control (), counter_addr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, MemNode::unordered);
1380
+ counter = _gvn.transform (new AddINode (counter, intcon (1 )));
1381
+ incr_store = store_to_memory (control (), counter_addr, counter, T_INT, Compile::AliasIdxRaw, MemNode::unordered);
1382
+ }
1383
+
1374
1384
// ----------------------------------do_ifnull----------------------------------
1375
1385
void Parse::do_ifnull (BoolTest::mask btest, Node *c) {
1376
1386
int target_bci = iter ().get_dest ();
1377
1387
1388
+ Node* counter = nullptr ;
1389
+ Node* incr_store = nullptr ;
1390
+ bool do_stress_trap = StressUnstableIfTraps && ((C->random () % 2 ) == 0 );
1391
+ if (do_stress_trap) {
1392
+ increment_trap_stress_counter (counter, incr_store);
1393
+ }
1394
+
1378
1395
Block* branch_block = successor_for_bci (target_bci);
1379
1396
Block* next_block = successor_for_bci (iter ().next_bci ());
1380
1397
@@ -1439,6 +1456,10 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) {
1439
1456
} else { // Path is live.
1440
1457
adjust_map_after_if (BoolTest (btest).negate (), c, 1.0 -prob, next_block);
1441
1458
}
1459
+
1460
+ if (do_stress_trap) {
1461
+ stress_trap (iff, counter, incr_store);
1462
+ }
1442
1463
}
1443
1464
1444
1465
// ------------------------------------do_if------------------------------------
@@ -1468,6 +1489,13 @@ void Parse::do_if(BoolTest::mask btest, Node* c) {
1468
1489
return ;
1469
1490
}
1470
1491
1492
+ Node* counter = nullptr ;
1493
+ Node* incr_store = nullptr ;
1494
+ bool do_stress_trap = StressUnstableIfTraps && ((C->random () % 2 ) == 0 );
1495
+ if (do_stress_trap) {
1496
+ increment_trap_stress_counter (counter, incr_store);
1497
+ }
1498
+
1471
1499
// Sanity check the probability value
1472
1500
assert (0 .0f < prob && prob < 1 .0f ," Bad probability in Parser" );
1473
1501
@@ -1550,9 +1578,58 @@ void Parse::do_if(BoolTest::mask btest, Node* c) {
1550
1578
} else {
1551
1579
adjust_map_after_if (untaken_btest, c, untaken_prob, next_block);
1552
1580
}
1581
+
1582
+ if (do_stress_trap) {
1583
+ stress_trap (iff, counter, incr_store);
1584
+ }
1585
+ }
1586
+
1587
+ // Force unstable if traps to be taken randomly to trigger intermittent bugs such as incorrect debug information.
1588
+ // Add another if before the unstable if that checks a "random" condition at runtime (a simple shared counter) and
1589
+ // then either takes the trap or executes the original, unstable if.
1590
+ void Parse::stress_trap (IfNode* orig_iff, Node* counter, Node* incr_store) {
1591
+ // Search for an unstable if trap
1592
+ CallStaticJavaNode* trap = nullptr ;
1593
+ assert (orig_iff->Opcode () == Op_If && orig_iff->outcnt () == 2 , " malformed if" );
1594
+ ProjNode* trap_proj = orig_iff->uncommon_trap_proj (trap, Deoptimization::Reason_unstable_if);
1595
+ if (trap == nullptr || !trap->jvms ()->should_reexecute ()) {
1596
+ // No suitable trap found. Remove unused counter load and increment.
1597
+ C->gvn_replace_by (incr_store, incr_store->in (MemNode::Memory));
1598
+ return ;
1599
+ }
1600
+
1601
+ // Remove trap from optimization list since we add another path to the trap.
1602
+ bool success = C->remove_unstable_if_trap (trap, true );
1603
+ assert (success, " Trap already modified" );
1604
+
1605
+ // Add a check before the original if that will trap with a certain frequency and execute the original if otherwise
1606
+ int freq_log = (C->random () % 31 ) + 1 ; // Random logarithmic frequency in [1, 31]
1607
+ Node* mask = intcon (right_n_bits (freq_log));
1608
+ counter = _gvn.transform (new AndINode (counter, mask));
1609
+ Node* cmp = _gvn.transform (new CmpINode (counter, intcon (0 )));
1610
+ Node* bol = _gvn.transform (new BoolNode (cmp, BoolTest::mask::eq));
1611
+ IfNode* iff = _gvn.transform (new IfNode (orig_iff->in (0 ), bol, orig_iff->_prob , orig_iff->_fcnt ))->as_If ();
1612
+ Node* if_true = _gvn.transform (new IfTrueNode (iff));
1613
+ Node* if_false = _gvn.transform (new IfFalseNode (iff));
1614
+ assert (!if_true->is_top () && !if_false->is_top (), " trap always / never taken" );
1615
+
1616
+ // Trap
1617
+ assert (trap_proj->outcnt () == 1 , " some other nodes are dependent on the trap projection" );
1618
+
1619
+ Node* trap_region = new RegionNode (3 );
1620
+ trap_region->set_req (1 , trap_proj);
1621
+ trap_region->set_req (2 , if_true);
1622
+ trap->set_req (0 , _gvn.transform (trap_region));
1623
+
1624
+ // Don't trap, execute original if
1625
+ orig_iff->set_req (0 , if_false);
1553
1626
}
1554
1627
1555
1628
bool Parse::path_is_suitable_for_uncommon_trap (float prob) const {
1629
+ // Randomly skip emitting an uncommon trap
1630
+ if (StressUnstableIfTraps && ((C->random () % 2 ) == 0 )) {
1631
+ return false ;
1632
+ }
1556
1633
// Don't want to speculate on uncommon traps when running with -Xcomp
1557
1634
if (!UseInterpreter) {
1558
1635
return false ;
0 commit comments