1 /*
   2  * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018, 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 "logging/log.hpp"
  28 #include "memory/metaspace.hpp"
  29 #include "memory/metaspace/chunkManager.hpp"
  30 #include "memory/metaspace/counter.hpp"
  31 #include "memory/metaspace/commitLimiter.hpp"
  32 #include "memory/metaspace/counter.hpp"
  33 #include "memory/metaspace/freeChunkList.hpp"
  34 #include "memory/metaspace/metaspaceContext.hpp"
  35 #include "memory/metaspace/virtualSpaceList.hpp"
  36 #include "memory/metaspace/virtualSpaceNode.hpp"
  37 #include "runtime/mutexLocker.hpp"
  38 
  39 
  40 namespace metaspace {
  41 
  42 #define LOGFMT         "VsList @" PTR_FORMAT " (%s)"
  43 #define LOGFMT_ARGS    p2i(this), this->_name
  44 
  45 // Create a new, empty, expandable list.
  46 VirtualSpaceList::VirtualSpaceList(const char* name, CommitLimiter* commit_limiter)
  47   : _name(name),
  48     _first_node(NULL),
  49     _can_expand(true),
  50     _can_purge(true),
  51     _commit_limiter(commit_limiter),
  52     _reserved_words_counter(),
  53     _committed_words_counter()
  54 {
  55 }
  56 
  57 // Create a new list. The list will contain one node only, which uses the given ReservedSpace.
  58 // It will be not expandable beyond that first node.
  59 VirtualSpaceList::VirtualSpaceList(const char* name, ReservedSpace rs, CommitLimiter* commit_limiter)
  60 : _name(name),
  61   _first_node(NULL),
  62   _can_expand(false),
  63   _can_purge(false),
  64   _commit_limiter(commit_limiter),
  65   _reserved_words_counter(),
  66   _committed_words_counter()
  67 {
  68   // Create the first node spanning the existing ReservedSpace. This will be the only node created
  69   // for this list since we cannot expand.
  70   VirtualSpaceNode* vsn = VirtualSpaceNode::create_node(rs, _commit_limiter,
  71                                                         &_reserved_words_counter, &_committed_words_counter);
  72   assert(vsn != NULL, "node creation failed");
  73   _first_node = vsn;
  74   _first_node->set_next(NULL);
  75   _nodes_counter.increment();
  76 }
  77 
  78 VirtualSpaceList::~VirtualSpaceList() {
  79   assert_lock_strong(MetaspaceExpand_lock);
  80   // Note: normally, there is no reason ever to delete a vslist since they are
  81   // global objects, but for gtests it makes sense to allow this.
  82   VirtualSpaceNode* vsn = _first_node;
  83   VirtualSpaceNode* vsn2 = vsn;
  84   while (vsn != NULL) {
  85     vsn2 = vsn->next();
  86     delete vsn;
  87     vsn = vsn2;
  88   }
  89 }
  90 
  91 // Create a new node and append it to the list. After
  92 // this function, _current_node shall point to a new empty node.
  93 // List must be expandable for this to work.
  94 void VirtualSpaceList::create_new_node() {
  95   assert(_can_expand, "List is not expandable");
  96   assert_lock_strong(MetaspaceExpand_lock);
  97 
  98   VirtualSpaceNode* vsn = VirtualSpaceNode::create_node(Settings::virtual_space_node_default_word_size(),
  99                                                         _commit_limiter,
 100                                                         &_reserved_words_counter, &_committed_words_counter);
 101   assert(vsn != NULL, "node creation failed");
 102   vsn->set_next(_first_node);
 103   _first_node = vsn;
 104   _nodes_counter.increment();
 105 }
 106 
 107 // Allocate a root chunk from this list.
 108 // Note: this just returns a chunk whose memory is reserved; no memory is committed yet.
 109 // Hence, before using this chunk, it must be committed.
 110 // Also, no limits are checked, since no committing takes place.
 111 Metachunk*  VirtualSpaceList::allocate_root_chunk() {
 112   assert_lock_strong(MetaspaceExpand_lock);
 113 
 114   if (_first_node == NULL ||
 115       _first_node->free_words() == 0) {
 116 
 117     // Since all allocations from a VirtualSpaceNode happen in
 118     // root-chunk-size units, and the node size must be root-chunk-size aligned,
 119     // we should never have left-over space.
 120     assert(_first_node == NULL ||
 121            _first_node->free_words() == 0, "Sanity");
 122 
 123     if (_can_expand) {
 124       create_new_node();
 125       UL2(debug, "added new node (now: %d).", num_nodes());
 126     } else {
 127       UL(debug, "list cannot expand.");
 128       return NULL; // We cannot expand this list.
 129     }
 130   }
 131 
 132   Metachunk* c = _first_node->allocate_root_chunk();
 133 
 134   assert(c != NULL, "This should have worked");
 135 
 136   return c;
 137 
 138 }
 139 
 140 // Attempts to purge nodes. This will remove and delete nodes which only contain free chunks.
 141 // The free chunks are removed from the freelists before the nodes are deleted.
 142 // Return number of purged nodes.
 143 int VirtualSpaceList::purge(FreeChunkListVector* freelists) {
 144 
 145   assert_lock_strong(MetaspaceExpand_lock);
 146 
 147   if (_can_purge == false) {
 148     return 0;
 149   }
 150 
 151   UL(debug, "purging.");
 152 
 153   VirtualSpaceNode* vsn = _first_node;
 154   VirtualSpaceNode* prev_vsn = NULL;
 155   int num = 0, num_purged = 0;
 156   while (vsn != NULL) {
 157     VirtualSpaceNode* next_vsn = vsn->next();
 158     bool purged = vsn->attempt_purge(freelists);
 159     if (purged) {
 160       // Note: from now on do not dereference vsn!
 161       UL2(debug, "purged node @" PTR_FORMAT ".", p2i(vsn));
 162       if (_first_node == vsn) {
 163         _first_node = next_vsn;
 164       }
 165       DEBUG_ONLY(vsn = (VirtualSpaceNode*)((uintptr_t)(0xdeadbeef));)
 166       if (prev_vsn != NULL) {
 167         prev_vsn->set_next(next_vsn);
 168       }
 169       num_purged ++;
 170       _nodes_counter.decrement();
 171     } else {
 172       prev_vsn = vsn;
 173     }
 174     vsn = next_vsn;
 175     num ++;
 176   }
 177 
 178   UL2(debug, "purged %d nodes (now: %d)", num_purged, num_nodes());
 179 
 180   return num_purged;
 181 
 182 }
 183 
 184 // Print all nodes in this space list.
 185 void VirtualSpaceList::print_on(outputStream* st) const {
 186   MutexLocker fcl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag);
 187 
 188   st->print_cr("vsl %s:", _name);
 189   const VirtualSpaceNode* vsn = _first_node;
 190   int n = 0;
 191   while (vsn != NULL) {
 192     st->print("- node #%d: ", n);
 193     vsn->print_on(st);
 194     vsn = vsn->next();
 195     n ++;
 196   }
 197   st->print_cr("- total %d nodes, " SIZE_FORMAT " reserved words, " SIZE_FORMAT " committed words.",
 198                n, reserved_words(), committed_words());
 199 }
 200 
 201 #ifdef ASSERT
 202 void VirtualSpaceList::verify_locked(bool slow) const {
 203 
 204   assert_lock_strong(MetaspaceExpand_lock);
 205 
 206   assert(_name != NULL, "Sanity");
 207 
 208   int n = 0;
 209 
 210   if (_first_node != NULL) {
 211 
 212     size_t total_reserved_words = 0;
 213     size_t total_committed_words = 0;
 214     const VirtualSpaceNode* vsn = _first_node;
 215     while (vsn != NULL) {
 216       n ++;
 217       vsn->verify_locked(slow);
 218       total_reserved_words += vsn->word_size();
 219       total_committed_words += vsn->committed_words();
 220       vsn = vsn->next();
 221     }
 222 
 223     _nodes_counter.check(n);
 224     _reserved_words_counter.check(total_reserved_words);
 225     _committed_words_counter.check(total_committed_words);
 226 
 227   } else {
 228 
 229     _reserved_words_counter.check(0);
 230     _committed_words_counter.check(0);
 231 
 232   }
 233 }
 234 
 235 void VirtualSpaceList::verify(bool slow) const {
 236   MutexLocker fcl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag);
 237   verify_locked(slow);
 238 }
 239 #endif
 240 
 241 // Returns true if this pointer is contained in one of our nodes.
 242 bool VirtualSpaceList::contains(const MetaWord* p) const {
 243   const VirtualSpaceNode* vsn = _first_node;
 244   while (vsn != NULL) {
 245     if (vsn->contains(p)) {
 246       return true;
 247     }
 248     vsn = vsn->next();
 249   }
 250   return false;
 251 }
 252 
 253 // Returns true if the vslist is not expandable and no more root chunks
 254 // can be allocated.
 255 bool VirtualSpaceList::is_full() const {
 256   if (!_can_expand && _first_node != NULL && _first_node->free_words() == 0) {
 257     return true;
 258   }
 259   return false;
 260 }
 261 
 262 // Convenience methods to return the global class-space chunkmanager
 263 //  and non-class chunkmanager, respectively.
 264 VirtualSpaceList* VirtualSpaceList::vslist_class() {
 265   return MetaspaceContext::context_class() == NULL ? NULL : MetaspaceContext::context_class()->vslist();
 266 }
 267 
 268 VirtualSpaceList* VirtualSpaceList::vslist_nonclass() {
 269   return MetaspaceContext::context_nonclass() == NULL ? NULL : MetaspaceContext::context_nonclass()->vslist();
 270 }
 271 
 272 
 273 
 274 } // namespace metaspace