Path: blob/master/src/hotspot/share/memory/metaspace/blockTree.cpp
40957 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020 SAP SE. 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 it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 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 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "memory/metaspace/chunklevel.hpp"27#include "memory/metaspace/blockTree.hpp"28#include "memory/resourceArea.hpp"29#include "utilities/debug.hpp"30#include "utilities/globalDefinitions.hpp"31#include "utilities/growableArray.hpp"32#include "utilities/ostream.hpp"3334namespace metaspace {3536// Needed to prevent linker errors on MacOS and AIX37const size_t BlockTree::MinWordSize;3839#define NODE_FORMAT \40"@" PTR_FORMAT \41": canary " INTPTR_FORMAT \42", parent " PTR_FORMAT \43", left " PTR_FORMAT \44", right " PTR_FORMAT \45", next " PTR_FORMAT \46", size " SIZE_FORMAT4748#define NODE_FORMAT_ARGS(n) \49p2i(n), \50(n)->_canary, \51p2i((n)->_parent), \52p2i((n)->_left), \53p2i((n)->_right), \54p2i((n)->_next), \55(n)->_word_size5657#ifdef ASSERT5859// Tree verification6061// This assert prints the tree too62#define tree_assert(cond, format, ...) \63do { \64if (!(cond)) { \65tty->print("Error in tree @" PTR_FORMAT ": ", p2i(this)); \66tty->print_cr(format, __VA_ARGS__); \67tty->print_cr("Tree:"); \68print_tree(tty); \69assert(cond, format, __VA_ARGS__); \70} \71} while (0)7273// Assert, prints tree and specific given node74#define tree_assert_invalid_node(cond, failure_node) \75tree_assert(cond, "Invalid node: " NODE_FORMAT, NODE_FORMAT_ARGS(failure_node))7677// walkinfo keeps a node plus the size corridor it and its children78// are supposed to be in.79struct BlockTree::walkinfo {80BlockTree::Node* n;81int depth;82size_t lim1; // (83size_t lim2; // )84};8586// Helper for verify()87void BlockTree::verify_node_pointer(const Node* n) const {88tree_assert(os::is_readable_pointer(n),89"Invalid node: @" PTR_FORMAT " is unreadable.", p2i(n));90// If the canary is broken, this is either an invalid node pointer or91// the node has been overwritten. Either way, print a hex dump, then92// assert away.93if (n->_canary != Node::_canary_value) {94os::print_hex_dump(tty, (address)n, (address)n + sizeof(Node), 1);95tree_assert(false, "Invalid node: @" PTR_FORMAT " canary broken or pointer invalid", p2i(n));96}97}9899void BlockTree::verify() const {100// Traverse the tree and test that all nodes are in the correct order.101102MemRangeCounter counter;103int longest_edge = 0;104if (_root != NULL) {105106ResourceMark rm;107GrowableArray<walkinfo> stack;108109walkinfo info;110info.n = _root;111info.lim1 = 0;112info.lim2 = SIZE_MAX;113info.depth = 0;114115stack.push(info);116117while (stack.length() > 0) {118info = stack.pop();119const Node* n = info.n;120121verify_node_pointer(n);122123// Assume a (ridiculously large) edge limit to catch cases124// of badly degenerated or circular trees.125tree_assert(info.depth < 10000, "too deep (%d)", info.depth);126counter.add(n->_word_size);127128if (n == _root) {129tree_assert_invalid_node(n->_parent == NULL, n);130} else {131tree_assert_invalid_node(n->_parent != NULL, n);132}133134// check size and ordering135tree_assert_invalid_node(n->_word_size >= MinWordSize, n);136tree_assert_invalid_node(n->_word_size <= chunklevel::MAX_CHUNK_WORD_SIZE, n);137tree_assert_invalid_node(n->_word_size > info.lim1, n);138tree_assert_invalid_node(n->_word_size < info.lim2, n);139140// Check children141if (n->_left != NULL) {142tree_assert_invalid_node(n->_left != n, n);143tree_assert_invalid_node(n->_left->_parent == n, n);144145walkinfo info2;146info2.n = n->_left;147info2.lim1 = info.lim1;148info2.lim2 = n->_word_size;149info2.depth = info.depth + 1;150stack.push(info2);151}152153if (n->_right != NULL) {154tree_assert_invalid_node(n->_right != n, n);155tree_assert_invalid_node(n->_right->_parent == n, n);156157walkinfo info2;158info2.n = n->_right;159info2.lim1 = n->_word_size;160info2.lim2 = info.lim2;161info2.depth = info.depth + 1;162stack.push(info2);163}164165// If node has same-sized siblings check those too.166const Node* n2 = n->_next;167while (n2 != NULL) {168verify_node_pointer(n2);169tree_assert_invalid_node(n2 != n, n2); // catch simple circles170tree_assert_invalid_node(n2->_word_size == n->_word_size, n2);171counter.add(n2->_word_size);172n2 = n2->_next;173}174}175}176177// At the end, check that counters match178// (which also verifies that we visited every node, or at least179// as many nodes as are in this tree)180_counter.check(counter);181182#undef assrt0n183}184185void BlockTree::zap_range(MetaWord* p, size_t word_size) {186memset(p, 0xF3, word_size * sizeof(MetaWord));187}188189void BlockTree::print_tree(outputStream* st) const {190191// Note: we do not print the tree indented, since I found that printing it192// as a quasi list is much clearer to the eye.193// We print the tree depth-first, with stacked nodes below normal ones194// (normal "real" nodes are marked with a leading '+')195if (_root != NULL) {196197ResourceMark rm;198GrowableArray<walkinfo> stack;199200walkinfo info;201info.n = _root;202info.depth = 0;203204stack.push(info);205while (stack.length() > 0) {206info = stack.pop();207const Node* n = info.n;208209// Print node.210st->print("%4d + ", info.depth);211if (os::is_readable_pointer(n)) {212st->print_cr(NODE_FORMAT, NODE_FORMAT_ARGS(n));213} else {214st->print_cr("@" PTR_FORMAT ": unreadable (skipping subtree)", p2i(n));215continue; // don't print this subtree216}217218// Print same-sized-nodes stacked under this node219for (Node* n2 = n->_next; n2 != NULL; n2 = n2->_next) {220st->print_raw(" ");221if (os::is_readable_pointer(n2)) {222st->print_cr(NODE_FORMAT, NODE_FORMAT_ARGS(n2));223} else {224st->print_cr("@" PTR_FORMAT ": unreadable (skipping rest of chain).", p2i(n2));225break; // stop printing this chain.226}227}228229// Handle children.230if (n->_right != NULL) {231walkinfo info2;232info2.n = n->_right;233info2.depth = info.depth + 1;234stack.push(info2);235}236if (n->_left != NULL) {237walkinfo info2;238info2.n = n->_left;239info2.depth = info.depth + 1;240stack.push(info2);241}242}243244} else {245st->print_cr("<no nodes>");246}247}248249#endif // ASSERT250251} // namespace metaspace252253254