Skip to content

Commit e0d01d7

Browse files
committed
Backport e203df46faf610e35e2c2510271ad68199f4fa3f
1 parent 45ee88f commit e0d01d7

File tree

7 files changed

+276
-50
lines changed

7 files changed

+276
-50
lines changed

src/hotspot/share/opto/loopnode.cpp

Lines changed: 35 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -3930,23 +3930,6 @@ bool PhaseIdealLoop::process_expensive_nodes() {
39303930
return progress;
39313931
}
39323932

3933-
#ifdef ASSERT
3934-
// Goes over all children of the root of the loop tree. Check if any of them have a path
3935-
// down to Root, that does not go via a NeverBranch exit.
3936-
bool PhaseIdealLoop::only_has_infinite_loops() {
3937-
ResourceMark rm;
3938-
Unique_Node_List worklist;
3939-
// start traversal at all loop heads of first-level loops
3940-
for (IdealLoopTree* l = _ltree_root->_child; l != nullptr; l = l->_next) {
3941-
Node* head = l->_head;
3942-
assert(head->is_Region(), "");
3943-
worklist.push(head);
3944-
}
3945-
return RegionNode::are_all_nodes_in_infinite_subgraph(worklist);
3946-
}
3947-
#endif
3948-
3949-
39503933
//=============================================================================
39513934
//----------------------------build_and_optimize-------------------------------
39523935
// Create a PhaseLoop. Build the ideal Loop tree. Map each Ideal Node to
@@ -4005,13 +3988,9 @@ void PhaseIdealLoop::build_and_optimize() {
40053988
return;
40063989
}
40073990

4008-
// Verify that the has_loops() flag set at parse time is consistent
4009-
// with the just built loop tree. With infinite loops, it could be
4010-
// that one pass of loop opts only finds infinite loops, clears the
4011-
// has_loops() flag but adds NeverBranch nodes so the next loop opts
4012-
// verification pass finds a non empty loop tree. When the back edge
3991+
// Verify that the has_loops() flag set at parse time is consistent with the just built loop tree. When the back edge
40133992
// is an exception edge, parsing doesn't set has_loops().
4014-
assert(_ltree_root->_child == nullptr || C->has_loops() || only_has_infinite_loops() || C->has_exception_backedge(), "parsing found no loops but there are some");
3993+
assert(_ltree_root->_child == nullptr || C->has_loops() || C->has_exception_backedge(), "parsing found no loops but there are some");
40153994
// No loops after all
40163995
if( !_ltree_root->_child && !_verify_only ) C->set_has_loops(false);
40173996

