< prev index next >

src/share/vm/gc_implementation/shenandoah/shenandoahMarkCompact.cpp

Print this page
rev 10658 : [backport] Single marking bitmap
rev 10659 : [backport] Make sure bitmap is marked incomplete before bitmap resets
rev 10660 : [backport] Refactor bitmap cleaning
rev 10664 : [backport] Fix indenting in ShMarkCompact::do_it
rev 10665 : [backport] Coarsen Full GC use of heap lock
rev 10668 : [backport] Cleanup buffered queue handling
rev 10678 : [backport] Rename concurrentMark -> concurrent_mark
rev 10690 : [backport] Cleanup header files and forward declarations
rev 10695 : [backport] Inline/rename confusingly named methods in ShConcurrentMark
rev 10715 : [backport] Cleanup up superfluous newlines
rev 10737 : [backport] Support VerifyBeforeGC and VerifyAfterGC VM options
rev 10743 : [backport] Clean up ShHeap::heap_region_iterate uses
rev 10749 : [backport] Adjust metaspace size during each GC
rev 10755 : [backport] Make heuristics tell if we can process references or unload classes
rev 10764 : [backport] Rename BrooksPointer to ShenandoahBrooksPointer
rev 10772 : [backport] Update copyrights
rev 10801 : [backport] Rename vm_operations_shenandoah.* to shenandoahVMOperations.*

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2014, 2015, Red Hat, Inc. and/or its affiliates.
+ * Copyright (c) 2014, 2018, Red Hat, Inc. All rights reserved.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.
  *

@@ -20,50 +20,56 @@
  * questions.
  *
  */
 
 #include "precompiled.hpp"
+
 #include "code/codeCache.hpp"
 #include "gc_implementation/shenandoah/shenandoahGCTraceTime.hpp"
 #include "gc_implementation/shared/gcTimer.hpp"
-#include "gc_implementation/shenandoah/brooksPointer.hpp"
+#include "gc_implementation/shenandoah/shenandoahBrooksPointer.hpp"
 #include "gc_implementation/shenandoah/shenandoahCollectorPolicy.hpp"
 #include "gc_implementation/shenandoah/shenandoahConcurrentMark.inline.hpp"
 #include "gc_implementation/shenandoah/shenandoahCollectionSet.hpp"
 #include "gc_implementation/shenandoah/shenandoahFreeSet.hpp"
 #include "gc_implementation/shenandoah/shenandoahPhaseTimings.hpp"
 #include "gc_implementation/shenandoah/shenandoahMarkCompact.hpp"
-#include "gc_implementation/shenandoah/shenandoahBarrierSet.hpp"
 #include "gc_implementation/shenandoah/shenandoahHeapRegionSet.hpp"
 #include "gc_implementation/shenandoah/shenandoahHeap.hpp"
 #include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp"
+#include "gc_implementation/shenandoah/shenandoahHeuristics.hpp"
 #include "gc_implementation/shenandoah/shenandoahMarkingContext.inline.hpp"
 #include "gc_implementation/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc_implementation/shenandoah/shenandoahTaskqueue.hpp"
+#include "gc_implementation/shenandoah/shenandoahTaskqueue.inline.hpp"
 #include "gc_implementation/shenandoah/shenandoahUtils.hpp"
 #include "gc_implementation/shenandoah/shenandoahVerifier.hpp"
+#include "gc_implementation/shenandoah/shenandoahVMOperations.hpp"
+#include "gc_implementation/shenandoah/shenandoahWorkGroup.hpp"
 #include "gc_implementation/shenandoah/shenandoahWorkerPolicy.hpp"
-#include "gc_implementation/shenandoah/vm_operations_shenandoah.hpp"
+#include "memory/metaspace.hpp"
 #include "oops/oop.inline.hpp"
-#include "runtime/biasedLocking.hpp"
 #include "runtime/thread.hpp"
 #include "utilities/copy.hpp"
 #include "utilities/growableArray.hpp"
