1 | /* |
2 | * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved. |
3 | * |
4 | * This code is free software; you can redistribute it and/or modify it |
5 | * under the terms of the GNU General Public License version 2 only, as |
6 | * published by the Free Software Foundation. |
7 | * |
8 | * This code is distributed in the hope that it will be useful, but WITHOUT |
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
11 | * version 2 for more details (a copy is included in the LICENSE file that |
12 | * accompanied this code). |
13 | * |
14 | * You should have received a copy of the GNU General Public License version |
15 | * 2 along with this work; if not, write to the Free Software Foundation, |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
17 | * |
18 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
19 | * or visit www.oracle.com if you need additional information or have any |
20 | * questions. |
21 | * |
22 | */ |
23 | |
24 | #include "precompiled.hpp" |
25 | |
26 | #include "classfile/symbolTable.hpp" |
27 | #include "classfile/systemDictionary.hpp" |
28 | #include "code/codeCache.hpp" |
29 | |
30 | #include "gc/shared/weakProcessor.inline.hpp" |
31 | #include "gc/shared/gcTimer.hpp" |
32 | #include "gc/shared/referenceProcessor.hpp" |
33 | #include "gc/shared/referenceProcessorPhaseTimes.hpp" |
34 | |
35 | #include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" |
36 | #include "gc/shenandoah/shenandoahClosures.inline.hpp" |
37 | #include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp" |
38 | #include "gc/shenandoah/shenandoahMarkCompact.hpp" |
39 | #include "gc/shenandoah/shenandoahHeap.inline.hpp" |
40 | #include "gc/shenandoah/shenandoahRootProcessor.inline.hpp" |
41 | #include "gc/shenandoah/shenandoahOopClosures.inline.hpp" |
42 | #include "gc/shenandoah/shenandoahTaskqueue.inline.hpp" |
43 | #include "gc/shenandoah/shenandoahTimingTracker.hpp" |
44 | #include "gc/shenandoah/shenandoahUtils.hpp" |
45 | |
46 | #include "memory/iterator.inline.hpp" |
47 | #include "memory/metaspace.hpp" |
48 | #include "memory/resourceArea.hpp" |
49 | #include "oops/oop.inline.hpp" |
50 | #include "runtime/handles.inline.hpp" |
51 | |
52 | template<UpdateRefsMode UPDATE_REFS> |
53 | class ShenandoahInitMarkRootsClosure : public OopClosure { |
54 | private: |
55 | ShenandoahObjToScanQueue* _queue; |
56 | ShenandoahHeap* _heap; |
57 | ShenandoahMarkingContext* const _mark_context; |
58 | |
59 | template <class T> |
60 | inline void do_oop_work(T* p) { |
61 | ShenandoahConcurrentMark::mark_through_ref<T, UPDATE_REFS, NO_DEDUP>(p, _heap, _queue, _mark_context); |
62 | } |
63 | |
64 | public: |
65 | ShenandoahInitMarkRootsClosure(ShenandoahObjToScanQueue* q) : |
66 | _queue(q), |
67 | _heap(ShenandoahHeap::heap()), |
68 | _mark_context(_heap->marking_context()) {}; |
69 | |
70 | void do_oop(narrowOop* p) { do_oop_work(p); } |
71 | void do_oop(oop* p) { do_oop_work(p); } |
72 | }; |
73 | |
74 | ShenandoahMarkRefsSuperClosure::ShenandoahMarkRefsSuperClosure(ShenandoahObjToScanQueue* q, ReferenceProcessor* rp) : |
75 | MetadataVisitingOopIterateClosure(rp), |
76 | _queue(q), |
77 | _heap(ShenandoahHeap::heap()), |
78 | _mark_context(_heap->marking_context()) |
79 | { } |
80 | |
81 | template<UpdateRefsMode UPDATE_REFS> |
82 | class ShenandoahInitMarkRootsTask : public AbstractGangTask { |
83 | private: |
84 | ShenandoahAllRootScanner* _rp; |
85 | bool _process_refs; |
86 | public: |
87 | ShenandoahInitMarkRootsTask(ShenandoahAllRootScanner* rp, bool process_refs) : |
88 | AbstractGangTask("Shenandoah init mark roots task" ), |
89 | _rp(rp), |
90 | _process_refs(process_refs) { |
91 | } |
92 | |
93 | void work(uint worker_id) { |
94 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
95 | ShenandoahParallelWorkerSession worker_session(worker_id); |
96 | |
97 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
98 | ShenandoahObjToScanQueueSet* queues = heap->concurrent_mark()->task_queues(); |
99 | assert(queues->get_reserved() > worker_id, "Queue has not been reserved for worker id: %d" , worker_id); |
100 | |
101 | ShenandoahObjToScanQueue* q = queues->queue(worker_id); |
102 | |
103 | ShenandoahInitMarkRootsClosure<UPDATE_REFS> mark_cl(q); |
104 | do_work(heap, &mark_cl, worker_id); |
105 | } |
106 | |
107 | private: |
108 | void do_work(ShenandoahHeap* heap, OopClosure* oops, uint worker_id) { |
109 | // The rationale for selecting the roots to scan is as follows: |
110 | // a. With unload_classes = true, we only want to scan the actual strong roots from the |
111 | // code cache. This will allow us to identify the dead classes, unload them, *and* |
112 | // invalidate the relevant code cache blobs. This could be only done together with |
113 | // class unloading. |
114 | // b. With unload_classes = false, we have to nominally retain all the references from code |
115 | // cache, because there could be the case of embedded class/oop in the generated code, |
116 | // which we will never visit during mark. Without code cache invalidation, as in (a), |
117 | // we risk executing that code cache blob, and crashing. |
118 | if (heap->unload_classes()) { |
119 | _rp->strong_roots_do(worker_id, oops); |
120 | } else { |
121 | _rp->roots_do(worker_id, oops); |
122 | } |
123 | } |
124 | }; |
125 | |
126 | class ShenandoahUpdateRootsTask : public AbstractGangTask { |
127 | private: |
128 | ShenandoahRootUpdater* _root_updater; |
129 | public: |
130 | ShenandoahUpdateRootsTask(ShenandoahRootUpdater* root_updater) : |
131 | AbstractGangTask("Shenandoah update roots task" ), |
132 | _root_updater(root_updater) { |
133 | } |
134 | |
135 | void work(uint worker_id) { |
136 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
137 | ShenandoahParallelWorkerSession worker_session(worker_id); |
138 | |
139 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
140 | ShenandoahUpdateRefsClosure cl; |
141 | AlwaysTrueClosure always_true; |
142 | _root_updater->roots_do<AlwaysTrueClosure, ShenandoahUpdateRefsClosure>(worker_id, &always_true, &cl); |
143 | } |
144 | }; |
145 | |
146 | class ShenandoahConcurrentMarkingTask : public AbstractGangTask { |
147 | private: |
148 | ShenandoahConcurrentMark* _cm; |
149 | ShenandoahTaskTerminator* _terminator; |
150 | |
151 | public: |
152 | ShenandoahConcurrentMarkingTask(ShenandoahConcurrentMark* cm, ShenandoahTaskTerminator* terminator) : |
153 | AbstractGangTask("Root Region Scan" ), _cm(cm), _terminator(terminator) { |
154 | } |
155 | |
156 | void work(uint worker_id) { |
157 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
158 | ShenandoahConcurrentWorkerSession worker_session(worker_id); |
159 | ShenandoahSuspendibleThreadSetJoiner stsj(ShenandoahSuspendibleWorkers); |
160 | ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id); |
161 | ReferenceProcessor* rp; |
162 | if (heap->process_references()) { |
163 | rp = heap->ref_processor(); |
164 | shenandoah_assert_rp_isalive_installed(); |
165 | } else { |
166 | rp = NULL; |
167 | } |
168 | |
169 | _cm->concurrent_scan_code_roots(worker_id, rp); |
170 | _cm->mark_loop(worker_id, _terminator, rp, |
171 | true, // cancellable |
172 | ShenandoahStringDedup::is_enabled()); // perform string dedup |
173 | } |
174 | }; |
175 | |
176 | class ShenandoahSATBThreadsClosure : public ThreadClosure { |
177 | private: |
178 | ShenandoahSATBBufferClosure* _satb_cl; |
179 | uintx _claim_token; |
180 | |
181 | public: |
182 | ShenandoahSATBThreadsClosure(ShenandoahSATBBufferClosure* satb_cl) : |
183 | _satb_cl(satb_cl), |
184 | _claim_token(Threads::thread_claim_token()) {} |
185 | |
186 | void do_thread(Thread* thread) { |
187 | if (thread->claim_threads_do(true, _claim_token)) { |
188 | ShenandoahThreadLocalData::satb_mark_queue(thread).apply_closure_and_empty(_satb_cl); |
189 | } |
190 | } |
191 | }; |
192 | |
193 | class ShenandoahFinalMarkingTask : public AbstractGangTask { |
194 | private: |
195 | ShenandoahConcurrentMark* _cm; |
196 | ShenandoahTaskTerminator* _terminator; |
197 | bool _dedup_string; |
198 | |
199 | public: |
200 | ShenandoahFinalMarkingTask(ShenandoahConcurrentMark* cm, ShenandoahTaskTerminator* terminator, bool dedup_string) : |
201 | AbstractGangTask("Shenandoah Final Marking" ), _cm(cm), _terminator(terminator), _dedup_string(dedup_string) { |
202 | } |
203 | |
204 | void work(uint worker_id) { |
205 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
206 | |
207 | ShenandoahParallelWorkerSession worker_session(worker_id); |
208 | // First drain remaining SATB buffers. |
209 | // Notice that this is not strictly necessary for mark-compact. But since |
210 | // it requires a StrongRootsScope around the task, we need to claim the |
211 | // threads, and performance-wise it doesn't really matter. Adds about 1ms to |
212 | // full-gc. |
213 | { |
214 | ShenandoahObjToScanQueue* q = _cm->get_queue(worker_id); |
215 | ShenandoahSATBBufferClosure cl(q); |
216 | SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); |
217 | while (satb_mq_set.apply_closure_to_completed_buffer(&cl)); |
218 | ShenandoahSATBThreadsClosure tc(&cl); |
219 | Threads::threads_do(&tc); |
220 | } |
221 | |
222 | ReferenceProcessor* rp; |
223 | if (heap->process_references()) { |
224 | rp = heap->ref_processor(); |
225 | shenandoah_assert_rp_isalive_installed(); |
226 | } else { |
227 | rp = NULL; |
228 | } |
229 | |
230 | if (heap->is_degenerated_gc_in_progress()) { |
231 | // Degenerated cycle may bypass concurrent cycle, so code roots might not be scanned, |
232 | // let's check here. |
233 | _cm->concurrent_scan_code_roots(worker_id, rp); |
234 | } |
235 | |
236 | _cm->mark_loop(worker_id, _terminator, rp, |
237 | false, // not cancellable |
238 | _dedup_string); |
239 | |
240 | assert(_cm->task_queues()->is_empty(), "Should be empty" ); |
241 | } |
242 | }; |
243 | |
244 | void ShenandoahConcurrentMark::mark_roots(ShenandoahPhaseTimings::Phase root_phase) { |
245 | assert(Thread::current()->is_VM_thread(), "can only do this in VMThread" ); |
246 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
247 | |
248 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
249 | |
250 | ShenandoahGCPhase phase(root_phase); |
251 | |
252 | WorkGang* workers = heap->workers(); |
253 | uint nworkers = workers->active_workers(); |
254 | |
255 | assert(nworkers <= task_queues()->size(), "Just check" ); |
256 | |
257 | ShenandoahAllRootScanner root_proc(nworkers, root_phase); |
258 | TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); |
259 | task_queues()->reserve(nworkers); |
260 | |
261 | if (heap->has_forwarded_objects()) { |
262 | ShenandoahInitMarkRootsTask<RESOLVE> mark_roots(&root_proc, _heap->process_references()); |
263 | workers->run_task(&mark_roots); |
264 | } else { |
265 | // No need to update references, which means the heap is stable. |
266 | // Can save time not walking through forwarding pointers. |
267 | ShenandoahInitMarkRootsTask<NONE> mark_roots(&root_proc, _heap->process_references()); |
268 | workers->run_task(&mark_roots); |
269 | } |
270 | |
271 | if (ShenandoahConcurrentScanCodeRoots) { |
272 | clear_claim_codecache(); |
273 | } |
274 | } |
275 | |
276 | void ShenandoahConcurrentMark::update_roots(ShenandoahPhaseTimings::Phase root_phase) { |
277 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
278 | |
279 | bool update_code_cache = true; // initialize to safer value |
280 | switch (root_phase) { |
281 | case ShenandoahPhaseTimings::update_roots: |
282 | case ShenandoahPhaseTimings::final_update_refs_roots: |
283 | update_code_cache = false; |
284 | break; |
285 | case ShenandoahPhaseTimings::full_gc_roots: |
286 | case ShenandoahPhaseTimings::degen_gc_update_roots: |
287 | update_code_cache = true; |
288 | break; |
289 | default: |
290 | ShouldNotReachHere(); |
291 | } |
292 | |
293 | ShenandoahGCPhase phase(root_phase); |
294 | |
295 | #if COMPILER2_OR_JVMCI |
296 | DerivedPointerTable::clear(); |
297 | #endif |
298 | |
299 | uint nworkers = _heap->workers()->active_workers(); |
300 | |
301 | ShenandoahRootUpdater root_updater(nworkers, root_phase, update_code_cache); |
302 | ShenandoahUpdateRootsTask update_roots(&root_updater); |
303 | _heap->workers()->run_task(&update_roots); |
304 | |
305 | #if COMPILER2_OR_JVMCI |
306 | DerivedPointerTable::update_pointers(); |
307 | #endif |
308 | } |
309 | |
310 | class ShenandoahUpdateThreadRootsTask : public AbstractGangTask { |
311 | private: |
312 | ShenandoahThreadRoots _thread_roots; |
313 | ShenandoahPhaseTimings::Phase _phase; |
314 | public: |
315 | ShenandoahUpdateThreadRootsTask(bool is_par, ShenandoahPhaseTimings::Phase phase) : |
316 | AbstractGangTask("Shenandoah Update Thread Roots" ), |
317 | _thread_roots(is_par), |
318 | _phase(phase) { |
319 | ShenandoahHeap::heap()->phase_timings()->record_workers_start(_phase); |
320 | } |
321 | |
322 | ~ShenandoahUpdateThreadRootsTask() { |
323 | ShenandoahHeap::heap()->phase_timings()->record_workers_end(_phase); |
324 | } |
325 | void work(uint worker_id) { |
326 | ShenandoahUpdateRefsClosure cl; |
327 | _thread_roots.oops_do(&cl, NULL, worker_id); |
328 | } |
329 | }; |
330 | |
331 | void ShenandoahConcurrentMark::update_thread_roots(ShenandoahPhaseTimings::Phase root_phase) { |
332 | WorkGang* workers = _heap->workers(); |
333 | bool is_par = workers->active_workers() > 1; |
334 | #if COMPILER2_OR_JVMCI |
335 | DerivedPointerTable::clear(); |
336 | #endif |
337 | ShenandoahUpdateThreadRootsTask task(is_par, root_phase); |
338 | workers->run_task(&task); |
339 | #if COMPILER2_OR_JVMCI |
340 | DerivedPointerTable::update_pointers(); |
341 | #endif |
342 | } |
343 | |
344 | void ShenandoahConcurrentMark::initialize(uint workers) { |
345 | _heap = ShenandoahHeap::heap(); |
346 | |
347 | uint num_queues = MAX2(workers, 1U); |
348 | |
349 | _task_queues = new ShenandoahObjToScanQueueSet((int) num_queues); |
350 | |
351 | for (uint i = 0; i < num_queues; ++i) { |
352 | ShenandoahObjToScanQueue* task_queue = new ShenandoahObjToScanQueue(); |
353 | task_queue->initialize(); |
354 | _task_queues->register_queue(i, task_queue); |
355 | } |
356 | } |
357 | |
358 | void ShenandoahConcurrentMark::concurrent_scan_code_roots(uint worker_id, ReferenceProcessor* rp) { |
359 | if (ShenandoahConcurrentScanCodeRoots && claim_codecache()) { |
360 | ShenandoahObjToScanQueue* q = task_queues()->queue(worker_id); |
361 | if (!_heap->unload_classes()) { |
362 | MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); |
363 | // TODO: We can not honor StringDeduplication here, due to lock ranking |
364 | // inversion. So, we may miss some deduplication candidates. |
365 | if (_heap->has_forwarded_objects()) { |
366 | ShenandoahMarkResolveRefsClosure cl(q, rp); |
367 | CodeBlobToOopClosure blobs(&cl, !CodeBlobToOopClosure::FixRelocations); |
368 | CodeCache::blobs_do(&blobs); |
369 | } else { |
370 | ShenandoahMarkRefsClosure cl(q, rp); |
371 | CodeBlobToOopClosure blobs(&cl, !CodeBlobToOopClosure::FixRelocations); |
372 | CodeCache::blobs_do(&blobs); |
373 | } |
374 | } |
375 | } |
376 | } |
377 | |
378 | void ShenandoahConcurrentMark::mark_from_roots() { |
379 | WorkGang* workers = _heap->workers(); |
380 | uint nworkers = workers->active_workers(); |
381 | |
382 | ShenandoahGCPhase conc_mark_phase(ShenandoahPhaseTimings::conc_mark); |
383 | |
384 | if (_heap->process_references()) { |
385 | ReferenceProcessor* rp = _heap->ref_processor(); |
386 | rp->set_active_mt_degree(nworkers); |
387 | |
388 | // enable ("weak") refs discovery |
389 | rp->enable_discovery(true /*verify_no_refs*/); |
390 | rp->setup_policy(_heap->soft_ref_policy()->should_clear_all_soft_refs()); |
391 | } |
392 | |
393 | shenandoah_assert_rp_isalive_not_installed(); |
394 | ShenandoahIsAliveSelector is_alive; |
395 | ReferenceProcessorIsAliveMutator fix_isalive(_heap->ref_processor(), is_alive.is_alive_closure()); |
396 | |
397 | task_queues()->reserve(nworkers); |
398 | |
399 | { |
400 | ShenandoahTerminationTracker term(ShenandoahPhaseTimings::conc_termination); |
401 | ShenandoahTaskTerminator terminator(nworkers, task_queues()); |
402 | ShenandoahConcurrentMarkingTask task(this, &terminator); |
403 | workers->run_task(&task); |
404 | } |
405 | |
406 | assert(task_queues()->is_empty() || _heap->cancelled_gc(), "Should be empty when not cancelled" ); |
407 | } |
408 | |
409 | void ShenandoahConcurrentMark::finish_mark_from_roots(bool full_gc) { |
410 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
411 | |
412 | uint nworkers = _heap->workers()->active_workers(); |
413 | |
414 | // Finally mark everything else we've got in our queues during the previous steps. |
415 | // It does two different things for concurrent vs. mark-compact GC: |
416 | // - For concurrent GC, it starts with empty task queues, drains the remaining |
417 | // SATB buffers, and then completes the marking closure. |
418 | // - For mark-compact GC, it starts out with the task queues seeded by initial |
419 | // root scan, and completes the closure, thus marking through all live objects |
420 | // The implementation is the same, so it's shared here. |
421 | { |
422 | ShenandoahGCPhase phase(full_gc ? |
423 | ShenandoahPhaseTimings::full_gc_mark_finish_queues : |
424 | ShenandoahPhaseTimings::finish_queues); |
425 | task_queues()->reserve(nworkers); |
426 | |
427 | shenandoah_assert_rp_isalive_not_installed(); |
428 | ShenandoahIsAliveSelector is_alive; |
429 | ReferenceProcessorIsAliveMutator fix_isalive(_heap->ref_processor(), is_alive.is_alive_closure()); |
430 | |
431 | ShenandoahTerminationTracker termination_tracker(full_gc ? |
432 | ShenandoahPhaseTimings::full_gc_mark_termination : |
433 | ShenandoahPhaseTimings::termination); |
434 | |
435 | StrongRootsScope scope(nworkers); |
436 | ShenandoahTaskTerminator terminator(nworkers, task_queues()); |
437 | ShenandoahFinalMarkingTask task(this, &terminator, ShenandoahStringDedup::is_enabled()); |
438 | _heap->workers()->run_task(&task); |
439 | } |
440 | |
441 | assert(task_queues()->is_empty(), "Should be empty" ); |
442 | |
443 | // When we're done marking everything, we process weak references. |
444 | if (_heap->process_references()) { |
445 | weak_refs_work(full_gc); |
446 | } |
447 | |
448 | weak_roots_work(); |
449 | |
450 | // And finally finish class unloading |
451 | if (_heap->unload_classes()) { |
452 | _heap->unload_classes_and_cleanup_tables(full_gc); |
453 | } else if (ShenandoahStringDedup::is_enabled()) { |
454 | ShenandoahIsAliveSelector alive; |
455 | BoolObjectClosure* is_alive = alive.is_alive_closure(); |
456 | ShenandoahStringDedup::unlink_or_oops_do(is_alive, NULL, false); |
457 | } |
458 | assert(task_queues()->is_empty(), "Should be empty" ); |
459 | TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats()); |
460 | TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); |
461 | |
462 | // Resize Metaspace |
463 | MetaspaceGC::compute_new_size(); |
464 | } |
465 | |
466 | // Weak Reference Closures |
467 | class ShenandoahCMDrainMarkingStackClosure: public VoidClosure { |
468 | uint _worker_id; |
469 | ShenandoahTaskTerminator* _terminator; |
470 | bool _reset_terminator; |
471 | |
472 | public: |
473 | ShenandoahCMDrainMarkingStackClosure(uint worker_id, ShenandoahTaskTerminator* t, bool reset_terminator = false): |
474 | _worker_id(worker_id), |
475 | _terminator(t), |
476 | _reset_terminator(reset_terminator) { |
477 | } |
478 | |
479 | void do_void() { |
480 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
481 | |
482 | ShenandoahHeap* sh = ShenandoahHeap::heap(); |
483 | ShenandoahConcurrentMark* scm = sh->concurrent_mark(); |
484 | assert(sh->process_references(), "why else would we be here?" ); |
485 | ReferenceProcessor* rp = sh->ref_processor(); |
486 | |
487 | shenandoah_assert_rp_isalive_installed(); |
488 | |
489 | scm->mark_loop(_worker_id, _terminator, rp, |
490 | false, // not cancellable |
491 | false); // do not do strdedup |
492 | |
493 | if (_reset_terminator) { |
494 | _terminator->reset_for_reuse(); |
495 | } |
496 | } |
497 | }; |
498 | |
499 | class ShenandoahCMKeepAliveClosure : public OopClosure { |
500 | private: |
501 | ShenandoahObjToScanQueue* _queue; |
502 | ShenandoahHeap* _heap; |
503 | ShenandoahMarkingContext* const _mark_context; |
504 | |
505 | template <class T> |
506 | inline void do_oop_work(T* p) { |
507 | ShenandoahConcurrentMark::mark_through_ref<T, NONE, NO_DEDUP>(p, _heap, _queue, _mark_context); |
508 | } |
509 | |
510 | public: |
511 | ShenandoahCMKeepAliveClosure(ShenandoahObjToScanQueue* q) : |
512 | _queue(q), |
513 | _heap(ShenandoahHeap::heap()), |
514 | _mark_context(_heap->marking_context()) {} |
515 | |
516 | void do_oop(narrowOop* p) { do_oop_work(p); } |
517 | void do_oop(oop* p) { do_oop_work(p); } |
518 | }; |
519 | |
520 | class ShenandoahCMKeepAliveUpdateClosure : public OopClosure { |
521 | private: |
522 | ShenandoahObjToScanQueue* _queue; |
523 | ShenandoahHeap* _heap; |
524 | ShenandoahMarkingContext* const _mark_context; |
525 | |
526 | template <class T> |
527 | inline void do_oop_work(T* p) { |
528 | ShenandoahConcurrentMark::mark_through_ref<T, SIMPLE, NO_DEDUP>(p, _heap, _queue, _mark_context); |
529 | } |
530 | |
531 | public: |
532 | ShenandoahCMKeepAliveUpdateClosure(ShenandoahObjToScanQueue* q) : |
533 | _queue(q), |
534 | _heap(ShenandoahHeap::heap()), |
535 | _mark_context(_heap->marking_context()) {} |
536 | |
537 | void do_oop(narrowOop* p) { do_oop_work(p); } |
538 | void do_oop(oop* p) { do_oop_work(p); } |
539 | }; |
540 | |
541 | class ShenandoahWeakUpdateClosure : public OopClosure { |
542 | private: |
543 | ShenandoahHeap* const _heap; |
544 | |
545 | template <class T> |
546 | inline void do_oop_work(T* p) { |
547 | oop o = _heap->maybe_update_with_forwarded(p); |
548 | shenandoah_assert_marked_except(p, o, o == NULL); |
549 | } |
550 | |
551 | public: |
552 | ShenandoahWeakUpdateClosure() : _heap(ShenandoahHeap::heap()) {} |
553 | |
554 | void do_oop(narrowOop* p) { do_oop_work(p); } |
555 | void do_oop(oop* p) { do_oop_work(p); } |
556 | }; |
557 | |
558 | class ShenandoahWeakAssertNotForwardedClosure : public OopClosure { |
559 | private: |
560 | template <class T> |
561 | inline void do_oop_work(T* p) { |
562 | #ifdef ASSERT |
563 | T o = RawAccess<>::oop_load(p); |
564 | if (!CompressedOops::is_null(o)) { |
565 | oop obj = CompressedOops::decode_not_null(o); |
566 | shenandoah_assert_not_forwarded(p, obj); |
567 | } |
568 | #endif |
569 | } |
570 | |
571 | public: |
572 | ShenandoahWeakAssertNotForwardedClosure() {} |
573 | |
574 | void do_oop(narrowOop* p) { do_oop_work(p); } |
575 | void do_oop(oop* p) { do_oop_work(p); } |
576 | }; |
577 | |
578 | class ShenandoahRefProcTaskProxy : public AbstractGangTask { |
579 | private: |
580 | AbstractRefProcTaskExecutor::ProcessTask& _proc_task; |
581 | ShenandoahTaskTerminator* _terminator; |
582 | |
583 | public: |
584 | ShenandoahRefProcTaskProxy(AbstractRefProcTaskExecutor::ProcessTask& proc_task, |
585 | ShenandoahTaskTerminator* t) : |
586 | AbstractGangTask("Process reference objects in parallel" ), |
587 | _proc_task(proc_task), |
588 | _terminator(t) { |
589 | } |
590 | |
591 | void work(uint worker_id) { |
592 | ResourceMark rm; |
593 | HandleMark hm; |
594 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
595 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
596 | ShenandoahCMDrainMarkingStackClosure complete_gc(worker_id, _terminator); |
597 | if (heap->has_forwarded_objects()) { |
598 | ShenandoahForwardedIsAliveClosure is_alive; |
599 | ShenandoahCMKeepAliveUpdateClosure keep_alive(heap->concurrent_mark()->get_queue(worker_id)); |
600 | _proc_task.work(worker_id, is_alive, keep_alive, complete_gc); |
601 | } else { |
602 | ShenandoahIsAliveClosure is_alive; |
603 | ShenandoahCMKeepAliveClosure keep_alive(heap->concurrent_mark()->get_queue(worker_id)); |
604 | _proc_task.work(worker_id, is_alive, keep_alive, complete_gc); |
605 | } |
606 | } |
607 | }; |
608 | |
609 | class ShenandoahRefProcTaskExecutor : public AbstractRefProcTaskExecutor { |
610 | private: |
611 | WorkGang* _workers; |
612 | |
613 | public: |
614 | ShenandoahRefProcTaskExecutor(WorkGang* workers) : |
615 | _workers(workers) { |
616 | } |
617 | |
618 | // Executes a task using worker threads. |
619 | void execute(ProcessTask& task, uint ergo_workers) { |
620 | assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Must be at a safepoint" ); |
621 | |
622 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
623 | ShenandoahConcurrentMark* cm = heap->concurrent_mark(); |
624 | ShenandoahPushWorkerQueuesScope scope(_workers, cm->task_queues(), |
625 | ergo_workers, |
626 | /* do_check = */ false); |
627 | uint nworkers = _workers->active_workers(); |
628 | cm->task_queues()->reserve(nworkers); |
629 | ShenandoahTaskTerminator terminator(nworkers, cm->task_queues()); |
630 | ShenandoahRefProcTaskProxy proc_task_proxy(task, &terminator); |
631 | _workers->run_task(&proc_task_proxy); |
632 | } |
633 | }; |
634 | |
635 | void ShenandoahConcurrentMark::weak_refs_work(bool full_gc) { |
636 | assert(_heap->process_references(), "sanity" ); |
637 | |
638 | ShenandoahPhaseTimings::Phase phase_root = |
639 | full_gc ? |
640 | ShenandoahPhaseTimings::full_gc_weakrefs : |
641 | ShenandoahPhaseTimings::weakrefs; |
642 | |
643 | ShenandoahGCPhase phase(phase_root); |
644 | |
645 | ReferenceProcessor* rp = _heap->ref_processor(); |
646 | |
647 | // NOTE: We cannot shortcut on has_discovered_references() here, because |
648 | // we will miss marking JNI Weak refs then, see implementation in |
649 | // ReferenceProcessor::process_discovered_references. |
650 | weak_refs_work_doit(full_gc); |
651 | |
652 | rp->verify_no_references_recorded(); |
653 | assert(!rp->discovery_enabled(), "Post condition" ); |
654 | |
655 | } |
656 | |
657 | // Process leftover weak oops: update them, if needed or assert they do not |
658 | // need updating otherwise. |
659 | // Weak processor API requires us to visit the oops, even if we are not doing |
660 | // anything to them. |
661 | void ShenandoahConcurrentMark::weak_roots_work() { |
662 | WorkGang* workers = _heap->workers(); |
663 | OopClosure* keep_alive = &do_nothing_cl; |
664 | #ifdef ASSERT |
665 | ShenandoahWeakAssertNotForwardedClosure verify_cl; |
666 | keep_alive = &verify_cl; |
667 | #endif |
668 | ShenandoahIsAliveClosure is_alive; |
669 | WeakProcessor::weak_oops_do(workers, &is_alive, keep_alive, 1); |
670 | } |
671 | |
672 | void ShenandoahConcurrentMark::weak_refs_work_doit(bool full_gc) { |
673 | ReferenceProcessor* rp = _heap->ref_processor(); |
674 | |
675 | ShenandoahPhaseTimings::Phase phase_process = |
676 | full_gc ? |
677 | ShenandoahPhaseTimings::full_gc_weakrefs_process : |
678 | ShenandoahPhaseTimings::weakrefs_process; |
679 | |
680 | ShenandoahPhaseTimings::Phase phase_process_termination = |
681 | full_gc ? |
682 | ShenandoahPhaseTimings::full_gc_weakrefs_termination : |
683 | ShenandoahPhaseTimings::weakrefs_termination; |
684 | |
685 | shenandoah_assert_rp_isalive_not_installed(); |
686 | ShenandoahIsAliveSelector is_alive; |
687 | ReferenceProcessorIsAliveMutator fix_isalive(rp, is_alive.is_alive_closure()); |
688 | |
689 | WorkGang* workers = _heap->workers(); |
690 | uint nworkers = workers->active_workers(); |
691 | |
692 | rp->setup_policy(_heap->soft_ref_policy()->should_clear_all_soft_refs()); |
693 | rp->set_active_mt_degree(nworkers); |
694 | |
695 | assert(task_queues()->is_empty(), "Should be empty" ); |
696 | |
697 | // complete_gc and keep_alive closures instantiated here are only needed for |
698 | // single-threaded path in RP. They share the queue 0 for tracking work, which |
699 | // simplifies implementation. Since RP may decide to call complete_gc several |
700 | // times, we need to be able to reuse the terminator. |
701 | uint serial_worker_id = 0; |
702 | ShenandoahTaskTerminator terminator(1, task_queues()); |
703 | ShenandoahCMDrainMarkingStackClosure complete_gc(serial_worker_id, &terminator, /* reset_terminator = */ true); |
704 | |
705 | ShenandoahRefProcTaskExecutor executor(workers); |
706 | |
707 | ReferenceProcessorPhaseTimes pt(_heap->gc_timer(), rp->num_queues()); |
708 | |
709 | { |
710 | ShenandoahGCPhase phase(phase_process); |
711 | ShenandoahTerminationTracker phase_term(phase_process_termination); |
712 | |
713 | if (_heap->has_forwarded_objects()) { |
714 | ShenandoahCMKeepAliveUpdateClosure keep_alive(get_queue(serial_worker_id)); |
715 | rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive, |
716 | &complete_gc, &executor, |
717 | &pt); |
718 | |
719 | } else { |
720 | ShenandoahCMKeepAliveClosure keep_alive(get_queue(serial_worker_id)); |
721 | rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive, |
722 | &complete_gc, &executor, |
723 | &pt); |
724 | |
725 | } |
726 | |
727 | pt.print_all_references(); |
728 | |
729 | assert(task_queues()->is_empty(), "Should be empty" ); |
730 | } |
731 | } |
732 | |
733 | class ShenandoahCancelledGCYieldClosure : public YieldClosure { |
734 | private: |
735 | ShenandoahHeap* const _heap; |
736 | public: |
737 | ShenandoahCancelledGCYieldClosure() : _heap(ShenandoahHeap::heap()) {}; |
738 | virtual bool should_return() { return _heap->cancelled_gc(); } |
739 | }; |
740 | |
741 | class ShenandoahPrecleanCompleteGCClosure : public VoidClosure { |
742 | public: |
743 | void do_void() { |
744 | ShenandoahHeap* sh = ShenandoahHeap::heap(); |
745 | ShenandoahConcurrentMark* scm = sh->concurrent_mark(); |
746 | assert(sh->process_references(), "why else would we be here?" ); |
747 | ShenandoahTaskTerminator terminator(1, scm->task_queues()); |
748 | |
749 | ReferenceProcessor* rp = sh->ref_processor(); |
750 | shenandoah_assert_rp_isalive_installed(); |
751 | |
752 | scm->mark_loop(0, &terminator, rp, |
753 | false, // not cancellable |
754 | false); // do not do strdedup |
755 | } |
756 | }; |
757 | |
758 | class ShenandoahPrecleanKeepAliveUpdateClosure : public OopClosure { |
759 | private: |
760 | ShenandoahObjToScanQueue* _queue; |
761 | ShenandoahHeap* _heap; |
762 | ShenandoahMarkingContext* const _mark_context; |
763 | |
764 | template <class T> |
765 | inline void do_oop_work(T* p) { |
766 | ShenandoahConcurrentMark::mark_through_ref<T, CONCURRENT, NO_DEDUP>(p, _heap, _queue, _mark_context); |
767 | } |
768 | |
769 | public: |
770 | ShenandoahPrecleanKeepAliveUpdateClosure(ShenandoahObjToScanQueue* q) : |
771 | _queue(q), |
772 | _heap(ShenandoahHeap::heap()), |
773 | _mark_context(_heap->marking_context()) {} |
774 | |
775 | void do_oop(narrowOop* p) { do_oop_work(p); } |
776 | void do_oop(oop* p) { do_oop_work(p); } |
777 | }; |
778 | |
779 | class ShenandoahPrecleanTask : public AbstractGangTask { |
780 | private: |
781 | ReferenceProcessor* _rp; |
782 | |
783 | public: |
784 | ShenandoahPrecleanTask(ReferenceProcessor* rp) : |
785 | AbstractGangTask("Precleaning task" ), |
786 | _rp(rp) {} |
787 | |
788 | void work(uint worker_id) { |
789 | assert(worker_id == 0, "The code below is single-threaded, only one worker is expected" ); |
790 | ShenandoahParallelWorkerSession worker_session(worker_id); |
791 | |
792 | ShenandoahHeap* sh = ShenandoahHeap::heap(); |
793 | |
794 | ShenandoahObjToScanQueue* q = sh->concurrent_mark()->get_queue(worker_id); |
795 | |
796 | ShenandoahCancelledGCYieldClosure yield; |
797 | ShenandoahPrecleanCompleteGCClosure complete_gc; |
798 | |
799 | if (sh->has_forwarded_objects()) { |
800 | ShenandoahForwardedIsAliveClosure is_alive; |
801 | ShenandoahPrecleanKeepAliveUpdateClosure keep_alive(q); |
802 | ResourceMark rm; |
803 | _rp->preclean_discovered_references(&is_alive, &keep_alive, |
804 | &complete_gc, &yield, |
805 | NULL); |
806 | } else { |
807 | ShenandoahIsAliveClosure is_alive; |
808 | ShenandoahCMKeepAliveClosure keep_alive(q); |
809 | ResourceMark rm; |
810 | _rp->preclean_discovered_references(&is_alive, &keep_alive, |
811 | &complete_gc, &yield, |
812 | NULL); |
813 | } |
814 | } |
815 | }; |
816 | |
817 | void ShenandoahConcurrentMark::preclean_weak_refs() { |
818 | // Pre-cleaning weak references before diving into STW makes sense at the |
819 | // end of concurrent mark. This will filter out the references which referents |
820 | // are alive. Note that ReferenceProcessor already filters out these on reference |
821 | // discovery, and the bulk of work is done here. This phase processes leftovers |
822 | // that missed the initial filtering, i.e. when referent was marked alive after |
823 | // reference was discovered by RP. |
824 | |
825 | assert(_heap->process_references(), "sanity" ); |
826 | |
827 | // Shortcut if no references were discovered to avoid winding up threads. |
828 | ReferenceProcessor* rp = _heap->ref_processor(); |
829 | if (!rp->has_discovered_references()) { |
830 | return; |
831 | } |
832 | |
833 | assert(task_queues()->is_empty(), "Should be empty" ); |
834 | |
835 | ReferenceProcessorMTDiscoveryMutator fix_mt_discovery(rp, false); |
836 | |
837 | shenandoah_assert_rp_isalive_not_installed(); |
838 | ShenandoahIsAliveSelector is_alive; |
839 | ReferenceProcessorIsAliveMutator fix_isalive(rp, is_alive.is_alive_closure()); |
840 | |
841 | // Execute precleaning in the worker thread: it will give us GCLABs, String dedup |
842 | // queues and other goodies. When upstream ReferenceProcessor starts supporting |
843 | // parallel precleans, we can extend this to more threads. |
844 | WorkGang* workers = _heap->workers(); |
845 | uint nworkers = workers->active_workers(); |
846 | assert(nworkers == 1, "This code uses only a single worker" ); |
847 | task_queues()->reserve(nworkers); |
848 | |
849 | ShenandoahPrecleanTask task(rp); |
850 | workers->run_task(&task); |
851 | |
852 | assert(task_queues()->is_empty(), "Should be empty" ); |
853 | } |
854 | |
855 | void ShenandoahConcurrentMark::cancel() { |
856 | // Clean up marking stacks. |
857 | ShenandoahObjToScanQueueSet* queues = task_queues(); |
858 | queues->clear(); |
859 | |
860 | // Cancel SATB buffers. |
861 | ShenandoahBarrierSet::satb_mark_queue_set().abandon_partial_marking(); |
862 | } |
863 | |
864 | ShenandoahObjToScanQueue* ShenandoahConcurrentMark::get_queue(uint worker_id) { |
865 | assert(task_queues()->get_reserved() > worker_id, "No reserved queue for worker id: %d" , worker_id); |
866 | return _task_queues->queue(worker_id); |
867 | } |
868 | |
869 | template <bool CANCELLABLE> |
870 | void ShenandoahConcurrentMark::mark_loop_prework(uint w, ShenandoahTaskTerminator *t, ReferenceProcessor *rp, |
871 | bool strdedup) { |
872 | ShenandoahObjToScanQueue* q = get_queue(w); |
873 | |
874 | jushort* ld = _heap->get_liveness_cache(w); |
875 | |
876 | // TODO: We can clean up this if we figure out how to do templated oop closures that |
877 | // play nice with specialized_oop_iterators. |
878 | if (_heap->unload_classes()) { |
879 | if (_heap->has_forwarded_objects()) { |
880 | if (strdedup) { |
881 | ShenandoahMarkUpdateRefsMetadataDedupClosure cl(q, rp); |
882 | mark_loop_work<ShenandoahMarkUpdateRefsMetadataDedupClosure, CANCELLABLE>(&cl, ld, w, t); |
883 | } else { |
884 | ShenandoahMarkUpdateRefsMetadataClosure cl(q, rp); |
885 | mark_loop_work<ShenandoahMarkUpdateRefsMetadataClosure, CANCELLABLE>(&cl, ld, w, t); |
886 | } |
887 | } else { |
888 | if (strdedup) { |
889 | ShenandoahMarkRefsMetadataDedupClosure cl(q, rp); |
890 | mark_loop_work<ShenandoahMarkRefsMetadataDedupClosure, CANCELLABLE>(&cl, ld, w, t); |
891 | } else { |
892 | ShenandoahMarkRefsMetadataClosure cl(q, rp); |
893 | mark_loop_work<ShenandoahMarkRefsMetadataClosure, CANCELLABLE>(&cl, ld, w, t); |
894 | } |
895 | } |
896 | } else { |
897 | if (_heap->has_forwarded_objects()) { |
898 | if (strdedup) { |
899 | ShenandoahMarkUpdateRefsDedupClosure cl(q, rp); |
900 | mark_loop_work<ShenandoahMarkUpdateRefsDedupClosure, CANCELLABLE>(&cl, ld, w, t); |
901 | } else { |
902 | ShenandoahMarkUpdateRefsClosure cl(q, rp); |
903 | mark_loop_work<ShenandoahMarkUpdateRefsClosure, CANCELLABLE>(&cl, ld, w, t); |
904 | } |
905 | } else { |
906 | if (strdedup) { |
907 | ShenandoahMarkRefsDedupClosure cl(q, rp); |
908 | mark_loop_work<ShenandoahMarkRefsDedupClosure, CANCELLABLE>(&cl, ld, w, t); |
909 | } else { |
910 | ShenandoahMarkRefsClosure cl(q, rp); |
911 | mark_loop_work<ShenandoahMarkRefsClosure, CANCELLABLE>(&cl, ld, w, t); |
912 | } |
913 | } |
914 | } |
915 | |
916 | _heap->flush_liveness_cache(w); |
917 | } |
918 | |
919 | template <class T, bool CANCELLABLE> |
920 | void ShenandoahConcurrentMark::mark_loop_work(T* cl, jushort* live_data, uint worker_id, ShenandoahTaskTerminator *terminator) { |
921 | uintx stride = ShenandoahMarkLoopStride; |
922 | |
923 | ShenandoahHeap* heap = ShenandoahHeap::heap(); |
924 | ShenandoahObjToScanQueueSet* queues = task_queues(); |
925 | ShenandoahObjToScanQueue* q; |
926 | ShenandoahMarkTask t; |
927 | |
928 | /* |
929 | * Process outstanding queues, if any. |
930 | * |
931 | * There can be more queues than workers. To deal with the imbalance, we claim |
932 | * extra queues first. Since marking can push new tasks into the queue associated |
933 | * with this worker id, we come back to process this queue in the normal loop. |
934 | */ |
935 | assert(queues->get_reserved() == heap->workers()->active_workers(), |
936 | "Need to reserve proper number of queues: reserved: %u, active: %u" , queues->get_reserved(), heap->workers()->active_workers()); |
937 | |
938 | q = queues->claim_next(); |
939 | while (q != NULL) { |
940 | if (CANCELLABLE && heap->check_cancelled_gc_and_yield()) { |
941 | return; |
942 | } |
943 | |
944 | for (uint i = 0; i < stride; i++) { |
945 | if (q->pop(t)) { |
946 | do_task<T>(q, cl, live_data, &t); |
947 | } else { |
948 | assert(q->is_empty(), "Must be empty" ); |
949 | q = queues->claim_next(); |
950 | break; |
951 | } |
952 | } |
953 | } |
954 | q = get_queue(worker_id); |
955 | |
956 | ShenandoahSATBBufferClosure drain_satb(q); |
957 | SATBMarkQueueSet& satb_mq_set = ShenandoahBarrierSet::satb_mark_queue_set(); |
958 | |
959 | /* |
960 | * Normal marking loop: |
961 | */ |
962 | while (true) { |
963 | if (CANCELLABLE && heap->check_cancelled_gc_and_yield()) { |
964 | return; |
965 | } |
966 | |
967 | while (satb_mq_set.completed_buffers_num() > 0) { |
968 | satb_mq_set.apply_closure_to_completed_buffer(&drain_satb); |
969 | } |
970 | |
971 | uint work = 0; |
972 | for (uint i = 0; i < stride; i++) { |
973 | if (q->pop(t) || |
974 | queues->steal(worker_id, t)) { |
975 | do_task<T>(q, cl, live_data, &t); |
976 | work++; |
977 | } else { |
978 | break; |
979 | } |
980 | } |
981 | |
982 | if (work == 0) { |
983 | // No work encountered in current stride, try to terminate. |
984 | // Need to leave the STS here otherwise it might block safepoints. |
985 | ShenandoahSuspendibleThreadSetLeaver stsl(CANCELLABLE && ShenandoahSuspendibleWorkers); |
986 | ShenandoahTerminationTimingsTracker term_tracker(worker_id); |
987 | ShenandoahTerminatorTerminator tt(heap); |
988 | if (terminator->offer_termination(&tt)) return; |
989 | } |
990 | } |
991 | } |
992 | |
993 | bool ShenandoahConcurrentMark::claim_codecache() { |
994 | assert(ShenandoahConcurrentScanCodeRoots, "must not be called otherwise" ); |
995 | return _claimed_codecache.try_set(); |
996 | } |
997 | |
998 | void ShenandoahConcurrentMark::clear_claim_codecache() { |
999 | assert(ShenandoahConcurrentScanCodeRoots, "must not be called otherwise" ); |
1000 | _claimed_codecache.unset(); |
1001 | } |
1002 | |