/* * Copyright (c) 2012, 2016, 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. * */ #include "precompiled.hpp" #include "memory/metaspace/chunkLevel.hpp" #include "memory/metaspace/constants.hpp" #include "memory/metaspace/metachunk.hpp" #include "memory/metaspace/metaspaceCommon.hpp" #include "memory/metaspace/virtualSpaceNode.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" #include "utilities/debug.hpp" namespace metaspace { // Make sure that the Klass alignment also agree. STATIC_ASSERT(Metachunk::allocation_alignment_bytes == (size_t)KlassAlignmentInBytes); void Metachunk::remove_from_list() { if (_prev != NULL) { _prev->set_next(_next); } if (_next != NULL) { _next->set_prev(_prev); } _prev = _next = NULL; } // Ensure that chunk is committed up to at least word_size words. bool Metachunk::ensure_committed(size_t new_committed_words) { assert(new_committed_words <= word_size(), "too much."); if (new_committed_words <= committed_words()) { return true; } // Note: we may commit more than the area of our own chunk and that is okay. MetaWord* const commit_top = align_down(base() + committed_words(), constants::commit_granule_words); MetaWord* const new_commit_top = align_up(base() + new_committed_words, constants::commit_granule_words); { // Expand lock from here on. MutexLocker cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); if (!_vsnode->ensure_range_is_committed(commit_top, new_commit_top - commit_top)) { return false; } // Remember how far we have committed. _committed_words = new_commit_top - base(); if (_committed_words > word_size()) { _committed_words = word_size(); } } return true; } // 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* Metachunk::allocate(size_t word_size, bool* p_did_hit_commit_limit) { size_t request_word_size = align_up(word_size, allocation_alignment_words); // Space enough left? if (free_words() < request_word_size) { *p_did_hit_commit_limit = false; return NULL; } // Expand committed region if necessary. if (ensure_committed(used_words() + request_word_size) == false) { *p_did_hit_commit_limit = true; return NULL; } MetaWord* const p = top(); _used_words += request_word_size; return p; } #ifdef ASSERT void Metachunk::verify(bool slow) const { // Note: only call this on a life Metachunk. chklvl::check_valid_level(level()); assert(base() != NULL, "No base ptr"); assert(committed_words() >= used_words(), "Sanity"); assert(word_size() >= committed_words(), "Sanity"); // Test base pointer assert(vsnode() != NULL, "No space"); vsnode()->check_pointer(base()); assert(base() != NULL, "Base pointer NULL"); // Starting address shall be aligned to chunk size. const size_t required_alignment = word_size() * sizeof(MetaWord); assert_is_aligned(base(), required_alignment); // Used words assert(used_words() < word_size(), "oob"); // If we are not a root chunk, we shall have a reference to a tree node assert(tree_node_ref() != 0 || level() == chklvl::ROOT_CHUNK_LEVEL, "No parent node."); } #endif // ASSERT #ifdef ASSERT bool MetachunkList::contains(const Metachunk* c) const { for (Metachunk* c2 = first(); c2 != NULL; c2 = c2->next()) { if (c == c2) { return true; } } return false; } void MetachunkList::verify(bool slow) const { int num = 0; for (Metachunk* c = first(); c != NULL; c = c->next()) { num ++; if (slow) { c->verify(false); } _num.check(num); } } #endif // ASSERT } // namespace metaspace