-#include "utilities/taskqueue.hpp"
 #include "utilities/workgroup.hpp"
 
 void ShenandoahMarkCompact::initialize(GCTimer* gc_timer) {
   _gc_timer = gc_timer;
 }
 
 void ShenandoahMarkCompact::do_it(GCCause::Cause gc_cause) {
   ShenandoahHeap* heap = ShenandoahHeap::heap();
 
-  {
     if (ShenandoahVerify) {
       heap->verifier()->verify_before_fullgc();
     }
 
+  if (VerifyBeforeGC) {
+    Universe::verify();
+  }
+
     heap->set_full_gc_in_progress(true);
 
     assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at a safepoint");
     assert(Thread::current()->is_VM_thread(), "Do full GC only while world is stopped");
 

@@ -79,11 +85,11 @@
       // 0. Remember if we have forwarded objects
       bool has_forwarded_objects = heap->has_forwarded_objects();
 
       // a. Cancel concurrent mark, if in progress
       if (heap->is_concurrent_mark_in_progress()) {
-        heap->concurrentMark()->cancel();
+      heap->concurrent_mark()->cancel();
         heap->stop_concurrent_marking();
       }
       assert(!heap->is_concurrent_mark_in_progress(), "sanity");
 
       // b1. Cancel evacuation, if in progress

@@ -97,12 +103,13 @@
         heap->set_update_refs_in_progress(false);
       }
       assert(!heap->is_update_refs_in_progress(), "sanity");
 
       // c. Reset the bitmaps for new marking
-      heap->reset_next_mark_bitmap();
-      assert(heap->next_marking_context()->is_bitmap_clear(), "sanity");
+    heap->reset_mark_bitmap();
+    assert(heap->marking_context()->is_bitmap_clear(), "sanity");
+    assert(!heap->marking_context()->is_complete(), "sanity");
 
       // d. Abandon reference discovery and clear all discovered references.
       ReferenceProcessor *rp = heap->ref_processor();
       rp->disable_discovery();
       rp->abandon_partial_discovery();

@@ -110,11 +117,10 @@
 
       // e. Set back forwarded objects bit back, in case some steps above dropped it.
       heap->set_has_forwarded_objects(has_forwarded_objects);
     }
 
