This commit is contained in:
Alejandro Murillo 2016-07-15 09:05:33 -07:00
commit 84a55fcca8
71 changed files with 1489 additions and 672 deletions

View File

@ -51,6 +51,7 @@ BUILD_HOTSPOT_JTREG_NATIVE_SRC := \
$(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \ $(HOTSPOT_TOPDIR)/test/compiler/floatingpoint/ \
$(HOTSPOT_TOPDIR)/test/compiler/calls \ $(HOTSPOT_TOPDIR)/test/compiler/calls \
$(HOTSPOT_TOPDIR)/test/compiler/native \ $(HOTSPOT_TOPDIR)/test/compiler/native \
$(HOTSPOT_TOPDIR)/test/serviceability/jvmti/GetNamedModule \
$(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \ $(HOTSPOT_TOPDIR)/test/testlibrary/jvmti \
# #
@ -64,6 +65,7 @@ endif
ifeq ($(TOOLCHAIN_TYPE), solstudio) ifeq ($(TOOLCHAIN_TYPE), solstudio)
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_liboverflow := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_liboverflow := -lc
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libSimpleClassFileLoadHook := -lc BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libSimpleClassFileLoadHook := -lc
BUILD_HOTSPOT_JTREG_LIBRARIES_LDFLAGS_libGetNamedModuleTest := -lc
endif endif
BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native BUILD_HOTSPOT_JTREG_OUTPUT_DIR := $(BUILD_OUTPUT)/support/test/hotspot/jtreg/native

View File

@ -1742,11 +1742,11 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
} }
typedef struct { typedef struct {
Elf32_Half code; // Actual value as defined in elf.h Elf32_Half code; // Actual value as defined in elf.h
Elf32_Half compat_class; // Compatibility of archs at VM's sense Elf32_Half compat_class; // Compatibility of archs at VM's sense
char elf_class; // 32 or 64 bit unsigned char elf_class; // 32 or 64 bit
char endianess; // MSB or LSB unsigned char endianess; // MSB or LSB
char* name; // String representation char* name; // String representation
} arch_t; } arch_t;
#ifndef EM_486 #ifndef EM_486

View File

