Skip to content

Commit e203df4

Browse files
rwestreleme64
andcommittedSep 5, 2024
8338100: C2: assert(!n_loop->is_member(get_loop(lca))) failed: control must not be back in the loop
Co-authored-by: Emanuel Peter <epeter@openjdk.org> Reviewed-by: chagedorn, thartmann
1 parent 98020e4 commit e203df4

7 files changed

+276
-51
lines changed
 

‎src/hotspot/share/opto/loopnode.cpp

+35-45
Original file line numberDiff line numberDiff line change
@@ -4511,23 +4511,6 @@ bool PhaseIdealLoop::process_expensive_nodes() {
45114511
return progress;
45124512
}
45134513

4514-
#ifdef ASSERT
4515-
// Goes over all children of the root of the loop tree. Check if any of them have a path
4516-
// down to Root, that does not go via a NeverBranch exit.
4517-
bool PhaseIdealLoop::only_has_infinite_loops() {
4518-
ResourceMark rm;
4519-
Unique_Node_List worklist;
4520-
// start traversal at all loop heads of first-level loops
4521-
for (IdealLoopTree* l = _ltree_root->_child; l != nullptr; l = l->_next) {
4522-
Node* head = l->_head;
4523-
assert(head->is_Region(), "");
4524-
worklist.push(head);
4525-
}
4526-
return RegionNode::are_all_nodes_in_infinite_subgraph(worklist);
4527-
}
4528-
#endif
4529-
4530-
45314514
//=============================================================================
45324515
//----------------------------build_and_optimize-------------------------------
45334516
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
@@ -4586,13 +4569,9 @@ void PhaseIdealLoop::build_and_optimize() {
45864569
return;
45874570
}
45884571

4589-
// Verify that the has_loops() flag set at parse time is consistent
4590-
// with the just built loop tree. With infinite loops, it could be
4591-
// that one pass of loop opts only finds infinite loops, clears the
4592-
// has_loops() flag but adds NeverBranch nodes so the next loop opts
4593-
// verification pass finds a non empty loop tree. When the back edge
4572+
// Verify that the has_loops() flag set at parse time is consistent with the just built loop tree. When the back edge
45944573
// is an exception edge, parsing doesn't set has_loops().
4595-
assert(_ltree_root->_child == nullptr || C->has_loops() || only_has_infinite_loops() || C->has_exception_backedge(), "parsing found no loops but there are some");
4574+
assert(_ltree_root->_child == nullptr || C->has_loops() || C->has_exception_backedge(), "parsing found no loops but there are some");
45964575
// No loops after all
45974576
if( !_ltree_root->_child && !_verify_only ) C->set_has_loops(false);
45984577

