--- /dev/null 2019-07-25 13:07:35.456009699 +0200 +++ new/src/hotspot/share/memory/metaspace/abstractPool.hpp 2019-07-25 15:30:02.037413638 +0200 @@ -0,0 +1,210 @@ +/* + * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP +#define SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP + +#include "memory/allocation.hpp" +#include "utilities/debug.hpp" +#include "utilities/globalDefinitions.hpp" + +namespace metaspace { + +// A simple helper class; +// +// Holds a linear array of elements of type E. Array lives in C heap and +// expands automatically. Free elements can be returned, will be kept in +// a freelist. Elements can be retrieved by their index (index type I). +// Index 0 will never be allocated and can be relied upon as being invalid. +// +// E must be of at least sizeof(I), and I must be an integral size. +// +template +class AbstractPool { +public: + + typedef I size_type_t; + +private: + + E* _arr; + size_type_t _capacity; + size_type_t _top; + + I _freelist; + size_type_t _num_in_freelist; + + const size_type_t _max_capacity; + const size_type_t _capacity_increase; + const char* const _name; + + // Enlarge internal array if needed. Zero out new portion of array. + void enlarge_to(size_type_t new_len) { + E* p = REALLOC_C_HEAP_ARRAY(E, _arr, new_len, mtInternal); + _arr = p; + _capacity = new_len; + } + + //// freelist handling //// + + struct free_elem_t { + I next_idx; + }; + + // free_elem_t must fit into an E, and sizeof(E) must be aligned such that + // one can write free_elem_t at &E. + STATIC_ASSERT(sizeof(E) >= sizeof(free_elem_t)); + STATIC_ASSERT(sizeof(E) % sizeof(free_elem_t) == 0); + + E* take_from_freelist() { + I idx = _freelist; + if (0 == idx) { + assert(_num_in_freelist == 0, "counter mismatch"); + return NULL; + } + E* p = elem_at_index(idx); + _freelist = ((free_elem_t*)p)->next_idx; + assert(_num_in_freelist > 0, "counter underflow"); + _num_in_freelist --; + return p; + } + + void add_to_freelist(E* p) { + ((free_elem_t*)p)->next_idx = _freelist; + _freelist = index_for_elem(p); + _num_in_freelist ++; + } + +public: + + AbstractPool(const char* name, size_type_t max_capacity, size_type_t capacity_increase) + : _arr(NULL), _capacity(0), + _top(0), + _freelist((I)0), _num_in_freelist(0), + _max_capacity(max_capacity), _capacity_increase(capacity_increase), + _name(name) + {} + + ~AbstractPool() { FREE_C_HEAP_ARRAY(E, _arr); } + + I index_for_elem(const E* p) const { + DEBUG_ONLY(check_elem(p)); + return p - _arr; + } + + E* elem_at_index(I i) const { + DEBUG_ONLY(check_idx(i)); + return _arr + i; + } + + // Allocate a new element. Enlarge internal array if needed. + // Will return NULL if max_size is reached. + E* allocate_element() { + + DEBUG_ONLY(verify(false)); + + E* p = take_from_freelist(); + if (p != NULL) { + return p; + } + + if (_capacity == _top) { // Need to enlarge. + size_type_t new_cap = MIN2((size_type_t)(_capacity + _capacity_increase), _max_capacity); + if (new_cap == _capacity) { + return NULL; // capped out. + } + enlarge_to(new_cap); + } + + // Avoid handing out anything at index 0. + // This allows callers to use "I index == 0" as "invalid ref". + if (_top == 0) { + _top ++; + } + + p = _arr + _top; + _top ++; + + return p; + + } + + void return_element(E* p) { + DEBUG_ONLY(check_elem(p)); + add_to_freelist(p); + } + + // Returns number of allocated elements. + size_type_t used() const { return _top - _num_in_freelist; } + + // True if pool is full. + bool is_full() const { return used() == max_capacity(); } + + // True if pool is empty. + bool is_empty() const { return used() == 0; } + + // Returns number of elements in free list. + size_type_t free_elements() const { return _num_in_freelist; } + + // Returns max. capacity of this pool. + size_type_t max_capacity() const { return _max_capacity; } + + // Returns size of memory used. + size_t memory_footprint_words() const { return _capacity * sizeof(E); } + + // Returns true if p was allocated from this pool. + bool is_valid_elem(const E* p) const { return p >= _arr && p < _arr + _top; } + + // Returns true if the index points into the allocated portion of the pool. + // Note: may point to an allocated element or one in the freelist. + bool is_valid_index(I idx) const { return idx > 0 && idx < _top; } + +#ifdef ASSERT + void check_elem(const E* p) const { assert(is_valid_elem(p), "invalid pointer"); } + void check_idx(I i) const { assert(i > 0 && i <= _top, "invalid index"); } + void verify(bool slow) const { + assert(_top <= _capacity && _capacity <= _max_capacity, "Sanity"); + assert(used() <= _capacity, "Sanity"); + if (slow) { + // check freelist. + I idx = _freelist; + size_type_t num = 0; + while (idx != 0) { + num ++; + idx = ((free_elem_t*)elem_at_index(idx))->next_idx; + } + assert(num == _num_in_freelist, "counter mismatch"); + } + } +#endif // ASSERT + +}; + + +} // namespace metaspace + + + + +#endif // SHARE_MEMORY_METASPACE_ABSTRACTPOOL_HPP