1 | /* |
2 | * Copyright (c) 2001, 2019, Oracle and/or its affiliates. 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 it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 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 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #ifndef SHARE_GC_G1_G1COLLECTEDHEAP_INLINE_HPP |
26 | #define SHARE_GC_G1_G1COLLECTEDHEAP_INLINE_HPP |
27 | |
28 | #include "gc/g1/g1BarrierSet.hpp" |
29 | #include "gc/g1/g1CollectedHeap.hpp" |
30 | #include "gc/g1/g1CollectorState.hpp" |
31 | #include "gc/g1/g1Policy.hpp" |
32 | #include "gc/g1/g1RemSet.hpp" |
33 | #include "gc/g1/heapRegionManager.inline.hpp" |
34 | #include "gc/g1/heapRegionRemSet.hpp" |
35 | #include "gc/g1/heapRegionSet.inline.hpp" |
36 | #include "gc/shared/taskqueue.inline.hpp" |
37 | #include "runtime/orderAccess.hpp" |
38 | |
39 | G1GCPhaseTimes* G1CollectedHeap::phase_times() const { |
40 | return _policy->phase_times(); |
41 | } |
42 | |
43 | G1EvacStats* G1CollectedHeap::alloc_buffer_stats(G1HeapRegionAttr dest) { |
44 | switch (dest.type()) { |
45 | case G1HeapRegionAttr::Young: |
46 | return &_survivor_evac_stats; |
47 | case G1HeapRegionAttr::Old: |
48 | return &_old_evac_stats; |
49 | default: |
50 | ShouldNotReachHere(); |
51 | return NULL; // Keep some compilers happy |
52 | } |
53 | } |
54 | |
55 | size_t G1CollectedHeap::desired_plab_sz(G1HeapRegionAttr dest) { |
56 | size_t gclab_word_size = alloc_buffer_stats(dest)->desired_plab_sz(workers()->active_workers()); |
57 | // Prevent humongous PLAB sizes for two reasons: |
58 | // * PLABs are allocated using a similar paths as oops, but should |
59 | // never be in a humongous region |
60 | // * Allowing humongous PLABs needlessly churns the region free lists |
61 | return MIN2(_humongous_object_threshold_in_words, gclab_word_size); |
62 | } |
63 | |
64 | // Inline functions for G1CollectedHeap |
65 | |
66 | // Return the region with the given index. It assumes the index is valid. |
67 | inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm->at(index); } |
68 | |
69 | // Return the region with the given index, or NULL if unmapped. It assumes the index is valid. |
70 | inline HeapRegion* G1CollectedHeap::region_at_or_null(uint index) const { return _hrm->at_or_null(index); } |
71 | |
72 | inline HeapRegion* G1CollectedHeap::next_region_in_humongous(HeapRegion* hr) const { |
73 | return _hrm->next_region_in_humongous(hr); |
74 | } |
75 | |
76 | inline uint G1CollectedHeap::addr_to_region(HeapWord* addr) const { |
77 | assert(is_in_reserved(addr), |
78 | "Cannot calculate region index for address " PTR_FORMAT " that is outside of the heap [" PTR_FORMAT ", " PTR_FORMAT ")" , |
79 | p2i(addr), p2i(reserved_region().start()), p2i(reserved_region().end())); |
80 | return (uint)(pointer_delta(addr, reserved_region().start(), sizeof(uint8_t)) >> HeapRegion::LogOfHRGrainBytes); |
81 | } |
82 | |
83 | inline HeapWord* G1CollectedHeap::bottom_addr_for_region(uint index) const { |
84 | return _hrm->reserved().start() + index * HeapRegion::GrainWords; |
85 | } |
86 | |
87 | template <class T> |
88 | inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const { |
89 | assert(addr != NULL, "invariant" ); |
90 | assert(is_in_g1_reserved((const void*) addr), |
91 | "Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")" , |
92 | p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end())); |
93 | return _hrm->addr_to_region((HeapWord*) addr); |
94 | } |
95 | |
96 | template <class T> |
97 | inline HeapRegion* G1CollectedHeap::heap_region_containing_or_null(const T addr) const { |
98 | assert(addr != NULL, "invariant" ); |
99 | assert(is_in_g1_reserved((const void*) addr), |
100 | "Address " PTR_FORMAT " is outside of the heap ranging from [" PTR_FORMAT " to " PTR_FORMAT ")" , |
101 | p2i((void*)addr), p2i(g1_reserved().start()), p2i(g1_reserved().end())); |
102 | uint const region_idx = addr_to_region(addr); |
103 | return region_at_or_null(region_idx); |
104 | } |
105 | |
106 | inline void G1CollectedHeap::old_set_add(HeapRegion* hr) { |
107 | _old_set.add(hr); |
108 | } |
109 | |
110 | inline void G1CollectedHeap::old_set_remove(HeapRegion* hr) { |
111 | _old_set.remove(hr); |
112 | } |
113 | |
114 | inline void G1CollectedHeap::archive_set_add(HeapRegion* hr) { |
115 | _archive_set.add(hr); |
116 | } |
117 | |
118 | // It dirties the cards that cover the block so that the post |
119 | // write barrier never queues anything when updating objects on this |
120 | // block. It is assumed (and in fact we assert) that the block |
121 | // belongs to a young region. |
122 | inline void |
123 | G1CollectedHeap::dirty_young_block(HeapWord* start, size_t word_size) { |
124 | assert_heap_not_locked(); |
125 | |
126 | // Assign the containing region to containing_hr so that we don't |
127 | // have to keep calling heap_region_containing() in the |
128 | // asserts below. |
129 | DEBUG_ONLY(HeapRegion* containing_hr = heap_region_containing(start);) |
130 | assert(word_size > 0, "pre-condition" ); |
131 | assert(containing_hr->is_in(start), "it should contain start" ); |
132 | assert(containing_hr->is_young(), "it should be young" ); |
133 | assert(!containing_hr->is_humongous(), "it should not be humongous" ); |
134 | |
135 | HeapWord* end = start + word_size; |
136 | assert(containing_hr->is_in(end - 1), "it should also contain end - 1" ); |
137 | |
138 | MemRegion mr(start, end); |
139 | card_table()->g1_mark_as_young(mr); |
140 | } |
141 | |
142 | inline RefToScanQueue* G1CollectedHeap::task_queue(uint i) const { |
143 | return _task_queues->queue(i); |
144 | } |
145 | |
146 | inline bool G1CollectedHeap::is_marked_next(oop obj) const { |
147 | return _cm->next_mark_bitmap()->is_marked((HeapWord*)obj); |
148 | } |
149 | |
150 | inline bool G1CollectedHeap::is_in_cset(oop obj) { |
151 | return is_in_cset((HeapWord*)obj); |
152 | } |
153 | |
154 | inline bool G1CollectedHeap::is_in_cset(HeapWord* addr) { |
155 | return _region_attr.is_in_cset(addr); |
156 | } |
157 | |
158 | bool G1CollectedHeap::is_in_cset(const HeapRegion* hr) { |
159 | return _region_attr.is_in_cset(hr); |
160 | } |
161 | |
162 | bool G1CollectedHeap::is_in_cset_or_humongous(const oop obj) { |
163 | return _region_attr.is_in_cset_or_humongous((HeapWord*)obj); |
164 | } |
165 | |
166 | G1HeapRegionAttr G1CollectedHeap::region_attr(const void* addr) { |
167 | return _region_attr.at((HeapWord*)addr); |
168 | } |
169 | |
170 | void G1CollectedHeap::register_humongous_region_with_region_attr(uint index) { |
171 | _region_attr.set_humongous(index, region_at(index)->rem_set()->is_tracked()); |
172 | } |
173 | |
174 | void G1CollectedHeap::register_region_with_region_attr(HeapRegion* r) { |
175 | _region_attr.set_has_remset(r->hrm_index(), r->rem_set()->is_tracked()); |
176 | } |
177 | |
178 | void G1CollectedHeap::register_old_region_with_region_attr(HeapRegion* r) { |
179 | _region_attr.set_in_old(r->hrm_index(), r->rem_set()->is_tracked()); |
180 | _rem_set->prepare_for_scan_rem_set(r->hrm_index()); |
181 | } |
182 | |
183 | void G1CollectedHeap::register_optional_region_with_region_attr(HeapRegion* r) { |
184 | _region_attr.set_optional(r->hrm_index(), r->rem_set()->is_tracked()); |
185 | } |
186 | |
187 | #ifndef PRODUCT |
188 | // Support for G1EvacuationFailureALot |
189 | |
190 | inline bool |
191 | G1CollectedHeap::evacuation_failure_alot_for_gc_type(bool for_young_gc, |
192 | bool during_initial_mark, |
193 | bool mark_or_rebuild_in_progress) { |
194 | bool res = false; |
195 | if (mark_or_rebuild_in_progress) { |
196 | res |= G1EvacuationFailureALotDuringConcMark; |
197 | } |
198 | if (during_initial_mark) { |
199 | res |= G1EvacuationFailureALotDuringInitialMark; |
200 | } |
201 | if (for_young_gc) { |
202 | res |= G1EvacuationFailureALotDuringYoungGC; |
203 | } else { |
204 | // GCs are mixed |
205 | res |= G1EvacuationFailureALotDuringMixedGC; |
206 | } |
207 | return res; |
208 | } |
209 | |
210 | inline void |
211 | G1CollectedHeap::set_evacuation_failure_alot_for_current_gc() { |
212 | if (G1EvacuationFailureALot) { |
213 | // Note we can't assert that _evacuation_failure_alot_for_current_gc |
214 | // is clear here. It may have been set during a previous GC but that GC |
215 | // did not copy enough objects (i.e. G1EvacuationFailureALotCount) to |
216 | // trigger an evacuation failure and clear the flags and and counts. |
217 | |
218 | // Check if we have gone over the interval. |
219 | const size_t gc_num = total_collections(); |
220 | const size_t elapsed_gcs = gc_num - _evacuation_failure_alot_gc_number; |
221 | |
222 | _evacuation_failure_alot_for_current_gc = (elapsed_gcs >= G1EvacuationFailureALotInterval); |
223 | |
224 | // Now check if G1EvacuationFailureALot is enabled for the current GC type. |
225 | const bool in_young_only_phase = collector_state()->in_young_only_phase(); |
226 | const bool in_initial_mark_gc = collector_state()->in_initial_mark_gc(); |
227 | const bool mark_or_rebuild_in_progress = collector_state()->mark_or_rebuild_in_progress(); |
228 | |
229 | _evacuation_failure_alot_for_current_gc &= |
230 | evacuation_failure_alot_for_gc_type(in_young_only_phase, |
231 | in_initial_mark_gc, |
232 | mark_or_rebuild_in_progress); |
233 | } |
234 | } |
235 | |
236 | inline bool G1CollectedHeap::evacuation_should_fail() { |
237 | if (!G1EvacuationFailureALot || !_evacuation_failure_alot_for_current_gc) { |
238 | return false; |
239 | } |
240 | // G1EvacuationFailureALot is in effect for current GC |
241 | // Access to _evacuation_failure_alot_count is not atomic; |
242 | // the value does not have to be exact. |
243 | if (++_evacuation_failure_alot_count < G1EvacuationFailureALotCount) { |
244 | return false; |
245 | } |
246 | _evacuation_failure_alot_count = 0; |
247 | return true; |
248 | } |
249 | |
250 | inline void G1CollectedHeap::reset_evacuation_should_fail() { |
251 | if (G1EvacuationFailureALot) { |
252 | _evacuation_failure_alot_gc_number = total_collections(); |
253 | _evacuation_failure_alot_count = 0; |
254 | _evacuation_failure_alot_for_current_gc = false; |
255 | } |
256 | } |
257 | #endif // #ifndef PRODUCT |
258 | |
259 | inline bool G1CollectedHeap::is_in_young(const oop obj) { |
260 | if (obj == NULL) { |
261 | return false; |
262 | } |
263 | return heap_region_containing(obj)->is_young(); |
264 | } |
265 | |
266 | inline bool G1CollectedHeap::is_obj_dead(const oop obj) const { |
267 | if (obj == NULL) { |
268 | return false; |
269 | } |
270 | return is_obj_dead(obj, heap_region_containing(obj)); |
271 | } |
272 | |
273 | inline bool G1CollectedHeap::is_obj_ill(const oop obj) const { |
274 | if (obj == NULL) { |
275 | return false; |
276 | } |
277 | return is_obj_ill(obj, heap_region_containing(obj)); |
278 | } |
279 | |
280 | inline bool G1CollectedHeap::is_obj_dead_full(const oop obj, const HeapRegion* hr) const { |
281 | return !is_marked_next(obj) && !hr->is_archive(); |
282 | } |
283 | |
284 | inline bool G1CollectedHeap::is_obj_dead_full(const oop obj) const { |
285 | return is_obj_dead_full(obj, heap_region_containing(obj)); |
286 | } |
287 | |
288 | inline void G1CollectedHeap::set_humongous_reclaim_candidate(uint region, bool value) { |
289 | assert(_hrm->at(region)->is_starts_humongous(), "Must start a humongous object" ); |
290 | _humongous_reclaim_candidates.set_candidate(region, value); |
291 | } |
292 | |
293 | inline bool G1CollectedHeap::is_humongous_reclaim_candidate(uint region) { |
294 | assert(_hrm->at(region)->is_starts_humongous(), "Must start a humongous object" ); |
295 | return _humongous_reclaim_candidates.is_candidate(region); |
296 | } |
297 | |
298 | inline void G1CollectedHeap::set_humongous_is_live(oop obj) { |
299 | uint region = addr_to_region((HeapWord*)obj); |
300 | // Clear the flag in the humongous_reclaim_candidates table. Also |
301 | // reset the entry in the region attribute table so that subsequent references |
302 | // to the same humongous object do not go into the slow path again. |
303 | // This is racy, as multiple threads may at the same time enter here, but this |
304 | // is benign. |
305 | // During collection we only ever clear the "candidate" flag, and only ever clear the |
306 | // entry in the in_cset_fast_table. |
307 | // We only ever evaluate the contents of these tables (in the VM thread) after |
308 | // having synchronized the worker threads with the VM thread, or in the same |
309 | // thread (i.e. within the VM thread). |
310 | if (is_humongous_reclaim_candidate(region)) { |
311 | set_humongous_reclaim_candidate(region, false); |
312 | _region_attr.clear_humongous(region); |
313 | } |
314 | } |
315 | |
316 | #endif // SHARE_GC_G1_G1COLLECTEDHEAP_INLINE_HPP |
317 | |