aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramurillo <none@none>2012-08-03 13:13:42 -0700
committeramurillo <none@none>2012-08-03 13:13:42 -0700
commitfeab0f7d21fdcd55771d476c4da5784e68e54e34 (patch)
tree731f0a60bb920158c3e189e80b9165e895eff715
parent0908796b699c0d2834dbb8e5dda054373b21859f (diff)
parent728511ae2e1ad3968c6bc83c66d5c5104c560a42 (diff)
-rw-r--r--make/hotspot_version2
-rw-r--r--src/os/bsd/vm/decoder_machO.cpp133
-rw-r--r--src/os/bsd/vm/decoder_machO.hpp19
-rw-r--r--src/os/bsd/vm/os_bsd.cpp14
-rw-r--r--src/os/windows/vm/decoder_windows.cpp4
-rw-r--r--src/os/windows/vm/decoder_windows.hpp4
-rw-r--r--src/share/vm/gc_implementation/g1/collectionSetChooser.hpp43
-rw-r--r--src/share/vm/gc_implementation/g1/concurrentMark.cpp122
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp175
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp104
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp38
-rw-r--r--src/share/vm/gc_implementation/g1/g1MarkSweep.cpp21
-rw-r--r--src/share/vm/gc_implementation/g1/g1OopClosures.hpp2
-rw-r--r--src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp31
-rw-r--r--src/share/vm/gc_implementation/g1/g1RemSet.cpp104
-rw-r--r--src/share/vm/gc_implementation/g1/heapRegion.cpp45
-rw-r--r--src/share/vm/gc_implementation/g1/heapRegion.hpp31
-rw-r--r--src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp219
-rw-r--r--src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp13
-rw-r--r--src/share/vm/gc_implementation/g1/heapRegionSet.cpp16
-rw-r--r--src/share/vm/gc_implementation/g1/heapRegionSet.hpp2
-rw-r--r--src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp13
-rw-r--r--src/share/vm/utilities/decoder.cpp12
-rw-r--r--src/share/vm/utilities/decoder.hpp7
-rw-r--r--src/share/vm/utilities/decoder_elf.hpp4
-rw-r--r--src/share/vm/utilities/hashtable.cpp2
-rw-r--r--src/share/vm/utilities/hashtable.hpp2
27 files changed, 708 insertions, 474 deletions
diff --git a/make/hotspot_version b/make/hotspot_version
index 0bb6186a9..084dcc249 100644
--- a/make/hotspot_version
+++ b/make/hotspot_version
@@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2012
HS_MAJOR_VER=24
HS_MINOR_VER=0
-HS_BUILD_NUMBER=18
+HS_BUILD_NUMBER=19
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
diff --git a/src/os/bsd/vm/decoder_machO.cpp b/src/os/bsd/vm/decoder_machO.cpp
index d77a32f7e..75250d195 100644
--- a/src/os/bsd/vm/decoder_machO.cpp
+++ b/src/os/bsd/vm/decoder_machO.cpp
@@ -26,6 +26,139 @@
#ifdef __APPLE__
#include "decoder_machO.hpp"
+
+#include <cxxabi.h>
+#include <mach-o/loader.h>
+#include <mach-o/nlist.h>
+
+
+bool MachODecoder::demangle(const char* symbol, char *buf, int buflen) {
+ int status;
+ char* result;
+ size_t size = (size_t)buflen;
+ // Don't pass buf to __cxa_demangle. In case of the 'buf' is too small,
+ // __cxa_demangle will call system "realloc" for additional memory, which
+ // may use different malloc/realloc mechanism that allocates 'buf'.
+ if ((result = abi::__cxa_demangle(symbol, NULL, NULL, &status)) != NULL) {
+ jio_snprintf(buf, buflen, "%s", result);
+ // call c library's free
+ ::free(result);
+ return true;
+ }
+ return false;
+}
+
+bool MachODecoder::decode(address addr, char *buf,
+ int buflen, int *offset, const void *mach_base) {
+ struct symtab_command * symt = (struct symtab_command *)
+ mach_find_command((struct mach_header_64 *)mach_base, LC_SYMTAB);
+ if (symt == NULL) {
+ DEBUG_ONLY(tty->print_cr("no symtab in mach file at 0x%lx", mach_base));
+ return false;
+ }
+ uint32_t off = symt->symoff; /* symbol table offset (within this mach file) */
+ uint32_t nsyms = symt->nsyms; /* number of symbol table entries */
+ uint32_t stroff = symt->stroff; /* string table offset */
+ uint32_t strsize = symt->strsize; /* string table size in bytes */
+
+ // iterate through symbol table trying to match our offset
+
+ uint32_t addr_relative = (uintptr_t) mach_base - (uintptr_t) addr; // offset we seek in the symtab
+ void * symtab_addr = (void*) ((uintptr_t) mach_base + off);
+ struct nlist_64 *cur_nlist = (struct nlist_64 *) symtab_addr;
+ struct nlist_64 *last_nlist = cur_nlist; // no size stored in an entry, so keep previously seen nlist
+
+ int32_t found_strx = 0;
+ int32_t found_symval = 0;
+
+ for (uint32_t i=0; i < nsyms; i++) {
+ uint32_t this_value = cur_nlist->n_value;
+
+ if (addr_relative == this_value) {
+ found_strx = cur_nlist->n_un.n_strx;
+ found_symval = this_value;
+ break;
+ } else if (addr_relative > this_value) {
+ // gone past it, use previously seen nlist:
+ found_strx = last_nlist->n_un.n_strx;
+ found_symval = last_nlist->n_value;
+ break;
+ }
+ last_nlist = cur_nlist;
+ cur_nlist = cur_nlist + sizeof(struct nlist_64);
+ }
+ if (found_strx == 0) {
+ return false;
+ }
+ // write the offset:
+ *offset = addr_relative - found_symval;
+
+ // lookup found_strx in the string table
+ char * symname = mach_find_in_stringtable((char*) ((uintptr_t)mach_base + stroff), strsize, found_strx);
+ if (symname) {
+ strncpy(buf, symname, buflen);
+ return true;
+ }
+ DEBUG_ONLY(tty->print_cr("no string or null string found."));
+ return false;
+}
+
+void* MachODecoder::mach_find_command(struct mach_header_64 * mach_base, uint32_t command_wanted) {
+ // possibly verify it is a mach_header, use magic number.
+ // commands begin immediately after the header.
+ struct load_command *pos = (struct load_command *) mach_base + sizeof(struct mach_header_64);
+ for (uint32_t i = 0; i < mach_base->ncmds; i++) {
+ struct load_command *this_cmd = (struct load_command *) pos;
+ if (this_cmd->cmd == command_wanted) {
+ return pos;
+ }
+ int cmdsize = this_cmd->cmdsize;
+ pos += cmdsize;
+ }
+ return NULL;
+}
+
+char* MachODecoder::mach_find_in_stringtable(char *strtab, uint32_t tablesize, int strx_wanted) {
+
+ if (strx_wanted == 0) {
+ return NULL;
+ }
+ char *strtab_end = strtab + tablesize;
+
+ // find the first string, skip over the space char
+ // (or the four zero bytes we see e.g. in libclient)
+ if (*strtab == ' ') {
+ strtab++;
+ if (*strtab != 0) {
+ DEBUG_ONLY(tty->print_cr("string table has leading space but no following zero."));
+ return NULL;
+ }
+ strtab++;
+ } else {
+ if ((uint32_t) *strtab != 0) {
+ DEBUG_ONLY(tty->print_cr("string table without leading space or leading int of zero."));
+ return NULL;
+ }
+ strtab+=4;
+ }
+ // read the real strings starting at index 1
+ int cur_strx = 1;
+ while (strtab < strtab_end) {
+ if (cur_strx == strx_wanted) {
+ return strtab;
+ }
+ // find start of next string
+ while (*strtab != 0) {
+ strtab++;
+ }
+ strtab++; // skip the terminating zero
+ cur_strx++;
+ }
+ DEBUG_ONLY(tty->print_cr("string number %d not found.", strx_wanted));
+ return NULL;
+}
+
+
#endif
diff --git a/src/os/bsd/vm/decoder_machO.hpp b/src/os/bsd/vm/decoder_machO.hpp
index 9fb16899c..25dedc6aa 100644
--- a/src/os/bsd/vm/decoder_machO.hpp
+++ b/src/os/bsd/vm/decoder_machO.hpp
@@ -31,10 +31,25 @@
// Just a placehold for now, a real implementation should derive
// from AbstractDecoder
-class MachODecoder : public NullDecoder {
-public:
+class MachODecoder : public AbstractDecoder {
+ public:
MachODecoder() { }
~MachODecoder() { }
+ virtual bool can_decode_C_frame_in_vm() const {
+ return true;
+ }
+ virtual bool demangle(const char* symbol, char* buf, int buflen);
+ virtual bool decode(address pc, char* buf, int buflen, int* offset,
+ const void* base);
+ virtual bool decode(address pc, char* buf, int buflen, int* offset,
+ const char* module_path = NULL) {
+ ShouldNotReachHere();
+ return false;
+ }
+
+ private:
+ void * mach_find_command(struct mach_header_64 * mach_base, uint32_t command_wanted);
+ char * mach_find_in_stringtable(char *strtab, uint32_t tablesize, int strx_wanted);
};
#endif
diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp
index 68ab3fc4c..a1c412182 100644
--- a/src/os/bsd/vm/os_bsd.cpp
+++ b/src/os/bsd/vm/os_bsd.cpp
@@ -1946,10 +1946,16 @@ bool os::address_is_in_vm(address addr) {
return false;
}
+
+#define MACH_MAXSYMLEN 256
+
bool os::dll_address_to_function_name(address addr, char *buf,
int buflen, int *offset) {
Dl_info dlinfo;
+ char localbuf[MACH_MAXSYMLEN];
+ // dladdr will find names of dynamic functions only, but does
+ // it set dli_fbase with mach_header address when it "fails" ?
if (dladdr((void*)addr, &dlinfo) && dlinfo.dli_sname != NULL) {
if (buf != NULL) {
if(!Decoder::demangle(dlinfo.dli_sname, buf, buflen)) {
@@ -1965,6 +1971,14 @@ bool os::dll_address_to_function_name(address addr, char *buf,
}
}
+ // Handle non-dymanic manually:
+ if (dlinfo.dli_fbase != NULL &&
+ Decoder::decode(addr, localbuf, MACH_MAXSYMLEN, offset, dlinfo.dli_fbase)) {
+ if(!Decoder::demangle(localbuf, buf, buflen)) {
+ jio_snprintf(buf, buflen, "%s", localbuf);
+ }
+ return true;
+ }
if (buf != NULL) buf[0] = '\0';
if (offset != NULL) *offset = -1;
return false;
diff --git a/src/os/windows/vm/decoder_windows.cpp b/src/os/windows/vm/decoder_windows.cpp
index 847e23108..6500e5930 100644
--- a/src/os/windows/vm/decoder_windows.cpp
+++ b/src/os/windows/vm/decoder_windows.cpp
@@ -72,10 +72,10 @@ void WindowsDecoder::initialize() {
// find out if jvm.dll contains private symbols, by decoding
// current function and comparing the result
- address addr = (address)Decoder::decode;
+ address addr = (address)Decoder::demangle;
char buf[MAX_PATH];
if (decode(addr, buf, sizeof(buf), NULL)) {
- _can_decode_in_vm = !strcmp(buf, "Decoder::decode");
+ _can_decode_in_vm = !strcmp(buf, "Decoder::demangle");
}
}
}
diff --git a/src/os/windows/vm/decoder_windows.hpp b/src/os/windows/vm/decoder_windows.hpp
index 05a5dc25f..ad80e5b9c 100644
--- a/src/os/windows/vm/decoder_windows.hpp
+++ b/src/os/windows/vm/decoder_windows.hpp
@@ -45,6 +45,10 @@ public:
bool can_decode_C_frame_in_vm() const;
bool demangle(const char* symbol, char *buf, int buflen);
bool decode(address addr, char *buf, int buflen, int* offset, const char* modulepath = NULL);
+ bool decode(address addr, char *buf, int buflen, int* offset, const void* base) {
+ ShouldNotReachHere();
+ return false;
+ }
private:
void initialize();
diff --git a/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp b/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp
index 44ee2ad34..1a147b831 100644
--- a/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp
+++ b/src/share/vm/gc_implementation/g1/collectionSetChooser.hpp
@@ -153,4 +153,47 @@ public:
void verify() PRODUCT_RETURN;
};
+class CSetChooserParUpdater : public StackObj {
+private:
+ CollectionSetChooser* _chooser;
+ bool _parallel;
+ uint _chunk_size;
+ uint _cur_chunk_idx;
+ uint _cur_chunk_end;
+ uint _regions_added;
+ size_t _reclaimable_bytes_added;
+
+public:
+ CSetChooserParUpdater(CollectionSetChooser* chooser,
+ bool parallel, uint chunk_size) :
+ _chooser(chooser), _parallel(parallel), _chunk_size(chunk_size),
+ _cur_chunk_idx(0), _cur_chunk_end(0),
+ _regions_added(0), _reclaimable_bytes_added(0) { }
+
+ ~CSetChooserParUpdater() {
+ if (_parallel && _regions_added > 0) {
+ _chooser->update_totals(_regions_added, _reclaimable_bytes_added);
+ }
+ }
+
+ void add_region(HeapRegion* hr) {
+ if (_parallel) {
+ if (_cur_chunk_idx == _cur_chunk_end) {
+ _cur_chunk_idx = _chooser->claim_array_chunk(_chunk_size);
+ _cur_chunk_end = _cur_chunk_idx + _chunk_size;
+ }
+ assert(_cur_chunk_idx < _cur_chunk_end, "invariant");
+ _chooser->set_region(_cur_chunk_idx, hr);
+ _cur_chunk_idx += 1;
+ } else {
+ _chooser->add_region(hr);
+ }
+ _regions_added += 1;
+ _reclaimable_bytes_added += hr->reclaimable_bytes();
+ }
+
+ bool should_add(HeapRegion* hr) { return _chooser->should_add(hr); }
+};
+
#endif // SHARE_VM_GC_IMPLEMENTATION_G1_COLLECTIONSETCHOOSER_HPP
+
diff --git a/src/share/vm/gc_implementation/g1/concurrentMark.cpp b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
index bee661471..0c796a7c6 100644
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp
+++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp
@@ -1226,9 +1226,7 @@ protected:
} else {
// Starts humongous case: calculate how many regions are part of
// this humongous region and then set the bit range.
- G1CollectedHeap* g1h = G1CollectedHeap::heap();
- HeapRegion *last_hr = g1h->heap_region_containing_raw(hr->end() - 1);
- BitMap::idx_t end_index = (BitMap::idx_t) last_hr->hrs_index() + 1;
+ BitMap::idx_t end_index = (BitMap::idx_t) hr->last_hc_index();
_region_bm->par_at_put_range(index, end_index, true);
}
}
@@ -1645,26 +1643,27 @@ public:
size_t freed_bytes() { return _freed_bytes; }
bool doHeapRegion(HeapRegion *hr) {
+ if (hr->continuesHumongous()) {
+ return false;
+ }
// We use a claim value of zero here because all regions
// were claimed with value 1 in the FinalCount task.
- hr->reset_gc_time_stamp();
- if (!hr->continuesHumongous()) {
- double start = os::elapsedTime();
- _regions_claimed++;
- hr->note_end_of_marking();
- _max_live_bytes += hr->max_live_bytes();
- _g1->free_region_if_empty(hr,
- &_freed_bytes,
- _local_cleanup_list,
- _old_proxy_set,
- _humongous_proxy_set,
- _hrrs_cleanup_task,
- true /* par */);
- double region_time = (os::elapsedTime() - start);
- _claimed_region_time += region_time;
- if (region_time > _max_region_time) {
- _max_region_time = region_time;
- }
+ _g1->reset_gc_time_stamps(hr);
+ double start = os::elapsedTime();
+ _regions_claimed++;
+ hr->note_end_of_marking();
+ _max_live_bytes += hr->max_live_bytes();
+ _g1->free_region_if_empty(hr,
+ &_freed_bytes,
+ _local_cleanup_list,
+ _old_proxy_set,
+ _humongous_proxy_set,
+ _hrrs_cleanup_task,
+ true /* par */);
+ double region_time = (os::elapsedTime() - start);
+ _claimed_region_time += region_time;
+ if (region_time > _max_region_time) {
+ _max_region_time = region_time;
}
return false;
}
@@ -1881,6 +1880,7 @@ void ConcurrentMark::cleanup() {
} else {
g1_par_note_end_task.work(0);
}
+ g1h->check_gc_time_stamps();
if (!cleanup_list_is_empty()) {
// The cleanup list is not empty, so we'll have to process it
@@ -2449,24 +2449,8 @@ public:
} else {
HeapRegion* hr = _g1h->heap_region_containing(obj);
guarantee(hr != NULL, "invariant");
- bool over_tams = false;
- bool marked = false;
-
- switch (_vo) {
- case VerifyOption_G1UsePrevMarking:
- over_tams = hr->obj_allocated_since_prev_marking(obj);
- marked = _g1h->isMarkedPrev(obj);
- break;
- case VerifyOption_G1UseNextMarking:
- over_tams = hr->obj_allocated_since_next_marking(obj);
- marked = _g1h->isMarkedNext(obj);
- break;
- case VerifyOption_G1UseMarkWord:
- marked = obj->is_gc_marked();
- break;
- default:
- ShouldNotReachHere();
- }
+ bool over_tams = _g1h->allocated_since_marking(obj, hr, _vo);
+ bool marked = _g1h->is_marked(obj, _vo);
if (over_tams) {
str = " >";
@@ -2502,24 +2486,8 @@ public:
_out(out), _vo(vo), _all(all), _hr(hr) { }
void do_object(oop o) {
- bool over_tams = false;
- bool marked = false;
-
- switch (_vo) {
- case VerifyOption_G1UsePrevMarking:
- over_tams = _hr->obj_allocated_since_prev_marking(o);
- marked = _g1h->isMarkedPrev(o);
- break;
- case VerifyOption_G1UseNextMarking:
- over_tams = _hr->obj_allocated_since_next_marking(o);
- marked = _g1h->isMarkedNext(o);
- break;
- case VerifyOption_G1UseMarkWord:
- marked = o->is_gc_marked();
- break;
- default:
- ShouldNotReachHere();
- }
+ bool over_tams = _g1h->allocated_since_marking(o, _hr, _vo);
+ bool marked = _g1h->is_marked(o, _vo);
bool print_it = _all || over_tams || marked;
if (print_it) {
@@ -2533,32 +2501,17 @@ public:
class PrintReachableRegionClosure : public HeapRegionClosure {
private:
- outputStream* _out;
- VerifyOption _vo;
- bool _all;
+ G1CollectedHeap* _g1h;
+ outputStream* _out;
+ VerifyOption _vo;
+ bool _all;
public:
bool doHeapRegion(HeapRegion* hr) {
HeapWord* b = hr->bottom();
HeapWord* e = hr->end();
HeapWord* t = hr->top();
- HeapWord* p = NULL;
-
- switch (_vo) {
- case VerifyOption_G1UsePrevMarking:
- p = hr->prev_top_at_mark_start();
- break;
- case VerifyOption_G1UseNextMarking:
- p = hr->next_top_at_mark_start();
- break;
- case VerifyOption_G1UseMarkWord:
- // When we are verifying marking using the mark word
- // TAMS has no relevance.
- assert(p == NULL, "post-condition");
- break;
- default:
- ShouldNotReachHere();
- }
+ HeapWord* p = _g1h->top_at_mark_start(hr, _vo);
_out->print_cr("** ["PTR_FORMAT", "PTR_FORMAT"] top: "PTR_FORMAT" "
"TAMS: "PTR_FORMAT, b, e, t, p);
_out->cr();
@@ -2580,20 +2533,9 @@ public:
PrintReachableRegionClosure(outputStream* out,
VerifyOption vo,
bool all) :
- _out(out), _vo(vo), _all(all) { }
+ _g1h(G1CollectedHeap::heap()), _out(out), _vo(vo), _all(all) { }
};
-static const char* verify_option_to_tams(VerifyOption vo) {
- switch (vo) {
- case VerifyOption_G1UsePrevMarking:
- return "PTAMS";
- case VerifyOption_G1UseNextMarking:
- return "NTAMS";
- default:
- return "NONE";
- }
-}
-
void ConcurrentMark::print_reachable(const char* str,
VerifyOption vo,
bool all) {
@@ -2622,7 +2564,7 @@ void ConcurrentMark::print_reachable(const char* str,
}
outputStream* out = &fout;
- out->print_cr("-- USING %s", verify_option_to_tams(vo));
+ out->print_cr("-- USING %s", _g1h->top_at_mark_start_str(vo));
out->cr();
out->print_cr("--- ITERATING OVER REGIONS");
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
index c865db428..81e422262 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
@@ -1149,13 +1149,16 @@ HeapWord* G1CollectedHeap::attempt_allocation_at_safepoint(size_t word_size,
}
class PostMCRemSetClearClosure: public HeapRegionClosure {
+ G1CollectedHeap* _g1h;
ModRefBarrierSet* _mr_bs;
public:
- PostMCRemSetClearClosure(ModRefBarrierSet* mr_bs) : _mr_bs(mr_bs) {}
+ PostMCRemSetClearClosure(G1CollectedHeap* g1h, ModRefBarrierSet* mr_bs) :
+ _g1h(g1h), _mr_bs(mr_bs) { }
bool doHeapRegion(HeapRegion* r) {
- r->reset_gc_time_stamp();
- if (r->continuesHumongous())
+ if (r->continuesHumongous()) {
return false;
+ }
+ _g1h->reset_gc_time_stamps(r);
HeapRegionRemSet* hrrs = r->rem_set();
if (hrrs != NULL) hrrs->clear();
// You might think here that we could clear just the cards
@@ -1168,19 +1171,10 @@ public:
}
};
-
-class PostMCRemSetInvalidateClosure: public HeapRegionClosure {
- ModRefBarrierSet* _mr_bs;
-public:
- PostMCRemSetInvalidateClosure(ModRefBarrierSet* mr_bs) : _mr_bs(mr_bs) {}
- bool doHeapRegion(HeapRegion* r) {
- if (r->continuesHumongous()) return false;
- if (r->used_region().word_size() != 0) {
- _mr_bs->invalidate(r->used_region(), true /*whole heap*/);
- }
- return false;
- }
-};
+void G1CollectedHeap::clear_rsets_post_compaction() {
+ PostMCRemSetClearClosure rs_clear(this, mr_bs());
+ heap_region_iterate(&rs_clear);
+}
class RebuildRSOutOfRegionClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
@@ -1229,7 +1223,7 @@ public:
if (!hr->isHumongous()) {
_hr_printer->post_compaction(hr, G1HRPrinter::Old);
} else if (hr->startsHumongous()) {
- if (hr->capacity() == HeapRegion::GrainBytes) {
+ if (hr->region_num() == 1) {
// single humongous region
_hr_printer->post_compaction(hr, G1HRPrinter::SingleHumongous);
} else {
@@ -1247,6 +1241,11 @@ public:
: _hr_printer(hr_printer) { }
};
+void G1CollectedHeap::print_hrs_post_compaction() {
+ PostCompactionPrinterClosure cl(hr_printer());
+ heap_region_iterate(&cl);
+}
+
bool G1CollectedHeap::do_collection(bool explicit_gc,
bool clear_all_soft_refs,
size_t word_size) {
@@ -1402,8 +1401,8 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
// Since everything potentially moved, we will clear all remembered
// sets, and clear all cards. Later we will rebuild remebered
// sets. We will also reset the GC time stamps of the regions.
- PostMCRemSetClearClosure rs_clear(mr_bs());
- heap_region_iterate(&rs_clear);
+ clear_rsets_post_compaction();
+ check_gc_time_stamps();
// Resize the heap if necessary.
resize_if_necessary_after_full_collection(explicit_gc ? 0 : word_size);
@@ -1413,9 +1412,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
// that all the COMMIT / UNCOMMIT events are generated before
// the end GC event.
- PostCompactionPrinterClosure cl(hr_printer());
- heap_region_iterate(&cl);
-
+ print_hrs_post_compaction();
_hr_printer.end_gc(true /* full */, (size_t) total_collections());
}
@@ -2263,6 +2260,51 @@ size_t G1CollectedHeap::capacity() const {
return _g1_committed.byte_size();
}
+void G1CollectedHeap::reset_gc_time_stamps(HeapRegion* hr) {
+ assert(!hr->continuesHumongous(), "pre-condition");
+ hr->reset_gc_time_stamp();
+ if (hr->startsHumongous()) {
+ uint first_index = hr->hrs_index() + 1;
+ uint last_index = hr->last_hc_index();
+ for (uint i = first_index; i < last_index; i += 1) {
+ HeapRegion* chr = region_at(i);
+ assert(chr->continuesHumongous(), "sanity");
+ chr->reset_gc_time_stamp();
+ }
+ }
+}
+
+#ifndef PRODUCT
+class CheckGCTimeStampsHRClosure : public HeapRegionClosure {
+private:
+ unsigned _gc_time_stamp;
+ bool _failures;
+
+public:
+ CheckGCTimeStampsHRClosure(unsigned gc_time_stamp) :
+ _gc_time_stamp(gc_time_stamp), _failures(false) { }
+
+ virtual bool doHeapRegion(HeapRegion* hr) {
+ unsigned region_gc_time_stamp = hr->get_gc_time_stamp();
+ if (_gc_time_stamp != region_gc_time_stamp) {
+ gclog_or_tty->print_cr("Region "HR_FORMAT" has GC time stamp = %d, "
+ "expected %d", HR_FORMAT_PARAMS(hr),
+ region_gc_time_stamp, _gc_time_stamp);
+ _failures = true;
+ }
+ return false;
+ }
+
+ bool failures() { return _failures; }
+};
+
+void G1CollectedHeap::check_gc_time_stamps() {
+ CheckGCTimeStampsHRClosure cl(_gc_time_stamp);
+ heap_region_iterate(&cl);
+ guarantee(!cl.failures(), "all GC time stamps should have been reset");
+}
+#endif // PRODUCT
+
void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl,
DirtyCardQueue* into_cset_dcq,
bool concurrent,
@@ -2530,7 +2572,7 @@ public:
IterateOopClosureRegionClosure(MemRegion mr, OopClosure* cl)
: _mr(mr), _cl(cl) {}
bool doHeapRegion(HeapRegion* r) {
- if (! r->continuesHumongous()) {
+ if (!r->continuesHumongous()) {
r->oop_iterate(_cl);
}
return false;
@@ -2601,14 +2643,9 @@ void G1CollectedHeap::heap_region_iterate(HeapRegionClosure* cl) const {
_hrs.iterate(cl);
}
-void G1CollectedHeap::heap_region_iterate_from(HeapRegion* r,
- HeapRegionClosure* cl) const {
- _hrs.iterate_from(r, cl);
-}
-
void
G1CollectedHeap::heap_region_par_iterate_chunked(HeapRegionClosure* cl,
- uint worker,
+ uint worker_id,
uint no_of_par_workers,
jint claim_value) {
const uint regions = n_regions();
@@ -2619,7 +2656,9 @@ G1CollectedHeap::heap_region_par_iterate_chunked(HeapRegionClosure* cl,
no_of_par_workers == workers()->total_workers(),
"Non dynamic should use fixed number of workers");
// try to spread out the starting points of the workers
- const uint start_index = regions / max_workers * worker;
+ const HeapRegion* start_hr =
+ start_region_for_worker(worker_id, no_of_par_workers);
+ const uint start_index = start_hr->hrs_index();
// each worker will actually look at all regions
for (uint count = 0; count < regions; ++count) {
@@ -2861,6 +2900,17 @@ HeapRegion* G1CollectedHeap::start_cset_region_for_worker(int worker_i) {
return result;
}
+HeapRegion* G1CollectedHeap::start_region_for_worker(uint worker_i,
+ uint no_of_par_workers) {
+ uint worker_num =
+ G1CollectedHeap::use_parallel_gc_threads() ? no_of_par_workers : 1U;
+ assert(UseDynamicNumberOfGCThreads ||
+ no_of_par_workers == workers()->total_workers(),
+ "Non dynamic should use fixed number of workers");
+ const uint start_index = n_regions() * worker_i / worker_num;
+ return region_at(start_index);
+}
+
void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
HeapRegion* r = g1_policy()->collection_set();
while (r != NULL) {
@@ -2974,6 +3024,51 @@ void G1CollectedHeap::prepare_for_verify() {
g1_rem_set()->prepare_for_verify();
}
+bool G1CollectedHeap::allocated_since_marking(oop obj, HeapRegion* hr,
+ VerifyOption vo) {
+ switch (vo) {
+ case VerifyOption_G1UsePrevMarking:
+ return hr->obj_allocated_since_prev_marking(obj);
+ case VerifyOption_G1UseNextMarking:
+ return hr->obj_allocated_since_next_marking(obj);
+ case VerifyOption_G1UseMarkWord:
+ return false;
+ default:
+ ShouldNotReachHere();
+ }
+ return false; // keep some compilers happy
+}
+
+HeapWord* G1CollectedHeap::top_at_mark_start(HeapRegion* hr, VerifyOption vo) {
+ switch (vo) {
+ case VerifyOption_G1UsePrevMarking: return hr->prev_top_at_mark_start();
+ case VerifyOption_G1UseNextMarking: return hr->next_top_at_mark_start();
+ case VerifyOption_G1UseMarkWord: return NULL;
+ default: ShouldNotReachHere();
+ }
+ return NULL; // keep some compilers happy
+}
+
+bool G1CollectedHeap::is_marked(oop obj, VerifyOption vo) {
+ switch (vo) {
+ case VerifyOption_G1UsePrevMarking: return isMarkedPrev(obj);
+ case VerifyOption_G1UseNextMarking: return isMarkedNext(obj);
+ case VerifyOption_G1UseMarkWord: return obj->is_gc_marked();
+ default: ShouldNotReachHere();
+ }
+ return false; // keep some compilers happy
+}
+
+const char* G1CollectedHeap::top_at_mark_start_str(VerifyOption vo) {
+ switch (vo) {
+ case VerifyOption_G1UsePrevMarking: return "PTAMS";
+ case VerifyOption_G1UseNextMarking: return "NTAMS";
+ case VerifyOption_G1UseMarkWord: return "NONE";
+ default: ShouldNotReachHere();
+ }
+ return NULL; // keep some compilers happy
+}
+
class VerifyLivenessOopClosure: public OopClosure {
G1CollectedHeap* _g1h;
VerifyOption _vo;
@@ -3061,9 +3156,9 @@ public:
class VerifyRegionClosure: public HeapRegionClosure {
private:
- bool _par;
- VerifyOption _vo;
- bool _failures;
+ bool _par;
+ VerifyOption _vo;
+ bool _failures;
public:
// _vo == UsePrevMarking -> use "prev" marking information,
// _vo == UseNextMarking -> use "next" marking information,
@@ -3078,8 +3173,6 @@ public:
}
bool doHeapRegion(HeapRegion* r) {
- guarantee(_par || r->claim_value() == HeapRegion::InitialClaimValue,
- "Should be unclaimed at verify points.");
if (!r->continuesHumongous()) {
bool failures = false;
r->verify(_vo, &failures);
@@ -5612,19 +5705,18 @@ void G1CollectedHeap::free_humongous_region(HeapRegion* hr,
size_t hr_capacity = hr->capacity();
size_t hr_pre_used = 0;
_humongous_set.remove_with_proxy(hr, humongous_proxy_set);
+ // We need to read this before we make the region non-humongous,
+ // otherwise the information will be gone.
+ uint last_index = hr->last_hc_index();
hr->set_notHumongous();
free_region(hr, &hr_pre_used, free_list, par);
uint i = hr->hrs_index() + 1;
- uint num = 1;
- while (i < n_regions()) {
+ while (i < last_index) {
HeapRegion* curr_hr = region_at(i);
- if (!curr_hr->continuesHumongous()) {
- break;
- }
+ assert(curr_hr->continuesHumongous(), "invariant");
curr_hr->set_notHumongous();
free_region(curr_hr, &hr_pre_used, free_list, par);
- num += 1;
i += 1;
}
assert(hr_pre_used == hr_used,
@@ -5732,7 +5824,6 @@ void G1CollectedHeap::verify_dirty_young_list(HeapRegion* head) {
void G1CollectedHeap::verify_dirty_young_regions() {
verify_dirty_young_list(_young_list->first_region());
- verify_dirty_young_list(_young_list->first_survivor_region());
}
#endif
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
index 611cdd0b5..32972e86c 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
@@ -375,6 +375,13 @@ private:
// this method will be found dead by the marking cycle).
void allocate_dummy_regions() PRODUCT_RETURN;
+ // Clear RSets after a compaction. It also resets the GC time stamps.
+ void clear_rsets_post_compaction();
+
+ // If the HR printer is active, dump the state of the regions in the
+ // heap after a compaction.
+ void print_hrs_post_compaction();
+
// These are macros so that, if the assert fires, we get the correct
// line number, file, etc.
@@ -1061,11 +1068,18 @@ public:
clear_cset_start_regions();
}
+ void check_gc_time_stamps() PRODUCT_RETURN;
+
void increment_gc_time_stamp() {
++_gc_time_stamp;
OrderAccess::fence();
}
+ // Reset the given region's GC timestamp. If it's starts humongous,
+ // also reset the GC timestamp of its corresponding
+ // continues humongous regions too.
+ void reset_gc_time_stamps(HeapRegion* hr);
+
void iterate_dirty_card_closure(CardTableEntryClosure* cl,
DirtyCardQueue* into_cset_dcq,
bool concurrent, int worker_i);
@@ -1302,11 +1316,6 @@ public:
// iteration early if the "doHeapRegion" method returns "true".
void heap_region_iterate(HeapRegionClosure* blk) const;
- // Iterate over heap regions starting with r (or the first region if "r"
- // is NULL), in address order, terminating early if the "doHeapRegion"
- // method returns "true".
- void heap_region_iterate_from(HeapRegion* r, HeapRegionClosure* blk) const;
-
// Return the region with the given index. It assumes the index is valid.
HeapRegion* region_at(uint index) const { return _hrs.at(index); }
@@ -1351,6 +1360,11 @@ public:
// starting region for iterating over the current collection set.
HeapRegion* start_cset_region_for_worker(int worker_i);
+ // This is a convenience method that is used by the
+ // HeapRegionIterator classes to calculate the starting region for
+ // each worker so that they do not all start from the same region.
+ HeapRegion* start_region_for_worker(uint worker_i, uint no_of_par_workers);
+
// Iterate over the regions (if any) in the current collection set.
void collection_set_iterate(HeapRegionClosure* blk);
@@ -1558,24 +1572,6 @@ public:
bool isMarkedPrev(oop obj) const;
bool isMarkedNext(oop obj) const;
- // vo == UsePrevMarking -> use "prev" marking information,
- // vo == UseNextMarking -> use "next" marking information,
- // vo == UseMarkWord -> use mark word from object header
- bool is_obj_dead_cond(const oop obj,
- const HeapRegion* hr,
- const VerifyOption vo) const {
-
- switch (vo) {
- case VerifyOption_G1UsePrevMarking:
- return is_obj_dead(obj, hr);
- case VerifyOption_G1UseNextMarking:
- return is_obj_ill(obj, hr);
- default:
- assert(vo == VerifyOption_G1UseMarkWord, "must be");
- return !obj->is_gc_marked();
- }
- }
-
// Determine if an object is dead, given the object and also
// the region to which the object belongs. An object is dead
// iff a) it was not allocated since the last mark and b) it
@@ -1587,15 +1583,6 @@ public:
!isMarkedPrev(obj);
}
- // This is used when copying an object to survivor space.
- // If the object is marked live, then we mark the copy live.
- // If the object is allocated since the start of this mark
- // cycle, then we mark the copy live.
- // If the object has been around since the previous mark
- // phase, and hasn't been marked yet during this phase,
- // then we don't mark it, we just wait for the
- // current marking cycle to get to it.
-
// This function returns true when an object has been
// around since the previous marking and hasn't yet
// been marked during this marking.
@@ -1613,23 +1600,6 @@ public:
// Added if it is in permanent gen it isn't dead.
// Added if it is NULL it isn't dead.
- // vo == UsePrevMarking -> use "prev" marking information,
- // vo == UseNextMarking -> use "next" marking information,
- // vo == UseMarkWord -> use mark word from object header
- bool is_obj_dead_cond(const oop obj,
- const VerifyOption vo) const {
-
- switch (vo) {
- case VerifyOption_G1UsePrevMarking:
- return is_obj_dead(obj);
- case VerifyOption_G1UseNextMarking:
- return is_obj_ill(obj);
- default:
- assert(vo == VerifyOption_G1UseMarkWord, "must be");
- return !obj->is_gc_marked();
- }
- }
-
bool is_obj_dead(const oop obj) const {
const HeapRegion* hr = heap_region_containing(obj);
if (hr == NULL) {
@@ -1652,6 +1622,42 @@ public:
else return is_obj_ill(obj, hr);
}
+ // The methods below are here for convenience and dispatch the
+ // appropriate method depending on value of the given VerifyOption
+ // parameter. The options for that parameter are:
+ //
+ // vo == UsePrevMarking -> use "prev" marking information,
+ // vo == UseNextMarking -> use "next" marking information,
+ // vo == UseMarkWord -> use mark word from object header
+
+ bool is_obj_dead_cond(const oop obj,
+ const HeapRegion* hr,
+ const VerifyOption vo) const {
+ 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();
+ default: ShouldNotReachHere();
+ }
+ return false; // keep some compilers happy
+ }
+
+ bool is_obj_dead_cond(const oop obj,
+ const VerifyOption vo) const {
+ switch (vo) {
+ case VerifyOption_G1UsePrevMarking: return is_obj_dead(obj);
+ case VerifyOption_G1UseNextMarking: return is_obj_ill(obj);
+ case VerifyOption_G1UseMarkWord: return !obj->is_gc_marked();
+ default: ShouldNotReachHere();
+ }
+ return false; // keep some compilers happy
+ }
+
+ bool allocated_since_marking(oop obj, HeapRegion* hr, VerifyOption vo);
+ HeapWord* top_at_mark_start(HeapRegion* hr, VerifyOption vo);
+ bool is_marked(oop obj, VerifyOption vo);
+ const char* top_at_mark_start_str(VerifyOption vo);
+
// The following is just to alert the verification code
// that a full collection has occurred and that the
// remembered sets are no longer up to date.
diff --git a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
index f07b14824..4fd1c20ec 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp
@@ -1528,35 +1528,13 @@ public:
class ParKnownGarbageHRClosure: public HeapRegionClosure {
G1CollectedHeap* _g1h;
- CollectionSetChooser* _hrSorted;
- uint _marked_regions_added;
- size_t _reclaimable_bytes_added;
- uint _chunk_size;
- uint _cur_chunk_idx;
- uint _cur_chunk_end; // Cur chunk [_cur_chunk_idx, _cur_chunk_end)
-
- void get_new_chunk() {
- _cur_chunk_idx = _hrSorted->claim_array_chunk(_chunk_size);
- _cur_chunk_end = _cur_chunk_idx + _chunk_size;
- }
- void add_region(HeapRegion* r) {
- if (_cur_chunk_idx == _cur_chunk_end) {
- get_new_chunk();
- }
- assert(_cur_chunk_idx < _cur_chunk_end, "postcondition");
- _hrSorted->set_region(_cur_chunk_idx, r);
- _marked_regions_added++;
- _reclaimable_bytes_added += r->reclaimable_bytes();
- _cur_chunk_idx++;
- }
+ CSetChooserParUpdater _cset_updater;
public:
ParKnownGarbageHRClosure(CollectionSetChooser* hrSorted,
uint chunk_size) :
- _g1h(G1CollectedHeap::heap()),
- _hrSorted(hrSorted), _chunk_size(chunk_size),
- _marked_regions_added(0), _reclaimable_bytes_added(0),
- _cur_chunk_idx(0), _cur_chunk_end(0) { }
+ _g1h(G1CollectedHeap::heap()),
+ _cset_updater(hrSorted, true /* parallel */, chunk_size) { }
bool doHeapRegion(HeapRegion* r) {
// Do we have any marking information for this region?
@@ -1564,14 +1542,12 @@ public:
// We will skip any region that's currently used as an old GC
// alloc region (we should not consider those for collection
// before we fill them up).
- if (_hrSorted->should_add(r) && !_g1h->is_old_gc_alloc_region(r)) {
- add_region(r);
+ if (_cset_updater.should_add(r) && !_g1h->is_old_gc_alloc_region(r)) {
+ _cset_updater.add_region(r);
}
}
return false;
}
- uint marked_regions_added() { return _marked_regions_added; }
- size_t reclaimable_bytes_added() { return _reclaimable_bytes_added; }
};
class ParKnownGarbageTask: public AbstractGangTask {
@@ -1591,10 +1567,6 @@ public:
_g1->heap_region_par_iterate_chunked(&parKnownGarbageCl, worker_id,
_g1->workers()->active_workers(),
HeapRegion::InitialClaimValue);
- uint regions_added = parKnownGarbageCl.marked_regions_added();
- size_t reclaimable_bytes_added =
- parKnownGarbageCl.reclaimable_bytes_added();
- _hrSorted->update_totals(regions_added, reclaimable_bytes_added);
}
};
diff --git a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp
index 02d254b67..93017544f 100644
--- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp
+++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp
@@ -262,18 +262,6 @@ public:
}
};
-// Finds the first HeapRegion.
-class FindFirstRegionClosure: public HeapRegionClosure {
- HeapRegion* _a_region;
-public:
- FindFirstRegionClosure() : _a_region(NULL) {}
- bool doHeapRegion(HeapRegion* r) {
- _a_region = r;
- return true;
- }
- HeapRegion* result() { return _a_region; }
-};
-
void G1MarkSweep::mark_sweep_phase2() {
// Now all live objects are marked, compute the new object addresses.
@@ -294,9 +282,8 @@ void G1MarkSweep::mark_sweep_phase2() {
TraceTime tm("phase 2", G1Log::fine() && Verbose, true, gclog_or_tty);
GenMarkSweep::trace("2");
- FindFirstRegionClosure cl;
- g1h->heap_region_iterate(&cl);
- HeapRegion *r = cl.result();
+ // find the first region
+ HeapRegion* r = g1h->region_at(0);
CompactibleSpace* sp = r;
if (r->isHumongous() && oop(r->bottom())->is_gc_marked()) {
sp = r->next_compaction_space();
@@ -408,7 +395,3 @@ void G1MarkSweep::mark_sweep_phase4() {
g1h->heap_region_iterate(&blk);
}
-
-// Local Variables: ***
-// c-indentation-style: gnu ***
-// End: ***
diff --git a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp
index c20a1a771..cc5b98617 100644
--- a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp
+++ b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp
@@ -197,7 +197,6 @@ class FilterOutOfRegionClosure: public OopClosure {
HeapWord* _r_bottom;
HeapWord* _r_end;
OopClosure* _oc;
- int _out_of_region;
public:
FilterOutOfRegionClosure(HeapRegion* r, OopClosure* oc);
template <class T> void do_oop_nv(T* p);
@@ -205,7 +204,6 @@ public:
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
bool apply_to_weak_ref_discovered_field() { return true; }
bool do_header() { return false; }
- int out_of_region() { return _out_of_region; }
};
// Closure for iterating over object fields during concurrent marking
diff --git a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp
index 18a9c0251..c84de6e9e 100644
--- a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp
+++ b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp
@@ -29,31 +29,22 @@
#include "gc_implementation/g1/g1CollectedHeap.hpp"
#include "gc_implementation/g1/g1OopClosures.hpp"
#include "gc_implementation/g1/g1RemSet.hpp"
+#include "gc_implementation/g1/heapRegionRemSet.hpp"
/*
* This really ought to be an inline function, but apparently the C++
* compiler sometimes sees fit to ignore inline declarations. Sigh.
*/
-// This must a ifdef'ed because the counting it controls is in a
-// perf-critical inner loop.
-#define FILTERINTOCSCLOSURE_DOHISTOGRAMCOUNT 0
-
template <class T>
inline void FilterIntoCSClosure::do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
if (!oopDesc::is_null(heap_oop) &&
_g1->obj_in_cs(oopDesc::decode_heap_oop_not_null(heap_oop))) {
_oc->do_oop(p);
-#if FILTERINTOCSCLOSURE_DOHISTOGRAMCOUNT
- if (_dcto_cl != NULL)
- _dcto_cl->incr_count();
-#endif
}
}
-#define FILTEROUTOFREGIONCLOSURE_DOHISTOGRAMCOUNT 0
-
template <class T>
inline void FilterOutOfRegionClosure::do_oop_nv(T* p) {
T heap_oop = oopDesc::load_heap_oop(p);
@@ -61,9 +52,6 @@ inline void FilterOutOfRegionClosure::do_oop_nv(T* p) {
HeapWord* obj_hw = (HeapWord*)oopDesc::decode_heap_oop_not_null(heap_oop);
if (obj_hw < _r_bottom || obj_hw >= _r_end) {
_oc->do_oop(p);
-#if FILTEROUTOFREGIONCLOSURE_DOHISTOGRAMCOUNT
- _out_of_region++;
-#endif
}
}
}
@@ -182,6 +170,7 @@ inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) {
#endif // ASSERT
assert(_from != NULL, "from region must be non-NULL");
+ assert(_from->is_in_reserved(p), "p is not in from");
HeapRegion* to = _g1->heap_region_containing(obj);
if (to != NULL && _from != to) {
@@ -212,14 +201,16 @@ inline void G1UpdateRSOrPushRefOopClosure::do_oop_nv(T* p) {
// or processed (if an evacuation failure occurs) at the end
// of the collection.
// See G1RemSet::cleanup_after_oops_into_collection_set_do().
- } else {
- // We either don't care about pushing references that point into the
- // collection set (i.e. we're not during an evacuation pause) _or_
- // the reference doesn't point into the collection set. Either way
- // we add the reference directly to the RSet of the region containing
- // the referenced object.
- _g1_rem_set->par_write_ref(_from, p, _worker_i);
+ return;
}
+
+ // We either don't care about pushing references that point into the
+ // collection set (i.e. we're not during an evacuation pause) _or_
+ // the reference doesn't point into the collection set. Either way
+ // we add the reference directly to the RSet of the region containing
+ // the referenced object.
+ assert(to->rem_set() != NULL, "Need per-region 'into' remsets.");
+ to->rem_set()->add_reference(p, _worker_i);
}
}
diff --git a/src/share/vm/gc_implementation/g1/g1RemSet.cpp b/src/share/vm/gc_implementation/g1/g1RemSet.cpp
index c3af182b2..3e2e07b2c 100644
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp
+++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp
@@ -280,62 +280,6 @@ void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) {
_g1p->phase_times()->record_update_rs_time(worker_i, (os::elapsedTime() - start) * 1000.0);
}
-class CountRSSizeClosure: public HeapRegionClosure {
- size_t _n;
- size_t _tot;
- size_t _max;
- HeapRegion* _max_r;
- enum {
- N = 20,
- MIN = 6
- };
- int _histo[N];
-public:
- CountRSSizeClosure() : _n(0), _tot(0), _max(0), _max_r(NULL) {
- for (int i = 0; i < N; i++) _histo[i] = 0;
- }
- bool doHeapRegion(HeapRegion* r) {
- if (!r->continuesHumongous()) {
- size_t occ = r->rem_set()->occupied();
- _n++;
- _tot += occ;
- if (occ > _max) {
- _max = occ;
- _max_r = r;
- }
- // Fit it into a histo bin.
- int s = 1 << MIN;
- int i = 0;
- while (occ > (size_t) s && i < (N-1)) {
- s = s << 1;
- i++;
- }
- _histo[i]++;
- }
- return false;
- }
- size_t n() { return _n; }
- size_t tot() { return _tot; }
- size_t mx() { return _max; }
- HeapRegion* mxr() { return _max_r; }
- void print_histo() {
- int mx = N;
- while (mx >= 0) {
- if (_histo[mx-1] > 0) break;
- mx--;
- }
- gclog_or_tty->print_cr("Number of regions with given RS sizes:");
- gclog_or_tty->print_cr(" <= %8d %8d", 1 << MIN, _histo[0]);
- for (int i = 1; i < mx-1; i++) {
- gclog_or_tty->print_cr(" %8d - %8d %8d",
- (1 << (MIN + i - 1)) + 1,
- 1 << (MIN + i),
- _histo[i]);
- }
- gclog_or_tty->print_cr(" > %8d %8d", (1 << (MIN+mx-2))+1, _histo[mx-1]);
- }
-};
-
void G1RemSet::cleanupHRRS() {
HeapRegionRemSet::cleanup();
}
@@ -349,17 +293,6 @@ void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
_cg1r->clear_and_record_card_counts();
}
- // Make this into a command-line flag...
- if (G1RSCountHisto && (ParallelGCThreads == 0 || worker_i == 0)) {
- CountRSSizeClosure count_cl;
- _g1->heap_region_iterate(&count_cl);
- gclog_or_tty->print_cr("Avg of %d RS counts is %f, max is %d, "
- "max region is " PTR_FORMAT,
- count_cl.n(), (float)count_cl.tot()/(float)count_cl.n(),
- count_cl.mx(), count_cl.mxr());
- count_cl.print_histo();
- }
-
// We cache the value of 'oc' closure into the appropriate slot in the
// _cset_rs_update_cl for this worker
assert(worker_i < (int)n_workers(), "sanity");
@@ -568,8 +501,6 @@ void G1RemSet::scrub_par(BitMap* region_bm, BitMap* card_bm,
}
-static IntHistogram out_of_histo(50, 50);
-
G1TriggerClosure::G1TriggerClosure() :
_triggered(false) { }
@@ -671,7 +602,6 @@ bool G1RemSet::concurrentRefineOneCard_impl(jbyte* card_ptr, int worker_i,
sdcq->enqueue(card_ptr);
}
} else {
- out_of_histo.add_entry(filter_then_update_rs_oop_cl.out_of_region());
_conc_refine_cards++;
}
@@ -862,11 +792,6 @@ void G1RemSet::print_summary_info() {
card_repeat_count.print_on(gclog_or_tty);
#endif
- if (FILTEROUTOFREGIONCLOSURE_DOHISTOGRAMCOUNT) {
- gclog_or_tty->print_cr("\nG1 rem-set out-of-region histogram: ");
- gclog_or_tty->print_cr(" # of CS ptrs --> # of cards with that number.");
- out_of_histo.print_on(gclog_or_tty);
- }
gclog_or_tty->print_cr("\n Concurrent RS processed %d cards",
_conc_refine_cards);
DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
@@ -889,21 +814,24 @@ void G1RemSet::print_summary_info() {
HRRSStatsIter blk;
g1->heap_region_iterate(&blk);
- gclog_or_tty->print_cr(" Total heap region rem set sizes = " SIZE_FORMAT "K."
- " Max = " SIZE_FORMAT "K.",
+ gclog_or_tty->print_cr(" Total heap region rem set sizes = "SIZE_FORMAT"K."
+ " Max = "SIZE_FORMAT"K.",
blk.total_mem_sz()/K, blk.max_mem_sz()/K);
- gclog_or_tty->print_cr(" Static structures = " SIZE_FORMAT "K,"
- " free_lists = " SIZE_FORMAT "K.",
- HeapRegionRemSet::static_mem_size()/K,
- HeapRegionRemSet::fl_mem_size()/K);
- gclog_or_tty->print_cr(" %d occupied cards represented.",
+ gclog_or_tty->print_cr(" Static structures = "SIZE_FORMAT"K,"
+ " free_lists = "SIZE_FORMAT"K.",
+ HeapRegionRemSet::static_mem_size() / K,
+ HeapRegionRemSet::fl_mem_size() / K);
+ gclog_or_tty->print_cr(" "SIZE_FORMAT" occupied cards represented.",
blk.occupied());
- gclog_or_tty->print_cr(" Max sz region = [" PTR_FORMAT ", " PTR_FORMAT " )"
- ", cap = " SIZE_FORMAT "K, occ = " SIZE_FORMAT "K.",
- blk.max_mem_sz_region()->bottom(), blk.max_mem_sz_region()->end(),
- (blk.max_mem_sz_region()->rem_set()->mem_size() + K - 1)/K,
- (blk.max_mem_sz_region()->rem_set()->occupied() + K - 1)/K);
- gclog_or_tty->print_cr(" Did %d coarsenings.", HeapRegionRemSet::n_coarsenings());
+ HeapRegion* max_mem_sz_region = blk.max_mem_sz_region();
+ HeapRegionRemSet* rem_set = max_mem_sz_region->rem_set();
+ gclog_or_tty->print_cr(" Max size region = "HR_FORMAT", "
+ "size = "SIZE_FORMAT "K, occupied = "SIZE_FORMAT"K.",
+ HR_FORMAT_PARAMS(max_mem_sz_region),
+ (rem_set->mem_size() + K - 1)/K,
+ (rem_set->occupied() + K - 1)/K);
+ gclog_or_tty->print_cr(" Did %d coarsenings.",
+ HeapRegionRemSet::n_coarsenings());
}
void G1RemSet::prepare_for_verify() {
diff --git a/src/share/vm/gc_implementation/g1/heapRegion.cpp b/src/share/vm/gc_implementation/g1/heapRegion.cpp
index 33dac688f..3d8dead5b 100644
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp
+++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp
@@ -44,14 +44,11 @@ HeapRegionDCTOC::HeapRegionDCTOC(G1CollectedHeap* g1,
CardTableModRefBS::PrecisionStyle precision,
FilterKind fk) :
ContiguousSpaceDCTOC(hr, cl, precision, NULL),
- _hr(hr), _fk(fk), _g1(g1)
-{ }
+ _hr(hr), _fk(fk), _g1(g1) { }
FilterOutOfRegionClosure::FilterOutOfRegionClosure(HeapRegion* r,
OopClosure* oc) :
- _r_bottom(r->bottom()), _r_end(r->end()),
- _oc(oc), _out_of_region(0)
-{}
+ _r_bottom(r->bottom()), _r_end(r->end()), _oc(oc) { }
class VerifyLiveClosure: public OopClosure {
private:
@@ -512,35 +509,19 @@ HeapRegion::HeapRegion(uint hrs_index,
assert(HeapRegionRemSet::num_par_rem_sets() > 0, "Invariant.");
}
-class NextCompactionHeapRegionClosure: public HeapRegionClosure {
- const HeapRegion* _target;
- bool _target_seen;
- HeapRegion* _last;
- CompactibleSpace* _res;
-public:
- NextCompactionHeapRegionClosure(const HeapRegion* target) :
- _target(target), _target_seen(false), _res(NULL) {}
- bool doHeapRegion(HeapRegion* cur) {
- if (_target_seen) {
- if (!cur->isHumongous()) {
- _res = cur;
- return true;
- }
- } else if (cur == _target) {
- _target_seen = true;
- }
- return false;
- }
- CompactibleSpace* result() { return _res; }
-};
-
CompactibleSpace* HeapRegion::next_compaction_space() const {
+ // We're not using an iterator given that it will wrap around when
+ // it reaches the last region and this is not what we want here.
G1CollectedHeap* g1h = G1CollectedHeap::heap();
- // cast away const-ness
- HeapRegion* r = (HeapRegion*) this;
- NextCompactionHeapRegionClosure blk(r);
- g1h->heap_region_iterate_from(r, &blk);
- return blk.result();
+ uint index = hrs_index() + 1;
+ while (index < g1h->n_regions()) {
+ HeapRegion* hr = g1h->region_at(index);
+ if (!hr->isHumongous()) {
+ return hr;
+ }
+ index += 1;
+ }
+ return NULL;
}
void HeapRegion::save_marks() {
diff --git a/src/share/vm/gc_implementation/g1/heapRegion.hpp b/src/share/vm/gc_implementation/g1/heapRegion.hpp
index a3b4e44b7..8ab893fcf 100644
--- a/src/share/vm/gc_implementation/g1/heapRegion.hpp
+++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp
@@ -55,7 +55,10 @@ class HeapRegionSetBase;
#define HR_FORMAT "%u:(%s)["PTR_FORMAT","PTR_FORMAT","PTR_FORMAT"]"
#define HR_FORMAT_PARAMS(_hr_) \
(_hr_)->hrs_index(), \
- (_hr_)->is_survivor() ? "S" : (_hr_)->is_young() ? "E" : "-", \
+ (_hr_)->is_survivor() ? "S" : (_hr_)->is_young() ? "E" : \
+ (_hr_)->startsHumongous() ? "HS" : \
+ (_hr_)->continuesHumongous() ? "HC" : \
+ !(_hr_)->is_empty() ? "O" : "F", \
(_hr_)->bottom(), (_hr_)->top(), (_hr_)->end()
// sentinel value for hrs_index
@@ -173,6 +176,7 @@ class G1OffsetTableContigSpace: public ContiguousSpace {
virtual HeapWord* saved_mark_word() const;
virtual void set_saved_mark();
void reset_gc_time_stamp() { _gc_time_stamp = 0; }
+ unsigned get_gc_time_stamp() { return _gc_time_stamp; }
// See the comment above in the declaration of _pre_dummy_top for an
// explanation of what it is.
@@ -439,6 +443,25 @@ class HeapRegion: public G1OffsetTableContigSpace {
return _humongous_start_region;
}
+ // Return the number of distinct regions that are covered by this region:
+ // 1 if the region is not humongous, >= 1 if the region is humongous.
+ uint region_num() const {
+ if (!isHumongous()) {
+ return 1U;
+ } else {
+ assert(startsHumongous(), "doesn't make sense on HC regions");
+ assert(capacity() % HeapRegion::GrainBytes == 0, "sanity");
+ return (uint) (capacity() >> HeapRegion::LogOfHRGrainBytes);
+ }
+ }
+
+ // Return the index + 1 of the last HC regions that's associated
+ // with this HS region.
+ uint last_hc_index() const {
+ assert(startsHumongous(), "don't call this otherwise");
+ return hrs_index() + region_num();
+ }
+
// Same as Space::is_in_reserved, but will use the original size of the region.
// The original size is different only for start humongous regions. They get
// their _end set up to be the end of the last continues region of the
@@ -622,8 +645,8 @@ class HeapRegion: public G1OffsetTableContigSpace {
bool is_marked() { return _prev_top_at_mark_start != bottom(); }
void reset_during_compaction() {
- guarantee( isHumongous() && startsHumongous(),
- "should only be called for humongous regions");
+ assert(isHumongous() && startsHumongous(),
+ "should only be called for starts humongous regions");
zero_marked_bytes();
init_top_at_mark_start();
@@ -774,7 +797,7 @@ class HeapRegion: public G1OffsetTableContigSpace {
virtual void oop_since_save_marks_iterate##nv_suffix(OopClosureType* cl);
SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(HeapRegion_OOP_SINCE_SAVE_MARKS_DECL)
- CompactibleSpace* next_compaction_space() const;
+ virtual CompactibleSpace* next_compaction_space() const;
virtual void reset_after_compaction();
diff --git a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp
index 84f7fb0bd..3252b1309 100644
--- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp
+++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.cpp
@@ -34,8 +34,6 @@
#include "utilities/bitMap.inline.hpp"
#include "utilities/globalDefinitions.hpp"
-// OtherRegionsTable
-
class PerRegionTable: public CHeapObj<mtGC> {
friend class OtherRegionsTable;
friend class HeapRegionRemSetIterator;
@@ -44,19 +42,17 @@ class PerRegionTable: public CHeapObj<mtGC> {
BitMap _bm;
jint _occupied;
- // next pointer for free/allocated lis
+ // next pointer for free/allocated 'all' list
PerRegionTable* _next;
- static PerRegionTable* _free_list;
-
-#ifdef _MSC_VER
- // For some reason even though the classes are marked as friend they are unable
- // to access CardsPerRegion when private/protected. Only the windows c++ compiler
- // says this Sun CC and linux gcc don't have a problem with access when private
+ // prev pointer for the allocated 'all' list
+ PerRegionTable* _prev;
- public:
+ // next pointer in collision list
+ PerRegionTable * _collision_list_next;
-#endif // _MSC_VER
+ // Global free list of PRTs
+ static PerRegionTable* _free_list;
protected:
// We need access in order to union things into the base table.
@@ -69,7 +65,8 @@ protected:
PerRegionTable(HeapRegion* hr) :
_hr(hr),
_occupied(0),
- _bm(HeapRegion::CardsPerRegion, false /* in-resource-area */)
+ _bm(HeapRegion::CardsPerRegion, false /* in-resource-area */),
+ _collision_list_next(NULL), _next(NULL), _prev(NULL)
{}
void add_card_work(CardIdx_t from_card, bool par) {
@@ -126,9 +123,13 @@ public:
return _occupied;
}
- void init(HeapRegion* hr) {
+ void init(HeapRegion* hr, bool clear_links_to_all_list) {
+ if (clear_links_to_all_list) {
+ set_next(NULL);
+ set_prev(NULL);
+ }
_hr = hr;
- _next = NULL;
+ _collision_list_next = NULL;
_occupied = 0;
_bm.clear();
}
@@ -175,22 +176,25 @@ public:
return _bm.at(card_ind);
}
- PerRegionTable* next() const { return _next; }
- void set_next(PerRegionTable* nxt) { _next = nxt; }
- PerRegionTable** next_addr() { return &_next; }
-
- static void free(PerRegionTable* prt) {
+ // Bulk-free the PRTs from prt to last, assumes that they are
+ // linked together using their _next field.
+ static void bulk_free(PerRegionTable* prt, PerRegionTable* last) {
while (true) {
PerRegionTable* fl = _free_list;
- prt->set_next(fl);
- PerRegionTable* res =
- (PerRegionTable*)
- Atomic::cmpxchg_ptr(prt, &_free_list, fl);
- if (res == fl) return;
+ last->set_next(fl);
+ PerRegionTable* res = (PerRegionTable*) Atomic::cmpxchg_ptr(prt, &_free_list, fl);
+ if (res == fl) {
+ return;
+ }
}
ShouldNotReachHere();
}
+ static void free(PerRegionTable* prt) {
+ bulk_free(prt, prt);
+ }
+
+ // Returns an initialized PerRegionTable instance.
static PerRegionTable* alloc(HeapRegion* hr) {
PerRegionTable* fl = _free_list;
while (fl != NULL) {
@@ -199,7 +203,7 @@ public:
(PerRegionTable*)
Atomic::cmpxchg_ptr(nxt, &_free_list, fl);
if (res == fl) {
- fl->init(hr);
+ fl->init(hr, true);
return fl;
} else {
fl = _free_list;
@@ -209,6 +213,31 @@ public:
return new PerRegionTable(hr);
}
+ PerRegionTable* next() const { return _next; }
+ void set_next(PerRegionTable* next) { _next = next; }
+ PerRegionTable* prev() const { return _prev; }
+ void set_prev(PerRegionTable* prev) { _prev = prev; }
+
+ // Accessor and Modification routines for the pointer for the
+ // singly linked collision list that links the PRTs within the
+ // OtherRegionsTable::_fine_grain_regions hash table.
+ //
+ // It might be useful to also make the collision list doubly linked
+ // to avoid iteration over the collisions list during scrubbing/deletion.
+ // OTOH there might not be many collisions.
+
+ PerRegionTable* collision_list_next() const {
+ return _collision_list_next;
+ }
+
+ void set_collision_list_next(PerRegionTable* next) {
+ _collision_list_next = next;
+ }
+
+ PerRegionTable** collision_list_next_addr() {
+ return &_collision_list_next;
+ }
+
static size_t fl_mem_size() {
PerRegionTable* cur = _free_list;
size_t res = 0;
@@ -234,6 +263,7 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
_coarse_map(G1CollectedHeap::heap()->max_regions(),
false /* in-resource-area */),
_fine_grain_regions(NULL),
+ _first_all_fine_prts(NULL), _last_all_fine_prts(NULL),
_n_fine_entries(0), _n_coarse_entries(0),
_fine_eviction_start(0),
_sparse_table(hr)
@@ -264,6 +294,66 @@ OtherRegionsTable::OtherRegionsTable(HeapRegion* hr) :
}
}
+void OtherRegionsTable::link_to_all(PerRegionTable* prt) {
+ // We always append to the beginning of the list for convenience;
+ // the order of entries in this list does not matter.
+ if (_first_all_fine_prts != NULL) {
+ assert(_first_all_fine_prts->prev() == NULL, "invariant");
+ _first_all_fine_prts->set_prev(prt);
+ prt->set_next(_first_all_fine_prts);
+ } else {
+ // this is the first element we insert. Adjust the "last" pointer
+ _last_all_fine_prts = prt;
+ assert(prt->next() == NULL, "just checking");
+ }
+ // the new element is always the first element without a predecessor
+ prt->set_prev(NULL);
+ _first_all_fine_prts = prt;
+
+ assert(prt->prev() == NULL, "just checking");
+ assert(_first_all_fine_prts == prt, "just checking");
+ assert((_first_all_fine_prts == NULL && _last_all_fine_prts == NULL) ||
+ (_first_all_fine_prts != NULL && _last_all_fine_prts != NULL),
+ "just checking");
+ assert(_last_all_fine_prts == NULL || _last_all_fine_prts->next() == NULL,
+ "just checking");
+ assert(_first_all_fine_prts == NULL || _first_all_fine_prts->prev() == NULL,
+ "just checking");
+}
+
+void OtherRegionsTable::unlink_from_all(PerRegionTable* prt) {
+ if (prt->prev() != NULL) {
+ assert(_first_all_fine_prts != prt, "just checking");
+ prt->prev()->set_next(prt->next());
+ // removing the last element in the list?
+ if (_last_all_fine_prts == prt) {
+ _last_all_fine_prts = prt->prev();
+ }
+ } else {
+ assert(_first_all_fine_prts == prt, "just checking");
+ _first_all_fine_prts = prt->next();
+ // list is empty now?
+ if (_first_all_fine_prts == NULL) {
+ _last_all_fine_prts = NULL;
+ }
+ }
+
+ if (prt->next() != NULL) {
+ prt->next()->set_prev(prt->prev());
+ }
+
+ prt->set_next(NULL);
+ prt->set_prev(NULL);
+
+ assert((_first_all_fine_prts == NULL && _last_all_fine_prts == NULL) ||
+ (_first_all_fine_prts != NULL && _last_all_fine_prts != NULL),
+ "just checking");
+ assert(_last_all_fine_prts == NULL || _last_all_fine_prts->next() == NULL,
+ "just checking");
+ assert(_first_all_fine_prts == NULL || _first_all_fine_prts->prev() == NULL,
+ "just checking");
+}
+
int** OtherRegionsTable::_from_card_cache = NULL;
size_t OtherRegionsTable::_from_card_cache_max_regions = 0;
size_t OtherRegionsTable::_from_card_cache_mem_size = 0;
@@ -386,13 +476,16 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
if (_n_fine_entries == _max_fine_entries) {
prt = delete_region_table();
+ // There is no need to clear the links to the 'all' list here:
+ // prt will be reused immediately, i.e. remain in the 'all' list.
+ prt->init(from_hr, false /* clear_links_to_all_list */);
} else {
prt = PerRegionTable::alloc(from_hr);
+ link_to_all(prt);
}
- prt->init(from_hr);
PerRegionTable* first_prt = _fine_grain_regions[ind];
- prt->set_next(first_prt); // XXX Maybe move to init?
+ prt->set_collision_list_next(first_prt);
_fine_grain_regions[ind] = prt;
_n_fine_entries++;
@@ -438,7 +531,7 @@ OtherRegionsTable::find_region_table(size_t ind, HeapRegion* hr) const {
assert(0 <= ind && ind < _max_fine_entries, "Preconditions.");
PerRegionTable* prt = _fine_grain_regions[ind];
while (prt != NULL && prt->hr() != hr) {
- prt = prt->next();
+ prt = prt->collision_list_next();
}
// Loop postcondition is the method postcondition.
return prt;
@@ -473,8 +566,8 @@ PerRegionTable* OtherRegionsTable::delete_region_table() {
max_ind = i;
max_occ = cur_occ;
}
- prev = cur->next_addr();
- cur = cur->next();
+ prev = cur->collision_list_next_addr();
+ cur = cur->collision_list_next();
}
i = i + _fine_eviction_stride;
if (i >= _n_fine_entries) i = i - _n_fine_entries;
@@ -503,7 +596,7 @@ PerRegionTable* OtherRegionsTable::delete_region_table() {
}
// Unsplice.
- *max_prev = max->next();
+ *max_prev = max->collision_list_next();
Atomic::inc(&_n_coarsenings);
_n_fine_entries--;
return max;
@@ -534,7 +627,7 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
PerRegionTable* cur = _fine_grain_regions[i];
PerRegionTable** prev = &_fine_grain_regions[i];
while (cur != NULL) {
- PerRegionTable* nxt = cur->next();
+ PerRegionTable* nxt = cur->collision_list_next();
// If the entire region is dead, eliminate.
if (G1RSScrubVerbose) {
gclog_or_tty->print_cr(" For other region %u:",
@@ -542,11 +635,12 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
}
if (!region_bm->at((size_t) cur->hr()->hrs_index())) {
*prev = nxt;
- cur->set_next(NULL);
+ cur->set_collision_list_next(NULL);
_n_fine_entries--;
if (G1RSScrubVerbose) {
gclog_or_tty->print_cr(" deleted via region map.");
}
+ unlink_from_all(cur);
PerRegionTable::free(cur);
} else {
// Do fine-grain elimination.
@@ -560,11 +654,12 @@ void OtherRegionsTable::scrub(CardTableModRefBS* ctbs,
// Did that empty the table completely?
if (cur->occupied() == 0) {
*prev = nxt;
- cur->set_next(NULL);
+ cur->set_collision_list_next(NULL);
_n_fine_entries--;
+ unlink_from_all(cur);
PerRegionTable::free(cur);
} else {
- prev = cur->next_addr();
+ prev = cur->collision_list_next_addr();
}
}
cur = nxt;
@@ -587,13 +682,15 @@ size_t OtherRegionsTable::occupied() const {
size_t OtherRegionsTable::occ_fine() const {
size_t sum = 0;
- for (size_t i = 0; i < _max_fine_entries; i++) {
- PerRegionTable* cur = _fine_grain_regions[i];
- while (cur != NULL) {
- sum += cur->occupied();
- cur = cur->next();
- }
+
+ size_t num = 0;
+ PerRegionTable * cur = _first_all_fine_prts;
+ while (cur != NULL) {
+ sum += cur->occupied();
+ cur = cur->next();
+ num++;
}
+ guarantee(num == _n_fine_entries, "just checking");
return sum;
}
@@ -609,12 +706,10 @@ size_t OtherRegionsTable::mem_size() const {
// Cast away const in this case.
MutexLockerEx x((Mutex*)&_m, Mutex::_no_safepoint_check_flag);
size_t sum = 0;
- for (size_t i = 0; i < _max_fine_entries; i++) {
- PerRegionTable* cur = _fine_grain_regions[i];
- while (cur != NULL) {
- sum += cur->mem_size();
- cur = cur->next();
- }
+ PerRegionTable * cur = _first_all_fine_prts;
+ while (cur != NULL) {
+ sum += cur->mem_size();
+ cur = cur->next();
}
sum += (sizeof(PerRegionTable*) * _max_fine_entries);
sum += (_coarse_map.size_in_words() * HeapWordSize);
@@ -632,22 +727,24 @@ size_t OtherRegionsTable::fl_mem_size() {
}
void OtherRegionsTable::clear_fcc() {
+ size_t hrs_idx = hr()->hrs_index();
for (int i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
- _from_card_cache[i][hr()->hrs_index()] = -1;
+ _from_card_cache[i][hrs_idx] = -1;
}
}
void OtherRegionsTable::clear() {
MutexLockerEx x(&_m, Mutex::_no_safepoint_check_flag);
- for (size_t i = 0; i < _max_fine_entries; i++) {
- PerRegionTable* cur = _fine_grain_regions[i];
- while (cur != NULL) {
- PerRegionTable* nxt = cur->next();
- PerRegionTable::free(cur);
- cur = nxt;
- }
- _fine_grain_regions[i] = NULL;
+ // if there are no entries, skip this step
+ if (_first_all_fine_prts != NULL) {
+ guarantee(_first_all_fine_prts != NULL && _last_all_fine_prts != NULL, "just checking");
+ PerRegionTable::bulk_free(_first_all_fine_prts, _last_all_fine_prts);
+ memset(_fine_grain_regions, 0, _max_fine_entries * sizeof(_fine_grain_regions[0]));
+ } else {
+ guarantee(_first_all_fine_prts == NULL && _last_all_fine_prts == NULL, "just checking");
}
+
+ _first_all_fine_prts = _last_all_fine_prts = NULL;
_sparse_table.clear();
_coarse_map.clear();
_n_fine_entries = 0;
@@ -686,12 +783,13 @@ bool OtherRegionsTable::del_single_region_table(size_t ind,
PerRegionTable** prev_addr = &_fine_grain_regions[ind];
PerRegionTable* prt = *prev_addr;
while (prt != NULL && prt->hr() != hr) {
- prev_addr = prt->next_addr();
- prt = prt->next();
+ prev_addr = prt->collision_list_next_addr();
+ prt = prt->collision_list_next();
}
if (prt != NULL) {
assert(prt->hr() == hr, "Loop postcondition.");
- *prev_addr = prt->next();
+ *prev_addr = prt->collision_list_next();
+ unlink_from_all(prt);
PerRegionTable::free(prt);
_n_fine_entries--;
return true;
@@ -793,7 +891,6 @@ void HeapRegionRemSet::print() const {
G1CollectedHeap::heap()->bot_shared()->address_for_index(card_index);
gclog_or_tty->print_cr(" Card " PTR_FORMAT, card_start);
}
-
if (iter.n_yielded() != occupied()) {
gclog_or_tty->print_cr("Yielded disagrees with occupied:");
gclog_or_tty->print_cr(" %6d yielded (%6d coarse, %6d fine).",
@@ -905,7 +1002,7 @@ bool HeapRegionRemSetIterator::fine_has_next(size_t& card_index) {
while (!fine_has_next()) {
if (_cur_region_cur_card == (size_t) HeapRegion::CardsPerRegion) {
_cur_region_cur_card = 0;
- _fine_cur_prt = _fine_cur_prt->next();
+ _fine_cur_prt = _fine_cur_prt->collision_list_next();
}
if (_fine_cur_prt == NULL) {
fine_find_next_non_null_prt();
diff --git a/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp b/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp
index c1ba2e8f1..1b1d42d7a 100644
--- a/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp
+++ b/src/share/vm/gc_implementation/g1/heapRegionRemSet.hpp
@@ -82,6 +82,14 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
PerRegionTable** _fine_grain_regions;
size_t _n_fine_entries;
+ // The fine grain remembered sets are doubly linked together using
+ // their 'next' and 'prev' fields.
+ // This allows fast bulk freeing of all the fine grain remembered
+ // set entries, and fast finding of all of them without iterating
+ // over the _fine_grain_regions table.
+ PerRegionTable * _first_all_fine_prts;
+ PerRegionTable * _last_all_fine_prts;
+
// Used to sample a subset of the fine grain PRTs to determine which
// PRT to evict and coarsen.
size_t _fine_eviction_start;
@@ -114,6 +122,11 @@ class OtherRegionsTable VALUE_OBJ_CLASS_SPEC {
static size_t _from_card_cache_max_regions;
static size_t _from_card_cache_mem_size;
+ // link/add the given fine grain remembered set into the "all" list
+ void link_to_all(PerRegionTable * prt);
+ // unlink/remove the given fine grain remembered set into the "all" list
+ void unlink_from_all(PerRegionTable * prt);
+
public:
OtherRegionsTable(HeapRegion* hr);
diff --git a/src/share/vm/gc_implementation/g1/heapRegionSet.cpp b/src/share/vm/gc_implementation/g1/heapRegionSet.cpp
index ac5f96b90..c0533c6bf 100644
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.cpp
+++ b/src/share/vm/gc_implementation/g1/heapRegionSet.cpp
@@ -35,14 +35,6 @@ void HeapRegionSetBase::set_unrealistically_long_length(uint len) {
_unrealistically_long_length = len;
}
-uint HeapRegionSetBase::calculate_region_num(HeapRegion* hr) {
- assert(hr->startsHumongous(), "pre-condition");
- assert(hr->capacity() % HeapRegion::GrainBytes == 0, "invariant");
- uint region_num = (uint) (hr->capacity() >> HeapRegion::LogOfHRGrainBytes);
- assert(region_num > 0, "sanity");
- return region_num;
-}
-
void HeapRegionSetBase::fill_in_ext_msg(hrs_ext_msg* msg, const char* message) {
msg->append("[%s] %s ln: %u rn: %u cy: "SIZE_FORMAT" ud: "SIZE_FORMAT,
name(), message, length(), region_num(),
@@ -152,11 +144,7 @@ void HeapRegionSetBase::verify_next_region(HeapRegion* hr) {
guarantee(verify_region(hr, this), hrs_ext_msg(this, "region verification"));
_calc_length += 1;
- if (!hr->isHumongous()) {
- _calc_region_num += 1;
- } else {
- _calc_region_num += calculate_region_num(hr);
- }
+ _calc_region_num += hr->region_num();
_calc_total_capacity_bytes += hr->capacity();
_calc_total_used_bytes += hr->used();
}
@@ -292,7 +280,7 @@ void HeapRegionLinkedList::add_as_head(HeapRegionLinkedList* from_list) {
assert(length() > 0 && _tail != NULL, hrs_ext_msg(this, "invariant"));
from_list->_tail->set_next(_head);
} else {
- assert(length() == 0 && _head == NULL, hrs_ext_msg(this, "invariant"));
+ assert(length() == 0 && _tail == NULL, hrs_ext_msg(this, "invariant"));
_tail = from_list->_tail;
}
_head = from_list->_head;
diff --git a/src/share/vm/gc_implementation/g1/heapRegionSet.hpp b/src/share/vm/gc_implementation/g1/heapRegionSet.hpp
index 1f0ffe167..f2f10d815 100644
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.hpp
+++ b/src/share/vm/gc_implementation/g1/heapRegionSet.hpp
@@ -62,8 +62,6 @@ class HeapRegionSetBase VALUE_OBJ_CLASS_SPEC {
friend class VMStructs;
protected:
- static uint calculate_region_num(HeapRegion* hr);
-
static uint _unrealistically_long_length;
// The number of regions added to the set. If the set contains
diff --git a/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp b/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp
index 8705f40cf..18c754bdc 100644
--- a/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp
+++ b/src/share/vm/gc_implementation/g1/heapRegionSet.inline.hpp
@@ -33,11 +33,7 @@ inline void HeapRegionSetBase::update_for_addition(HeapRegion* hr) {
// Assumes the caller has already verified the region.
_length += 1;
- if (!hr->isHumongous()) {
- _region_num += 1;
- } else {
- _region_num += calculate_region_num(hr);
- }
+ _region_num += hr->region_num();
_total_used_bytes += hr->used();
}
@@ -54,12 +50,7 @@ inline void HeapRegionSetBase::update_for_removal(HeapRegion* hr) {
assert(_length > 0, hrs_ext_msg(this, "pre-condition"));
_length -= 1;
- uint region_num_diff;
- if (!hr->isHumongous()) {
- region_num_diff = 1;
- } else {
- region_num_diff = calculate_region_num(hr);
- }
+ uint region_num_diff = hr->region_num();
assert(region_num_diff <= _region_num,
hrs_err_msg("[%s] region's region num: %u "
"should be <= region num: %u",
diff --git a/src/share/vm/utilities/decoder.cpp b/src/share/vm/utilities/decoder.cpp
index cf7be329f..4a9266f0b 100644
--- a/src/share/vm/utilities/decoder.cpp
+++ b/src/share/vm/utilities/decoder.cpp
@@ -91,6 +91,18 @@ bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const cha
return decoder->decode(addr, buf, buflen, offset, modulepath);
}
+bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const void* base) {
+ assert(_shared_decoder_lock != NULL, "Just check");
+ bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid;
+ MutexLockerEx locker(error_handling_thread ? NULL : _shared_decoder_lock, true);
+ AbstractDecoder* decoder = error_handling_thread ?
+ get_error_handler_instance(): get_shared_instance();
+ assert(decoder != NULL, "null decoder");
+
+ return decoder->decode(addr, buf, buflen, offset, base);
+}
+
+
bool Decoder::demangle(const char* symbol, char* buf, int buflen) {
assert(_shared_decoder_lock != NULL, "Just check");
bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid;
diff --git a/src/share/vm/utilities/decoder.hpp b/src/share/vm/utilities/decoder.hpp
index a24f771b7..0d2af8098 100644
--- a/src/share/vm/utilities/decoder.hpp
+++ b/src/share/vm/utilities/decoder.hpp
@@ -47,6 +47,8 @@ public:
// the function
virtual bool decode(address pc, char* buf, int buflen, int* offset,
const char* modulepath = NULL) = 0;
+ virtual bool decode(address pc, char* buf, int buflen, int* offset, const void* base) = 0;
+
// demangle a C++ symbol
virtual bool demangle(const char* symbol, char* buf, int buflen) = 0;
// if the decoder can decode symbols in vm
@@ -82,6 +84,10 @@ public:
return false;
}
+ virtual bool decode(address pc, char* buf, int buflen, int* offset, const void* base) {
+ return false;
+ }
+
virtual bool demangle(const char* symbol, char* buf, int buflen) {
return false;
}
@@ -95,6 +101,7 @@ public:
class Decoder : AllStatic {
public:
static bool decode(address pc, char* buf, int buflen, int* offset, const char* modulepath = NULL);
+ static bool decode(address pc, char* buf, int buflen, int* offset, const void* base);
static bool demangle(const char* symbol, char* buf, int buflen);
static bool can_decode_C_frame_in_vm();
diff --git a/src/share/vm/utilities/decoder_elf.hpp b/src/share/vm/utilities/decoder_elf.hpp
index 971cd3c22..79652aeff 100644
--- a/src/share/vm/utilities/decoder_elf.hpp
+++ b/src/share/vm/utilities/decoder_elf.hpp
@@ -43,6 +43,10 @@ public:
bool demangle(const char* symbol, char *buf, int buflen);
bool decode(address addr, char *buf, int buflen, int* offset, const char* filepath = NULL);
+ bool decode(address addr, char *buf, int buflen, int* offset, const void *base) {
+ ShouldNotReachHere();
+ return false;
+ }
private:
ElfFile* get_elf_file(const char* filepath);
diff --git a/src/share/vm/utilities/hashtable.cpp b/src/share/vm/utilities/hashtable.cpp
index 39092d95f..68b433ca9 100644
--- a/src/share/vm/utilities/hashtable.cpp
+++ b/src/share/vm/utilities/hashtable.cpp
@@ -135,7 +135,7 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::move_to(Hashtable<T, F>* ne
// walking the hashtable past these entries requires
// BasicHashtableEntry::make_ptr() call.
bool keep_shared = p->is_shared();
- unlink_entry(p);
+ this->unlink_entry(p);
new_table->add_entry(index, p);
if (keep_shared) {
p->set_shared();
diff --git a/src/share/vm/utilities/hashtable.hpp b/src/share/vm/utilities/hashtable.hpp
index de7d319c0..24347c2e4 100644
--- a/src/share/vm/utilities/hashtable.hpp
+++ b/src/share/vm/utilities/hashtable.hpp
@@ -260,7 +260,7 @@ protected:
}
int index_for(Symbol* name) {
- return hash_to_index(compute_hash(name));
+ return this->hash_to_index(compute_hash(name));
}
// Table entry management