@ -1320,36 +1320,8 @@ bool os::getTimesSecs(double* process_real_time,
} }
bool os::supports_vtime() { return true; } bool os::supports_vtime() { return true; }
bool os::enable_vtime() { return false; }
bool os::enable_vtime() { bool os::vtime_enabled() { return false; }
int fd = ::open("/proc/self/ctl", O_WRONLY);
if (fd == -1) {
return false;
}
long cmd[] = { PCSET, PR_MSACCT };
int res = ::write(fd, cmd, sizeof(long) * 2);
::close(fd);
if (res != sizeof(long) * 2) {
return false;
}
return true;
}
bool os::vtime_enabled() {
int fd = ::open("/proc/self/status", O_RDONLY);
if (fd == -1) {
return false;
}
pstatus_t status;
int res = os::read(fd, (void*) &status, sizeof(pstatus_t));
::close(fd);
if (res != sizeof(pstatus_t)) {
return false;
}
return status.pr_flags & PR_MSACCT;
}
double os::elapsedVTime() { double os::elapsedVTime() {
return (double)gethrvtime() / (double)hrtime_hz; return (double)gethrvtime() / (double)hrtime_hz;

View File

@ -224,7 +224,7 @@ static const jchar ONE_CHAR[] = { (jchar) 0x8180};
static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82}; static const jbyte THREE_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82};
static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83}; static const jbyte FOUR_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83};
static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382}; static const jchar TWO_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382};
static const jint ONE_INT[] = { 0x83828180}; static const jint ONE_INT[] = { (jint)0x83828180};
static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85}; static const jbyte SIX_BYTE[] = { (jbyte) 0x80, (jbyte) 0x81, (jbyte) 0x82, (jbyte) 0x83, (jbyte) 0x84, (jbyte) 0x85};
static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584}; static const jchar THREE_CHAR[] = { (jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8584};
static const jbyte EIGHT_BYTE[] = { static const jbyte EIGHT_BYTE[] = {
@ -235,7 +235,7 @@ static const jchar FOUR_CHAR[] = {
(jchar) 0x8180, (jchar) 0x8382, (jchar) 0x8180, (jchar) 0x8382,
(jchar) 0x8584, (jchar) 0x8786}; (jchar) 0x8584, (jchar) 0x8786};
static const jint TWO_INT[] = { 0x83828180, 0x87868584}; static const jint TWO_INT[] = { (jint)0x83828180, (jint)0x87868584};
static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3; static const juint MURMUR3_32_X86_CHECK_VALUE = 0xB0F57EE3;

View File

@ -142,7 +142,9 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m
f->do_oop(&_class_loader); f->do_oop(&_class_loader);
_dependencies.oops_do(f); _dependencies.oops_do(f);
_handles->oops_do(f); if (_handles != NULL) {
_handles->oops_do(f);
}
if (klass_closure != NULL) { if (klass_closure != NULL) {
classes_do(klass_closure); classes_do(klass_closure);
} }

View File

@ -871,12 +871,17 @@ void java_lang_Class::fixup_module_field(KlassHandle k, Handle module) {
int java_lang_Class::oop_size(oop java_class) { int java_lang_Class::oop_size(oop java_class) {
assert(_oop_size_offset != 0, "must be set"); assert(_oop_size_offset != 0, "must be set");
return java_class->int_field(_oop_size_offset); int size = java_class->int_field(_oop_size_offset);
assert(size > 0, "Oop size must be greater than zero, not %d", size);
return size;
} }
void java_lang_Class::set_oop_size(oop java_class, int size) { void java_lang_Class::set_oop_size(oop java_class, int size) {
assert(_oop_size_offset != 0, "must be set"); assert(_oop_size_offset != 0, "must be set");
assert(size > 0, "Oop size must be greater than zero, not %d", size);
java_class->int_field_put(_oop_size_offset, size); java_class->int_field_put(_oop_size_offset, size);
} }
int java_lang_Class::static_oop_field_count(oop java_class) { int java_lang_Class::static_oop_field_count(oop java_class) {
assert(_static_oop_field_count_offset != 0, "must be set"); assert(_static_oop_field_count_offset != 0, "must be set");
return java_class->int_field(_static_oop_field_count_offset); return java_class->int_field(_static_oop_field_count_offset);

View File

@ -275,7 +275,6 @@ class java_lang_Class : AllStatic {
static int static_oop_field_count(oop java_class); static int static_oop_field_count(oop java_class);
static void set_static_oop_field_count(oop java_class, int size); static void set_static_oop_field_count(oop java_class, int size);
static GrowableArray<Klass*>* fixup_mirror_list() { static GrowableArray<Klass*>* fixup_mirror_list() {
return _fixup_mirror_list; return _fixup_mirror_list;
} }

View File

@ -820,6 +820,28 @@ jobject Modules::get_module_by_package_name(jobject loader, jstring package, TRA
} }
jobject Modules::get_named_module(Handle h_loader, const char* package_str, TRAPS) {
assert(ModuleEntryTable::javabase_defined(),
"Attempt to call get_named_module before java.base is defined");
assert(h_loader.is_null() || java_lang_ClassLoader::is_subclass(h_loader->klass()),
"Class loader is not a subclass of java.lang.ClassLoader");
assert(package_str != NULL, "the package_str should not be NULL");
if (strlen(package_str) == 0) {
return NULL;
}
TempNewSymbol package_sym = SymbolTable::new_symbol(package_str, CHECK_NULL);
const PackageEntry* const pkg_entry =
get_package_entry_by_name(package_sym, h_loader, THREAD);
const ModuleEntry* const module_entry = (pkg_entry != NULL ? pkg_entry->module() : NULL);
if (module_entry != NULL && module_entry->module() != NULL && module_entry->is_named()) {
return JNIHandles::make_local(THREAD, JNIHandles::resolve(module_entry->module()));
}
return NULL;
}
// This method is called by JFR and by the above method. // This method is called by JFR and by the above method.
jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) { jobject Modules::get_module(Symbol* package_name, Handle h_loader, TRAPS) {
const PackageEntry* const pkg_entry = const PackageEntry* const pkg_entry =

View File

@ -121,6 +121,7 @@ public:
// IllegalArgumentException is thrown if loader is neither null nor a subtype of // IllegalArgumentException is thrown if loader is neither null nor a subtype of
// java/lang/ClassLoader. // java/lang/ClassLoader.
static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS); static jobject get_module_by_package_name(jobject loader, jstring package, TRAPS);
static jobject get_named_module(Handle h_loader, const char* package, TRAPS);
// If package is defined by loader, return the // If package is defined by loader, return the
// java.lang.reflect.Module object for the module in which the package is defined. // java.lang.reflect.Module object for the module in which the package is defined.

View File

@ -1256,9 +1256,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc,
// set between the last GC or pause and now. We need to clear the // set between the last GC or pause and now. We need to clear the
// incremental collection set and then start rebuilding it afresh // incremental collection set and then start rebuilding it afresh
// after this full GC. // after this full GC.
abandon_collection_set(collection_set()->inc_head()); abandon_collection_set(collection_set());
collection_set()->clear_incremental();
collection_set()->stop_incremental_building();
tear_down_region_sets(false /* free_list_only */); tear_down_region_sets(false /* free_list_only */);
collector_state()->set_gcs_are_young(true); collector_state()->set_gcs_are_young(true);
@ -1379,7 +1377,6 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc,
_verifier->check_bitmaps("Full GC End"); _verifier->check_bitmaps("Full GC End");
// Start a new incremental collection set for the next pause // Start a new incremental collection set for the next pause
assert(collection_set()->head() == NULL, "must be");
collection_set()->start_incremental_building(); collection_set()->start_incremental_building();
clear_cset_fast_test(); clear_cset_fast_test();
@ -1724,8 +1721,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* collector_policy) :
_old_marking_cycles_started(0), _old_marking_cycles_started(0),
_old_marking_cycles_completed(0), _old_marking_cycles_completed(0),
_in_cset_fast_test(), _in_cset_fast_test(),
_worker_cset_start_region(NULL),
_worker_cset_start_region_time_stamp(NULL),
_gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()), _gc_timer_stw(new (ResourceObj::C_HEAP, mtGC) STWGCTimer()),
_gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()) { _gc_tracer_stw(new (ResourceObj::C_HEAP, mtGC) G1NewTracer()) {
@ -1748,8 +1743,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* collector_policy) :
uint n_queues = ParallelGCThreads; uint n_queues = ParallelGCThreads;
_task_queues = new RefToScanQueueSet(n_queues); _task_queues = new RefToScanQueueSet(n_queues);
_worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues, mtGC);
_worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(uint, n_queues, mtGC);
_evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC); _evacuation_failed_info_array = NEW_C_HEAP_ARRAY(EvacuationFailedInfo, n_queues, mtGC);
for (uint i = 0; i < n_queues; i++) { for (uint i = 0; i < n_queues; i++) {
@ -1758,7 +1751,6 @@ G1CollectedHeap::G1CollectedHeap(G1CollectorPolicy* collector_policy) :
_task_queues->register_queue(i, q); _task_queues->register_queue(i, q);
::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo(); ::new (&_evacuation_failed_info_array[i]) EvacuationFailedInfo();
} }
clear_cset_start_regions();
// Initialize the G1EvacuationFailureALot counters and flags. // Initialize the G1EvacuationFailureALot counters and flags.
NOT_PRODUCT(reset_evacuation_should_fail();) NOT_PRODUCT(reset_evacuation_should_fail();)
@ -1987,6 +1979,8 @@ jint G1CollectedHeap::initialize() {
_preserved_marks_set.init(ParallelGCThreads); _preserved_marks_set.init(ParallelGCThreads);
_collection_set.initialize(max_regions());
return JNI_OK; return JNI_OK;
} }
@ -2420,117 +2414,12 @@ G1CollectedHeap::heap_region_par_iterate(HeapRegionClosure* cl,
_hrm.par_iterate(cl, worker_id, hrclaimer, concurrent); _hrm.par_iterate(cl, worker_id, hrclaimer, concurrent);
} }
// Clear the cached CSet starting regions and (more importantly)
// the time stamps. Called when we reset the GC time stamp.
void G1CollectedHeap::clear_cset_start_regions() {
assert(_worker_cset_start_region != NULL, "sanity");
assert(_worker_cset_start_region_time_stamp != NULL, "sanity");
for (uint i = 0; i < ParallelGCThreads; i++) {
_worker_cset_start_region[i] = NULL;
_worker_cset_start_region_time_stamp[i] = 0;
}
}
// Given the id of a worker, obtain or calculate a suitable
// starting region for iterating over the current collection set.
HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) {
assert(get_gc_time_stamp() > 0, "should have been updated by now");
HeapRegion* result = NULL;
unsigned gc_time_stamp = get_gc_time_stamp();
if (_worker_cset_start_region_time_stamp[worker_i] == gc_time_stamp) {
// Cached starting region for current worker was set
// during the current pause - so it's valid.
// Note: the cached starting heap region may be NULL
// (when the collection set is empty).
result = _worker_cset_start_region[worker_i];
assert(result == NULL || result->in_collection_set(), "sanity");
return result;
}
// The cached entry was not valid so let's calculate
// a suitable starting heap region for this worker.
// We want the parallel threads to start their collection
// set iteration at different collection set regions to
// avoid contention.
// If we have:
// n collection set regions
// p threads
// Then thread t will start at region floor ((t * n) / p)
result = collection_set()->head();
uint cs_size = collection_set()->region_length();
uint active_workers = workers()->active_workers();
uint end_ind = (cs_size * worker_i) / active_workers;
uint start_ind = 0;
if (worker_i > 0 &&
_worker_cset_start_region_time_stamp[worker_i - 1] == gc_time_stamp) {
// Previous workers starting region is valid
// so let's iterate from there
start_ind = (cs_size * (worker_i - 1)) / active_workers;
OrderAccess::loadload();
result = _worker_cset_start_region[worker_i - 1];
}
for (uint i = start_ind; i < end_ind; i++) {
result = result->next_in_collection_set();
}
// Note: the calculated starting heap region may be NULL
// (when the collection set is empty).
assert(result == NULL || result->in_collection_set(), "sanity");
assert(_worker_cset_start_region_time_stamp[worker_i] != gc_time_stamp,
"should be updated only once per pause");
_worker_cset_start_region[worker_i] = result;
OrderAccess::storestore();
_worker_cset_start_region_time_stamp[worker_i] = gc_time_stamp;
return result;
}
void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) { void G1CollectedHeap::collection_set_iterate(HeapRegionClosure* cl) {
HeapRegion* r = collection_set()->head(); _collection_set.iterate(cl);
while (r != NULL) {
HeapRegion* next = r->next_in_collection_set();
if (cl->doHeapRegion(r)) {
cl->incomplete();
return;
}
r = next;
}
} }
void G1CollectedHeap::collection_set_iterate_from(HeapRegion* r, void G1CollectedHeap::collection_set_iterate_from(HeapRegionClosure *cl, uint worker_id) {
HeapRegionClosure *cl) { _collection_set.iterate_from(cl, worker_id, workers()->active_workers());
if (r == NULL) {
// The CSet is empty so there's nothing to do.
return;
}
assert(r->in_collection_set(),
"Start region must be a member of the collection set.");
HeapRegion* cur = r;
while (cur != NULL) {
HeapRegion* next = cur->next_in_collection_set();
if (cl->doHeapRegion(cur) && false) {
cl->incomplete();
return;
}
cur = next;
}
cur = collection_set()->head();
while (cur != r) {
HeapRegion* next = cur->next_in_collection_set();
if (cl->doHeapRegion(cur) && false) {
cl->incomplete();
return;
}
cur = next;
}
} }
HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const { HeapRegion* G1CollectedHeap::next_compaction_region(const HeapRegion* from) const {
@ -3090,6 +2979,18 @@ void G1CollectedHeap::wait_for_root_region_scanning() {
g1_policy()->phase_times()->record_root_region_scan_wait_time(wait_time_ms); g1_policy()->phase_times()->record_root_region_scan_wait_time(wait_time_ms);
} }
class G1PrintCollectionSetClosure : public HeapRegionClosure {
private:
G1HRPrinter* _hr_printer;
public:
G1PrintCollectionSetClosure(G1HRPrinter* hr_printer) : HeapRegionClosure(), _hr_printer(hr_printer) { }
virtual bool doHeapRegion(HeapRegion* r) {
_hr_printer->cset(r);
return false;
}
};
bool bool
G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) { G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
assert_at_safepoint(true /* should_be_vm_thread */); assert_at_safepoint(true /* should_be_vm_thread */);
@ -3268,11 +3169,8 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
_cm->verify_no_cset_oops(); _cm->verify_no_cset_oops();
if (_hr_printer.is_active()) { if (_hr_printer.is_active()) {
HeapRegion* hr = collection_set()->head(); G1PrintCollectionSetClosure cl(&_hr_printer);
while (hr != NULL) { _collection_set.iterate(&cl);
_hr_printer.cset(hr);
hr = hr->next_in_collection_set();
}
} }
// Initialize the GC alloc regions. // Initialize the GC alloc regions.
@ -3287,12 +3185,10 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
post_evacuate_collection_set(evacuation_info, &per_thread_states); post_evacuate_collection_set(evacuation_info, &per_thread_states);
const size_t* surviving_young_words = per_thread_states.surviving_young_words(); const size_t* surviving_young_words = per_thread_states.surviving_young_words();
free_collection_set(collection_set()->head(), evacuation_info, surviving_young_words); free_collection_set(&_collection_set, evacuation_info, surviving_young_words);
eagerly_reclaim_humongous_regions(); eagerly_reclaim_humongous_regions();
collection_set()->clear_head();
record_obj_copy_mem_stats(); record_obj_copy_mem_stats();
_survivor_evac_stats.adjust_desired_plab_sz(); _survivor_evac_stats.adjust_desired_plab_sz();
_old_evac_stats.adjust_desired_plab_sz(); _old_evac_stats.adjust_desired_plab_sz();
@ -4704,120 +4600,139 @@ void G1CollectedHeap::scrub_rem_set() {
workers()->run_task(&g1_par_scrub_rs_task); workers()->run_task(&g1_par_scrub_rs_task);
} }
void G1CollectedHeap::free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info, const size_t* surviving_young_words) { class G1FreeCollectionSetClosure : public HeapRegionClosure {
size_t pre_used = 0; private:
FreeRegionList local_free_list("Local List for CSet Freeing"); const size_t* _surviving_young_words;
double young_time_ms = 0.0; FreeRegionList _local_free_list;
double non_young_time_ms = 0.0; size_t _rs_lengths;
// Bytes used in successfully evacuated regions before the evacuation.
size_t _before_used_bytes;
// Bytes used in unsucessfully evacuated regions before the evacuation
size_t _after_used_bytes;
_eden.clear(); size_t _bytes_allocated_in_old_since_last_gc;
G1Policy* policy = g1_policy(); size_t _failure_used_words;
size_t _failure_waste_words;
double start_sec = os::elapsedTime(); double _young_time;
bool non_young = true; double _non_young_time;
public:
G1FreeCollectionSetClosure(const size_t* surviving_young_words) :
HeapRegionClosure(),
_surviving_young_words(surviving_young_words),
_local_free_list("Local Region List for CSet Freeing"),
_rs_lengths(0),
_before_used_bytes(0),
_after_used_bytes(0),
_bytes_allocated_in_old_since_last_gc(0),
_failure_used_words(0),
_failure_waste_words(0),
_young_time(0.0),
_non_young_time(0.0) {
}
HeapRegion* cur = cs_head; virtual bool doHeapRegion(HeapRegion* r) {
int age_bound = -1; double start_time = os::elapsedTime();
size_t rs_lengths = 0;
while (cur != NULL) { bool is_young = r->is_young();
assert(!is_on_master_free_list(cur), "sanity");
if (non_young) {
if (cur->is_young()) {
double end_sec = os::elapsedTime();
double elapsed_ms = (end_sec - start_sec) * 1000.0;
non_young_time_ms += elapsed_ms;
start_sec = os::elapsedTime(); G1CollectedHeap* g1h = G1CollectedHeap::heap();
non_young = false; assert(!g1h->is_on_master_free_list(r), "sanity");
}
_rs_lengths += r->rem_set()->occupied_locked();
assert(r->in_collection_set(), "Region %u should be in collection set.", r->hrm_index());
g1h->clear_in_cset(r);
if (is_young) {
int index = r->young_index_in_cset();
assert(index != -1, "Young index in collection set must not be -1 for region %u", r->hrm_index());
assert((uint) index < g1h->collection_set()->young_region_length(), "invariant");
size_t words_survived = _surviving_young_words[index];
r->record_surv_words_in_group(words_survived);
} else { } else {
if (!cur->is_young()) { assert(r->young_index_in_cset() == -1, "Young index for old region %u in collection set must be -1", r->hrm_index());
double end_sec = os::elapsedTime();
double elapsed_ms = (end_sec - start_sec) * 1000.0;
young_time_ms += elapsed_ms;
start_sec = os::elapsedTime();
non_young = true;
}
} }
rs_lengths += cur->rem_set()->occupied_locked(); if (!r->evacuation_failed()) {
assert(r->not_empty(), "Region %u is an empty region in the collection set.", r->hrm_index());
HeapRegion* next = cur->next_in_collection_set(); _before_used_bytes += r->used();
assert(cur->in_collection_set(), "bad CS"); g1h->free_region(r, &_local_free_list, false /* par */, true /* locked */);
cur->set_next_in_collection_set(NULL);
clear_in_cset(cur);
if (cur->is_young()) {
int index = cur->young_index_in_cset();
assert(index != -1, "invariant");
assert((uint) index < collection_set()->young_region_length(), "invariant");
size_t words_survived = surviving_young_words[index];
cur->record_surv_words_in_group(words_survived);
} else { } else {
int index = cur->young_index_in_cset(); r->uninstall_surv_rate_group();
assert(index == -1, "invariant"); r->set_young_index_in_cset(-1);
} r->set_evacuation_failed(false);
assert( (cur->is_young() && cur->young_index_in_cset() > -1) ||
(!cur->is_young() && cur->young_index_in_cset() == -1),
"invariant" );
if (!cur->evacuation_failed()) {
MemRegion used_mr = cur->used_region();
// And the region is empty.
assert(!used_mr.is_empty(), "Should not have empty regions in a CS.");
pre_used += cur->used();
free_region(cur, &local_free_list, false /* par */, true /* locked */);
} else {
cur->uninstall_surv_rate_group();
if (cur->is_young()) {
cur->set_young_index_in_cset(-1);
}
cur->set_evacuation_failed(false);
// When moving a young gen region to old gen, we "allocate" that whole region // When moving a young gen region to old gen, we "allocate" that whole region
// there. This is in addition to any already evacuated objects. Notify the // there. This is in addition to any already evacuated objects. Notify the
// policy about that. // policy about that.
// Old gen regions do not cause an additional allocation: both the objects // Old gen regions do not cause an additional allocation: both the objects
// still in the region and the ones already moved are accounted for elsewhere. // still in the region and the ones already moved are accounted for elsewhere.
if (cur->is_young()) { if (is_young) {
policy->add_bytes_allocated_in_old_since_last_gc(HeapRegion::GrainBytes); _bytes_allocated_in_old_since_last_gc += HeapRegion::GrainBytes;
} }
// The region is now considered to be old. // The region is now considered to be old.
cur->set_old(); r->set_old();
// Do some allocation statistics accounting. Regions that failed evacuation // Do some allocation statistics accounting. Regions that failed evacuation
// are always made old, so there is no need to update anything in the young // are always made old, so there is no need to update anything in the young
// gen statistics, but we need to update old gen statistics. // gen statistics, but we need to update old gen statistics.
size_t used_words = cur->marked_bytes() / HeapWordSize; size_t used_words = r->marked_bytes() / HeapWordSize;
_old_evac_stats.add_failure_used_and_waste(used_words, HeapRegion::GrainWords - used_words);
_old_set.add(cur); _failure_used_words += used_words;
evacuation_info.increment_collectionset_used_after(cur->used()); _failure_waste_words += HeapRegion::GrainWords - used_words;
g1h->old_set_add(r);
_after_used_bytes += r->used();
} }
cur = next;
if (is_young) {
_young_time += os::elapsedTime() - start_time;
} else {
_non_young_time += os::elapsedTime() - start_time;
}
return false;
} }
evacuation_info.set_regions_freed(local_free_list.length()); FreeRegionList* local_free_list() { return &_local_free_list; }
policy->record_max_rs_lengths(rs_lengths); size_t rs_lengths() const { return _rs_lengths; }
size_t before_used_bytes() const { return _before_used_bytes; }
size_t after_used_bytes() const { return _after_used_bytes; }
size_t bytes_allocated_in_old_since_last_gc() const { return _bytes_allocated_in_old_since_last_gc; }
size_t failure_used_words() const { return _failure_used_words; }
size_t failure_waste_words() const { return _failure_waste_words; }
double young_time() const { return _young_time; }
double non_young_time() const { return _non_young_time; }
};
void G1CollectedHeap::free_collection_set(G1CollectionSet* collection_set, EvacuationInfo& evacuation_info, const size_t* surviving_young_words) {
_eden.clear();
G1FreeCollectionSetClosure cl(surviving_young_words);
collection_set_iterate(&cl);
evacuation_info.set_regions_freed(cl.local_free_list()->length());
evacuation_info.increment_collectionset_used_after(cl.after_used_bytes());
G1Policy* policy = g1_policy();
policy->record_max_rs_lengths(cl.rs_lengths());
policy->cset_regions_freed(); policy->cset_regions_freed();
double end_sec = os::elapsedTime(); prepend_to_freelist(cl.local_free_list());
double elapsed_ms = (end_sec - start_sec) * 1000.0; decrement_summary_bytes(cl.before_used_bytes());
if (non_young) { policy->add_bytes_allocated_in_old_since_last_gc(cl.bytes_allocated_in_old_since_last_gc());
non_young_time_ms += elapsed_ms;
} else {
young_time_ms += elapsed_ms;
}
prepend_to_freelist(&local_free_list); _old_evac_stats.add_failure_used_and_waste(cl.failure_used_words(), cl.failure_waste_words());
decrement_summary_bytes(pre_used);
policy->phase_times()->record_young_free_cset_time_ms(young_time_ms); policy->phase_times()->record_young_free_cset_time_ms(cl.young_time() * 1000.0);
policy->phase_times()->record_non_young_free_cset_time_ms(non_young_time_ms); policy->phase_times()->record_non_young_free_cset_time_ms(cl.non_young_time() * 1000.0);
collection_set->clear();
} }
class G1FreeHumongousRegionClosure : public HeapRegionClosure { class G1FreeHumongousRegionClosure : public HeapRegionClosure {
@ -4960,25 +4875,22 @@ void G1CollectedHeap::eagerly_reclaim_humongous_regions() {
cl.humongous_free_count()); cl.humongous_free_count());
} }
// This routine is similar to the above but does not record class G1AbandonCollectionSetClosure : public HeapRegionClosure {
// any policy statistics or update free lists; we are abandoning public:
// the current incremental collection set in preparation of a virtual bool doHeapRegion(HeapRegion* r) {
// full collection. After the full GC we will start to build up assert(r->in_collection_set(), "Region %u must have been in collection set", r->hrm_index());
// the incremental collection set again. G1CollectedHeap::heap()->clear_in_cset(r);
// This is only called when we're doing a full collection r->set_young_index_in_cset(-1);
// and is immediately followed by the tearing down of the young list. return false;
void G1CollectedHeap::abandon_collection_set(HeapRegion* cs_head) {
HeapRegion* cur = cs_head;
while (cur != NULL) {
HeapRegion* next = cur->next_in_collection_set();
assert(cur->in_collection_set(), "bad CS");
cur->set_next_in_collection_set(NULL);
clear_in_cset(cur);
cur->set_young_index_in_cset(-1);
cur = next;
} }
};
void G1CollectedHeap::abandon_collection_set(G1CollectionSet* collection_set) {
G1AbandonCollectionSetClosure cl;
collection_set->iterate(&cl);
collection_set->clear();
collection_set->stop_incremental_building();
} }
void G1CollectedHeap::set_free_regions_coming() { void G1CollectedHeap::set_free_regions_coming() {

View File

@ -778,13 +778,13 @@ protected:
// The closure used to refine a single card. // The closure used to refine a single card.
RefineCardTableEntryClosure* _refine_cte_cl; RefineCardTableEntryClosure* _refine_cte_cl;
// After a collection pause, make the regions in the CS into free // After a collection pause, convert the regions in the collection set into free
// regions. // regions.
void free_collection_set(HeapRegion* cs_head, EvacuationInfo& evacuation_info, const size_t* surviving_young_words); void free_collection_set(G1CollectionSet* collection_set, EvacuationInfo& evacuation_info, const size_t* surviving_young_words);
// Abandon the current collection set without recording policy // Abandon the current collection set without recording policy
// statistics or updating free lists. // statistics or updating free lists.
void abandon_collection_set(HeapRegion* cs_head); void abandon_collection_set(G1CollectionSet* collection_set);
// The concurrent marker (and the thread it runs in.) // The concurrent marker (and the thread it runs in.)
G1ConcurrentMark* _cm; G1ConcurrentMark* _cm;
@ -930,16 +930,6 @@ protected:
// discovery. // discovery.
G1CMIsAliveClosure _is_alive_closure_cm; G1CMIsAliveClosure _is_alive_closure_cm;
// Cache used by G1CollectedHeap::start_cset_region_for_worker().
HeapRegion** _worker_cset_start_region;
// Time stamp to validate the regions recorded in the cache
// used by G1CollectedHeap::start_cset_region_for_worker().
// The heap region entry for a given worker is valid iff
// the associated time stamp value matches the current value
// of G1CollectedHeap::_gc_time_stamp.
uint* _worker_cset_start_region_time_stamp;
volatile bool _free_regions_coming; volatile bool _free_regions_coming;
public: public:
@ -1211,19 +1201,14 @@ public:
HeapRegionClaimer* hrclaimer, HeapRegionClaimer* hrclaimer,
bool concurrent = false) const; bool concurrent = false) const;
// Clear the cached cset start regions and (more importantly)
// the time stamps. Called when we reset the GC time stamp.
void clear_cset_start_regions();
// Given the id of a worker, obtain or calculate a suitable
// starting region for iterating over the current collection set.
HeapRegion* start_cset_region_for_worker(uint worker_i);
// Iterate over the regions (if any) in the current collection set. // Iterate over the regions (if any) in the current collection set.
void collection_set_iterate(HeapRegionClosure* blk); void collection_set_iterate(HeapRegionClosure* blk);
// As above but starting from region r // Iterate over the regions (if any) in the current collection set. Starts the
void collection_set_iterate_from(HeapRegion* r, HeapRegionClosure *blk); // iteration over the entire collection set so that the start regions of a given
// worker id over the set active_workers are evenly spread across the set of
// collection set regions.
void collection_set_iterate_from(HeapRegionClosure *blk, uint worker_id);
HeapRegion* next_compaction_region(const HeapRegion* from) const; HeapRegion* next_compaction_region(const HeapRegion* from) const;

View File

