24
24
*/
25
25
26
26
#include " precompiled.hpp"
27
+ #include " memory/metaspace/chunklevel.hpp"
27
28
#include " memory/metaspace/blockTree.hpp"
28
29
#include " memory/resourceArea.hpp"
29
30
#include " utilities/debug.hpp"
@@ -36,27 +37,43 @@ namespace metaspace {
36
37
// Needed to prevent linker errors on MacOS and AIX
37
38
const size_t BlockTree::MinWordSize;
38
39
40
+ #define NODE_FORMAT \
41
+ " @" PTR_FORMAT \
42
+ " : canary " INTPTR_FORMAT \
43
+ " , parent " PTR_FORMAT \
44
+ " , left " PTR_FORMAT \
45
+ " , right " PTR_FORMAT \
46
+ " , next " PTR_FORMAT \
47
+ " , size " SIZE_FORMAT
48
+
49
+ #define NODE_FORMAT_ARGS (n ) \
50
+ p2i (n), \
51
+ (n)->_canary, \
52
+ p2i ((n)->_parent), \
53
+ p2i ((n)->_left), \
54
+ p2i ((n)->_right), \
55
+ p2i ((n)->_next), \
56
+ (n)->_word_size
57
+
39
58
#ifdef ASSERT
40
59
41
60
// Tree verification
42
61
43
- // These asserts prints the tree, then asserts
44
- #define assrt (cond, format, ...) \
62
+ // This assert prints the tree too
63
+ #define tree_assert (cond, format, ...) \
45
64
do { \
46
65
if (!(cond)) { \
66
+ tty->print (" Error in tree @" PTR_FORMAT " : " , p2i (this )); \
67
+ tty->print_cr (format, __VA_ARGS__); \
68
+ tty->print_cr (" Tree:" ); \
47
69
print_tree (tty); \
48
70
assert (cond, format, __VA_ARGS__); \
49
71
} \
50
72
} while (0 )
51
73
52
- // This assert prints the tree, then stops (generic message)
53
- #define assrt0 (cond ) \
54
- do { \
55
- if (!(cond)) { \
56
- print_tree (tty); \
57
- assert (cond, " sanity" ); \
58
- } \
59
- } while (0 )
74
+ // Assert, prints tree and specific given node
75
+ #define tree_assert_invalid_node (cond, failure_node ) \
76
+ tree_assert (cond, " Invalid node: " NODE_FORMAT, NODE_FORMAT_ARGS(failure_node))
60
77
61
78
// walkinfo keeps a node plus the size corridor it and its children
62
79
// are supposed to be in.
@@ -67,12 +84,24 @@ struct BlockTree::walkinfo {
67
84
size_t lim2; // )
68
85
};
69
86
87
+ // Helper for verify()
88
+ void BlockTree::verify_node_pointer (const Node* n) const {
89
+ tree_assert (os::is_readable_pointer (n),
90
+ " Invalid node: @" PTR_FORMAT " is unreadable." , p2i (n));
91
+ // If the canary is broken, this is either an invalid node pointer or
92
+ // the node has been overwritten. Either way, print a hex dump, then
93
+ // assert away.
94
+ if (n->_canary != Node::_canary_value) {
95
+ os::print_hex_dump (tty, (address)n, (address)n + sizeof (Node), 1 );
96
+ tree_assert (false , " Invalid node: @" PTR_FORMAT " canary broken or pointer invalid" , p2i (n));
97
+ }
98
+ }
99
+
70
100
void BlockTree::verify () const {
71
101
// Traverse the tree and test that all nodes are in the correct order.
72
102
73
103
MemRangeCounter counter;
74
104
int longest_edge = 0 ;
75
-
76
105
if (_root != NULL ) {
77
106
78
107
ResourceMark rm;
@@ -90,27 +119,29 @@ void BlockTree::verify() const {
90
119
info = stack.pop ();
91
120
const Node* n = info.n ;
92
121
122
+ verify_node_pointer (n);
123
+
93
124
// Assume a (ridiculously large) edge limit to catch cases
94
125
// of badly degenerated or circular trees.
95
- assrt0 (info.depth < 10000 );
126
+ tree_assert (info.depth < 10000 , " too deep (%d) " , info. depth );
96
127
counter.add (n->_word_size );
97
128
98
- // Verify node.
99
129
if (n == _root) {
100
- assrt0 (n->_parent == NULL );
130
+ tree_assert_invalid_node (n->_parent == NULL , n );
101
131
} else {
102
- assrt0 (n->_parent != NULL );
132
+ tree_assert_invalid_node (n->_parent != NULL , n );
103
133
}
104
134
105
135
// check size and ordering
106
- assrt (n->_word_size >= MinWordSize, " bad node size " SIZE_FORMAT, n->_word_size );
107
- assrt0 (n->_word_size > info.lim1 );
108
- assrt0 (n->_word_size < info.lim2 );
136
+ tree_assert_invalid_node (n->_word_size >= MinWordSize, n);
137
+ tree_assert_invalid_node (n->_word_size <= chunklevel::MAX_CHUNK_WORD_SIZE, n);
138
+ tree_assert_invalid_node (n->_word_size > info.lim1 , n);
139
+ tree_assert_invalid_node (n->_word_size < info.lim2 , n);
109
140
110
141
// Check children
111
142
if (n->_left != NULL ) {
112
- assrt0 (n->_left != n);
113
- assrt0 (n->_left ->_parent == n);
143
+ tree_assert_invalid_node (n->_left != n, n);
144
+ tree_assert_invalid_node (n->_left ->_parent == n, n);
114
145
115
146
walkinfo info2;
116
147
info2.n = n->_left ;
@@ -121,8 +152,8 @@ void BlockTree::verify() const {
121
152
}
122
153
123
154
if (n->_right != NULL ) {
124
- assrt0 (n->_right != n);
125
- assrt0 (n->_right ->_parent == n);
155
+ tree_assert_invalid_node (n->_right != n, n);
156
+ tree_assert_invalid_node (n->_right ->_parent == n, n);
126
157
127
158
walkinfo info2;
128
159
info2.n = n->_right ;
@@ -135,26 +166,33 @@ void BlockTree::verify() const {
135
166
// If node has same-sized siblings check those too.
136
167
const Node* n2 = n->_next ;
137
168
while (n2 != NULL ) {
138
- assrt0 (n2 != n);
139
- assrt0 (n2->_word_size == n->_word_size );
169
+ verify_node_pointer (n2);
170
+ tree_assert_invalid_node (n2 != n, n2); // catch simple circles
171
+ tree_assert_invalid_node (n2->_word_size == n->_word_size , n2);
140
172
counter.add (n2->_word_size );
141
173
n2 = n2->_next ;
142
174
}
143
175
}
144
176
}
145
177
146
178
// At the end, check that counters match
179
+ // (which also verifies that we visited every node, or at least
180
+ // as many nodes as are in this tree)
147
181
_counter.check (counter);
182
+
183
+ #undef assrt0n
148
184
}
149
185
150
186
void BlockTree::zap_range (MetaWord* p, size_t word_size) {
151
187
memset (p, 0xF3 , word_size * sizeof (MetaWord));
152
188
}
153
189
154
- #undef assrt
155
- #undef assrt0
156
-
157
190
void BlockTree::print_tree (outputStream* st) const {
191
+
192
+ // Note: we do not print the tree indented, since I found that printing it
193
+ // as a quasi list is much clearer to the eye.
194
+ // We print the tree depth-first, with stacked nodes below normal ones
195
+ // (normal "real" nodes are marked with a leading '+')
158
196
if (_root != NULL ) {
159
197
160
198
ResourceMark rm;
@@ -168,11 +206,27 @@ void BlockTree::print_tree(outputStream* st) const {
168
206
while (stack.length () > 0 ) {
169
207
info = stack.pop ();
170
208
const Node* n = info.n ;
209
+
171
210
// Print node.
172
- for (int i = 0 ; i < info.depth ; i++) {
173
- st->print (" ---" );
211
+ st->print (" %4d + " , info.depth );
212
+ if (os::is_readable_pointer (n)) {
213
+ st->print_cr (NODE_FORMAT, NODE_FORMAT_ARGS (n));
214
+ } else {
215
+ st->print_cr (" @" PTR_FORMAT " : unreadable (skipping subtree)" , p2i (n));
216
+ continue ; // don't print this subtree
217
+ }
218
+
219
+ // Print same-sized-nodes stacked under this node
220
+ for (Node* n2 = n->_next ; n2 != NULL ; n2 = n2->_next ) {
221
+ st->print_raw (" " );
222
+ if (os::is_readable_pointer (n2)) {
223
+ st->print_cr (NODE_FORMAT, NODE_FORMAT_ARGS (n2));
224
+ } else {
225
+ st->print_cr (" @" PTR_FORMAT " : unreadable (skipping rest of chain)." , p2i (n2));
226
+ break ; // stop printing this chain.
227
+ }
174
228
}
175
- st-> print_cr ( " < " PTR_FORMAT " (size " SIZE_FORMAT " ) " , p2i (n), n-> _word_size );
229
+
176
230
// Handle children.
177
231
if (n->_right != NULL ) {
178
232
walkinfo info2;
0 commit comments