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 
  28 #include "memory/metaspace/msBlockTree.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 #ifdef ASSERT
  38 
  39 // Tree verification
  40 
  41 // These asserts prints the tree, then asserts
  42 #define assrt(cond, format, ...) \
  43   do { \
  44     if (!(cond)) { \
  45       print_tree(tty); \
  46       assert(cond, format, __VA_ARGS__); \
  47     } \
  48   } while(0)
  49 
  50   // This assert prints the tree, then stops (generic message)
  51 #define assrt0(cond) \
  52   do { \
  53     if (!(cond)) { \
  54       print_tree(tty); \
  55       assert(cond, "sanity"); \
  56     } \
  57   } while(0)
  58 
  59 
  60 
  61 // walkinfo keeps a node plus the size corridor it and its children
  62 //  are supposed to be in.
  63 struct BlockTree::walkinfo {
  64   BlockTree::Node* n;
  65   int depth;
  66   size_t lim1; // (
  67   size_t lim2; // )
  68 };
  69 
  70 void BlockTree::verify() const {
  71 
  72   // Traverse the tree and test that all nodes are in the correct order.
  73 
  74   MemRangeCounter counter;
  75   int longest_edge = 0;
  76 
  77   if (_root != NULL) {
  78 
  79     ResourceMark rm;
  80 
  81     GrowableArray<walkinfo> stack;
  82 
  83     walkinfo info;
  84     info.n = _root;
  85     info.lim1 = 0;
  86     info.lim2 = SIZE_MAX;
  87     info.depth = 0;
  88 
  89     stack.push(info);
  90 
  91     while (stack.length() > 0) {
  92 
  93       info = stack.pop();
  94       const Node* n = info.n;
  95 
  96       // Assume a (ridiculously large) edge limit to catch cases
  97       //  of badly degenerated or circular trees.
  98       assrt0(info.depth < 10000);
  99 
 100       counter.add(n->_word_size);
 101 
 102       // Verify node.
 103       if (n == _root) {
 104         assrt0(n->_parent == NULL);
 105       } else {
 106         assrt0(n->_parent != NULL);
 107       }
 108 
 109       // check size and ordering
 110       assrt(n->_word_size >= MinWordSize, "bad node size " SIZE_FORMAT, n->_word_size);
 111       assrt0(n->_word_size > info.lim1);
 112       assrt0(n->_word_size < info.lim2);
 113 
 114       // Check children
 115       if (n->_left != NULL) {
 116         assrt0(n->_left != n);
 117         assrt0(n->_left->_parent == n);
 118 
 119         walkinfo info2;
 120         info2.n = n->_left;
 121         info2.lim1 = info.lim1;
 122         info2.lim2 = n->_word_size;
 123         info2.depth = info.depth + 1;
 124         stack.push(info2);
 125       }
 126 
 127       if (n->_right != NULL) {
 128         assrt0(n->_right != n);
 129         assrt0(n->_right->_parent == n);
 130 
 131         walkinfo info2;
 132         info2.n = n->_right;
 133         info2.lim1 = n->_word_size;
 134         info2.lim2 = info.lim2;
 135         info2.depth = info.depth + 1;
 136         stack.push(info2);
 137       }
 138 
 139       // If node has same-sized siblings check those too.
 140       const Node* n2 = n->_next;
 141       while (n2 != NULL) {
 142         assrt0(n2 != n);
 143         assrt0(n2->_word_size == n->_word_size);
 144         counter.add(n2->_word_size);
 145         n2 = n2->_next;
 146       }
 147     }
 148   }
 149 
 150   // At the end, check that counters match
 151   _counter.check(counter);
 152 
 153 }
 154 
 155 void BlockTree::zap_range(MetaWord* p, size_t word_size) {
 156   memset(p, 0xF3, word_size * sizeof(MetaWord));
 157 }
 158 
 159 #undef assrt
 160 #undef assrt0
 161 
 162 void BlockTree::print_tree(outputStream* st) const {
 163 
 164   if (_root != NULL) {
 165 
 166     ResourceMark rm;
 167 
 168     GrowableArray<walkinfo> stack;
 169 
 170     walkinfo info;
 171     info.n = _root;
 172     info.depth = 0;
 173 
 174     stack.push(info);
 175     while (stack.length() > 0) {
 176       info = stack.pop();
 177       const Node* n = info.n;
 178       // Print node.
 179       for (int i = 0; i < info.depth; i++) {
 180          st->print("---");
 181       }
 182       st->print_cr("<" PTR_FORMAT " (size " SIZE_FORMAT ")", p2i(n), n->_word_size);
 183       // Handle children.
 184       if (n->_right != NULL) {
 185         walkinfo info2;
 186         info2.n = n->_right;
 187         info2.depth = info.depth + 1;
 188         stack.push(info2);
 189       }
 190       if (n->_left != NULL) {
 191         walkinfo info2;
 192         info2.n = n->_left;
 193         info2.depth = info.depth + 1;
 194         stack.push(info2);
 195       }
 196     }
 197 
 198   } else {
 199     st->print_cr("<no nodes>");
 200   }
 201 }
 202 
 203 #endif // ASSERT
 204 
 205 } // namespace metaspace