@@ -5425,7 +5404,7 @@ void PhaseIdealLoop::build_loop_tree() {
54255404
if ( bltstack.length() == stack_size ) {
54265405
// There were no additional children, post visit node now
54275406
(void)bltstack.pop(); // Remove node from stack
5428-
pre_order = build_loop_tree_impl( n, pre_order );
5407+
pre_order = build_loop_tree_impl(n, pre_order);
54295408
// Check for bailout
54305409
if (C->failing()) {
54315410
return;
@@ -5443,7 +5422,7 @@ void PhaseIdealLoop::build_loop_tree() {
54435422
}
54445423

54455424
//------------------------------build_loop_tree_impl---------------------------
5446-
int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
5425+
int PhaseIdealLoop::build_loop_tree_impl(Node* n, int pre_order) {
54475426
// ---- Post-pass Work ----
54485427
// Pre-walked but not post-walked nodes need a pre_order number.
54495428

@@ -5454,24 +5433,24 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
54545433
// for it. Then find the tightest enclosing loop for the self Node.
54555434
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
54565435
Node* m = n->fast_out(i); // Child
5457-
if( n == m ) continue; // Ignore control self-cycles
5458-
if( !m->is_CFG() ) continue;// Ignore non-CFG edges
5436+
if (n == m) continue; // Ignore control self-cycles
5437+
if (!m->is_CFG()) continue;// Ignore non-CFG edges
54595438

54605439
IdealLoopTree *l; // Child's loop
5461-
if( !is_postvisited(m) ) { // Child visited but not post-visited?
5440+
if (!is_postvisited(m)) { // Child visited but not post-visited?
54625441
// Found a backedge
5463-
assert( get_preorder(m) < pre_order, "should be backedge" );
5442+
assert(get_preorder(m) < pre_order, "should be backedge");
54645443
// Check for the RootNode, which is already a LoopNode and is allowed
54655444
// to have multiple "backedges".
5466-
if( m == C->root()) { // Found the root?
5445+
if (m == C->root()) { // Found the root?
54675446
l = _ltree_root; // Root is the outermost LoopNode
54685447
} else { // Else found a nested loop
54695448
// Insert a LoopNode to mark this loop.
54705449
l = new IdealLoopTree(this, m, n);
54715450
} // End of Else found a nested loop
5472-
if( !has_loop(m) ) // If 'm' does not already have a loop set
5451+
if (!has_loop(m)) { // If 'm' does not already have a loop set
54735452
set_loop(m, l); // Set loop header to loop now
5474-
5453+
}
54755454
} else { // Else not a nested loop
54765455
if (!_loop_or_ctrl[m->_idx]) continue; // Dead code has no loop
54775456
IdealLoopTree* m_loop = get_loop(m);
@@ -5480,23 +5459,17 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
54805459
// is a member of some outer enclosing loop. Since there are no
54815460
// shared headers (I've split them already) I only need to go up
54825461
// at most 1 level.
5483-
while( l && l->_head == m ) // Successor heads loop?
5462+
while (l && l->_head == m) { // Successor heads loop?
54845463
l = l->_parent; // Move up 1 for me
5464+
}
54855465
// If this loop is not properly parented, then this loop
54865466
// has no exit path out, i.e. its an infinite loop.
5487-
if( !l ) {
5467+
if (!l) {
54885468
// Make loop "reachable" from root so the CFG is reachable. Basically
54895469
// insert a bogus loop exit that is never taken. 'm', the loop head,
54905470
// points to 'n', one (of possibly many) fall-in paths. There may be
54915471
// many backedges as well.
54925472

5493-
// Here I set the loop to be the root loop. I could have, after
5494-
// inserting a bogus loop exit, restarted the recursion and found my
5495-
// new loop exit. This would make the infinite loop a first-class
5496-
// loop and it would then get properly optimized. What's the use of
5497-
// optimizing an infinite loop?
5498-
l = _ltree_root; // Oops, found infinite loop
5499-
55005473
if (!_verify_only) {
55015474
// Insert the NeverBranch between 'm' and it's control user.
55025475
NeverBranchNode *iff = new NeverBranchNode( m );
@@ -5520,7 +5493,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
55205493
// Now create the never-taken loop exit
55215494
Node *if_f = new CProjNode( iff, 1 );
55225495
_igvn.register_new_node_with_optimizer(if_f);
5523-
set_loop(if_f, l);
5496+
set_loop(if_f, _ltree_root);
55245497
// Find frame ptr for Halt. Relies on the optimizer
55255498
// V-N'ing. Easier and quicker than searching through
55265499
// the program structure.
@@ -5529,10 +5502,27 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
55295502
// Halt & Catch Fire
55305503
Node* halt = new HaltNode(if_f, frame, "never-taken loop exit reached");
55315504
_igvn.register_new_node_with_optimizer(halt);
5532-
set_loop(halt, l);
5505+
set_loop(halt, _ltree_root);
55335506
_igvn.add_input_to(C->root(), halt);
55345507
}
55355508
set_loop(C->root(), _ltree_root);
5509+
// move to outer most loop with same header
5510+
l = m_loop;
5511+
while (true) {
5512+
IdealLoopTree* next = l->_parent;
5513+
if (next == nullptr || next->_head != m) {
5514+
break;
5515+
}
5516+
l = next;
5517+
}
5518+
// properly insert infinite loop in loop tree
5519+
sort(_ltree_root, l);
5520+
// fix child link from parent
5521+
IdealLoopTree* p = l->_parent;
5522+
l->_next = p->_child;
5523+
p->_child = l;
5524+
// code below needs enclosing loop
5525+
l = l->_parent;
55365526
}
55375527
}
55385528
if (is_postvisited(l->_head)) {
@@ -5586,7 +5576,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
55865576
assert( get_loop(n) == innermost, "" );
55875577
IdealLoopTree *p = innermost->_parent;
55885578
IdealLoopTree *l = innermost;
5589-
while( p && l->_head == n ) {
5579+
while (p && l->_head == n) {
55905580
l->_next = p->_child; // Put self on parents 'next child'
55915581
p->_child = l; // Make self as first child of parent
55925582
l = p; // Now walk up the parent chain
@@ -5600,7 +5590,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
56005590
// Record tightest enclosing loop for self. Mark as post-visited.
56015591
set_loop(n, innermost);
56025592
// Also record has_call flag early on
5603-
if( innermost ) {
5593+
if (innermost) {
56045594
if( n->is_Call() && !n->is_CallLeaf() && !n->is_macro() ) {
56055595
// Do not count uncommon calls
56065596
if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) {

‎src/hotspot/share/opto/loopnode.hpp

+1-5
Original file line numberDiff line numberDiff line change
@@ -966,10 +966,6 @@ class PhaseIdealLoop : public PhaseTransform {
966966
const Node_List& old_new);
967967
void insert_loop_limit_check_predicate(ParsePredicateSuccessProj* loop_limit_check_parse_proj, Node* cmp_limit,
968968
Node* bol);
969-
#ifdef ASSERT
970-
bool only_has_infinite_loops();
971-
#endif
972-
973969
void log_loop_tree();
974970

975971
public:
@@ -1076,7 +1072,7 @@ class PhaseIdealLoop : public PhaseTransform {
10761072

10771073
// Place 'n' in some loop nest, where 'n' is a CFG node
10781074
void build_loop_tree();
1079-
int build_loop_tree_impl( Node *n, int pre_order );
1075+
int build_loop_tree_impl(Node* n, int pre_order);
10801076
// Insert loop into the existing loop tree. 'innermost' is a leaf of the
10811077
// loop tree, not the root.
10821078
IdealLoopTree *sort( IdealLoopTree *loop, IdealLoopTree *innermost );

‎src/hotspot/share/opto/parse1.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1651,7 +1651,7 @@ void Parse::merge_new_path(int target_bci) {
16511651
// The ex_oop must be pushed on the stack, unlike throw_to_exit.
16521652
void Parse::merge_exception(int target_bci) {
16531653
#ifdef ASSERT
1654-
if (target_bci < bci()) {
1654+
if (target_bci <= bci()) {
16551655
C->set_exception_backedge();
16561656
}
16571657
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
super public class LongCountedLoopInInfiniteLoop
25+
{
26+
public Method "<init>":"()V"
27+
stack 1 locals 1
28+
{
29+
aload_0;
30+
invokespecial Method java/lang/Object."<init>":"()V";
31+
return;
32+
}
33+
Method test:"()V"
34+
stack 3 locals 3
35+
{
36+
// #1 = 0;
37+
iconst_0;
38+
istore_1;
39+
40+
LOOPa:
41+
// if #1 >= 10: goto END
42+
iload_1;
43+
bipush 10;
44+
if_icmpge END;
45+
46+
// if #1 > 1: goto LOOPc
47+
iload_1;
48+
iconst_1;
49+
if_icmpgt LOOPc;
50+
51+
// #2 = 0;
52+
iconst_0;
53+
istore_2;
54+
55+
LOOPb:
56+
// if #2 > 2: goto LOOPa
57+
iload_2;
58+
iconst_2;
59+
if_icmpgt LOOPa;
60+
61+
// #2 ++
62+
iinc 2, 1;
63+
64+
goto LOOPb;
65+
66+
LOOPc:
67+
// #1 ++
68+
iinc 1, 1;
69+
70+
goto LOOPa;
71+
72+
END:
73+
return;
74+
75+
}
76+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
super public class MoveStoreAfterInfiniteLoop
25+
{
26+
static Field a:I;
27+
static Field b:I;
28+
static Field c:S;
29+
30+
public Method "<init>":"()V"
31+
stack 1 locals 1
32+
{
33+
aload_0;
34+
invokespecial Method java/lang/Object."<init>":"()V";
35+
return;
36+
}
37+
38+
public static Method test:"()V"
39+
stack 3 locals 3
40+
{
41+
LTOP:
42+
iconst_0;
43+
istore_1;
44+
45+
LOUTER:
46+
iload_1;
47+
bipush 10;
48+
if_icmpge LTOP;
49+
50+
getstatic Field c:"S";
51+
putstatic Field a:"I";
52+
53+
iconst_0;
54+
istore_2;
55+
56+
LINNER:
57+
iload_2;
58+
iconst_2;
59+
if_icmpge LBOTTOM;
60+
61+
getstatic Field b:"I";
62+
i2s;
63+
putstatic Field c:"S";
64+
65+
iinc 2, 1;
66+
67+
goto LINNER;
68+
69+
LBOTTOM:
70+
iinc 1, 1;
71+
72+
goto LOUTER;
73+
}
74+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2024, Red Hat, Inc. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8336478
27+
* @summary C2: assert(!n->as_Loop()->is_loop_nest_inner_loop() || _loop_opts_cnt == 0) failed: should have been turned into a counted loop
28+
* @compile LongCountedLoopInInfiniteLoop.jasm
29+
* @run main/othervm -XX:+UnlockExperimentalVMOptions -Xcomp -XX:PerMethodTrapLimit=0 -XX:PerMethodSpecTrapLimit=0
30+
* -XX:+IgnoreUnrecognizedVMOptions -XX:StressLongCountedLoop=2000000
31+
* -XX:CompileCommand=compileonly,TestLongCountedLoopInInfiniteLoop::test TestLongCountedLoopInInfiniteLoop
32+
*/
33+
34+
public class TestLongCountedLoopInInfiniteLoop {
35+
public static void main(String[] args) {
36+
LongCountedLoopInInfiniteLoop obj = new LongCountedLoopInInfiniteLoop();
37+
test(false, obj);
38+
}
39+
40+
private static void test(boolean flag, LongCountedLoopInInfiniteLoop obj) {
41+
if (flag) {
42+
obj.test();
43+
}
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright (c) 2024, Red Hat, Inc. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/*
25+
* @test
26+
* @bug 8338100
27+
* @summary C2: assert(!n_loop->is_member(get_loop(lca))) failed: control must not be back in the loop
28+
* @compile MoveStoreAfterInfiniteLoop.jasm
29+
* @run main/othervm -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestMoveStoreAfterInfiniteLoop::test
30+
* -XX:CompileCommand=inline,MoveStoreAfterInfiniteLoop::test TestMoveStoreAfterInfiniteLoop
31+
*/
32+
33+
public class TestMoveStoreAfterInfiniteLoop {
34+
public static void main(String[] args) {
35+
new MoveStoreAfterInfiniteLoop();
36+
test(false);
37+
}
38+
39+
private static void test(boolean flag) {
40+
if (flag) {
41+
MoveStoreAfterInfiniteLoop.test();
42+
}
43+
}
44+
}

0 commit comments

Comments
 (0)
Please sign in to comment.