@ -89,16 +89,13 @@ inline HeapRegion* G1CollectedHeap::heap_region_containing(const T addr) const {
} }
inline void G1CollectedHeap::reset_gc_time_stamp() { inline void G1CollectedHeap::reset_gc_time_stamp() {
assert_at_safepoint(true);
_gc_time_stamp = 0; _gc_time_stamp = 0;
OrderAccess::fence();
// Clear the cached CSet starting regions and time stamps.
// Their validity is dependent on the GC timestamp.
clear_cset_start_regions();
} }
inline void G1CollectedHeap::increment_gc_time_stamp() { inline void G1CollectedHeap::increment_gc_time_stamp() {
assert_at_safepoint(true);
++_gc_time_stamp; ++_gc_time_stamp;
OrderAccess::fence();
} }
inline void G1CollectedHeap::old_set_add(HeapRegion* hr) { inline void G1CollectedHeap::old_set_add(HeapRegion* hr) {

View File

@ -30,6 +30,7 @@
#include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp" #include "gc/g1/heapRegionRemSet.hpp"
#include "gc/g1/heapRegionSet.hpp" #include "gc/g1/heapRegionSet.hpp"
#include "logging/logStream.hpp"
#include "utilities/debug.hpp" #include "utilities/debug.hpp"
G1CollectorState* G1CollectionSet::collector_state() { G1CollectorState* G1CollectionSet::collector_state() {
@ -55,48 +56,63 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) :
_eden_region_length(0), _eden_region_length(0),
_survivor_region_length(0), _survivor_region_length(0),
_old_region_length(0), _old_region_length(0),
_head(NULL),
_bytes_used_before(0), _bytes_used_before(0),
_recorded_rs_lengths(0), _recorded_rs_lengths(0),
_collection_set_regions(NULL),
_collection_set_cur_length(0),
_collection_set_max_length(0),
// Incremental CSet attributes // Incremental CSet attributes
_inc_build_state(Inactive), _inc_build_state(Inactive),
_inc_head(NULL),
_inc_tail(NULL),
_inc_bytes_used_before(0), _inc_bytes_used_before(0),
_inc_recorded_rs_lengths(0), _inc_recorded_rs_lengths(0),
_inc_recorded_rs_lengths_diffs(0), _inc_recorded_rs_lengths_diffs(0),
_inc_predicted_elapsed_time_ms(0.0), _inc_predicted_elapsed_time_ms(0.0),
_inc_predicted_elapsed_time_ms_diffs(0.0), _inc_predicted_elapsed_time_ms_diffs(0.0) {
_inc_region_length(0) {} }
G1CollectionSet::~G1CollectionSet() { G1CollectionSet::~G1CollectionSet() {
if (_collection_set_regions != NULL) {
FREE_C_HEAP_ARRAY(uint, _collection_set_regions);
}
delete _cset_chooser; delete _cset_chooser;
} }
void G1CollectionSet::init_region_lengths(uint eden_cset_region_length, void G1CollectionSet::init_region_lengths(uint eden_cset_region_length,
uint survivor_cset_region_length) { uint survivor_cset_region_length) {
assert_at_safepoint(true);
_eden_region_length = eden_cset_region_length; _eden_region_length = eden_cset_region_length;
_survivor_region_length = survivor_cset_region_length; _survivor_region_length = survivor_cset_region_length;
assert(young_region_length() == _inc_region_length, "should match %u == %u", young_region_length(), _inc_region_length); assert((size_t) young_region_length() == _collection_set_cur_length,
"Young region length %u should match collection set length " SIZE_FORMAT, young_region_length(), _collection_set_cur_length);
_old_region_length = 0; _old_region_length = 0;
} }
void G1CollectionSet::initialize(uint max_region_length) {
guarantee(_collection_set_regions == NULL, "Must only initialize once.");
_collection_set_max_length = max_region_length;
_collection_set_regions = NEW_C_HEAP_ARRAY(uint, max_region_length, mtGC);
}
void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) { void G1CollectionSet::set_recorded_rs_lengths(size_t rs_lengths) {
_recorded_rs_lengths = rs_lengths; _recorded_rs_lengths = rs_lengths;
} }
// Add the heap region at the head of the non-incremental collection set // Add the heap region at the head of the non-incremental collection set
void G1CollectionSet::add_old_region(HeapRegion* hr) { void G1CollectionSet::add_old_region(HeapRegion* hr) {
assert_at_safepoint(true);
assert(_inc_build_state == Active, "Precondition"); assert(_inc_build_state == Active, "Precondition");
assert(hr->is_old(), "the region should be old"); assert(hr->is_old(), "the region should be old");
assert(!hr->in_collection_set(), "should not already be in the CSet"); assert(!hr->in_collection_set(), "should not already be in the CSet");
_g1->register_old_region_with_cset(hr); _g1->register_old_region_with_cset(hr);
hr->set_next_in_collection_set(_head);
_head = hr; _collection_set_regions[_collection_set_cur_length++] = hr->hrm_index();
assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set now larger than maximum size.");
_bytes_used_before += hr->used(); _bytes_used_before += hr->used();
size_t rs_length = hr->rem_set()->occupied(); size_t rs_length = hr->rem_set()->occupied();
_recorded_rs_lengths += rs_length; _recorded_rs_lengths += rs_length;
@ -105,12 +121,10 @@ void G1CollectionSet::add_old_region(HeapRegion* hr) {
// Initialize the per-collection-set information // Initialize the per-collection-set information
void G1CollectionSet::start_incremental_building() { void G1CollectionSet::start_incremental_building() {
assert(_collection_set_cur_length == 0, "Collection set must be empty before starting a new collection set.");
assert(_inc_build_state == Inactive, "Precondition"); assert(_inc_build_state == Inactive, "Precondition");
_inc_head = NULL;
_inc_tail = NULL;
_inc_bytes_used_before = 0; _inc_bytes_used_before = 0;
_inc_region_length = 0;
_inc_recorded_rs_lengths = 0; _inc_recorded_rs_lengths = 0;
_inc_recorded_rs_lengths_diffs = 0; _inc_recorded_rs_lengths_diffs = 0;
@ -151,6 +165,38 @@ void G1CollectionSet::finalize_incremental_building() {
_inc_predicted_elapsed_time_ms_diffs = 0.0; _inc_predicted_elapsed_time_ms_diffs = 0.0;
} }
void G1CollectionSet::clear() {
assert_at_safepoint(true);
_collection_set_cur_length = 0;
}
void G1CollectionSet::iterate(HeapRegionClosure* cl) const {
iterate_from(cl, 0, 1);
}
void G1CollectionSet::iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const {
size_t len = _collection_set_cur_length;
OrderAccess::loadload();
if (len == 0) {
return;
}
size_t start_pos = (worker_id * len) / total_workers;
size_t cur_pos = start_pos;
do {
HeapRegion* r = G1CollectedHeap::heap()->region_at(_collection_set_regions[cur_pos]);
bool result = cl->doHeapRegion(r);
if (result) {
cl->incomplete();
return;
}
cur_pos++;
if (cur_pos == len) {
cur_pos = 0;
}
} while (cur_pos != start_pos);
}
void G1CollectionSet::update_young_region_prediction(HeapRegion* hr, void G1CollectionSet::update_young_region_prediction(HeapRegion* hr,
size_t new_rs_length) { size_t new_rs_length) {
// Update the CSet information that is dependent on the new RS length // Update the CSet information that is dependent on the new RS length
@ -183,8 +229,16 @@ void G1CollectionSet::add_young_region_common(HeapRegion* hr) {
assert(hr->is_young(), "invariant"); assert(hr->is_young(), "invariant");
assert(_inc_build_state == Active, "Precondition"); assert(_inc_build_state == Active, "Precondition");
hr->set_young_index_in_cset(_inc_region_length); size_t collection_set_length = _collection_set_cur_length;
_inc_region_length++; assert(collection_set_length <= INT_MAX, "Collection set is too large with %d entries", (int)collection_set_length);
hr->set_young_index_in_cset((int)collection_set_length);
_collection_set_regions[collection_set_length] = hr->hrm_index();
// Concurrent readers must observe the store of the value in the array before an
// update to the length field.
OrderAccess::storestore();
_collection_set_cur_length++;
assert(_collection_set_cur_length <= _collection_set_max_length, "Collection set larger than maximum allowed.");
// This routine is used when: // This routine is used when:
// * adding survivor regions to the incremental cset at the end of an // * adding survivor regions to the incremental cset at the end of an
@ -218,59 +272,81 @@ void G1CollectionSet::add_young_region_common(HeapRegion* hr) {
assert(!hr->in_collection_set(), "invariant"); assert(!hr->in_collection_set(), "invariant");
_g1->register_young_region_with_cset(hr); _g1->register_young_region_with_cset(hr);
assert(hr->next_in_collection_set() == NULL, "invariant");
} }
// Add the region at the RHS of the incremental cset
void G1CollectionSet::add_survivor_regions(HeapRegion* hr) { void G1CollectionSet::add_survivor_regions(HeapRegion* hr) {
// We should only ever be appending survivors at the end of a pause assert(hr->is_survivor(), "Must only add survivor regions, but is %s", hr->get_type_str());
assert(hr->is_survivor(), "Logic");
// Do the 'common' stuff
add_young_region_common(hr); add_young_region_common(hr);
// Now add the region at the right hand side
if (_inc_tail == NULL) {
assert(_inc_head == NULL, "invariant");
_inc_head = hr;
} else {
_inc_tail->set_next_in_collection_set(hr);
}
_inc_tail = hr;
} }
// Add the region to the LHS of the incremental cset
void G1CollectionSet::add_eden_region(HeapRegion* hr) { void G1CollectionSet::add_eden_region(HeapRegion* hr) {
// Survivors should be added to the RHS at the end of a pause assert(hr->is_eden(), "Must only add eden regions, but is %s", hr->get_type_str());
assert(hr->is_eden(), "Logic");
// Do the 'common' stuff
add_young_region_common(hr); add_young_region_common(hr);
// Add the region at the left hand side
hr->set_next_in_collection_set(_inc_head);
if (_inc_head == NULL) {
assert(_inc_tail == NULL, "Invariant");
_inc_tail = hr;
}
_inc_head = hr;
} }
#ifndef PRODUCT #ifndef PRODUCT
void G1CollectionSet::print(HeapRegion* list_head, outputStream* st) { class G1VerifyYoungAgesClosure : public HeapRegionClosure {
assert(list_head == inc_head() || list_head == head(), "must be"); public:
bool _valid;
public:
G1VerifyYoungAgesClosure() : HeapRegionClosure(), _valid(true) { }
st->print_cr("\nCollection_set:"); virtual bool doHeapRegion(HeapRegion* r) {
HeapRegion* csr = list_head; guarantee(r->is_young(), "Region must be young but is %s", r->get_type_str());
while (csr != NULL) {
HeapRegion* next = csr->next_in_collection_set(); SurvRateGroup* group = r->surv_rate_group();
assert(csr->in_collection_set(), "bad CS");
st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d", if (group == NULL) {
HR_FORMAT_PARAMS(csr), log_error(gc, verify)("## encountered NULL surv_rate_group in young region");
p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()), _valid = false;
csr->age_in_surv_rate_group_cond()); }
csr = next;
if (r->age_in_surv_rate_group() < 0) {
log_error(gc, verify)("## encountered negative age in young region");
_valid = false;
}
return false;
} }
bool valid() const { return _valid; }
};
bool G1CollectionSet::verify_young_ages() {
assert_at_safepoint(true);
G1VerifyYoungAgesClosure cl;
iterate(&cl);
if (!cl.valid()) {
LogStreamHandle(Error, gc, verify) log;
print(&log);
}
return cl.valid();
}
class G1PrintCollectionSetClosure : public HeapRegionClosure {
outputStream* _st;
public:
G1PrintCollectionSetClosure(outputStream* st) : HeapRegionClosure(), _st(st) { }
virtual bool doHeapRegion(HeapRegion* r) {
assert(r->in_collection_set(), "Region %u should be in collection set", r->hrm_index());
_st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d",
HR_FORMAT_PARAMS(r),
p2i(r->prev_top_at_mark_start()),
p2i(r->next_top_at_mark_start()),
r->age_in_surv_rate_group_cond());
return false;
}
};
void G1CollectionSet::print(outputStream* st) {
st->print_cr("\nCollection_set:");
G1PrintCollectionSetClosure cl(st);
iterate(&cl);
} }
#endif // !PRODUCT #endif // !PRODUCT
@ -281,7 +357,6 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi
guarantee(target_pause_time_ms > 0.0, guarantee(target_pause_time_ms > 0.0,
"target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms);
guarantee(_head == NULL, "Precondition");
size_t pending_cards = _policy->pending_cards(); size_t pending_cards = _policy->pending_cards();
double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards); double base_time_ms = _policy->predict_base_elapsed_time_ms(pending_cards);
@ -305,7 +380,6 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi
// Clear the fields that point to the survivor list - they are all young now. // Clear the fields that point to the survivor list - they are all young now.
survivors->convert_to_eden(); survivors->convert_to_eden();
_head = _inc_head;
_bytes_used_before = _inc_bytes_used_before; _bytes_used_before = _inc_bytes_used_before;
time_remaining_ms = MAX2(time_remaining_ms - _inc_predicted_elapsed_time_ms, 0.0); time_remaining_ms = MAX2(time_remaining_ms - _inc_predicted_elapsed_time_ms, 0.0);
@ -422,23 +496,41 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) {
} }
#ifdef ASSERT #ifdef ASSERT
class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure {
private:
size_t _young_length;
int* _heap_region_indices;
public:
G1VerifyYoungCSetIndicesClosure(size_t young_length) : HeapRegionClosure(), _young_length(young_length) {
_heap_region_indices = NEW_C_HEAP_ARRAY(int, young_length, mtGC);
for (size_t i = 0; i < young_length; i++) {
_heap_region_indices[i] = -1;
}
}
~G1VerifyYoungCSetIndicesClosure() {
FREE_C_HEAP_ARRAY(int, _heap_region_indices);
}
virtual bool doHeapRegion(HeapRegion* r) {
const int idx = r->young_index_in_cset();
assert(idx > -1, "Young index must be set for all regions in the incremental collection set but is not for region %u.", r->hrm_index());
assert((size_t)idx < _young_length, "Young cset index too large for region %u", r->hrm_index());
assert(_heap_region_indices[idx] == -1,
"Index %d used by multiple regions, first use by region %u, second by region %u",
idx, _heap_region_indices[idx], r->hrm_index());
_heap_region_indices[idx] = r->hrm_index();
return false;
}
};
void G1CollectionSet::verify_young_cset_indices() const { void G1CollectionSet::verify_young_cset_indices() const {
ResourceMark rm; assert_at_safepoint(true);
uint* heap_region_indices = NEW_RESOURCE_ARRAY(uint, young_region_length());
for (uint i = 0; i < young_region_length(); ++i) {
heap_region_indices[i] = (uint)-1;
}
for (HeapRegion* hr = _inc_head; hr != NULL; hr = hr->next_in_collection_set()) { G1VerifyYoungCSetIndicesClosure cl(_collection_set_cur_length);
const int idx = hr->young_index_in_cset(); iterate(&cl);
assert(idx > -1, "must be set for all inc cset regions");
assert((uint)idx < young_region_length(), "young cset index too large");
assert(heap_region_indices[idx] == (uint)-1,
"index %d used by multiple regions, first use by %u, second by %u",
idx, heap_region_indices[idx], hr->hrm_index());
heap_region_indices[idx] = hr->hrm_index();
}
} }
#endif #endif

View File

@ -47,10 +47,15 @@ class G1CollectionSet VALUE_OBJ_CLASS_SPEC {
uint _survivor_region_length; uint _survivor_region_length;
uint _old_region_length; uint _old_region_length;
// The head of the list (via "next_in_collection_set()") representing the // The actual collection set as a set of region indices.
// current collection set. Set from the incrementally built collection // All entries in _collection_set_regions below _collection_set_cur_length are
// set at the start of the pause. // assumed to be valid entries.
HeapRegion* _head; // We assume that at any time there is at most only one writer and (one or more)
// concurrent readers. This means we are good with using storestore and loadload
// barriers on the writer and reader respectively only.
uint* _collection_set_regions;
volatile size_t _collection_set_cur_length;
size_t _collection_set_max_length;
// The number of bytes in the collection set before the pause. Set from // The number of bytes in the collection set before the pause. Set from
// the incrementally built collection set at the start of an evacuation // the incrementally built collection set at the start of an evacuation
@ -71,12 +76,6 @@ class G1CollectionSet VALUE_OBJ_CLASS_SPEC {
CSetBuildType _inc_build_state; CSetBuildType _inc_build_state;
// The head of the incrementally built collection set.
HeapRegion* _inc_head;
// The tail of the incrementally built collection set.
HeapRegion* _inc_tail;
// The number of bytes in the incrementally built collection set. // The number of bytes in the incrementally built collection set.
// Used to set _collection_set_bytes_used_before at the start of // Used to set _collection_set_bytes_used_before at the start of
// an evacuation pause. // an evacuation pause.
@ -105,8 +104,6 @@ class G1CollectionSet VALUE_OBJ_CLASS_SPEC {
// See the comment for _inc_recorded_rs_lengths_diffs. // See the comment for _inc_recorded_rs_lengths_diffs.
double _inc_predicted_elapsed_time_ms_diffs; double _inc_predicted_elapsed_time_ms_diffs;
uint _inc_region_length;
G1CollectorState* collector_state(); G1CollectorState* collector_state();
G1GCPhaseTimes* phase_times(); G1GCPhaseTimes* phase_times();
@ -117,6 +114,9 @@ public:
G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy); G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy);
~G1CollectionSet(); ~G1CollectionSet();
// Initializes the collection set giving the maximum possible length of the collection set.
void initialize(uint max_region_length);
CollectionSetChooser* cset_chooser(); CollectionSetChooser* cset_chooser();
void init_region_lengths(uint eden_cset_region_length, void init_region_lengths(uint eden_cset_region_length,
@ -133,36 +133,31 @@ public:
uint survivor_region_length() const { return _survivor_region_length; } uint survivor_region_length() const { return _survivor_region_length; }
uint old_region_length() const { return _old_region_length; } uint old_region_length() const { return _old_region_length; }
// Incremental CSet Support // Incremental collection set support
// The head of the incrementally built collection set.
HeapRegion* inc_head() { return _inc_head; }
// The tail of the incrementally built collection set.
HeapRegion* inc_tail() { return _inc_tail; }
// Initialize incremental collection set info. // Initialize incremental collection set info.
void start_incremental_building(); void start_incremental_building();
// Perform any final calculations on the incremental CSet fields // Perform any final calculations on the incremental collection set fields
// before we can use them. // before we can use them.
void finalize_incremental_building(); void finalize_incremental_building();
void clear_incremental() { // Reset the contents of the collection set.
_inc_head = NULL; void clear();
_inc_tail = NULL;
_inc_region_length = 0;
}
// Stop adding regions to the incremental collection set // Iterate over the collection set, applying the given HeapRegionClosure on all of them.
// If may_be_aborted is true, iteration may be aborted using the return value of the
// called closure method.
void iterate(HeapRegionClosure* cl) const;
// Iterate over the collection set, applying the given HeapRegionClosure on all of them,
// trying to optimally spread out starting position of total_workers workers given the
// caller's worker_id.
void iterate_from(HeapRegionClosure* cl, uint worker_id, uint total_workers) const;
// Stop adding regions to the incremental collection set.
void stop_incremental_building() { _inc_build_state = Inactive; } void stop_incremental_building() { _inc_build_state = Inactive; }
// The head of the list (via "next_in_collection_set()") representing the
// current collection set.
HeapRegion* head() { return _head; }
void clear_head() { _head = NULL; }
size_t recorded_rs_lengths() { return _recorded_rs_lengths; } size_t recorded_rs_lengths() { return _recorded_rs_lengths; }
size_t bytes_used_before() const { size_t bytes_used_before() const {
@ -174,33 +169,32 @@ public:
} }
// Choose a new collection set. Marks the chosen regions as being // Choose a new collection set. Marks the chosen regions as being
// "in_collection_set", and links them together. The head and number of // "in_collection_set".
// the collection set are available via access methods.
double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors); double finalize_young_part(double target_pause_time_ms, G1SurvivorRegions* survivors);
void finalize_old_part(double time_remaining_ms); void finalize_old_part(double time_remaining_ms);
// Add old region "hr" to the CSet. // Add old region "hr" to the collection set.
void add_old_region(HeapRegion* hr); void add_old_region(HeapRegion* hr);
// Update information about hr in the aggregated information for // Update information about hr in the aggregated information for
// the incrementally built collection set. // the incrementally built collection set.
void update_young_region_prediction(HeapRegion* hr, size_t new_rs_length); void update_young_region_prediction(HeapRegion* hr, size_t new_rs_length);
// Add hr to the LHS of the incremental collection set. // Add eden region to the collection set.
void add_eden_region(HeapRegion* hr); void add_eden_region(HeapRegion* hr);
// Add hr to the RHS of the incremental collection set. // Add survivor region to the collection set.
void add_survivor_regions(HeapRegion* hr); void add_survivor_regions(HeapRegion* hr);
#ifndef PRODUCT #ifndef PRODUCT
void print(HeapRegion* list_head, outputStream* st); bool verify_young_ages();
void print(outputStream* st);
#endif // !PRODUCT #endif // !PRODUCT
private: private:
// Update the incremental cset information when adding a region // Update the incremental collection set information when adding a region.
// (should not be called directly).
void add_young_region_common(HeapRegion* hr); void add_young_region_common(HeapRegion* hr);
}; };
#endif // SHARE_VM_GC_G1_G1COLLECTIONSET_HPP #endif // SHARE_VM_GC_G1_G1COLLECTIONSET_HPP

View File

@ -394,37 +394,6 @@ void G1DefaultPolicy::update_rs_lengths_prediction(size_t prediction) {
} }
} }
#ifndef PRODUCT
bool G1DefaultPolicy::verify_young_ages() {
bool ret = true;
for (HeapRegion* curr = _collection_set->inc_head();
curr != NULL;
curr = curr->next_in_collection_set()) {
guarantee(curr->is_young(), "Region must be young");
SurvRateGroup* group = curr->surv_rate_group();
if (group == NULL) {
log_error(gc, verify)("## encountered NULL surv_rate_group in young region");
ret = false;
}
if (curr->age_in_surv_rate_group() < 0) {
log_error(gc, verify)("## encountered negative age in young region");
ret = false;
}
}
if (!ret) {
LogStreamHandle(Error, gc, verify) log;
_collection_set->print(_collection_set->inc_head(), &log);
}
return ret;
}
#endif // PRODUCT
void G1DefaultPolicy::record_full_collection_start() { void G1DefaultPolicy::record_full_collection_start() {
_full_collection_start_sec = os::elapsedTime(); _full_collection_start_sec = os::elapsedTime();
// Release the future to-space so that it is available for compaction into. // Release the future to-space so that it is available for compaction into.
@ -488,7 +457,7 @@ void G1DefaultPolicy::record_collection_pause_start(double start_time_sec) {
_short_lived_surv_rate_group->stop_adding_regions(); _short_lived_surv_rate_group->stop_adding_regions();
_survivors_age_table.clear(); _survivors_age_table.clear();
assert( verify_young_ages(), "region age verification" ); assert(_g1->collection_set()->verify_young_ages(), "region age verification failed");
} }
void G1DefaultPolicy::record_concurrent_mark_init_end(double mark_init_elapsed_time_ms) { void G1DefaultPolicy::record_concurrent_mark_init_end(double mark_init_elapsed_time_ms) {

View File

@ -89,10 +89,6 @@ class G1DefaultPolicy: public G1Policy {
size_t _rs_lengths_prediction; size_t _rs_lengths_prediction;
#ifndef PRODUCT
bool verify_young_ages(HeapRegion* head, SurvRateGroup *surv_rate_group);
#endif // PRODUCT
size_t _pending_cards; size_t _pending_cards;
// The amount of allocated bytes in old gen during the last mutator and the following // The amount of allocated bytes in old gen during the last mutator and the following
@ -116,10 +112,6 @@ public:
hr->install_surv_rate_group(_survivor_surv_rate_group); hr->install_surv_rate_group(_survivor_surv_rate_group);
} }
#ifndef PRODUCT
bool verify_young_ages();
#endif // PRODUCT
void record_max_rs_lengths(size_t rs_lengths) { void record_max_rs_lengths(size_t rs_lengths) {
_max_rs_lengths = rs_lengths; _max_rs_lengths = rs_lengths;
} }

View File

@ -251,6 +251,5 @@ G1ParRemoveSelfForwardPtrsTask::G1ParRemoveSelfForwardPtrsTask() :
void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) { void G1ParRemoveSelfForwardPtrsTask::work(uint worker_id) {
RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_hrclaimer); RemoveSelfForwardPtrHRClosure rsfp_cl(worker_id, &_hrclaimer);
HeapRegion* hr = _g1h->start_cset_region_for_worker(worker_id); _g1h->collection_set_iterate_from(&rsfp_cl, worker_id);
_g1h->collection_set_iterate_from(hr, &rsfp_cl);
} }

