Skip to content

Commit 08df6a1

Browse files
committedJun 15, 2020
8246203: Segmentation fault in verification due to stack overflow with -XX:+VerifyIterativeGVN
Replace the recursive verification algorithm with an iterative one to avoid a stack overflow for large graphs. Reviewed-by: kvn, thartmann
1 parent 3341d36 commit 08df6a1

File tree

4 files changed

+157
-54
lines changed

4 files changed

+157
-54
lines changed
 

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

+56-40
Original file line numberDiff line numberDiff line change
@@ -2152,63 +2152,79 @@ void Node::verify_edges(Unique_Node_List &visited) {
21522152
}
21532153
}
21542154

2155-
void Node::verify_recur(const Node *n, int verify_depth,
2156-
VectorSet &old_space, VectorSet &new_space) {
2157-
if ( verify_depth == 0 ) return;
2158-
if (verify_depth > 0) --verify_depth;
2159-
2155+
// Verify all nodes if verify_depth is negative
2156+
void Node::verify(Node* n, int verify_depth) {
2157+
assert(verify_depth != 0, "depth should not be 0");
2158+
ResourceMark rm;
2159+
ResourceArea* area = Thread::current()->resource_area();
2160+
VectorSet old_space(area);
2161+
VectorSet new_space(area);
2162+
Node_List worklist(area);
2163+
worklist.push(n);
21602164
Compile* C = Compile::current();
2165+
uint last_index_on_current_depth = 0;
2166+
verify_depth--; // Visiting the first node on depth 1
2167+
// Only add nodes to worklist if verify_depth is negative (visit all nodes) or greater than 0
2168+
bool add_to_worklist = verify_depth != 0;
21612169

2162-
// Contained in new_space or old_space?
2163-
VectorSet *v = C->node_arena()->contains(n) ? &new_space : &old_space;
2164-
// Check for visited in the proper space. Numberings are not unique
2165-
// across spaces so we need a separate VectorSet for each space.
2166-
if( v->test_set(n->_idx) ) return;
21672170

2168-
if (n->is_Con() && n->bottom_type() == Type::TOP) {
2169-
if (C->cached_top_node() == NULL)
2170-
C->set_cached_top_node((Node*)n);
2171-
assert(C->cached_top_node() == n, "TOP node must be unique");
2172-
}
2171+
for (uint list_index = 0; list_index < worklist.size(); list_index++) {
2172+
n = worklist[list_index];
2173+
2174+
if (n->is_Con() && n->bottom_type() == Type::TOP) {
2175+
if (C->cached_top_node() == NULL) {
2176+
C->set_cached_top_node((Node*)n);
2177+
}
2178+
assert(C->cached_top_node() == n, "TOP node must be unique");
2179+
}
21732180

2174-
for( uint i = 0; i < n->len(); i++ ) {
2175-
Node *x = n->in(i);
2176-
if (!x || x->is_top()) continue;
2181+
for (uint i = 0; i < n->len(); i++) {
2182+
Node* x = n->in(i);
2183+
if (!x || x->is_top()) {
2184+
continue;
2185+
}
21772186

2178-
// Verify my input has a def-use edge to me
2179-
if (true /*VerifyDefUse*/) {
2187+
// Verify my input has a def-use edge to me
21802188
// Count use-def edges from n to x
21812189
int cnt = 0;
2182-
for( uint j = 0; j < n->len(); j++ )
2183-
if( n->in(j) == x )
2190+
for (uint j = 0; j < n->len(); j++) {
2191+
if (n->in(j) == x) {
21842192
cnt++;
2193+
}
2194+
}
2195+
21852196
// Count def-use edges from x to n
21862197
uint max = x->_outcnt;
2187-
for( uint k = 0; k < max; k++ )
2188-
if (x->_out[k] == n)
2198+
for (uint k = 0; k < max; k++) {
2199+
if (x->_out[k] == n) {
21892200
cnt--;
2190-
assert( cnt == 0, "mismatched def-use edge counts" );
2201+
}
2202+
}
2203+
assert(cnt == 0, "mismatched def-use edge counts");
2204+
2205+
// Contained in new_space or old_space?
2206+
VectorSet* v = C->node_arena()->contains(x) ? &new_space : &old_space;
2207+
// Check for visited in the proper space. Numberings are not unique
2208+
// across spaces so we need a separate VectorSet for each space.
2209+
if (add_to_worklist && !v->test_set(x->_idx)) {
2210+
worklist.push(x);
2211+
}
21912212
}
21922213

2193-
verify_recur(x, verify_depth, old_space, new_space);
2214+
if (verify_depth > 0 && list_index == last_index_on_current_depth) {
2215+
// All nodes on this depth were processed and its inputs are on the worklist. Decrement verify_depth and
2216+
// store the current last list index which is the last node in the list with the new depth. All nodes
2217+
// added afterwards will have a new depth again. Stop adding new nodes if depth limit is reached (=0).
2218+
verify_depth--;
2219+
if (verify_depth == 0) {
2220+
add_to_worklist = false;
2221+
}
2222+
last_index_on_current_depth = worklist.size() - 1;
2223+
}
21942224
}
2195-
2196-
}
2197-
2198-
//------------------------------verify-----------------------------------------
2199-
// Check Def-Use info for my subgraph
2200-
void Node::verify() const {
2201-
Compile* C = Compile::current();
2202-
Node* old_top = C->cached_top_node();
2203-
ResourceMark rm;
2204-
ResourceArea *area = Thread::current()->resource_area();
2205-
VectorSet old_space(area), new_space(area);
2206-
verify_recur(this, -1, old_space, new_space);
2207-
C->set_cached_top_node(old_top);
22082225
}
22092226
#endif
22102227

2211-
22122228
//------------------------------walk-------------------------------------------
22132229
// Graph walk, with both pre-order and post-order functions
22142230
void Node::walk(NFunc pre, NFunc post, void *env) {

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -1150,8 +1150,7 @@ class Node {
11501150
void collect_nodes_out_all_ctrl_boundary(GrowableArray<Node*> *ns) const;
11511151

11521152
void verify_edges(Unique_Node_List &visited); // Verify bi-directional edges
1153-
void verify() const; // Check Def-Use info for my subgraph
1154-
static void verify_recur(const Node *n, int verify_depth, VectorSet &old_space, VectorSet &new_space);
1153+
static void verify(Node* n, int verify_depth);
11551154

11561155
// This call defines a class-unique string used to identify class instances
11571156
virtual const char *Name() const;

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

+10-12
Original file line numberDiff line numberDiff line change
@@ -1005,24 +1005,22 @@ void PhaseIterGVN::verify_step(Node* n) {
10051005
if (VerifyIterativeGVN) {
10061006
_verify_window[_verify_counter % _verify_window_size] = n;
10071007
++_verify_counter;
1008-
ResourceMark rm;
1009-
ResourceArea* area = Thread::current()->resource_area();
1010-
VectorSet old_space(area), new_space(area);
1011-
if (C->unique() < 1000 ||
1012-
0 == _verify_counter % (C->unique() < 10000 ? 10 : 100)) {
1008+
if (C->unique() < 1000 || 0 == _verify_counter % (C->unique() < 10000 ? 10 : 100)) {
10131009
++_verify_full_passes;
1014-
Node::verify_recur(C->root(), -1, old_space, new_space);
1010+
Node::verify(C->root(), -1);
10151011
}
1016-
const int verify_depth = 4;
1017-
for ( int i = 0; i < _verify_window_size; i++ ) {
1012+
for (int i = 0; i < _verify_window_size; i++) {
10181013
Node* n = _verify_window[i];
1019-
if ( n == NULL ) continue;
1020-
if( n->in(0) == NodeSentinel ) { // xform_idom
1014+
if (n == NULL) {
1015+
continue;
1016+
}
1017+
if (n->in(0) == NodeSentinel) { // xform_idom
10211018
_verify_window[i] = n->in(1);
1022-
--i; continue;
1019+
--i;
1020+
continue;
10231021
}
10241022
// Typical fanout is 1-2, so this call visits about 6 nodes.
1025-
Node::verify_recur(n, verify_depth, old_space, new_space);
1023+
Node::verify(n, 4);
10261024
}
10271025
}
10281026
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
* Copyright (c) 2020, 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+
/**
25+
* @test
26+
* @bug 8246203
27+
* @requires vm.debug == true & vm.flavor == "server"
28+
* @summary Test which causes a stack overflow segmentation fault with -XX:+VerifyIterativeGVN due to a too deep recursion in Node::verify_recur().
29+
*
30+
* @run main/othervm/timeout=600 -Xcomp -XX:+VerifyIterativeGVN -XX:CompileCommand=compileonly,compiler.loopopts.TestDeepGraphVerifyIterativeGVN::*
31+
* compiler.loopopts.TestDeepGraphVerifyIterativeGVN
32+
*/
33+
34+
package compiler.loopopts;
35+
36+
public class TestDeepGraphVerifyIterativeGVN
37+
{
38+
static volatile int[] iArr;
39+
static volatile int x;
40+
41+
public static void main(String[] arr) {
42+
/*
43+
* Just enough statements to create a deep enough graph (i.e. many nodes in one chain). The current recursive verification in Node::verify_recur() will follow this chain
44+
* and call itself again for each newly discovered input node. The current implementation can only handle up to around 10000 recursive calls and will then crash with a
45+
* stack overflow segementation fault. The iterative fix needs much less memory and does not result in a segementation fault anymore.
46+
*/
47+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
48+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
49+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
50+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
51+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
52+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
53+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
54+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
55+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
56+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
57+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
58+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
59+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
60+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
61+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
62+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
63+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
64+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
65+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
66+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
67+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
68+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
69+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
70+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
71+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
72+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
73+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
74+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
75+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
76+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
77+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
78+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
79+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
80+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
81+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
82+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
83+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
84+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
85+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
86+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
87+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
88+
iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 }; iArr = new int[] { x % 2 };
89+
}
90+
}

0 commit comments

Comments
 (0)
Please sign in to comment.