# HG changeset patch # User sjohanss # Date 1510655603 -3600 # Node ID 5caa1d5f74c1ac6fa3aced63e9865a19a6f8798f # Parent 3cfab71d6c81e5d232e2fe08f02eaefe9446a741 8186571: Implementation: JEP 307: Parallel Full GC for G1 Summary: Improve G1 worst-case latencies by making the full GC parallel. Reviewed-by: tschatzl, sangheki, ehelin diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/collectionSetChooser.cpp --- a/src/hotspot/share/gc/g1/collectionSetChooser.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/collectionSetChooser.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -247,8 +247,8 @@ _g1(G1CollectedHeap::heap()), _hrclaimer(n_workers) {} void work(uint worker_id) { - ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size); - _g1->heap_region_par_iterate(&parKnownGarbageCl, worker_id, &_hrclaimer); + ParKnownGarbageHRClosure par_known_garbage_cl(_hrSorted, _chunk_size); + _g1->heap_region_par_iterate_from_worker_offset(&par_known_garbage_cl, &_hrclaimer, worker_id); } }; diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1CardLiveData.cpp --- a/src/hotspot/share/gc/g1/g1CardLiveData.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1CardLiveData.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -314,7 +314,7 @@ G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1ConcurrentMark* cm = g1h->concurrent_mark(); G1CreateLiveDataClosure cl(g1h, cm, cm->next_mark_bitmap(), _live_data); - g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); + g1h->heap_region_par_iterate_from_worker_offset(&cl, &_hr_claimer, worker_id); } }; @@ -381,7 +381,7 @@ void work(uint worker_id) { G1FinalizeCardLiveDataClosure cl(G1CollectedHeap::heap(), _bitmap, _live_data); - G1CollectedHeap::heap()->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); + G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&cl, &_hr_claimer, worker_id); } }; @@ -560,7 +560,7 @@ _mark_bitmap, _act_live_data, &_exp_live_data); - _g1h->heap_region_par_iterate(&cl, worker_id, &_hr_claimer); + _g1h->heap_region_par_iterate_from_worker_offset(&cl, &_hr_claimer, worker_id); Atomic::add(cl.failures(), &_failures); } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1CollectedHeap.cpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -38,6 +38,7 @@ #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1ConcurrentRefineThread.hpp" #include "gc/g1/g1EvacStats.inline.hpp" +#include "gc/g1/g1FullCollector.hpp" #include "gc/g1/g1FullGCScope.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapSizingPolicy.hpp" @@ -48,10 +49,9 @@ #include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1RegionToSpaceMapper.hpp" -#include "gc/g1/g1RemSet.inline.hpp" +#include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RootProcessor.hpp" -#include "gc/g1/g1SerialFullCollector.hpp" #include "gc/g1/g1StringDedup.hpp" #include "gc/g1/g1YCTypes.hpp" #include "gc/g1/g1YoungRemSetSamplingThread.hpp" @@ -143,6 +143,12 @@ reset_from_card_cache(start_idx, num_regions); } + +HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, + MemRegion mr) { + return new HeapRegion(hrs_index, bot(), mr); +} + // Private methods. HeapRegion* @@ -1155,7 +1161,6 @@ void G1CollectedHeap::abort_refinement() { if (_hot_card_cache->use_cache()) { - _hot_card_cache->reset_card_counts(); _hot_card_cache->reset_hot_cache(); } @@ -1199,6 +1204,10 @@ } void G1CollectedHeap::print_heap_after_full_collection(G1HeapTransition* heap_transition) { + // Post collection logging. + // We should do this after we potentially resize the heap so + // that all the COMMIT / UNCOMMIT events are generated before + // the compaction events. print_hrm_post_compaction(); heap_transition->print(); print_heap_after_gc(); @@ -1221,23 +1230,18 @@ gc_prologue(true); prepare_heap_for_full_collection(); - G1SerialFullCollector serial(scope, ref_processor_stw()); - serial.prepare_collection(); - serial.collect(); - serial.complete_collection(); + G1FullCollector collector(scope, ref_processor_stw(), concurrent_mark()->next_mark_bitmap(), workers()->active_workers()); + collector.prepare_collection(); + collector.collect(); + collector.complete_collection(); prepare_heap_for_mutators(); g1_policy()->record_full_collection_end(); gc_epilogue(true); - // Post collection verification. verify_after_full_collection(); - // Post collection logging. - // We should do this after we potentially resize the heap so - // that all the COMMIT / UNCOMMIT events are generated before - // the compaction events. print_heap_after_full_collection(scope->heap_transition()); } @@ -1269,10 +1273,10 @@ } void G1CollectedHeap::resize_if_necessary_after_full_collection() { - // Include bytes that will be pre-allocated to support collections, as "used". - const size_t used_after_gc = used(); + // Capacity, free and used after the GC counted as full regions to + // include the waste in the following calculations. const size_t capacity_after_gc = capacity(); - const size_t free_after_gc = capacity_after_gc - used_after_gc; + const size_t used_after_gc = capacity_after_gc - unused_committed_regions_in_bytes(); // This is enforced in arguments.cpp. assert(MinHeapFreeRatio <= MaxHeapFreeRatio, @@ -1326,8 +1330,9 @@ size_t expand_bytes = minimum_desired_capacity - capacity_after_gc; log_debug(gc, ergo, heap)("Attempt heap expansion (capacity lower than min desired capacity after Full GC). " - "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)", - capacity_after_gc, used_after_gc, minimum_desired_capacity, MinHeapFreeRatio); + "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B live: " SIZE_FORMAT "B " + "min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)", + capacity_after_gc, used_after_gc, used(), minimum_desired_capacity, MinHeapFreeRatio); expand(expand_bytes, _workers); @@ -1337,8 +1342,9 @@ size_t shrink_bytes = capacity_after_gc - maximum_desired_capacity; log_debug(gc, ergo, heap)("Attempt heap shrinking (capacity higher than max desired capacity after Full GC). " - "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B min_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)", - capacity_after_gc, used_after_gc, minimum_desired_capacity, MinHeapFreeRatio); + "Capacity: " SIZE_FORMAT "B occupancy: " SIZE_FORMAT "B live: " SIZE_FORMAT "B " + "maximum_desired_capacity: " SIZE_FORMAT "B (" UINTX_FORMAT " %%)", + capacity_after_gc, used_after_gc, used(), maximum_desired_capacity, MaxHeapFreeRatio); shrink(shrink_bytes); } @@ -1959,6 +1965,10 @@ return _hrm.length() * HeapRegion::GrainBytes; } +size_t G1CollectedHeap::unused_committed_regions_in_bytes() const { + return _hrm.total_free_bytes(); +} + void G1CollectedHeap::reset_gc_time_stamps(HeapRegion* hr) { hr->reset_gc_time_stamp(); } @@ -2262,10 +2272,15 @@ _hrm.iterate(cl); } -void G1CollectedHeap::heap_region_par_iterate(HeapRegionClosure* cl, - uint worker_id, - HeapRegionClaimer *hrclaimer) const { - _hrm.par_iterate(cl, worker_id, hrclaimer); +void G1CollectedHeap::heap_region_par_iterate_from_worker_offset(HeapRegionClosure* cl, + HeapRegionClaimer *hrclaimer, + uint worker_id) const { + _hrm.par_iterate(cl, hrclaimer, hrclaimer->offset_for_worker(worker_id)); +} + +void G1CollectedHeap::heap_region_par_iterate_from_start(HeapRegionClosure* cl, + HeapRegionClaimer *hrclaimer) const { + _hrm.par_iterate(cl, hrclaimer, 0); } void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) { @@ -2276,14 +2291,6 @@ _collection_set.iterate_from(cl, worker_id, workers()->active_workers()); } -HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const { - HeapRegion* result = _hrm.next_region_in_heap(from); - while (result != NULL && result->is_pinned()) { - result = _hrm.next_region_in_heap(result); - } - return result; -} - HeapWord* G1CollectedHeap::block_start(const void* addr) const { HeapRegion* hr = heap_region_containing(addr); return hr->block_start(addr); @@ -2375,7 +2382,7 @@ switch (vo) { case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj, hr); case VerifyOption_G1UseNextMarking: return is_obj_ill(obj, hr); - case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked() && !hr->is_archive(); + case VerifyOption_G1UseFullMarking: return is_obj_dead_full(obj, hr); default: ShouldNotReachHere(); } return false; // keep some compilers happy @@ -2386,10 +2393,7 @@ switch (vo) { case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj); case VerifyOption_G1UseNextMarking: return is_obj_ill(obj); - case VerifyOption_G1UseMarkWord: { - HeapRegion* hr = _hrm.addr_to_region((HeapWord*)obj); - return !obj->is_gc_marked() && !hr->is_archive(); - } + case VerifyOption_G1UseFullMarking: return is_obj_dead_full(obj); default: ShouldNotReachHere(); } return false; // keep some compilers happy diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1CollectedHeap.hpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -1046,6 +1046,7 @@ // The Concurrent Marking reference processor... ReferenceProcessor* ref_processor_cm() const { return _ref_processor_cm; } + size_t unused_committed_regions_in_bytes() const; virtual size_t capacity() const; virtual size_t used() const; // This should be called when we're not holding the heap lock. The @@ -1181,6 +1182,8 @@ return barrier_set_cast(barrier_set()); } + G1HotCardCache* g1_hot_card_cache() const { return _hot_card_cache; } + // Iteration functions. // Iterate over all objects, calling "cl.do_object" on each. @@ -1207,15 +1210,18 @@ inline HeapWord* bottom_addr_for_region(uint index) const; - // Iterate over the heap regions in parallel. Assumes that this will be called - // in parallel by a number of worker threads with distinct worker ids - // in the range passed to the HeapRegionClaimer. Applies "blk->doHeapRegion" - // to each of the regions, by attempting to claim the region using the - // HeapRegionClaimer and, if successful, applying the closure to the claimed - // region. - void heap_region_par_iterate(HeapRegionClosure* cl, - uint worker_id, - HeapRegionClaimer* hrclaimer) const; + // Two functions to iterate over the heap regions in parallel. Threads + // compete using the HeapRegionClaimer to claim the regions before + // applying the closure on them. + // The _from_worker_offset version uses the HeapRegionClaimer and + // the worker id to calculate a start offset to prevent all workers to + // start from the point. + void heap_region_par_iterate_from_worker_offset(HeapRegionClosure* cl, + HeapRegionClaimer* hrclaimer, + uint worker_id) const; + + void heap_region_par_iterate_from_start(HeapRegionClosure* cl, + HeapRegionClaimer* hrclaimer) const; // Iterate over the regions (if any) in the current collection set. void collection_set_iterate(HeapRegionClosure* blk); @@ -1226,8 +1232,6 @@ // collection set regions. void collection_set_iterate_from(HeapRegionClosure *blk, uint worker_id); - HeapRegion* next_compaction_region(const HeapRegion* from) const; - // Returns the HeapRegion that contains addr. addr must not be NULL. template inline HeapRegion* heap_region_containing(const T addr) const; @@ -1391,6 +1395,9 @@ inline bool is_obj_ill(const oop obj) const; + inline bool is_obj_dead_full(const oop obj, const HeapRegion* hr) const; + inline bool is_obj_dead_full(const oop obj) const; + G1ConcurrentMark* concurrent_mark() const { return _cm; } // Refinement @@ -1435,9 +1442,9 @@ // Perform verification. - // vo == UsePrevMarking -> use "prev" marking information, + // vo == UsePrevMarking -> use "prev" marking information, // vo == UseNextMarking -> use "next" marking information - // vo == UseMarkWord -> use the mark word in the object header + // vo == UseFullMarking -> use "next" marking bitmap but no TAMS // // NOTE: Only the "prev" marking information is guaranteed to be // consistent most of the time, so most calls to this should use @@ -1446,7 +1453,7 @@ // vo == UseNextMarking, which is to verify the "next" marking // information at the end of remark. // Currently there is only one place where this is called with - // vo == UseMarkWord, which is to verify the marking during a + // vo == UseFullMarking, which is to verify the marking during a // full GC. void verify(VerifyOption vo); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -264,6 +264,14 @@ return is_obj_ill(obj, heap_region_containing(obj)); } +inline bool G1CollectedHeap::is_obj_dead_full(const oop obj, const HeapRegion* hr) const { + return !isMarkedNext(obj) && !hr->is_archive(); +} + +inline bool G1CollectedHeap::is_obj_dead_full(const oop obj) const { + return is_obj_dead_full(obj, heap_region_containing(obj)); +} + inline void G1CollectedHeap::set_humongous_reclaim_candidate(uint region, bool value) { assert(_hrm.at(region)->is_starts_humongous(), "Must start a humongous object"); _humongous_reclaim_candidates.set_candidate(region, value); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1CollectedHeap_ext.cpp --- a/src/hotspot/share/gc/g1/g1CollectedHeap_ext.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1CollectedHeap_ext.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,11 +37,6 @@ return false; } -HeapRegion* G1CollectedHeap::new_heap_region(uint hrs_index, - MemRegion mr) { - return new HeapRegion(hrs_index, bot(), mr); -} - G1Policy* G1CollectedHeap::create_g1_policy(STWGCTimer* gc_timer) { return new G1DefaultPolicy(gc_timer); } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1ConcurrentMark.cpp --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -634,7 +634,7 @@ void work(uint worker_id) { SuspendibleThreadSetJoiner sts_join(_suspendible); - G1CollectedHeap::heap()->heap_region_par_iterate(&_cl, worker_id, &_hr_claimer); + G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&_cl, &_hr_claimer, worker_id); } bool is_complete() { @@ -1140,7 +1140,7 @@ HRRSCleanupTask hrrs_cleanup_task; G1NoteEndOfConcMarkClosure g1_note_end(_g1h, &local_cleanup_list, &hrrs_cleanup_task); - _g1h->heap_region_par_iterate(&g1_note_end, worker_id, &_hrclaimer); + _g1h->heap_region_par_iterate_from_worker_offset(&g1_note_end, &_hrclaimer, worker_id); assert(g1_note_end.complete(), "Shouldn't have yielded!"); // Now update the lists diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.cpp --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/heapRegion.hpp" #include "memory/virtualspace.hpp" void G1CMBitMap::print_on_error(outputStream* st, const char* prefix) const { @@ -65,3 +66,10 @@ _bm.at_put_range(addr_to_offset(intersection.start()), addr_to_offset(intersection.end()), false); } + +void G1CMBitMap::clear_region(HeapRegion* region) { + if (!region->is_empty()) { + MemRegion mr(region->bottom(), region->top()); + clear_range(mr); + } +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.hpp --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -28,6 +28,7 @@ #include "gc/g1/g1RegionToSpaceMapper.hpp" #include "memory/allocation.hpp" #include "memory/memRegion.hpp" +#include "oops/oopsHierarchy.hpp" #include "utilities/bitMap.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" @@ -35,6 +36,7 @@ class G1CMBitMap; class G1CMTask; class G1ConcurrentMark; +class HeapRegion; // Closure for iteration over bitmaps class G1CMBitMapClosure VALUE_OBJ_CLASS_SPEC { @@ -96,6 +98,7 @@ void initialize(MemRegion heap, G1RegionToSpaceMapper* storage); // Read marks + bool is_marked(oop obj) const; bool is_marked(HeapWord* addr) const { assert(_covered.contains(addr), "Address " PTR_FORMAT " is outside underlying space from " PTR_FORMAT " to " PTR_FORMAT, @@ -120,9 +123,12 @@ // Write marks. inline void mark(HeapWord* addr); inline void clear(HeapWord* addr); + inline void clear(oop obj); inline bool par_mark(HeapWord* addr); + inline bool par_mark(oop obj); void clear_range(MemRegion mr); + void clear_region(HeapRegion* hr); }; #endif // SHARE_VM_GC_G1_G1CONCURRENTMARKBITMAP_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.inline.hpp --- a/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.inline.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1ConcurrentMarkBitMap.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -83,4 +83,16 @@ return _bm.par_set_bit(addr_to_offset(addr)); } +inline bool G1CMBitMap::par_mark(oop obj) { + return par_mark((HeapWord*) obj); +} + +inline bool G1CMBitMap::is_marked(oop obj) const{ + return is_marked((HeapWord*) obj); +} + +inline void G1CMBitMap::clear(oop obj) { + clear((HeapWord*) obj); +} + #endif // SHARE_VM_GC_G1_G1CONCURRENTMARKBITMAP_INLINE_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullCollector.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "code/codeCache.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1CollectorPolicy.hpp" +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCAdjustTask.hpp" +#include "gc/g1/g1FullGCCompactTask.hpp" +#include "gc/g1/g1FullGCMarker.inline.hpp" +#include "gc/g1/g1FullGCMarkTask.hpp" +#include "gc/g1/g1FullGCPrepareTask.hpp" +#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp" +#include "gc/g1/g1FullGCScope.hpp" +#include "gc/g1/g1OopClosures.hpp" +#include "gc/g1/g1StringDedup.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/preservedMarks.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "gc/shared/weakProcessor.hpp" +#include "logging/log.hpp" +#include "runtime/biasedLocking.hpp" +#include "utilities/debug.hpp" + +static void clear_and_activate_derived_pointers() { +#if COMPILER2_OR_JVMCI + DerivedPointerTable::clear(); +#endif +} + +static void deactivate_derived_pointers() { +#if COMPILER2_OR_JVMCI + DerivedPointerTable::set_active(false); +#endif +} + +static void update_derived_pointers() { +#if COMPILER2_OR_JVMCI + DerivedPointerTable::update_pointers(); +#endif +} + +G1FullCollector::G1FullCollector(G1FullGCScope* scope, + ReferenceProcessor* reference_processor, + G1CMBitMap* bitmap, + uint workers) : + _scope(scope), + _num_workers(workers), + _mark_bitmap(bitmap), + _oop_queue_set(_num_workers), + _array_queue_set(_num_workers), + _preserved_marks_set(true), + _reference_processor(reference_processor), + _serial_compaction_point(), + _is_alive(_mark_bitmap), + _is_alive_mutator(_reference_processor, &_is_alive) { + assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); + + _preserved_marks_set.init(_num_workers); + _markers = NEW_C_HEAP_ARRAY(G1FullGCMarker*, _num_workers, mtGC); + _compaction_points = NEW_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _num_workers, mtGC); + for (uint i = 0; i < _num_workers; i++) { + _markers[i] = new G1FullGCMarker(i, _preserved_marks_set.get(i), mark_bitmap()); + _compaction_points[i] = new G1FullGCCompactionPoint(); + _oop_queue_set.register_queue(i, marker(i)->oop_stack()); + _array_queue_set.register_queue(i, marker(i)->objarray_stack()); + } +} + +G1FullCollector::~G1FullCollector() { + for (uint i = 0; i < _num_workers; i++) { + delete _markers[i]; + delete _compaction_points[i]; + } + FREE_C_HEAP_ARRAY(G1FullGCMarker*, _markers); + FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points); +} + +void G1FullCollector::prepare_collection() { + _reference_processor->enable_discovery(); + _reference_processor->setup_policy(scope()->should_clear_soft_refs()); + + // When collecting the permanent generation Method*s may be moving, + // so we either have to flush all bcp data or convert it into bci. + CodeCache::gc_prologue(); + + // We should save the marks of the currently locked biased monitors. + // The marking doesn't preserve the marks of biased objects. + BiasedLocking::preserve_marks(); + + // Clear and activate derived pointer collection. + clear_and_activate_derived_pointers(); +} + +void G1FullCollector::collect() { + phase1_mark_live_objects(); + verify_after_marking(); + + // Don't add any more derived pointers during later phases + deactivate_derived_pointers(); + + phase2_prepare_compaction(); + + phase3_adjust_pointers(); + + phase4_do_compaction(); +} + +void G1FullCollector::complete_collection() { + // Restore all marks. + restore_marks(); + + // When the pointers have been adjusted and moved, we can + // update the derived pointer table. + update_derived_pointers(); + + BiasedLocking::restore_marks(); + CodeCache::gc_epilogue(); + JvmtiExport::gc_epilogue(); +} + +void G1FullCollector::phase1_mark_live_objects() { + // Recursively traverse all live objects and mark them. + GCTraceTime(Info, gc, phases) info("Phase 1: Mark live objects", scope()->timer()); + + // Do the actual marking. + G1FullGCMarkTask marking_task(this); + run_task(&marking_task); + + // Process references discovered during marking. + G1FullGCReferenceProcessingExecutor reference_processing(this); + reference_processing.execute(scope()->timer(), scope()->tracer()); + + // Weak oops cleanup. + { + GCTraceTime(Debug, gc, phases) trace("Phase 1: Weak Processing", scope()->timer()); + WeakProcessor::weak_oops_do(&_is_alive, &do_nothing_cl); + } + + // Class unloading and cleanup. + if (ClassUnloading) { + GCTraceTime(Debug, gc, phases) debug("Phase 1: Class Unloading and Cleanup", scope()->timer()); + // Unload classes and purge the SystemDictionary. + bool purged_class = SystemDictionary::do_unloading(&_is_alive, scope()->timer()); + G1CollectedHeap::heap()->complete_cleaning(&_is_alive, purged_class); + } else { + GCTraceTime(Debug, gc, phases) debug("Phase 1: String and Symbol Tables Cleanup", scope()->timer()); + // If no class unloading just clean out strings and symbols. + G1CollectedHeap::heap()->partial_cleaning(&_is_alive, true, true, G1StringDedup::is_enabled()); + } + + scope()->tracer()->report_object_count_after_gc(&_is_alive); +} + +void G1FullCollector::prepare_compaction_common() { + G1FullGCPrepareTask task(this); + run_task(&task); + + // To avoid OOM when there is memory left. + if (!task.has_freed_regions()) { + task.prepare_serial_compaction(); + } +} + +void G1FullCollector::phase2_prepare_compaction() { + GCTraceTime(Info, gc, phases) info("Phase 2: Prepare for compaction", scope()->timer()); + prepare_compaction_ext(); // Will call prepare_compaction_common() above. +} + +void G1FullCollector::phase3_adjust_pointers() { + // Adjust the pointers to reflect the new locations + GCTraceTime(Info, gc, phases) info("Phase 3: Adjust pointers and remembered sets", scope()->timer()); + + G1FullGCAdjustTask task(this); + run_task(&task); +} + +void G1FullCollector::phase4_do_compaction() { + // Compact the heap using the compaction queues created in phase 2. + GCTraceTime(Info, gc, phases) info("Phase 4: Compact heap", scope()->timer()); + G1FullGCCompactTask task(this); + run_task(&task); + + // Serial compact to avoid OOM when very few free regions. + if (serial_compaction_point()->has_regions()) { + task.serial_compaction(); + } +} + +void G1FullCollector::restore_marks() { + SharedRestorePreservedMarksTaskExecutor task_executor(G1CollectedHeap::heap()->workers()); + _preserved_marks_set.restore(&task_executor); + _preserved_marks_set.reclaim(); +} + +void G1FullCollector::run_task(AbstractGangTask* task) { + G1CollectedHeap::heap()->workers()->run_task(task, _num_workers); +} + +void G1FullCollector::verify_after_marking() { + if (!VerifyDuringGC) { + //Only do verification if VerifyDuringGC is set. + return; + } + + HandleMark hm; // handle scope +#if COMPILER2_OR_JVMCI + DerivedPointerTableDeactivate dpt_deact; +#endif + G1CollectedHeap::heap()->prepare_for_verify(); + // Note: we can verify only the heap here. When an object is + // marked, the previous value of the mark word (including + // identity hash values, ages, etc) is preserved, and the mark + // word is set to markOop::marked_value - effectively removing + // any hash values from the mark word. These hash values are + // used when verifying the dictionaries and so removing them + // from the mark word can make verification of the dictionaries + // fail. At the end of the GC, the original mark word values + // (including hash values) are restored to the appropriate + // objects. + GCTraceTime(Info, gc, verify)("During GC (full)"); + G1CollectedHeap::heap()->verify(VerifyOption_G1UseFullMarking); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullCollector.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLCOLLECTOR_HPP +#define SHARE_GC_G1_G1FULLCOLLECTOR_HPP + +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCMarker.hpp" +#include "gc/g1/g1FullGCOopClosures.hpp" +#include "gc/shared/preservedMarks.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "gc/shared/taskqueue.hpp" +#include "memory/allocation.hpp" + +class AbstractGangTask; +class G1CMBitMap; +class G1FullGCMarker; +class G1FullGCScope; +class G1FullGCCompactionPoint; +class ReferenceProcessor; + +// The G1FullCollector holds data associated with the current Full GC. +class G1FullCollector : StackObj { + G1FullGCScope* _scope; + uint _num_workers; + G1FullGCMarker** _markers; + G1FullGCCompactionPoint** _compaction_points; + G1CMBitMap* _mark_bitmap; + OopQueueSet _oop_queue_set; + ObjArrayTaskQueueSet _array_queue_set; + PreservedMarksSet _preserved_marks_set; + ReferenceProcessor* _reference_processor; + G1FullGCCompactionPoint _serial_compaction_point; + + G1IsAliveClosure _is_alive; + ReferenceProcessorIsAliveMutator _is_alive_mutator; + +public: + G1FullCollector(G1FullGCScope* scope, + ReferenceProcessor* reference_processor, + G1CMBitMap* mark_bitmap, + uint workers); + ~G1FullCollector(); + + void prepare_collection(); + void collect(); + void complete_collection(); + + G1FullGCScope* scope() { return _scope; } + uint workers() { return _num_workers; } + G1FullGCMarker* marker(uint id) { return _markers[id]; } + G1FullGCCompactionPoint* compaction_point(uint id) { return _compaction_points[id]; } + G1CMBitMap* mark_bitmap() { return _mark_bitmap; } + OopQueueSet* oop_queue_set() { return &_oop_queue_set; } + ObjArrayTaskQueueSet* array_queue_set() { return &_array_queue_set; } + PreservedMarksSet* preserved_mark_set() { return &_preserved_marks_set; } + ReferenceProcessor* reference_processor() { return _reference_processor; } + G1FullGCCompactionPoint* serial_compaction_point() { return &_serial_compaction_point; } + +private: + void phase1_mark_live_objects(); + void phase2_prepare_compaction(); + void phase3_adjust_pointers(); + void phase4_do_compaction(); + + void restore_marks(); + void verify_after_marking(); + + void run_task(AbstractGangTask* task); + + // Prepare compaction extension support. + void prepare_compaction_ext(); + void prepare_compaction_common(); +}; + + +#endif // SHARE_GC_G1_G1FULLCOLLECTOR_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullCollector_ext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullCollector_ext.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1FullCollector.hpp" + +void G1FullCollector::prepare_compaction_ext() { + prepare_compaction_common(); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCAdjustTask.hpp" +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCMarker.hpp" +#include "gc/g1/g1FullGCOopClosures.inline.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "logging/log.hpp" +#include "utilities/ticks.inline.hpp" + +class G1AdjustLiveClosure : public StackObj { + G1AdjustAndRebuildClosure* _adjust_closure; +public: + G1AdjustLiveClosure(G1AdjustAndRebuildClosure* cl) : + _adjust_closure(cl) { } + + size_t apply(oop object) { + _adjust_closure->update_compaction_delta(object); + return object->oop_iterate_size(_adjust_closure); + } +}; + +class G1AdjustRegionClosure : public HeapRegionClosure { + G1CMBitMap* _bitmap; + uint _worker_id; + public: + G1AdjustRegionClosure(G1CMBitMap* bitmap, uint worker_id) : + _bitmap(bitmap), + _worker_id(worker_id) { } + + bool doHeapRegion(HeapRegion* r) { + G1AdjustAndRebuildClosure cl(_worker_id); + if (r->is_humongous()) { + oop obj = oop(r->humongous_start_region()->bottom()); + cl.update_compaction_delta(obj); + obj->oop_iterate(&cl, MemRegion(r->bottom(), r->top())); + } else if (r->is_open_archive()) { + // Only adjust the open archive regions, the closed ones + // never change. + G1AdjustLiveClosure adjust(&cl); + r->apply_to_marked_objects(_bitmap, &adjust); + // Open archive regions will not be compacted and the marking information is + // no longer needed. Clear it here to avoid having to do it later. + _bitmap->clear_region(r); + } else { + G1AdjustLiveClosure adjust(&cl); + r->apply_to_marked_objects(_bitmap, &adjust); + } + return false; + } +}; + +G1FullGCAdjustTask::G1FullGCAdjustTask(G1FullCollector* collector) : + G1FullGCTask("G1 Adjust and Rebuild", collector), + _root_processor(G1CollectedHeap::heap(), collector->workers()), + _hrclaimer(collector->workers()), + _adjust(), + _adjust_string_dedup(NULL, &_adjust, G1StringDedup::is_enabled()) { + // Need cleared claim bits for the roots processing + ClassLoaderDataGraph::clear_claimed_marks(); +} + +void G1FullGCAdjustTask::work(uint worker_id) { + Ticks start = Ticks::now(); + ResourceMark rm; + + // Adjust preserved marks first since they are not balanced. + G1FullGCMarker* marker = collector()->marker(worker_id); + marker->preserved_stack()->adjust_during_full_gc(); + + // Adjust the weak_roots. + CLDToOopClosure adjust_cld(&_adjust); + CodeBlobToOopClosure adjust_code(&_adjust, CodeBlobToOopClosure::FixRelocations); + _root_processor.process_full_gc_weak_roots(&_adjust); + + // Needs to be last, process_all_roots calls all_tasks_completed(...). + _root_processor.process_all_roots( + &_adjust, + &adjust_cld, + &adjust_code); + + // Adjust string dedup if enabled. + if (G1StringDedup::is_enabled()) { + G1StringDedup::parallel_unlink(&_adjust_string_dedup, worker_id); + } + + // Now adjust pointers region by region + G1AdjustRegionClosure blk(collector()->mark_bitmap(), worker_id); + G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&blk, &_hrclaimer, worker_id); + log_task("Adjust and Rebuild task", worker_id, start); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCADJUSTTASK_HPP +#define SHARE_GC_G1_G1FULLGCADJUSTTASK_HPP + +#include "gc/g1/g1FullGCOopClosures.hpp" +#include "gc/g1/g1FullGCTask.hpp" +#include "gc/g1/g1RootProcessor.hpp" +#include "gc/g1/g1StringDedup.hpp" +#include "gc/g1/heapRegionManager.hpp" +#include "utilities/ticks.hpp" + +class G1CollectedHeap; + +class G1FullGCAdjustTask : public G1FullGCTask { + G1RootProcessor _root_processor; + HeapRegionClaimer _hrclaimer; + G1AdjustClosure _adjust; + G1StringDedupUnlinkOrOopsDoClosure _adjust_string_dedup; + +public: + G1FullGCAdjustTask(G1FullCollector* collector); + void work(uint worker_id); +}; + +#endif // SHARE_GC_G1_G1FULLGCADJUSTTASK_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCCompactTask.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "logging/log.hpp" +#include "utilities/ticks.inline.hpp" + +class G1ResetHumongousClosure : public HeapRegionClosure { + G1CMBitMap* _bitmap; + +public: + G1ResetHumongousClosure(G1CMBitMap* bitmap) : + _bitmap(bitmap) { } + + bool doHeapRegion(HeapRegion* current) { + if (current->is_humongous()) { + if (current->is_starts_humongous()) { + oop obj = oop(current->bottom()); + if (_bitmap->is_marked(obj)) { + // Clear bitmap and fix mark word. + _bitmap->clear(obj); + obj->init_mark(); + } else { + assert(current->is_empty(), "Should have been cleared in phase 2."); + } + } + current->reset_during_compaction(); + } + return false; + } +}; + +size_t G1FullGCCompactTask::G1CompactRegionClosure::apply(oop obj) { + size_t size = obj->size(); + HeapWord* destination = (HeapWord*)obj->forwardee(); + if (destination == NULL) { + // Object not moving + return size; + } + + // copy object and reinit its mark + HeapWord* obj_addr = (HeapWord*) obj; + assert(obj_addr != destination, "everything in this pass should be moving"); + Copy::aligned_conjoint_words(obj_addr, destination, size); + oop(destination)->init_mark(); + assert(oop(destination)->klass() != NULL, "should have a class"); + + return size; +} + +void G1FullGCCompactTask::compact_region(HeapRegion* hr) { + assert(!hr->is_humongous(), "Should be no humongous regions in compaction queue"); + G1CompactRegionClosure compact(collector()->mark_bitmap()); + hr->apply_to_marked_objects(collector()->mark_bitmap(), &compact); + // Once all objects have been moved the liveness information + // needs be cleared. + collector()->mark_bitmap()->clear_region(hr); + hr->complete_compaction(); +} + +void G1FullGCCompactTask::work(uint worker_id) { + Ticks start = Ticks::now(); + GrowableArray* compaction_queue = collector()->compaction_point(worker_id)->regions(); + for (GrowableArrayIterator it = compaction_queue->begin(); + it != compaction_queue->end(); + ++it) { + compact_region(*it); + } + + G1ResetHumongousClosure hc(collector()->mark_bitmap()); + G1CollectedHeap::heap()->heap_region_par_iterate_from_worker_offset(&hc, &_claimer, worker_id); + log_task("Compaction task", worker_id, start); +} + +void G1FullGCCompactTask::serial_compaction() { + GCTraceTime(Debug, gc, phases) tm("Phase 4: Serial Compaction", collector()->scope()->timer()); + GrowableArray* compaction_queue = collector()->serial_compaction_point()->regions(); + for (GrowableArrayIterator it = compaction_queue->begin(); + it != compaction_queue->end(); + ++it) { + compact_region(*it); + } +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCCompactTask.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCCOMPACTTASK_HPP +#define SHARE_GC_G1_G1FULLGCCOMPACTTASK_HPP + +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCScope.hpp" +#include "gc/g1/g1FullGCTask.hpp" +#include "gc/g1/g1StringDedup.hpp" +#include "gc/g1/heapRegionManager.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "utilities/ticks.hpp" + +class G1CollectedHeap; +class G1CMBitMap; + +class G1FullGCCompactTask : public G1FullGCTask { +protected: + HeapRegionClaimer _claimer; + +private: + void compact_region(HeapRegion* hr); + +public: + G1FullGCCompactTask(G1FullCollector* collector) : + G1FullGCTask("G1 Compact Task", collector), + _claimer(collector->workers()) { } + void work(uint worker_id); + void serial_compaction(); + + class G1CompactRegionClosure : public StackObj { + G1CMBitMap* _bitmap; + + public: + G1CompactRegionClosure(G1CMBitMap* bitmap) : _bitmap(bitmap) { } + size_t apply(oop object); + }; +}; + +#endif // SHARE_GC_G1_G1FULLGCCOMPACTTASK_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/heapRegion.hpp" +#include "oops/oop.inline.hpp" +#include "utilities/debug.hpp" + +G1FullGCCompactionPoint::G1FullGCCompactionPoint() : + _current_region(NULL), + _threshold(NULL), + _compaction_top(NULL) { + _compaction_regions = new (ResourceObj::C_HEAP, mtGC) GrowableArray(32, true, mtGC); + _compaction_region_iterator = _compaction_regions->begin(); +} + +G1FullGCCompactionPoint::~G1FullGCCompactionPoint() { + delete _compaction_regions; +} + +void G1FullGCCompactionPoint::update() { + if (is_initialized()) { + _current_region->set_compaction_top(_compaction_top); + } +} + +void G1FullGCCompactionPoint::initialize_values(bool init_threshold) { + _compaction_top = _current_region->compaction_top(); + if (init_threshold) { + _threshold = _current_region->initialize_threshold(); + } +} + +bool G1FullGCCompactionPoint::has_regions() { + return !_compaction_regions->is_empty(); +} + +bool G1FullGCCompactionPoint::is_initialized() { + return _current_region != NULL; +} + +void G1FullGCCompactionPoint::initialize(HeapRegion* hr, bool init_threshold) { + _current_region = hr; + initialize_values(init_threshold); +} + +HeapRegion* G1FullGCCompactionPoint::current_region() { + return *_compaction_region_iterator; +} + +HeapRegion* G1FullGCCompactionPoint::next_region() { + HeapRegion* next = *(++_compaction_region_iterator); + assert(next != NULL, "Must return valid region"); + return next; +} + +GrowableArray* G1FullGCCompactionPoint::regions() { + return _compaction_regions; +} + +bool G1FullGCCompactionPoint::object_will_fit(size_t size) { + size_t space_left = pointer_delta(_current_region->end(), _compaction_top); + return size <= space_left; +} + +void G1FullGCCompactionPoint::switch_region() { + // Save compaction top in the region. + _current_region->set_compaction_top(_compaction_top); + // Get the next region and re-initialize the values. + _current_region = next_region(); + initialize_values(true); +} + +void G1FullGCCompactionPoint::forward(oop object, size_t size) { + assert(_current_region != NULL, "Must have been initialized"); + + // Ensure the object fit in the current region. + while (!object_will_fit(size)) { + switch_region(); + } + + // Store a forwarding pointer if the object should be moved. + if ((HeapWord*)object != _compaction_top) { + object->forward_to(oop(_compaction_top)); + } else { + if (object->forwardee() != NULL) { + // Object should not move but mark-word is used so it looks like the + // object is forwarded. Need to clear the mark and it's no problem + // since it will be restored by preserved marks. There is an exception + // with BiasedLocking, in this case forwardee() will return NULL + // even if the mark-word is used. This is no problem since + // forwardee() will return NULL in the compaction phase as well. + object->init_mark(); + } else { + // Make sure object has the correct mark-word set or that it will be + // fixed when restoring the preserved marks. + assert(object->mark() == markOopDesc::prototype_for_object(object) || // Correct mark + object->mark()->must_be_preserved(object) || // Will be restored by PreservedMarksSet + (UseBiasedLocking && object->has_bias_pattern()), // Will be restored by BiasedLocking + "should have correct prototype obj: " PTR_FORMAT " mark: " PTR_FORMAT " prototype: " PTR_FORMAT, + p2i(object), p2i(object->mark()), p2i(markOopDesc::prototype_for_object(object))); + } + assert(object->forwardee() == NULL, "should be forwarded to NULL"); + } + + // Update compaction values. + _compaction_top += size; + if (_compaction_top > _threshold) { + _threshold = _current_region->cross_threshold(_compaction_top - size, _compaction_top); + } +} + +void G1FullGCCompactionPoint::add(HeapRegion* hr) { + _compaction_regions->append(hr); +} + +void G1FullGCCompactionPoint::merge(G1FullGCCompactionPoint* other) { + _compaction_regions->appendAll(other->regions()); +} + +HeapRegion* G1FullGCCompactionPoint::remove_last() { + return _compaction_regions->pop(); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCCompactionPoint.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCCOMPACTIONPOINT_HPP +#define SHARE_GC_G1_G1FULLGCCOMPACTIONPOINT_HPP + +#include "memory/allocation.hpp" +#include "utilities/growableArray.hpp" + +class HeapRegion; + +class G1FullGCCompactionPoint : public CHeapObj { + HeapRegion* _current_region; + HeapWord* _threshold; + HeapWord* _compaction_top; + GrowableArray* _compaction_regions; + GrowableArrayIterator _compaction_region_iterator; + + bool object_will_fit(size_t size); + void initialize_values(bool init_threshold); + void switch_region(); + HeapRegion* next_region(); + +public: + G1FullGCCompactionPoint(); + ~G1FullGCCompactionPoint(); + + bool has_regions(); + bool is_initialized(); + void initialize(HeapRegion* hr, bool init_threshold); + void update(); + void forward(oop object, size_t size); + void add(HeapRegion* hr); + void merge(G1FullGCCompactionPoint* other); + + HeapRegion* remove_last(); + HeapRegion* current_region(); + + GrowableArray* regions(); +}; + +#endif // SHARE_GC_G1_G1FULLGCCOMPACTIONPOINT_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCMarker.hpp" +#include "gc/g1/g1FullGCMarkTask.hpp" +#include "gc/g1/g1FullGCOopClosures.inline.hpp" +#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/referenceProcessor.hpp" + +G1FullGCMarkTask::G1FullGCMarkTask(G1FullCollector* collector) : + G1FullGCTask("G1 Parallel Marking Task", collector), + _root_processor(G1CollectedHeap::heap(), collector->workers()), + _terminator(collector->workers(), collector->array_queue_set()) { + // Need cleared claim bits for the roots processing + ClassLoaderDataGraph::clear_claimed_marks(); +} + +void G1FullGCMarkTask::work(uint worker_id) { + Ticks start = Ticks::now(); + ResourceMark rm; + G1FullGCMarker* marker = collector()->marker(worker_id); + MarkingCodeBlobClosure code_closure(marker->mark_closure(), !CodeBlobToOopClosure::FixRelocations); + + if (ClassUnloading) { + _root_processor.process_strong_roots( + marker->mark_closure(), + marker->cld_closure(), + &code_closure); + } else { + _root_processor.process_all_roots_no_string_table( + marker->mark_closure(), + marker->cld_closure(), + &code_closure); + } + + // Mark stack is populated, now process and drain it. + marker->complete_marking(collector()->oop_queue_set(), collector()->array_queue_set(), &_terminator); + + // This is the point where the entire marking should have completed. + assert(marker->oop_stack()->is_empty(), "Marking should have completed"); + assert(marker->objarray_stack()->is_empty(), "Array marking should have completed"); + log_task("Marking task", worker_id, start); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCMarkTask.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCMarkTask.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCMARKTASK_HPP +#define SHARE_GC_G1_G1FULLGCMARKTASK_HPP + +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCScope.hpp" +#include "gc/g1/g1FullGCTask.hpp" +#include "gc/g1/g1RootProcessor.hpp" +#include "gc/g1/g1StringDedup.hpp" +#include "gc/g1/heapRegionManager.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "utilities/ticks.hpp" + +class G1FullGCMarkTask : public G1FullGCTask { + G1RootProcessor _root_processor; + ParallelTaskTerminator _terminator; + +public: + G1FullGCMarkTask(G1FullCollector* collector); + void work(uint worker_id); +}; + +#endif // SHARE_GC_G1_G1FULLGCMARKTASK_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCMarker.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1FullGCMarker.inline.hpp" + +G1FullGCMarker::G1FullGCMarker(uint worker_id, PreservedMarks* preserved_stack, G1CMBitMap* bitmap) : + _worker_id(worker_id), + _mark_closure(worker_id, this, G1CollectedHeap::heap()->ref_processor_stw()), + _verify_closure(VerifyOption_G1UseFullMarking), + _cld_closure(mark_closure()), + _stack_closure(this), + _preserved_stack(preserved_stack), + _bitmap(bitmap) { + _oop_stack.initialize(); + _objarray_stack.initialize(); +} + +G1FullGCMarker::~G1FullGCMarker() { + assert(is_empty(), "Must be empty at this point"); +} + +void G1FullGCMarker::complete_marking(OopQueueSet* oop_stacks, + ObjArrayTaskQueueSet* array_stacks, + ParallelTaskTerminator* terminator) { + int hash_seed = 17; + do { + drain_stack(); + ObjArrayTask steal_array; + if (array_stacks->steal(_worker_id, &hash_seed, steal_array)) { + follow_array_chunk(objArrayOop(steal_array.obj()), steal_array.index()); + } else { + oop steal_oop; + if (oop_stacks->steal(_worker_id, &hash_seed, steal_oop)) { + follow_object(steal_oop); + } + } + } while (!is_empty() || !terminator->offer_termination()); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCMarker.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCMARKER_HPP +#define SHARE_GC_G1_G1FULLGCMARKER_HPP + +#include "gc/g1/g1FullGCOopClosures.hpp" +#include "gc/shared/preservedMarks.hpp" +#include "gc/shared/taskqueue.hpp" +#include "memory/iterator.hpp" +#include "oops/markOop.hpp" +#include "oops/oop.hpp" +#include "runtime/timer.hpp" +#include "utilities/chunkedList.hpp" +#include "utilities/growableArray.hpp" +#include "utilities/stack.hpp" + +typedef OverflowTaskQueue OopQueue; +typedef OverflowTaskQueue ObjArrayTaskQueue; + +typedef GenericTaskQueueSet OopQueueSet; +typedef GenericTaskQueueSet ObjArrayTaskQueueSet; + +class G1CMBitMap; + +class G1FullGCMarker : public CHeapObj { +private: + uint _worker_id; + // Backing mark bitmap + G1CMBitMap* _bitmap; + + // Mark stack + OopQueue _oop_stack; + ObjArrayTaskQueue _objarray_stack; + PreservedMarks* _preserved_stack; + + // Marking closures + G1MarkAndPushClosure _mark_closure; + G1VerifyOopClosure _verify_closure; + G1FollowStackClosure _stack_closure; + CLDToOopClosure _cld_closure; + + inline bool is_empty(); + inline bool pop_object(oop& obj); + inline bool pop_objarray(ObjArrayTask& array); + inline void push_objarray(oop obj, size_t index); + inline bool mark_object(oop obj); + + // Marking helpers + inline void follow_object(oop obj); + inline void follow_array(objArrayOop array); + inline void follow_array_chunk(objArrayOop array, int index); +public: + G1FullGCMarker(uint worker_id, PreservedMarks* preserved_stack, G1CMBitMap* bitmap); + ~G1FullGCMarker(); + + // Stack getters + OopQueue* oop_stack() { return &_oop_stack; } + ObjArrayTaskQueue* objarray_stack() { return &_objarray_stack; } + PreservedMarks* preserved_stack() { return _preserved_stack; } + + // Marking entry points + template inline void mark_and_push(T* p); + inline void follow_klass(Klass* k); + inline void follow_cld(ClassLoaderData* cld); + + inline void drain_stack(); + void complete_marking(OopQueueSet* oop_stacks, + ObjArrayTaskQueueSet* array_stacks, + ParallelTaskTerminator* terminator); + + // Closure getters + CLDToOopClosure* cld_closure() { return &_cld_closure; } + G1MarkAndPushClosure* mark_closure() { return &_mark_closure; } + G1FollowStackClosure* stack_closure() { return &_stack_closure; } +}; + +#endif // SHARE_GC_G1_G1FULLGCMARKER_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCMarker.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_VM_GC_G1_G1MARKSTACK_INLINE_HPP +#define SHARE_VM_GC_G1_G1MARKSTACK_INLINE_HPP + +#include "gc/g1/g1Allocator.inline.hpp" +#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/g1FullGCMarker.hpp" +#include "gc/g1/g1StringDedup.hpp" +#include "gc/g1/g1StringDedupQueue.hpp" +#include "gc/shared/preservedMarks.inline.hpp" +#include "utilities/debug.hpp" + +inline bool G1FullGCMarker::mark_object(oop obj) { + // Not marking closed archive objects. + if (G1ArchiveAllocator::is_closed_archive_object(obj)) { + return false; + } + + // Try to mark. + if (!_bitmap->par_mark(obj)) { + // Lost mark race. + return false; + } + + // Marked by us, preserve if needed. + markOop mark = obj->mark(); + if (mark->must_be_preserved(obj) && + !G1ArchiveAllocator::is_open_archive_object(obj)) { + preserved_stack()->push(obj, mark); + } + + // Check if deduplicatable string. + if (G1StringDedup::is_enabled()) { + G1StringDedup::enqueue_from_mark(obj, _worker_id); + } + return true; +} + +template inline void G1FullGCMarker::mark_and_push(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + if (mark_object(obj)) { + _oop_stack.push(obj); + assert(_bitmap->is_marked(obj), "Must be marked now - map self"); + } else { + assert(_bitmap->is_marked(obj) || G1ArchiveAllocator::is_closed_archive_object(obj), + "Must be marked by other or closed archive object"); + } + } +} + +inline bool G1FullGCMarker::is_empty() { + return _oop_stack.is_empty() && _objarray_stack.is_empty(); +} + +inline bool G1FullGCMarker::pop_object(oop& oop) { + return _oop_stack.pop_overflow(oop) || _oop_stack.pop_local(oop); +} + +inline void G1FullGCMarker::push_objarray(oop obj, size_t index) { + ObjArrayTask task(obj, index); + assert(task.is_valid(), "bad ObjArrayTask"); + _objarray_stack.push(task); +} + +inline bool G1FullGCMarker::pop_objarray(ObjArrayTask& arr) { + return _objarray_stack.pop_overflow(arr) || _objarray_stack.pop_local(arr); +} + +inline void G1FullGCMarker::follow_array(objArrayOop array) { + follow_klass(array->klass()); + // Don't push empty arrays to avoid unnecessary work. + if (array->length() > 0) { + push_objarray(array, 0); + } +} + +void G1FullGCMarker::follow_array_chunk(objArrayOop array, int index) { + const int len = array->length(); + const int beg_index = index; + assert(beg_index < len || len == 0, "index too large"); + + const int stride = MIN2(len - beg_index, (int) ObjArrayMarkingStride); + const int end_index = beg_index + stride; + + array->oop_iterate_range(mark_closure(), beg_index, end_index); + + if (VerifyDuringGC) { + _verify_closure.set_containing_obj(array); + NoHeaderExtendedOopClosure no(&_verify_closure); + array->oop_iterate_range(&no, beg_index, end_index); + if (_verify_closure.failures()) { + assert(false, "Failed"); + } + } + + if (end_index < len) { + push_objarray(array, end_index); // Push the continuation. + } +} + +inline void G1FullGCMarker::follow_object(oop obj) { + assert(_bitmap->is_marked(obj), "should be marked"); + if (obj->is_objArray()) { + // Handle object arrays explicitly to allow them to + // be split into chunks if needed. + follow_array((objArrayOop)obj); + } else { + obj->oop_iterate(mark_closure()); + if (VerifyDuringGC) { + if (obj->is_instance() && InstanceKlass::cast(obj->klass())->is_reference_instance_klass()) { + return; + } + _verify_closure.set_containing_obj(obj); + obj->oop_iterate_no_header(&_verify_closure); + if (_verify_closure.failures()) { + log_warning(gc, verify)("Failed after %d", _verify_closure._cc); + assert(false, "Failed"); + } + } + } +} + +void G1FullGCMarker::drain_stack() { + do { + oop obj; + while (pop_object(obj)) { + assert(_bitmap->is_marked(obj), "must be marked"); + follow_object(obj); + } + // Process ObjArrays one at a time to avoid marking stack bloat. + ObjArrayTask task; + if (pop_objarray(task)) { + follow_array_chunk(objArrayOop(task.obj()), task.index()); + } + } while (!is_empty()); +} + +inline void G1FullGCMarker::follow_klass(Klass* k) { + oop op = k->klass_holder(); + mark_and_push(&op); +} + +inline void G1FullGCMarker::follow_cld(ClassLoaderData* cld) { + _cld_closure.do_cld(cld); +} + +#endif diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1FullGCMarker.inline.hpp" +#include "gc/g1/g1FullGCOopClosures.inline.hpp" +#include "gc/g1/g1_specialized_oop_closures.hpp" +#include "logging/logStream.hpp" + +void G1MarkAndPushClosure::do_oop(oop* p) { + do_oop_nv(p); +} + +void G1MarkAndPushClosure::do_oop(narrowOop* p) { + do_oop_nv(p); +} + +bool G1MarkAndPushClosure::do_metadata() { + return do_metadata_nv(); +} + +void G1MarkAndPushClosure::do_klass(Klass* k) { + do_klass_nv(k); +} + +void G1MarkAndPushClosure::do_cld(ClassLoaderData* cld) { + do_cld_nv(cld); +} + +G1AdjustAndRebuildClosure::G1AdjustAndRebuildClosure(uint worker_id) : + _worker_id(worker_id), + _compaction_delta(0), + _g1h(G1CollectedHeap::heap()) { } + +void G1AdjustAndRebuildClosure::update_compaction_delta(oop obj) { + if (G1ArchiveAllocator::is_open_archive_object(obj)) { + _compaction_delta = 0; + return; + } + oop forwardee = obj->forwardee(); + if (forwardee == NULL) { + // Object not moved. + _compaction_delta = 0; + } else { + // Object moved to forwardee, calculate delta. + _compaction_delta = calculate_compaction_delta(obj, forwardee); + } +} + +void G1AdjustClosure::do_oop(oop* p) { adjust_pointer(p); } +void G1AdjustClosure::do_oop(narrowOop* p) { adjust_pointer(p); } + +void G1AdjustAndRebuildClosure::do_oop(oop* p) { do_oop_nv(p); } +void G1AdjustAndRebuildClosure::do_oop(narrowOop* p) { do_oop_nv(p); } + +void G1FollowStackClosure::do_void() { _marker->drain_stack(); } + +void G1FullKeepAliveClosure::do_oop(oop* p) { do_oop_work(p); } +void G1FullKeepAliveClosure::do_oop(narrowOop* p) { do_oop_work(p); } + +G1VerifyOopClosure::G1VerifyOopClosure(VerifyOption option) : + _g1h(G1CollectedHeap::heap()), + _containing_obj(NULL), + _verify_option(option), + _cc(0), + _failures(false) { +} + +void G1VerifyOopClosure::print_object(outputStream* out, oop obj) { +#ifdef PRODUCT + Klass* k = obj->klass(); + const char* class_name = InstanceKlass::cast(k)->external_name(); + out->print_cr("class name %s", class_name); +#else // PRODUCT + obj->print_on(out); +#endif // PRODUCT +} + +template void G1VerifyOopClosure::do_oop_nv(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (!oopDesc::is_null(heap_oop)) { + _cc++; + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + bool failed = false; + if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _verify_option)) { + MutexLockerEx x(ParGCRareEvent_lock, + Mutex::_no_safepoint_check_flag); + LogStreamHandle(Error, gc, verify) yy; + if (!_failures) { + yy.cr(); + yy.print_cr("----------"); + } + if (!_g1h->is_in_closed_subset(obj)) { + HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); + yy.print_cr("Field " PTR_FORMAT + " of live obj " PTR_FORMAT " in region " + "[" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(_containing_obj), + p2i(from->bottom()), p2i(from->end())); + print_object(&yy, _containing_obj); + yy.print_cr("points to obj " PTR_FORMAT " not in the heap", + p2i(obj)); + } else { + HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p); + HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj); + yy.print_cr("Field " PTR_FORMAT + " of live obj " PTR_FORMAT " in region " + "[" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(p), p2i(_containing_obj), + p2i(from->bottom()), p2i(from->end())); + print_object(&yy, _containing_obj); + yy.print_cr("points to dead obj " PTR_FORMAT " in region " + "[" PTR_FORMAT ", " PTR_FORMAT ")", + p2i(obj), p2i(to->bottom()), p2i(to->end())); + print_object(&yy, obj); + } + yy.print_cr("----------"); + yy.flush(); + _failures = true; + failed = true; + } + } +} + +// Generate G1 full GC specialized oop_oop_iterate functions. +SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1FULL(ALL_KLASS_OOP_OOP_ITERATE_DEFN) diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCOOPCLOSURES_HPP +#define SHARE_GC_G1_G1FULLGCOOPCLOSURES_HPP + +#include "memory/iterator.hpp" +#include "memory/universe.hpp" + +class G1CollectedHeap; +class G1FullCollector; +class G1CMBitMap; +class G1FullGCMarker; + +// Below are closures used by the G1 Full GC. +class G1IsAliveClosure : public BoolObjectClosure { + G1CMBitMap* _bitmap; + +public: + G1IsAliveClosure(G1CMBitMap* bitmap) : _bitmap(bitmap) { } + + virtual bool do_object_b(oop p); +}; + +class G1FullKeepAliveClosure: public OopClosure { + G1FullGCMarker* _marker; + template + inline void do_oop_work(T* p); + +public: + G1FullKeepAliveClosure(G1FullGCMarker* pm) : _marker(pm) { } + + virtual void do_oop(oop* p); + virtual void do_oop(narrowOop* p); +}; + +class G1MarkAndPushClosure : public ExtendedOopClosure { + G1FullGCMarker* _marker; + uint _worker_id; + +public: + G1MarkAndPushClosure(uint worker, G1FullGCMarker* marker, ReferenceProcessor* ref) : + _marker(marker), + _worker_id(worker), + ExtendedOopClosure(ref) { } + + template inline void do_oop_nv(T* p); + virtual void do_oop(oop* p); + virtual void do_oop(narrowOop* p); + + virtual bool do_metadata(); + bool do_metadata_nv(); + + virtual void do_klass(Klass* k); + void do_klass_nv(Klass* k); + + virtual void do_cld(ClassLoaderData* cld); + void do_cld_nv(ClassLoaderData* cld); +}; + +class G1AdjustClosure : public OopClosure { +public: + template static inline oop adjust_pointer(T* p); + virtual void do_oop(oop* p); + virtual void do_oop(narrowOop* p); +}; + +class G1AdjustAndRebuildClosure : public ExtendedOopClosure { + uint _worker_id; + size_t _compaction_delta; + G1CollectedHeap* _g1h; + + inline size_t calculate_compaction_delta(oop current, oop forwardee); + template inline T* add_compaction_delta(T* p); + +public: + G1AdjustAndRebuildClosure(uint worker_id); + + void update_compaction_delta(oop obj); + + template inline void add_reference(T* from_field, oop reference, uint worker_id); + template void do_oop_nv(T* p); + virtual void do_oop(oop* p); + virtual void do_oop(narrowOop* p); + + virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } +}; + +class G1AdjustObjectClosure { + G1AdjustAndRebuildClosure* _closure; + +public: + G1AdjustObjectClosure(G1AdjustAndRebuildClosure* cl) : _closure(cl) { } + + inline int adjust_object(oop obj); +}; + +class G1VerifyOopClosure: public OopClosure { +private: + G1CollectedHeap* _g1h; + bool _failures; + oop _containing_obj; + VerifyOption _verify_option; + +public: + int _cc; + G1VerifyOopClosure(VerifyOption option); + + void set_containing_obj(oop obj) { + _containing_obj = obj; + } + + bool failures() { return _failures; } + void print_object(outputStream* out, oop obj); + + template void do_oop_nv(T* p); + + void do_oop(oop* p) { do_oop_nv(p); } + void do_oop(narrowOop* p) { do_oop_nv(p); } +}; + +class G1FollowStackClosure: public VoidClosure { + G1FullGCMarker* _marker; + +public: + G1FollowStackClosure(G1FullGCMarker* marker) : _marker(marker) {} + virtual void do_void(); +}; + +#endif // SHARE_GC_G1_G1FULLGCOOPCLOSURES_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCOopClosures.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_VM_GC_G1_G1FULLGCOOPCLOSURES_INLINE_HPP +#define SHARE_VM_GC_G1_G1FULLGCOOPCLOSURES_INLINE_HPP + +#include "gc/g1/g1Allocator.hpp" +#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/g1FullGCMarker.inline.hpp" +#include "gc/g1/g1FullGCOopClosures.hpp" +#include "gc/g1/heapRegionRemSet.hpp" +#include "memory/iterator.inline.hpp" + +template +inline void G1MarkAndPushClosure::do_oop_nv(T* p) { + _marker->mark_and_push(p); +} + +inline bool G1MarkAndPushClosure::do_metadata_nv() { + return true; +} + +inline void G1MarkAndPushClosure::do_klass_nv(Klass* k) { + _marker->follow_klass(k); +} + +inline void G1MarkAndPushClosure::do_cld_nv(ClassLoaderData* cld) { + _marker->follow_cld(cld); +} + +template inline oop G1AdjustClosure::adjust_pointer(T* p) { + T heap_oop = oopDesc::load_heap_oop(p); + if (oopDesc::is_null(heap_oop)) { + // NULL reference, return NULL. + return NULL; + } + + oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); + assert(Universe::heap()->is_in(obj), "should be in heap"); + if (G1ArchiveAllocator::is_archive_object(obj)) { + // Never forwarding archive objects, return current reference. + return obj; + } + + oop forwardee = obj->forwardee(); + if (forwardee == NULL) { + // Not forwarded, return current reference. + assert(obj->mark() == markOopDesc::prototype_for_object(obj) || // Correct mark + obj->mark()->must_be_preserved(obj) || // Will be restored by PreservedMarksSet + (UseBiasedLocking && obj->has_bias_pattern()), // Will be restored by BiasedLocking + "Must have correct prototype or be preserved, obj: " PTR_FORMAT ", mark: " PTR_FORMAT ", prototype: " PTR_FORMAT, + p2i(obj), p2i(obj->mark()), p2i(markOopDesc::prototype_for_object(obj))); + return obj; + } + + // Forwarded, update and return new reference. + assert(Universe::heap()->is_in_reserved(forwardee), "should be in object space"); + oopDesc::encode_store_heap_oop_not_null(p, forwardee); + return forwardee; +} + +template +inline void G1AdjustAndRebuildClosure::add_reference(T* from_field, oop reference, uint worker_id) { + if (HeapRegion::is_in_same_region(from_field, reference)) { + return; + } + _g1h->heap_region_containing(reference)->rem_set()->add_reference(from_field, worker_id); +} + +inline size_t G1AdjustAndRebuildClosure::calculate_compaction_delta(oop current, oop forwardee) { + return pointer_delta((HeapWord*)forwardee, (HeapWord*)current); +} + +template +inline T* G1AdjustAndRebuildClosure::add_compaction_delta(T* p) { + return (T*)((HeapWord*)p + _compaction_delta); +} + +template +void G1AdjustAndRebuildClosure::do_oop_nv(T* p) { + oop new_reference = G1AdjustClosure::adjust_pointer(p); + if (new_reference == NULL) { + return; + } + + // Update p using the calculated compaction delta to + // get the new field address. + T* new_field = add_compaction_delta(p); + // Update the remembered set. + add_reference(new_field, new_reference, _worker_id); +} + +inline int G1AdjustObjectClosure::adjust_object(oop obj) { + _closure->update_compaction_delta(obj); + return obj->oop_iterate_size(_closure); +} + +inline bool G1IsAliveClosure::do_object_b(oop p) { + return _bitmap->is_marked(p) || G1ArchiveAllocator::is_closed_archive_object(p); +} + +template +inline void G1FullKeepAliveClosure::do_oop_work(T* p) { + _marker->mark_and_push(p); +} + +#endif diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,220 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCMarker.hpp" +#include "gc/g1/g1FullGCOopClosures.inline.hpp" +#include "gc/g1/g1FullGCPrepareTask.hpp" +#include "gc/g1/g1HotCardCache.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "logging/log.hpp" +#include "utilities/ticks.inline.hpp" + +bool G1FullGCPrepareTask::G1CalculatePointersClosure::doHeapRegion(HeapRegion* hr) { + if (hr->is_humongous()) { + oop obj = oop(hr->humongous_start_region()->bottom()); + if (_bitmap->is_marked(obj)) { + if (hr->is_starts_humongous()) { + obj->forward_to(obj); + } + } else { + free_humongous_region(hr); + } + } else if (!hr->is_pinned()) { + prepare_for_compaction(hr); + } + + // Reset data structures not valid after Full GC. + reset_region_metadata(hr); + + return false; +} + +G1FullGCPrepareTask::G1FullGCPrepareTask(G1FullCollector* collector) : + G1FullGCTask("G1 Prepare Compact Task", collector), + _hrclaimer(collector->workers()), + _freed_regions(false) { +} + +void G1FullGCPrepareTask::set_freed_regions() { + if (!_freed_regions) { + _freed_regions = true; + } +} + +bool G1FullGCPrepareTask::has_freed_regions() { + return _freed_regions; +} + +void G1FullGCPrepareTask::work(uint worker_id) { + Ticks start = Ticks::now(); + G1FullGCCompactionPoint* compaction_point = collector()->compaction_point(worker_id); + G1CalculatePointersClosure closure(collector()->mark_bitmap(), compaction_point); + G1CollectedHeap::heap()->heap_region_par_iterate_from_start(&closure, &_hrclaimer); + + // Update humongous region sets + closure.update_sets(); + compaction_point->update(); + + // Check if any regions was freed by this worker and store in task. + if (closure.freed_regions()) { + set_freed_regions(); + } + log_task("Prepare compaction task", worker_id, start); +} + +G1FullGCPrepareTask::G1CalculatePointersClosure::G1CalculatePointersClosure(G1CMBitMap* bitmap, + G1FullGCCompactionPoint* cp) : + _g1h(G1CollectedHeap::heap()), + _bitmap(bitmap), + _cp(cp), + _humongous_regions_removed(0) { } + +void G1FullGCPrepareTask::G1CalculatePointersClosure::free_humongous_region(HeapRegion* hr) { + FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); + + hr->set_containing_set(NULL); + _humongous_regions_removed++; + + _g1h->free_humongous_region(hr, &dummy_free_list, false /* skip_remset */); + prepare_for_compaction(hr); + dummy_free_list.remove_all(); +} + +void G1FullGCPrepareTask::G1CalculatePointersClosure::reset_region_metadata(HeapRegion* hr) { + hr->reset_gc_time_stamp(); + hr->rem_set()->clear(); + + _g1h->g1_barrier_set()->clear(MemRegion(hr->bottom(), hr->end())); + + if (_g1h->g1_hot_card_cache()->use_cache()) { + _g1h->g1_hot_card_cache()->reset_card_counts(hr); + } +} + +G1FullGCPrepareTask::G1PrepareCompactLiveClosure::G1PrepareCompactLiveClosure(G1FullGCCompactionPoint* cp) : + _cp(cp) { } + +size_t G1FullGCPrepareTask::G1PrepareCompactLiveClosure::apply(oop object) { + size_t size = object->size(); + _cp->forward(object, size); + return size; +} + +size_t G1FullGCPrepareTask::G1RePrepareClosure::apply(oop obj) { + // We only re-prepare objects forwarded within the current region, so + // skip objects that are already forwarded to another region. + oop forwarded_to = obj->forwardee(); + if (forwarded_to != NULL && !_current->is_in(forwarded_to)) { + return obj->size(); + } + + // Get size and forward. + size_t size = obj->size(); + _cp->forward(obj, size); + + return size; +} + +void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction_work(G1FullGCCompactionPoint* cp, + HeapRegion* hr) { + G1PrepareCompactLiveClosure prepare_compact(cp); + hr->set_compaction_top(hr->bottom()); + hr->apply_to_marked_objects(_bitmap, &prepare_compact); +} + +void G1FullGCPrepareTask::G1CalculatePointersClosure::prepare_for_compaction(HeapRegion* hr) { + if (!_cp->is_initialized()) { + hr->set_compaction_top(hr->bottom()); + _cp->initialize(hr, true); + } + // Add region to the compaction queue and prepare it. + _cp->add(hr); + prepare_for_compaction_work(_cp, hr); +} + +void G1FullGCPrepareTask::prepare_serial_compaction() { + GCTraceTime(Debug, gc, phases) debug("Phase 2: Prepare Serial Compaction", collector()->scope()->timer()); + // At this point we know that no regions were completely freed by + // the parallel compaction. That means that the last region of + // all compaction queues still have data in them. We try to compact + // these regions in serial to avoid a premature OOM. + for (uint i = 0; i < collector()->workers(); i++) { + G1FullGCCompactionPoint* cp = collector()->compaction_point(i); + if (cp->has_regions()) { + collector()->serial_compaction_point()->add(cp->remove_last()); + } + } + + // Update the forwarding information for the regions in the serial + // compaction point. + G1FullGCCompactionPoint* cp = collector()->serial_compaction_point(); + for (GrowableArrayIterator it = cp->regions()->begin(); it != cp->regions()->end(); ++it) { + HeapRegion* current = *it; + if (!cp->is_initialized()) { + // Initialize the compaction point. Nothing more is needed for the first heap region + // since it is already prepared for compaction. + cp->initialize(current, false); + } else { + assert(!current->is_humongous(), "Should be no humongous regions in compaction queue"); + G1RePrepareClosure re_prepare(cp, current); + current->set_compaction_top(current->bottom()); + current->apply_to_marked_objects(collector()->mark_bitmap(), &re_prepare); + } + } + cp->update(); +} + +void G1FullGCPrepareTask::G1CalculatePointersClosure::update_sets() { + // We'll recalculate total used bytes and recreate the free list + // at the end of the GC, so no point in updating those values here. + _g1h->remove_from_old_sets(0, _humongous_regions_removed); +} + +bool G1FullGCPrepareTask::G1CalculatePointersClosure::freed_regions() { + if (_humongous_regions_removed > 0) { + // Free regions from dead humongous regions. + return true; + } + + if (!_cp->has_regions()) { + // No regions in queue, so no free ones either. + return false; + } + + if (_cp->current_region() != _cp->regions()->last()) { + // The current region used for compaction is not the last in the + // queue. That means there is at least one free region in the queue. + return true; + } + + // No free regions in the queue. + return false; +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCPrepareTask.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCPREPARETASK_HPP +#define SHARE_GC_G1_G1FULLGCPREPARETASK_HPP + +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCScope.hpp" +#include "gc/g1/g1FullGCTask.hpp" +#include "gc/g1/g1RootProcessor.hpp" +#include "gc/g1/g1StringDedup.hpp" +#include "gc/g1/heapRegionManager.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "utilities/ticks.hpp" + +class G1CMBitMap; + +class G1FullGCPrepareTask : public G1FullGCTask { +protected: + volatile bool _freed_regions; + HeapRegionClaimer _hrclaimer; + + void set_freed_regions(); + +public: + G1FullGCPrepareTask(G1FullCollector* collector); + void work(uint worker_id); + void prepare_serial_compaction(); + bool has_freed_regions(); + +protected: + class G1CalculatePointersClosure : public HeapRegionClosure { + protected: + G1CollectedHeap* _g1h; + G1CMBitMap* _bitmap; + G1FullGCCompactionPoint* _cp; + uint _humongous_regions_removed; + + virtual void prepare_for_compaction(HeapRegion* hr); + void prepare_for_compaction_work(G1FullGCCompactionPoint* cp, HeapRegion* hr); + void free_humongous_region(HeapRegion* hr); + void reset_region_metadata(HeapRegion* hr); + + public: + G1CalculatePointersClosure(G1CMBitMap* bitmap, + G1FullGCCompactionPoint* cp); + + void update_sets(); + bool doHeapRegion(HeapRegion* hr); + bool freed_regions(); + }; + + class G1PrepareCompactLiveClosure : public StackObj { + G1FullGCCompactionPoint* _cp; + + public: + G1PrepareCompactLiveClosure(G1FullGCCompactionPoint* cp); + size_t apply(oop object); + }; + + class G1RePrepareClosure : public StackObj { + G1FullGCCompactionPoint* _cp; + HeapRegion* _current; + + public: + G1RePrepareClosure(G1FullGCCompactionPoint* hrcp, + HeapRegion* hr) : + _cp(hrcp), + _current(hr) { } + + size_t apply(oop object); + }; +}; + +#endif // SHARE_GC_G1_G1FULLGCPREPARETASK_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1FullCollector.hpp" +#include "gc/g1/g1FullGCMarker.hpp" +#include "gc/g1/g1FullGCOopClosures.inline.hpp" +#include "gc/g1/g1FullGCReferenceProcessorExecutor.hpp" +#include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/referenceProcessor.hpp" + +G1FullGCReferenceProcessingExecutor::G1FullGCReferenceProcessingExecutor(G1FullCollector* collector) : + _collector(collector), + _reference_processor(collector->reference_processor()), + _old_mt_degree(_reference_processor->num_q()) { + if (_reference_processor->processing_is_mt()) { + _reference_processor->set_active_mt_degree(_collector->workers()); + } +} + +G1FullGCReferenceProcessingExecutor::~G1FullGCReferenceProcessingExecutor() { + if (_reference_processor->processing_is_mt()) { + _reference_processor->set_active_mt_degree(_old_mt_degree); + } +} + +G1FullGCReferenceProcessingExecutor::G1RefProcTaskProxy::G1RefProcTaskProxy(ProcessTask& proc_task, + G1FullCollector* collector) : + AbstractGangTask("G1 reference processing task"), + _proc_task(proc_task), + _collector(collector), + _terminator(_collector->workers(), _collector->oop_queue_set()) { } + +void G1FullGCReferenceProcessingExecutor::G1RefProcTaskProxy::work(uint worker_id) { + G1FullGCMarker* marker = _collector->marker(worker_id); + G1IsAliveClosure is_alive(_collector->mark_bitmap()); + G1FullKeepAliveClosure keep_alive(marker); + _proc_task.work(worker_id, + is_alive, + keep_alive, + *marker->stack_closure()); +} + +G1FullGCReferenceProcessingExecutor::G1RefEnqueueTaskProxy::G1RefEnqueueTaskProxy(EnqueueTask& enq_task) : + AbstractGangTask("G1 reference enqueue task"), + _enq_task(enq_task) { } + +void G1FullGCReferenceProcessingExecutor::G1RefEnqueueTaskProxy::work(uint worker_id) { + _enq_task.work(worker_id); +} + +void G1FullGCReferenceProcessingExecutor::run_task(AbstractGangTask* task) { + G1CollectedHeap::heap()->workers()->run_task(task, _collector->workers()); +} + +void G1FullGCReferenceProcessingExecutor::execute(ProcessTask& proc_task) { + G1RefProcTaskProxy proc_task_proxy(proc_task, _collector); + run_task(&proc_task_proxy); +} + +// Driver routine for parallel reference processing. +void G1FullGCReferenceProcessingExecutor::execute(EnqueueTask& enq_task) { + G1RefEnqueueTaskProxy enq_task_proxy(enq_task); + run_task(&enq_task_proxy); +} + +void G1FullGCReferenceProcessingExecutor::execute(STWGCTimer* timer, G1FullGCTracer* tracer) { + GCTraceTime(Debug, gc, phases) debug("Phase 1: Reference Processing", timer); + // Process reference objects found during marking. + G1FullGCMarker* marker = _collector->marker(0); + G1IsAliveClosure is_alive(_collector->mark_bitmap()); + G1FullKeepAliveClosure keep_alive(marker); + ReferenceProcessorPhaseTimes pt(timer, _reference_processor->num_q()); + AbstractRefProcTaskExecutor* executor = _reference_processor->processing_is_mt() ? this : NULL; + + // Process discovered references, use this executor if multi-threaded + // processing is enabled. + const ReferenceProcessorStats& stats = + _reference_processor->process_discovered_references(&is_alive, + &keep_alive, + marker->stack_closure(), + executor, + &pt); + + tracer->report_gc_reference_stats(stats); + pt.print_all_references(); + + assert(marker->oop_stack()->is_empty(), "Should be no oops on the stack"); + + // Now enqueue the references. + _reference_processor->enqueue_discovered_references(executor, &pt); + pt.print_enqueue_phase(); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCREFERENCEPROCESSOREXECUTOR_HPP +#define SHARE_GC_G1_G1FULLGCREFERENCEPROCESSOREXECUTOR_HPP + +#include "gc/g1/g1FullGCCompactionPoint.hpp" +#include "gc/g1/g1FullGCScope.hpp" +#include "gc/g1/g1FullGCTask.hpp" +#include "gc/g1/g1RootProcessor.hpp" +#include "gc/g1/g1StringDedup.hpp" +#include "gc/g1/heapRegionManager.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "utilities/ticks.hpp" + +class G1FullGCTracer; +class STWGCTimer; + +class G1FullGCReferenceProcessingExecutor: public AbstractRefProcTaskExecutor { + G1FullCollector* _collector; + ReferenceProcessor* _reference_processor; + uint _old_mt_degree; + +public: + G1FullGCReferenceProcessingExecutor(G1FullCollector* collector); + ~G1FullGCReferenceProcessingExecutor(); + + // Do reference processing. + void execute(STWGCTimer* timer, G1FullGCTracer* tracer); + + // Executes the given task using concurrent marking worker threads. + virtual void execute(ProcessTask& task); + virtual void execute(EnqueueTask& task); + +private: + void run_task(AbstractGangTask* task); + + class G1RefProcTaskProxy : public AbstractGangTask { + typedef AbstractRefProcTaskExecutor::ProcessTask ProcessTask; + ProcessTask& _proc_task; + G1FullCollector* _collector; + ParallelTaskTerminator _terminator; + + public: + G1RefProcTaskProxy(ProcessTask& proc_task, + G1FullCollector* scope); + + virtual void work(uint worker_id); + }; + + class G1RefEnqueueTaskProxy: public AbstractGangTask { + typedef AbstractRefProcTaskExecutor::EnqueueTask EnqueueTask; + EnqueueTask& _enq_task; + + public: + G1RefEnqueueTaskProxy(EnqueueTask& enq_task); + virtual void work(uint worker_id); + }; +}; + +#endif // SHARE_GC_G1_G1FULLGCREFERENCEPROCESSOREXECUTOR_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCScope.cpp --- a/src/hotspot/share/gc/g1/g1FullGCScope.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1FullGCScope.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -25,13 +25,6 @@ #include "precompiled.hpp" #include "gc/g1/g1FullGCScope.hpp" -G1FullGCScope* G1FullGCScope::_instance = NULL; - -G1FullGCScope* G1FullGCScope::instance() { - assert(_instance != NULL, "Must be setup already"); - return _instance; -} - G1FullGCScope::G1FullGCScope(bool explicit_gc, bool clear_soft) : _rm(), _explicit_gc(explicit_gc), @@ -46,12 +39,10 @@ _memory_stats(true, _g1h->gc_cause()), _collector_stats(_g1h->g1mm()->full_collection_counters()), _heap_transition(_g1h) { - assert(_instance == NULL, "Only one scope at a time"); _timer.register_gc_start(); _tracer.report_gc_start(_g1h->gc_cause(), _timer.gc_start()); _g1h->pre_full_gc_dump(&_timer); _g1h->trace_heap_before_gc(&_tracer); - _instance = this; } G1FullGCScope::~G1FullGCScope() { @@ -64,7 +55,6 @@ _g1h->post_full_gc_dump(&_timer); _timer.register_gc_end(); _tracer.report_gc_end(_timer.gc_end(), _timer.time_partitions()); - _instance = NULL; } bool G1FullGCScope::is_explicit_gc() { @@ -79,7 +69,7 @@ return &_timer; } -SerialOldTracer* G1FullGCScope::tracer() { +G1FullGCTracer* G1FullGCScope::tracer() { return &_tracer; } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCScope.hpp --- a/src/hotspot/share/gc/g1/g1FullGCScope.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1FullGCScope.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -45,7 +45,7 @@ GCIdMark _gc_id; SvcGCMarker _svc_marker; STWGCTimer _timer; - SerialOldTracer _tracer; + G1FullGCTracer _tracer; IsGCActiveMark _active; GCTraceCPUTime _cpu_time; ClearedAllSoftRefs _soft_refs; @@ -53,11 +53,7 @@ TraceMemoryManagerStats _memory_stats; G1HeapTransition _heap_transition; - // Singleton instance. - static G1FullGCScope* _instance; public: - static G1FullGCScope* instance(); - G1FullGCScope(bool explicit_gc, bool clear_soft); ~G1FullGCScope(); @@ -65,7 +61,7 @@ bool should_clear_soft_refs(); STWGCTimer* timer(); - SerialOldTracer* tracer(); + G1FullGCTracer* tracer(); G1HeapTransition* heap_transition(); }; diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCTask.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCTask.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1FullGCTask.hpp" +#include "logging/log.hpp" +#include "utilities/ticks.inline.hpp" + +void G1FullGCTask::log_task(const char* name, uint worker_id, const Ticks& start, const Ticks& stop) { + Tickspan duration = stop - start; + double duration_ms = TimeHelper::counter_to_millis(duration.value()); + log_trace(gc, phases)("%s (%u) %.3fms", name, worker_id, duration_ms); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1FullGCTask.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hotspot/share/gc/g1/g1FullGCTask.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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. + * + */ + +#ifndef SHARE_GC_G1_G1FULLGCTASK_HPP +#define SHARE_GC_G1_G1FULLGCTASK_HPP + +#include "gc/shared/workgroup.hpp" +#include "utilities/ticks.hpp" + +class G1FullCollector; + +class G1FullGCTask : public AbstractGangTask { + G1FullCollector* _collector; + +protected: + G1FullGCTask(const char* name, G1FullCollector* collector) : + AbstractGangTask(name), + _collector(collector) { } + + G1FullCollector* collector() { return _collector; } + void log_task(const char* name, uint worker_id, const Ticks& start, const Ticks& stop = Ticks::now()); +}; + +#endif // SHARE_GC_G1_G1FULLGCTASK_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1HeapVerifier.cpp --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -48,7 +48,7 @@ public: // _vo == UsePrevMarking -> use "prev" marking information, // _vo == UseNextMarking -> use "next" marking information, - // _vo == UseMarkWord -> use mark word from object header. + // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS VerifyRootsClosure(VerifyOption vo) : _g1h(G1CollectedHeap::heap()), _vo(vo), @@ -63,9 +63,6 @@ if (_g1h->is_obj_dead_cond(obj, _vo)) { Log(gc, verify) log; log.error("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj)); - if (_vo == VerifyOption_G1UseMarkWord) { - log.error(" Mark word: " PTR_FORMAT, p2i(obj->mark())); - } ResourceMark rm; LogStream ls(log.error()); obj->print_on(&ls); @@ -95,7 +92,7 @@ } // Don't check the code roots during marking verification in a full GC - if (_vo == VerifyOption_G1UseMarkWord) { + if (_vo == VerifyOption_G1UseFullMarking) { return; } @@ -203,7 +200,7 @@ public: // _vo == UsePrevMarking -> use "prev" marking information, // _vo == UseNextMarking -> use "next" marking information, - // _vo == UseMarkWord -> use mark word from object header. + // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS. VerifyObjsInRegionClosure(HeapRegion *hr, VerifyOption vo) : _live_bytes(0), _hr(hr), _vo(vo) { _g1h = G1CollectedHeap::heap(); @@ -212,15 +209,15 @@ VerifyLivenessOopClosure isLive(_g1h, _vo); assert(o != NULL, "Huh?"); if (!_g1h->is_obj_dead_cond(o, _vo)) { - // If the object is alive according to the mark word, + // If the object is alive according to the full gc mark, // then verify that the marking information agrees. // Note we can't verify the contra-positive of the // above: if the object is dead (according to the mark // word), it may not be marked, or may have been marked // but has since became dead, or may have been allocated // since the last marking. - if (_vo == VerifyOption_G1UseMarkWord) { - guarantee(!_g1h->is_obj_dead(o), "mark word and concurrent mark mismatch"); + if (_vo == VerifyOption_G1UseFullMarking) { + guarantee(!_g1h->is_obj_dead(o), "Full GC marking and concurrent mark mismatch"); } o->oop_iterate_no_header(&isLive); @@ -299,7 +296,7 @@ public: // _vo == UsePrevMarking -> use "prev" marking information, // _vo == UseNextMarking -> use "next" marking information, - // _vo == UseMarkWord -> use mark word from object header. + // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS VerifyRegionClosure(bool par, VerifyOption vo) : _par(par), _vo(vo), @@ -357,7 +354,7 @@ public: // _vo == UsePrevMarking -> use "prev" marking information, // _vo == UseNextMarking -> use "next" marking information, - // _vo == UseMarkWord -> use mark word from object header. + // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS G1ParVerifyTask(G1CollectedHeap* g1h, VerifyOption vo) : AbstractGangTask("Parallel verify task"), _g1h(g1h), @@ -372,7 +369,7 @@ void work(uint worker_id) { HandleMark hm; VerifyRegionClosure blk(true, _vo); - _g1h->heap_region_par_iterate(&blk, worker_id, &_hrclaimer); + _g1h->heap_region_par_iterate_from_worker_offset(&blk, &_hrclaimer, worker_id); if (blk.failures()) { _failures = true; } @@ -407,7 +404,7 @@ bool failures = rootsCl.failures() || codeRootsCl.failures(); - if (vo != VerifyOption_G1UseMarkWord) { + if (!_g1h->g1_policy()->collector_state()->full_collection()) { // If we're verifying during a full GC then the region sets // will have been torn down at the start of the GC. Therefore // verifying the region sets will fail. So we only verify diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1HeapVerifier.hpp --- a/src/hotspot/share/gc/g1/g1HeapVerifier.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -46,9 +46,9 @@ // Perform verification. - // vo == UsePrevMarking -> use "prev" marking information, + // vo == UsePrevMarking -> use "prev" marking information, // vo == UseNextMarking -> use "next" marking information - // vo == UseMarkWord -> use the mark word in the object header + // vo == UseFullMarking -> use "next" marking bitmap but no TAMS // // NOTE: Only the "prev" marking information is guaranteed to be // consistent most of the time, so most calls to this should use @@ -57,7 +57,7 @@ // vo == UseNextMarking, which is to verify the "next" marking // information at the end of remark. // Currently there is only one place where this is called with - // vo == UseMarkWord, which is to verify the marking during a + // vo == UseFullMarking, which is to verify the marking during a // full GC. void verify(VerifyOption vo); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1HotCardCache.cpp --- a/src/hotspot/share/gc/g1/g1HotCardCache.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1HotCardCache.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -110,7 +110,3 @@ void G1HotCardCache::reset_card_counts(HeapRegion* hr) { _card_counts.clear_region(hr); } - -void G1HotCardCache::reset_card_counts() { - _card_counts.clear_all(); -} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1HotCardCache.hpp --- a/src/hotspot/share/gc/g1/g1HotCardCache.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1HotCardCache.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -128,9 +128,6 @@ } } - // Zeros the values in the card counts table for entire committed heap - void reset_card_counts(); - // Zeros the values in the card counts table for the given region void reset_card_counts(HeapRegion* hr); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1MarkSweep.cpp --- a/src/hotspot/share/gc/g1/g1MarkSweep.cpp Mon Oct 30 08:34:54 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,387 +0,0 @@ -/* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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 "precompiled.hpp" -#include "classfile/javaClasses.hpp" -#include "classfile/symbolTable.hpp" -#include "classfile/systemDictionary.hpp" -#include "classfile/vmSymbols.hpp" -#include "code/codeCache.hpp" -#include "code/icBuffer.hpp" -#include "gc/g1/g1FullGCScope.hpp" -#include "gc/g1/g1MarkSweep.hpp" -#include "gc/g1/g1RootProcessor.hpp" -#include "gc/g1/g1StringDedup.hpp" -#include "gc/serial/markSweep.inline.hpp" -#include "gc/shared/gcHeapSummary.hpp" -#include "gc/shared/gcLocker.hpp" -#include "gc/shared/gcTimer.hpp" -#include "gc/shared/gcTrace.hpp" -#include "gc/shared/gcTraceTime.inline.hpp" -#include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/modRefBarrierSet.hpp" -#include "gc/shared/referencePolicy.hpp" -#include "gc/shared/space.hpp" -#include "gc/shared/weakProcessor.hpp" -#include "oops/instanceRefKlass.hpp" -#include "oops/oop.inline.hpp" -#include "prims/jvmtiExport.hpp" -#include "runtime/atomic.hpp" -#include "runtime/biasedLocking.hpp" -#include "runtime/synchronizer.hpp" -#include "runtime/thread.hpp" -#include "runtime/vmThread.hpp" -#include "utilities/copy.hpp" -#include "utilities/events.hpp" - -class HeapRegion; - -void G1MarkSweep::invoke_at_safepoint(ReferenceProcessor* rp, - bool clear_all_softrefs) { - assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); - HandleMark hm; // Discard invalid handles created during gc - -#if COMPILER2_OR_JVMCI - DerivedPointerTable::clear(); -#endif -#ifdef ASSERT - if (G1CollectedHeap::heap()->collector_policy()->should_clear_all_soft_refs()) { - assert(clear_all_softrefs, "Policy should have been checked earler"); - } -#endif - // hook up weak ref data so it can be used during Mark-Sweep - assert(GenMarkSweep::ref_processor() == NULL, "no stomping"); - assert(rp != NULL, "should be non-NULL"); - assert(rp == G1CollectedHeap::heap()->ref_processor_stw(), "Precondition"); - - GenMarkSweep::set_ref_processor(rp); - rp->setup_policy(clear_all_softrefs); - - // When collecting the permanent generation Method*s may be moving, - // so we either have to flush all bcp data or convert it into bci. - CodeCache::gc_prologue(); - - bool marked_for_unloading = false; - - allocate_stacks(); - - // We should save the marks of the currently locked biased monitors. - // The marking doesn't preserve the marks of biased objects. - BiasedLocking::preserve_marks(); - - // Process roots and do the marking. - mark_sweep_phase1(marked_for_unloading, clear_all_softrefs); - - // Prepare compaction. - mark_sweep_phase2(); - -#if COMPILER2_OR_JVMCI - // Don't add any more derived pointers during phase3 - DerivedPointerTable::set_active(false); -#endif - - // Adjust all pointers. - mark_sweep_phase3(); - - // Do the actual compaction. - mark_sweep_phase4(); - - GenMarkSweep::restore_marks(); - BiasedLocking::restore_marks(); - GenMarkSweep::deallocate_stacks(); - -#if COMPILER2_OR_JVMCI - // Now update the derived pointers. - DerivedPointerTable::update_pointers(); -#endif - - CodeCache::gc_epilogue(); - JvmtiExport::gc_epilogue(); - - // refs processing: clean slate - GenMarkSweep::set_ref_processor(NULL); -} - -STWGCTimer* G1MarkSweep::gc_timer() { - return G1FullGCScope::instance()->timer(); -} - -SerialOldTracer* G1MarkSweep::gc_tracer() { - return G1FullGCScope::instance()->tracer(); -} - -void G1MarkSweep::allocate_stacks() { - GenMarkSweep::_preserved_count_max = 0; - GenMarkSweep::_preserved_marks = NULL; - GenMarkSweep::_preserved_count = 0; -} - -void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading, - bool clear_all_softrefs) { - // Recursively traverse all live objects and mark them - GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", gc_timer()); - - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - // Need cleared claim bits for the roots processing - ClassLoaderDataGraph::clear_claimed_marks(); - - MarkingCodeBlobClosure follow_code_closure(&GenMarkSweep::follow_root_closure, !CodeBlobToOopClosure::FixRelocations); - { - G1RootProcessor root_processor(g1h, 1); - if (ClassUnloading) { - root_processor.process_strong_roots(&GenMarkSweep::follow_root_closure, - &GenMarkSweep::follow_cld_closure, - &follow_code_closure); - } else { - root_processor.process_all_roots_no_string_table( - &GenMarkSweep::follow_root_closure, - &GenMarkSweep::follow_cld_closure, - &follow_code_closure); - } - } - - { - GCTraceTime(Debug, gc, phases) trace("Reference Processing", gc_timer()); - - // Process reference objects found during marking - ReferenceProcessor* rp = GenMarkSweep::ref_processor(); - assert(rp == g1h->ref_processor_stw(), "Sanity"); - - rp->setup_policy(clear_all_softrefs); - ReferenceProcessorPhaseTimes pt(gc_timer(), rp->num_q()); - - const ReferenceProcessorStats& stats = - rp->process_discovered_references(&GenMarkSweep::is_alive, - &GenMarkSweep::keep_alive, - &GenMarkSweep::follow_stack_closure, - NULL, - &pt); - gc_tracer()->report_gc_reference_stats(stats); - pt.print_all_references(); - } - - // This is the point where the entire marking should have completed. - assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed"); - - { - GCTraceTime(Debug, gc, phases) trace("Weak Processing", gc_timer()); - WeakProcessor::weak_oops_do(&GenMarkSweep::is_alive, &do_nothing_cl); - } - - if (ClassUnloading) { - GCTraceTime(Debug, gc, phases) trace("Class Unloading", gc_timer()); - - // Unload classes and purge the SystemDictionary. - bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive, gc_timer()); - - g1h->complete_cleaning(&GenMarkSweep::is_alive, purged_class); - } else { - GCTraceTime(Debug, gc, phases) trace("Cleanup", gc_timer()); - g1h->partial_cleaning(&GenMarkSweep::is_alive, true, true, G1StringDedup::is_enabled()); - } - - if (VerifyDuringGC) { - HandleMark hm; // handle scope -#if COMPILER2_OR_JVMCI - DerivedPointerTableDeactivate dpt_deact; -#endif - g1h->prepare_for_verify(); - // Note: we can verify only the heap here. When an object is - // marked, the previous value of the mark word (including - // identity hash values, ages, etc) is preserved, and the mark - // word is set to markOop::marked_value - effectively removing - // any hash values from the mark word. These hash values are - // used when verifying the dictionaries and so removing them - // from the mark word can make verification of the dictionaries - // fail. At the end of the GC, the original mark word values - // (including hash values) are restored to the appropriate - // objects. - GCTraceTime(Info, gc, verify)("During GC (full)"); - g1h->verify(VerifyOption_G1UseMarkWord); - } - - gc_tracer()->report_object_count_after_gc(&GenMarkSweep::is_alive); -} - - -void G1MarkSweep::mark_sweep_phase2() { - // Now all live objects are marked, compute the new object addresses. - - // It is not required that we traverse spaces in the same order in - // phase2, phase3 and phase4, but the ValidateMarkSweep live oops - // tracking expects us to do so. See comment under phase4. - - GCTraceTime(Info, gc, phases) tm("Phase 2: Compute new object addresses", gc_timer()); - - prepare_compaction(); -} - -class G1AdjustPointersClosure: public HeapRegionClosure { - public: - bool doHeapRegion(HeapRegion* r) { - if (r->is_humongous()) { - if (r->is_starts_humongous()) { - // We must adjust the pointers on the single H object. - oop obj = oop(r->bottom()); - // point all the oops to the new location - MarkSweep::adjust_pointers(obj); - } - } else if (!r->is_closed_archive()) { - // This really ought to be "as_CompactibleSpace"... - r->adjust_pointers(); - } - return false; - } -}; - -void G1MarkSweep::mark_sweep_phase3() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - // Adjust the pointers to reflect the new locations - GCTraceTime(Info, gc, phases) tm("Phase 3: Adjust pointers", gc_timer()); - - // Need cleared claim bits for the roots processing - ClassLoaderDataGraph::clear_claimed_marks(); - - CodeBlobToOopClosure adjust_code_closure(&GenMarkSweep::adjust_pointer_closure, CodeBlobToOopClosure::FixRelocations); - { - G1RootProcessor root_processor(g1h, 1); - root_processor.process_all_roots(&GenMarkSweep::adjust_pointer_closure, - &GenMarkSweep::adjust_cld_closure, - &adjust_code_closure); - } - - assert(GenMarkSweep::ref_processor() == g1h->ref_processor_stw(), "Sanity"); - g1h->ref_processor_stw()->weak_oops_do(&GenMarkSweep::adjust_pointer_closure); - - // Now adjust pointers in remaining weak roots. (All of which should - // have been cleared if they pointed to non-surviving objects.) - WeakProcessor::oops_do(&GenMarkSweep::adjust_pointer_closure); - - if (G1StringDedup::is_enabled()) { - G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure); - } - - GenMarkSweep::adjust_marks(); - - G1AdjustPointersClosure blk; - g1h->heap_region_iterate(&blk); -} - -class G1SpaceCompactClosure: public HeapRegionClosure { -public: - G1SpaceCompactClosure() {} - - bool doHeapRegion(HeapRegion* hr) { - if (hr->is_humongous()) { - if (hr->is_starts_humongous()) { - oop obj = oop(hr->bottom()); - if (obj->is_gc_marked()) { - obj->init_mark(); - } else { - assert(hr->is_empty(), "Should have been cleared in phase 2."); - } - } - hr->reset_during_compaction(); - } else if (!hr->is_pinned()) { - hr->compact(); - } - return false; - } -}; - -void G1MarkSweep::mark_sweep_phase4() { - // All pointers are now adjusted, move objects accordingly - - // The ValidateMarkSweep live oops tracking expects us to traverse spaces - // in the same order in phase2, phase3 and phase4. We don't quite do that - // here (code and comment not fixed for perm removal), so we tell the validate code - // to use a higher index (saved from phase2) when verifying perm_gen. - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - - GCTraceTime(Info, gc, phases) tm("Phase 4: Move objects", gc_timer()); - - G1SpaceCompactClosure blk; - g1h->heap_region_iterate(&blk); - -} - -void G1MarkSweep::prepare_compaction_work(G1PrepareCompactClosure* blk) { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - g1h->heap_region_iterate(blk); - blk->update_sets(); -} - -void G1PrepareCompactClosure::free_humongous_region(HeapRegion* hr) { - HeapWord* end = hr->end(); - FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); - - hr->set_containing_set(NULL); - _humongous_regions_removed++; - - _g1h->free_humongous_region(hr, &dummy_free_list, false /* skip_remset */); - prepare_for_compaction(hr, end); - dummy_free_list.remove_all(); -} - -void G1PrepareCompactClosure::prepare_for_compaction(HeapRegion* hr, HeapWord* end) { - // If this is the first live region that we came across which we can compact, - // initialize the CompactPoint. - if (!is_cp_initialized()) { - _cp.space = hr; - _cp.threshold = hr->initialize_threshold(); - } - prepare_for_compaction_work(&_cp, hr, end); -} - -void G1PrepareCompactClosure::prepare_for_compaction_work(CompactPoint* cp, - HeapRegion* hr, - HeapWord* end) { - hr->prepare_for_compaction(cp); - // Also clear the part of the card table that will be unused after - // compaction. - _mrbs->clear(MemRegion(hr->compaction_top(), end)); -} - -void G1PrepareCompactClosure::update_sets() { - // We'll recalculate total used bytes and recreate the free list - // at the end of the GC, so no point in updating those values here. - _g1h->remove_from_old_sets(0, _humongous_regions_removed); -} - -bool G1PrepareCompactClosure::doHeapRegion(HeapRegion* hr) { - if (hr->is_humongous()) { - oop obj = oop(hr->humongous_start_region()->bottom()); - if (hr->is_starts_humongous() && obj->is_gc_marked()) { - obj->forward_to(obj); - } - if (!obj->is_gc_marked()) { - free_humongous_region(hr); - } - } else if (!hr->is_pinned()) { - prepare_for_compaction(hr, hr->end()); - } - return false; -} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1MarkSweep.hpp --- a/src/hotspot/share/gc/g1/g1MarkSweep.hpp Mon Oct 30 08:34:54 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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. - * - */ - -#ifndef SHARE_VM_GC_G1_G1MARKSWEEP_HPP -#define SHARE_VM_GC_G1_G1MARKSWEEP_HPP - -#include "gc/g1/g1CollectedHeap.hpp" -#include "gc/g1/heapRegion.hpp" -#include "gc/serial/genMarkSweep.hpp" -#include "gc/shared/generation.hpp" -#include "memory/universe.hpp" -#include "oops/markOop.hpp" -#include "oops/oop.hpp" -#include "runtime/timer.hpp" -#include "utilities/growableArray.hpp" - -class ReferenceProcessor; - -// G1MarkSweep takes care of global mark-compact garbage collection for a -// G1CollectedHeap using a four-phase pointer forwarding algorithm. All -// generations are assumed to support marking; those that can also support -// compaction. -// -// Class unloading will only occur when a full gc is invoked. -class G1PrepareCompactClosure; -class G1ArchiveRegionMap; - -class G1MarkSweep : AllStatic { - public: - - static void invoke_at_safepoint(ReferenceProcessor* rp, - bool clear_all_softrefs); - - static STWGCTimer* gc_timer(); - static SerialOldTracer* gc_tracer(); - -private: - // Mark live objects - static void mark_sweep_phase1(bool& marked_for_deopt, - bool clear_all_softrefs); - // Calculate new addresses - static void mark_sweep_phase2(); - // Update pointers - static void mark_sweep_phase3(); - // Move objects to new positions - static void mark_sweep_phase4(); - - static void allocate_stacks(); - static void prepare_compaction(); - static void prepare_compaction_work(G1PrepareCompactClosure* blk); -}; - -class G1PrepareCompactClosure : public HeapRegionClosure { - protected: - G1CollectedHeap* _g1h; - ModRefBarrierSet* _mrbs; - CompactPoint _cp; - uint _humongous_regions_removed; - - virtual void prepare_for_compaction(HeapRegion* hr, HeapWord* end); - void prepare_for_compaction_work(CompactPoint* cp, HeapRegion* hr, HeapWord* end); - void free_humongous_region(HeapRegion* hr); - bool is_cp_initialized() const { return _cp.space != NULL; } - - public: - G1PrepareCompactClosure() : - _g1h(G1CollectedHeap::heap()), - _mrbs(_g1h->g1_barrier_set()), - _humongous_regions_removed(0) { } - - void update_sets(); - bool doHeapRegion(HeapRegion* hr); -}; - -#endif // SHARE_VM_GC_G1_G1MARKSWEEP_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1MarkSweep_ext.cpp --- a/src/hotspot/share/gc/g1/g1MarkSweep_ext.cpp Mon Oct 30 08:34:54 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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 "precompiled.hpp" -#include "gc/g1/g1MarkSweep.hpp" - -void G1MarkSweep::prepare_compaction() { - G1PrepareCompactClosure blk; - G1MarkSweep::prepare_compaction_work(&blk); -} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1OopClosures.inline.hpp --- a/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1OopClosures.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -30,7 +30,6 @@ #include "gc/g1/g1OopClosures.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1RemSet.hpp" -#include "gc/g1/g1RemSet.inline.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" #include "memory/iterator.inline.hpp" diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -26,7 +26,7 @@ #define SHARE_VM_GC_G1_G1PARSCANTHREADSTATE_INLINE_HPP #include "gc/g1/g1ParScanThreadState.hpp" -#include "gc/g1/g1RemSet.inline.hpp" +#include "gc/g1/g1RemSet.hpp" #include "oops/oop.inline.hpp" template void G1ParScanThreadState::do_oop_evac(T* p, HeapRegion* from) { diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1RemSet.cpp --- a/src/hotspot/share/gc/g1/g1RemSet.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -31,7 +31,7 @@ #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HotCardCache.hpp" #include "gc/g1/g1OopClosures.inline.hpp" -#include "gc/g1/g1RemSet.inline.hpp" +#include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1SATBCardTableModRefBS.inline.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionManager.inline.hpp" @@ -532,7 +532,7 @@ void G1RemSet::scrub(uint worker_num, HeapRegionClaimer *hrclaimer) { G1ScrubRSClosure scrub_cl(&_card_live_data); - _g1->heap_region_par_iterate(&scrub_cl, worker_num, hrclaimer); + _g1->heap_region_par_iterate_from_worker_offset(&scrub_cl, hrclaimer, worker_num); } inline void check_card_ptr(jbyte* card_ptr, CardTableModRefBS* ct_bs) { diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1RemSet.hpp --- a/src/hotspot/share/gc/g1/g1RemSet.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -114,10 +114,6 @@ G1RemSetScanState* scan_state() const { return _scan_state; } - // Record, if necessary, the fact that *p (where "p" is in region "from", - // which is required to be non-NULL) has changed to a new non-NULL value. - template void par_write_ref(HeapRegion* from, T* p, uint tid); - // Eliminates any remembered set entries that correspond to dead heap ranges. void scrub(uint worker_num, HeapRegionClaimer* hrclaimer); @@ -191,25 +187,4 @@ size_t cards_skipped() const { return _cards_skipped; } }; -class RebuildRSOopClosure: public ExtendedOopClosure { - HeapRegion* _from; - G1RemSet* _rs; - uint _worker_i; - - template void do_oop_work(T* p); - -public: - RebuildRSOopClosure(G1RemSet* rs, uint worker_i = 0) : - _from(NULL), _rs(rs), _worker_i(worker_i) - {} - - void set_from(HeapRegion* from) { - assert(from != NULL, "from region must be non-NULL"); - _from = from; - } - - virtual void do_oop(narrowOop* p) { do_oop_work(p); } - virtual void do_oop(oop* p) { do_oop_work(p); } -}; - #endif // SHARE_VM_GC_G1_G1REMSET_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1RemSet.inline.hpp --- a/src/hotspot/share/gc/g1/g1RemSet.inline.hpp Mon Oct 30 08:34:54 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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. - * - */ - -#ifndef SHARE_VM_GC_G1_G1REMSET_INLINE_HPP -#define SHARE_VM_GC_G1_G1REMSET_INLINE_HPP - -#include "gc/g1/g1RemSet.hpp" -#include "gc/g1/heapRegion.hpp" -#include "gc/g1/heapRegionRemSet.hpp" -#include "oops/oop.inline.hpp" - -template -inline void G1RemSet::par_write_ref(HeapRegion* from, T* p, uint tid) { - oop obj = oopDesc::load_decode_heap_oop(p); - if (obj == NULL) { - return; - } - -#ifdef ASSERT - // can't do because of races - // assert(oopDesc::is_oop_or_null(obj), "expected an oop"); - assert(check_obj_alignment(obj), "not oop aligned"); - assert(_g1->is_in_reserved(obj), "must be in heap"); -#endif // ASSERT - - assert(from->is_in_reserved(p) || from->is_starts_humongous(), "p is not in from"); - - HeapRegion* to = _g1->heap_region_containing(obj); - if (from != to) { - assert(to->rem_set() != NULL, "Need per-region 'into' remsets."); - to->rem_set()->add_reference(p, tid); - } -} - -template -inline void RebuildRSOopClosure::do_oop_work(T* p) { - assert(_from != NULL, "from region must be non-NULL"); - _rs->par_write_ref(_from, p, _worker_i); -} - -#endif // SHARE_VM_GC_G1_G1REMSET_INLINE_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1RemSetSummary.cpp --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -26,7 +26,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentRefine.hpp" #include "gc/g1/g1ConcurrentRefineThread.hpp" -#include "gc/g1/g1RemSet.inline.hpp" +#include "gc/g1/g1RemSet.hpp" #include "gc/g1/g1RemSetSummary.hpp" #include "gc/g1/g1YoungRemSetSamplingThread.hpp" #include "gc/g1/heapRegion.hpp" diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1RootProcessor.cpp --- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -37,6 +37,7 @@ #include "gc/g1/g1RootClosures.hpp" #include "gc/g1/g1RootProcessor.hpp" #include "gc/g1/heapRegion.inline.hpp" +#include "gc/shared/weakProcessor.hpp" #include "memory/allocation.inline.hpp" #include "runtime/mutex.hpp" #include "services/management.hpp" @@ -319,6 +320,16 @@ } } +void G1RootProcessor::process_full_gc_weak_roots(OopClosure* oops) { + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_refProcessor_oops_do)) { + _g1h->ref_processor_stw()->weak_oops_do(oops); + } + + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_weakProcessor_oops_do)) { + WeakProcessor::oops_do(oops); + } +} + uint G1RootProcessor::n_workers() const { return _srs.n_threads(); } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1RootProcessor.hpp --- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -65,6 +65,7 @@ G1RP_PS_aot_oops_do, G1RP_PS_filter_satb_buffers, G1RP_PS_refProcessor_oops_do, + G1RP_PS_weakProcessor_oops_do, // Leave this one last. G1RP_PS_NumElements }; @@ -118,6 +119,10 @@ CLDClosure* clds, CodeBlobClosure* blobs); + // Apply closure to weak roots in the system. Used during the adjust phase + // for the Full GC. + void process_full_gc_weak_roots(OopClosure* oops); + // Number of worker threads used by the root processor. uint n_workers() const; }; diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1SerialFullCollector.cpp --- a/src/hotspot/share/gc/g1/g1SerialFullCollector.cpp Mon Oct 30 08:34:54 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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 "precompiled.hpp" -#include "gc/g1/g1CollectedHeap.inline.hpp" -#include "gc/g1/g1FullGCScope.hpp" -#include "gc/g1/g1MarkSweep.hpp" -#include "gc/g1/g1RemSet.inline.hpp" -#include "gc/g1/g1SerialFullCollector.hpp" -#include "gc/g1/heapRegionRemSet.hpp" -#include "gc/shared/referenceProcessor.hpp" - -G1SerialFullCollector::G1SerialFullCollector(G1FullGCScope* scope, - ReferenceProcessor* reference_processor) : - _scope(scope), - _reference_processor(reference_processor), - _is_alive_mutator(_reference_processor, NULL), - _mt_discovery_mutator(_reference_processor, false) { - // Temporarily make discovery by the STW ref processor single threaded (non-MT) - // and clear the STW ref processor's _is_alive_non_header field. -} - -void G1SerialFullCollector::prepare_collection() { - _reference_processor->enable_discovery(); - _reference_processor->setup_policy(_scope->should_clear_soft_refs()); -} - -void G1SerialFullCollector::complete_collection() { - // Enqueue any discovered reference objects that have - // not been removed from the discovered lists. - ReferenceProcessorPhaseTimes pt(NULL, _reference_processor->num_q()); - _reference_processor->enqueue_discovered_references(NULL, &pt); - pt.print_enqueue_phase(); - - // Iterate the heap and rebuild the remembered sets. - rebuild_remembered_sets(); -} - -void G1SerialFullCollector::collect() { - // Do the actual collection work. - G1MarkSweep::invoke_at_safepoint(_reference_processor, _scope->should_clear_soft_refs()); -} - -class PostMCRemSetClearClosure: public HeapRegionClosure { - G1CollectedHeap* _g1h; - ModRefBarrierSet* _mr_bs; -public: - PostMCRemSetClearClosure(G1CollectedHeap* g1h, ModRefBarrierSet* mr_bs) : - _g1h(g1h), _mr_bs(mr_bs) {} - - bool doHeapRegion(HeapRegion* r) { - HeapRegionRemSet* hrrs = r->rem_set(); - - _g1h->reset_gc_time_stamps(r); - - if (r->is_continues_humongous()) { - // We'll assert that the strong code root list and RSet is empty - assert(hrrs->strong_code_roots_list_length() == 0, "sanity"); - assert(hrrs->occupied() == 0, "RSet should be empty"); - } else { - hrrs->clear(); - } - // You might think here that we could clear just the cards - // corresponding to the used region. But no: if we leave a dirty card - // in a region we might allocate into, then it would prevent that card - // from being enqueued, and cause it to be missed. - // Re: the performance cost: we shouldn't be doing full GC anyway! - _mr_bs->clear(MemRegion(r->bottom(), r->end())); - - return false; - } -}; - - -class RebuildRSOutOfRegionClosure: public HeapRegionClosure { - G1CollectedHeap* _g1h; - RebuildRSOopClosure _cl; -public: - RebuildRSOutOfRegionClosure(G1CollectedHeap* g1, uint worker_i = 0) : - _cl(g1->g1_rem_set(), worker_i), - _g1h(g1) - { } - - bool doHeapRegion(HeapRegion* r) { - if (!r->is_continues_humongous()) { - _cl.set_from(r); - r->oop_iterate(&_cl); - } - return false; - } -}; - -class ParRebuildRSTask: public AbstractGangTask { - G1CollectedHeap* _g1; - HeapRegionClaimer _hrclaimer; - -public: - ParRebuildRSTask(G1CollectedHeap* g1) : - AbstractGangTask("ParRebuildRSTask"), _g1(g1), _hrclaimer(g1->workers()->active_workers()) {} - - void work(uint worker_id) { - RebuildRSOutOfRegionClosure rebuild_rs(_g1, worker_id); - _g1->heap_region_par_iterate(&rebuild_rs, worker_id, &_hrclaimer); - } -}; - -void G1SerialFullCollector::rebuild_remembered_sets() { - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - // First clear the stale remembered sets. - PostMCRemSetClearClosure rs_clear(g1h, g1h->g1_barrier_set()); - g1h->heap_region_iterate(&rs_clear); - - // Rebuild remembered sets of all regions. - uint n_workers = AdaptiveSizePolicy::calc_active_workers(g1h->workers()->total_workers(), - g1h->workers()->active_workers(), - Threads::number_of_non_daemon_threads()); - g1h->workers()->update_active_workers(n_workers); - log_info(gc,task)("Using %u workers of %u to rebuild remembered set", n_workers, g1h->workers()->total_workers()); - - ParRebuildRSTask rebuild_rs_task(g1h); - g1h->workers()->run_task(&rebuild_rs_task); -} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1SerialFullCollector.hpp --- a/src/hotspot/share/gc/g1/g1SerialFullCollector.hpp Mon Oct 30 08:34:54 2017 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/* - * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * 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. - * - */ - -#ifndef SHARE_VM_GC_G1_G1SERIALCOLLECTOR_HPP -#define SHARE_VM_GC_G1_G1SERIALCOLLECTOR_HPP - -#include "memory/allocation.hpp" - -class G1FullGCScope; -class ReferenceProcessor; - -class G1SerialFullCollector : StackObj { - G1FullGCScope* _scope; - ReferenceProcessor* _reference_processor; - ReferenceProcessorIsAliveMutator _is_alive_mutator; - ReferenceProcessorMTDiscoveryMutator _mt_discovery_mutator; - - void rebuild_remembered_sets(); - -public: - G1SerialFullCollector(G1FullGCScope* scope, ReferenceProcessor* reference_processor); - - void prepare_collection(); - void collect(); - void complete_collection(); -}; - -#endif // SHARE_VM_GC_G1_G1SERIALCOLLECTOR_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1StringDedup.cpp --- a/src/hotspot/share/gc/g1/g1StringDedup.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1StringDedup.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -65,10 +65,10 @@ return false; } -void G1StringDedup::enqueue_from_mark(oop java_string) { +void G1StringDedup::enqueue_from_mark(oop java_string, uint worker_id) { assert(is_enabled(), "String deduplication not enabled"); if (is_candidate_from_mark(java_string)) { - G1StringDedupQueue::push(0 /* worker_id */, java_string); + G1StringDedupQueue::push(worker_id, java_string); } } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1StringDedup.hpp --- a/src/hotspot/share/gc/g1/g1StringDedup.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1StringDedup.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -125,7 +125,7 @@ // Enqueues a deduplication candidate for later processing by the deduplication // thread. Before enqueuing, these functions apply the appropriate candidate // selection policy to filters out non-candidates. - static void enqueue_from_mark(oop java_string); + static void enqueue_from_mark(oop java_string, uint worker_id); static void enqueue_from_evacuation(bool from_young, bool to_young, unsigned int queue, oop java_string); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/g1_specialized_oop_closures.hpp --- a/src/hotspot/share/gc/g1/g1_specialized_oop_closures.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/g1_specialized_oop_closures.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -41,6 +41,9 @@ class G1CMOopClosure; class G1RootRegionScanClosure; +class G1MarkAndPushClosure; +class G1AdjustAndRebuildClosure; + #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f) \ f(G1ScanEvacuatedObjClosure,_nv) \ f(G1ScanObjsDuringUpdateRSClosure,_nv) \ @@ -49,4 +52,8 @@ f(G1CMOopClosure,_nv) \ f(G1RootRegionScanClosure,_nv) +#define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1FULL(f) \ + f(G1MarkAndPushClosure,_nv) \ + f(G1AdjustAndRebuildClosure,_nv) + #endif // SHARE_VM_GC_G1_G1_SPECIALIZED_OOP_CLOSURES_HPP diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/heapRegion.cpp --- a/src/hotspot/share/gc/g1/heapRegion.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/heapRegion.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -42,6 +42,7 @@ #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" #include "runtime/orderAccess.inline.hpp" +#include "utilities/growableArray.hpp" int HeapRegion::LogOfHRGrainBytes = 0; int HeapRegion::LogOfHRGrainWords = 0; @@ -106,14 +107,6 @@ } } -void HeapRegion::reset_after_compaction() { - G1ContiguousSpace::reset_after_compaction(); - // After a compaction the mark bitmap is invalid, so we must - // treat all objects as being inside the unmarked area. - zero_marked_bytes(); - init_top_at_mark_start(); -} - void HeapRegion::hr_clear(bool keep_remset, bool clear_space, bool locked) { assert(_humongous_start_region == NULL, "we should have already filtered out humongous regions"); @@ -278,10 +271,6 @@ (uint)allocation_context()); } -CompactibleSpace* HeapRegion::next_compaction_space() const { - return G1CollectedHeap::heap()->next_compaction_region(this); -} - void HeapRegion::note_self_forwarding_removal_start(bool during_initial_mark, bool during_conc_mark) { // We always recreate the prev marking info and we'll explicitly @@ -411,7 +400,7 @@ // We're not verifying code roots. return; } - if (vo == VerifyOption_G1UseMarkWord) { + if (vo == VerifyOption_G1UseFullMarking) { // Marking verification during a full GC is performed after class // unloading, code cache unloading, etc so the strong code roots // attached to each heap region are in an inconsistent state. They won't @@ -482,7 +471,7 @@ public: // _vo == UsePrevMarking -> use "prev" marking information, // _vo == UseNextMarking -> use "next" marking information, - // _vo == UseMarkWord -> use mark word from object header. + // _vo == UseFullMarking -> use "next" marking bitmap but no TAMS. G1VerificationClosure(G1CollectedHeap* g1h, VerifyOption vo) : _g1h(g1h), _bs(barrier_set_cast(g1h->barrier_set())), _containing_obj(NULL), _failures(false), _n_failures(0), _vo(vo) { @@ -833,7 +822,8 @@ } void HeapRegion::prepare_for_compaction(CompactPoint* cp) { - scan_and_forward(this, cp); + // Not used for G1 anymore, but pure virtual in Space. + ShouldNotReachHere(); } // G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/heapRegion.hpp --- a/src/hotspot/share/gc/g1/heapRegion.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/heapRegion.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -57,6 +57,7 @@ class G1CollectedHeap; class G1CMBitMap; +class G1IsAliveAndApplyClosure; class HeapRegionRemSet; class HeapRegionRemSetIterator; class HeapRegion; @@ -355,8 +356,14 @@ // and the amount of unallocated words if called on top() size_t block_size(const HeapWord* p) const; + // Scans through the region using the bitmap to determine what + // objects to call size_t ApplyToMarkedClosure::apply(oop) for. + template + inline void apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMarkedClosure* closure); // Override for scan_and_forward support. void prepare_for_compaction(CompactPoint* cp); + // Update heap region to be consistent after compaction. + void complete_compaction(); inline HeapWord* par_allocate_no_bot_updates(size_t min_word_size, size_t desired_word_size, size_t* word_size); inline HeapWord* allocate_no_bot_updates(size_t word_size); @@ -672,10 +679,6 @@ _predicted_elapsed_time_ms = ms; } - virtual CompactibleSpace* next_compaction_space() const; - - virtual void reset_after_compaction(); - // Routines for managing a list of code roots (attached to the // this region's RSet) that point into this heap region. void add_strong_code_root(nmethod* nm); @@ -693,9 +696,9 @@ void print() const; void print_on(outputStream* st) const; - // vo == UsePrevMarking -> use "prev" marking information, + // vo == UsePrevMarking -> use "prev" marking information, // vo == UseNextMarking -> use "next" marking information - // vo == UseMarkWord -> use the mark word in the object header + // vo == UseFullMarking -> use "next" marking bitmap but no TAMS // // NOTE: Only the "prev" marking information is guaranteed to be // consistent most of the time, so most calls to this should use @@ -704,7 +707,7 @@ // vo == UseNextMarking, which is to verify the "next" marking // information at the end of remark. // Currently there is only one place where this is called with - // vo == UseMarkWord, which is to verify the marking during a + // vo == UseFullMarking, which is to verify the marking during a // full GC. void verify(VerifyOption vo, bool *failures) const; diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/heapRegion.inline.hpp --- a/src/hotspot/share/gc/g1/heapRegion.inline.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/heapRegion.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -27,10 +27,12 @@ #include "gc/g1/g1BlockOffsetTable.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" +#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" #include "gc/g1/heapRegion.hpp" #include "gc/shared/space.hpp" #include "oops/oop.inline.hpp" #include "runtime/atomic.hpp" +#include "runtime/prefetch.inline.hpp" #include "utilities/align.hpp" inline HeapWord* G1ContiguousSpace::allocate_impl(size_t min_word_size, @@ -180,6 +182,45 @@ return block_size_using_bitmap(addr, G1CollectedHeap::heap()->concurrent_mark()->prev_mark_bitmap()); } +inline void HeapRegion::complete_compaction() { + // Reset space and bot after compaction is complete if needed. + reset_after_compaction(); + if (used_region().is_empty()) { + reset_bot(); + } + + // After a compaction the mark bitmap is invalid, so we must + // treat all objects as being inside the unmarked area. + zero_marked_bytes(); + init_top_at_mark_start(); + + // Clear unused heap memory in debug builds. + if (ZapUnusedHeapArea) { + mangle_unused_area(); + } +} + +template +inline void HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMarkedClosure* closure) { + HeapWord* limit = scan_limit(); + HeapWord* next_addr = bottom(); + + while (next_addr < limit) { + Prefetch::write(next_addr, PrefetchScanIntervalInBytes); + // This explicit is_marked check is a way to avoid + // some extra work done by get_next_marked_addr for + // the case where next_addr is marked. + if (bitmap->is_marked(next_addr)) { + oop current = oop(next_addr); + next_addr += closure->apply(current); + } else { + next_addr = bitmap->get_next_marked_addr(next_addr, limit); + } + } + + assert(next_addr == limit, "Should stop the scan at the limit."); +} + inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t min_word_size, size_t desired_word_size, size_t* actual_word_size) { diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/heapRegionManager.cpp --- a/src/hotspot/share/gc/g1/heapRegionManager.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/heapRegionManager.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -327,9 +327,7 @@ return true; } -void HeapRegionManager::par_iterate(HeapRegionClosure* blk, uint worker_id, HeapRegionClaimer* hrclaimer) const { - const uint start_index = hrclaimer->start_region_for_worker(worker_id); - +void HeapRegionManager::par_iterate(HeapRegionClosure* blk, HeapRegionClaimer* hrclaimer, const uint start_index) const { // Every worker will actually look at all regions, skipping over regions that // are currently not committed. // This also (potentially) iterates over regions newly allocated during GC. This @@ -493,7 +491,7 @@ } } -uint HeapRegionClaimer::start_region_for_worker(uint worker_id) const { +uint HeapRegionClaimer::offset_for_worker(uint worker_id) const { assert(worker_id < _n_workers, "Invalid worker_id."); return _n_regions * worker_id / _n_workers; } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/g1/heapRegionManager.hpp --- a/src/hotspot/share/gc/g1/heapRegionManager.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/g1/heapRegionManager.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -189,7 +189,7 @@ return _free_list.length(); } - size_t total_capacity_bytes() const { + size_t total_free_bytes() const { return num_free_regions() * HeapRegion::GrainBytes; } @@ -240,7 +240,7 @@ // terminating the iteration early if doHeapRegion() returns true. void iterate(HeapRegionClosure* blk) const; - void par_iterate(HeapRegionClosure* blk, uint worker_id, HeapRegionClaimer* hrclaimer) const; + void par_iterate(HeapRegionClosure* blk, HeapRegionClaimer* hrclaimer, const uint start_index) const; // Uncommit up to num_regions_to_remove regions that are completely free. // Return the actual number of uncommitted regions. @@ -274,9 +274,8 @@ return _n_regions; } - // Calculate the starting region for given worker so - // that they do not all start from the same region. - uint start_region_for_worker(uint worker_id) const; + // Return a start offset given a worker id. + uint offset_for_worker(uint worker_id) const; // Check if region has been claimed with this HRClaimer. bool is_region_claimed(uint region_index) const; diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/serial/markSweep.cpp --- a/src/hotspot/share/gc/serial/markSweep.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/serial/markSweep.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -65,13 +65,6 @@ CLDToOopClosure MarkSweep::adjust_cld_closure(&adjust_pointer_closure); inline void MarkSweep::mark_object(oop obj) { -#if INCLUDE_ALL_GCS - if (G1StringDedup::is_enabled()) { - // We must enqueue the object before it is marked - // as we otherwise can't read the object's age. - G1StringDedup::enqueue_from_mark(obj); - } -#endif // some marks may contain information we need to preserve so we store them away // and overwrite the mark. We'll restore it at the end of markSweep. markOop mark = obj->mark(); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/shared/gcName.hpp --- a/src/hotspot/share/gc/shared/gcName.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/shared/gcName.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ G1New, ConcurrentMarkSweep, G1Old, + G1Full, GCNameEndSentinel }; @@ -53,6 +54,7 @@ case G1New: return "G1New"; case ConcurrentMarkSweep: return "ConcurrentMarkSweep"; case G1Old: return "G1Old"; + case G1Full: return "G1Full"; default: ShouldNotReachHere(); return NULL; } } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/shared/gcTrace.hpp --- a/src/hotspot/share/gc/shared/gcTrace.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/shared/gcTrace.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -289,6 +289,12 @@ double predicted_marking_length, bool prediction_active); }; + +class G1FullGCTracer : public OldGCTracer { + public: + G1FullGCTracer() : OldGCTracer(G1Full) {} +}; + #endif class CMSTracer : public OldGCTracer { diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/shared/preservedMarks.cpp --- a/src/hotspot/share/gc/shared/preservedMarks.cpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/shared/preservedMarks.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,18 @@ assert_empty(); } +void PreservedMarks::adjust_during_full_gc() { + StackIterator iter(_stack); + while (!iter.is_empty()) { + OopAndMarkOop* elem = iter.next_addr(); + + oop obj = elem->get_oop(); + if (obj->is_forwarded()) { + elem->set_oop(obj->forwardee()); + } + } +} + void PreservedMarks::restore_and_increment(volatile size_t* const total_size_addr) { const size_t stack_size = size(); restore(); @@ -104,7 +116,6 @@ } }; - void PreservedMarksSet::reclaim() { assert_empty(); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/shared/preservedMarks.hpp --- a/src/hotspot/share/gc/shared/preservedMarks.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/shared/preservedMarks.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -35,7 +35,7 @@ class PreservedMarks VALUE_OBJ_CLASS_SPEC { private: - class OopAndMarkOop { + class OopAndMarkOop VALUE_OBJ_CLASS_SPEC { private: oop _o; markOop _m; @@ -43,23 +43,26 @@ public: OopAndMarkOop(oop obj, markOop m) : _o(obj), _m(m) { } - void set_mark() const { - _o->set_mark(_m); - } + oop get_oop() { return _o; } + void set_mark() const { _o->set_mark(_m); } + void set_oop(oop obj) { _o = obj; } }; typedef Stack OopAndMarkOopStack; OopAndMarkOopStack _stack; inline bool should_preserve_mark(oop obj, markOop m) const; - inline void push(oop obj, markOop m); public: size_t size() const { return _stack.size(); } + inline void push(oop obj, markOop m); inline void push_if_necessary(oop obj, markOop m); // Iterate over the stack, restore all preserved marks, and // reclaim the memory taken up by the stack segments. void restore(); + // Iterate over the stack, adjust all preserved marks according + // to their forwarding location stored in the mark. + void adjust_during_full_gc(); void restore_and_increment(volatile size_t* const _total_size_addr); inline static void init_forwarded_mark(oop obj); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/shared/specialized_oop_closures.hpp --- a/src/hotspot/share/gc/shared/specialized_oop_closures.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/shared/specialized_oop_closures.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -110,7 +110,8 @@ #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(f) \ - SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f) + SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f) \ + SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1FULL(f) #else // INCLUDE_ALL_GCS #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f) \ SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f) diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/shared/taskqueue.hpp --- a/src/hotspot/share/gc/shared/taskqueue.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/shared/taskqueue.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -369,6 +369,7 @@ typedef typename T::element_type E; GenericTaskQueueSet(int n); + ~GenericTaskQueueSet(); bool steal_best_of_2(uint queue_num, int* seed, E& t); diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/gc/shared/taskqueue.inline.hpp --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -42,6 +42,11 @@ } } +template +inline GenericTaskQueueSet::~GenericTaskQueueSet() { + FREE_C_HEAP_ARRAY(T*, _queues); +} + template inline void GenericTaskQueue::initialize() { _elems = ArrayAllocator::allocate(N, F); @@ -49,7 +54,6 @@ template inline GenericTaskQueue::~GenericTaskQueue() { - assert(false, "This code is currently never called"); ArrayAllocator::free(const_cast(_elems), N); } diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/hotspot/share/memory/universe.hpp --- a/src/hotspot/share/memory/universe.hpp Mon Oct 30 08:34:54 2017 +0100 +++ b/src/hotspot/share/memory/universe.hpp Tue Nov 14 11:33:23 2017 +0100 @@ -90,7 +90,7 @@ // G1 VerifyOption_G1UsePrevMarking = VerifyOption_Default, VerifyOption_G1UseNextMarking = VerifyOption_G1UsePrevMarking + 1, - VerifyOption_G1UseMarkWord = VerifyOption_G1UseNextMarking + 1 + VerifyOption_G1UseFullMarking = VerifyOption_G1UseNextMarking + 1 }; class Universe: AllStatic { diff -r 3cfab71d6c81 -r 5caa1d5f74c1 src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCName.java --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCName.java Mon Oct 30 08:34:54 2017 +0100 +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/GCName.java Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,7 @@ G1New ("G1New"), ConcurrentMarkSweep ("ConcurrentMarkSweep"), G1Old ("G1Old"), + G1Full ("G1Full"), GCNameEndSentinel ("GCNameEndSentinel"); private final String value; diff -r 3cfab71d6c81 -r 5caa1d5f74c1 test/hotspot/gtest/gc/g1/test_heapRegion.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/gtest/gc/g1/test_heapRegion.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/g1/g1BlockOffsetTable.hpp" +#include "gc/g1/g1CollectedHeap.hpp" +#include "gc/g1/g1ConcurrentMarkBitMap.inline.hpp" +#include "gc/g1/heapRegion.inline.hpp" +#include "gc/shared/referenceProcessor.hpp" +#include "unittest.hpp" + +class VerifyAndCountMarkClosure : public StackObj { + int _count; + G1CMBitMap* _bm; + + void ensure_marked(HeapWord* addr) { + ASSERT_TRUE(_bm->is_marked(addr)); + } + +public: + VerifyAndCountMarkClosure(G1CMBitMap* bm) : _count(0), _bm(bm) { } + + virtual size_t apply(oop object) { + _count++; + ensure_marked((HeapWord*) object); + // Must return positive size to advance the iteration. + return MinObjAlignment; + } + + void reset() { + _count = 0; + } + + int count() { + return _count; + } +}; + +#define MARK_OFFSET_1 ( 17 * MinObjAlignment) +#define MARK_OFFSET_2 ( 99 * MinObjAlignment) +#define MARK_OFFSET_3 (337 * MinObjAlignment) + +TEST_OTHER_VM(HeapRegion, apply_to_marked_objects) { + if (!UseG1GC) { + return; + } + + G1CollectedHeap* heap = G1CollectedHeap::heap(); + + // Using region 0 for testing. + HeapRegion* region = heap->heap_region_containing(heap->bottom_addr_for_region(0)); + + // Mark some "oops" in the bitmap. + G1CMBitMap* bitmap = heap->concurrent_mark()->next_mark_bitmap(); + bitmap->mark(region->bottom()); + bitmap->mark(region->bottom() + MARK_OFFSET_1); + bitmap->mark(region->bottom() + MARK_OFFSET_2); + bitmap->mark(region->bottom() + MARK_OFFSET_3); + bitmap->mark(region->end()); + + VerifyAndCountMarkClosure cl(bitmap); + + // When top is equal to bottom the closure should not be + // applied to any object because apply_to_marked_objects + // will stop at HeapRegion::scan_limit which is equal to top. + region->set_top(region->bottom()); + region->apply_to_marked_objects(bitmap, &cl); + EXPECT_EQ(0, cl.count()); + cl.reset(); + + // Set top to offset_1 and expect only to find 1 entry (bottom) + region->set_top(region->bottom() + MARK_OFFSET_1); + region->apply_to_marked_objects(bitmap, &cl); + EXPECT_EQ(1, cl.count()); + cl.reset(); + + // Set top to (offset_2 + 1) and expect only to find 3 + // entries (bottom, offset_1 and offset_2) + region->set_top(region->bottom() + MARK_OFFSET_2 + MinObjAlignment); + region->apply_to_marked_objects(bitmap, &cl); + EXPECT_EQ(3, cl.count()); + cl.reset(); + + // Still expect same 3 entries when top is (offset_3 - 1) + region->set_top(region->bottom() + MARK_OFFSET_3 - MinObjAlignment); + region->apply_to_marked_objects(bitmap, &cl); + EXPECT_EQ(3, cl.count()); + cl.reset(); + + // Setting top to end should render 4 entries. + region->set_top(region->end()); + region->apply_to_marked_objects(bitmap, &cl); + EXPECT_EQ(4, cl.count()); + cl.reset(); +} + diff -r 3cfab71d6c81 -r 5caa1d5f74c1 test/hotspot/gtest/gc/shared/test_preservedMarks.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/hotspot/gtest/gc/shared/test_preservedMarks.cpp Tue Nov 14 11:33:23 2017 +0100 @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * 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 "precompiled.hpp" +#include "gc/shared/preservedMarks.inline.hpp" +#include "unittest.hpp" + +class ScopedDisabledBiasedLocking { + bool _orig; +public: + ScopedDisabledBiasedLocking() : _orig(UseBiasedLocking) { UseBiasedLocking = false; } + ~ScopedDisabledBiasedLocking() { UseBiasedLocking = _orig; } +}; + +// Class to create a "fake" oop with a mark that will +// return true for calls to must_be_preserved(). +class FakeOop { + oopDesc _oop; + +public: + FakeOop() : _oop() { _oop.set_mark(originalMark()); } + + oop get_oop() { return &_oop; } + markOop mark() { return _oop.mark(); } + void set_mark(markOop m) { _oop.set_mark(m); } + void forward_to(oop obj) { + markOop m = markOopDesc::encode_pointer_as_mark(obj); + _oop.set_mark(m); + } + + static markOop originalMark() { return markOop(markOopDesc::lock_mask_in_place); } + static markOop changedMark() { return markOop(0x4711); } +}; + +TEST_VM(PreservedMarks, iterate_and_restore) { + // Need to disable biased locking to easily + // create oops that "must_be_preseved" + ScopedDisabledBiasedLocking dbl; + + PreservedMarks pm; + FakeOop o1; + FakeOop o2; + FakeOop o3; + FakeOop o4; + + // Make sure initial marks are correct. + ASSERT_EQ(o1.mark(), FakeOop::originalMark()); + ASSERT_EQ(o2.mark(), FakeOop::originalMark()); + ASSERT_EQ(o3.mark(), FakeOop::originalMark()); + ASSERT_EQ(o4.mark(), FakeOop::originalMark()); + + // Change the marks and verify change. + o1.set_mark(FakeOop::changedMark()); + o2.set_mark(FakeOop::changedMark()); + ASSERT_EQ(o1.mark(), FakeOop::changedMark()); + ASSERT_EQ(o2.mark(), FakeOop::changedMark()); + + // Push o1 and o2 to have their marks preserved. + pm.push(o1.get_oop(), o1.mark()); + pm.push(o2.get_oop(), o2.mark()); + + // Fake a move from o1->o3 and o2->o4. + o1.forward_to(o3.get_oop()); + o2.forward_to(o4.get_oop()); + ASSERT_EQ(o1.get_oop()->forwardee(), o3.get_oop()); + ASSERT_EQ(o2.get_oop()->forwardee(), o4.get_oop()); + // Adjust will update the PreservedMarks stack to + // make sure the mark is updated at the new location. + pm.adjust_during_full_gc(); + + // Restore all preserved and verify that the changed + // mark is now present at o3 and o4. + pm.restore(); + ASSERT_EQ(o3.mark(), FakeOop::changedMark()); + ASSERT_EQ(o4.mark(), FakeOop::changedMark()); +} diff -r 3cfab71d6c81 -r 5caa1d5f74c1 test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java --- a/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java Mon Oct 30 08:34:54 2017 +0100 +++ b/test/hotspot/jtreg/gc/arguments/TestMaxMinHeapFreeRatioFlags.java Tue Nov 14 11:33:23 2017 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -156,8 +156,9 @@ if (args.length != 3) { throw new IllegalArgumentException("Expected 3 args: "); } - if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.PSOld) { - System.out.println("Test is not applicable to parallel GC"); + if (GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.PSOld || + GCTypes.OldGCType.getOldGCType() == GCTypes.OldGCType.G1) { + System.out.println("Test is not applicable to parallel full GCs"); return; }