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 }