View File

@ -580,15 +580,20 @@ void G1HeapVerifier::verify_dirty_region(HeapRegion* hr) {
} }
} }
void G1HeapVerifier::verify_dirty_young_list(HeapRegion* head) { class G1VerifyDirtyYoungListClosure : public HeapRegionClosure {
G1SATBCardTableModRefBS* ct_bs = _g1h->g1_barrier_set(); private:
for (HeapRegion* hr = head; hr != NULL; hr = hr->next_in_collection_set()) { G1HeapVerifier* _verifier;
verify_dirty_region(hr); public:
G1VerifyDirtyYoungListClosure(G1HeapVerifier* verifier) : HeapRegionClosure(), _verifier(verifier) { }
virtual bool doHeapRegion(HeapRegion* r) {
_verifier->verify_dirty_region(r);
return false;
} }
} };
void G1HeapVerifier::verify_dirty_young_regions() { void G1HeapVerifier::verify_dirty_young_regions() {
verify_dirty_young_list(_g1h->collection_set()->inc_head()); G1VerifyDirtyYoungListClosure cl(this);
_g1h->collection_set()->iterate(&cl);
} }
bool G1HeapVerifier::verify_no_bits_over_tams(const char* bitmap_name, G1CMBitMapRO* bitmap, bool G1HeapVerifier::verify_no_bits_over_tams(const char* bitmap_name, G1CMBitMapRO* bitmap,

View File

@ -108,7 +108,6 @@ public:
void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN; void verify_not_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN; void verify_dirty_region(HeapRegion* hr) PRODUCT_RETURN;
void verify_dirty_young_list(HeapRegion* head) PRODUCT_RETURN;
void verify_dirty_young_regions() PRODUCT_RETURN; void verify_dirty_young_regions() PRODUCT_RETURN;
}; };

View File

@ -382,10 +382,8 @@ size_t G1RemSet::scan_rem_set(G1ParPushHeapRSClosure* oops_in_heap_closure,
uint worker_i) { uint worker_i) {
double rs_time_start = os::elapsedTime(); double rs_time_start = os::elapsedTime();
HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i);
G1ScanRSClosure cl(_scan_state, oops_in_heap_closure, heap_region_codeblobs, worker_i); G1ScanRSClosure cl(_scan_state, oops_in_heap_closure, heap_region_codeblobs, worker_i);
_g1->collection_set_iterate_from(startRegion, &cl); _g1->collection_set_iterate_from(&cl, worker_i);
double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) - double scan_rs_time_sec = (os::elapsedTime() - rs_time_start) -
cl.strong_code_root_scan_time_sec(); cl.strong_code_root_scan_time_sec();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -154,8 +154,8 @@ void G1StringDedupQueue::unlink_or_oops_do(G1StringDedupUnlinkOrOopsDoClosure* c
} }
void G1StringDedupQueue::print_statistics() { void G1StringDedupQueue::print_statistics() {
log_debug(gc, stringdedup)(" [Queue]"); log_debug(gc, stringdedup)(" Queue");
log_debug(gc, stringdedup)(" [Dropped: " UINTX_FORMAT "]", _queue->_dropped); log_debug(gc, stringdedup)(" Dropped: " UINTX_FORMAT, _queue->_dropped);
} }
void G1StringDedupQueue::verify() { void G1StringDedupQueue::verify() {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -42,7 +42,9 @@ G1StringDedupStat::G1StringDedupStat() :
_idle(0), _idle(0),
_exec(0), _exec(0),
_block(0), _block(0),
_start(0.0), _start_concurrent(0.0),
_end_concurrent(0.0),
_start_phase(0.0),
_idle_elapsed(0.0), _idle_elapsed(0.0),
_exec_elapsed(0.0), _exec_elapsed(0.0),
_block_elapsed(0.0) { _block_elapsed(0.0) {
@ -69,7 +71,13 @@ void G1StringDedupStat::add(const G1StringDedupStat& stat) {
_block_elapsed += stat._block_elapsed; _block_elapsed += stat._block_elapsed;
} }
void G1StringDedupStat::print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { void G1StringDedupStat::print_start(const G1StringDedupStat& last_stat) {
log_info(gc, stringdedup)(
"Concurrent String Deduplication (" G1_STRDEDUP_TIME_FORMAT ")",
G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent));
}
void G1StringDedupStat::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
double total_deduped_bytes_percent = 0.0; double total_deduped_bytes_percent = 0.0;
if (total_stat._new_bytes > 0) { if (total_stat._new_bytes > 0) {
@ -79,13 +87,16 @@ void G1StringDedupStat::print_summary(const G1StringDedupStat& last_stat, const
log_info(gc, stringdedup)( log_info(gc, stringdedup)(
"Concurrent String Deduplication " "Concurrent String Deduplication "
G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS "), avg " G1_STRDEDUP_BYTES_FORMAT_NS "->" G1_STRDEDUP_BYTES_FORMAT_NS "(" G1_STRDEDUP_BYTES_FORMAT_NS ") "
G1_STRDEDUP_PERCENT_FORMAT_NS ", " G1_STRDEDUP_TIME_FORMAT, "avg " G1_STRDEDUP_PERCENT_FORMAT_NS " "
"(" G1_STRDEDUP_TIME_FORMAT ", " G1_STRDEDUP_TIME_FORMAT ") " G1_STRDEDUP_TIME_FORMAT_MS,
G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes), G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes),
G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes), G1_STRDEDUP_BYTES_PARAM(last_stat._new_bytes - last_stat._deduped_bytes),
G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes), G1_STRDEDUP_BYTES_PARAM(last_stat._deduped_bytes),
total_deduped_bytes_percent, total_deduped_bytes_percent,
last_stat._exec_elapsed); G1_STRDEDUP_TIME_PARAM(last_stat._start_concurrent),
G1_STRDEDUP_TIME_PARAM(last_stat._end_concurrent),
G1_STRDEDUP_TIME_PARAM_MS(last_stat._exec_elapsed));
} }
void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool total) { void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool total) {
@ -134,23 +145,31 @@ void G1StringDedupStat::print_statistics(const G1StringDedupStat& stat, bool tot
if (total) { if (total) {
log_debug(gc, stringdedup)( log_debug(gc, stringdedup)(
" [Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]", " Total Exec: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
stat._exec, stat._exec_elapsed, stat._idle, stat._idle_elapsed, stat._block, stat._block_elapsed); ", Idle: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS
", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
stat._exec, G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
stat._idle, G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
} else { } else {
log_debug(gc, stringdedup)( log_debug(gc, stringdedup)(
" [Last Exec: " G1_STRDEDUP_TIME_FORMAT ", Idle: " G1_STRDEDUP_TIME_FORMAT ", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT "]", " Last Exec: " G1_STRDEDUP_TIME_FORMAT_MS
stat._exec_elapsed, stat._idle_elapsed, stat._block, stat._block_elapsed); ", Idle: " G1_STRDEDUP_TIME_FORMAT_MS
", Blocked: " UINTX_FORMAT "/" G1_STRDEDUP_TIME_FORMAT_MS,
G1_STRDEDUP_TIME_PARAM_MS(stat._exec_elapsed),
G1_STRDEDUP_TIME_PARAM_MS(stat._idle_elapsed),
stat._block, G1_STRDEDUP_TIME_PARAM_MS(stat._block_elapsed));
} }
log_debug(gc, stringdedup)(" [Inspected: " G1_STRDEDUP_OBJECTS_FORMAT "]", stat._inspected); log_debug(gc, stringdedup)(" Inspected: " G1_STRDEDUP_OBJECTS_FORMAT, stat._inspected);
log_debug(gc, stringdedup)(" [Skipped: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._skipped, skipped_percent); log_debug(gc, stringdedup)(" Skipped: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._skipped, skipped_percent);
log_debug(gc, stringdedup)(" [Hashed: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._hashed, hashed_percent); log_debug(gc, stringdedup)(" Hashed: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._hashed, hashed_percent);
log_debug(gc, stringdedup)(" [Known: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", stat._known, known_percent); log_debug(gc, stringdedup)(" Known: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")", stat._known, known_percent);
log_debug(gc, stringdedup)(" [New: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "]", log_debug(gc, stringdedup)(" New: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT,
stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes)); stat._new, new_percent, G1_STRDEDUP_BYTES_PARAM(stat._new_bytes));
log_debug(gc, stringdedup)(" [Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", log_debug(gc, stringdedup)(" Deduplicated: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent); stat._deduped, deduped_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_bytes), deduped_bytes_percent);
log_debug(gc, stringdedup)(" [Young: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", log_debug(gc, stringdedup)(" Young: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent); stat._deduped_young, deduped_young_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_young_bytes), deduped_young_bytes_percent);
log_debug(gc, stringdedup)(" [Old: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")]", log_debug(gc, stringdedup)(" Old: " G1_STRDEDUP_OBJECTS_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ") " G1_STRDEDUP_BYTES_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT ")",
stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent); stat._deduped_old, deduped_old_percent, G1_STRDEDUP_BYTES_PARAM(stat._deduped_old_bytes), deduped_old_bytes_percent);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,11 +30,14 @@
// Macros for GC log output formating // Macros for GC log output formating
#define G1_STRDEDUP_OBJECTS_FORMAT UINTX_FORMAT_W(12) #define G1_STRDEDUP_OBJECTS_FORMAT UINTX_FORMAT_W(12)
#define G1_STRDEDUP_TIME_FORMAT "%1.7lf secs" #define G1_STRDEDUP_TIME_FORMAT "%.3fs"
#define G1_STRDEDUP_PERCENT_FORMAT "%5.1lf%%" #define G1_STRDEDUP_TIME_PARAM(time) (time)
#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1lf%%" #define G1_STRDEDUP_TIME_FORMAT_MS "%.3fms"
#define G1_STRDEDUP_BYTES_FORMAT "%8.1lf%s" #define G1_STRDEDUP_TIME_PARAM_MS(time) ((time) * MILLIUNITS)
#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1lf%s" #define G1_STRDEDUP_PERCENT_FORMAT "%5.1f%%"
#define G1_STRDEDUP_PERCENT_FORMAT_NS "%.1f%%"
#define G1_STRDEDUP_BYTES_FORMAT "%8.1f%s"
#define G1_STRDEDUP_BYTES_FORMAT_NS "%.1f%s"
#define G1_STRDEDUP_BYTES_PARAM(bytes) byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes)) #define G1_STRDEDUP_BYTES_PARAM(bytes) byte_size_in_proper_unit((double)(bytes)), proper_unit_for_byte_size((bytes))
// //
@ -60,7 +63,9 @@ private:
uintx _block; uintx _block;
// Time spent by the deduplication thread in different phases // Time spent by the deduplication thread in different phases
double _start; double _start_concurrent;
double _end_concurrent;
double _start_phase;
double _idle_elapsed; double _idle_elapsed;
double _exec_elapsed; double _exec_elapsed;
double _block_elapsed; double _block_elapsed;
@ -104,38 +109,41 @@ public:
} }
void mark_idle() { void mark_idle() {
_start = os::elapsedTime(); _start_phase = os::elapsedTime();
_idle++; _idle++;
} }
void mark_exec() { void mark_exec() {
double now = os::elapsedTime(); double now = os::elapsedTime();
_idle_elapsed = now - _start; _idle_elapsed = now - _start_phase;
_start = now; _start_phase = now;
_start_concurrent = now;
_exec++; _exec++;
} }
void mark_block() { void mark_block() {
double now = os::elapsedTime(); double now = os::elapsedTime();
_exec_elapsed += now - _start; _exec_elapsed += now - _start_phase;
_start = now; _start_phase = now;
_block++; _block++;
} }
void mark_unblock() { void mark_unblock() {
double now = os::elapsedTime(); double now = os::elapsedTime();
_block_elapsed += now - _start; _block_elapsed += now - _start_phase;
_start = now; _start_phase = now;
} }
void mark_done() { void mark_done() {
double now = os::elapsedTime(); double now = os::elapsedTime();
_exec_elapsed += now - _start; _exec_elapsed += now - _start_phase;
_end_concurrent = now;
} }
void add(const G1StringDedupStat& stat); void add(const G1StringDedupStat& stat);
static void print_summary(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); static void print_start(const G1StringDedupStat& last_stat);
static void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
static void print_statistics(const G1StringDedupStat& stat, bool total); static void print_statistics(const G1StringDedupStat& stat, bool total);
}; };

