Path: blob/master/src/hotspot/share/memory/metaspace/metachunk.cpp
40957 views
/*1* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2017, 2021 SAP SE. 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 it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 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 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "logging/log.hpp"27#include "memory/metaspace/metachunk.hpp"28#include "memory/metaspace/metaspaceCommon.hpp"29#include "memory/metaspace/metaspaceSettings.hpp"30#include "memory/metaspace/virtualSpaceNode.hpp"31#include "runtime/mutexLocker.hpp"32#include "utilities/align.hpp"33#include "utilities/copy.hpp"34#include "utilities/debug.hpp"3536namespace metaspace {3738// Return a single char presentation of the state ('f', 'u', 'd')39char Metachunk::get_state_char() const {40switch (_state) {41case State::Free: return 'f';42case State::InUse: return 'u';43case State::Dead: return 'd';44}45return '?';46}4748#ifdef ASSERT49void Metachunk::assert_have_expand_lock() {50assert_lock_strong(Metaspace_lock);51}52#endif5354// Commit uncommitted section of the chunk.55// Fails if we hit a commit limit.56bool Metachunk::commit_up_to(size_t new_committed_words) {57// Please note:58//59// VirtualSpaceNode::ensure_range_is_committed(), when called over a range containing both committed and uncommitted parts,60// will replace the whole range with a new mapping, thus erasing the existing content in the committed parts. Therefore61// we must make sure never to call VirtualSpaceNode::ensure_range_is_committed() over a range containing live data.62//63// Luckily, this cannot happen by design. We have two cases:64//65// 1) chunks equal or larger than a commit granule.66// In this case, due to chunk geometry, the chunk should cover whole commit granules (in other words, a chunk equal or larger than67// a commit granule will never share a granule with a neighbor). That means whatever we commit or uncommit here does not affect68// neighboring chunks. We only have to take care not to re-commit used parts of ourself. We do this by moving the committed_words69// limit in multiple of commit granules.70//71// 2) chunks smaller than a commit granule.72// In this case, a chunk shares a single commit granule with its neighbors. But this never can be a problem:73// - Either the commit granule is already committed (and maybe the neighbors contain live data). In that case calling74// ensure_range_is_committed() will do nothing.75// - Or the commit granule is not committed, but in this case, the neighbors are uncommitted too and cannot contain live data.7677#ifdef ASSERT78if (word_size() >= Settings::commit_granule_words()) {79// case (1)80assert(is_aligned(base(), Settings::commit_granule_bytes()) &&81is_aligned(end(), Settings::commit_granule_bytes()),82"Chunks larger than a commit granule must cover whole granules.");83assert(is_aligned(_committed_words, Settings::commit_granule_words()),84"The commit boundary must be aligned to commit granule size");85assert(_used_words <= _committed_words, "Sanity");86} else {87// case (2)88assert(_committed_words == 0 || _committed_words == word_size(), "Sanity");89}90#endif9192// We should hold the expand lock at this point.93assert_lock_strong(Metaspace_lock);9495const size_t commit_from = _committed_words;96const size_t commit_to = MIN2(align_up(new_committed_words, Settings::commit_granule_words()), word_size());97assert(commit_from >= used_words(), "Sanity");98assert(commit_to <= word_size(), "Sanity");99if (commit_to > commit_from) {100log_debug(metaspace)("Chunk " METACHUNK_FORMAT ": attempting to move commit line to "101SIZE_FORMAT " words.", METACHUNK_FORMAT_ARGS(this), commit_to);102if (!_vsnode->ensure_range_is_committed(base() + commit_from, commit_to - commit_from)) {103DEBUG_ONLY(verify();)104return false;105}106}107108// Remember how far we have committed.109_committed_words = commit_to;110DEBUG_ONLY(verify();)111return true;112}113114// Ensure that chunk is committed up to at least new_committed_words words.115// Fails if we hit a commit limit.116bool Metachunk::ensure_committed(size_t new_committed_words) {117bool rc = true;118if (new_committed_words > committed_words()) {119MutexLocker cl(Metaspace_lock, Mutex::_no_safepoint_check_flag);120rc = commit_up_to(new_committed_words);121}122return rc;123}124125bool Metachunk::ensure_committed_locked(size_t new_committed_words) {126// the .._locked() variant should be called if we own the lock already.127assert_lock_strong(Metaspace_lock);128bool rc = true;129if (new_committed_words > committed_words()) {130rc = commit_up_to(new_committed_words);131}132return rc;133}134135// Uncommit chunk area. The area must be a common multiple of the136// commit granule size (in other words, we cannot uncommit chunks smaller than137// a commit granule size).138void Metachunk::uncommit() {139MutexLocker cl(Metaspace_lock, Mutex::_no_safepoint_check_flag);140uncommit_locked();141}142143void Metachunk::uncommit_locked() {144// Only uncommit chunks which are free, have no used words set (extra precaution) and are equal or larger in size than a single commit granule.145assert_lock_strong(Metaspace_lock);146assert(_state == State::Free && _used_words == 0 && word_size() >= Settings::commit_granule_words(),147"Only free chunks equal or larger than commit granule size can be uncommitted "148"(chunk " METACHUNK_FULL_FORMAT ").", METACHUNK_FULL_FORMAT_ARGS(this));149if (word_size() >= Settings::commit_granule_words()) {150_vsnode->uncommit_range(base(), word_size());151_committed_words = 0;152}153}154void Metachunk::set_committed_words(size_t v) {155// Set committed words. Since we know that we only commit whole commit granules, we can round up v here.156v = MIN2(align_up(v, Settings::commit_granule_words()), word_size());157_committed_words = v;158}159160// Allocate word_size words from this chunk (word_size must be aligned to161// allocation_alignment_words).162//163// Caller must make sure the chunk is both large enough and committed far enough164// to hold the allocation. Will always work.165//166MetaWord* Metachunk::allocate(size_t request_word_size) {167// Caller must have made sure this works168assert(free_words() >= request_word_size, "Chunk too small.");169assert(free_below_committed_words() >= request_word_size, "Chunk not committed.");170MetaWord* const p = top();171_used_words += request_word_size;172SOMETIMES(verify();)173return p;174}175176#ifdef ASSERT177178// Zap this structure.179void Metachunk::zap_header(uint8_t c) {180memset(this, c, sizeof(Metachunk));181}182183// Verifies linking with neighbors in virtual space.184// Can only be done under expand lock protection.185void Metachunk::verify_neighborhood() const {186assert_lock_strong(Metaspace_lock);187assert(!is_dead(), "Do not call on dead chunks.");188if (is_root_chunk()) {189// Root chunks are all alone in the world.190assert(next_in_vs() == NULL || prev_in_vs() == NULL, "Root chunks should have no neighbors");191} else {192// Non-root chunks have neighbors, at least one, possibly two.193assert(next_in_vs() != NULL || prev_in_vs() != NULL,194"A non-root chunk should have neighbors (chunk @" PTR_FORMAT195", base " PTR_FORMAT ", level " CHKLVL_FORMAT ".",196p2i(this), p2i(base()), level());197if (prev_in_vs() != NULL) {198assert(prev_in_vs()->end() == base(),199"Chunk " METACHUNK_FULL_FORMAT ": should be adjacent to predecessor: " METACHUNK_FULL_FORMAT ".",200METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(prev_in_vs()));201assert(prev_in_vs()->next_in_vs() == this,202"Chunk " METACHUNK_FULL_FORMAT ": broken link to left neighbor: " METACHUNK_FULL_FORMAT " (" PTR_FORMAT ").",203METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(prev_in_vs()), p2i(prev_in_vs()->next_in_vs()));204}205if (next_in_vs() != NULL) {206assert(end() == next_in_vs()->base(),207"Chunk " METACHUNK_FULL_FORMAT ": should be adjacent to successor: " METACHUNK_FULL_FORMAT ".",208METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(next_in_vs()));209assert(next_in_vs()->prev_in_vs() == this,210"Chunk " METACHUNK_FULL_FORMAT ": broken link to right neighbor: " METACHUNK_FULL_FORMAT " (" PTR_FORMAT ").",211METACHUNK_FULL_FORMAT_ARGS(this), METACHUNK_FULL_FORMAT_ARGS(next_in_vs()), p2i(next_in_vs()->prev_in_vs()));212}213214// One of the neighbors must be the buddy. It can be whole or splintered.215216// The chunk following us or preceeding us may be our buddy or a splintered part of it.217Metachunk* buddy = is_leader() ? next_in_vs() : prev_in_vs();218assert(buddy != NULL, "Missing neighbor.");219assert(!buddy->is_dead(), "Invalid buddy state.");220221// This neighbor is either or buddy (same level) or a splinter of our buddy - hence222// the level can never be smaller (aka the chunk size cannot be larger).223assert(buddy->level() >= level(), "Wrong level.");224225if (buddy->level() == level()) {226// If the buddy is of the same size as us, it is unsplintered.227assert(buddy->is_leader() == !is_leader(),228"Only one chunk can be leader in a pair");229230// When direct buddies are neighbors, one or both should be in use, otherwise they should231// have been merged.232// But since we call this verification function from internal functions where we are about to merge or just did split,233// do not test this. We have RootChunkArea::verify_area_is_ideally_merged() for testing that.234if (is_leader()) {235assert(buddy->base() == end(), "Sanity");236assert(is_aligned(base(), word_size() * 2 * BytesPerWord), "Sanity");237} else {238assert(buddy->end() == base(), "Sanity");239assert(is_aligned(buddy->base(), word_size() * 2 * BytesPerWord), "Sanity");240}241} else {242// Buddy, but splintered, and this is a part of it.243if (is_leader()) {244assert(buddy->base() == end(), "Sanity");245} else {246assert(buddy->end() > (base() - word_size()), "Sanity");247}248}249}250}251252volatile MetaWord dummy = 0;253254void Metachunk::verify() const {255// Note. This should be called under CLD lock protection.256257// We can verify everything except the _prev_in_vs/_next_in_vs pair.258// This is because neighbor chunks may be added concurrently, so we cannot rely259// on the content of _next_in_vs/_prev_in_vs unless we have the expand lock.260assert(!is_dead(), "Do not call on dead chunks.");261if (is_free()) {262assert(used_words() == 0, "free chunks are not used.");263}264265// Note: only call this on a life Metachunk.266chunklevel::check_valid_level(level());267268assert(base() != NULL, "No base ptr");269assert(committed_words() >= used_words(),270"mismatch: committed: " SIZE_FORMAT ", used: " SIZE_FORMAT ".",271committed_words(), used_words());272assert(word_size() >= committed_words(),273"mismatch: word_size: " SIZE_FORMAT ", committed: " SIZE_FORMAT ".",274word_size(), committed_words());275276// Test base pointer277assert(base() != NULL, "Base pointer NULL");278assert(vsnode() != NULL, "No space");279vsnode()->check_pointer(base());280281// Starting address shall be aligned to chunk size.282const size_t required_alignment = word_size() * sizeof(MetaWord);283assert_is_aligned(base(), required_alignment);284285// Test accessing the committed area.286SOMETIMES(287if (_committed_words > 0) {288for (const MetaWord* p = _base; p < _base + _committed_words; p += os::vm_page_size()) {289dummy = *p;290}291dummy = *(_base + _committed_words - 1);292}293)294}295#endif // ASSERT296297void Metachunk::print_on(outputStream* st) const {298// Note: must also work with invalid/random data. (e.g. do not call word_size())299st->print("Chunk @" PTR_FORMAT ", state %c, base " PTR_FORMAT ", "300"level " CHKLVL_FORMAT " (" SIZE_FORMAT " words), "301"used " SIZE_FORMAT " words, committed " SIZE_FORMAT " words.",302p2i(this), get_state_char(), p2i(base()), level(),303(chunklevel::is_valid_level(level()) ? chunklevel::word_size_for_level(level()) : (size_t)-1),304used_words(), committed_words());305}306307} // namespace metaspace308309310311