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 #ifndef SHARE_MEMORY_METASPACE_CHUNKHEADERPOOL_HPP
  27 #define SHARE_MEMORY_METASPACE_CHUNKHEADERPOOL_HPP
  28 
  29 #include "memory/allocation.hpp"
  30 #include "memory/metaspace/metachunk.hpp"
  31 #include "memory/metaspace/metachunkList.hpp"
  32 #include "utilities/debug.hpp"
  33 #include "utilities/globalDefinitions.hpp"
  34 
  35 namespace metaspace {
  36 
  37 // Chunk headers (Metachunk objects) are separate entities from their payload.
  38 //  Since they are allocated and released frequently in the course of buddy allocation
  39 //  (splitting, merging chunks happens often) we want allocation of them fast. Therefore
  40 //  we keep them in a simple pool (somewhat like a primitive slab allocator).
  41 
  42 class ChunkHeaderPool : public CHeapObj<mtMetaspace> {
  43 
  44   static const int slab_capacity = 128;
  45 
  46   struct slab_t : public CHeapObj<mtMetaspace> {
  47     slab_t* next;
  48     int top;
  49     Metachunk elems [slab_capacity];
  50     slab_t() : next(NULL), top(0) {
  51       for (int i = 0; i < slab_capacity; i++) {
  52         elems[i].clear();
  53       }
  54     }
  55   };
  56 
  57   IntCounter _num_slabs;
  58   slab_t* _first_slab;
  59   slab_t* _current_slab;
  60 
  61   IntCounter _num_handed_out;
  62 
  63   MetachunkList _freelist;
  64 
  65   void allocate_new_slab();
  66 
  67   static ChunkHeaderPool* _chunkHeaderPool;
  68 
  69 
  70 public:
  71 
  72   ChunkHeaderPool();
  73 
  74   ~ChunkHeaderPool();
  75 
  76   // Allocates a Metachunk structure. The structure is uninitialized.
  77   Metachunk* allocate_chunk_header() {
  78 
  79     Metachunk* c = NULL;
  80 
  81     DEBUG_ONLY(verify(false));
  82 
  83     c = _freelist.remove_first();
  84     assert(c == NULL || c->is_dead(), "Not a freelist chunk header?");
  85 
  86     if (c == NULL) {
  87 
  88       if (_current_slab == NULL ||
  89           _current_slab->top == slab_capacity) {
  90         allocate_new_slab();
  91         assert(_current_slab->top < slab_capacity, "Sanity");
  92       }
  93 
  94       c = _current_slab->elems + _current_slab->top;
  95       _current_slab->top ++;
  96 
  97     }
  98 
  99     _num_handed_out.increment();
 100 
 101     // By contract, the returned structure is uninitialized.
 102     // Zap to make this clear.
 103     DEBUG_ONLY(c->zap_header(0xBB);)
 104 
 105     return c;
 106 
 107   }
 108 
 109   void return_chunk_header(Metachunk* c) {
 110     // We only ever should return free chunks, since returning chunks
 111     // happens only on merging and merging only works with free chunks.
 112     assert(c != NULL && c->is_free(), "Sanity");
 113 #ifdef ASSERT
 114     // In debug, fill dead header with pattern.
 115     c->zap_header(0xCC);
 116     c->set_next(NULL);
 117     c->set_prev(NULL);
 118 #endif
 119     c->set_dead();
 120     _freelist.add(c);
 121     _num_handed_out.decrement();
 122 
 123   }
 124 
 125   // Returns number of allocated elements.
 126   int used() const                   { return _num_handed_out.get(); }
 127 
 128   // Returns number of elements in free list.
 129   int freelist_size() const          { return _freelist.count(); }
 130 
 131   // Returns size of memory used.
 132   size_t memory_footprint_words() const;
 133 
 134   DEBUG_ONLY(void verify(bool slow) const;)
 135 
 136   static void initialize();
 137 
 138   // Returns reference to the one global chunk header pool.
 139   static ChunkHeaderPool* pool() { return _chunkHeaderPool; }
 140 
 141 };
 142 
 143 
 144 } // namespace metaspace
 145 
 146 
 147 
 148 
 149 #endif // SHARE_MEMORY_METASPACE_CHUNKHEADERPOOL_HPP