@@ -4759,7 +4738,7 @@ void PhaseIdealLoop::build_loop_tree() {
47594738
if ( bltstack.length() == stack_size ) {
47604739
// There were no additional children, post visit node now
47614740
(void)bltstack.pop(); // Remove node from stack
4762-
pre_order = build_loop_tree_impl( n, pre_order );
4741+
pre_order = build_loop_tree_impl(n, pre_order);
47634742
// Check for bailout
47644743
if (C->failing()) {
47654744
return;
@@ -4776,7 +4755,7 @@ void PhaseIdealLoop::build_loop_tree() {
47764755
}
47774756

47784757
//------------------------------build_loop_tree_impl---------------------------
4779-
int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
4758+
int PhaseIdealLoop::build_loop_tree_impl(Node* n, int pre_order) {
47804759
// ---- Post-pass Work ----
47814760
// Pre-walked but not post-walked nodes need a pre_order number.
47824761

@@ -4787,24 +4766,24 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
47874766
// for it. Then find the tightest enclosing loop for the self Node.
47884767
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
47894768
Node* m = n->fast_out(i); // Child
4790-
if( n == m ) continue; // Ignore control self-cycles
4791-
if( !m->is_CFG() ) continue;// Ignore non-CFG edges
4769+
if (n == m) continue; // Ignore control self-cycles
4770+
if (!m->is_CFG()) continue;// Ignore non-CFG edges
47924771

47934772
IdealLoopTree *l; // Child's loop
4794-
if( !is_postvisited(m) ) { // Child visited but not post-visited?
4773+
if (!is_postvisited(m)) { // Child visited but not post-visited?
47954774
// Found a backedge
4796-
assert( get_preorder(m) < pre_order, "should be backedge" );
4775+
assert(get_preorder(m) < pre_order, "should be backedge");
47974776
// Check for the RootNode, which is already a LoopNode and is allowed
47984777
// to have multiple "backedges".
4799-
if( m == C->root()) { // Found the root?
4778+
if (m == C->root()) { // Found the root?
48004779
l = _ltree_root; // Root is the outermost LoopNode
48014780
} else { // Else found a nested loop
48024781
// Insert a LoopNode to mark this loop.
48034782
l = new IdealLoopTree(this, m, n);
48044783
} // End of Else found a nested loop
4805-
if( !has_loop(m) ) // If 'm' does not already have a loop set
4784+
if (!has_loop(m)) { // If 'm' does not already have a loop set
48064785
set_loop(m, l); // Set loop header to loop now
4807-
4786+
}
48084787
} else { // Else not a nested loop
48094788
if( !_nodes[m->_idx] ) continue; // Dead code has no loop
48104789
IdealLoopTree* m_loop = get_loop(m);
@@ -4813,23 +4792,17 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
48134792
// is a member of some outer enclosing loop. Since there are no
48144793
// shared headers (I've split them already) I only need to go up
48154794
// at most 1 level.
4816-
while( l && l->_head == m ) // Successor heads loop?
4795+
while (l && l->_head == m) { // Successor heads loop?
48174796
l = l->_parent; // Move up 1 for me
4797+
}
48184798
// If this loop is not properly parented, then this loop
48194799
// has no exit path out, i.e. its an infinite loop.
4820-
if( !l ) {
4800+
if (!l) {
48214801
// Make loop "reachable" from root so the CFG is reachable. Basically
48224802
// insert a bogus loop exit that is never taken. 'm', the loop head,
48234803
// points to 'n', one (of possibly many) fall-in paths. There may be
48244804
// many backedges as well.
48254805

4826-
// Here I set the loop to be the root loop. I could have, after
4827-
// inserting a bogus loop exit, restarted the recursion and found my
4828-
// new loop exit. This would make the infinite loop a first-class
4829-
// loop and it would then get properly optimized. What's the use of
4830-
// optimizing an infinite loop?
4831-
l = _ltree_root; // Oops, found infinite loop
4832-
48334806
if (!_verify_only) {
48344807
// Insert the NeverBranch between 'm' and it's control user.
48354808
NeverBranchNode *iff = new NeverBranchNode( m );
@@ -4854,7 +4827,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
48544827
// Now create the never-taken loop exit
48554828
Node *if_f = new CProjNode( iff, 1 );
48564829
_igvn.register_new_node_with_optimizer(if_f);
4857-
set_loop(if_f, l);
4830+
set_loop(if_f, _ltree_root);
48584831
// Find frame ptr for Halt. Relies on the optimizer
48594832
// V-N'ing. Easier and quicker than searching through
48604833
// the program structure.
@@ -4863,10 +4836,27 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
48634836
// Halt & Catch Fire
48644837
Node* halt = new HaltNode(if_f, frame, "never-taken loop exit reached");
48654838
_igvn.register_new_node_with_optimizer(halt);
4866-
set_loop(halt, l);
4839+
set_loop(halt, _ltree_root);
48674840
C->root()->add_req(halt);
48684841
}
48694842
set_loop(C->root(), _ltree_root);
4843+
// move to outer most loop with same header
4844+
l = m_loop;
4845+
while (true) {
4846+
IdealLoopTree* next = l->_parent;
4847+
if (next == nullptr || next->_head != m) {
4848+
break;
4849+
}
4850+
l = next;
4851+
}
4852+
// properly insert infinite loop in loop tree
4853+
sort(_ltree_root, l);
4854+
// fix child link from parent
4855+
IdealLoopTree* p = l->_parent;
4856+
l->_next = p->_child;
4857+
p->_child = l;
4858+
// code below needs enclosing loop
4859+
l = l->_parent;
48704860
}
48714861
}
48724862
// Weeny check for irreducible. This child was already visited (this
@@ -4906,7 +4896,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
49064896
assert( get_loop(n) == innermost, "" );
49074897
IdealLoopTree *p = innermost->_parent;
49084898
IdealLoopTree *l = innermost;
4909-
while( p && l->_head == n ) {
4899+
while (p && l->_head == n) {
49104900
l->_next = p->_child; // Put self on parents 'next child'
49114901
p->_child = l; // Make self as first child of parent
49124902
l = p; // Now walk up the parent chain
@@ -4920,7 +4910,7 @@ int PhaseIdealLoop::build_loop_tree_impl( Node *n, int pre_order ) {
49204910
// Record tightest enclosing loop for self. Mark as post-visited.
49214911
set_loop(n, innermost);
49224912
// Also record has_call flag early on
4923-
if( innermost ) {
4913+
if (innermost) {
49244914
if( n->is_Call() && !n->is_CallLeaf() && !n->is_macro() ) {
49254915
// Do not count uncommon calls
49264916
if( !n->is_CallStaticJava() || !n->as_CallStaticJava()->_name ) {

src/hotspot/share/opto/loopnode.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -927,9 +927,6 @@ class PhaseIdealLoop : public PhaseTransform {
927927
void update_main_loop_skeleton_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con);
928928
void copy_skeleton_predicates_to_post_loop(LoopNode* main_loop_head, CountedLoopNode* post_loop_head, Node* init, Node* stride);
929929
void insert_loop_limit_check(ProjNode* limit_check_proj, Node* cmp_limit, Node* bol);
930-
#ifdef ASSERT
931-
bool only_has_infinite_loops();
932-
#endif
933930

934931
void log_loop_tree();
935932

@@ -1036,7 +1033,7 @@ class PhaseIdealLoop : public PhaseTransform {
10361033

10371034
// Place 'n' in some loop nest, where 'n' is a CFG node
10381035
void build_loop_tree();
1039-
int build_loop_tree_impl( Node *n, int pre_order );
1036+
int build_loop_tree_impl(Node* n, int pre_order);
10401037
// Insert loop into the existing loop tree. 'innermost' is a leaf of the
10411038
// loop tree, not the root.
10421039
IdealLoopTree *sort( IdealLoopTree *loop, IdealLoopTree *innermost );

src/hotspot/share/opto/parse1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,7 @@ void Parse::merge_new_path(int target_bci) {
16211621
// The ex_oop must be pushed on the stack, unlike throw_to_exit.
16221622
void Parse::merge_exception(int target_bci) {
16231623
#ifdef ASSERT
1624-
if (target_bci < bci()) {
1624+
if (target_bci <= bci()) {
16251625
C->set_exception_backedge();
16261626
}
16271627
#endif
Lines changed: 76 additions & 0 deletions
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+
}
Lines changed: 74 additions & 0 deletions
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+
}
Lines changed: 45 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)