1 /*
2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
3  * Copyright (c) 2020 SAP SE. All rights reserved.
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This code is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 only, as
8  * published by the Free Software Foundation.
9  *
10  * This code is distributed in the hope that it will be useful, but WITHOUT
11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
13  * version 2 for more details (a copy is included in the LICENSE file that
14  * accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License version
17  * 2 along with this work; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21  * or visit www.oracle.com if you need additional information or have any
22  * questions.
23  *
24  */
25 
26 #ifndef SHARE_MEMORY_METASPACE_COMMITMASK_HPP
27 #define SHARE_MEMORY_METASPACE_COMMITMASK_HPP
28 
29 #include "utilities/bitMap.hpp"
30 #include "utilities/debug.hpp"
31 #include "utilities/globalDefinitions.hpp"
32 
33 class outputStream;
34 
35 namespace metaspace {
36 
37 // The CommitMask is a bitmask used to store the commit state of commit granules.
38 // It keeps one bit per granule; 1 means committed, 0 means uncommitted.
39 
40 class CommitMask : public CHeapBitMap {
41 
42   const MetaWord* const _base;
43   const size_t _word_size;
44   const size_t _words_per_bit;
45 
46   // Given an offset, in words, into the area, return the number of the bit
47   // covering it.
bitno_for_word_offset(size_t offset,size_t words_per_bit)48   static idx_t bitno_for_word_offset(size_t offset, size_t words_per_bit) {
49     return offset / words_per_bit;
50   }
51 
bitno_for_address(const MetaWord * p) const52   idx_t bitno_for_address(const MetaWord* p) const {
53     // Note: we allow one-beyond since this is a typical need.
54     assert(p >= _base && p <= _base + _word_size, "Invalid address");
55     const size_t off = p - _base;
56     return bitno_for_word_offset(off, _words_per_bit);
57   }
58 
mask_size(size_t word_size,size_t words_per_bit)59   static idx_t mask_size(size_t word_size, size_t words_per_bit) {
60     return bitno_for_word_offset(word_size, words_per_bit);
61   }
62 
63   // Marks a single commit granule as committed (value == true)
64   // or uncomitted (value == false) and returns
65   // its prior state.
mark_granule(idx_t bitno,bool value)66   bool mark_granule(idx_t bitno, bool value) {
67     bool b = at(bitno);
68     at_put(bitno, value);
69     return b;
70   }
71 
72 #ifdef ASSERT
73 
74   // Given a pointer, check if it points into the range this bitmap covers.
75   bool is_pointer_valid(const MetaWord* p) const;
76 
77   // Given a pointer, check if it points into the range this bitmap covers.
78   void check_pointer(const MetaWord* p) const;
79 
80   // Given a pointer, check if it points into the range this bitmap covers,
81   // and if it is aligned to commit granule border.
82   void check_pointer_aligned(const MetaWord* p) const;
83 
84   // Given a range, check if it points into the range this bitmap covers,
85   // and if its borders are aligned to commit granule border.
86   void check_range(const MetaWord* start, size_t word_size) const;
87 
88 #endif // ASSERT
89 
90 public:
91 
92   // Create a commit mask covering a range [start, start + word_size).
93   CommitMask(const MetaWord* start, size_t word_size);
94 
base() const95   const MetaWord* base() const  { return _base; }
word_size() const96   size_t word_size() const      { return _word_size; }
end() const97   const MetaWord* end() const   { return _base + word_size(); }
98 
99   // Given an address, returns true if the address is committed, false if not.
is_committed_address(const MetaWord * p) const100   bool is_committed_address(const MetaWord* p) const {
101     DEBUG_ONLY(check_pointer(p));
102     const idx_t bitno = bitno_for_address(p);
103     return at(bitno);
104   }
105 
106   // Given an address range, return size, in number of words, of committed area within that range.
get_committed_size_in_range(const MetaWord * start,size_t word_size) const107   size_t get_committed_size_in_range(const MetaWord* start, size_t word_size) const {
108     DEBUG_ONLY(check_range(start, word_size));
109     assert(word_size > 0, "zero range");
110     const idx_t b1 = bitno_for_address(start);
111     const idx_t b2 = bitno_for_address(start + word_size);
112     const idx_t num_bits = count_one_bits(b1, b2);
113     return num_bits * _words_per_bit;
114   }
115 
116   // Return total committed size, in number of words.
get_committed_size() const117   size_t get_committed_size() const {
118     return count_one_bits() * _words_per_bit;
119   }
120 
121   // Mark a whole address range [start, end) as committed.
122   // Return the number of words which had already been committed before this operation.
mark_range_as_committed(const MetaWord * start,size_t word_size)123   size_t mark_range_as_committed(const MetaWord* start, size_t word_size) {
124     DEBUG_ONLY(check_range(start, word_size));
125     assert(word_size > 0, "zero range");
126     const idx_t b1 = bitno_for_address(start);
127     const idx_t b2 = bitno_for_address(start + word_size);
128     if (b1 == b2) { // Simple case, 1 granule
129       bool was_committed = mark_granule(b1, true);
130       return was_committed ? _words_per_bit : 0;
131     }
132     const idx_t one_bits_in_range_before = count_one_bits(b1, b2);
133     set_range(b1, b2);
134     return one_bits_in_range_before * _words_per_bit;
135   }
136 
137   // Mark a whole address range [start, end) as uncommitted.
138   // Return the number of words which had already been uncommitted before this operation.
mark_range_as_uncommitted(const MetaWord * start,size_t word_size)139   size_t mark_range_as_uncommitted(const MetaWord* start, size_t word_size) {
140     DEBUG_ONLY(check_range(start, word_size));
141     assert(word_size > 0, "zero range");
142     const idx_t b1 = bitno_for_address(start);
143     const idx_t b2 = bitno_for_address(start + word_size);
144     if (b1 == b2) { // Simple case, 1 granule
145       bool was_committed = mark_granule(b1, false);
146       return was_committed ? 0 : _words_per_bit;
147     }
148     const idx_t zero_bits_in_range_before =
149         (b2 - b1) - count_one_bits(b1, b2);
150     clear_range(b1, b2);
151     return zero_bits_in_range_before * _words_per_bit;
152   }
153 
154   //// Debug stuff ////
155 
156   // Verify internals.
157   DEBUG_ONLY(void verify() const;)
158 
159   void print_on(outputStream* st) const;
160 
161 };
162 
163 } // namespace metaspace
164 
165 #endif // SHARE_MEMORY_METASPACE_COMMITMASK_HPP
166