View File

@ -196,7 +196,8 @@ void G1StringDedupEntryCache::delete_overflowed() {
} }
double end = os::elapsedTime(); double end = os::elapsedTime();
log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT, count, end - start); log_trace(gc, stringdedup)("Deleted " UINTX_FORMAT " entries, " G1_STRDEDUP_TIME_FORMAT_MS,
count, G1_STRDEDUP_TIME_PARAM_MS(end - start));
} }
G1StringDedupTable* G1StringDedupTable::_table = NULL; G1StringDedupTable* G1StringDedupTable::_table = NULL;
@ -610,14 +611,14 @@ void G1StringDedupTable::clean_entry_cache() {
void G1StringDedupTable::print_statistics() { void G1StringDedupTable::print_statistics() {
Log(gc, stringdedup) log; Log(gc, stringdedup) log;
log.debug(" [Table]"); log.debug(" Table");
log.debug(" [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]", log.debug(" Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS,
G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry))); G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)));
log.debug(" [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]", _table->_size, _min_size, _max_size); log.debug(" Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT, _table->_size, _min_size, _max_size);
log.debug(" [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]", log.debug(" Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT,
_table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed); _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed);
log.debug(" [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]", log.debug(" Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")",
_resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0); _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0);
log.debug(" [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x]", _rehash_count, _rehash_threshold, _table->_hash_seed); log.debug(" Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x", _rehash_count, _rehash_threshold, _table->_hash_seed);
log.debug(" [Age Threshold: " UINTX_FORMAT "]", StringDeduplicationAgeThreshold); log.debug(" Age Threshold: " UINTX_FORMAT, StringDeduplicationAgeThreshold);
} }

View File

@ -103,6 +103,7 @@ void G1StringDedupThread::run_service() {
SuspendibleThreadSetJoiner sts_join; SuspendibleThreadSetJoiner sts_join;
stat.mark_exec(); stat.mark_exec();
print_start(stat);
// Process the queue // Process the queue
for (;;) { for (;;) {
@ -123,9 +124,8 @@ void G1StringDedupThread::run_service() {
stat.mark_done(); stat.mark_done();
// Print statistics
total_stat.add(stat); total_stat.add(stat);
print(stat, total_stat); print_end(stat, total_stat);
} }
G1StringDedupTable::clean_entry_cache(); G1StringDedupTable::clean_entry_cache();
@ -136,14 +136,16 @@ void G1StringDedupThread::stop_service() {
G1StringDedupQueue::cancel_wait(); G1StringDedupQueue::cancel_wait();
} }
void G1StringDedupThread::print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) { void G1StringDedupThread::print_start(const G1StringDedupStat& last_stat) {
if (log_is_enabled(Info, gc, stringdedup)) { G1StringDedupStat::print_start(last_stat);
G1StringDedupStat::print_summary(last_stat, total_stat); }
if (log_is_enabled(Debug, gc, stringdedup)) {
G1StringDedupStat::print_statistics(last_stat, false); void G1StringDedupThread::print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat) {
G1StringDedupStat::print_statistics(total_stat, true); G1StringDedupStat::print_end(last_stat, total_stat);
G1StringDedupTable::print_statistics(); if (log_is_enabled(Debug, gc, stringdedup)) {
G1StringDedupQueue::print_statistics(); G1StringDedupStat::print_statistics(last_stat, false);
} G1StringDedupStat::print_statistics(total_stat, true);
G1StringDedupTable::print_statistics();
G1StringDedupQueue::print_statistics();
} }
} }

View File

@ -43,7 +43,8 @@ private:
G1StringDedupThread(); G1StringDedupThread();
~G1StringDedupThread(); ~G1StringDedupThread();
void print(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat); void print_start(const G1StringDedupStat& last_stat);
void print_end(const G1StringDedupStat& last_stat, const G1StringDedupStat& total_stat);
void run_service(); void run_service();
void stop_service(); void stop_service();

View File

@ -71,38 +71,51 @@ void G1YoungRemSetSamplingThread::stop_service() {
_monitor.notify(); _monitor.notify();
} }
class G1YoungRemSetSamplingClosure : public HeapRegionClosure {
SuspendibleThreadSetJoiner* _sts;
size_t _regions_visited;
size_t _sampled_rs_lengths;
public:
G1YoungRemSetSamplingClosure(SuspendibleThreadSetJoiner* sts) :
HeapRegionClosure(), _sts(sts), _regions_visited(0), _sampled_rs_lengths(0) { }
virtual bool doHeapRegion(HeapRegion* r) {
size_t rs_length = r->rem_set()->occupied();
_sampled_rs_lengths += rs_length;
// Update the collection set policy information for this region
G1CollectedHeap::heap()->collection_set()->update_young_region_prediction(r, rs_length);
_regions_visited++;
if (_regions_visited == 10) {
if (_sts->should_yield()) {
_sts->yield();
// A gc may have occurred and our sampling data is stale and further
// traversal of the collection set is unsafe
return true;
}
_regions_visited = 0;
}
return false;
}
size_t sampled_rs_lengths() const { return _sampled_rs_lengths; }
};
void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() { void G1YoungRemSetSamplingThread::sample_young_list_rs_lengths() {
SuspendibleThreadSetJoiner sts; SuspendibleThreadSetJoiner sts;
G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectedHeap* g1h = G1CollectedHeap::heap();
G1Policy* g1p = g1h->g1_policy(); G1Policy* g1p = g1h->g1_policy();
G1CollectionSet* g1cs = g1h->collection_set();
if (g1p->adaptive_young_list_length()) { if (g1p->adaptive_young_list_length()) {
int regions_visited = 0; G1YoungRemSetSamplingClosure cl(&sts);
HeapRegion* hr = g1cs->inc_head();
size_t sampled_rs_lengths = 0;
while (hr != NULL) { G1CollectionSet* g1cs = g1h->collection_set();
size_t rs_length = hr->rem_set()->occupied(); g1cs->iterate(&cl);
sampled_rs_lengths += rs_length;
// Update the collection set policy information for this region if (cl.complete()) {
g1cs->update_young_region_prediction(hr, rs_length); g1p->revise_young_list_target_length_if_necessary(cl.sampled_rs_lengths());
++regions_visited;
// we try to yield every time we visit 10 regions
if (regions_visited == 10) {
if (sts.should_yield()) {
sts.yield();
// A gc may have occurred and our sampling data is stale and further
// traversal of the collection set is unsafe
return;
}
regions_visited = 0;
}
assert(hr == g1cs->inc_tail() || hr->next_in_collection_set() != NULL, "next should only be null at tail of icset");
hr = hr->next_in_collection_set();
} }
g1p->revise_young_list_target_length_if_necessary(sampled_rs_lengths);
} }
} }

View File

@ -284,7 +284,6 @@ HeapRegion::HeapRegion(uint hrm_index,
_hrm_index(hrm_index), _hrm_index(hrm_index),
_allocation_context(AllocationContext::system()), _allocation_context(AllocationContext::system()),
_humongous_start_region(NULL), _humongous_start_region(NULL),
_next_in_special_set(NULL),
_evacuation_failed(false), _evacuation_failed(false),
_prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0), _prev_marked_bytes(0), _next_marked_bytes(0), _gc_efficiency(0.0),
_next(NULL), _prev(NULL), _next(NULL), _prev(NULL),

View File

