Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/memory/metaspace/blockTree.cpp
40957 views
1
/*
2
* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3
* Copyright (c) 2020 SAP SE. All rights reserved.
4
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5
*
6
* This code is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License version 2 only, as
8
* published by the Free Software Foundation.
9
*
10
* This code is distributed in the hope that it will be useful, but WITHOUT
11
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13
* version 2 for more details (a copy is included in the LICENSE file that
14
* accompanied this code).
15
*
16
* You should have received a copy of the GNU General Public License version
17
* 2 along with this work; if not, write to the Free Software Foundation,
18
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19
*
20
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21
* or visit www.oracle.com if you need additional information or have any
22
* questions.
23
*
24
*/
25
26
#include "precompiled.hpp"
27
#include "memory/metaspace/chunklevel.hpp"
28
#include "memory/metaspace/blockTree.hpp"
29
#include "memory/resourceArea.hpp"
30
#include "utilities/debug.hpp"
31
#include "utilities/globalDefinitions.hpp"
32
#include "utilities/growableArray.hpp"
33
#include "utilities/ostream.hpp"
34
35
namespace metaspace {
36
37
// Needed to prevent linker errors on MacOS and AIX
38
const size_t BlockTree::MinWordSize;
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
58
#ifdef ASSERT
59
60
// Tree verification
61
62
// This assert prints the tree too
63
#define tree_assert(cond, format, ...) \
64
do { \
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:"); \
69
print_tree(tty); \
70
assert(cond, format, __VA_ARGS__); \
71
} \
72
} while (0)
73
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))
77
78
// walkinfo keeps a node plus the size corridor it and its children
79
// are supposed to be in.
80
struct BlockTree::walkinfo {
81
BlockTree::Node* n;
82
int depth;
83
size_t lim1; // (
84
size_t lim2; // )
85
};
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
100
void BlockTree::verify() const {
101
// Traverse the tree and test that all nodes are in the correct order.
102
103
MemRangeCounter counter;
104
int longest_edge = 0;
105
if (_root != NULL) {
106
107
ResourceMark rm;
108
GrowableArray<walkinfo> stack;
109
110
walkinfo info;
111
info.n = _root;
112
info.lim1 = 0;
113
info.lim2 = SIZE_MAX;
114
info.depth = 0;
115
116
stack.push(info);
117
118
while (stack.length() > 0) {
119
info = stack.pop();
120
const Node* n = info.n;
121
122
verify_node_pointer(n);
123
124
// Assume a (ridiculously large) edge limit to catch cases
125
// of badly degenerated or circular trees.
126
tree_assert(info.depth < 10000, "too deep (%d)", info.depth);
127
counter.add(n->_word_size);
128
129
if (n == _root) {
130
tree_assert_invalid_node(n->_parent == NULL, n);
131
} else {
132
tree_assert_invalid_node(n->_parent != NULL, n);
133
}
134
135
// check size and ordering
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);
140
141
// Check children
142
if (n->_left != NULL) {
143
tree_assert_invalid_node(n->_left != n, n);
144
tree_assert_invalid_node(n->_left->_parent == n, n);
145
146
walkinfo info2;
147
info2.n = n->_left;
148
info2.lim1 = info.lim1;
149
info2.lim2 = n->_word_size;
150
info2.depth = info.depth + 1;
151
stack.push(info2);
152
}
153
154
if (n->_right != NULL) {
155
tree_assert_invalid_node(n->_right != n, n);
156
tree_assert_invalid_node(n->_right->_parent == n, n);
157
158
walkinfo info2;
159
info2.n = n->_right;
160
info2.lim1 = n->_word_size;
161
info2.lim2 = info.lim2;
162
info2.depth = info.depth + 1;
163
stack.push(info2);
164
}
165
166
// If node has same-sized siblings check those too.
167
const Node* n2 = n->_next;
168
while (n2 != NULL) {
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);
172
counter.add(n2->_word_size);
173
n2 = n2->_next;
174
}
175
}
176
}
177
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)
181
_counter.check(counter);
182
183
#undef assrt0n
184
}
185
186
void BlockTree::zap_range(MetaWord* p, size_t word_size) {
187
memset(p, 0xF3, word_size * sizeof(MetaWord));
188
}
189
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 '+')
196
if (_root != NULL) {
197
198
ResourceMark rm;
199
GrowableArray<walkinfo> stack;
200
201
walkinfo info;
202
info.n = _root;
203
info.depth = 0;
204
205
stack.push(info);
206
while (stack.length() > 0) {
207
info = stack.pop();
208
const Node* n = info.n;
209
210
// Print node.
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
}
228
}
229
230
// Handle children.
231
if (n->_right != NULL) {
232
walkinfo info2;
233
info2.n = n->_right;
234
info2.depth = info.depth + 1;
235
stack.push(info2);
236
}
237
if (n->_left != NULL) {
238
walkinfo info2;
239
info2.n = n->_left;
240
info2.depth = info.depth + 1;
241
stack.push(info2);
242
}
243
}
244
245
} else {
246
st->print_cr("<no nodes>");
247
}
248
}
249
250
#endif // ASSERT
251
252
} // namespace metaspace
253
254