1 /*
   2  * Copyright (c) 2018, 2019, Oracle and/or its affiliates. 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 it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 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 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #ifndef SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP
  26 #define SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP
  27 
  28 #include "memory/allocation.hpp"
  29 #include "utilities/debug.hpp"
  30 #include "utilities/globalDefinitions.hpp"
  31 
  32 namespace metaspace {
  33 
  34 // A simple helper class;
  35 //
  36 // holds a linear array of elements of type E;
  37 //
  38 // array lives in C heap and expands automatically;
  39 //
  40 // free elements can be returned and are kept in a freelist;
  41 //
  42 // elements can be retrieved by their index (index type I).
  43 //
  44 // E must offer a "E* next()" and "set_next(E*)" methods.
  45 // I must be an integral type.
  46 //
  47 template <class E, class I>
  48 class AbstractPool {
  49 public:
  50 
  51   typedef I size_type_t;
  52 
  53 private:
  54 
  55   E* _arr;
  56   size_type_t _len;
  57   size_type_t _used;
  58   E* _freelist;
  59   const char* const _name;
  60 
  61   // Enlarge internal array if needed. Zero out new portion of array.
  62   void enlarge_to(size_type_t new_len) {
  63     const size_t new_size_bytes = new_len * sizeof(E);
  64     E* p = (E*) os::realloc(_arr, new_size_bytes, mtInternal);
  65     if (p == NULL) {
  66       vm_exit_out_of_memory(new_size_bytes, OOM_MALLOC_ERROR, "Pool %s: not enough space", _name);
  67     }
  68     _arr = p; _len = new_len;
  69   }
  70 
  71 #ifdef ASSERT
  72   void check_elem(E* p) { assert(is_valid_elem(p), "invalid pointer"); }
  73   void check_idx(I i) { assert(i <= _used, "invalid index"); }
  74 #endif
  75 
  76 public:
  77 
  78   AbstractPool(const char* name)
  79     : _arr(NULL), _len(0), _used(0), _name(name), _freelist(NULL) {}
  80   ~AbstractPool() { os::free(_arr); }
  81 
  82   I index_for_elem(E* p) const {
  83     DEBUG_ONLY(check_elem(p));
  84     return p - _arr;
  85   }
  86 
  87   E* elem_at_index(I i) const {
  88     DEBUG_ONLY(check_idx(i));
  89     return _arr + i;
  90   }
  91 
  92   // Allocate a new element. Enlarge internal array if needed.
  93   // Will return NULL if cap is reached.
  94   E* allocate_element() {
  95 
  96     if (_freelist != NULL) {
  97       E* p = _freelist;
  98       _freelist = _freelist->next();
  99       DEBUG_ONLY(p->set_next(NULL);)
 100       return p;
 101     }
 102 
 103     if (_len == _used) {
 104       size_type_t new_len = _len == 0 ? 0x100 : _len * 2;
 105       enlarge_to(new_len);
 106     }
 107 
 108     // Avoid handing out anything at index 0.
 109     // This allows callers to use "I index == 0" as "invalid ref".
 110     if (_used == 0) {
 111       _used ++;
 112     }
 113 
 114     E* p = _arr[_used ++];
 115     return p;
 116 
 117   }
 118 
 119   void return_element(E* p) {
 120     DEBUG_ONLY(check_elem(p));
 121     p->set_next(_freelist);
 122     _freelist = p;
 123   }
 124 
 125   // Returns true if p was allocated from this pool.
 126   bool is_valid_elem(const E* p) { return p >= _arr && p < _arr + _used; }
 127 
 128 };
 129 
 130 } // namespace metaspace
 131 
 132 #endif // SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP