1 /* 2 * Copyright (c) 2014, 2015, Red Hat, Inc. and/or its affiliates. 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 "code/codeCache.hpp" 25 #include "gc/shared/gcTraceTime.inline.hpp" 26 #include "gc/shared/isGCActiveMark.hpp" 27 #include "gc/shenandoah/brooksPointer.hpp" 28 #include "gc/shenandoah/shenandoahCollectorPolicy.hpp" 29 #include "gc/shenandoah/shenandoahMarkCompact.hpp" 30 #include "gc/shenandoah/shenandoahBarrierSet.hpp" 31 #include "gc/shenandoah/shenandoahHeapRegionSet.hpp" 32 #include "gc/shenandoah/shenandoahHeap.hpp" 33 #include "gc/shenandoah/shenandoahHeap.inline.hpp" 34 #include "gc/shenandoah/shenandoahRootProcessor.hpp" 35 #include "gc/shenandoah/vm_operations_shenandoah.hpp" 36 #include "oops/oop.inline.hpp" 37 #include "runtime/biasedLocking.hpp" 38 #include "runtime/thread.hpp" 39 #include "utilities/copy.hpp" 40 #include "gc/shared/taskqueue.inline.hpp" 41 #include "gc/shared/workgroup.hpp" 42 43 class ShenandoahMarkCompactBarrierSet : public ShenandoahBarrierSet { 44 public: 45 ShenandoahMarkCompactBarrierSet(ShenandoahHeap* heap) : ShenandoahBarrierSet(heap) { 46 } 47 oop read_barrier(oop src) { 48 return src; 49 } 50 #ifdef ASSERT 51 bool is_safe(oop o) { 52 if (o == NULL) return true; 53 if (! oopDesc::unsafe_equals(o, read_barrier(o))) { 54 return false; 55 } 56 return true; 57 } 58 bool is_safe(narrowOop o) { 59 oop obj = oopDesc::decode_heap_oop(o); 60 return is_safe(obj); 61 } 62 #endif 63 }; 64 65 class ClearInCollectionSetHeapRegionClosure: public ShenandoahHeapRegionClosure { 66 bool doHeapRegion(ShenandoahHeapRegion* r) { 67 r->set_top_at_mark_start(r->end()); 68 r->clearLiveData(); 69 r->set_concurrent_iteration_safe_limit(r->top()); 70 r->set_top_prev_mark_bitmap(r->top_at_mark_start()); 71 return false; 72 } 73 }; 74 75 STWGCTimer* ShenandoahMarkCompact::_gc_timer = NULL; 76 77 void ShenandoahMarkCompact::initialize() { 78 _gc_timer = new (ResourceObj::C_HEAP, mtGC) STWGCTimer(); 79 } 80 81 void ShenandoahMarkCompact::do_mark_compact(GCCause::Cause gc_cause) { 82 83 ShenandoahHeap* _heap = ShenandoahHeap::heap(); 84 85 _gc_timer->register_gc_start(); 86 87 _heap->set_full_gc_in_progress(true); 88 89 assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); 90 IsGCActiveMark is_active; 91 92 assert(Thread::current()->is_VM_thread(), "Do full GC only while world is stopped"); 93 assert(_heap->is_bitmap_clear(), "require cleared bitmap"); 94 assert(!_heap->concurrent_mark_in_progress(), "can't do full-GC while marking is in progress"); 95 assert(!_heap->is_evacuation_in_progress(), "can't do full-GC while evacuation is in progress"); 96 97 _heap->shenandoahPolicy()->record_phase_start(ShenandoahCollectorPolicy::full_gc); 98 99 ClearInCollectionSetHeapRegionClosure cl; 100 _heap->heap_region_iterate(&cl, false, false); 101 102 assert(_heap->is_bitmap_clear(), "require cleared bitmap"); 103 104 /* 105 if (ShenandoahVerify) { 106 // Full GC should only be called between regular concurrent cycles, therefore 107 // those verifications should be valid. 108 _heap->verify_heap_after_evacuation(); 109 _heap->verify_heap_after_update_refs(); 110 } 111 */ 112 113 BarrierSet* old_bs = oopDesc::bs(); 114 ShenandoahMarkCompactBarrierSet bs(_heap); 115 oopDesc::set_bs(&bs); 116 117 { 118 GCTraceTime(Info, gc, phases) time("Pause Full", _gc_timer, gc_cause, true); 119 120 if (UseTLAB) { 121 _heap->ensure_parsability(true); 122 } 123 124 CodeCache::gc_prologue(); 125 126 // We should save the marks of the currently locked biased monitors. 127 // The marking doesn't preserve the marks of biased objects. 128 //BiasedLocking::preserve_marks(); 129 130 _heap->set_need_update_refs(true); 131 132 OrderAccess::fence(); 133 134 phase1_mark_heap(); 135 136 OrderAccess::fence(); 137 138 ShenandoahHeapRegionSet* copy_queues[_heap->max_parallel_workers()]; 139 phase2_calculate_target_addresses(copy_queues); 140 141 OrderAccess::fence(); 142 143 phase3_update_references(); 144 145 phase4_compact_objects(copy_queues); 146 147 CodeCache::gc_epilogue(); 148 JvmtiExport::gc_epilogue(); 149 150 // refs processing: clean slate 151 // rp.enqueue_discovered_references(); 152 153 if (ShenandoahVerify) { 154 _heap->verify_heap_after_evacuation(); 155 } 156 157 _heap->reset_mark_bitmap(); 158 _heap->set_bytes_allocated_since_cm(0); 159 160 _heap->set_need_update_refs(false); 161 162 _heap->set_full_gc_in_progress(false); 163 } 164 165 _gc_timer->register_gc_end(); 166 167 _heap->shenandoahPolicy()->record_phase_end(ShenandoahCollectorPolicy::full_gc); 168 169 oopDesc::set_bs(old_bs); 170 } 171 172 #ifdef ASSERT 173 class VerifyNotForwardedPointersClosure : public MetadataAwareOopClosure { 174 private: 175 template <class T> 176 inline void do_oop_work(T* p) { 177 T o = oopDesc::load_heap_oop(p); 178 if (! oopDesc::is_null(o)) { 179 oop obj = oopDesc::decode_heap_oop_not_null(o); 180 assert(oopDesc::unsafe_equals(obj, ShenandoahBarrierSet::resolve_oop_static_not_null(obj)), 181 "expect forwarded oop"); 182 ShenandoahHeap* heap = ShenandoahHeap::heap(); 183 if (! heap->is_marked_current(obj)) { 184 tty->print_cr("ref region humongous? %s", BOOL_TO_STR(heap->heap_region_containing(p)->is_humongous())); 185 } 186 assert(heap->is_marked_current(obj), "must be marked"); 187 assert(! heap->allocated_after_mark_start((HeapWord*) obj), "must be truly marked"); 188 } 189 } 190 public: 191 void do_oop(oop* p) { 192 do_oop_work(p); 193 } 194 void do_oop(narrowOop* p) { 195 do_oop_work(p); 196 } 197 }; 198 199 class ShenandoahMCVerifyAfterMarkingObjectClosure : public ObjectClosure { 200 void do_object(oop p) { 201 ShenandoahHeap* heap = ShenandoahHeap::heap(); 202 assert(oopDesc::unsafe_equals(p, ShenandoahBarrierSet::resolve_oop_static_not_null(p)), 203 "expect forwarded oop"); 204 assert(heap->is_marked_current(p), "must be marked"); 205 assert(! heap->allocated_after_mark_start((HeapWord*) p), "must be truly marked"); 206 VerifyNotForwardedPointersClosure cl; 207 p->oop_iterate(&cl); 208 } 209 }; 210 211 class ShenandoahMCVerifyAfterMarkingRegionClosure : public ShenandoahHeapRegionClosure { 212 bool doHeapRegion(ShenandoahHeapRegion* r) { 213 ShenandoahMCVerifyAfterMarkingObjectClosure cl; 214 if (! r->is_humongous_continuation()) { 215 r->marked_object_iterate(&cl); 216 } 217 return false; 218 } 219 }; 220 221 class ShenandoahMCVerifyBeforeMarkingObjectClosure : public ObjectClosure { 222 public: 223 bool marked; 224 ShenandoahMCVerifyBeforeMarkingObjectClosure() : ObjectClosure(), marked(false) { 225 } 226 void do_object(oop p) { 227 marked = true; 228 } 229 }; 230 231 class ShenandoahMCVerifyBeforeMarkingRegionClosure : public ShenandoahHeapRegionClosure { 232 public: 233 bool doHeapRegion(ShenandoahHeapRegion* r) { 234 ShenandoahMCVerifyBeforeMarkingObjectClosure cl; 235 if (! r->is_humongous_continuation()) { 236 r->marked_object_iterate(&cl); 237 } 238 assert(! cl.marked, "must not see marked objects"); 239 return false; 240 } 241 }; 242 243 #endif 244 245 void ShenandoahMarkCompact::phase1_mark_heap() { 246 GCTraceTime(Info, gc, phases) time("Phase 1: Mark live objects", _gc_timer); 247 ShenandoahHeap* _heap = ShenandoahHeap::heap(); 248 249 #ifdef ASSERT 250 ShenandoahMCVerifyBeforeMarkingRegionClosure cl1; 251 _heap->heap_region_iterate(&cl1); 252 #endif 253 254 ShenandoahConcurrentMark* cm = _heap->concurrentMark(); 255 256 cm->set_process_references(true); 257 cm->set_unload_classes(true); 258 259 ReferenceProcessor* rp = _heap->ref_processor(); 260 // enable ("weak") refs discovery 261 rp->enable_discovery(true /*verify_no_refs*/); 262 rp->setup_policy(true); // snapshot the soft ref policy to be used in this cycle 263 264 COMPILER2_PRESENT(DerivedPointerTable::clear()); 265 cm->update_roots(); 266 COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); 267 268 cm->mark_roots(); 269 cm->shared_finish_mark_from_roots(); 270 271 if (VerifyDuringGC) { 272 HandleMark hm; // handle scope 273 // Universe::heap()->prepare_for_verify(); 274 _heap->prepare_for_verify(); 275 // Note: we can verify only the heap here. When an object is 276 // marked, the previous value of the mark word (including 277 // identity hash values, ages, etc) is preserved, and the mark 278 // word is set to markOop::marked_value - effectively removing 279 // any hash values from the mark word. These hash values are 280 // used when verifying the dictionaries and so removing them 281 // from the mark word can make verification of the dictionaries 282 // fail. At the end of the GC, the original mark word values 283 // (including hash values) are restored to the appropriate 284 // objects. 285 // Universe::heap()->verify(VerifySilently, VerifyOption_G1UseMarkWord); 286 _heap->verify(VerifyOption_G1UseMarkWord); 287 } 288 289 #ifdef ASSERT 290 ShenandoahMCVerifyAfterMarkingRegionClosure cl; 291 _heap->heap_region_iterate(&cl); 292 #endif 293 } 294 295 class ShenandoahPrepareForCompactionObjectClosure : public ObjectClosure { 296 297 private: 298 299 ShenandoahHeap* _heap; 300 ShenandoahHeapRegionSet* _to_regions; 301 ShenandoahHeapRegion* _to_region; 302 ShenandoahHeapRegion* _from_region; 303 HeapWord* _compact_point; 304 305 public: 306 307 ShenandoahPrepareForCompactionObjectClosure(ShenandoahHeapRegionSet* to_regions, ShenandoahHeapRegion* to_region) : 308 _heap(ShenandoahHeap::heap()), 309 _to_regions(to_regions), 310 _to_region(to_region), 311 _from_region(NULL), 312 _compact_point(to_region->bottom()) { 313 } 314 315 void set_from_region(ShenandoahHeapRegion* from_region) { 316 _from_region = from_region; 317 } 318 319 ShenandoahHeapRegion* to_region() const { 320 return _to_region; 321 } 322 HeapWord* compact_point() const { 323 return _compact_point; 324 } 325 void do_object(oop p) { 326 assert(_from_region != NULL, "must set before work"); 327 assert(_heap->is_marked_current(p), "must be marked"); 328 assert(! _heap->allocated_after_mark_start((HeapWord*) p), "must be truly marked"); 329 size_t size = p->size(); 330 size_t obj_size = size + BrooksPointer::BROOKS_POINTER_OBJ_SIZE; 331 if (_compact_point + obj_size > _to_region->end()) { 332 // Object doesn't fit. Pick next to-region and start compacting there. 333 _to_region->set_new_top(_compact_point); 334 ShenandoahHeapRegion* new_to_region = _to_regions->next(); 335 if (new_to_region == NULL) { 336 new_to_region = _from_region; 337 } 338 assert(new_to_region != _to_region, "must not reuse same to-region"); 339 assert(new_to_region != NULL, "must not be NULL"); 340 _to_region = new_to_region; 341 _compact_point = _to_region->bottom(); 342 } 343 assert(_compact_point + obj_size <= _to_region->end(), "must fit"); 344 // tty->print_cr("forwarding %p to %p", p, _compact_point + BrooksPointer::BROOKS_POINTER_OBJ_SIZE); 345 assert(oopDesc::unsafe_equals(p, ShenandoahBarrierSet::resolve_oop_static_not_null(p)), 346 "expect forwarded oop"); 347 BrooksPointer::get(p).set_forwardee(oop(_compact_point + BrooksPointer::BROOKS_POINTER_OBJ_SIZE)); 348 _compact_point += obj_size; 349 } 350 }; 351 352 class ShenandoahPrepareForCompactionTask : public AbstractGangTask { 353 private: 354 355 ShenandoahHeapRegionSet** _copy_queues; 356 ShenandoahHeapRegionSet* _from_regions; 357 358 ShenandoahHeapRegion* next_from_region(ShenandoahHeapRegionSet* copy_queue) { 359 ShenandoahHeapRegion* from_region = _from_regions->claim_next(); 360 while (from_region != NULL && from_region->is_humongous()) { 361 from_region = _from_regions->claim_next(); 362 } 363 if (from_region != NULL) { 364 assert(copy_queue != NULL, "sanity"); 365 assert(! from_region->is_humongous(), "must not get humongous regions here"); 366 copy_queue->add_region(from_region); 367 } 368 return from_region; 369 } 370 371 public: 372 ShenandoahPrepareForCompactionTask(ShenandoahHeapRegionSet* from_regions, ShenandoahHeapRegionSet** copy_queues) : 373 AbstractGangTask("Shenandoah Prepare For Compaction Task"), 374 _from_regions(from_regions), _copy_queues(copy_queues) { 375 } 376 377 void work(uint worker_id) { 378 ShenandoahHeapRegionSet* copy_queue = _copy_queues[worker_id]; 379 ShenandoahHeapRegion* from_region = next_from_region(copy_queue); 380 if (from_region == NULL) return; 381 ShenandoahHeapRegionSet* to_regions = new ShenandoahHeapRegionSet(ShenandoahHeap::heap()->max_regions()); 382 ShenandoahPrepareForCompactionObjectClosure cl(to_regions, from_region); 383 while (from_region != NULL) { 384 assert(from_region != NULL, "sanity"); 385 cl.set_from_region(from_region); 386 from_region->marked_object_iterate(&cl); 387 if (from_region != cl.to_region()) { 388 assert(from_region != NULL, "sanity"); 389 to_regions->add_region(from_region); 390 } 391 from_region = next_from_region(copy_queue); 392 } 393 assert(cl.to_region() != NULL, "should not happen"); 394 cl.to_region()->set_new_top(cl.compact_point()); 395 while (to_regions->count() > 0) { 396 ShenandoahHeapRegion* r = to_regions->next(); 397 if (r == NULL) { 398 to_regions->print(); 399 } 400 assert(r != NULL, "should not happen"); 401 r->set_new_top(r->bottom()); 402 } 403 delete to_regions; 404 } 405 }; 406 407 void ShenandoahMarkCompact::phase2_calculate_target_addresses(ShenandoahHeapRegionSet** copy_queues) { 408 GCTraceTime(Info, gc, phases) time("Phase 2: Compute new object addresses", _gc_timer); 409 ShenandoahHeap* heap = ShenandoahHeap::heap(); 410 411 // Initialize copy queues. 412 for (int i = 0; i < heap->max_parallel_workers(); i++) { 413 copy_queues[i] = new ShenandoahHeapRegionSet(heap->max_regions()); 414 } 415 416 ShenandoahHeapRegionSet* from_regions = heap->regions(); 417 from_regions->clear_current_index(); 418 ShenandoahPrepareForCompactionTask prepare_task(from_regions, copy_queues); 419 heap->workers()->run_task(&prepare_task); 420 } 421 422 class ShenandoahAdjustPointersClosure : public MetadataAwareOopClosure { 423 private: 424 ShenandoahHeap* _heap; 425 426 public: 427 428 ShenandoahAdjustPointersClosure() : _heap(ShenandoahHeap::heap()) { 429 } 430 431 private: 432 template <class T> 433 inline void do_oop_work(T* p) { 434 T o = oopDesc::load_heap_oop(p); 435 if (! oopDesc::is_null(o)) { 436 oop obj = oopDesc::decode_heap_oop_not_null(o); 437 assert(_heap->is_marked_current(obj), "must be marked"); 438 oop forw = oop(BrooksPointer::get(obj).get_forwardee()); 439 oopDesc::encode_store_heap_oop(p, forw); 440 } 441 } 442 public: 443 void do_oop(oop* p) { 444 do_oop_work(p); 445 } 446 void do_oop(narrowOop* p) { 447 do_oop_work(p); 448 } 449 }; 450 451 class ShenandoahAdjustPointersObjectClosure : public ObjectClosure { 452 private: 453 ShenandoahAdjustPointersClosure* _cl; 454 ShenandoahHeap* _heap; 455 public: 456 ShenandoahAdjustPointersObjectClosure(ShenandoahAdjustPointersClosure* cl) : 457 _cl(cl), _heap(ShenandoahHeap::heap()) { 458 } 459 void do_object(oop p) { 460 assert(_heap->is_marked_current(p), "must be marked"); 461 p->oop_iterate(_cl); 462 } 463 }; 464 465 class ShenandoahAdjustPointersTask : public AbstractGangTask { 466 private: 467 ShenandoahHeapRegionSet* _regions; 468 public: 469 470 ShenandoahAdjustPointersTask(ShenandoahHeapRegionSet* regions) : 471 AbstractGangTask("Shenandoah Adjust Pointers Task"), 472 _regions(regions) { 473 } 474 475 void work(uint worker_id) { 476 ShenandoahHeapRegion* r = _regions->claim_next(); 477 ShenandoahAdjustPointersClosure cl; 478 ShenandoahAdjustPointersObjectClosure obj_cl(&cl); 479 while (r != NULL) { 480 if (! r->is_humongous_continuation()) { 481 r->marked_object_iterate(&obj_cl); 482 } 483 r = _regions->claim_next(); 484 } 485 } 486 }; 487 488 class ShenandoahAdjustRootPointersTask : public AbstractGangTask { 489 private: 490 ShenandoahRootProcessor* _rp; 491 492 public: 493 494 ShenandoahAdjustRootPointersTask(ShenandoahRootProcessor* rp) : 495 AbstractGangTask("Shenandoah Adjust Root Pointers Task"), 496 _rp(rp) { 497 } 498 499 void work(uint worker_id) { 500 ShenandoahAdjustPointersClosure cl; 501 CLDToOopClosure adjust_cld_closure(&cl, true); 502 MarkingCodeBlobClosure adjust_code_closure(&cl, 503 CodeBlobToOopClosure::FixRelocations); 504 505 _rp->process_all_roots(&cl, &cl, 506 &adjust_cld_closure, 507 &adjust_code_closure, worker_id); 508 } 509 }; 510 511 void ShenandoahMarkCompact::phase3_update_references() { 512 GCTraceTime(Info, gc, phases) time("Phase 2: Adjust pointers", _gc_timer); 513 ShenandoahHeap* heap = ShenandoahHeap::heap(); 514 515 // Need cleared claim bits for the roots processing 516 ClassLoaderDataGraph::clear_claimed_marks(); 517 518 { 519 COMPILER2_PRESENT(DerivedPointerTable::clear()); 520 ShenandoahRootProcessor rp(heap, heap->max_parallel_workers()); 521 ShenandoahAdjustRootPointersTask task(&rp); 522 heap->workers()->run_task(&task); 523 COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); 524 } 525 526 ShenandoahHeapRegionSet* regions = heap->regions(); 527 regions->clear_current_index(); 528 ShenandoahAdjustPointersTask adjust_pointers_task(regions); 529 heap->workers()->run_task(&adjust_pointers_task); 530 } 531 532 class ShenandoahCompactObjectsClosure : public ObjectClosure { 533 private: 534 ShenandoahHeap* _heap; 535 public: 536 ShenandoahCompactObjectsClosure() : _heap(ShenandoahHeap::heap()) { 537 } 538 void do_object(oop p) { 539 assert(_heap->is_marked_current(p), "must be marked"); 540 size_t size = p->size(); 541 HeapWord* compact_to = BrooksPointer::get(p).get_forwardee(); 542 HeapWord* compact_from = (HeapWord*) p; 543 if (compact_from != compact_to) { 544 Copy::aligned_conjoint_words(compact_from, compact_to, size); 545 } 546 oop new_obj = oop(compact_to); 547 // new_obj->init_mark(); 548 _heap->initialize_brooks_ptr(new_obj); 549 } 550 }; 551 552 class ShenandoahCompactObjectsTask : public AbstractGangTask { 553 ShenandoahHeapRegionSet** _regions; 554 public: 555 ShenandoahCompactObjectsTask(ShenandoahHeapRegionSet** regions) : 556 AbstractGangTask("Shenandoah Compact Objects Task"), 557 _regions(regions) { 558 } 559 void work(uint worker_id) { 560 ShenandoahHeapRegionSet* copy_queue = _regions[worker_id]; 561 copy_queue->clear_current_index(); 562 ShenandoahCompactObjectsClosure cl; 563 ShenandoahHeapRegion* r = copy_queue->next(); 564 while (r != NULL) { 565 assert(! r->is_humongous(), "must not get humongous regions here"); 566 r->marked_object_iterate(&cl); 567 r->set_top(r->new_top()); 568 r = copy_queue->next(); 569 } 570 } 571 }; 572 573 class ShenandoahPostCompactClosure : public ShenandoahHeapRegionClosure { 574 size_t _live; 575 ShenandoahHeap* _heap; 576 public: 577 578 ShenandoahPostCompactClosure() : _live(0), _heap(ShenandoahHeap::heap()) { 579 _heap->clear_free_regions(); 580 } 581 582 bool doHeapRegion(ShenandoahHeapRegion* r) { 583 r->reset_top_at_prev_mark_start(); 584 r->set_is_in_collection_set(false); 585 if (r->is_humongous()) { 586 if (r->is_humongous_start()) { 587 oop humongous_obj = oop(r->bottom() + BrooksPointer::BROOKS_POINTER_OBJ_SIZE); 588 if (! _heap->is_marked_current(humongous_obj)) { 589 _heap->reclaim_humongous_region_at(r); 590 } else { 591 _live += ShenandoahHeapRegion::RegionSizeBytes; 592 } 593 } else { 594 _live += ShenandoahHeapRegion::RegionSizeBytes; 595 } 596 597 } else { 598 size_t live = r->used(); 599 if (live == 0) { 600 r->recycle(); 601 _heap->add_free_region(r); 602 } 603 r->setLiveData(live); 604 _live += live; 605 } 606 return false; 607 } 608 609 size_t getLive() { return _live;} 610 611 }; 612 613 void ShenandoahMarkCompact::phase4_compact_objects(ShenandoahHeapRegionSet** copy_queues) { 614 GCTraceTime(Info, gc, phases) time("Phase 4: Move objects", _gc_timer); 615 ShenandoahHeap* heap = ShenandoahHeap::heap(); 616 ShenandoahCompactObjectsTask compact_task(copy_queues); 617 heap->workers()->run_task(&compact_task); 618 619 heap->clear_cset_fast_test(); 620 ShenandoahPostCompactClosure post_compact; 621 heap->heap_region_iterate(&post_compact); 622 623 heap->clear_cancelled_concgc(); 624 625 // We just reset the top-at-prev-mark-start pointer. Thus 626 // we also need to clear the bitmap, otherwise it would make 627 // a mess later when clearing the prev bitmap. 628 // TODO: Use all workers to clear the bitmap here, and get rid of clear_all(). 629 heap->prev_mark_bit_map()->clear_all(); 630 631 heap->set_used(post_compact.getLive()); 632 633 for (int i = 0; i < heap->max_parallel_workers(); i++) { 634 delete copy_queues[i]; 635 } 636 637 }