# HG changeset patch # User rkennke # Date 1507625976 -7200 # Tue Oct 10 10:59:36 2017 +0200 # Node ID 35b56394e21b36982398fd548de489451292e42c # Parent e58464fa9bebba3d788c079dc345a4e625cd91f0 Remove secondary marking bitmap. diff --git a/src/share/vm/gc/shenandoah/shenandoahBarrierSet.cpp b/src/share/vm/gc/shenandoah/shenandoahBarrierSet.cpp --- a/src/share/vm/gc/shenandoah/shenandoahBarrierSet.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahBarrierSet.cpp @@ -445,15 +445,13 @@ if (p == NULL) return; if (heap->in_collection_set(p) && ! heap->cancelled_concgc()) { - tty->print_cr("oop = "PTR_FORMAT", resolved: "PTR_FORMAT", marked-next %s, marked-complete: %s", + tty->print_cr("oop = "PTR_FORMAT", resolved: "PTR_FORMAT", marked %s", p2i(p), p2i(read_barrier(p)), - BOOL_TO_STR(heap->is_marked_next(p)), - BOOL_TO_STR(heap->is_marked_complete(p))); + BOOL_TO_STR(heap->is_marked(p))); tty->print_cr("in_cset: %s", BOOL_TO_STR(heap->in_collection_set(p))); heap->heap_region_containing((HeapWord*) p)->print(); - tty->print_cr("top-at-mark-start: %p", heap->next_top_at_mark_start((HeapWord*) p)); - tty->print_cr("top-at-prev-mark-start: %p", heap->complete_top_at_mark_start((HeapWord*) p)); + tty->print_cr("top-at-mark-start: %p", heap->top_at_mark_start((HeapWord*) p)); tty->print_cr("marking: %s, evacuating: %s", BOOL_TO_STR(heap->concurrent_mark_in_progress()), BOOL_TO_STR(heap->is_evacuation_in_progress())); assert(false, "We should have fixed this earlier"); } diff --git a/src/share/vm/gc/shenandoah/shenandoahCollectorPolicy.cpp b/src/share/vm/gc/shenandoah/shenandoahCollectorPolicy.cpp --- a/src/share/vm/gc/shenandoah/shenandoahCollectorPolicy.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahCollectorPolicy.cpp @@ -350,7 +350,7 @@ // Reclaim humongous regions here, and count them as the immediate garbage #ifdef ASSERT bool reg_live = region->has_live(); - bool bm_live = heap->is_marked_complete(oop(region->bottom() + BrooksPointer::word_size())); + bool bm_live = heap->is_marked(oop(region->bottom() + BrooksPointer::word_size())); assert(reg_live == bm_live, "Humongous liveness and marks should agree. Region live: %s; Bitmap live: %s; Region Live Words: " SIZE_FORMAT, BOOL_TO_STR(reg_live), BOOL_TO_STR(bm_live), region->get_live_data_words()); diff --git a/src/share/vm/gc/shenandoah/shenandoahConcurrentMark.inline.hpp b/src/share/vm/gc/shenandoah/shenandoahConcurrentMark.inline.hpp --- a/src/share/vm/gc/shenandoah/shenandoahConcurrentMark.inline.hpp +++ b/src/share/vm/gc/shenandoah/shenandoahConcurrentMark.inline.hpp @@ -41,7 +41,7 @@ || oopDesc::bs()->is_safe(obj), "we don't want to mark objects in from-space"); assert(_heap->is_in(obj), "referenced objects must be in the heap. No?"); - assert(_heap->is_marked_next(obj), "only marked objects on task queue"); + assert(_heap->is_marked(obj), "only marked objects on task queue"); if (task->is_not_chunked()) { if (COUNT_LIVENESS) count_liveness(live_data, obj); @@ -240,14 +240,14 @@ assert(heap->is_in(obj), "We shouldn't be calling this on objects not in the heap: " PTR_FORMAT, p2i(obj)); assert(oopDesc::bs()->is_safe(obj), "Only mark objects in from-space"); - if (heap->mark_next(obj)) { + if (heap->mark(obj)) { log_develop_trace(gc, marking)("Marked obj: " PTR_FORMAT, p2i((HeapWord*) obj)); bool pushed = q->push(ShenandoahMarkTask(obj)); assert(pushed, "overflow queue should always succeed pushing"); } else { log_develop_trace(gc, marking)("Failed to mark obj (already marked): " PTR_FORMAT, p2i((HeapWord*) obj)); - assert(heap->is_marked_next(obj), "Consistency: should be marked."); + assert(heap->is_marked(obj), "Consistency: should be marked."); } } } diff --git a/src/share/vm/gc/shenandoah/shenandoahConcurrentThread.cpp b/src/share/vm/gc/shenandoah/shenandoahConcurrentThread.cpp --- a/src/share/vm/gc/shenandoah/shenandoahConcurrentThread.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahConcurrentThread.cpp @@ -176,6 +176,18 @@ TraceCollectorStats tcs(heap->monitoring_support()->concurrent_collection_counters()); TraceMemoryManagerStats tmms(false, GCCause::_no_cause_specified); + // Mark requires clean bitmaps. Clear them here, before diving into STW. + // There is a potential race from this moment on to TAMS reset in init mark: the bitmaps + // would be clear, but TAMS not yet updated. + { + GCTraceTime(Info, gc) time("Concurrent cleanup", gc_timer, GCCause::_no_gc, true); + ShenandoahGCPhase phase(ShenandoahPhaseTimings::conc_cleanup); + ShenandoahGCPhase phase_reset(ShenandoahPhaseTimings::conc_cleanup_reset_bitmaps); + WorkGang *workers = heap->workers(); + ShenandoahPushWorkerScope scope(workers, ConcGCThreads); + heap->reset_mark_bitmap(workers); + } + // Start initial mark under STW: { // Workers are setup by VM_ShenandoahInitMark @@ -326,6 +338,17 @@ VM_ShenandoahFinalUpdateRefs final_update_refs; VMThread::execute(&final_update_refs); } + + if (do_it) { + GCTraceTime(Info, gc) time("Concurrent cleanup", gc_timer, GCCause::_no_gc, true); + ShenandoahGCPhase phase(ShenandoahPhaseTimings::conc_cleanup); + ShenandoahGCPhase phase_recycle(ShenandoahPhaseTimings::conc_cleanup_recycle); + heap->recycle_trash(); + } + + // Allocations happen during bitmap cleanup, record peak after the phase: + heap->shenandoahPolicy()->record_peak_occupancy(); + } else { // If update-refs were skipped, need to do another verification pass after evacuation. if (ShenandoahVerify && !check_cancellation()) { @@ -341,26 +364,6 @@ reset_full_gc(); } - { - GCTraceTime(Info, gc) time("Concurrent cleanup", gc_timer, GCCause::_no_gc, true); - ShenandoahGCPhase phase(ShenandoahPhaseTimings::conc_cleanup); - - { - ShenandoahGCPhase phase_recycle(ShenandoahPhaseTimings::conc_cleanup_recycle); - heap->recycle_trash(); - } - - { - ShenandoahGCPhase phase_reset(ShenandoahPhaseTimings::conc_cleanup_reset_bitmaps); - WorkGang *workers = heap->workers(); - ShenandoahPushWorkerScope scope(workers, ConcGCThreads); - heap->reset_next_mark_bitmap(workers); - } - } - - // Allocations happen during bitmap cleanup, record peak after the phase: - heap->shenandoahPolicy()->record_peak_occupancy(); - // Cycle is complete heap->shenandoahPolicy()->record_cycle_end(); diff --git a/src/share/vm/gc/shenandoah/shenandoahHeap.cpp b/src/share/vm/gc/shenandoah/shenandoahHeap.cpp --- a/src/share/vm/gc/shenandoah/shenandoahHeap.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahHeap.cpp @@ -82,11 +82,10 @@ ShenandoahHeapRegionSet* _regions; const size_t _bitmap_size; const size_t _page_size; - char* _bitmap0_base; - char* _bitmap1_base; + char* _bitmap_base; public: ShenandoahPretouchTask(ShenandoahHeapRegionSet* regions, - char* bitmap0_base, char* bitmap1_base, size_t bitmap_size, + char* bitmap_base, size_t bitmap_size, size_t page_size) : AbstractGangTask("Shenandoah PreTouch", Universe::is_fully_initialized() ? GCId::current_raw() : @@ -94,8 +93,7 @@ // no GC cycle that this task can be // associated with. GCId::undefined()), - _bitmap0_base(bitmap0_base), - _bitmap1_base(bitmap1_base), + _bitmap_base(bitmap_base), _regions(regions), _bitmap_size(bitmap_size), _page_size(page_size) { @@ -114,12 +112,8 @@ assert (end <= _bitmap_size, "end is sane: " SIZE_FORMAT " < " SIZE_FORMAT, end, _bitmap_size); log_trace(gc, heap)("Pretouch bitmap under region " SIZE_FORMAT ": " PTR_FORMAT " -> " PTR_FORMAT, - r->region_number(), p2i(_bitmap0_base + start), p2i(_bitmap0_base + end)); - os::pretouch_memory(_bitmap0_base + start, _bitmap0_base + end, _page_size); - - log_trace(gc, heap)("Pretouch bitmap under region " SIZE_FORMAT ": " PTR_FORMAT " -> " PTR_FORMAT, - r->region_number(), p2i(_bitmap1_base + start), p2i(_bitmap1_base + end)); - os::pretouch_memory(_bitmap1_base + start, _bitmap1_base + end, _page_size); + r->region_number(), p2i(_bitmap_base + start), p2i(_bitmap_base + end)); + os::pretouch_memory(_bitmap_base + start, _bitmap_base + end, _page_size); r = _regions->claim_next(); } @@ -171,13 +165,10 @@ _collection_set = new ShenandoahCollectionSet(this, (HeapWord*)pgc_rs.base()); - _next_top_at_mark_starts_base = NEW_C_HEAP_ARRAY(HeapWord*, _num_regions, mtGC); - _next_top_at_mark_starts = _next_top_at_mark_starts_base - + _top_at_mark_starts_base = NEW_C_HEAP_ARRAY(HeapWord*, _num_regions, mtGC); + _top_at_mark_starts = _top_at_mark_starts_base - ((uintx) pgc_rs.base() >> ShenandoahHeapRegion::region_size_bytes_shift()); - _complete_top_at_mark_starts_base = NEW_C_HEAP_ARRAY(HeapWord*, _num_regions, mtGC); - _complete_top_at_mark_starts = _complete_top_at_mark_starts_base - - ((uintx) pgc_rs.base() >> ShenandoahHeapRegion::region_size_bytes_shift()); { ShenandoahHeapLocker locker(lock()); @@ -188,8 +179,7 @@ i, i < num_committed_regions); - _complete_top_at_mark_starts_base[i] = r->bottom(); - _next_top_at_mark_starts_base[i] = r->bottom(); + _top_at_mark_starts_base[i] = r->bottom(); // Add to ordered regions first. // We use the active size of ordered regions as the number of active regions in heap, @@ -243,13 +233,9 @@ size_t bitmap_page_size = UseLargePages && (bitmap_bytes_per_region >= (size_t)os::large_page_size()) ? (size_t)os::large_page_size() : (size_t)os::vm_page_size(); - ReservedSpace bitmap0(_bitmap_size, bitmap_page_size); - MemTracker::record_virtual_memory_type(bitmap0.base(), mtGC); - _bitmap0_region = MemRegion((HeapWord*) bitmap0.base(), bitmap0.size() / HeapWordSize); - - ReservedSpace bitmap1(_bitmap_size, bitmap_page_size); - MemTracker::record_virtual_memory_type(bitmap1.base(), mtGC); - _bitmap1_region = MemRegion((HeapWord*) bitmap1.base(), bitmap1.size() / HeapWordSize); + ReservedSpace bitmap(_bitmap_size, bitmap_page_size); + MemTracker::record_virtual_memory_type(bitmap.base(), mtGC); + _bitmap_region = MemRegion((HeapWord*) bitmap.base(), bitmap.size() / HeapWordSize); { ShenandoahHeapLocker locker(lock()); @@ -282,15 +268,17 @@ log_info(gc, heap)("Parallel pretouch " SIZE_FORMAT " regions with " SIZE_FORMAT " byte pages", _ordered_regions->count(), page_size); - ShenandoahPretouchTask cl(_ordered_regions, bitmap0.base(), bitmap1.base(), _bitmap_size, page_size); + ShenandoahPretouchTask cl(_ordered_regions, bitmap.base(), _bitmap_size, page_size); _workers->run_task(&cl); } - _mark_bit_map0.initialize(_heap_region, _bitmap0_region); - _complete_mark_bit_map = &_mark_bit_map0; + _mark_bit_map.initialize(_heap_region, _bitmap_region); - _mark_bit_map1.initialize(_heap_region, _bitmap1_region); - _next_mark_bit_map = &_mark_bit_map1; + // Reserve aux bitmap for use in object_iterate(). We don't commit it here. + ReservedSpace aux_bitmap(_bitmap_size, bitmap_page_size); + MemTracker::record_virtual_memory_type(aux_bitmap.base(), mtGC); + _aux_bitmap_region = MemRegion((HeapWord*) aux_bitmap.base(), aux_bitmap.size() / HeapWordSize); + _aux_bit_map.initialize(_heap_region, _aux_bitmap_region); if (UseShenandoahMatrix) { _connection_matrix = new ShenandoahConnectionMatrix(_num_regions); @@ -337,16 +325,15 @@ _used_start_gc(0), _max_workers(MAX2(ConcGCThreads, ParallelGCThreads)), _ref_processor(NULL), - _next_top_at_mark_starts(NULL), - _next_top_at_mark_starts_base(NULL), - _complete_top_at_mark_starts(NULL), - _complete_top_at_mark_starts_base(NULL), - _mark_bit_map0(), - _mark_bit_map1(), + _top_at_mark_starts(NULL), + _top_at_mark_starts_base(NULL), + _mark_bit_map(), + _aux_bit_map(), _connection_matrix(NULL), _cancelled_concgc(0), _need_update_refs(false), - _need_reset_bitmaps(false), + _need_reset_bitmap(false), + _bitmap_valid(true), _verifier(NULL), _heap_lock(0), _used_at_last_gc(0), @@ -386,12 +373,12 @@ } } -class ShenandoahResetNextBitmapTask : public AbstractGangTask { +class ShenandoahResetBitmapTask : public AbstractGangTask { private: ShenandoahHeapRegionSet* _regions; public: - ShenandoahResetNextBitmapTask(ShenandoahHeapRegionSet* regions) : + ShenandoahResetBitmapTask(ShenandoahHeapRegionSet* regions) : AbstractGangTask("Parallel Reset Bitmap Task"), _regions(regions) { _regions->clear_current_index(); @@ -403,75 +390,37 @@ while (region != NULL) { if (region->is_committed()) { HeapWord* bottom = region->bottom(); - HeapWord* top = heap->next_top_at_mark_start(region->bottom()); + HeapWord* top = heap->top_at_mark_start(region->bottom()); if (top > bottom) { - heap->next_mark_bit_map()->clear_range_large(MemRegion(bottom, top)); + heap->mark_bit_map()->clear_range_large(MemRegion(bottom, top)); } - assert(heap->is_next_bitmap_clear_range(bottom, region->end()), "must be clear"); + assert(heap->is_bitmap_clear_range(bottom, region->end()), "must be clear"); + heap->set_top_at_mark_start(region->bottom(), region->bottom()); } region = _regions->claim_next(); } } }; -void ShenandoahHeap::reset_next_mark_bitmap(WorkGang* workers) { +void ShenandoahHeap::reset_mark_bitmap(WorkGang* workers) { assert_gc_workers(workers->active_workers()); - ShenandoahResetNextBitmapTask task = ShenandoahResetNextBitmapTask(_ordered_regions); + ShenandoahResetBitmapTask task = ShenandoahResetBitmapTask(_ordered_regions); workers->run_task(&task); } -class ShenandoahResetCompleteBitmapTask : public AbstractGangTask { -private: - ShenandoahHeapRegionSet* _regions; - -public: - ShenandoahResetCompleteBitmapTask(ShenandoahHeapRegionSet* regions) : - AbstractGangTask("Parallel Reset Bitmap Task"), - _regions(regions) { - _regions->clear_current_index(); - } - - void work(uint worker_id) { - ShenandoahHeapRegion* region = _regions->claim_next(); - ShenandoahHeap* heap = ShenandoahHeap::heap(); - while (region != NULL) { - if (region->is_committed()) { - HeapWord* bottom = region->bottom(); - HeapWord* top = heap->complete_top_at_mark_start(region->bottom()); - if (top > bottom) { - heap->complete_mark_bit_map()->clear_range_large(MemRegion(bottom, top)); - } - assert(heap->is_complete_bitmap_clear_range(bottom, region->end()), "must be clear"); - } - region = _regions->claim_next(); - } - } -}; - -void ShenandoahHeap::reset_complete_mark_bitmap(WorkGang* workers) { - assert_gc_workers(workers->active_workers()); - - ShenandoahResetCompleteBitmapTask task = ShenandoahResetCompleteBitmapTask(_ordered_regions); - workers->run_task(&task); -} - -bool ShenandoahHeap::is_next_bitmap_clear() { +bool ShenandoahHeap::is_bitmap_clear() { for (size_t idx = 0; idx < _num_regions; idx++) { ShenandoahHeapRegion* r = _ordered_regions->get(idx); - if (r->is_committed() && !is_next_bitmap_clear_range(r->bottom(), r->end())) { + if (r->is_committed() && !is_bitmap_clear_range(r->bottom(), r->end())) { return false; } } return true; } -bool ShenandoahHeap::is_next_bitmap_clear_range(HeapWord* start, HeapWord* end) { - return _next_mark_bit_map->getNextMarkedWordAddress(start, end) == end; -} - -bool ShenandoahHeap::is_complete_bitmap_clear_range(HeapWord* start, HeapWord* end) { - return _complete_mark_bit_map->getNextMarkedWordAddress(start, end) == end; +bool ShenandoahHeap::is_bitmap_clear_range(HeapWord* start, HeapWord* end) { + return _mark_bit_map.getNextMarkedWordAddress(start, end) == end; } void ShenandoahHeap::print_on(outputStream* st) const { @@ -787,8 +736,8 @@ if (! oopDesc::is_null(o)) { oop obj = oopDesc::decode_heap_oop_not_null(o); if (_heap->in_collection_set(obj)) { - assert(_heap->is_marked_complete(obj), "only evacuate marked objects %d %d", - _heap->is_marked_complete(obj), _heap->is_marked_complete(ShenandoahBarrierSet::resolve_oop_static_not_null(obj))); + assert(_heap->is_marked(obj), "only evacuate marked objects %d %d", + _heap->is_marked(obj), _heap->is_marked(ShenandoahBarrierSet::resolve_oop_static_not_null(obj))); oop resolved = ShenandoahBarrierSet::resolve_oop_static_not_null(obj); if (oopDesc::unsafe_equals(resolved, obj)) { bool evac; @@ -851,7 +800,7 @@ _heap(heap), _thread(Thread::current()) {} void do_object(oop p) { - assert(_heap->is_marked_complete(p), "expect only marked objects"); + assert(_heap->is_marked(p), "expect only marked objects"); if (oopDesc::unsafe_equals(p, ShenandoahBarrierSet::resolve_oop_static_not_null(p))) { bool evac; _heap->evacuate_object(p, _thread, evac); @@ -981,7 +930,7 @@ // Allocations might have happened before we STWed here, record peak: shenandoahPolicy()->record_peak_occupancy(); - ensure_parsability(true); + make_tlabs_parsable(true); if (ShenandoahVerify) { verifier()->verify_after_concmark(); @@ -1037,7 +986,7 @@ } }; -void ShenandoahHeap::ensure_parsability(bool retire_tlabs) { +void ShenandoahHeap::make_tlabs_parsable(bool retire_tlabs) { if (UseTLAB) { CollectedHeap::ensure_parsability(retire_tlabs); ShenandoahRetireTLABClosure cl(retire_tlabs); @@ -1303,7 +1252,7 @@ void ShenandoahHeap::prepare_for_verify() { if (SafepointSynchronize::is_at_safepoint() || ! UseTLAB) { - ensure_parsability(false); + make_tlabs_parsable(false); } } @@ -1364,69 +1313,94 @@ } }; -void ShenandoahHeap::object_iterate(ObjectClosure* cl) { - ShenandoahIterateObjectClosureRegionClosure blk(cl); - heap_region_iterate(&blk, false, true); -} +class ObjectIterateScanRootClosure : public ExtendedOopClosure { +private: + MarkBitMap* _bitmap; + Stack* _oop_stack; -class ShenandoahSafeObjectIterateAdjustPtrsClosure : public MetadataAwareOopClosure { -private: - ShenandoahHeap* _heap; - -public: - ShenandoahSafeObjectIterateAdjustPtrsClosure() : _heap(ShenandoahHeap::heap()) {} - -private: template - inline void do_oop_work(T* p) { + 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); - oopDesc::encode_store_heap_oop(p, BrooksPointer::forwardee(obj)); + obj = ShenandoahBarrierSet::resolve_oop_static_not_null(obj); + assert(oopDesc::is_oop(obj), "must be a valid oop"); + if (!_bitmap->isMarked((HeapWord*) obj)) { + _bitmap->mark((HeapWord*) obj); + _oop_stack->push(obj); + } } } + public: - void do_oop(oop* p) { - do_oop_work(p); - } - void do_oop(narrowOop* p) { - do_oop_work(p); - } + ObjectIterateScanRootClosure(MarkBitMap* bitmap, Stack* oop_stack) : + _bitmap(bitmap), _oop_stack(oop_stack) {} + void do_oop(oop* p) { do_oop_work(p); } + void do_oop(narrowOop* p) { do_oop_work(p); } }; -class ShenandoahSafeObjectIterateAndUpdate : public ObjectClosure { -private: - ObjectClosure* _cl; -public: - ShenandoahSafeObjectIterateAndUpdate(ObjectClosure *cl) : _cl(cl) {} +/* + * This is public API, used in preparation of object_iterate(). + * Since we don't do linear scan of heap in object_iterate() (see comment below), we don't + * need to make the heap parsable. For Shenandoah-internal linear heap scans that we can + * control, we call SH::make_tlabs_parsable(). + */ +void ShenandoahHeap::ensure_parsability(bool retire_tlabs) { + // No-op. +} - virtual void do_object(oop obj) { - assert (oopDesc::unsafe_equals(obj, BrooksPointer::forwardee(obj)), - "avoid double-counting: only non-forwarded objects here"); - // Fix up the ptrs. - ShenandoahSafeObjectIterateAdjustPtrsClosure adjust_ptrs; - obj->oop_iterate(&adjust_ptrs); +/* + * Iterates objects in the heap. This is public API, used for, e.g., heap dumping. + * + * We cannot safely iterate objects by doing a linear scan at random points in time. Linear + * scanning needs to deal with dead objects, which may have dead Klass* pointers (e.g. + * calling oopDesc::size() would crash) or dangling reference fields (crashes) etc. Linear + * scanning therefore depends on having a valid marking bitmap to support it. However, we only + * have a valid marking bitmap after successful marking. In particular, we *don't* have a valid + * marking bitmap during marking, after aborted marking or during/after cleanup (when we just + * wiped the bitmap in preparation for next marking). + * + * For all those reasons, we implement object iteration as a single marking traversal, reporting + * objects as we mark+traverse through the heap, starting from GC roots. This is ok. JVMTI + * IterateThroughHeap is allowed to report dead objects, but is not required to do so. + */ +void ShenandoahHeap::object_iterate(ObjectClosure* cl) { + assert(SafepointSynchronize::is_at_safepoint(), "safe iteration is only available during safepoints"); + if (!os::commit_memory((char*)_aux_bitmap_region.start(), _aux_bitmap_region.byte_size(), false)) { + log_warning(gc)("Hold my beer, we are about to crash this VM."); + log_warning(gc)("Could not commit native memory for auxiliary marking bitmap for heap iteration"); + return; + } - // Can reply the object now: - _cl->do_object(obj); + Stack oop_stack; + + // First, we process all GC roots. This populates the work stack with initial objects. + ShenandoahRootProcessor rp(this, 1, ShenandoahPhaseTimings::_num_phases); + ObjectIterateScanRootClosure oops(&_aux_bit_map, &oop_stack); + CLDToOopClosure clds(&oops, false); + CodeBlobToOopClosure blobs(&oops, false); + rp.process_all_roots(&oops, &oops, &clds, &blobs, 0); + + // Work through the oop stack to traverse heap. + while (! oop_stack.is_empty()) { + oop obj = oop_stack.pop(); + assert(oopDesc::is_oop(obj), "must be a valid oop"); + cl->do_object(obj); + obj->oop_iterate(&oops); } -}; + + assert(oop_stack.is_empty(), "should be empty"); + + if (!os::uncommit_memory((char*)_aux_bitmap_region.start(), _aux_bitmap_region.byte_size())) { + log_warning(gc)("Hold my beer, we are about to crash this VM."); + log_warning(gc)("Could not uncommit native memory for auxiliary marking bitmap for heap iteration"); + } +} void ShenandoahHeap::safe_object_iterate(ObjectClosure* cl) { assert(SafepointSynchronize::is_at_safepoint(), "safe iteration is only available during safepoints"); - - // Safe iteration does objects only with correct references. - // This is why we skip collection set regions that have stale copies of objects, - // and fix up the pointers in the returned objects. - - ShenandoahSafeObjectIterateAndUpdate safe_cl(cl); - ShenandoahIterateObjectClosureRegionClosure blk(&safe_cl); - heap_region_iterate(&blk, - /* skip_cset_regions = */ true, - /* skip_humongous_continuations = */ true); - - _need_update_refs = false; // already updated the references + object_iterate(cl); } // Apply blk->heap_region_do() on all committed regions in address order, @@ -1454,7 +1428,7 @@ bool heap_region_do(ShenandoahHeapRegion* r) { r->clear_live_data(); - sh->set_next_top_at_mark_start(r->bottom(), r->top()); + sh->set_top_at_mark_start(r->bottom(), r->top()); return false; } }; @@ -1473,7 +1447,7 @@ // We need to reset all TLABs because we'd lose marks on all objects allocated in them. if (UseTLAB) { ShenandoahGCPhase phase(ShenandoahPhaseTimings::make_parsable); - ensure_parsability(true); + make_tlabs_parsable(true); } _shenandoah_policy->record_bytes_allocated(_bytes_allocated_since_cm); @@ -1496,30 +1470,12 @@ } } -void ShenandoahHeap::swap_mark_bitmaps() { - // Swap bitmaps. - MarkBitMap* tmp1 = _complete_mark_bit_map; - _complete_mark_bit_map = _next_mark_bit_map; - _next_mark_bit_map = tmp1; - - // Swap top-at-mark-start pointers - HeapWord** tmp2 = _complete_top_at_mark_starts; - _complete_top_at_mark_starts = _next_top_at_mark_starts; - _next_top_at_mark_starts = tmp2; - - HeapWord** tmp3 = _complete_top_at_mark_starts_base; - _complete_top_at_mark_starts_base = _next_top_at_mark_starts_base; - _next_top_at_mark_starts_base = tmp3; -} - - void ShenandoahHeap::stop_concurrent_marking() { assert(concurrent_mark_in_progress(), "How else could we get here?"); if (! cancelled_concgc()) { // If we needed to update refs, and concurrent marking has been cancelled, // we need to finish updating references. set_need_update_refs(false); - swap_mark_bitmaps(); } set_concurrent_mark_in_progress(false); @@ -1607,7 +1563,7 @@ } #endif assert(!oopDesc::is_null(obj), "null"); - return _heap->is_marked_next(obj); + return _heap->is_marked(obj); } ShenandoahIsAliveClosure::ShenandoahIsAliveClosure() : @@ -1618,7 +1574,7 @@ assert(_heap != NULL, "sanity"); assert(!oopDesc::is_null(obj), "null"); assert(oopDesc::unsafe_equals(obj, ShenandoahBarrierSet::resolve_oop_static_not_null(obj)), "only query to-space"); - return _heap->is_marked_next(obj); + return _heap->is_marked(obj); } BoolObjectClosure* ShenandoahHeap::is_alive_closure() { @@ -1805,12 +1761,8 @@ return _monitoring_support; } -MarkBitMap* ShenandoahHeap::complete_mark_bit_map() { - return _complete_mark_bit_map; -} - -MarkBitMap* ShenandoahHeap::next_mark_bit_map() { - return _next_mark_bit_map; +MarkBitMap* ShenandoahHeap::mark_bit_map() { + return &_mark_bit_map; } void ShenandoahHeap::add_free_region(ShenandoahHeapRegion* r) { @@ -1844,24 +1796,14 @@ _bytes_allocated_since_cm = bytes; } -void ShenandoahHeap::set_next_top_at_mark_start(HeapWord* region_base, HeapWord* addr) { +void ShenandoahHeap::set_top_at_mark_start(HeapWord* region_base, HeapWord* addr) { uintx index = ((uintx) region_base) >> ShenandoahHeapRegion::region_size_bytes_shift(); - _next_top_at_mark_starts[index] = addr; + _top_at_mark_starts[index] = addr; } -HeapWord* ShenandoahHeap::next_top_at_mark_start(HeapWord* region_base) { +HeapWord* ShenandoahHeap::top_at_mark_start(HeapWord* region_base) { uintx index = ((uintx) region_base) >> ShenandoahHeapRegion::region_size_bytes_shift(); - return _next_top_at_mark_starts[index]; -} - -void ShenandoahHeap::set_complete_top_at_mark_start(HeapWord* region_base, HeapWord* addr) { - uintx index = ((uintx) region_base) >> ShenandoahHeapRegion::region_size_bytes_shift(); - _complete_top_at_mark_starts[index] = addr; -} - -HeapWord* ShenandoahHeap::complete_top_at_mark_start(HeapWord* region_base) { - uintx index = ((uintx) region_base) >> ShenandoahHeapRegion::region_size_bytes_shift(); - return _complete_top_at_mark_starts[index]; + return _top_at_mark_starts[index]; } void ShenandoahHeap::set_full_gc_in_progress(bool in_progress) { @@ -1987,9 +1929,9 @@ while (r != NULL) { if (_heap->in_collection_set(r)) { HeapWord* bottom = r->bottom(); - HeapWord* top = _heap->complete_top_at_mark_start(r->bottom()); + HeapWord* top = _heap->top_at_mark_start(r->bottom()); if (top > bottom) { - _heap->complete_mark_bit_map()->clear_range_large(MemRegion(bottom, top)); + _heap->mark_bit_map()->clear_range_large(MemRegion(bottom, top)); } } else { if (r->is_active()) { @@ -2030,7 +1972,7 @@ set_evacuation_in_progress_at_safepoint(false); set_update_refs_in_progress(true); - ensure_parsability(true); + make_tlabs_parsable(true); if (UseShenandoahMatrix) { connection_matrix()->clear_all(); } @@ -2195,10 +2137,7 @@ bool ShenandoahHeap::commit_bitmaps(ShenandoahHeapRegion* r) { size_t len = _bitmap_words_per_region * HeapWordSize; size_t off = r->region_number() * _bitmap_words_per_region; - if (!os::commit_memory((char*)(_bitmap0_region.start() + off), len, false)) { - return false; - } - if (!os::commit_memory((char*)(_bitmap1_region.start() + off), len, false)) { + if (!os::commit_memory((char*)(_bitmap_region.start() + off), len, false)) { return false; } return true; @@ -2207,10 +2146,7 @@ bool ShenandoahHeap::uncommit_bitmaps(ShenandoahHeapRegion* r) { size_t len = _bitmap_words_per_region * HeapWordSize; size_t off = r->region_number() * _bitmap_words_per_region; - if (!os::uncommit_memory((char*)(_bitmap0_region.start() + off), len)) { - return false; - } - if (!os::uncommit_memory((char*)(_bitmap1_region.start() + off), len)) { + if (!os::uncommit_memory((char*)(_bitmap_region.start() + off), len)) { return false; } return true; diff --git a/src/share/vm/gc/shenandoah/shenandoahHeap.hpp b/src/share/vm/gc/shenandoah/shenandoahHeap.hpp --- a/src/share/vm/gc/shenandoah/shenandoahHeap.hpp +++ b/src/share/vm/gc/shenandoah/shenandoahHeap.hpp @@ -135,8 +135,8 @@ size_t _bitmap_size; size_t _bitmap_words_per_region; MemRegion _heap_region; - MemRegion _bitmap0_region; - MemRegion _bitmap1_region; + MemRegion _bitmap_region; + MemRegion _aux_bitmap_region; // Sortable array of regions ShenandoahHeapRegionSet* _ordered_regions; @@ -165,16 +165,12 @@ volatile size_t _committed; MarkBitMap _verification_bit_map; - MarkBitMap _mark_bit_map0; - MarkBitMap _mark_bit_map1; - MarkBitMap* _complete_mark_bit_map; - MarkBitMap* _next_mark_bit_map; + MarkBitMap _aux_bit_map; + MarkBitMap _mark_bit_map; + bool _bitmap_valid; - HeapWord** _complete_top_at_mark_starts; - HeapWord** _complete_top_at_mark_starts_base; - - HeapWord** _next_top_at_mark_starts; - HeapWord** _next_top_at_mark_starts_base; + HeapWord** _top_at_mark_starts; + HeapWord** _top_at_mark_starts_base; volatile jbyte _cancelled_concgc; @@ -191,7 +187,7 @@ unsigned int _evacuation_in_progress; bool _need_update_refs; - bool _need_reset_bitmaps; + bool _need_reset_bitmap; ReferenceProcessor* _ref_processor; @@ -345,13 +341,9 @@ template inline bool in_collection_set(T obj) const; - inline bool allocated_after_next_mark_start(HeapWord* addr) const; - void set_next_top_at_mark_start(HeapWord* region_base, HeapWord* addr); - HeapWord* next_top_at_mark_start(HeapWord* region_base); - - inline bool allocated_after_complete_mark_start(HeapWord* addr) const; - void set_complete_top_at_mark_start(HeapWord* region_base, HeapWord* addr); - HeapWord* complete_top_at_mark_start(HeapWord* region_base); + inline bool allocated_after_mark_start(HeapWord* addr) const; + void set_top_at_mark_start(HeapWord* region_base, HeapWord* addr); + HeapWord* top_at_mark_start(HeapWord* region_base); // Evacuates object src. Returns the evacuated object if this thread // succeeded, otherwise rolls back the evacuation and returns the @@ -383,17 +375,16 @@ size_t garbage(); - void reset_next_mark_bitmap(WorkGang* gang); - void reset_complete_mark_bitmap(WorkGang* gang); + void reset_mark_bitmap(WorkGang* gang); - MarkBitMap* complete_mark_bit_map(); - MarkBitMap* next_mark_bit_map(); - inline bool is_marked_complete(oop obj) const; - inline bool mark_next(oop obj) const; - inline bool is_marked_next(oop obj) const; - bool is_next_bitmap_clear(); - bool is_next_bitmap_clear_range(HeapWord* start, HeapWord* end); - bool is_complete_bitmap_clear_range(HeapWord* start, HeapWord* end); + MarkBitMap* mark_bit_map(); + inline bool is_marked(oop obj) const; + inline bool mark(oop obj); + bool is_bitmap_clear(); + bool is_bitmap_clear_range(HeapWord* start, HeapWord* end); + + bool is_bitmap_valid() const { return _bitmap_valid; } + void set_bitmap_valid(bool valid) { _bitmap_valid = valid; } bool commit_bitmaps(ShenandoahHeapRegion* r); bool uncommit_bitmaps(ShenandoahHeapRegion* r); @@ -459,8 +450,6 @@ GCTimer* gc_timer() const; - void swap_mark_bitmaps(); - void cancel_concgc(GCCause::Cause cause); void cancel_concgc(ShenandoahCancelCause cause); @@ -503,11 +492,11 @@ HeapWord* allocate_new_gclab(size_t word_size); template - inline void do_marked_object(MarkBitMap* bitmap, T* cl, oop obj); + inline void do_marked_object(T* cl, oop obj); ShenandoahConcurrentThread* concurrent_thread() { return _concurrent_gc_thread; } - inline bool mark_next_no_checks(oop obj) const; + inline bool mark_no_checks(oop obj); public: inline oop atomic_compare_exchange_oop(oop n, narrowOop* addr, oop c); @@ -545,6 +534,8 @@ void set_alloc_seq_gc_end(); void set_used_at_last_gc() {_used_at_last_gc = used();} + + void make_tlabs_parsable(bool retire_tlabs) /* override */; }; #endif // SHARE_VM_GC_SHENANDOAH_SHENANDOAHHEAP_HPP diff --git a/src/share/vm/gc/shenandoah/shenandoahHeap.inline.hpp b/src/share/vm/gc/shenandoah/shenandoahHeap.inline.hpp --- a/src/share/vm/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/share/vm/gc/shenandoah/shenandoahHeap.inline.hpp @@ -63,7 +63,7 @@ * been marked by this thread. Returns false if the object has already been marked, * or if a competing thread succeeded in marking this object. */ -inline bool ShenandoahHeap::mark_next(oop obj) const { +inline bool ShenandoahHeap::mark(oop obj) { #ifdef ASSERT if (! oopDesc::unsafe_equals(obj, oopDesc::bs()->read_barrier(obj))) { tty->print_cr("heap region containing obj:"); @@ -76,22 +76,17 @@ #endif assert(oopDesc::unsafe_equals(obj, oopDesc::bs()->read_barrier(obj)), "only mark forwarded copy of objects"); - return mark_next_no_checks(obj); + return mark_no_checks(obj); } -inline bool ShenandoahHeap::mark_next_no_checks(oop obj) const { +inline bool ShenandoahHeap::mark_no_checks(oop obj) { HeapWord* addr = (HeapWord*) obj; - return (! allocated_after_next_mark_start(addr)) && _next_mark_bit_map->parMark(addr); + return !allocated_after_mark_start(addr) && _mark_bit_map.parMark(addr); } -inline bool ShenandoahHeap::is_marked_next(oop obj) const { +inline bool ShenandoahHeap::is_marked(oop obj) const { HeapWord* addr = (HeapWord*) obj; - return allocated_after_next_mark_start(addr) || _next_mark_bit_map->isMarked(addr); -} - -inline bool ShenandoahHeap::is_marked_complete(oop obj) const { - HeapWord* addr = (HeapWord*) obj; - return allocated_after_complete_mark_start(addr) || _complete_mark_bit_map->isMarked(addr); + return allocated_after_mark_start(addr) || _mark_bit_map.isMarked(addr); } inline bool ShenandoahHeap::need_update_refs() const { @@ -428,7 +423,7 @@ // assert(free_regions()->contains(heap_region_containing(entry)), "expect to-space object"); return true; } else if (concurrent_mark_in_progress()) { - return ! is_marked_next(oop(entry)); + return ! is_marked(oop(entry)); } else { return false; } @@ -472,16 +467,9 @@ return (address) &(ShenandoahHeap::heap()->_evacuation_in_progress); } -inline bool ShenandoahHeap::allocated_after_next_mark_start(HeapWord* addr) const { +inline bool ShenandoahHeap::allocated_after_mark_start(HeapWord* addr) const { uintx index = ((uintx) addr) >> ShenandoahHeapRegion::region_size_bytes_shift(); - HeapWord* top_at_mark_start = _next_top_at_mark_starts[index]; - bool alloc_after_mark_start = addr >= top_at_mark_start; - return alloc_after_mark_start; -} - -inline bool ShenandoahHeap::allocated_after_complete_mark_start(HeapWord* addr) const { - uintx index = ((uintx) addr) >> ShenandoahHeapRegion::region_size_bytes_shift(); - HeapWord* top_at_mark_start = _complete_top_at_mark_starts[index]; + HeapWord* top_at_mark_start = _top_at_mark_starts[index]; bool alloc_after_mark_start = addr >= top_at_mark_start; return alloc_after_mark_start; } @@ -501,16 +489,17 @@ assert(BrooksPointer::word_offset() < 0, "skip_delta calculation below assumes the forwarding ptr is before obj"); assert(! region->is_humongous_continuation(), "no humongous continuation regions here"); + assert(is_bitmap_valid(), "only try this with complete marking bitmap"); - MarkBitMap* mark_bit_map = _complete_mark_bit_map; - HeapWord* top_at_mark_start = complete_top_at_mark_start(region->bottom()); + MarkBitMap mark_bit_map = _mark_bit_map; + HeapWord* tams = top_at_mark_start(region->bottom()); size_t skip_bitmap_delta = BrooksPointer::word_size() + 1; size_t skip_objsize_delta = BrooksPointer::word_size() /* + actual obj.size() below */; HeapWord* start = region->bottom() + BrooksPointer::word_size(); - HeapWord* end = MIN2(top_at_mark_start + BrooksPointer::word_size(), region->end()); - HeapWord* addr = mark_bit_map->getNextMarkedWordAddress(start, end); + HeapWord* end = MIN2(tams + BrooksPointer::word_size(), region->end()); + HeapWord* addr = mark_bit_map.getNextMarkedWordAddress(start, end); intx dist = ShenandoahMarkScanPrefetch; if (dist > 0) { @@ -537,9 +526,9 @@ Prefetch::read(addr, BrooksPointer::byte_offset()); oop obj = oop(addr); slots[avail++] = obj; - if (addr < top_at_mark_start) { + if (addr < tams) { addr += skip_bitmap_delta; - addr = mark_bit_map->getNextMarkedWordAddress(addr, end); + addr = mark_bit_map.getNextMarkedWordAddress(addr, end); } else { // cannot trust mark bitmap anymore, finish the current stride, // and switch to accurate traversal @@ -549,7 +538,7 @@ } for (int c = 0; c < avail; c++) { - do_marked_object(mark_bit_map, cl, slots[c]); + do_marked_object(cl, slots[c]); } } while (avail > 0 && !aborting); @@ -557,29 +546,28 @@ while (addr < limit) { oop obj = oop(addr); int size = obj->size(); - do_marked_object(mark_bit_map, cl, obj); + do_marked_object(cl, obj); addr += size + skip_objsize_delta; } } else { while (addr < limit) { oop obj = oop(addr); int size = obj->size(); - do_marked_object(mark_bit_map, cl, obj); + do_marked_object(cl, obj); addr += size + skip_objsize_delta; - if (addr < top_at_mark_start) { - addr = mark_bit_map->getNextMarkedWordAddress(addr, end); + if (addr < tams) { + addr = mark_bit_map.getNextMarkedWordAddress(addr, end); } } } } template -inline void ShenandoahHeap::do_marked_object(MarkBitMap* bitmap, T* cl, oop obj) { +inline void ShenandoahHeap::do_marked_object(T* cl, oop obj) { assert(!oopDesc::is_null(obj), "sanity"); assert(oopDesc::is_oop(obj), "sanity"); assert(is_in(obj), "sanity"); - assert(bitmap == _complete_mark_bit_map, "only iterate completed mark bitmap"); - assert(is_marked_complete(obj), "object expected to be marked"); + assert(is_marked(obj), "object expected to be marked"); cl->do_object(obj); } diff --git a/src/share/vm/gc/shenandoah/shenandoahHeapRegion.cpp b/src/share/vm/gc/shenandoah/shenandoahHeapRegion.cpp --- a/src/share/vm/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahHeapRegion.cpp @@ -387,30 +387,8 @@ } st->print("|CP " SIZE_FORMAT_W(3), _critical_pins); - st->print_cr("|TAMS " PTR_FORMAT ", " PTR_FORMAT "|", - p2i(ShenandoahHeap::heap()->complete_top_at_mark_start(_bottom)), - p2i(ShenandoahHeap::heap()->next_top_at_mark_start(_bottom))); -} - -void ShenandoahHeapRegion::object_iterate_interruptible(ObjectClosure* blk, bool allow_cancel) { - HeapWord* p = bottom() + BrooksPointer::word_size(); - while (p < top() && !(allow_cancel && _heap->cancelled_concgc())) { - blk->do_object(oop(p)); - p += oop(p)->size() + BrooksPointer::word_size(); - } -} - -HeapWord* ShenandoahHeapRegion::object_iterate_careful(ObjectClosureCareful* blk) { - HeapWord * limit = concurrent_iteration_safe_limit(); - assert(limit <= top(), "sanity check"); - for (HeapWord* p = bottom() + BrooksPointer::word_size(); p < limit;) { - size_t size = blk->do_object_careful(oop(p)); - if (size == 0) { - return p; // failed at p - } - p += size + BrooksPointer::word_size(); - } - return NULL; // all done + st->print_cr("|TAMS " PTR_FORMAT "|", + p2i(ShenandoahHeap::heap()->top_at_mark_start(_bottom))); } void ShenandoahHeapRegion::oop_iterate(ExtendedOopClosure* blk) { @@ -480,11 +458,11 @@ _first_alloc_seq_num = 0; _last_alloc_seq_num = 0; - // Reset C-TAMS pointer to ensure size-based iteration, everything + // Reset TAMS pointer to ensure size-based iteration, everything // in that regions is going to be new objects. - _heap->set_complete_top_at_mark_start(bottom(), bottom()); - // We can only safely reset the C-TAMS pointer if the bitmap is clear for that region. - assert(_heap->is_complete_bitmap_clear_range(bottom(), end()), "must be clear"); + _heap->set_top_at_mark_start(bottom(), bottom()); + // We can only safely reset the TAMS pointer if the bitmap is clear for that region. + assert(_heap->is_bitmap_clear_range(bottom(), end()), "must be clear"); make_empty_committed(); } diff --git a/src/share/vm/gc/shenandoah/shenandoahHeapRegion.hpp b/src/share/vm/gc/shenandoah/shenandoahHeapRegion.hpp --- a/src/share/vm/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/share/vm/gc/shenandoah/shenandoahHeapRegion.hpp @@ -328,9 +328,6 @@ void recycle(); void recycle_no_matrix(); - void object_iterate_interruptible(ObjectClosure* blk, bool allow_cancel); - - HeapWord* object_iterate_careful(ObjectClosureCareful* cl); void oop_iterate(ExtendedOopClosure* cl); HeapWord* block_start_const(const void* p) const; diff --git a/src/share/vm/gc/shenandoah/shenandoahMarkCompact.cpp b/src/share/vm/gc/shenandoah/shenandoahMarkCompact.cpp --- a/src/share/vm/gc/shenandoah/shenandoahMarkCompact.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahMarkCompact.cpp @@ -78,7 +78,7 @@ ShenandoahClearRegionStatusClosure() : _heap(ShenandoahHeap::heap()) {} bool heap_region_do(ShenandoahHeapRegion *r) { - _heap->set_next_top_at_mark_start(r->bottom(), r->top()); + _heap->set_top_at_mark_start(r->bottom(), r->top()); r->clear_live_data(); r->set_concurrent_iteration_safe_limit(r->top()); return false; @@ -147,8 +147,8 @@ assert(!heap->is_evacuation_in_progress(), "sanity"); // c. Reset the bitmaps for new marking - heap->reset_next_mark_bitmap(heap->workers()); - assert(heap->is_next_bitmap_clear(), "sanity"); + heap->reset_mark_bitmap(heap->workers()); + assert(heap->is_bitmap_clear(), "sanity"); // d. Abandon reference discovery and clear all discovered references. ReferenceProcessor* rp = heap->ref_processor(); @@ -185,7 +185,7 @@ GCTraceTime(Info, gc) time("Pause Full", _gc_timer, gc_cause, true); if (UseTLAB) { - heap->ensure_parsability(true); + heap->make_tlabs_parsable(true); } CodeCache::gc_prologue(); @@ -295,8 +295,6 @@ cm->mark_roots(ShenandoahPhaseTimings::full_gc_roots); cm->shared_finish_mark_from_roots(/* full_gc = */ true); - _heap->swap_mark_bitmaps(); - if (UseShenandoahMatrix && PrintShenandoahMatrix) { LogTarget(Info, gc) lt; LogStream ls(lt); @@ -318,6 +316,7 @@ // objects. _heap->verify(VerifyOption_G1UseMarkWord); } + _heap->set_bitmap_valid(true); } class ShenandoahMCReclaimHumongousRegionClosure : public ShenandoahHeapRegionClosure { @@ -330,7 +329,7 @@ bool heap_region_do(ShenandoahHeapRegion* r) { if (r->is_humongous_start()) { oop humongous_obj = oop(r->bottom() + BrooksPointer::word_size()); - if (! _heap->is_marked_complete(humongous_obj)) { + if (! _heap->is_marked(humongous_obj)) { _heap->trash_humongous_region_at(r); } } @@ -371,8 +370,8 @@ } void do_object(oop p) { assert(_from_region != NULL, "must set before work"); - assert(_heap->is_marked_complete(p), "must be marked"); - assert(! _heap->allocated_after_complete_mark_start((HeapWord*) p), "must be truly marked"); + assert(_heap->is_marked(p), "must be marked"); + assert(! _heap->allocated_after_mark_start((HeapWord*) p), "must be truly marked"); size_t obj_size = p->size() + BrooksPointer::word_size(); if (_compact_point + obj_size > _to_region->end()) { // Object doesn't fit. Pick next to-region and start compacting there. @@ -497,7 +496,7 @@ T o = oopDesc::load_heap_oop(p); if (! oopDesc::is_null(o)) { oop obj = oopDesc::decode_heap_oop_not_null(o); - assert(_heap->is_marked_complete(obj), "must be marked"); + assert(_heap->is_marked(obj), "must be marked"); oop forw = oop(BrooksPointer::get_raw(obj)); oopDesc::encode_store_heap_oop(p, forw); if (UseShenandoahMatrix) { @@ -536,7 +535,7 @@ _heap(ShenandoahHeap::heap()) { } void do_object(oop p) { - assert(_heap->is_marked_complete(p), "must be marked"); + assert(_heap->is_marked(p), "must be marked"); HeapWord* forw = BrooksPointer::get_raw(p); _cl.set_new_obj_offset(pointer_delta((HeapWord*) p, forw)); p->oop_iterate(&_cl); @@ -627,7 +626,7 @@ _str_dedup(ShenandoahStringDedup::is_enabled()), _worker_id(worker_id) { } void do_object(oop p) { - assert(_heap->is_marked_complete(p), "must be marked"); + assert(_heap->is_marked(p), "must be marked"); size_t size = (size_t)p->size(); HeapWord* compact_to = BrooksPointer::get_raw(p); HeapWord* compact_from = (HeapWord*) p; @@ -682,10 +681,10 @@ } bool heap_region_do(ShenandoahHeapRegion* r) { - // Need to reset the complete-top-at-mark-start pointer here because - // the complete marking bitmap is no longer valid. This ensures + // Need to reset the top-at-mark-start pointer here because + // the marking bitmap is no longer valid. This ensures // size-based iteration in marked_object_iterate(). - _heap->set_complete_top_at_mark_start(r->bottom(), r->bottom()); + _heap->set_top_at_mark_start(r->bottom(), r->bottom()); size_t live = r->used(); @@ -730,9 +729,9 @@ ShenandoahCompactObjectsTask compact_task(copy_queues); heap->workers()->run_task(&compact_task); - // Reset complete bitmap. We're about to reset the complete-top-at-mark-start pointer + // Reset marking bitmap. We're about to reset the top-at-mark-start pointer // and must ensure the bitmap is in sync. - heap->reset_complete_mark_bitmap(heap->workers()); + heap->reset_mark_bitmap(heap->workers()); { ShenandoahHeapLocker lock(heap->lock()); @@ -745,9 +744,6 @@ heap->collection_set()->clear(); heap->clear_cancelled_concgc(); - // Also clear the next bitmap in preparation for next marking. - heap->reset_next_mark_bitmap(heap->workers()); - for (uint i = 0; i < heap->max_workers(); i++) { delete copy_queues[i]; } diff --git a/src/share/vm/gc/shenandoah/shenandoahPartialGC.cpp b/src/share/vm/gc/shenandoah/shenandoahPartialGC.cpp --- a/src/share/vm/gc/shenandoah/shenandoahPartialGC.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahPartialGC.cpp @@ -217,9 +217,9 @@ ShenandoahHeapRegion* r = cset->claim_next(); while (r != NULL) { HeapWord* bottom = r->bottom(); - HeapWord* top = _heap->complete_top_at_mark_start(r->bottom()); + HeapWord* top = _heap->top_at_mark_start(r->bottom()); if (top > bottom) { - _heap->complete_mark_bit_map()->clear_range_large(MemRegion(bottom, top)); + _heap->mark_bit_map()->clear_range_large(MemRegion(bottom, top)); } r = cset->claim_next(); } @@ -254,7 +254,7 @@ _heap->collection_set()->clear(); assert(_heap->collection_set()->count() == 0, "collection set not clear"); - _heap->ensure_parsability(true); + _heap->make_tlabs_parsable(true); ShenandoahConnectionMatrix* matrix = _heap->connection_matrix(); diff --git a/src/share/vm/gc/shenandoah/shenandoahPrinter.cpp b/src/share/vm/gc/shenandoah/shenandoahPrinter.cpp --- a/src/share/vm/gc/shenandoah/shenandoahPrinter.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahPrinter.cpp @@ -46,7 +46,7 @@ tty->print_cr("%s "INT32_FORMAT" ("PTR_FORMAT")-> "PTR_FORMAT" (marked: %s) (%s "PTR_FORMAT")", _prefix, _index, p2i(p), p2i(o), - BOOL_TO_STR(ShenandoahHeap::heap()->is_marked_complete(o)), + BOOL_TO_STR(ShenandoahHeap::heap()->is_marked(o)), o->klass()->internal_name(), p2i(o->klass())); } else { tty->print_cr("%s "INT32_FORMAT" ("PTR_FORMAT" dirty -> "PTR_FORMAT" (not in heap, possibly corrupted or dirty)", @@ -79,7 +79,7 @@ if (ShenandoahHeap::heap()->is_in(p)) { tty->print_cr("%s object "PTR_FORMAT" (marked: %s) (%s "PTR_FORMAT") refers to:", _prefix, p2i(p), - BOOL_TO_STR(ShenandoahHeap::heap()->is_marked_complete(p)), + BOOL_TO_STR(ShenandoahHeap::heap()->is_marked(p)), p->klass()->internal_name(), p2i(p->klass())); ShenandoahPrintAllRefsOopClosure cl(_prefix); p->oop_iterate(&cl); @@ -91,7 +91,7 @@ tty->print_cr("printing all references in the heap"); tty->print_cr("root references:"); - _heap->ensure_parsability(false); + _heap->make_tlabs_parsable(false); ShenandoahPrintAllRefsOopClosure cl(prefix); _heap->roots_iterate(&cl); diff --git a/src/share/vm/gc/shenandoah/shenandoahStringDedup.cpp b/src/share/vm/gc/shenandoah/shenandoahStringDedup.cpp --- a/src/share/vm/gc/shenandoah/shenandoahStringDedup.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahStringDedup.cpp @@ -49,7 +49,7 @@ bool do_object_b(oop obj) { assert(!oopDesc::is_null(obj), "null"); - return _heap->is_marked_complete(obj); + return _heap->is_marked(obj); } }; diff --git a/src/share/vm/gc/shenandoah/shenandoahVerifier.cpp b/src/share/vm/gc/shenandoah/shenandoahVerifier.cpp --- a/src/share/vm/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/share/vm/gc/shenandoah/shenandoahVerifier.cpp @@ -59,11 +59,9 @@ r->print_on(&ss); msg.append(" " PTR_FORMAT " - klass " PTR_FORMAT " %s\n", p2i(obj), p2i(obj->klass()), obj->klass()->external_name()); - msg.append(" %3s allocated after complete mark start\n", _heap->allocated_after_complete_mark_start((HeapWord *) obj) ? "" : "not"); - msg.append(" %3s allocated after next mark start\n", _heap->allocated_after_next_mark_start((HeapWord *) obj) ? "" : "not"); - msg.append(" %3s marked complete\n", _heap->is_marked_complete(obj) ? "" : "not"); - msg.append(" %3s marked next\n", _heap->is_marked_next(obj) ? "" : "not"); - msg.append(" %3s in collection set\n", _heap->in_collection_set(obj) ? "" : "not"); + msg.append(" %3s allocated after mark start\n", _heap->allocated_after_mark_start((HeapWord *) obj) ? "" : "not"); + msg.append(" %3s marked\n", _heap->is_marked(obj) ? "" : "not"); + msg.append(" %3s in collection set\n", _heap->in_collection_set(obj) ? "" : "not"); msg.append(" region: %s", ss.as_string()); } @@ -306,13 +304,9 @@ case ShenandoahVerifier::_verify_marked_disable: // skip break; - case ShenandoahVerifier::_verify_marked_next: - verify(_safe_all, obj, _heap->is_marked_next(obj), - "Must be marked in next bitmap"); - break; - case ShenandoahVerifier::_verify_marked_complete: - verify(_safe_all, obj, _heap->is_marked_complete(obj), - "Must be marked in complete bitmap"); + case ShenandoahVerifier::_verify_marked: + verify(_safe_all, obj, _heap->is_marked(obj), + "Must be marked"); break; default: assert(false, "Unhandled mark verification"); @@ -488,11 +482,11 @@ verify(r, r->capacity() == ShenandoahHeapRegion::region_size_bytes(), "Capacity should match region size"); - verify(r, r->bottom() <= _heap->complete_top_at_mark_start(r->bottom()), + verify(r, r->bottom() <= _heap->top_at_mark_start(r->bottom()), "Region top should not be less than bottom"); - verify(r, _heap->complete_top_at_mark_start(r->bottom()) <= r->top(), - "Complete TAMS should not be larger than top"); + verify(r, _heap->top_at_mark_start(r->bottom()) <= r->top(), + "TAMS should not be larger than top"); verify(r, r->get_live_data_bytes() <= r->capacity(), "Live data cannot be larger than capacity"); @@ -639,7 +633,7 @@ virtual void work_humongous(ShenandoahHeapRegion *r, ShenandoahVerifierStack& stack, ShenandoahVerifyOopClosure& cl) { size_t processed = 0; HeapWord* obj = r->bottom() + BrooksPointer::word_size(); - if (_heap->is_marked_complete((oop)obj)) { + if (_heap->is_marked((oop)obj)) { verify_and_follow(obj, stack, cl, &processed); } Atomic::add(processed, &_processed); @@ -647,8 +641,8 @@ virtual void work_regular(ShenandoahHeapRegion *r, ShenandoahVerifierStack &stack, ShenandoahVerifyOopClosure &cl) { size_t processed = 0; - MarkBitMap* mark_bit_map = _heap->complete_mark_bit_map(); - HeapWord* tams = _heap->complete_top_at_mark_start(r->bottom()); + MarkBitMap* mark_bit_map = _heap->mark_bit_map(); + HeapWord* tams = _heap->top_at_mark_start(r->bottom()); // Bitmaps, before TAMS if (tams > r->bottom()) { @@ -736,7 +730,7 @@ } OrderAccess::fence(); - _heap->ensure_parsability(false); + _heap->make_tlabs_parsable(false); // Allocate temporary bitmap for storing marking wavefront: MemRegion mr = MemRegion(_verification_bit_map->startWord(), _verification_bit_map->endWord()); @@ -768,18 +762,18 @@ // version size_t count_marked = 0; - if (ShenandoahVerifyLevel >= 4 && marked == _verify_marked_complete) { + if (ShenandoahVerifyLevel >= 4 && marked == _verify_marked) { ShenandoahVerifierMarkedRegionTask task(_heap->regions(), _verification_bit_map, ld, label, options); _heap->workers()->run_task(&task); count_marked = task.processed(); } else { - guarantee(ShenandoahVerifyLevel < 4 || marked == _verify_marked_next || marked == _verify_marked_disable, "Should be"); + guarantee(ShenandoahVerifyLevel < 4 || marked == _verify_marked_disable, "Should be"); } // Step 4. Verify accumulated liveness data, if needed. Only reliable if verification level includes // marked objects. - if (ShenandoahVerifyLevel >= 4 && marked == _verify_marked_complete && liveness == _verify_liveness_complete) { + if (ShenandoahVerifyLevel >= 4 && marked == _verify_marked && liveness == _verify_liveness_complete) { ShenandoahHeapRegionSet* set = _heap->regions(); for (size_t i = 0; i < _heap->num_regions(); i++) { ShenandoahHeapRegion* r = set->get(i); @@ -853,7 +847,7 @@ verify_at_safepoint( "After Mark", _verify_forwarded_none, // no forwarded references - _verify_marked_complete, // bitmaps as precise as we can get + _verify_marked, // bitmaps as precise as we can get _verify_matrix_disable, // matrix might be foobared _verify_cset_none, // no references to cset anymore _verify_liveness_complete, // liveness data must be complete here @@ -867,7 +861,7 @@ verify_at_safepoint( "Before Evacuation", _verify_forwarded_none, // no forwarded references - _verify_marked_complete, // walk over marked objects too + _verify_marked, // walk over marked objects too _verify_matrix_disable, // skip, verified after mark _verify_cset_disable, // skip, verified after mark _verify_liveness_disable, // skip, verified after mark @@ -879,7 +873,7 @@ verify_at_safepoint( "After Evacuation", _verify_forwarded_allow, // objects are still forwarded - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_marked, // bitmaps might be stale, but alloc-after-mark should be well _verify_matrix_disable, // matrix is inconsistent here _verify_cset_forwarded, // all cset refs are fully forwarded _verify_liveness_disable, // no reliable liveness data anymore @@ -891,7 +885,7 @@ verify_at_safepoint( "Before Updating References", _verify_forwarded_allow, // forwarded references allowed - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_marked, // bitmaps might be stale, but alloc-after-mark should be well _verify_matrix_disable, // matrix is inconsistent here _verify_cset_forwarded, // all cset refs are fully forwarded _verify_liveness_disable, // no reliable liveness data anymore @@ -903,7 +897,7 @@ verify_at_safepoint( "After Updating References", _verify_forwarded_none, // no forwarded references - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_marked, // bitmaps might be stale, but alloc-after-mark should be well _verify_matrix_conservative, // matrix is conservatively consistent _verify_cset_none, // no cset references, all updated _verify_liveness_disable, // no reliable liveness data anymore @@ -915,7 +909,7 @@ verify_at_safepoint( "Before Partial GC", _verify_forwarded_none, // cannot have forwarded objects - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_marked, // bitmaps might be stale, but alloc-after-mark should be well _verify_matrix_conservative, // matrix is conservatively consistent _verify_cset_none, // no cset references before partial _verify_liveness_disable, // no reliable liveness data anymore @@ -927,7 +921,7 @@ verify_at_safepoint( "After Partial GC", _verify_forwarded_none, // cannot have forwarded objects - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_marked, // bitmaps might be stale, but alloc-after-mark should be well _verify_matrix_conservative, // matrix is conservatively consistent _verify_cset_none, // no cset references left after partial _verify_liveness_disable, // no reliable liveness data anymore @@ -951,7 +945,7 @@ verify_at_safepoint( "After Full GC", _verify_forwarded_none, // all objects are non-forwarded - _verify_marked_complete, // all objects are marked in complete bitmap + _verify_marked, // all objects are marked _verify_matrix_conservative, // matrix is conservatively consistent _verify_cset_none, // no cset references _verify_liveness_disable, // no reliable liveness data anymore diff --git a/src/share/vm/gc/shenandoah/shenandoahVerifier.hpp b/src/share/vm/gc/shenandoah/shenandoahVerifier.hpp --- a/src/share/vm/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/share/vm/gc/shenandoah/shenandoahVerifier.hpp @@ -89,11 +89,9 @@ // Disable marked objects verification. _verify_marked_disable, - // Objects should be marked in "next" bitmap. - _verify_marked_next, + // Objects should be marked + _verify_marked, - // Objects should be marked in "complete" bitmap. - _verify_marked_complete, } VerifyMarked; typedef enum { diff --git a/src/share/vm/gc/shenandoah/vm_operations_shenandoah.cpp b/src/share/vm/gc/shenandoah/vm_operations_shenandoah.cpp --- a/src/share/vm/gc/shenandoah/vm_operations_shenandoah.cpp +++ b/src/share/vm/gc/shenandoah/vm_operations_shenandoah.cpp @@ -48,7 +48,9 @@ ShenandoahWorkerScope scope(workers, nworkers); - assert(sh->is_next_bitmap_clear(), "need clear marking bitmap"); + assert(sh->is_bitmap_clear(), "need clear marking bitmap"); + + sh->set_bitmap_valid(false); sh->start_concurrent_marking(); } @@ -86,6 +88,7 @@ if (! sh->cancelled_concgc()) { GCTraceTime(Info, gc) time("Pause Final Mark", sh->gc_timer(), GCCause::_no_gc, true); sh->concurrentMark()->finish_mark_from_roots(); + sh->set_bitmap_valid(true); sh->stop_concurrent_marking(); { diff --git a/test/gc/shenandoah/jvmti/TestHeapDump.java b/test/gc/shenandoah/jvmti/TestHeapDump.java new file mode 100644 --- /dev/null +++ b/test/gc/shenandoah/jvmti/TestHeapDump.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. + * + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test TestHeapDump + * @summary Tests JVMTI heap dumps + * @compile TestHeapDump.java + * @run main/othervm/native -agentlib:TestHeapDump -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive -XX:-UseCompressedOops TestHeapDump + */ + +public class TestHeapDump { + + private static final int NUM_ITER = 10000; + + static { + try { + System.loadLibrary("TestHeapDump"); + } catch (UnsatisfiedLinkError ule) { + System.err.println("Could not load TestHeapDump library"); + System.err.println("java.library.path: " + + System.getProperty("java.library.path")); + throw ule; + } + } + + native static int heapdump(); + + public static void main(String args[]) { + for (int i = 0; i < NUM_ITER; i++) { + int numObjs = heapdump(); + if (numObjs != 0) throw new RuntimeException(); + } + } +} diff --git a/test/gc/shenandoah/jvmti/libTestHeapDump.c b/test/gc/shenandoah/jvmti/libTestHeapDump.c new file mode 100644 --- /dev/null +++ b/test/gc/shenandoah/jvmti/libTestHeapDump.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017 Red Hat, Inc. and/or its affiliates. + * + * 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. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include +#include +#include "jvmti.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef JNI_ENV_ARG + +#ifdef __cplusplus +#define JNI_ENV_ARG(x, y) y +#define JNI_ENV_PTR(x) x +#else +#define JNI_ENV_ARG(x,y) x, y +#define JNI_ENV_PTR(x) (*x) +#endif + +#endif + +#define TranslateError(err) "JVMTI error" + +#define PASSED 0 +#define FAILED 2 + +static const char *EXC_CNAME = "java/lang/Exception"; + +static jvmtiEnv *jvmti = NULL; +static jint result = PASSED; + +static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); + +JNIEXPORT +jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT +jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT +jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { + return JNI_VERSION_1_8; +} + +static +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), + JVMTI_VERSION_9); + if (res != JNI_OK || jvmti == NULL) { + printf(" Error: wrong result of a valid call to GetEnv!\n"); + return JNI_ERR; + } + + jvmtiCapabilities capabilities; + (void)memset(&capabilities, 0, sizeof(capabilities)); + capabilities.can_tag_objects = 1; + capabilities.can_generate_garbage_collection_events = 1; + (*jvmti)->AddCapabilities(jvmti, &capabilities); + + return JNI_OK; +} + +static +void throw_exc(JNIEnv *env, char *msg) { + jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); + jint rt = JNI_OK; + + if (exc_class == NULL) { + printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME); + return; + } + rt = JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); + if (rt == JNI_ERR) { + printf("throw_exc: Error in JNI ThrowNew(env, %s)\n", msg); + } +} + +static jint JNICALL heap_iter_callback(jlong class_tag, + jlong size, + jlong* tag_ptr, + jint length, + void* user_data) { + (*((jint*)(user_data)))++; + return JVMTI_VISIT_OBJECTS; +} + +JNIEXPORT jint JNICALL +Java_TestHeapDump_heapdump(JNIEnv *env, jclass cls) { + if (jvmti == NULL) { + throw_exc(env, "JVMTI client was not properly loaded!\n"); + return 0; + } + + jvmtiHeapCallbacks callbacks; + (void)memset(&callbacks, 0, sizeof(callbacks)); + callbacks.heap_iteration_callback = &heap_iter_callback; + jint totalCount = 0; + (*jvmti)->IterateThroughHeap(jvmti, 0, NULL, &callbacks, (const void *)&totalCount); + return totalCount; +} + +#ifdef __cplusplus +} +#endif