/* * Copyright (c) 2012, 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_METACHUNK_HPP #define SHARE_MEMORY_METASPACE_METACHUNK_HPP #include "memory/metaspace/abstractPool.hpp" #include "memory/metaspace/chunkLevel.hpp" #include "utilities/debug.hpp" #include "utilities/globalDefinitions.hpp" namespace metaspace { struct qtnode_t; class VirtualSpaceNode; // Metachunk - Quantum of allocation from a Virtualspace // Metachunks are reused (when freed are put on a global freelist) and // have no permanent association to a SpaceManager. // +--------------+ <- end ----+ --+ // | | | | // | | | free | // | | | // | | | | size (aka capacity) // | | | | // | ----------- | <- top -- + | // | | | | // | | | used | // +--------------+ <- start -- + -- + // Note: this is a chunk **descriptor**. The real Payload area lives in metaspace, // this class lives somewhere else. class Metachunk { // A chunk header is kept in a list: // - in the list of used chunks inside a SpaceManager, if it is in use // - in the list of free chunks inside a ChunkManager, if it is free // - in the freelist of dead headers inside the MetaChunkHeaderPool, // if it is dead (e.g. result of chunk merging). Metachunk* _prev; Metachunk* _next; chklvl_t _level; // aka size. // true: free, owned by ChunkManager // false: in-use, owned by SpaceManager // if dead, meaningless bool _is_free; // start of chunk memory; NULL if dead. MetaWord* _base; // Used words. size_t _used_words; // the chunk tree node this header is hanging under; NULL if dead. qtnode_t* _tree_node; // We need unfortunately a back link to the virtual space node // for splitting and merging nodes. VirtualSpaceNode* _vsnode; MetaWord* top() const { return base() + _used_words; } Metachunk() : _prev(NULL), _next(NULL), _level(chklvl::ROOT_CHUNK_LEVEL), _is_free(true), _base(NULL), _used_words(0), _tree_node(NULL), _vsnode(NULL) {} size_t word_size() const { return chklvl::word_size_for_level(_level); } MetaWord* base() const { return _base; } void set_base(MetaWord* p) { _base = p; } MetaWord* end() const { return base() + word_size(); } void set_prev(Metachunk* c) { _prev = c; } Metachunk* prev() const { return _prev; } void set_next(Metachunk* c) { _next = c; } Metachunk* next() const { return _next; } // Remove chunk from whatever list it lives in by wiring next with previous. void remove_from_list(); bool is_free() const { return _is_free; } bool is_in_use() const { return !_is_free; } void set_free(bool v) { _is_free = v; } void inc_level() { _level ++; DEBUG_ONLY(chklvl::is_valid_level(_level);) } void dec_level() { _level --; DEBUG_ONLY(chklvl::is_valid_level(_level);) } void set_level(chklvl_t v) { _level = v; DEBUG_ONLY(chklvl::is_valid_level(_level);) } chklvl_t level() const { return _level; } void set_tree_node(qtnode_t* n) { _tree_node = n; } qtnode_t* tree_node() const { return _tree_node; } VirtualSpaceNode* vsnode() const { return _vsnode; } void set_vsnode(VirtualSpaceNode* n) { _vsnode = n; } size_t used_words() const { return _used_words; } size_t free_words() const { return word_size() - used_words(); } void reset_used_words() { _used_words = 0; } // Allocation from a chunk // Allocate word_size words from this chunk. // // May cause memory to be committed. That may fail if we hit a commit limit. In that case, // NULL is returned and p_did_hit_commit_limit will be set to true. // If the remainder portion of the chunk was too small to hold the allocation, // NULL is returned and p_did_hit_commit_limit will be set to false. MetaWord* allocate(size_t word_size, bool* p_did_hit_commit_limit); // Wipe this object to look as if it were default constructed. void wipe() { _prev = NULL; _next = NULL; _level = chklvl::ROOT_CHUNK_LEVEL; _is_free(true); _base(NULL); _used_words(0); _tree_node(NULL); _vsnode(NULL); } //// Debug stuff //// DEBUG_ONLY(void verify(bool slow) const;) }; class MetachunkPool : private AbstractPool { public: static bool is_metachunk_pointer(void* p) { return is_valid_elem((Metachunk*)p); } // Allocate new Metachunk header. Header will be default constructed. static Metachunk* alloc_header() { Metachunk* c = allocate_element(); c->wipe(); return c; } // Mark a header as dead and return to the pool for later reuse. static void release_header(Metachunk* c) { DEBUG_ONLY(c->set_base(NULL);) return_element(c); } }; } // namespace metaspace #endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP