src/hotspot/share/memory/metaspace/commitMask.hpp
branchstuefe-new-metaspace-branch
changeset 58063 bdf136b8ae0e
child 58646 bcdba1c9f1fe
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/memory/metaspace/commitMask.hpp	Tue Sep 10 09:24:05 2019 +0200
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2019, SAP SE. All rights reserved.
+ * Copyright (c) 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 "utilities/debug.hpp"
+#include "utilities/bitMap.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class outputStream;
+
+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;
+  const size_t _words_per_bit;
+
+  // 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, size_t words_per_bit) {
+    return offset / words_per_bit;
+  }
+
+  idx_t bitno_for_address(const MetaWord* p) const {
+    // Note: we allow one-beyond since this is a typical need.
+    assert(p >= _base && p <= _base + _word_size, "Invalid address");
+    const size_t off = p - _base;
+    return bitno_for_word_offset(off, _words_per_bit);
+  }
+
+  static idx_t mask_size(size_t word_size, size_t words_per_bit) {
+    return bitno_for_word_offset(word_size, words_per_bit);
+  }
+
+  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 {
+    assert(start < end, "Zero range");
+    // TODO: This can be done more efficiently.
+    BitCounterClosure bcc;
+    bcc.cnt = 0;
+    iterate(&bcc, start, end);
+    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.
+  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, _words_per_bit * BytesPerWord),
+           "Pointer " PTR_FORMAT " should be aligned to commit granule size " SIZE_FORMAT ".",
+           p2i(p), _words_per_bit * BytesPerWord);
+  }
+  // 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);
+    assert(is_aligned(word_size, _words_per_bit),
+           "Range " SIZE_FORMAT " should be aligned to commit granule size " SIZE_FORMAT ".",
+           word_size, _words_per_bit);
+    check_pointer(start + word_size - 1);
+  }
+#endif
+
+  // Marks a single commit granule as committed (value == true)
+  // or uncomitted (value == false) 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);
+
+  const MetaWord* base() const  { return _base; }
+  size_t word_size() const      { return _word_size; }
+  const MetaWord* end() const   { return _base + 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));
+    assert(word_size > 0, "zero range");
+    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));
+    assert(word_size > 0, "zero range");
+    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 * _words_per_bit;
+  }
+
+  // Return total committed size, in number of words.
+  size_t get_committed_size() const {
+    return count_one_bits() * _words_per_bit;
+  }
+
+  // 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));
+    assert(word_size > 0, "zero range");
+    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
+      bool was_committed = mark_granule(b1, true);
+      return was_committed ? _words_per_bit : 0;
+    }
+    const idx_t one_bits_in_range_before = count_one_bits_in_range(b1, b2);
+    set_range(b1, b2);
+    return one_bits_in_range_before * _words_per_bit;
+  }
+
+  // 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));
+    assert(word_size > 0, "zero range");
+    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
+      bool was_committed = mark_granule(b1, false);
+      return was_committed ? 0 : _words_per_bit;
+    }
+    const idx_t zero_bits_in_range_before =
+        (b2 - b1) - count_one_bits_in_range(b1, b2);
+    clear_range(b1, b2);
+    return zero_bits_in_range_before * _words_per_bit;
+  }
+
+
+  //// Debug stuff ////
+  DEBUG_ONLY(void verify(bool slow, bool do_touch_test = true) const;)
+
+  void print_on(outputStream* st) const;
+
+};
+
+} // namespace metaspace
+
+#endif // SHARE_MEMORY_METASPACE_COMMITMASK_HPP