@ -261,12 +261,6 @@ class HeapRegion: public G1ContiguousSpace {
// True iff an attempt to evacuate an object in the region failed. // True iff an attempt to evacuate an object in the region failed.
bool _evacuation_failed; bool _evacuation_failed;
// A heap region may be a member one of a number of special subsets, each
// represented as linked lists through the field below. Currently, there
// is only one set:
// The collection set.
HeapRegion* _next_in_special_set;
// Fields used by the HeapRegionSetBase class and subclasses. // Fields used by the HeapRegionSetBase class and subclasses.
HeapRegion* _next; HeapRegion* _next;
HeapRegion* _prev; HeapRegion* _prev;
@ -476,9 +470,6 @@ class HeapRegion: public G1ContiguousSpace {
inline bool in_collection_set() const; inline bool in_collection_set() const;
inline HeapRegion* next_in_collection_set() const;
inline void set_next_in_collection_set(HeapRegion* r);
void set_allocation_context(AllocationContext_t context) { void set_allocation_context(AllocationContext_t context) {
_allocation_context = context; _allocation_context = context;
} }
@ -744,7 +735,7 @@ class HeapRegion: public G1ContiguousSpace {
// Terminates the iteration when the "doHeapRegion" method returns "true". // Terminates the iteration when the "doHeapRegion" method returns "true".
class HeapRegionClosure : public StackObj { class HeapRegionClosure : public StackObj {
friend class HeapRegionManager; friend class HeapRegionManager;
friend class G1CollectedHeap; friend class G1CollectionSet;
bool _complete; bool _complete;
void incomplete() { _complete = false; } void incomplete() { _complete = false; }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -230,18 +230,4 @@ inline bool HeapRegion::in_collection_set() const {
return G1CollectedHeap::heap()->is_in_cset(this); return G1CollectedHeap::heap()->is_in_cset(this);
} }
inline HeapRegion* HeapRegion::next_in_collection_set() const {
assert(in_collection_set(), "should only invoke on member of CS.");
assert(_next_in_special_set == NULL ||
_next_in_special_set->in_collection_set(),
"Malformed CS.");
return _next_in_special_set;
}
void HeapRegion::set_next_in_collection_set(HeapRegion* r) {
assert(in_collection_set(), "should only invoke on member of CS.");
assert(r == NULL || r->in_collection_set(), "Malformed CS.");
_next_in_special_set = r;
}
#endif // SHARE_VM_GC_G1_HEAPREGION_INLINE_HPP #endif // SHARE_VM_GC_G1_HEAPREGION_INLINE_HPP

View File

@ -386,13 +386,21 @@ GCTaskThread* GCTaskManager::install_worker(uint t) {
void GCTaskManager::add_workers(bool initializing) { void GCTaskManager::add_workers(bool initializing) {
os::ThreadType worker_type = os::pgc_thread; os::ThreadType worker_type = os::pgc_thread;
uint previous_created_workers = _created_workers;
_created_workers = WorkerManager::add_workers(this, _created_workers = WorkerManager::add_workers(this,
_active_workers, _active_workers,
(uint) _workers, _workers,
_created_workers, _created_workers,
worker_type, worker_type,
initializing); initializing);
_active_workers = MIN2(_created_workers, _active_workers); _active_workers = MIN2(_created_workers, _active_workers);
WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing);
}
const char* GCTaskManager::group_name() {
return "ParGC Thread";
} }
void GCTaskManager::initialize() { void GCTaskManager::initialize() {

View File

@ -556,6 +556,8 @@ protected:
GCTaskThread* install_worker(uint worker_id); GCTaskThread* install_worker(uint worker_id);
// Add GC workers as needed. // Add GC workers as needed.
void add_workers(bool initializing); void add_workers(bool initializing);
// Base name (without worker id #) of threads.
const char* group_name();
}; };
// //

View File

@ -45,7 +45,7 @@ GCTaskThread::GCTaskThread(GCTaskManager* manager,
_time_stamp_index(0) _time_stamp_index(0)
{ {
set_id(which); set_id(which);
set_name("ParGC Thread#%d", which); set_name("%s#%d", manager->group_name(), which);
} }
GCTaskThread::~GCTaskThread() { GCTaskThread::~GCTaskThread() {

View File

@ -55,6 +55,7 @@ private:
return new GCTaskThread(manager, which, processor_id); return new GCTaskThread(manager, which, processor_id);
} }
public: public:
static void destroy(GCTaskThread* manager) { static void destroy(GCTaskThread* manager) {
if (manager != NULL) { if (manager != NULL) {
delete manager; delete manager;

View File

@ -159,6 +159,8 @@ class CollectedHeap : public CHeapObj<mtInternal> {
inline static void post_allocation_setup_array(KlassHandle klass, inline static void post_allocation_setup_array(KlassHandle klass,
HeapWord* obj, int length); HeapWord* obj, int length);
inline static void post_allocation_setup_class(KlassHandle klass, HeapWord* obj, int size);
// Clears an allocated object. // Clears an allocated object.
inline static void init_obj(HeapWord* obj, size_t size); inline static void init_obj(HeapWord* obj, size_t size);
@ -300,6 +302,7 @@ class CollectedHeap : public CHeapObj<mtInternal> {
inline static oop obj_allocate(KlassHandle klass, int size, TRAPS); inline static oop obj_allocate(KlassHandle klass, int size, TRAPS);
inline static oop array_allocate(KlassHandle klass, int size, int length, TRAPS); inline static oop array_allocate(KlassHandle klass, int size, int length, TRAPS);
inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS); inline static oop array_allocate_nozero(KlassHandle klass, int size, int length, TRAPS);
inline static oop class_allocate(KlassHandle klass, int size, TRAPS);
inline static void post_allocation_install_obj_klass(KlassHandle klass, inline static void post_allocation_install_obj_klass(KlassHandle klass,
oop obj); oop obj);

View File

@ -25,6 +25,7 @@
#ifndef SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP #ifndef SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP
#define SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP #define SHARE_VM_GC_SHARED_COLLECTEDHEAP_INLINE_HPP
#include "classfile/javaClasses.hpp"
#include "gc/shared/allocTracer.hpp" #include "gc/shared/allocTracer.hpp"
#include "gc/shared/collectedHeap.hpp" #include "gc/shared/collectedHeap.hpp"
#include "gc/shared/threadLocalAllocBuffer.inline.hpp" #include "gc/shared/threadLocalAllocBuffer.inline.hpp"
@ -96,6 +97,22 @@ void CollectedHeap::post_allocation_setup_obj(KlassHandle klass,
post_allocation_notify(klass, (oop)obj, size); post_allocation_notify(klass, (oop)obj, size);
} }
void CollectedHeap::post_allocation_setup_class(KlassHandle klass,
HeapWord* obj,
int size) {
// Set oop_size field before setting the _klass field
// in post_allocation_setup_common() because the klass field
// indicates that the object is parsable by concurrent GC.
oop new_cls = (oop)obj;
assert(size > 0, "oop_size must be positive.");
java_lang_Class::set_oop_size(new_cls, size);
post_allocation_setup_common(klass, obj);
assert(Universe::is_bootstrapping() ||
!new_cls->is_array(), "must not be an array");
// notify jvmti and dtrace
post_allocation_notify(klass, new_cls, size);
}
void CollectedHeap::post_allocation_setup_array(KlassHandle klass, void CollectedHeap::post_allocation_setup_array(KlassHandle klass,
HeapWord* obj, HeapWord* obj,
int length) { int length) {
@ -207,6 +224,16 @@ oop CollectedHeap::obj_allocate(KlassHandle klass, int size, TRAPS) {
return (oop)obj; return (oop)obj;
} }
oop CollectedHeap::class_allocate(KlassHandle klass, int size, TRAPS) {
debug_only(check_for_valid_allocation_state());
assert(!Universe::heap()->is_gc_active(), "Allocation during gc not allowed");
assert(size >= 0, "int won't convert to size_t");
HeapWord* obj = common_mem_allocate_init(klass, size, CHECK_NULL);
post_allocation_setup_class(klass, obj, size); // set oop_size
NOT_PRODUCT(Universe::heap()->check_for_bad_heap_word_value(obj, size));
return (oop)obj;
}
oop CollectedHeap::array_allocate(KlassHandle klass, oop CollectedHeap::array_allocate(KlassHandle klass,
int size, int size,
int length, int length,

View File

@ -47,18 +47,18 @@ class WorkerManager : public AllStatic {
// threads and a failure would not be optimal but should not be fatal. // threads and a failure would not be optimal but should not be fatal.
template <class WorkerType> template <class WorkerType>
static uint add_workers (WorkerType* holder, static uint add_workers (WorkerType* holder,
uint active_workers, uint active_workers,
uint total_workers, uint total_workers,
uint created_workers, uint created_workers,
os::ThreadType worker_type, os::ThreadType worker_type,
bool initializing) { bool initializing) {
uint start = created_workers; uint start = created_workers;
uint end = MIN2(active_workers, total_workers); uint end = MIN2(active_workers, total_workers);
for (uint worker_id = start; worker_id < end; worker_id += 1) { for (uint worker_id = start; worker_id < end; worker_id += 1) {
WorkerThread* new_worker = holder->install_worker(worker_id); WorkerThread* new_worker = holder->install_worker(worker_id);
assert(new_worker != NULL, "Failed to allocate GangWorker"); assert(new_worker != NULL, "Failed to allocate GangWorker");
if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) { if (new_worker == NULL || !os::create_thread(new_worker, worker_type)) {
if(initializing) { if (initializing) {
vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, vm_exit_out_of_memory(0, OOM_MALLOC_ERROR,
"Cannot create worker GC thread. Out of system resources."); "Cannot create worker GC thread. Out of system resources.");
} }
@ -67,11 +67,21 @@ class WorkerManager : public AllStatic {
os::start_thread(new_worker); os::start_thread(new_worker);
} }
log_trace(gc, task)("AdaptiveSizePolicy::add_workers() : "
"active_workers: %u created_workers: %u",
active_workers, created_workers);
return created_workers; return created_workers;
} }
// Log (at trace level) a change in the number of created workers.
template <class WorkerType>
static void log_worker_creation(WorkerType* holder,
uint previous_created_workers,
uint active_workers,
uint created_workers,
bool initializing) {
if (previous_created_workers < created_workers) {
const char* initializing_msg = initializing ? "Adding initial" : "Creating additional";
log_trace(gc, task)("%s %s(s) previously created workers %u active workers %u total created workers %u",
initializing_msg, holder->group_name(), previous_created_workers, active_workers, created_workers);
}
}
}; };
#endif // SHARE_VM_GC_SHARED_WORKERMANAGER_HPP #endif // SHARE_VM_GC_SHARED_WORKERMANAGER_HPP

View File

@ -66,6 +66,7 @@ void AbstractWorkGang::add_workers(uint active_workers, bool initializing) {
} else { } else {
worker_type = os::pgc_thread; worker_type = os::pgc_thread;
} }
uint previous_created_workers = _created_workers;
_created_workers = WorkerManager::add_workers(this, _created_workers = WorkerManager::add_workers(this,
active_workers, active_workers,
@ -74,6 +75,8 @@ void AbstractWorkGang::add_workers(uint active_workers, bool initializing) {
worker_type, worker_type,
initializing); initializing);
_active_workers = MIN2(_created_workers, _active_workers); _active_workers = MIN2(_created_workers, _active_workers);
WorkerManager::log_worker_creation(this, previous_created_workers, _active_workers, _created_workers, initializing);
} }
AbstractGangWorker* AbstractWorkGang::worker(uint i) const { AbstractGangWorker* AbstractWorkGang::worker(uint i) const {

View File

@ -176,6 +176,9 @@ class AbstractWorkGang : public CHeapObj<mtInternal> {
// Return the Ith worker. // Return the Ith worker.
AbstractGangWorker* worker(uint i) const; AbstractGangWorker* worker(uint i) const;
// Base name (without worker id #) of threads.
const char* group_name() { return name(); }
void threads_do(ThreadClosure* tc) const; void threads_do(ThreadClosure* tc) const;
// Create a GC worker and install it into the work gang. // Create a GC worker and install it into the work gang.

View File

@ -576,27 +576,27 @@ void InterpreterRuntime::resolve_get_put(JavaThread* thread, Bytecodes::Code byt
// compute auxiliary field attributes // compute auxiliary field attributes
TosState state = as_TosState(info.field_type()); TosState state = as_TosState(info.field_type());
// We need to delay resolving put instructions on final fields // Put instructions on final fields are not resolved. This is required so we throw
// until we actually invoke one. This is required so we throw // exceptions at the correct place (when the instruction is actually invoked).
// exceptions at the correct place. If we do not resolve completely // If we do not resolve an instruction in the current pass, leaving the put_code
// in the current pass, leaving the put_code set to zero will // set to zero will cause the next put instruction to the same field to reresolve.
// cause the next put instruction to reresolve. //
Bytecodes::Code put_code = (Bytecodes::Code)0; // Also, we need to delay resolving getstatic and putstatic instructions until the
// class is initialized. This is required so that access to the static
// We also need to delay resolving getstatic instructions until the
// class is intitialized. This is required so that access to the static
// field will call the initialization function every time until the class // field will call the initialization function every time until the class
// is completely initialized ala. in 2.17.5 in JVM Specification. // is completely initialized ala. in 2.17.5 in JVM Specification.
InstanceKlass* klass = InstanceKlass::cast(info.field_holder()); InstanceKlass* klass = InstanceKlass::cast(info.field_holder());
bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) && bool uninitialized_static = ((bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic) &&
!klass->is_initialized()); !klass->is_initialized());
Bytecodes::Code get_code = (Bytecodes::Code)0;
Bytecodes::Code put_code = (Bytecodes::Code)0;
if (is_put && !info.access_flags().is_final() && !uninitialized_static) {
put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
}
Bytecodes::Code get_code = (Bytecodes::Code)0;
if (!uninitialized_static) { if (!uninitialized_static) {
get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield); get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
if (is_put || !info.access_flags().is_final()) {
put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
}
} }
cp_cache_entry->set_field( cp_cache_entry->set_field(

View File

@ -970,7 +970,7 @@ void LinkResolver::resolve_field(fieldDescriptor& fd,
if (is_initialized_static_final_update || is_initialized_instance_final_update) { if (is_initialized_static_final_update || is_initialized_instance_final_update) {
ss.print("Update to %s final field %s.%s attempted from a different method (%s) than the initializer method %s ", ss.print("Update to %s final field %s.%s attempted from a different method (%s) than the initializer method %s ",
is_static ? "static" : "non-static", resolved_klass()->external_name(), fd.name()->as_C_string(), is_static ? "static" : "non-static", resolved_klass()->external_name(), fd.name()->as_C_string(),
current_klass()->external_name(), m()->name()->as_C_string(),
is_static ? "<clinit>" : "<init>"); is_static ? "<clinit>" : "<init>");
THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string()); THROW_MSG(vmSymbols::java_lang_IllegalAccessError(), ss.as_string());
} }

View File

@ -415,17 +415,8 @@ void LogConfiguration::describe_available(outputStream* out){
void LogConfiguration::describe_current_configuration(outputStream* out){ void LogConfiguration::describe_current_configuration(outputStream* out){
out->print_cr("Log output configuration:"); out->print_cr("Log output configuration:");
for (size_t i = 0; i < _n_outputs; i++) { for (size_t i = 0; i < _n_outputs; i++) {
out->print("#" SIZE_FORMAT ": %s ", i, _outputs[i]->name()); out->print("#" SIZE_FORMAT ": ", i);
out->print_raw(_outputs[i]->config_string()); _outputs[i]->describe(out);
out->print(" ");
char delimiter[2] = {0};
for (size_t d = 0; d < LogDecorators::Count; d++) {
LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
if (_outputs[i]->decorators().is_decorator(decorator)) {
out->print("%s%s", delimiter, LogDecorators::name(decorator));
*delimiter = ',';
}
}
out->cr(); out->cr();
} }
} }

View File

@ -428,3 +428,13 @@ char* LogFileOutput::make_file_name(const char* file_name,
result[result_len] = '\0'; result[result_len] = '\0';
return result; return result;
} }
void LogFileOutput::describe(outputStream *out) {
LogOutput::describe(out);
out->print(" ");
out->print("filecount=%u,filesize=" SIZE_FORMAT "%s", _file_count,
byte_size_in_proper_unit(_rotate_size),
proper_unit_for_byte_size(_rotate_size));
}

View File

@ -85,6 +85,7 @@ class LogFileOutput : public LogFileStreamOutput {
virtual int write(const LogDecorations& decorations, const char* msg); virtual int write(const LogDecorations& decorations, const char* msg);
virtual int write(LogMessageBuffer::Iterator msg_iterator); virtual int write(LogMessageBuffer::Iterator msg_iterator);
virtual void force_rotate(); virtual void force_rotate();
virtual void describe(outputStream *out);
virtual const char* name() const { virtual const char* name() const {
return _name; return _name;

View File

@ -83,3 +83,18 @@ void LogOutput::add_to_config_string(const LogTagSet* ts, LogLevelType level) {
break; break;
} }
} }
void LogOutput::describe(outputStream *out) {
out->print("%s ", name());
out->print_raw(config_string());
out->print(" ");
char delimiter[2] = {0};
for (size_t d = 0; d < LogDecorators::Count; d++) {
LogDecorators::Decorator decorator = static_cast<LogDecorators::Decorator>(d);
if (decorators().is_decorator(decorator)) {
out->print("%s%s", delimiter, LogDecorators::name(decorator));
*delimiter = ',';
}
}
}

View File

@ -83,6 +83,8 @@ class LogOutput : public CHeapObj<mtLogging> {
// Do nothing by default. // Do nothing by default.
} }
virtual void describe(outputStream *out);
virtual const char* name() const = 0; virtual const char* name() const = 0;
virtual bool initialize(const char* options, outputStream* errstream) = 0; virtual bool initialize(const char* options, outputStream* errstream) = 0;
virtual int write(const LogDecorations& decorations, const char* msg) = 0; virtual int write(const LogDecorations& decorations, const char* msg) = 0;

View File

@ -74,6 +74,7 @@ DEBUG_ONLY(size_t Test_log_prefix_prefixer(char* buf, size_t len);)
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref, start)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref, start)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, start)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, start)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, stringtable)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, sweep)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, sweep)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task)) \
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, start)) \ LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task, start)) \

View File

@ -3106,10 +3106,6 @@ void Metaspace::ergo_initialize() {
assert(MetaspaceSize <= MaxMetaspaceSize, "MetaspaceSize should be limited by MaxMetaspaceSize"); assert(MetaspaceSize <= MaxMetaspaceSize, "MetaspaceSize should be limited by MaxMetaspaceSize");
if (MetaspaceSize < 256*K) {
vm_exit_during_initialization("Too small initial Metaspace size");
}
MinMetaspaceExpansion = align_size_down_bounded(MinMetaspaceExpansion, _commit_alignment); MinMetaspaceExpansion = align_size_down_bounded(MinMetaspaceExpansion, _commit_alignment);
MaxMetaspaceExpansion = align_size_down_bounded(MaxMetaspaceExpansion, _commit_alignment); MaxMetaspaceExpansion = align_size_down_bounded(MaxMetaspaceExpansion, _commit_alignment);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -50,13 +50,12 @@ instanceOop InstanceMirrorKlass::allocate_instance(KlassHandle k, TRAPS) {
// Query before forming handle. // Query before forming handle.
int size = instance_size(k); int size = instance_size(k);
KlassHandle h_k(THREAD, this); KlassHandle h_k(THREAD, this);
instanceOop i = (instanceOop)CollectedHeap::obj_allocate(h_k, size, CHECK_NULL);
assert(size > 0, "total object size must be positive: %d", size);
// Since mirrors can be variable sized because of the static fields, store // Since mirrors can be variable sized because of the static fields, store
// the size in the mirror itself. // the size in the mirror itself.
java_lang_Class::set_oop_size(i, size); return (instanceOop)CollectedHeap::class_allocate(h_k, size, CHECK_NULL);
return i;
} }
int InstanceMirrorKlass::oop_size(oop obj) const { int InstanceMirrorKlass::oop_size(oop obj) const {

View File

@ -258,8 +258,8 @@ int oopDesc::size_given_klass(Klass* klass) {
} }
} }
assert(s % MinObjAlignment == 0, "alignment check"); assert(s % MinObjAlignment == 0, "Oop size is not properly aligned: %d", s);
assert(s > 0, "Bad size calculated"); assert(s > 0, "Oop size must be greater than zero, not %d", s);
return s; return s;
} }

View File

