1/*
2 * Copyright (c) 2002, 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_PARALLEL_PSPROMOTIONMANAGER_INLINE_HPP
26#define SHARE_GC_PARALLEL_PSPROMOTIONMANAGER_INLINE_HPP
27
28#include "gc/parallel/parallelScavengeHeap.hpp"
29#include "gc/parallel/parMarkBitMap.inline.hpp"
30#include "gc/parallel/psOldGen.hpp"
31#include "gc/parallel/psPromotionLAB.inline.hpp"
32#include "gc/parallel/psPromotionManager.hpp"
33#include "gc/parallel/psScavenge.inline.hpp"
34#include "gc/shared/taskqueue.inline.hpp"
35#include "logging/log.hpp"
36#include "memory/iterator.inline.hpp"
37#include "oops/access.inline.hpp"
38#include "oops/oop.inline.hpp"
39
40inline PSPromotionManager* PSPromotionManager::manager_array(uint index) {
41 assert(_manager_array != NULL, "access of NULL manager_array");
42 assert(index <= ParallelGCThreads, "out of range manager_array access");
43 return &_manager_array[index];
44}
45
46template <class T>
47inline void PSPromotionManager::push_depth(T* p) {
48 claimed_stack_depth()->push(p);
49}
50
51template <class T>
52inline void PSPromotionManager::claim_or_forward_internal_depth(T* p) {
53 if (p != NULL) { // XXX: error if p != NULL here
54 oop o = RawAccess<IS_NOT_NULL>::oop_load(p);
55 if (o->is_forwarded()) {
56 o = o->forwardee();
57 // Card mark
58 if (PSScavenge::is_obj_in_young(o)) {
59 PSScavenge::card_table()->inline_write_ref_field_gc(p, o);
60 }
61 RawAccess<IS_NOT_NULL>::oop_store(p, o);
62 } else {
63 push_depth(p);
64 }
65 }
66}
67
68template <class T>
69inline void PSPromotionManager::claim_or_forward_depth(T* p) {
70 assert(should_scavenge(p, true), "revisiting object?");
71 assert(ParallelScavengeHeap::heap()->is_in(p), "pointer outside heap");
72
73 claim_or_forward_internal_depth(p);
74}
75
76inline void PSPromotionManager::promotion_trace_event(oop new_obj, oop old_obj,
77 size_t obj_size,
78 uint age, bool tenured,
79 const PSPromotionLAB* lab) {
80 // Skip if memory allocation failed
81 if (new_obj != NULL) {
82 const ParallelScavengeTracer* gc_tracer = PSScavenge::gc_tracer();
83
84 if (lab != NULL) {
85 // Promotion of object through newly allocated PLAB
86 if (gc_tracer->should_report_promotion_in_new_plab_event()) {
87 size_t obj_bytes = obj_size * HeapWordSize;
88 size_t lab_size = lab->capacity();
89 gc_tracer->report_promotion_in_new_plab_event(old_obj->klass(), obj_bytes,
90 age, tenured, lab_size);
91 }
92 } else {
93 // Promotion of object directly to heap
94 if (gc_tracer->should_report_promotion_outside_plab_event()) {
95 size_t obj_bytes = obj_size * HeapWordSize;
96 gc_tracer->report_promotion_outside_plab_event(old_obj->klass(), obj_bytes,
97 age, tenured);
98 }
99 }
100 }
101}
102
103class PSPushContentsClosure: public BasicOopIterateClosure {
104 PSPromotionManager* _pm;
105 public:
106 PSPushContentsClosure(PSPromotionManager* pm) : BasicOopIterateClosure(PSScavenge::reference_processor()), _pm(pm) {}
107
108 template <typename T> void do_oop_nv(T* p) {
109 if (PSScavenge::should_scavenge(p)) {
110 _pm->claim_or_forward_depth(p);
111 }
112 }
113
114 virtual void do_oop(oop* p) { do_oop_nv(p); }
115 virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
116
117 // Don't use the oop verification code in the oop_oop_iterate framework.
118 debug_only(virtual bool should_verify_oops() { return false; })
119};
120
121//
122// This closure specialization will override the one that is defined in
123// instanceRefKlass.inline.cpp. It swaps the order of oop_oop_iterate and
124// oop_oop_iterate_ref_processing. Unfortunately G1 and Parallel behaves
125// significantly better (especially in the Derby benchmark) using opposite
126// order of these function calls.
127//
128template <>
129inline void InstanceRefKlass::oop_oop_iterate_reverse<oop, PSPushContentsClosure>(oop obj, PSPushContentsClosure* closure) {
130 oop_oop_iterate_ref_processing<oop>(obj, closure);
131 InstanceKlass::oop_oop_iterate_reverse<oop>(obj, closure);
132}
133
134template <>
135inline void InstanceRefKlass::oop_oop_iterate_reverse<narrowOop, PSPushContentsClosure>(oop obj, PSPushContentsClosure* closure) {
136 oop_oop_iterate_ref_processing<narrowOop>(obj, closure);
137 InstanceKlass::oop_oop_iterate_reverse<narrowOop>(obj, closure);
138}
139
140inline void PSPromotionManager::push_contents(oop obj) {
141 if (!obj->klass()->is_typeArray_klass()) {
142 PSPushContentsClosure pcc(this);
143 obj->oop_iterate_backwards(&pcc);
144 }
145}
146//
147// This method is pretty bulky. It would be nice to split it up
148// into smaller submethods, but we need to be careful not to hurt
149// performance.
150//
151template<bool promote_immediately>
152inline oop PSPromotionManager::copy_to_survivor_space(oop o) {
153 assert(should_scavenge(&o), "Sanity");
154
155 oop new_obj = NULL;
156
157 // NOTE! We must be very careful with any methods that access the mark
158 // in o. There may be multiple threads racing on it, and it may be forwarded
159 // at any time. Do not use oop methods for accessing the mark!
160 markOop test_mark = o->mark_raw();
161
162 // The same test as "o->is_forwarded()"
163 if (!test_mark->is_marked()) {
164 bool new_obj_is_tenured = false;
165 size_t new_obj_size = o->size();
166
167 // Find the objects age, MT safe.
168 uint age = (test_mark->has_displaced_mark_helper() /* o->has_displaced_mark() */) ?
169 test_mark->displaced_mark_helper()->age() : test_mark->age();
170
171 if (!promote_immediately) {
172 // Try allocating obj in to-space (unless too old)
173 if (age < PSScavenge::tenuring_threshold()) {
174 new_obj = (oop) _young_lab.allocate(new_obj_size);
175 if (new_obj == NULL && !_young_gen_is_full) {
176 // Do we allocate directly, or flush and refill?
177 if (new_obj_size > (YoungPLABSize / 2)) {
178 // Allocate this object directly
179 new_obj = (oop)young_space()->cas_allocate(new_obj_size);
180 promotion_trace_event(new_obj, o, new_obj_size, age, false, NULL);
181 } else {
182 // Flush and fill
183 _young_lab.flush();
184
185 HeapWord* lab_base = young_space()->cas_allocate(YoungPLABSize);
186 if (lab_base != NULL) {
187 _young_lab.initialize(MemRegion(lab_base, YoungPLABSize));
188 // Try the young lab allocation again.
189 new_obj = (oop) _young_lab.allocate(new_obj_size);
190 promotion_trace_event(new_obj, o, new_obj_size, age, false, &_young_lab);
191 } else {
192 _young_gen_is_full = true;
193 }
194 }
195 }
196 }
197 }
198
199 // Otherwise try allocating obj tenured
200 if (new_obj == NULL) {
201#ifndef PRODUCT
202 if (ParallelScavengeHeap::heap()->promotion_should_fail()) {
203 return oop_promotion_failed(o, test_mark);
204 }
205#endif // #ifndef PRODUCT
206
207 new_obj = (oop) _old_lab.allocate(new_obj_size);
208 new_obj_is_tenured = true;
209
210 if (new_obj == NULL) {
211 if (!_old_gen_is_full) {
212 // Do we allocate directly, or flush and refill?
213 if (new_obj_size > (OldPLABSize / 2)) {
214 // Allocate this object directly
215 new_obj = (oop)old_gen()->cas_allocate(new_obj_size);
216 promotion_trace_event(new_obj, o, new_obj_size, age, true, NULL);
217 } else {
218 // Flush and fill
219 _old_lab.flush();
220
221 HeapWord* lab_base = old_gen()->cas_allocate(OldPLABSize);
222 if(lab_base != NULL) {
223#ifdef ASSERT
224 // Delay the initialization of the promotion lab (plab).
225 // This exposes uninitialized plabs to card table processing.
226 if (GCWorkerDelayMillis > 0) {
227 os::sleep(Thread::current(), GCWorkerDelayMillis, false);
228 }
229#endif
230 _old_lab.initialize(MemRegion(lab_base, OldPLABSize));
231 // Try the old lab allocation again.
232 new_obj = (oop) _old_lab.allocate(new_obj_size);
233 promotion_trace_event(new_obj, o, new_obj_size, age, true, &_old_lab);
234 }
235 }
236 }
237
238 // This is the promotion failed test, and code handling.
239 // The code belongs here for two reasons. It is slightly
240 // different than the code below, and cannot share the
241 // CAS testing code. Keeping the code here also minimizes
242 // the impact on the common case fast path code.
243
244 if (new_obj == NULL) {
245 _old_gen_is_full = true;
246 return oop_promotion_failed(o, test_mark);
247 }
248 }
249 }
250
251 assert(new_obj != NULL, "allocation should have succeeded");
252
253 // Copy obj
254 Copy::aligned_disjoint_words((HeapWord*)o, (HeapWord*)new_obj, new_obj_size);
255
256 // Now we have to CAS in the header.
257 // Make copy visible to threads reading the forwardee.
258 if (o->cas_forward_to(new_obj, test_mark, memory_order_release)) {
259 // We won any races, we "own" this object.
260 assert(new_obj == o->forwardee(), "Sanity");
261
262 // Increment age if obj still in new generation. Now that
263 // we're dealing with a markOop that cannot change, it is
264 // okay to use the non mt safe oop methods.
265 if (!new_obj_is_tenured) {
266 new_obj->incr_age();
267 assert(young_space()->contains(new_obj), "Attempt to push non-promoted obj");
268 }
269
270 // Do the size comparison first with new_obj_size, which we
271 // already have. Hopefully, only a few objects are larger than
272 // _min_array_size_for_chunking, and most of them will be arrays.
273 // So, the is->objArray() test would be very infrequent.
274 if (new_obj_size > _min_array_size_for_chunking &&
275 new_obj->is_objArray() &&
276 PSChunkLargeArrays) {
277 // we'll chunk it
278 oop* const masked_o = mask_chunked_array_oop(o);
279 push_depth(masked_o);
280 TASKQUEUE_STATS_ONLY(++_arrays_chunked; ++_masked_pushes);
281 } else {
282 // we'll just push its contents
283 push_contents(new_obj);
284 }
285 } else {
286 // We lost, someone else "owns" this object
287 guarantee(o->is_forwarded(), "Object must be forwarded if the cas failed.");
288
289 // Try to deallocate the space. If it was directly allocated we cannot
290 // deallocate it, so we have to test. If the deallocation fails,
291 // overwrite with a filler object.
292 if (new_obj_is_tenured) {
293 if (!_old_lab.unallocate_object((HeapWord*) new_obj, new_obj_size)) {
294 CollectedHeap::fill_with_object((HeapWord*) new_obj, new_obj_size);
295 }
296 } else if (!_young_lab.unallocate_object((HeapWord*) new_obj, new_obj_size)) {
297 CollectedHeap::fill_with_object((HeapWord*) new_obj, new_obj_size);
298 }
299
300 // don't update this before the unallocation!
301 // Using acquire though consume would be accurate for accessing new_obj.
302 new_obj = o->forwardee_acquire();
303 }
304 } else {
305 assert(o->is_forwarded(), "Sanity");
306 new_obj = o->forwardee_acquire();
307 }
308
309 // This code must come after the CAS test, or it will print incorrect
310 // information.
311 log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}",
312 should_scavenge(&new_obj) ? "copying" : "tenuring",
313 new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size());
314
315 return new_obj;
316}
317
318// Attempt to "claim" oop at p via CAS, push the new obj if successful
319// This version tests the oop* to make sure it is within the heap before
320// attempting marking.
321template <class T, bool promote_immediately>
322inline void PSPromotionManager::copy_and_push_safe_barrier(T* p) {
323 assert(should_scavenge(p, true), "revisiting object?");
324
325 oop o = RawAccess<IS_NOT_NULL>::oop_load(p);
326 oop new_obj = o->is_forwarded()
327 ? o->forwardee()
328 : copy_to_survivor_space<promote_immediately>(o);
329
330 // This code must come after the CAS test, or it will print incorrect
331 // information.
332 if (log_develop_is_enabled(Trace, gc, scavenge) && o->is_forwarded()) {
333 log_develop_trace(gc, scavenge)("{%s %s " PTR_FORMAT " -> " PTR_FORMAT " (%d)}",
334 "forwarding",
335 new_obj->klass()->internal_name(), p2i((void *)o), p2i((void *)new_obj), new_obj->size());
336 }
337
338 RawAccess<IS_NOT_NULL>::oop_store(p, new_obj);
339
340 // We cannot mark without test, as some code passes us pointers
341 // that are outside the heap. These pointers are either from roots
342 // or from metadata.
343 if ((!PSScavenge::is_obj_in_young((HeapWord*)p)) &&
344 ParallelScavengeHeap::heap()->is_in_reserved(p)) {
345 if (PSScavenge::is_obj_in_young(new_obj)) {
346 PSScavenge::card_table()->inline_write_ref_field_gc(p, new_obj);
347 }
348 }
349}
350
351inline void PSPromotionManager::process_popped_location_depth(StarTask p) {
352 if (is_oop_masked(p)) {
353 assert(PSChunkLargeArrays, "invariant");
354 oop const old = unmask_chunked_array_oop(p);
355 process_array_chunk(old);
356 } else {
357 if (p.is_narrow()) {
358 assert(UseCompressedOops, "Error");
359 copy_and_push_safe_barrier<narrowOop, /*promote_immediately=*/false>(p);
360 } else {
361 copy_and_push_safe_barrier<oop, /*promote_immediately=*/false>(p);
362 }
363 }
364}
365
366inline bool PSPromotionManager::steal_depth(int queue_num, StarTask& t) {
367 return stack_array_depth()->steal(queue_num, t);
368}
369
370#if TASKQUEUE_STATS
371void PSPromotionManager::record_steal(StarTask& p) {
372 if (is_oop_masked(p)) {
373 ++_masked_steals;
374 }
375}
376#endif // TASKQUEUE_STATS
377
378#endif // SHARE_GC_PARALLEL_PSPROMOTIONMANAGER_INLINE_HPP
379