-    {
       heap->make_parsable(true);
 
       CodeCache::gc_prologue();
 
       OrderAccess::fence();

@@ -127,43 +133,53 @@
       heap->set_has_forwarded_objects(false);
 
       heap->set_full_gc_move_in_progress(true);
 
       // Setup workers for the rest
-      {
         OrderAccess::fence();
 
         // Initialize worker slices
         ShenandoahHeapRegionSet** worker_slices = NEW_C_HEAP_ARRAY(ShenandoahHeapRegionSet*, heap->max_workers(), mtGC);
         for (uint i = 0; i < heap->max_workers(); i++) {
           worker_slices[i] = new ShenandoahHeapRegionSet();
         }
 
+  {
+    // The rest of code performs region moves, where region status is undefined
+    // until all phases run together.
+    ShenandoahHeapLocker lock(heap->lock());
+
         phase2_calculate_target_addresses(worker_slices);
 
         OrderAccess::fence();
 
         phase3_update_references();
 
         phase4_compact_objects(worker_slices);
+  }
+
+  // Resize metaspace
+  MetaspaceGC::compute_new_size();
 
         // Free worker slices
         for (uint i = 0; i < heap->max_workers(); i++) {
           delete worker_slices[i];
         }
         FREE_C_HEAP_ARRAY(ShenandoahHeapRegionSet*, worker_slices, mtGC);
 
         CodeCache::gc_epilogue();
         JvmtiExport::gc_epilogue();
-      }
 
       heap->set_full_gc_move_in_progress(false);
       heap->set_full_gc_in_progress(false);
 
       if (ShenandoahVerify) {
         heap->verifier()->verify_after_fullgc();
       }
+
+  if (VerifyAfterGC) {
+    Universe::verify();
     }
 
     {
       ShenandoahGCPhase phase(ShenandoahPhaseTimings::full_gc_heapdumps);
       heap->post_full_gc_dump(_gc_timer);

@@ -171,57 +187,50 @@
 
     if (UseTLAB) {
       ShenandoahGCPhase phase(ShenandoahPhaseTimings::full_gc_resize_tlabs);
       heap->resize_all_tlabs();
     }
-  }
 }
 
 class ShenandoahPrepareForMarkClosure: public ShenandoahHeapRegionClosure {
 private:
   ShenandoahMarkingContext* const _ctx;
 
 public:
-  ShenandoahPrepareForMarkClosure() : _ctx(ShenandoahHeap::heap()->next_marking_context()) {}
+  ShenandoahPrepareForMarkClosure() : _ctx(ShenandoahHeap::heap()->marking_context()) {}
 
-  bool heap_region_do(ShenandoahHeapRegion *r) {
-    _ctx->set_top_at_mark_start(r->region_number(), r->top());
+  void heap_region_do(ShenandoahHeapRegion *r) {
+    _ctx->capture_top_at_mark_start(r);
     r->clear_live_data();
     r->set_concurrent_iteration_safe_limit(r->top());
-    return false;
   }
 };
 
 void ShenandoahMarkCompact::phase1_mark_heap() {
   ShenandoahHeap* heap = ShenandoahHeap::heap();
   GCTraceTime time("Phase 1: Mark live objects", ShenandoahLogDebug, _gc_timer, heap->tracer()->gc_id());
   ShenandoahGCPhase mark_phase(ShenandoahPhaseTimings::full_gc_mark);
 
-  {
-    ShenandoahHeapLocker lock(heap->lock());
     ShenandoahPrepareForMarkClosure cl;
-    heap->heap_region_iterate(&cl, false, false);
-  }
+  heap->heap_region_iterate(&cl);
 
-  ShenandoahConcurrentMark* cm = heap->concurrentMark();
+  ShenandoahConcurrentMark* cm = heap->concurrent_mark();
 
-  // Do not trust heuristics, because this can be our last resort collection.
-  // Only ignore processing references and class unloading if explicitly disabled.
-  heap->set_process_references(ShenandoahRefProcFrequency != 0);
-  heap->set_unload_classes(ClassUnloading);
+  heap->set_process_references(heap->heuristics()->can_process_references());
+  heap->set_unload_classes(heap->heuristics()->can_unload_classes());
 
   ReferenceProcessor* rp = heap->ref_processor();
   // enable ("weak") refs discovery
   rp->enable_discovery(true /*verify_no_refs*/, true);
   rp->setup_policy(true); // forcefully purge all soft references
   rp->set_active_mt_degree(heap->workers()->active_workers());
 
   cm->update_roots(ShenandoahPhaseTimings::full_gc_roots);
   cm->mark_roots(ShenandoahPhaseTimings::full_gc_roots);
-  cm->shared_finish_mark_from_roots(/* full_gc = */ true);
+  cm->finish_mark_from_roots(/* full_gc = */ true);
 
-  heap->swap_mark_contexts();
+  heap->mark_complete_marking_context();
 }
 
 class ShenandoahPrepareForCompactionObjectClosure : public ObjectClosure {
 private:
   ShenandoahHeap*          const _heap;

@@ -260,11 +269,11 @@
   void do_object(oop p) {
     assert(_from_region != NULL, "must set before work");
     assert(_heap->complete_marking_context()->is_marked(p), "must be marked");
     assert(!_heap->complete_marking_context()->allocated_after_mark_start((HeapWord*) p), "must be truly marked");
 
-    size_t obj_size = p->size() + BrooksPointer::word_size();
+    size_t obj_size = p->size() + ShenandoahBrooksPointer::word_size();
     if (_compact_point + obj_size > _to_region->end()) {
       finish_region();
 
       // Object doesn't fit. Pick next empty region and start compacting there.
       ShenandoahHeapRegion* new_to_region;

@@ -283,11 +292,11 @@
     }
 
     // Object fits into current region, record new location:
     assert(_compact_point + obj_size <= _to_region->end(), "must fit");
     shenandoah_assert_not_forwarded(NULL, p);
-    BrooksPointer::set_raw(p, _compact_point + BrooksPointer::word_size());
+    ShenandoahBrooksPointer::set_raw(p, _compact_point + ShenandoahBrooksPointer::word_size());
     _compact_point += obj_size;
   }
 };
 
 class ShenandoahPrepareForCompactionTask : public AbstractGangTask {

@@ -380,19 +389,19 @@
       continue;
     }
 
     if (r->is_humongous_start() && r->is_move_allowed()) {
       // From-region candidate: movable humongous region
-      oop old_obj = oop(r->bottom() + BrooksPointer::word_size());
-      size_t words_size = old_obj->size() + BrooksPointer::word_size();
+      oop old_obj = oop(r->bottom() + ShenandoahBrooksPointer::word_size());
+      size_t words_size = old_obj->size() + ShenandoahBrooksPointer::word_size();
       size_t num_regions = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize);
 
       size_t start = to_end - num_regions;
 
       if (start >= to_begin && start != r->region_number()) {
         // Fits into current window, and the move is non-trivial. Record the move then, and continue scan.
-        BrooksPointer::set_raw(old_obj, heap->get_region(start)->bottom() + BrooksPointer::word_size());
+        ShenandoahBrooksPointer::set_raw(old_obj, heap->get_region(start)->bottom() + ShenandoahBrooksPointer::word_size());
         to_end = start;
         continue;
       }
     }
 

