|
1 /* |
|
2 * Copyright (c) 2019, SAP SE. All rights reserved. |
|
3 * Copyright (c) 2019, Oracle and/or its affiliates. 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/debug.hpp" |
|
30 #include "utilities/bitMap.hpp" |
|
31 #include "utilities/globalDefinitions.hpp" |
|
32 |
|
33 class outputStream; |
|
34 |
|
35 namespace metaspace { |
|
36 |
|
37 // A bitmap covering a range of metaspace; each bit in this mask corresponds to |
|
38 // |
|
39 class CommitMask : public CHeapBitMap { |
|
40 |
|
41 const MetaWord* const _base; |
|
42 const size_t _word_size; |
|
43 const size_t _words_per_bit; |
|
44 |
|
45 // Given an offset, in words, into the area, return the number of the bit |
|
46 // covering it. |
|
47 static idx_t bitno_for_word_offset(size_t offset, size_t words_per_bit) { |
|
48 return offset / words_per_bit; |
|
49 } |
|
50 |
|
51 idx_t bitno_for_address(const MetaWord* p) const { |
|
52 // Note: we allow one-beyond since this is a typical need. |
|
53 assert(p >= _base && p <= _base + _word_size, "Invalid address"); |
|
54 const size_t off = p - _base; |
|
55 return bitno_for_word_offset(off, _words_per_bit); |
|
56 } |
|
57 |
|
58 static idx_t mask_size(size_t word_size, size_t words_per_bit) { |
|
59 return bitno_for_word_offset(word_size, words_per_bit); |
|
60 } |
|
61 |
|
62 struct BitCounterClosure : public BitMapClosure { |
|
63 idx_t cnt; |
|
64 bool do_bit(BitMap::idx_t offset) { cnt ++; return true; } |
|
65 }; |
|
66 |
|
67 // Missing from BitMap. |
|
68 // Count 1 bits in range [start, end). |
|
69 idx_t count_one_bits_in_range(idx_t start, idx_t end) const { |
|
70 assert(start < end, "Zero range"); |
|
71 // TODO: This can be done more efficiently. |
|
72 BitCounterClosure bcc; |
|
73 bcc.cnt = 0; |
|
74 iterate(&bcc, start, end); |
|
75 return bcc.cnt; |
|
76 } |
|
77 |
|
78 #ifdef ASSERT |
|
79 // Given a pointer, check if it points into the range this bitmap covers. |
|
80 bool is_pointer_valid(const MetaWord* p) const { |
|
81 return p >= _base && p < _base + _word_size; |
|
82 } |
|
83 |
|
84 // Given a pointer, check if it points into the range this bitmap covers. |
|
85 void check_pointer(const MetaWord* p) const { |
|
86 assert(is_pointer_valid(p), |
|
87 "Pointer " PTR_FORMAT " not in range of this bitmap [" PTR_FORMAT ", " PTR_FORMAT ").", |
|
88 p2i(p), p2i(_base), p2i(_base + _word_size)); |
|
89 } |
|
90 // Given a pointer, check if it points into the range this bitmap covers, |
|
91 // and if it is aligned to commit granule border. |
|
92 void check_pointer_aligned(const MetaWord* p) const { |
|
93 check_pointer(p); |
|
94 assert(is_aligned(p, _words_per_bit * BytesPerWord), |
|
95 "Pointer " PTR_FORMAT " should be aligned to commit granule size " SIZE_FORMAT ".", |
|
96 p2i(p), _words_per_bit * BytesPerWord); |
|
97 } |
|
98 // Given a range, check if it points into the range this bitmap covers, |
|
99 // and if its borders are aligned to commit granule border. |
|
100 void check_range(const MetaWord* start, size_t word_size) const { |
|
101 check_pointer_aligned(start); |
|
102 assert(is_aligned(word_size, _words_per_bit), |
|
103 "Range " SIZE_FORMAT " should be aligned to commit granule size " SIZE_FORMAT ".", |
|
104 word_size, _words_per_bit); |
|
105 check_pointer(start + word_size - 1); |
|
106 } |
|
107 #endif |
|
108 |
|
109 // Marks a single commit granule as committed (value == true) |
|
110 // or uncomitted (value == false) and returns |
|
111 // its prior state. |
|
112 bool mark_granule(idx_t bitno, bool value) { |
|
113 bool b = at(bitno); |
|
114 at_put(bitno, value); |
|
115 return b; |
|
116 } |
|
117 |
|
118 public: |
|
119 |
|
120 CommitMask(const MetaWord* start, size_t word_size); |
|
121 |
|
122 const MetaWord* base() const { return _base; } |
|
123 size_t word_size() const { return _word_size; } |
|
124 const MetaWord* end() const { return _base + word_size(); } |
|
125 |
|
126 // Given an address, returns true if the address is committed, false if not. |
|
127 bool is_committed_address(const MetaWord* p) const { |
|
128 DEBUG_ONLY(check_pointer(p)); |
|
129 const idx_t bitno = bitno_for_address(p); |
|
130 return at(bitno); |
|
131 } |
|
132 |
|
133 // Given an address range [start..end), returns true if area is fully committed through. |
|
134 bool is_fully_committed_range(const MetaWord* start, size_t word_size) const { |
|
135 DEBUG_ONLY(check_range(start, word_size)); |
|
136 assert(word_size > 0, "zero range"); |
|
137 const idx_t b1 = bitno_for_address(start); |
|
138 const idx_t b2 = bitno_for_address(start + word_size); |
|
139 return get_next_zero_offset(b1, b2) == b2; |
|
140 } |
|
141 |
|
142 // Given an address range, return size, in number of words, of committed area within that range. |
|
143 size_t get_committed_size_in_range(const MetaWord* start, size_t word_size) const { |
|
144 DEBUG_ONLY(check_range(start, word_size)); |
|
145 assert(word_size > 0, "zero range"); |
|
146 const idx_t b1 = bitno_for_address(start); |
|
147 const idx_t b2 = bitno_for_address(start + word_size); |
|
148 const idx_t num_bits = count_one_bits_in_range(b1, b2); |
|
149 return num_bits * _words_per_bit; |
|
150 } |
|
151 |
|
152 // Return total committed size, in number of words. |
|
153 size_t get_committed_size() const { |
|
154 return count_one_bits() * _words_per_bit; |
|
155 } |
|
156 |
|
157 // Mark a whole address range [start, end) as committed. |
|
158 // Return the number of words which had already been committed before this operation. |
|
159 size_t mark_range_as_committed(const MetaWord* start, size_t word_size) { |
|
160 DEBUG_ONLY(check_range(start, word_size)); |
|
161 assert(word_size > 0, "zero range"); |
|
162 const idx_t b1 = bitno_for_address(start); |
|
163 const idx_t b2 = bitno_for_address(start + word_size); |
|
164 if (b1 == b2) { // Simple case, 1 granule |
|
165 bool was_committed = mark_granule(b1, true); |
|
166 return was_committed ? _words_per_bit : 0; |
|
167 } |
|
168 const idx_t one_bits_in_range_before = count_one_bits_in_range(b1, b2); |
|
169 set_range(b1, b2); |
|
170 return one_bits_in_range_before * _words_per_bit; |
|
171 } |
|
172 |
|
173 // Mark a whole address range [start, end) as uncommitted. |
|
174 // Return the number of words which had already been uncommitted before this operation. |
|
175 size_t mark_range_as_uncommitted(const MetaWord* start, size_t word_size) { |
|
176 DEBUG_ONLY(check_range(start, word_size)); |
|
177 assert(word_size > 0, "zero range"); |
|
178 const idx_t b1 = bitno_for_address(start); |
|
179 const idx_t b2 = bitno_for_address(start + word_size); |
|
180 if (b1 == b2) { // Simple case, 1 granule |
|
181 bool was_committed = mark_granule(b1, false); |
|
182 return was_committed ? 0 : _words_per_bit; |
|
183 } |
|
184 const idx_t zero_bits_in_range_before = |
|
185 (b2 - b1) - count_one_bits_in_range(b1, b2); |
|
186 clear_range(b1, b2); |
|
187 return zero_bits_in_range_before * _words_per_bit; |
|
188 } |
|
189 |
|
190 |
|
191 //// Debug stuff //// |
|
192 DEBUG_ONLY(void verify(bool slow, bool do_touch_test = true) const;) |
|
193 |
|
194 void print_on(outputStream* st) const; |
|
195 |
|
196 }; |
|
197 |
|
198 } // namespace metaspace |
|
199 |
|
200 #endif // SHARE_MEMORY_METASPACE_COMMITMASK_HPP |