@ -6509,6 +6509,59 @@ class C2 extends C1 implements I2 {
<errors> <errors>
</errors> </errors>
</function> </function>
<function id="GetNamedModule" num="40" since="9">
<synopsis>Get Named Module</synopsis>
<description>
Return the <code>java.lang.reflect.Module</code> object for a named
module defined to a class loader that contains a given package.
The module is returned via <code>module_ptr</code>.
<p/>
If a named module is defined to the class loader and it
contains the package then that named module is returned,
otherwise <code>NULL</code> is returned.
<p/>
</description>
<origin>new</origin>
<capabilities>
</capabilities>
<parameters>
<param id="class_loader">
<ptrtype>
<jobject/>
<nullok>the bootstrap loader is assumed</nullok>
</ptrtype>
<description>
A class loader.
If the <code>class_loader</code> is not <code>NULL</code>
or a subclass of <code>java.lang.ClassLoader</code>
this function returns
<errorlink id="JVMTI_ERROR_ILLEGAL_ARGUMENT"></errorlink>.
</description>
</param>
<param id="package_name">
<inbuf><char/></inbuf>
<description>
The name of the package, encoded as a
<internallink id="mUTF">modified UTF-8</internallink> string.
The package name is in internal form (JVMS 4.2.1);
identifiers are separated by forward slashes rather than periods.
</description>
</param>
<param id="module_ptr">
<outptr><jobject/></outptr>
<description>
On return, points to a <code>java.lang.reflect.Module</code> object
or points to <code>NULL</code>.
</description>
</param>
</parameters>
<errors>
<error id="JVMTI_ERROR_ILLEGAL_ARGUMENT">
If class loader is not <code>NULL</code> and is not a class loader object.
</error>
</errors>
</function>
</category> </category>
<category id="class" label="Class"> <category id="class" label="Class">
@ -12462,6 +12515,14 @@ myInit() {
<code>new_class_data</code> has been set, it becomes the <code>new_class_data</code> has been set, it becomes the
<code>class_data</code> for the next agent. <code>class_data</code> for the next agent.
<p/> <p/>
When handling a class load in the live phase, then the
<functionlink id="GetNamedModule"></functionlink>
function can be used to map class loader and a package name to a module.
When a class is being redefined or retransformed then
<code>class_being_redefined</code> is non <code>NULL</code> and so
the JNI <code>GetModule</code> function can also be used
to obtain the Module.
<p/>
The order that this event is sent to each environment differs The order that this event is sent to each environment differs
from other events. from other events.
This event is sent to environments in the following order: This event is sent to environments in the following order:
@ -14427,20 +14488,15 @@ typedef void (JNICALL *jvmtiEventVMInit)
<change date="19 June 2013" version="1.2.3"> <change date="19 June 2013" version="1.2.3">
Added support for statically linked agents. Added support for statically linked agents.
</change> </change>
<change date="20 January 2016" version="9.0.0"> <change date="5 July 2016" version="9.0.0">
Support for modules: Support for modules:
- The majorversion is 9 now - The majorversion is 9 now
- The ClassFileLoadHook events are not sent during the primordial phase anymore. - The ClassFileLoadHook events are not sent during the primordial phase anymore.
- Add new function GetAllModules - Add new function GetAllModules
</change>
<change date="17 February 2016" version="9.0.0">
Support for modules:
- Add new capability can_generate_early_vmstart - Add new capability can_generate_early_vmstart
- Allow CompiledMethodLoad events at start phase - Allow CompiledMethodLoad events at start phase
</change>
<change date="14 April 2016" version="9.0.0">
Support for modules:
- Add new capability can_generate_early_class_hook_events - Add new capability can_generate_early_class_hook_events
- Add new function GetNamedModule
</change> </change>
</changehistory> </changehistory>

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include "classfile/classLoaderExt.hpp" #include "classfile/classLoaderExt.hpp"
#include "classfile/modules.hpp"
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
#include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeStream.hpp"
@ -201,6 +202,28 @@ JvmtiEnv::GetAllModules(jint* module_count_ptr, jobject** modules_ptr) {
} /* end GetAllModules */ } /* end GetAllModules */
// class_loader - NULL is a valid value, must be pre-checked
// package_name - pre-checked for NULL
// module_ptr - pre-checked for NULL
jvmtiError
JvmtiEnv::GetNamedModule(jobject class_loader, const char* package_name, jobject* module_ptr) {
JavaThread* THREAD = JavaThread::current(); // pass to macros
ResourceMark rm(THREAD);
Handle h_loader (THREAD, JNIHandles::resolve(class_loader));
// Check that loader is a subclass of java.lang.ClassLoader.
if (h_loader.not_null() && !java_lang_ClassLoader::is_subclass(h_loader->klass())) {
return JVMTI_ERROR_ILLEGAL_ARGUMENT;
}
jobject module = Modules::get_named_module(h_loader, package_name, THREAD);
if (HAS_PENDING_EXCEPTION) {
CLEAR_PENDING_EXCEPTION;
return JVMTI_ERROR_INTERNAL; // unexpected exception
}
*module_ptr = module;
return JVMTI_ERROR_NONE;
} /* end GetNamedModule */
// //
// Class functions // Class functions
// //

View File

@ -131,8 +131,6 @@ static int Knob_MoveNotifyee = 2; // notify() - disposition of noti
static int Knob_QMode = 0; // EntryList-cxq policy - queue discipline static int Knob_QMode = 0; // EntryList-cxq policy - queue discipline
static volatile int InitDone = 0; static volatile int InitDone = 0;
#define TrySpin TrySpin_VaryDuration
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Theory of operations -- Monitors lists, thread residency, etc: // Theory of operations -- Monitors lists, thread residency, etc:
// //
@ -1848,13 +1846,8 @@ void ObjectMonitor::notifyAll(TRAPS) {
// hysteresis control to damp the transition rate between spinning and // hysteresis control to damp the transition rate between spinning and
// not spinning. // not spinning.
intptr_t ObjectMonitor::SpinCallbackArgument = 0;
int (*ObjectMonitor::SpinCallbackFunction)(intptr_t, int) = NULL;
// Spinning: Fixed frequency (100%), vary duration // Spinning: Fixed frequency (100%), vary duration
int ObjectMonitor::TrySpin(Thread * Self) {
int ObjectMonitor::TrySpin_VaryDuration(Thread * Self) {
// Dumb, brutal spin. Good for comparative measurements against adaptive spinning. // Dumb, brutal spin. Good for comparative measurements against adaptive spinning.
int ctr = Knob_FixedSpin; int ctr = Knob_FixedSpin;
if (ctr != 0) { if (ctr != 0) {
@ -1948,11 +1941,6 @@ int ObjectMonitor::TrySpin_VaryDuration(Thread * Self) {
goto Abort; // abrupt spin egress goto Abort; // abrupt spin egress
} }
if (Knob_UsePause & 1) SpinPause(); if (Knob_UsePause & 1) SpinPause();
int (*scb)(intptr_t,int) = SpinCallbackFunction;
if (hits > 50 && scb != NULL) {
int abend = (*scb)(SpinCallbackArgument, 0);
}
} }
if (Knob_UsePause & 2) SpinPause(); if (Knob_UsePause & 2) SpinPause();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -161,9 +161,6 @@ class ObjectMonitor {
Thread * volatile _Responsible; Thread * volatile _Responsible;
volatile int _Spinner; // for exit->spinner handoff optimization volatile int _Spinner; // for exit->spinner handoff optimization
volatile int _SpinFreq; // Spin 1-out-of-N attempts: success rate
volatile int _SpinClock;
volatile intptr_t _SpinState; // MCS/CLH list of spinners
volatile int _SpinDuration; volatile int _SpinDuration;
volatile jint _count; // reference count to prevent reclamation/deflation volatile jint _count; // reference count to prevent reclamation/deflation
@ -238,10 +235,6 @@ class ObjectMonitor {
static int cxq_offset_in_bytes() { return offset_of(ObjectMonitor, _cxq); } static int cxq_offset_in_bytes() { return offset_of(ObjectMonitor, _cxq); }
static int succ_offset_in_bytes() { return offset_of(ObjectMonitor, _succ); } static int succ_offset_in_bytes() { return offset_of(ObjectMonitor, _succ); }
static int EntryList_offset_in_bytes() { return offset_of(ObjectMonitor, _EntryList); } static int EntryList_offset_in_bytes() { return offset_of(ObjectMonitor, _EntryList); }
static int FreeNext_offset_in_bytes() { return offset_of(ObjectMonitor, FreeNext); }
static int WaitSet_offset_in_bytes() { return offset_of(ObjectMonitor, _WaitSet); }
static int Responsible_offset_in_bytes() { return offset_of(ObjectMonitor, _Responsible); }
static int Spinner_offset_in_bytes() { return offset_of(ObjectMonitor, _Spinner); }
// ObjectMonitor references can be ORed with markOopDesc::monitor_value // ObjectMonitor references can be ORed with markOopDesc::monitor_value
// as part of the ObjectMonitor tagging mechanism. When we combine an // as part of the ObjectMonitor tagging mechanism. When we combine an
@ -257,11 +250,6 @@ class ObjectMonitor {
#define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \ #define OM_OFFSET_NO_MONITOR_VALUE_TAG(f) \
((ObjectMonitor::f ## _offset_in_bytes()) - markOopDesc::monitor_value) ((ObjectMonitor::f ## _offset_in_bytes()) - markOopDesc::monitor_value)
// Eventually we'll make provisions for multiple callbacks, but
// now one will suffice.
static int (*SpinCallbackFunction)(intptr_t, int);
static intptr_t SpinCallbackArgument;
markOop header() const; markOop header() const;
void set_header(markOop hdr); void set_header(markOop hdr);
@ -312,8 +300,6 @@ class ObjectMonitor {
_cxq = NULL; _cxq = NULL;
_WaitSet = NULL; _WaitSet = NULL;
_recursions = 0; _recursions = 0;
_SpinFreq = 0;
_SpinClock = 0;
} }
public: public:
@ -353,9 +339,7 @@ class ObjectMonitor {
void UnlinkAfterAcquire(Thread * Self, ObjectWaiter * SelfNode); void UnlinkAfterAcquire(Thread * Self, ObjectWaiter * SelfNode);
int TryLock(Thread * Self); int TryLock(Thread * Self);
int NotRunnable(Thread * Self, Thread * Owner); int NotRunnable(Thread * Self, Thread * Owner);
int TrySpin_Fixed(Thread * Self); int TrySpin(Thread * Self);
int TrySpin_VaryFrequency(Thread * Self);
int TrySpin_VaryDuration(Thread * Self);
void ExitEpilog(Thread * Self, ObjectWaiter * Wakee); void ExitEpilog(Thread * Self, ObjectWaiter * Wakee);
bool ExitSuspendEquivalent(JavaThread * Self); bool ExitSuspendEquivalent(JavaThread * Self);
void post_monitor_wait_event(EventJavaMonitorWait * event, void post_monitor_wait_event(EventJavaMonitorWait * event,

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -144,8 +144,6 @@ class ObjectSynchronizer : AllStatic {
static void verify() PRODUCT_RETURN; static void verify() PRODUCT_RETURN;
static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0; static int verify_objmon_isinpool(ObjectMonitor *addr) PRODUCT_RETURN0;
static void RegisterSpinCallback(int(*)(intptr_t, int), intptr_t);
private: private:
enum { _BLOCKSIZE = 128 }; enum { _BLOCKSIZE = 128 };
// global list of blocks of monitors // global list of blocks of monitors

View File

@ -29,6 +29,7 @@
## @summary testing of ciReplay with using generated by VM replay.txt w/o comp_level ## @summary testing of ciReplay with using generated by VM replay.txt w/o comp_level
## @author igor.ignatyev@oracle.com ## @author igor.ignatyev@oracle.com
## @requires vm.flightRecorder != true ## @requires vm.flightRecorder != true
## @ignore 8157984
## @run shell TestVM_no_comp_level.sh ## @run shell TestVM_no_comp_level.sh
## ##

View File

@ -28,6 +28,7 @@
* @library /testlibrary /test/lib / * @library /testlibrary /test/lib /
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* java.management * java.management
* @ignore 8157984
* @build TestRangeCheckSmearing * @build TestRangeCheckSmearing
* @run driver ClassFileInstaller sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox
* jdk.test.lib.Platform * jdk.test.lib.Platform

View File

@ -26,6 +26,7 @@
* @library /testlibrary /test/lib / * @library /testlibrary /test/lib /
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* @modules java.management * @modules java.management
* @ignore 8157984
* @build NonTieredLevelsTest * @build NonTieredLevelsTest
* @run driver ClassFileInstaller sun.hotspot.WhiteBox * @run driver ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission * sun.hotspot.WhiteBox$WhiteBoxPermission

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test TestInitialGCThreadLogging
* @bug 8157240
* @summary Check trace logging of initial GC threads.
* @requires vm.gc=="null"
* @key gc
* @modules java.base/jdk.internal.misc
* @library /testlibrary
*/
import jdk.test.lib.ProcessTools;
import jdk.test.lib.OutputAnalyzer;
public class TestInitialGCThreadLogging {
public static void main(String[] args) throws Exception {
testInitialGCThreadLogging("UseConcMarkSweepGC", "GC Thread");
testInitialGCThreadLogging("UseG1GC", "GC Thread");
testInitialGCThreadLogging("UseParallelGC", "ParGC Thread");
}
private static void verifyDynamicNumberOfGCThreads(OutputAnalyzer output, String threadName) {
output.shouldHaveExitValue(0); // test should run succesfully
output.shouldContain(threadName);
}
private static void testInitialGCThreadLogging(String gcFlag, String threadName) throws Exception {
// UseDynamicNumberOfGCThreads and TraceDynamicGCThreads enabled
String[] baseArgs = {"-XX:+" + gcFlag, "-Xmx10M", "-XX:+UseDynamicNumberOfGCThreads", "-Xlog:gc+task=trace", "-version"};
// Base test with gc and +UseDynamicNumberOfGCThreads:
ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder(baseArgs);
verifyDynamicNumberOfGCThreads(new OutputAnalyzer(pb_enabled.start()), threadName);
}
}

View File

@ -46,7 +46,7 @@ public class TestStringSymbolTableStats {
System.out.println("Output:\n" + output.getOutput()); System.out.println("Output:\n" + output.getOutput());
output.shouldContain("Cleaned string and symbol table"); output.shouldMatch("GC\\(\\d+\\) Cleaned string and symbol table");
output.shouldHaveExitValue(0); output.shouldHaveExitValue(0);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -24,11 +24,11 @@
import java.util.ArrayList; import java.util.ArrayList;
/* @test TestMetaspaceInitialization /* @test TestMetaspaceInitialization
* @bug 8042933 * @bug 8024945
* @summary Tests to initialize metaspace with a very low MetaspaceSize * @summary Tests to initialize metaspace with a very low MetaspaceSize
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* @library /testlibrary * @library /testlibrary
* @run main/othervm -XX:MetaspaceSize=2m TestMetaspaceInitialization * @run main/othervm -XX:MetaspaceSize=0 TestMetaspaceInitialization
*/ */
public class TestMetaspaceInitialization { public class TestMetaspaceInitialization {
private class Internal { private class Internal {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2013, 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -47,9 +47,6 @@ public class TestMetaspaceSizeFlags {
// 8024650: MaxMetaspaceSize was adjusted instead of MetaspaceSize. // 8024650: MaxMetaspaceSize was adjusted instead of MetaspaceSize.
testMaxMetaspaceSizeLTMetaspaceSize(MAX_ALIGNMENT, MAX_ALIGNMENT * 2); testMaxMetaspaceSizeLTMetaspaceSize(MAX_ALIGNMENT, MAX_ALIGNMENT * 2);
testMaxMetaspaceSizeGTMetaspaceSize(MAX_ALIGNMENT * 2, MAX_ALIGNMENT); testMaxMetaspaceSizeGTMetaspaceSize(MAX_ALIGNMENT * 2, MAX_ALIGNMENT);
testTooSmallInitialMetaspace(0, 0);
testTooSmallInitialMetaspace(0, MAX_ALIGNMENT);
testTooSmallInitialMetaspace(MAX_ALIGNMENT, 0);
} }
private static void testMaxMetaspaceSizeEQMetaspaceSize(long maxMetaspaceSize, long metaspaceSize) throws Exception { private static void testMaxMetaspaceSizeEQMetaspaceSize(long maxMetaspaceSize, long metaspaceSize) throws Exception {
@ -73,11 +70,6 @@ public class TestMetaspaceSizeFlags {
Asserts.assertEQ(mf.metaspaceSize, metaspaceSize); Asserts.assertEQ(mf.metaspaceSize, metaspaceSize);
} }
private static void testTooSmallInitialMetaspace(long maxMetaspaceSize, long metaspaceSize) throws Exception {
OutputAnalyzer output = run(maxMetaspaceSize, metaspaceSize);
output.shouldContain("Too small initial Metaspace size");
}
private static MetaspaceFlags runAndGetValue(long maxMetaspaceSize, long metaspaceSize) throws Exception { private static MetaspaceFlags runAndGetValue(long maxMetaspaceSize, long metaspaceSize) throws Exception {
OutputAnalyzer output = run(maxMetaspaceSize, metaspaceSize); OutputAnalyzer output = run(maxMetaspaceSize, metaspaceSize);
output.shouldNotMatch("Error occurred during initialization of VM\n.*"); output.shouldNotMatch("Error occurred during initialization of VM\n.*");

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
public class TestPutField
version 53:0
{
final Field test_field:"I";
public Method <init>:"()V"
stack 2 locals 1
{
aload_0;
dup;
invokespecial Method java/lang/Object.<init>:"()V";
bipush 13;
putfield Field test_field:"I";
return;
}
public Method aMethod:"()I"
stack 2 locals 2
{
aload_0;
getfield Field test_field:"I";
istore_1;
aload_0;
bipush 14;
putfield Field test_field:"I";
iload_1;
ireturn;
}
public static Method test:"()V"
stack 2 locals 2
{
new class TestPutField;
astore_0;
aload_0;
invokespecial Method <init>:"()V";
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
astore_1;
aload_1;
aload_0;
invokevirtual Method aMethod:"()I";
invokevirtual Method java/io/PrintStream.println:"(I)V";
aload_1;
aload_0;
getfield Field test_field:"I";
invokevirtual Method java/io/PrintStream.println:"(I)V";
return;
}
}

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
/*
* @test
* @bug 8160527
* @summary The VM does not always perform checks added by 8157181 when updating final instance fields
* @library /testlibrary
* @compile TestPutField.jasm
* @compile TestPutStatic.jasm
* @compile TestPutMain.java
* @run main/othervm TestPutMain
*/
import jdk.test.lib.Asserts;
public class TestPutMain {
public static void main(String[] args) {
boolean exception = false;
try {
TestPutField.test();
} catch (java.lang.IllegalAccessError e) {
exception = true;
}
Asserts.assertTrue(exception, "FAILED: Expected IllegalAccessError for illegal update to final instance field was not thrown.");
exception = false;
try {
TestPutStatic.test();
} catch (java.lang.IllegalAccessError e) {
exception = true;
}
Asserts.assertTrue(exception, "FAILED: Expected IllegalAccessError for illegal update to final static field was not thrown.");
System.out.println("PASSED: Expected IllegalAccessError was thrown.");
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
public class TestPutStatic
version 53:0
{
final static Field test_field:"I";
public static Method <clinit>:"()V"
stack 2 locals 1
{
bipush 13;
putstatic Field test_field:"I";
return;
}
public static Method aMethod:"()I"
stack 1 locals 1
{
getstatic Field test_field:"I";
istore_0;
bipush 14;
putstatic Field test_field:"I";
iload_0;
ireturn;
}
public static Method test:"()V"
stack 2 locals 1
{
getstatic Field java/lang/System.out:"Ljava/io/PrintStream;";
astore_0;
aload_0;
invokestatic Method aMethod:"()I";
invokevirtual Method java/io/PrintStream.println:"(I)V";
aload_0;
getstatic Field test_field:"I";
invokevirtual Method java/io/PrintStream.println:"(I)V";
return;
}
}

View File

@ -24,6 +24,9 @@
/* /*
* @test SASymbolTableTest * @test SASymbolTableTest
* @summary Walk symbol table using SA, with and without CDS. * @summary Walk symbol table using SA, with and without CDS.
* Started failing on 2016.06.24 due to 8160376 on MacOS X so quarantine
* it on that platform:
* @requires os.family != "mac"
* @library /testlibrary * @library /testlibrary
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* jdk.hotspot.agent/sun.jvm.hotspot.oops * jdk.hotspot.agent/sun.jvm.hotspot.oops

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package MyPackage;
/**
* @test
* @summary Verifies the JVMTI GetNamedModule API
* @compile GetNamedModuleTest.java
* @run main/othervm/native -agentlib:GetNamedModuleTest MyPackage.GetNamedModuleTest
*/
import java.io.PrintStream;
public class GetNamedModuleTest {
static {
try {
System.loadLibrary("GetNamedModuleTest");
} catch (UnsatisfiedLinkError ule) {
System.err.println("Could not load GetNamedModuleTest library");
System.err.println("java.library.path: "
+ System.getProperty("java.library.path"));
throw ule;
}
}
native static int check();
public static void main(String args[]) {
int status = check();
if (status != 0) {
throw new RuntimeException("Non-zero status returned from the agent: " + status);
}
}
}

View File

@ -0,0 +1,405 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdio.h>
#include <string.h>
#include "jvmti.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifndef JNI_ENV_ARG
#ifdef __cplusplus
#define JNI_ENV_ARG(x, y) y
#define JNI_ENV_PTR(x) x
#else
#define JNI_ENV_ARG(x,y) x, y
#define JNI_ENV_PTR(x) (*x)
#endif
#endif
#define TranslateError(err) "JVMTI error"
#define PASSED 0
#define FAILED 2
static const char *EXC_CNAME = "java/lang/Exception";
static const char* MOD_CNAME = "Ljava/lang/reflect/Module;";
static jvmtiEnv *jvmti = NULL;
static jint result = PASSED;
static jboolean printdump = JNI_FALSE;
static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
JNIEXPORT
jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
return Agent_Initialize(jvm, options, reserved);
}
JNIEXPORT
jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
return Agent_Initialize(jvm, options, reserved);
}
JNIEXPORT
jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
return JNI_VERSION_1_8;
}
static
jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
jint res;
if (options != NULL && strcmp(options, "printdump") == 0) {
printdump = JNI_TRUE;
}
res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
JVMTI_VERSION_9);
if (res != JNI_OK || jvmti == NULL) {
printf(" Error: wrong result of a valid call to GetEnv!\n");
return JNI_ERR;
}
return JNI_OK;
}
static
jint throw_exc(JNIEnv *env, char *msg) {
jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
if (exc_class == NULL) {
printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
return -1;
}
return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
}
static
jobject get_class_loader(jclass cls) {
jvmtiError err = JVMTI_ERROR_NONE;
jobject loader = NULL;
if (printdump == JNI_TRUE) {
printf(">>> getting class loader ...\n");
}
err = (*jvmti)->GetClassLoader(jvmti, cls, &loader);
if (err != JVMTI_ERROR_NONE) {
printf(" Error in GetClassLoader: %s (%d)\n", TranslateError(err), err);
}
return loader;
}
static
jclass jlrM(JNIEnv *env) {
jclass cls = NULL;
cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME));
if (cls == NULL) {
printf(" Error in JNI FindClass: %s\n", MOD_CNAME);
}
return cls;
}
jmethodID
get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) {
jmethodID method = NULL;
method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig);
if (method == NULL) {
printf(" Error in JNI GetMethodID %s with signature %s", name, sig);
}
return method;
}
static
jobject get_module_loader(JNIEnv *env, jobject module) {
static jmethodID cl_method = NULL;
jobject loader = NULL;
if (cl_method == NULL) {
cl_method = get_method(env, jlrM(env), "getClassLoader", "()Ljava/lang/ClassLoader;");
}
loader = (jobject)JNI_ENV_PTR(env)->CallObjectMethod(JNI_ENV_ARG(env, module), cl_method);
return loader;
}
static
const char* get_module_name(JNIEnv *env, jobject module) {
static jmethodID method = NULL;
jobject loader = NULL;
jstring jstr = NULL;
const char *name = NULL;
const char *nstr = NULL;
if (method == NULL) {
method = get_method(env, jlrM(env), "getName", "()Ljava/lang/String;");
}
jstr = (jstring)JNI_ENV_PTR(env)->CallObjectMethod(JNI_ENV_ARG(env, module), method);
if (jstr != NULL) {
name = JNI_ENV_PTR(env)->GetStringUTFChars(JNI_ENV_ARG(env, jstr), NULL);
}
loader = get_module_loader(env, module);
nstr = (name == NULL) ? "<UNNAMED>" : name;
printf(" loader: %p, module: %p, name: %s\n", loader, module, nstr);
return name;
}
static
jvmtiError get_module(JNIEnv *env,
jobject loader,
const char* pkg_name,
jobject* module_ptr,
const char** mod_name_ptr) {
jvmtiError err = JVMTI_ERROR_NONE;
const char* name = (pkg_name == NULL) ? "<NULL>" : pkg_name;
printf(">>> getting module by loader %p and package \"%s\"\n", loader, name);
*mod_name_ptr = NULL;
err = (*jvmti)->GetNamedModule(jvmti, loader, pkg_name, module_ptr);
if (err != JVMTI_ERROR_NONE) {
printf(" Error in GetNamedModule for package \"%s\": %s (%d)\n",
pkg_name, TranslateError(err), err);
return err;
}
printf(" returned module: %p\n", *module_ptr);
if (*module_ptr == NULL) { // named module was not found
return err;
}
*mod_name_ptr = get_module_name(env, *module_ptr);
return err;
}
static
jint get_all_modules(JNIEnv *env) {
jvmtiError err;
jint cnt = -1;
jint idx = 0;
jobject* modules;
printf(">>> Inspecting modules with GetAllModules\n");
err = (*jvmti)->GetAllModules(jvmti, &cnt, &modules);
if (err != JVMTI_ERROR_NONE) {
printf("Error in GetAllModules: %d\n", err);
return -1;
}
for (idx = 0; idx < cnt; ++idx) {
get_module_name(env, modules[idx]);
}
return cnt;
}
static
jint check_bad_loader(JNIEnv *env, jobject loader) {
jvmtiError err = JVMTI_ERROR_NONE;
jobject module = NULL;
const char* mod_name = NULL;
err = get_module(env, loader, "", &module, &mod_name);
if (err != JVMTI_ERROR_ILLEGAL_ARGUMENT) {
return FAILED;
}
printf(" got expected JVMTI_ERROR_ILLEGAL_ARGUMENT for bad loader\n");
return PASSED;
}
static
jint check_system_loader(JNIEnv *env, jobject loader) {
jvmtiError err = JVMTI_ERROR_NONE;
jobject module = NULL;
const char* exp_name = NULL;
const char* mod_name = NULL;
// NULL pointer for package name
err = get_module(env, loader, NULL, &module, &mod_name);
if (err != JVMTI_ERROR_NULL_POINTER) {
throw_exc(env, "check #SN1: failed to return JVMTI_ERROR_NULL_POINTER for NULL package");
return FAILED;
}
// NULL pointer for module_ptr
err = (*jvmti)->GetNamedModule(jvmti, loader, "", NULL);
if (err != JVMTI_ERROR_NULL_POINTER) {
throw_exc(env, "check #SN2: failed to return JVMTI_ERROR_NULL_POINTER for NULL module_ptr");
return FAILED;
}
// Unnamed/default package ""
err = get_module(env, loader, "", &module, &mod_name);
if (err != JVMTI_ERROR_NONE) {
throw_exc(env, "check #S1: failed to return JVMTI_ERROR_NONE for default package");
return FAILED;
}
if (module != NULL || mod_name != NULL) {
throw_exc(env, "check #S2: failed to return NULL-module for default package");
return FAILED;
}
// Test package: MyPackage
err = get_module(env, loader, "MyPackage", &module, &mod_name);
if (err != JVMTI_ERROR_NONE) {
throw_exc(env, "check #S3: failed to return JVMTI_ERROR_NONE for MyPackage");
return FAILED;
}
if (module != NULL || mod_name != NULL) {
throw_exc(env, "check #S4: failed to return NULL-module for MyPackage");
return FAILED;
}
// Package: com/sun/jdi
exp_name = "jdk.jdi";
err = get_module(env, loader, "com/sun/jdi", &module, &mod_name);
if (err != JVMTI_ERROR_NONE) {
throw_exc(env, "check #S5: failed to return JVMTI_ERROR_NONE for test package");
return FAILED;
}
if (module == NULL || mod_name == NULL) {
throw_exc(env, "check #S6: failed to return named module for com/sun/jdi package");
return FAILED;
}
if (strcmp(mod_name, exp_name) != 0) {
printf("check #S7: failed to return right module, expected: %s, returned: %s\n",
exp_name, mod_name);
throw_exc(env, "check #S7: failed to return jdk.jdi module for com/sun/jdi package");
return FAILED;
}
// Non-existing package: "bad/package/name"
err = get_module(env, loader, "bad/package/name", &module, &mod_name);
if (err != JVMTI_ERROR_NONE) {
throw_exc(env, "check #S8: failed to return JVMTI_ERROR_NONE for bad package");
return FAILED;
}
if (module != NULL || mod_name != NULL) {
throw_exc(env, "check #S9: failed to return NULL-module for bad package");
return FAILED;
}
return PASSED;
}
static
jint check_bootstrap_loader(JNIEnv *env, jobject loader) {
jvmtiError err = JVMTI_ERROR_NONE;
jobject module = NULL;
const char* exp_name = NULL;
const char* mod_name = NULL;
// NULL pointer for package name
err = get_module(env, loader, NULL, &module, &mod_name);
if (err != JVMTI_ERROR_NULL_POINTER) {
throw_exc(env, "check #BN1: failed to return JVMTI_ERROR_NULL_POINTER for NULL package");
return FAILED;
}
// NULL pointer for module_ptr
err = (*jvmti)->GetNamedModule(jvmti, loader, "", NULL);
if (err != JVMTI_ERROR_NULL_POINTER) {
throw_exc(env, "check #BN2: failed to return JVMTI_ERROR_NULL_POINTER for NULL module_ptr");
return FAILED;
}
// Unnamed/default package ""
err = get_module(env, loader, "", &module, &mod_name);
if (err != JVMTI_ERROR_NONE) {
throw_exc(env, "check #B1: failed to return JVMTI_ERROR_NONE for default package");
return FAILED;
}
if (module != NULL || mod_name != NULL) {
throw_exc(env, "check #B2: failed to return NULL-module for default package");
return FAILED;
}
// Normal package from java.base module: "java/lang"
exp_name = "java.base";
err = get_module(env, loader, "java/lang", &module, &mod_name);
if (err != JVMTI_ERROR_NONE) {
throw_exc(env, "check #B3: failed to return JVMTI_ERROR_NONE for java/lang package");
return FAILED;
}
if (module == NULL || mod_name == NULL) {
throw_exc(env, "check #B4: failed to return named module for java/lang package");
return FAILED;
}
if (strcmp(exp_name, mod_name) != 0) {
printf("check #B5: failed to return right module, expected: %s, returned: %s\n",
exp_name, mod_name);
throw_exc(env, "check #B5: failed to return expected module for java/lang package");
return FAILED;
}
// Non-existing package: "bad/package/name"
err = get_module(env, loader, "bad/package/name", &module, &mod_name);
if (err != JVMTI_ERROR_NONE) {
throw_exc(env, "check #B6: failed to return JVMTI_ERROR_NONE for bad package");
return FAILED;
}
if (module != NULL || mod_name != NULL) {
throw_exc(env, "check #B7: failed to return NULL-module for bad package");
return FAILED;
}
return PASSED;
}
JNIEXPORT jint JNICALL
Java_MyPackage_GetNamedModuleTest_check(JNIEnv *env, jclass cls) {
jobject loader = NULL;
if (jvmti == NULL) {
throw_exc(env, "JVMTI client was not properly loaded!\n");
return FAILED;
}
get_all_modules(env);
printf("\n*** Check for bad ClassLoader ***\n\n");
result = check_bad_loader(env, (jobject)cls);
if (result != PASSED) {
throw_exc(env, "check #L1: failed to return JVMTI_ERROR_ILLEGAL_ARGUMENT for bad loader");
return result;
}
loader = get_class_loader(cls);
if (loader == NULL) {
throw_exc(env, "check #L2: failed to return non-NULL loader for valid test class");
return FAILED;
}
printf("\n*** Checks for System ClassLoader ***\n\n");
result = check_system_loader(env, loader);
if (result != PASSED) {
return result;
}
printf("\n*** Checks for Bootstrap ClassLoader ***\n\n");
result = check_bootstrap_loader(env, NULL);
return result;
}
#ifdef __cplusplus
}
#endif

View File

@ -32,6 +32,9 @@ import jdk.test.lib.apps.LingeredApp;
/* /*
* @test * @test
* @summary Started failing on 2016.06.24 due to 8160376 on MacOS X so
* quarantine it on that platform:
* @requires os.family != "mac"
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* @library /test/lib/share/classes * @library /test/lib/share/classes
* @library /testlibrary * @library /testlibrary

View File

@ -32,6 +32,9 @@ import jdk.test.lib.apps.LingeredApp;
/* /*
* @test * @test
* @summary Started failing on 2016.06.24 due to 8160376 on MacOS X so
* quarantine it on that platform:
* @requires os.family != "mac"
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* @library /test/lib/share/classes * @library /test/lib/share/classes
* @library /testlibrary * @library /testlibrary

View File

@ -43,6 +43,9 @@ import jdk.test.lib.ProcessTools;
* @bug 6313383 * @bug 6313383
* @key regression * @key regression
* @summary Regression test for hprof export issue due to large heaps (>2G) * @summary Regression test for hprof export issue due to large heaps (>2G)
* Started failing on 2016.06.24 due to 8160376 on MacOS X so quarantine
* it on that platform:
* @requires os.family != "mac"
* @library /testlibrary * @library /testlibrary
* @modules java.base/jdk.internal.misc * @modules java.base/jdk.internal.misc
* java.compiler * java.compiler