@@ -406,11 +415,11 @@
 private:
   ShenandoahHeap* const _heap;
 
 public:
   ShenandoahEnsureHeapActiveClosure() : _heap(ShenandoahHeap::heap()) {}
-  bool heap_region_do(ShenandoahHeapRegion* r) {
+  void heap_region_do(ShenandoahHeapRegion* r) {
     if (r->is_trash()) {
       r->recycle();
     }
     if (r->is_cset()) {
       r->make_regular_bypass();

@@ -421,11 +430,10 @@
     assert (r->is_committed(), err_msg("only committed regions in heap now, see region " SIZE_FORMAT, r->region_number()));
 
     // Record current region occupancy: this communicates empty regions are free
     // to the rest of Full GC code.
     r->set_new_top(r->top());
-    return false;
   }
 };
 
 class ShenandoahTrashImmediateGarbageClosure: public ShenandoahHeapRegionClosure {
 private:

@@ -435,13 +443,13 @@
 public:
   ShenandoahTrashImmediateGarbageClosure() :
     _heap(ShenandoahHeap::heap()),
     _ctx(ShenandoahHeap::heap()->complete_marking_context()) {}
 
-  bool heap_region_do(ShenandoahHeapRegion* r) {
+  void heap_region_do(ShenandoahHeapRegion* r) {
     if (r->is_humongous_start()) {
-      oop humongous_obj = oop(r->bottom() + BrooksPointer::word_size());
+      oop humongous_obj = oop(r->bottom() + ShenandoahBrooksPointer::word_size());
       if (!_ctx->is_marked(humongous_obj)) {
         assert(!r->has_live(),
                err_msg("Region " SIZE_FORMAT " is not marked, should not have live", r->region_number()));
         _heap->trash_humongous_region_at(r);
       } else {

@@ -452,35 +460,30 @@
       // If we hit continuation, the non-live humongous starts should have been trashed already
       assert(r->humongous_start_region()->has_live(),
              err_msg("Region " SIZE_FORMAT " should have live", r->region_number()));
     } else if (r->is_regular()) {
       if (!r->has_live()) {
-        assert(_ctx->is_bitmap_clear_range(r->bottom(), r->end()),
-               err_msg("Region " SIZE_FORMAT " should not have marks in bitmap", r->region_number()));
-        r->make_trash();
+        r->make_trash_immediate();
       }
     }
-    return false;
   }
 };
 
 void ShenandoahMarkCompact::phase2_calculate_target_addresses(ShenandoahHeapRegionSet** worker_slices) {
   ShenandoahHeap* heap = ShenandoahHeap::heap();
   GCTraceTime time("Phase 2: Compute new object addresses", ShenandoahLogDebug, _gc_timer, heap->tracer()->gc_id());
   ShenandoahGCPhase calculate_address_phase(ShenandoahPhaseTimings::full_gc_calculate_addresses);
 
   {
-    ShenandoahHeapLocker lock(heap->lock());
-
     // Trash the immediately collectible regions before computing addresses
     ShenandoahTrashImmediateGarbageClosure tigcl;
-    heap->heap_region_iterate(&tigcl, false, false);
+    heap->heap_region_iterate(&tigcl);
 
     // Make sure regions are in good state: committed, active, clean.
     // This is needed because we are potentially sliding the data through them.
     ShenandoahEnsureHeapActiveClosure ecl;
-    heap->heap_region_iterate(&ecl, false, false);
+    heap->heap_region_iterate(&ecl);
   }
 
   // Compute the new addresses for regular objects
   {
     ShenandoahGCPhase phase(ShenandoahPhaseTimings::full_gc_calculate_addresses_regular);

@@ -504,11 +507,11 @@
   inline void do_oop_work(T* p) {
     T o = oopDesc::load_heap_oop(p);
     if (! oopDesc::is_null(o)) {
       oop obj = oopDesc::decode_heap_oop_not_null(o);
       assert(_ctx->is_marked(obj), "must be marked");
-      oop forw = oop(BrooksPointer::get_raw(obj));
+      oop forw = oop(ShenandoahBrooksPointer::get_raw(obj));
       oopDesc::encode_store_heap_oop(p, forw);
     }
   }
 
 public:

@@ -606,17 +609,17 @@
   ShenandoahCompactObjectsClosure() : _heap(ShenandoahHeap::heap()) {}
 
   void do_object(oop p) {
     assert(_heap->complete_marking_context()->is_marked(p), "must be marked");
     size_t size = (size_t)p->size();
-    HeapWord* compact_to = BrooksPointer::get_raw(p);
+    HeapWord* compact_to = ShenandoahBrooksPointer::get_raw(p);
     HeapWord* compact_from = (HeapWord*) p;
     if (compact_from != compact_to) {
       Copy::aligned_conjoint_words(compact_from, compact_to, size);
     }
     oop new_obj = oop(compact_to);
-    BrooksPointer::initialize(new_obj);
+    ShenandoahBrooksPointer::initialize(new_obj);
   }
 };
 
 class ShenandoahCompactObjectsTask : public AbstractGangTask {
 private:

@@ -654,20 +657,20 @@
 public:
   ShenandoahPostCompactClosure() : _heap(ShenandoahHeap::heap()), _live(0) {
     _heap->free_set()->clear();
   }
 
-  bool heap_region_do(ShenandoahHeapRegion* r) {
+  void heap_region_do(ShenandoahHeapRegion* r) {
     assert (!r->is_cset(), "cset regions should have been demoted already");
 
     // Need to reset the complete-top-at-mark-start pointer here because
     // the complete marking bitmap is no longer valid. This ensures
     // size-based iteration in marked_object_iterate().
     // NOTE: See blurb at ShenandoahMCResetCompleteBitmapTask on why we need to skip
     // pinned regions.
     if (!r->is_pinned()) {
-      _heap->complete_marking_context()->set_top_at_mark_start(r->region_number(), r->bottom());
+      _heap->complete_marking_context()->reset_top_at_mark_start(r);
     }
 
     size_t live = r->used();
 
     // Make empty regions that have been allocated into regular

@@ -687,11 +690,10 @@
     }
 
     r->set_live_data(live);
     r->reset_alloc_metadata_to_shared();
     _live += live;
-    return false;
   }
 
   size_t get_live() {
     return _live;
   }

@@ -707,17 +709,17 @@
   ShenandoahHeap* heap = ShenandoahHeap::heap();
 
   for (size_t c = heap->num_regions() - 1; c > 0; c--) {
     ShenandoahHeapRegion* r = heap->get_region(c);
     if (r->is_humongous_start()) {
-      oop old_obj = oop(r->bottom() + BrooksPointer::word_size());
-      size_t words_size = old_obj->size() + BrooksPointer::word_size();
+      oop old_obj = oop(r->bottom() + ShenandoahBrooksPointer::word_size());
+      size_t words_size = old_obj->size() + ShenandoahBrooksPointer::word_size();
       size_t num_regions = ShenandoahHeapRegion::required_regions(words_size * HeapWordSize);
 
       size_t old_start = r->region_number();
       size_t old_end   = old_start + num_regions - 1;
-      size_t new_start = heap->heap_region_index_containing(BrooksPointer::get_raw(old_obj));
+      size_t new_start = heap->heap_region_index_containing(ShenandoahBrooksPointer::get_raw(old_obj));
       size_t new_end   = new_start + num_regions - 1;
 
       if (old_start == new_start) {
         // No need to move the object, it stays at the same slot
         continue;

@@ -727,16 +729,14 @@
 
       Copy::aligned_conjoint_words(heap->get_region(old_start)->bottom(),
                                    heap->get_region(new_start)->bottom(),
                                    ShenandoahHeapRegion::region_size_words()*num_regions);
 
-      oop new_obj = oop(heap->get_region(new_start)->bottom() + BrooksPointer::word_size());
-      BrooksPointer::initialize(new_obj);
+      oop new_obj = oop(heap->get_region(new_start)->bottom() + ShenandoahBrooksPointer::word_size());
+      ShenandoahBrooksPointer::initialize(new_obj);
 
       {
-        ShenandoahHeapLocker lock(heap->lock());
-
         for (size_t c = old_start; c <= old_end; c++) {
           ShenandoahHeapRegion* r = heap->get_region(c);
           r->make_regular_bypass();
           r->set_top(r->bottom());
         }

@@ -762,11 +762,10 @@
       }
     }
   }
 }
 
-
 // This is slightly different to ShHeap::reset_next_mark_bitmap:
 // we need to remain able to walk pinned regions.
 // Since pinned region do not move and don't get compacted, we will get holes with
 // unreachable objects in them (which may have pointers to unloaded Klasses and thus
 // cannot be iterated over using oop->size(). The only way to safely iterate over those is using

@@ -784,17 +783,12 @@
   void work(uint worker_id) {
     ShenandoahHeapRegion* region = _regions.next();
     ShenandoahHeap* heap = ShenandoahHeap::heap();
     ShenandoahMarkingContext* const ctx = heap->complete_marking_context();
     while (region != NULL) {
-      if (heap->is_bitmap_slice_committed(region) && !region->is_pinned()) {
-        HeapWord* bottom = region->bottom();
-        HeapWord* top = ctx->top_at_mark_start(region->region_number());
-        if (top > bottom && region->has_live()) {
-          ctx->clear_bitmap(bottom, top);
-        }
-        assert(ctx->is_bitmap_clear_range(bottom, region->end()), "must be clear");
+      if (heap->is_bitmap_slice_committed(region) && !region->is_pinned() && region->has_live()) {
+        ctx->clear_bitmap(region);
       }
       region = _regions.next();
     }
   }
 };

@@ -827,22 +821,15 @@
 
   // Bring regions in proper states after the collection, and set heap properties.
   {
     ShenandoahGCPhase phase(ShenandoahPhaseTimings::full_gc_copy_objects_rebuild);
 
-    ShenandoahHeapLocker lock(heap->lock());
     ShenandoahPostCompactClosure post_compact;
     heap->heap_region_iterate(&post_compact);
     heap->set_used(post_compact.get_live());
 
     heap->collection_set()->clear();
     heap->free_set()->rebuild();
   }
 
   heap->clear_cancelled_gc();
-
-  // Also clear the next bitmap in preparation for next marking.
-  {
-    ShenandoahGCPhase phase(ShenandoahPhaseTimings::full_gc_copy_objects_reset_next);
-    heap->reset_next_mark_bitmap();
-  }
 }
< prev index next >