提交 27009359 编写于 作者: T tonyp

Merge

......@@ -541,9 +541,20 @@ jprt.make.rule.test.targets.standard.server = \
${jprt.my.windows.i586}-*-c2-servertest, \
${jprt.my.windows.x64}-*-c2-servertest
jprt.make.rule.test.targets.standard.internalvmtests = \
${jprt.my.solaris.sparc}-fastdebug-c2-internalvmtests, \
${jprt.my.solaris.sparcv9}-fastdebug-c2-internalvmtests, \
${jprt.my.solaris.i586}-fastdebug-c2-internalvmtests, \
${jprt.my.solaris.x64}-fastdebug-c2-internalvmtests, \
${jprt.my.linux.i586}-fastdebug-c2-internalvmtests, \
${jprt.my.linux.x64}-fastdebug-c2-internalvmtests, \
${jprt.my.windows.i586}-fastdebug-c2-internalvmtests, \
${jprt.my.windows.x64}-fastdebug-c2-internalvmtests
jprt.make.rule.test.targets.standard = \
${jprt.make.rule.test.targets.standard.client}, \
${jprt.make.rule.test.targets.standard.server}
${jprt.make.rule.test.targets.standard.server}, \
${jprt.make.rule.test.targets.standard.internalvmtests}
jprt.make.rule.test.targets.embedded = \
${jprt.make.rule.test.targets.standard.client}
......
......@@ -50,8 +50,8 @@
int CompactibleFreeListSpace::_lockRank = Mutex::leaf + 3;
// Defaults are 0 so things will break badly if incorrectly initialized.
int CompactibleFreeListSpace::IndexSetStart = 0;
int CompactibleFreeListSpace::IndexSetStride = 0;
size_t CompactibleFreeListSpace::IndexSetStart = 0;
size_t CompactibleFreeListSpace::IndexSetStride = 0;
size_t MinChunkSize = 0;
......@@ -62,7 +62,7 @@ void CompactibleFreeListSpace::set_cms_values() {
MinChunkSize = numQuanta(sizeof(FreeChunk), MinObjAlignmentInBytes) * MinObjAlignment;
assert(IndexSetStart == 0 && IndexSetStride == 0, "already set");
IndexSetStart = (int) MinChunkSize;
IndexSetStart = MinChunkSize;
IndexSetStride = MinObjAlignment;
}
......@@ -250,7 +250,7 @@ void CompactibleFreeListSpace::initializeIndexedFreeListArray() {
}
void CompactibleFreeListSpace::resetIndexedFreeListArray() {
for (int i = 1; i < IndexSetSize; i++) {
for (size_t i = 1; i < IndexSetSize; i++) {
assert(_indexedFreeList[i].size() == (size_t) i,
"Indexed free list sizes are incorrect");
_indexedFreeList[i].reset(IndexSetSize);
......@@ -337,7 +337,7 @@ size_t CompactibleFreeListSpace::sumIndexedFreeListArrayReturnedBytes() {
size_t CompactibleFreeListSpace::totalCountInIndexedFreeLists() const {
size_t count = 0;
for (int i = (int)MinChunkSize; i < IndexSetSize; i++) {
for (size_t i = IndexSetStart; i < IndexSetSize; i++) {
debug_only(
ssize_t total_list_count = 0;
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL;
......@@ -2200,7 +2200,7 @@ void CompactibleFreeListSpace::setFLHints() {
void CompactibleFreeListSpace::clearFLCensus() {
assert_locked();
int i;
size_t i;
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
FreeList *fl = &_indexedFreeList[i];
fl->set_prevSweep(fl->count());
......@@ -2494,7 +2494,7 @@ void CompactibleFreeListSpace::verifyFreeLists() const {
void CompactibleFreeListSpace::verifyIndexedFreeLists() const {
size_t i = 0;
for (; i < MinChunkSize; i++) {
for (; i < IndexSetStart; i++) {
guarantee(_indexedFreeList[i].head() == NULL, "should be NULL");
}
for (; i < IndexSetSize; i++) {
......@@ -2507,7 +2507,7 @@ void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const {
FreeChunk* tail = _indexedFreeList[size].tail();
size_t num = _indexedFreeList[size].count();
size_t n = 0;
guarantee(((size >= MinChunkSize) && (size % IndexSetStride == 0)) || fc == NULL,
guarantee(((size >= IndexSetStart) && (size % IndexSetStride == 0)) || fc == NULL,
"Slot should have been empty");
for (; fc != NULL; fc = fc->next(), n++) {
guarantee(fc->size() == size, "Size inconsistency");
......@@ -2527,7 +2527,7 @@ void CompactibleFreeListSpace::check_free_list_consistency() const {
"else MIN_TREE_CHUNK_SIZE is wrong");
assert((IndexSetStride == 2 && IndexSetStart == 4) || // 32-bit
(IndexSetStride == 1 && IndexSetStart == 3), "just checking"); // 64-bit
assert((IndexSetStride != 2) || (MinChunkSize % 2 == 0),
assert((IndexSetStride != 2) || (IndexSetStart % 2 == 0),
"Some for-loops may be incorrectly initialized");
assert((IndexSetStride != 2) || (IndexSetSize % 2 == 1),
"For-loops that iterate over IndexSet with stride 2 may be wrong");
......
......@@ -104,8 +104,8 @@ class CompactibleFreeListSpace: public CompactibleSpace {
SmallForDictionary = 257, // size < this then use _indexedFreeList
IndexSetSize = SmallForDictionary // keep this odd-sized
};
static int IndexSetStart;
static int IndexSetStride;
static size_t IndexSetStart;
static size_t IndexSetStride;
private:
enum FitStrategyOptions {
......
......@@ -1518,6 +1518,7 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
size_t _regions_claimed;
size_t _freed_bytes;
FreeRegionList* _local_cleanup_list;
OldRegionSet* _old_proxy_set;
HumongousRegionSet* _humongous_proxy_set;
HRRSCleanupTask* _hrrs_cleanup_task;
double _claimed_region_time;
......@@ -1527,6 +1528,7 @@ public:
G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
int worker_num,
FreeRegionList* local_cleanup_list,
OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task);
size_t freed_bytes() { return _freed_bytes; }
......@@ -1557,9 +1559,11 @@ public:
void work(int i) {
double start = os::elapsedTime();
FreeRegionList local_cleanup_list("Local Cleanup List");
OldRegionSet old_proxy_set("Local Cleanup Old Proxy Set");
HumongousRegionSet humongous_proxy_set("Local Cleanup Humongous Proxy Set");
HRRSCleanupTask hrrs_cleanup_task;
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, i, &local_cleanup_list,
&old_proxy_set,
&humongous_proxy_set,
&hrrs_cleanup_task);
if (G1CollectedHeap::use_parallel_gc_threads()) {
......@@ -1573,6 +1577,7 @@ public:
// Now update the lists
_g1h->update_sets_after_freeing_regions(g1_note_end.freed_bytes(),
NULL /* free_list */,
&old_proxy_set,
&humongous_proxy_set,
true /* par */);
{
......@@ -1643,6 +1648,7 @@ G1NoteEndOfConcMarkClosure::
G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
int worker_num,
FreeRegionList* local_cleanup_list,
OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task)
: _g1(g1), _worker_num(worker_num),
......@@ -1650,6 +1656,7 @@ G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
_freed_bytes(0),
_claimed_region_time(0.0), _max_region_time(0.0),
_local_cleanup_list(local_cleanup_list),
_old_proxy_set(old_proxy_set),
_humongous_proxy_set(humongous_proxy_set),
_hrrs_cleanup_task(hrrs_cleanup_task) { }
......@@ -1665,6 +1672,7 @@ bool G1NoteEndOfConcMarkClosure::doHeapRegion(HeapRegion *hr) {
_g1->free_region_if_empty(hr,
&_freed_bytes,
_local_cleanup_list,
_old_proxy_set,
_humongous_proxy_set,
_hrrs_cleanup_task,
true /* par */);
......@@ -1689,6 +1697,7 @@ void ConcurrentMark::cleanup() {
return;
}
HRSPhaseSetter x(HRSPhaseCleanup);
g1h->verify_region_sets_optional();
if (VerifyDuringGC) {
......
......@@ -1203,6 +1203,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
Universe::print_heap_before_gc();
}
HRSPhaseSetter x(HRSPhaseFullGC);
verify_region_sets_optional();
const bool do_clear_all_soft_refs = clear_all_soft_refs ||
......@@ -1263,7 +1264,6 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
release_mutator_alloc_region();
abandon_gc_alloc_regions();
g1_rem_set()->cleanupHRRS();
tear_down_region_lists();
// We should call this after we retire any currently active alloc
// regions so that all the ALLOC / RETIRE events are generated
......@@ -1278,7 +1278,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
g1_policy()->clear_incremental_cset();
g1_policy()->stop_incremental_cset_building();
empty_young_list();
tear_down_region_sets(false /* free_list_only */);
g1_policy()->set_full_young_gcs(true);
// See the comments in g1CollectedHeap.hpp and
......@@ -1301,9 +1301,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
}
assert(free_regions() == 0, "we should not have added any free regions");
rebuild_region_lists();
_summary_bytes_used = recalculate_used();
rebuild_region_sets(false /* free_list_only */);
// Enqueue any discovered reference objects that have
// not been removed from the discovered lists.
......@@ -1764,9 +1762,9 @@ void G1CollectedHeap::shrink(size_t shrink_bytes) {
// Instead of tearing down / rebuilding the free lists here, we
// could instead use the remove_all_pending() method on free_list to
// remove only the ones that we need to remove.
tear_down_region_lists(); // We will rebuild them in a moment.
tear_down_region_sets(true /* free_list_only */);
shrink_helper(shrink_bytes);
rebuild_region_lists();
rebuild_region_sets(true /* free_list_only */);
_hrs.verify_optional();
verify_region_sets_optional();
......@@ -1799,6 +1797,7 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* policy_) :
_full_collection(false),
_free_list("Master Free List"),
_secondary_free_list("Secondary Free List"),
_old_set("Old Set"),
_humongous_set("Master Humongous Set"),
_free_regions_coming(false),
_young_list(new YoungList(this)),
......@@ -3007,7 +3006,10 @@ void G1CollectedHeap::verify(bool allow_dirty,
if (failures) {
gclog_or_tty->print_cr("Heap:");
print_on(gclog_or_tty, true /* extended */);
// It helps to have the per-region information in the output to
// help us track down what went wrong. This is why we call
// print_extended_on() instead of print_on().
print_extended_on(gclog_or_tty);
gclog_or_tty->print_cr("");
#ifndef PRODUCT
if (VerifyDuringGC && G1VerifyDuringGCPrintReachable) {
......@@ -3033,13 +3035,7 @@ public:
}
};
void G1CollectedHeap::print() const { print_on(tty); }
void G1CollectedHeap::print_on(outputStream* st) const {
print_on(st, PrintHeapAtGCExtended);
}
void G1CollectedHeap::print_on(outputStream* st, bool extended) const {
st->print(" %-20s", "garbage-first heap");
st->print(" total " SIZE_FORMAT "K, used " SIZE_FORMAT "K",
capacity()/K, used_unlocked()/K);
......@@ -3057,13 +3053,14 @@ void G1CollectedHeap::print_on(outputStream* st, bool extended) const {
survivor_regions, survivor_regions * HeapRegion::GrainBytes / K);
st->cr();
perm()->as_gen()->print_on(st);
if (extended) {
st->cr();
print_on_extended(st);
}
}
void G1CollectedHeap::print_on_extended(outputStream* st) const {
void G1CollectedHeap::print_extended_on(outputStream* st) const {
print_on(st);
// Print the per-region information.
st->cr();
st->print_cr("Heap Regions: (Y=young(eden), SU=young(survivor), HS=humongous(starts), HC=humongous(continues), CS=collection set, F=free, TS=gc time stamp, PTAMS=previous top-at-mark-start, NTAMS=next top-at-mark-start)");
PrintRegionClosure blk(st);
heap_region_iterate(&blk);
}
......@@ -3352,6 +3349,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
Universe::print_heap_before_gc();
}
HRSPhaseSetter x(HRSPhaseEvacuation);
verify_region_sets_optional();
verify_dirty_young_regions();
......@@ -3774,6 +3772,11 @@ void G1CollectedHeap::init_gc_alloc_regions() {
!retained_region->is_empty() &&
!retained_region->isHumongous()) {
retained_region->set_saved_mark();
// The retained region was added to the old region set when it was
// retired. We have to remove it now, since we don't allow regions
// we allocate to in the region sets. We'll re-add it later, when
// it's retired again.
_old_set.remove(retained_region);
_old_gc_alloc_region.set(retained_region);
_hr_printer.reuse(retained_region);
}
......@@ -5338,6 +5341,7 @@ void G1CollectedHeap::evacuate_collection_set() {
void G1CollectedHeap::free_region_if_empty(HeapRegion* hr,
size_t* pre_used,
FreeRegionList* free_list,
OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task,
bool par) {
......@@ -5346,6 +5350,7 @@ void G1CollectedHeap::free_region_if_empty(HeapRegion* hr,
assert(hr->startsHumongous(), "we should only see starts humongous");
free_humongous_region(hr, pre_used, free_list, humongous_proxy_set, par);
} else {
_old_set.remove_with_proxy(hr, old_proxy_set);
free_region(hr, pre_used, free_list, par);
}
} else {
......@@ -5402,6 +5407,7 @@ void G1CollectedHeap::free_humongous_region(HeapRegion* hr,
void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used,
FreeRegionList* free_list,
OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
bool par) {
if (pre_used > 0) {
......@@ -5417,6 +5423,10 @@ void G1CollectedHeap::update_sets_after_freeing_regions(size_t pre_used,
MutexLockerEx x(FreeList_lock, Mutex::_no_safepoint_check_flag);
_free_list.add_as_head(free_list);
}
if (old_proxy_set != NULL && !old_proxy_set->is_empty()) {
MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag);
_old_set.update_from_proxy(old_proxy_set);
}
if (humongous_proxy_set != NULL && !humongous_proxy_set->is_empty()) {
MutexLockerEx x(OldSets_lock, Mutex::_no_safepoint_check_flag);
_humongous_set.update_from_proxy(humongous_proxy_set);
......@@ -5614,6 +5624,8 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) {
cur->set_young_index_in_cset(-1);
cur->set_not_young();
cur->set_evacuation_failed(false);
// The region is now considered to be old.
_old_set.add(cur);
}
cur = next;
}
......@@ -5629,6 +5641,7 @@ void G1CollectedHeap::free_collection_set(HeapRegion* cs_head) {
young_time_ms += elapsed_ms;
update_sets_after_freeing_regions(pre_used, &local_free_list,
NULL /* old_proxy_set */,
NULL /* humongous_proxy_set */,
false /* par */);
policy->record_young_free_cset_time_ms(young_time_ms);
......@@ -5740,52 +5753,106 @@ bool G1CollectedHeap::check_young_list_empty(bool check_heap, bool check_sample)
return ret;
}
void G1CollectedHeap::empty_young_list() {
assert(heap_lock_held_for_gc(),
"the heap lock should already be held by or for this thread");
class TearDownRegionSetsClosure : public HeapRegionClosure {
private:
OldRegionSet *_old_set;
_young_list->empty_list();
}
public:
TearDownRegionSetsClosure(OldRegionSet* old_set) : _old_set(old_set) { }
bool doHeapRegion(HeapRegion* r) {
if (r->is_empty()) {
// We ignore empty regions, we'll empty the free list afterwards
} else if (r->is_young()) {
// We ignore young regions, we'll empty the young list afterwards
} else if (r->isHumongous()) {
// We ignore humongous regions, we're not tearing down the
// humongous region set
} else {
// The rest should be old
_old_set->remove(r);
}
return false;
}
~TearDownRegionSetsClosure() {
assert(_old_set->is_empty(), "post-condition");
}
};
void G1CollectedHeap::tear_down_region_sets(bool free_list_only) {
assert_at_safepoint(true /* should_be_vm_thread */);
if (!free_list_only) {
TearDownRegionSetsClosure cl(&_old_set);
heap_region_iterate(&cl);
// Done at the start of full GC.
void G1CollectedHeap::tear_down_region_lists() {
// Need to do this after the heap iteration to be able to
// recognize the young regions and ignore them during the iteration.
_young_list->empty_list();
}
_free_list.remove_all();
}
class RegionResetter: public HeapRegionClosure {
G1CollectedHeap* _g1h;
FreeRegionList _local_free_list;
class RebuildRegionSetsClosure : public HeapRegionClosure {
private:
bool _free_list_only;
OldRegionSet* _old_set;
FreeRegionList* _free_list;
size_t _total_used;
public:
RegionResetter() : _g1h(G1CollectedHeap::heap()),
_local_free_list("Local Free List for RegionResetter") { }
RebuildRegionSetsClosure(bool free_list_only,
OldRegionSet* old_set, FreeRegionList* free_list) :
_free_list_only(free_list_only),
_old_set(old_set), _free_list(free_list), _total_used(0) {
assert(_free_list->is_empty(), "pre-condition");
if (!free_list_only) {
assert(_old_set->is_empty(), "pre-condition");
}
}
bool doHeapRegion(HeapRegion* r) {
if (r->continuesHumongous()) return false;
if (r->top() > r->bottom()) {
if (r->top() < r->end()) {
Copy::fill_to_words(r->top(),
pointer_delta(r->end(), r->top()));
if (r->continuesHumongous()) {
return false;
}
if (r->is_empty()) {
// Add free regions to the free list
_free_list->add_as_tail(r);
} else if (!_free_list_only) {
assert(!r->is_young(), "we should not come across young regions");
if (r->isHumongous()) {
// We ignore humongous regions, we left the humongous set unchanged
} else {
// The rest should be old, add them to the old set
_old_set->add(r);
}
} else {
assert(r->is_empty(), "tautology");
_local_free_list.add_as_tail(r);
_total_used += r->used();
}
return false;
}
void update_free_lists() {
_g1h->update_sets_after_freeing_regions(0, &_local_free_list, NULL,
false /* par */);
size_t total_used() {
return _total_used;
}
};
// Done at the end of full GC.
void G1CollectedHeap::rebuild_region_lists() {
// This needs to go at the end of the full GC.
RegionResetter rs;
heap_region_iterate(&rs);
rs.update_free_lists();
void G1CollectedHeap::rebuild_region_sets(bool free_list_only) {
assert_at_safepoint(true /* should_be_vm_thread */);
RebuildRegionSetsClosure cl(free_list_only, &_old_set, &_free_list);
heap_region_iterate(&cl);
if (!free_list_only) {
_summary_bytes_used = cl.total_used();
}
assert(_summary_bytes_used == recalculate_used(),
err_msg("inconsistent _summary_bytes_used, "
"value: "SIZE_FORMAT" recalculated: "SIZE_FORMAT,
_summary_bytes_used, recalculate_used()));
}
void G1CollectedHeap::set_refine_cte_cl_concurrency(bool concurrent) {
......@@ -5882,6 +5949,8 @@ void G1CollectedHeap::retire_gc_alloc_region(HeapRegion* alloc_region,
g1_policy()->record_bytes_copied_during_gc(allocated_bytes);
if (ap == GCAllocForSurvived) {
young_list()->add_survivor_region(alloc_region);
} else {
_old_set.add(alloc_region);
}
_hr_printer.retire(alloc_region);
}
......@@ -5913,15 +5982,17 @@ void OldGCAllocRegion::retire_region(HeapRegion* alloc_region,
class VerifyRegionListsClosure : public HeapRegionClosure {
private:
HumongousRegionSet* _humongous_set;
FreeRegionList* _free_list;
OldRegionSet* _old_set;
HumongousRegionSet* _humongous_set;
size_t _region_count;
public:
VerifyRegionListsClosure(HumongousRegionSet* humongous_set,
VerifyRegionListsClosure(OldRegionSet* old_set,
HumongousRegionSet* humongous_set,
FreeRegionList* free_list) :
_humongous_set(humongous_set), _free_list(free_list),
_region_count(0) { }
_old_set(old_set), _humongous_set(humongous_set),
_free_list(free_list), _region_count(0) { }
size_t region_count() { return _region_count; }
......@@ -5938,6 +6009,8 @@ public:
_humongous_set->verify_next_region(hr);
} else if (hr->is_empty()) {
_free_list->verify_next_region(hr);
} else {
_old_set->verify_next_region(hr);
}
return false;
}
......@@ -5964,6 +6037,7 @@ void G1CollectedHeap::verify_region_sets() {
MutexLockerEx x(SecondaryFreeList_lock, Mutex::_no_safepoint_check_flag);
_secondary_free_list.verify();
}
_old_set.verify();
_humongous_set.verify();
// If a concurrent region freeing operation is in progress it will
......@@ -5987,12 +6061,14 @@ void G1CollectedHeap::verify_region_sets() {
// Finally, make sure that the region accounting in the lists is
// consistent with what we see in the heap.
_old_set.verify_start();
_humongous_set.verify_start();
_free_list.verify_start();
VerifyRegionListsClosure cl(&_humongous_set, &_free_list);
VerifyRegionListsClosure cl(&_old_set, &_humongous_set, &_free_list);
heap_region_iterate(&cl);
_old_set.verify_end();
_humongous_set.verify_end();
_free_list.verify_end();
}
......@@ -239,6 +239,9 @@ private:
// master free list when appropriate.
SecondaryFreeRegionList _secondary_free_list;
// It keeps track of the old regions.
MasterOldRegionSet _old_set;
// It keeps track of the humongous regions.
MasterHumongousRegionSet _humongous_set;
......@@ -248,10 +251,21 @@ private:
// The block offset table for the G1 heap.
G1BlockOffsetSharedArray* _bot_shared;
// Move all of the regions off the free lists, then rebuild those free
// lists, before and after full GC.
void tear_down_region_lists();
void rebuild_region_lists();
// Tears down the region sets / lists so that they are empty and the
// regions on the heap do not belong to a region set / list. The
// only exception is the humongous set which we leave unaltered. If
// free_list_only is true, it will only tear down the master free
// list. It is called before a Full GC (free_list_only == false) or
// before heap shrinking (free_list_only == true).
void tear_down_region_sets(bool free_list_only);
// Rebuilds the region sets / lists so that they are repopulated to
// reflect the contents of the heap. The only exception is the
// humongous set which was not torn down in the first place. If
// free_list_only is true, it will only rebuild the master free
// list. It is called after a Full GC (free_list_only == false) or
// after heap shrinking (free_list_only == true).
void rebuild_region_sets(bool free_list_only);
// The sequence of all heap regions in the heap.
HeapRegionSeq _hrs;
......@@ -1124,6 +1138,10 @@ public:
}
}
void old_set_remove(HeapRegion* hr) {
_old_set.remove(hr);
}
void set_free_regions_coming();
void reset_free_regions_coming();
bool free_regions_coming() { return _free_regions_coming; }
......@@ -1153,6 +1171,7 @@ public:
void free_region_if_empty(HeapRegion* hr,
size_t* pre_used,
FreeRegionList* free_list,
OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
HRRSCleanupTask* hrrs_cleanup_task,
bool par);
......@@ -1163,6 +1182,7 @@ public:
// (if par is true, it will do so by taking the ParGCRareEvent_lock).
void update_sets_after_freeing_regions(size_t pre_used,
FreeRegionList* free_list,
OldRegionSet* old_proxy_set,
HumongousRegionSet* humongous_proxy_set,
bool par);
......@@ -1429,14 +1449,8 @@ public:
// Override; it uses the "prev" marking information
virtual void verify(bool allow_dirty, bool silent);
// Default behavior by calling print(tty);
virtual void print() const;
// This calls print_on(st, PrintHeapAtGCExtended).
virtual void print_on(outputStream* st) const;
// If extended is true, it will print out information for all
// regions in the heap by calling print_on_extended(st).
virtual void print_on(outputStream* st, bool extended) const;
virtual void print_on_extended(outputStream* st) const;
virtual void print_extended_on(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
......@@ -1452,8 +1466,6 @@ public:
// asserted to be this type.
static G1CollectedHeap* heap();
void empty_young_list();
void set_region_short_lived_locked(HeapRegion* hr);
// add appropriate methods for any other surv rate groups
......
......@@ -3015,6 +3015,7 @@ void G1CollectorPolicy::choose_collection_set(double target_pause_time_ms) {
hr = _collectionSetChooser->getNextMarkedRegion(time_remaining_ms,
avg_prediction);
if (hr != NULL) {
_g1->old_set_remove(hr);
double predicted_time_ms = predict_region_elapsed_time_ms(hr, false);
time_remaining_ms -= predicted_time_ms;
predicted_pause_time_ms += predicted_time_ms;
......
......@@ -236,6 +236,7 @@ public:
// at the end of the GC, so no point in updating those values here.
_g1h->update_sets_after_freeing_regions(0, /* pre_used */
NULL, /* free_list */
NULL, /* old_proxy_set */
&_humongous_proxy_set,
false /* par */);
}
......
......@@ -635,10 +635,18 @@ bool G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
ct_freq_note_card(_ct_bs->index_for(start));
#endif
assert(!check_for_refs_into_cset || _cset_rs_update_cl[worker_i] != NULL, "sanity");
OopsInHeapRegionClosure* oops_in_heap_closure = NULL;
if (check_for_refs_into_cset) {
// ConcurrentG1RefineThreads have worker numbers larger than what
// _cset_rs_update_cl[] is set up to handle. But those threads should
// only be active outside of a collection which means that when they
// reach here they should have check_for_refs_into_cset == false.
assert((size_t)worker_i < n_workers(), "index of worker larger than _cset_rs_update_cl[].length");
oops_in_heap_closure = _cset_rs_update_cl[worker_i];
}
UpdateRSOrPushRefOopClosure update_rs_oop_cl(_g1,
_g1->g1_rem_set(),
_cset_rs_update_cl[worker_i],
oops_in_heap_closure,
check_for_refs_into_cset,
worker_i);
update_rs_oop_cl.set_from(r);
......
......@@ -722,7 +722,7 @@ void HeapRegion::print_on(outputStream* st) const {
st->print(" F");
else
st->print(" ");
st->print(" %5d", _gc_time_stamp);
st->print(" TS %5d", _gc_time_stamp);
st->print(" PTAMS "PTR_FORMAT" NTAMS "PTR_FORMAT,
prev_top_at_mark_start(), next_top_at_mark_start());
G1OffsetTableContigSpace::print_on(st);
......
......@@ -26,6 +26,7 @@
#include "gc_implementation/g1/heapRegionSet.inline.hpp"
size_t HeapRegionSetBase::_unrealistically_long_length = 0;
HRSPhase HeapRegionSetBase::_phase = HRSPhaseNone;
//////////////////// HeapRegionSetBase ////////////////////
......@@ -192,6 +193,17 @@ void HeapRegionSetBase::verify_end() {
_verify_in_progress = false;
}
void HeapRegionSetBase::clear_phase() {
assert(_phase != HRSPhaseNone, "pre-condition");
_phase = HRSPhaseNone;
}
void HeapRegionSetBase::set_phase(HRSPhase phase) {
assert(_phase == HRSPhaseNone, "pre-condition");
assert(phase != HRSPhaseNone, "pre-condition");
_phase = phase;
}
void HeapRegionSetBase::print_on(outputStream* out, bool print_contents) {
out->cr();
out->print_cr("Set: %s ("PTR_FORMAT")", name(), this);
......
......@@ -47,8 +47,18 @@ typedef FormatBuffer<HRS_ERR_MSG_BUFSZ> hrs_err_msg;
class hrs_ext_msg;
typedef enum {
HRSPhaseNone,
HRSPhaseEvacuation,
HRSPhaseCleanup,
HRSPhaseFullGC
} HRSPhase;
class HRSPhaseSetter;
class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC {
friend class hrs_ext_msg;
friend class HRSPhaseSetter;
protected:
static size_t calculate_region_num(HeapRegion* hr);
......@@ -80,6 +90,15 @@ protected:
size_t _calc_total_capacity_bytes;
size_t _calc_total_used_bytes;
// This is here so that it can be used in the subclasses to assert
// something different depending on which phase the GC is in. This
// can be particularly helpful in the check_mt_safety() methods.
static HRSPhase _phase;
// Only used by HRSPhaseSetter.
static void clear_phase();
static void set_phase(HRSPhase phase);
// verify_region() is used to ensure that the contents of a region
// added to / removed from a set are consistent. Different sets
// make different assumptions about the regions added to them. So
......@@ -177,6 +196,16 @@ public:
}
};
class HRSPhaseSetter {
public:
HRSPhaseSetter(HRSPhase phase) {
HeapRegionSetBase::set_phase(phase);
}
~HRSPhaseSetter() {
HeapRegionSetBase::clear_phase();
}
};
// These two macros are provided for convenience, to keep the uses of
// these two asserts a bit more concise.
......
......@@ -26,6 +26,17 @@
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#include "gc_implementation/g1/heapRegionSets.hpp"
// Note on the check_mt_safety() methods below:
//
// Verification of the "master" heap region sets / lists that are
// maintained by G1CollectedHeap is always done during a STW pause and
// by the VM thread at the start / end of the pause. The standard
// verification methods all assert check_mt_safety(). This is
// important as it ensures that verification is done without
// concurrent updates taking place at the same time. It follows, that,
// for the "master" heap region sets / lists, the check_mt_safety()
// method should include the VM thread / STW case.
//////////////////// FreeRegionList ////////////////////
const char* FreeRegionList::verify_region_extra(HeapRegion* hr) {
......@@ -33,7 +44,7 @@ const char* FreeRegionList::verify_region_extra(HeapRegion* hr) {
return "the region should not be young";
}
// The superclass will check that the region is empty and
// not-humongous.
// not humongous.
return HeapRegionLinkedList::verify_region_extra(hr);
}
......@@ -58,12 +69,16 @@ bool MasterFreeRegionList::check_mt_safety() {
// (b) If we're not at a safepoint, operations on the master free
// list should be invoked while holding the Heap_lock.
guarantee((SafepointSynchronize::is_at_safepoint() &&
(Thread::current()->is_VM_thread() ||
FreeList_lock->owned_by_self())) ||
(!SafepointSynchronize::is_at_safepoint() &&
Heap_lock->owned_by_self()),
hrs_ext_msg(this, "master free list MT safety protocol"));
if (SafepointSynchronize::is_at_safepoint()) {
guarantee(Thread::current()->is_VM_thread() ||
FreeList_lock->owned_by_self(),
hrs_ext_msg(this, "master free list MT safety protocol "
"at a safepoint"));
} else {
guarantee(Heap_lock->owned_by_self(),
hrs_ext_msg(this, "master free list MT safety protocol "
"outside a safepoint"));
}
return FreeRegionList::check_mt_safety();
}
......@@ -81,6 +96,48 @@ bool SecondaryFreeRegionList::check_mt_safety() {
return FreeRegionList::check_mt_safety();
}
//////////////////// OldRegionSet ////////////////////
const char* OldRegionSet::verify_region_extra(HeapRegion* hr) {
if (hr->is_young()) {
return "the region should not be young";
}
// The superclass will check that the region is not empty and not
// humongous.
return HeapRegionSet::verify_region_extra(hr);
}
//////////////////// MasterOldRegionSet ////////////////////
bool MasterOldRegionSet::check_mt_safety() {
// Master Old Set MT safety protocol:
// (a) If we're at a safepoint, operations on the master old set
// should be invoked:
// - by the VM thread (which will serialize them), or
// - by the GC workers while holding the FreeList_lock, if we're
// at a safepoint for an evacuation pause (this lock is taken
// anyway when an GC alloc region is retired so that a new one
// is allocated from the free list), or
// - by the GC workers while holding the OldSets_lock, if we're at a
// safepoint for a cleanup pause.
// (b) If we're not at a safepoint, operations on the master old set
// should be invoked while holding the Heap_lock.
if (SafepointSynchronize::is_at_safepoint()) {
guarantee(Thread::current()->is_VM_thread() ||
_phase == HRSPhaseEvacuation && FreeList_lock->owned_by_self() ||
_phase == HRSPhaseCleanup && OldSets_lock->owned_by_self(),
hrs_ext_msg(this, "master old set MT safety protocol "
"at a safepoint"));
} else {
guarantee(Heap_lock->owned_by_self(),
hrs_ext_msg(this, "master old set MT safety protocol "
"outside a safepoint"));
}
return OldRegionSet::check_mt_safety();
}
//////////////////// HumongousRegionSet ////////////////////
const char* HumongousRegionSet::verify_region_extra(HeapRegion* hr) {
......@@ -103,11 +160,16 @@ bool MasterHumongousRegionSet::check_mt_safety() {
// (b) If we're not at a safepoint, operations on the master
// humongous set should be invoked while holding the Heap_lock.
guarantee((SafepointSynchronize::is_at_safepoint() &&
(Thread::current()->is_VM_thread() ||
OldSets_lock->owned_by_self())) ||
(!SafepointSynchronize::is_at_safepoint() &&
Heap_lock->owned_by_self()),
hrs_ext_msg(this, "master humongous set MT safety protocol"));
if (SafepointSynchronize::is_at_safepoint()) {
guarantee(Thread::current()->is_VM_thread() ||
OldSets_lock->owned_by_self(),
hrs_ext_msg(this, "master humongous set MT safety protocol "
"at a safepoint"));
} else {
guarantee(Heap_lock->owned_by_self(),
hrs_ext_msg(this, "master humongous set MT safety protocol "
"outside a safepoint"));
}
return HumongousRegionSet::check_mt_safety();
}
......@@ -61,6 +61,30 @@ public:
SecondaryFreeRegionList(const char* name) : FreeRegionList(name) { }
};
//////////////////// OldRegionSet ////////////////////
class OldRegionSet : public HeapRegionSet {
protected:
virtual const char* verify_region_extra(HeapRegion* hr);
virtual bool regions_humongous() { return false; }
virtual bool regions_empty() { return false; }
public:
OldRegionSet(const char* name) : HeapRegionSet(name) { }
};
//////////////////// MasterOldRegionSet ////////////////////
class MasterOldRegionSet : public OldRegionSet {
private:
protected:
virtual bool check_mt_safety();
public:
MasterOldRegionSet(const char* name) : OldRegionSet(name) { }
};
//////////////////// HumongousRegionSet ////////////////////
class HumongousRegionSet : public HeapRegionSet {
......
......@@ -863,8 +863,6 @@ void ParallelScavengeHeap::prepare_for_verify() {
ensure_parsability(false); // no need to retire TLABs for verification
}
void ParallelScavengeHeap::print() const { print_on(tty); }
void ParallelScavengeHeap::print_on(outputStream* st) const {
young_gen()->print_on(st);
old_gen()->print_on(st);
......
......@@ -246,8 +246,7 @@ CollectorPolicy* collector_policy() const { return (CollectorPolicy*) _collector
jlong millis_since_last_gc();
void prepare_for_verify();
void print() const;
void print_on(outputStream* st) const;
virtual void print_on(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
virtual void print_tracing_info() const;
......
......@@ -590,13 +590,27 @@ class CollectedHeap : public CHeapObj {
void pre_full_gc_dump();
void post_full_gc_dump();
virtual void print() const = 0;
// Print heap information on the given outputStream.
virtual void print_on(outputStream* st) const = 0;
// The default behavior is to call print_on() on tty.
virtual void print() const {
print_on(tty);
}
// Print more detailed heap information on the given
// outputStream. The default behaviour is to call print_on(). It is
// up to each subclass to override it and add any additional output
// it needs.
virtual void print_extended_on(outputStream* st) const {
print_on(st);
}
// Print all GC threads (other than the VM thread)
// used by this heap.
virtual void print_gc_threads_on(outputStream* st) const = 0;
void print_gc_threads() { print_gc_threads_on(tty); }
// The default behavior is to call print_gc_threads_on() on tty.
void print_gc_threads() {
print_gc_threads_on(tty);
}
// Iterator for all GC threads (other than VM thread)
virtual void gc_threads_do(ThreadClosure* tc) const = 0;
......
......@@ -42,12 +42,6 @@ const char* GCCause::to_string(GCCause::Cause cause) {
case _jvmti_force_gc:
return "JvmtiEnv ForceGarbageCollection";
case _no_gc:
return "No GC";
case _allocation_failure:
return "Allocation Failure";
case _gc_locker:
return "GCLocker Initiated GC";
......@@ -57,6 +51,12 @@ const char* GCCause::to_string(GCCause::Cause cause) {
case _heap_dump:
return "Heap Dump Initiated GC";
case _no_gc:
return "No GC";
case _allocation_failure:
return "Allocation Failure";
case _tenured_generation_full:
return "Tenured Generation Full";
......@@ -78,6 +78,9 @@ const char* GCCause::to_string(GCCause::Cause cause) {
case _old_generation_too_full_to_scavenge:
return "Old Generation Too Full To Scavenge";
case _adaptive_size_policy:
return "Ergonomics";
case _g1_inc_collection_pause:
return "G1 Evacuation Pause";
......
......@@ -1270,7 +1270,6 @@ void GenCollectedHeap::verify(bool allow_dirty, bool silent, VerifyOption option
rem_set()->verify();
}
void GenCollectedHeap::print() const { print_on(tty); }
void GenCollectedHeap::print_on(outputStream* st) const {
for (int i = 0; i < _n_gens; i++) {
_gens[i]->print_on(st);
......
......@@ -360,8 +360,7 @@ public:
void verify(bool allow_dirty, bool silent, VerifyOption option);
// Override.
void print() const;
void print_on(outputStream* st) const;
virtual void print_on(outputStream* st) const;
virtual void print_gc_threads_on(outputStream* st) const;
virtual void gc_threads_do(ThreadClosure* tc) const;
virtual void print_tracing_info() const;
......
......@@ -1281,11 +1281,17 @@ void Universe::flush_dependents_on_method(methodHandle m_h) {
}
}
void Universe::print() { print_on(gclog_or_tty); }
void Universe::print() {
print_on(gclog_or_tty);
}
void Universe::print_on(outputStream* st) {
void Universe::print_on(outputStream* st, bool extended) {
st->print_cr("Heap");
heap()->print_on(st);
if (!extended) {
heap()->print_on(st);
} else {
heap()->print_extended_on(st);
}
}
void Universe::print_heap_at_SIGBREAK() {
......@@ -1301,14 +1307,22 @@ void Universe::print_heap_before_gc(outputStream* st) {
st->print_cr("{Heap before GC invocations=%u (full %u):",
heap()->total_collections(),
heap()->total_full_collections());
heap()->print_on(st);
if (!PrintHeapAtGCExtended) {
heap()->print_on(st);
} else {
heap()->print_extended_on(st);
}
}
void Universe::print_heap_after_gc(outputStream* st) {
st->print_cr("Heap after GC invocations=%u (full %u):",
heap()->total_collections(),
heap()->total_full_collections());
heap()->print_on(st);
if (!PrintHeapAtGCExtended) {
heap()->print_on(st);
} else {
heap()->print_extended_on(st);
}
st->print_cr("}");
}
......
......@@ -414,9 +414,13 @@ class Universe: AllStatic {
static bool verify_in_progress() { return _verify_in_progress; }
static void verify(bool allow_dirty = true, bool silent = false,
VerifyOption option = VerifyOption_Default );
static int verify_count() { return _verify_count; }
static int verify_count() { return _verify_count; }
// The default behavior is to call print_on() on gclog_or_tty.
static void print();
static void print_on(outputStream* st);
// The extended parameter determines which method on the heap will
// be called: print_on() (extended == false) or print_extended_on()
// (extended == true).
static void print_on(outputStream* st, bool extended = false);
static void print_heap_at_SIGBREAK();
static void print_heap_before_gc() { print_heap_before_gc(gclog_or_tty); }
static void print_heap_after_gc() { print_heap_after_gc(gclog_or_tty); }
......
......@@ -23,9 +23,40 @@
*/
#include "precompiled.hpp"
/////////////// Unit tests ///////////////
#ifndef PRODUCT
#include "oops/arrayOop.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "utilities/globalDefinitions.hpp"
bool arrayOopDesc::check_max_length_overflow(BasicType type) {
julong length = max_array_length(type);
julong bytes_per_element = type2aelembytes(type);
julong bytes = length * bytes_per_element + header_size_in_bytes();
return (julong)(size_t)bytes == bytes;
}
bool arrayOopDesc::test_max_array_length() {
tty->print_cr("test_max_array_length");
assert(check_max_length_overflow(T_BOOLEAN), "size_t overflow for boolean array");
assert(check_max_length_overflow(T_CHAR), "size_t overflow for char array");
assert(check_max_length_overflow(T_FLOAT), "size_t overflow for float array");
assert(check_max_length_overflow(T_DOUBLE), "size_t overflow for double array");
assert(check_max_length_overflow(T_BYTE), "size_t overflow for byte array");
assert(check_max_length_overflow(T_SHORT), "size_t overflow for short array");
assert(check_max_length_overflow(T_INT), "size_t overflow for int array");
assert(check_max_length_overflow(T_LONG), "size_t overflow for long array");
assert(check_max_length_overflow(T_OBJECT), "size_t overflow for object array");
assert(check_max_length_overflow(T_ARRAY), "size_t overflow for array array");
assert(check_max_length_overflow(T_NARROWOOP), "size_t overflow for narrowOop array");
// T_VOID and T_ADDRESS are not supported by max_array_length()
return true;
}
// <<this page is intentionally left blank>>
#endif //PRODUCT
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, 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
......@@ -104,20 +104,32 @@ class arrayOopDesc : public oopDesc {
// Return the maximum length of an array of BasicType. The length can passed
// to typeArrayOop::object_size(scale, length, header_size) without causing an
// overflow.
// overflow. We also need to make sure that this will not overflow a size_t on
// 32 bit platforms when we convert it to a byte size.
static int32_t max_array_length(BasicType type) {
assert(type >= 0 && type < T_CONFLICT, "wrong type");
assert(type2aelembytes(type) != 0, "wrong type");
const int bytes_per_element = type2aelembytes(type);
if (bytes_per_element < HeapWordSize) {
return max_jint;
}
const int32_t max_words = align_size_down(max_jint, MinObjAlignment);
const int32_t max_element_words = max_words - header_size(type);
const int32_t words_per_element = bytes_per_element >> LogHeapWordSize;
return max_element_words / words_per_element;
const size_t max_element_words_per_size_t =
align_size_down((SIZE_MAX/HeapWordSize - header_size(type)), MinObjAlignment);
const size_t max_elements_per_size_t =
HeapWordSize * max_element_words_per_size_t / type2aelembytes(type);
if ((size_t)max_jint < max_elements_per_size_t) {
// It should be ok to return max_jint here, but parts of the code
// (CollectedHeap, Klass::oop_oop_iterate(), and more) uses an int for
// passing around the size (in words) of an object. So, we need to avoid
// overflowing an int when we add the header. See CRs 4718400 and 7110613.
return align_size_down(max_jint - header_size(type), MinObjAlignment);
}
return (int32_t)max_elements_per_size_t;
}
// for unit testing
#ifndef PRODUCT
static bool check_max_length_overflow(BasicType type);
static int32_t old_max_array_length(BasicType type);
static bool test_max_array_length();
#endif
};
#endif // SHARE_VM_OOPS_ARRAYOOP_HPP
......@@ -5042,7 +5042,8 @@ _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) {
void execute_internal_vm_tests() {
if (ExecuteInternalVMTests) {
assert(QuickSort::test_quick_sort(), "test_quick_sort failed");
tty->print_cr("All tests passed");
assert(arrayOopDesc::test_max_array_length(), "test_max_array_length failed");
tty->print_cr("All internal VM tests passed");
}
}
......
......@@ -27,6 +27,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc_implementation/shared/vmGCOperations.hpp"
#include "memory/gcLocker.inline.hpp"
#include "memory/genCollectedHeap.hpp"
#include "memory/universe.hpp"
#include "oops/objArrayKlass.hpp"
......@@ -1709,11 +1710,16 @@ void VM_HeapDumper::doit() {
HandleMark hm;
CollectedHeap* ch = Universe::heap();
ch->ensure_parsability(false); // must happen, even if collection does
// not happen (e.g. due to GC_locker)
if (_gc_before_heap_dump) {
ch->collect_as_vm_thread(GCCause::_heap_dump);
} else {
// make the heap parsable (no need to retire TLABs)
ch->ensure_parsability(false);
if (GC_locker::is_active()) {
warning("GC locker is held; pre-heapdump GC was skipped");
} else {
ch->collect_as_vm_thread(GCCause::_heap_dump);
}
}
// At this point we should be the only dumper active, so
......
......@@ -23,13 +23,13 @@
*/
#include "precompiled.hpp"
#include "utilities/quickSort.hpp"
#ifndef PRODUCT
/////////////// Unit tests ///////////////
// Unit tests
#ifndef PRODUCT
#include "runtime/os.hpp"
#include "utilities/quickSort.hpp"
#include <stdlib.h>
static int test_comparator(int a, int b) {
......@@ -94,7 +94,7 @@ bool QuickSort::sort_and_compare(int* arrayToSort, int* expectedResult, int leng
}
bool QuickSort::test_quick_sort() {
tty->print_cr("test_quick_sort\n");
tty->print_cr("test_quick_sort");
{
int* test_array = NULL;
int* expected_array = NULL;
......
......@@ -680,8 +680,10 @@ void VMError::report(outputStream* st) {
STEP(190, "(printing heap information)" )
if (_verbose && Universe::is_fully_initialized()) {
// print heap information before vm abort
Universe::print_on(st);
// Print heap information before vm abort. As we'd like as much
// information as possible in the report we ask for the
// extended (i.e., more detailed) version.
Universe::print_on(st, true /* extended */);
st->cr();
}
......
#
# Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 1995, 2011, 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
......@@ -219,6 +219,15 @@ PHONY_LIST += servertest
################################################################
# internalvmtests (run internal unit tests inside the VM)
internalvmtests: prep $(PRODUCT_HOME)
$(PRODUCT_HOME)/bin/java $(JAVA_OPTIONS) -XX:+ExecuteInternalVMTests -version
PHONY_LIST += internalvmtests
################################################################
# packtest
# Expect JPRT to set JPRT_PACKTEST_HOME.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册