--- /dev/null 2019-07-26 17:25:35.550269839 +0200 +++ new/src/hotspot/share/memory/metaspace/commitMask.hpp 2019-08-02 08:07:35.476580224 +0200 @@ -0,0 +1,189 @@ +/* + * 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_COMMITMASK_HPP +#define SHARE_MEMORY_METASPACE_COMMITMASK_HPP + +#include "memory/metaspace/constants.hpp" +#include "utilities/debug.hpp" +#include "utilities/bitMap.hpp" +#include "utilities/globalDefinitions.hpp" + +namespace metaspace { + +// A bitmap covering a range of metaspace; each bit in this mask corresponds to +// +class CommitMask : public CHeapBitMap { + + const MetaWord* const _base; + const size_t _word_size; + + // Given an offset, in words, into the area, return the number of the bit + // covering it. + static idx_t bitno_for_word_offset(size_t offset) { + return offset / constants::commit_granule_words; + } + + idx_t bitno_for_address(const MetaWord* p) const { + assert(p >= _base && p < _base + _word_size, "Invalid address"); + const size_t off = p - _base; + return bitno_for_word_offset(off); + } + + static idx_t mask_size(size_t word_size) { + assert(is_aligned(word_size, constants::commit_granule_words), "size not aligned correctly."); + return bitno_for_word_offset(word_size) + 1; + } + + struct BitCounterClosure : public BitMapClosure { + idx_t cnt; + bool do_bit(BitMap::idx_t offset) { cnt ++; return true; } + }; + + // Missing from BitMap. + // Count 1 bits in range [start, end). + idx_t count_one_bits_in_range(idx_t start, idx_t end) const { + if (start == end) { + return at(start) ? 1 : 0; + } + // TODO: This can be done more efficiently. + BitCounterClosure bcc; + bcc.cnt = 0; + iterate(&bcc, start, end + 1); + return bcc.cnt; + } + +#ifdef ASSERT + // Given a pointer, check if it points into the range this bitmap covers. + bool is_pointer_valid(const MetaWord* p) const { + return p >= _base && p < _base + _word_size; + } + // Given a pointer, check if it points into the range this bitmap covers, + // and if it is aligned to commit granule border. + bool is_pointer_valid_and_aligned(const MetaWord* p) const { + return is_pointer_valid(p) && is_aligned(p, constants::commit_granule_bytes); + } + // Given a pointer, check if it points into the range this bitmap covers. + void check_pointer(const MetaWord* p) const { + assert(is_pointer_valid(p), + "Pointer " PTR_FORMAT " not in range of this bitmap [" PTR_FORMAT ", " PTR_FORMAT ").", + p2i(p), p2i(_base), p2i(_base + _word_size)); + } + // Given a pointer, check if it points into the range this bitmap covers, + // and if it is aligned to commit granule border. + void check_pointer_aligned(const MetaWord* p) const { + check_pointer(p); + assert(is_aligned(p, constants::commit_granule_bytes), + "Pointer " PTR_FORMAT " should be aligned to commit granule size " SIZE_FORMAT ".", p2i(p), constants::commit_granule_bytes); + } + // Given a range, check if it points into the range this bitmap covers, + // and if its borders are aligned to commit granule border. + void check_range(const MetaWord* start, size_t word_size) const { + check_pointer_aligned(start); + check_pointer_aligned(start + word_size); + } +#endif + + // Marks a single commit granule as committed or uncomitted and returns + // its prior state. + bool mark_granule(idx_t bitno, bool value) { + bool b = at(bitno); + at_put(bitno, value); + return b; + } + +public: + + CommitMask(const MetaWord* start, size_t word_size) + : CHeapBitMap(mask_size(word_size)) + , _base(start) + , _word_size(word_size) + {} + + // Given an address, returns true if the address is committed, false if not. + bool is_committed_address(const MetaWord* p) const { + DEBUG_ONLY(check_pointer(p)); + const idx_t bitno = bitno_for_address(p); + return at(bitno); + } + + // Given an address range [start, end), returns true if area is fully committed through. + bool is_fully_committed_range(const MetaWord* start, size_t word_size) const { + DEBUG_ONLY(check_range(start, word_size)); + const idx_t b1 = bitno_for_address(start); + const idx_t b2 = bitno_for_address(start + word_size); + return get_next_zero_offset(b1, b2) == b2; + } + + // Given an address range, return size, in number of words, of committed area within that range. + size_t get_committed_size_in_range(const MetaWord* start, size_t word_size) const { + DEBUG_ONLY(check_range(start, word_size)); + const idx_t b1 = bitno_for_address(start); + const idx_t b2 = bitno_for_address(start + word_size); + const idx_t num_bits = count_one_bits_in_range(b1, b2); + return num_bits * constants::commit_granule_words; + } + + // Return total committed size, in number of words. + size_t get_committed_size() const { + return count_one_bits() * constants::commit_granule_words; + } + + // Mark a whole address range [start, end) as committed. + // Return the number of words which had already been committed before this operation. + size_t mark_range_as_committed(const MetaWord* start, size_t word_size) { + DEBUG_ONLY(check_range(start, word_size)); + const idx_t b1 = bitno_for_address(start); + const idx_t b2 = bitno_for_address(start + word_size); + if (b1 == b2) { // Simple case, 1 granule + return mark_granule(b1, true) ? constants::commit_granule_words : 0; + } + const idx_t bits_set_before = count_one_bits_in_range(bitno_for_address(start), word_size); + set_range(b1, b2); + return bits_set_before * constants::commit_granule_words; + } + + // Mark a whole address range [start, end) as uncommitted. + // Return the number of words which had already been uncommitted before this operation. + size_t mark_range_as_uncommitted(const MetaWord* start, size_t word_size) { + DEBUG_ONLY(check_range(start, word_size)); + const idx_t b1 = bitno_for_address(start); + const idx_t b2 = bitno_for_address(start + word_size); + if (b1 == b2) { // Simple case, 1 granule + return mark_granule(b1, true) ? constants::commit_granule_words : 0; + } + const idx_t bits_set_before = count_one_bits_in_range(bitno_for_address(start), word_size); + clear_range(b1, b2); + return ((b2 - b1) - bits_set_before) * constants::commit_granule_words; + } + + + //// Debug stuff //// + DEBUG_ONLY(void verify(bool slow) const;) + +}; + +} // namespace metaspace + +#endif // SHARE_MEMORY_METASPACE_COMMITMASK_HPP