aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramurillo <none@none>2014-02-28 08:43:42 -0800
committeramurillo <none@none>2014-02-28 08:43:42 -0800
commit6d488647762b5c67144b96ee6ab5c8c51e1db523 (patch)
tree9564b8c15d601270cd6c9c24fec7b9ae3eac33fa
parentc889b5e8a0819e9b8f1c28aa1dbaae0ed6d8524a (diff)
parent50ae7d69ceb27273d8de36bc595837941151b188 (diff)
-rw-r--r--agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java5
-rw-r--r--make/excludeSrc.make2
-rw-r--r--make/hotspot_version2
-rw-r--r--src/cpu/sparc/vm/vm_version_sparc.hpp8
-rw-r--r--src/os/bsd/vm/os_bsd.cpp11
-rw-r--r--src/os/linux/vm/os_linux.cpp3
-rw-r--r--src/os/posix/vm/os_posix.cpp4
-rw-r--r--src/os/solaris/vm/os_solaris.cpp4
-rw-r--r--src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp23
-rw-r--r--src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp8
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp70
-rw-r--r--src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp146
-rw-r--r--src/share/vm/gc_implementation/g1/g1OopClosures.cpp31
-rw-r--r--src/share/vm/gc_implementation/g1/g1OopClosures.hpp39
-rw-r--r--src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp2
-rw-r--r--src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp2
-rw-r--r--src/share/vm/memory/binaryTreeDictionary.cpp227
-rw-r--r--src/share/vm/memory/binaryTreeDictionary.hpp32
-rw-r--r--src/share/vm/memory/metaspace.cpp16
-rw-r--r--src/share/vm/oops/constantPool.cpp1
-rw-r--r--src/share/vm/opto/c2_globals.hpp3
-rw-r--r--src/share/vm/opto/output.cpp15
-rw-r--r--src/share/vm/prims/jni.cpp14
-rw-r--r--src/share/vm/prims/jvm.cpp8
-rw-r--r--src/share/vm/runtime/globals.cpp24
-rw-r--r--src/share/vm/runtime/objectMonitor.cpp64
-rw-r--r--src/share/vm/runtime/vmStructs.cpp2
-rw-r--r--src/share/vm/trace/trace.xml40
-rw-r--r--src/share/vm/trace/tracetypes.xml26
-rw-r--r--test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java82
-rw-r--r--test/serviceability/jvmti/UnresolvedClassAgent.java69
-rw-r--r--test/serviceability/jvmti/UnresolvedClassAgent.mf3
-rw-r--r--test/serviceability/sa/jmap-hashcode/Test8028623.java74
-rw-r--r--test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java81
-rw-r--r--test/testlibrary/com/oracle/java/testlibrary/Utils.java263
35 files changed, 1020 insertions, 384 deletions
diff --git a/agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java b/agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java
index e9248e74f..e2281e7b3 100644
--- a/agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java
+++ b/agent/src/share/classes/sun/jvm/hotspot/utilities/Hashtable.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2014, 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
@@ -61,8 +61,9 @@ public class Hashtable extends BasicHashtable {
long h = 0;
int s = 0;
int len = buf.length;
+ // Emulate the unsigned int in java_lang_String::hash_code
while (len-- > 0) {
- h = 31*h + (0xFFL & buf[s]);
+ h = 31*h + (0xFFFFFFFFL & buf[s]);
s++;
}
return h & 0xFFFFFFFFL;
diff --git a/make/excludeSrc.make b/make/excludeSrc.make
index a95dc1b11..24f1fa20e 100644
--- a/make/excludeSrc.make
+++ b/make/excludeSrc.make
@@ -86,7 +86,7 @@ ifeq ($(INCLUDE_ALL_GCS), false)
concurrentMark.cpp concurrentMarkThread.cpp dirtyCardQueue.cpp g1AllocRegion.cpp \
g1BlockOffsetTable.cpp g1CardCounts.cpp g1CollectedHeap.cpp g1CollectorPolicy.cpp \
g1ErgoVerbose.cpp g1GCPhaseTimes.cpp g1HRPrinter.cpp g1HotCardCache.cpp g1Log.cpp \
- g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp \
+ g1MMUTracker.cpp g1MarkSweep.cpp g1MemoryPool.cpp g1MonitoringSupport.cpp g1OopClosures.cpp \
g1RemSet.cpp g1RemSetSummary.cpp g1SATBCardTableModRefBS.cpp g1_globals.cpp heapRegion.cpp \
g1BiasedArray.cpp heapRegionRemSet.cpp heapRegionSeq.cpp heapRegionSet.cpp heapRegionSets.cpp \
ptrQueue.cpp satbQueue.cpp sparsePRT.cpp survRateGroup.cpp vm_operations_g1.cpp \
diff --git a/make/hotspot_version b/make/hotspot_version
index a213846dc..b6fe79757 100644
--- a/make/hotspot_version
+++ b/make/hotspot_version
@@ -35,7 +35,7 @@ HOTSPOT_VM_COPYRIGHT=Copyright 2014
HS_MAJOR_VER=25
HS_MINOR_VER=20
-HS_BUILD_NUMBER=04
+HS_BUILD_NUMBER=05
JDK_MAJOR_VER=1
JDK_MINOR_VER=8
diff --git a/src/cpu/sparc/vm/vm_version_sparc.hpp b/src/cpu/sparc/vm/vm_version_sparc.hpp
index 6ddf57007..eafb48562 100644
--- a/src/cpu/sparc/vm/vm_version_sparc.hpp
+++ b/src/cpu/sparc/vm/vm_version_sparc.hpp
@@ -49,7 +49,8 @@ protected:
M_family = 15,
T_family = 16,
T1_model = 17,
- aes_instructions = 18
+ sparc5_instructions = 18,
+ aes_instructions = 19
};
enum Feature_Flag_Set {
@@ -74,6 +75,7 @@ protected:
M_family_m = 1 << M_family,
T_family_m = 1 << T_family,
T1_model_m = 1 << T1_model,
+ sparc5_instructions_m = 1 << sparc5_instructions,
aes_instructions_m = 1 << aes_instructions,
generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m,
@@ -125,6 +127,7 @@ public:
static bool has_vis3() { return (_features & vis3_instructions_m) != 0; }
static bool has_blk_init() { return (_features & blk_init_instructions_m) != 0; }
static bool has_cbcond() { return (_features & cbcond_instructions_m) != 0; }
+ static bool has_sparc5_instr() { return (_features & sparc5_instructions_m) != 0; }
static bool has_aes() { return (_features & aes_instructions_m) != 0; }
static bool supports_compare_and_exchange()
@@ -136,6 +139,7 @@ public:
static bool is_M_series() { return is_M_family(_features); }
static bool is_T4() { return is_T_family(_features) && has_cbcond(); }
+ static bool is_T7() { return is_T_family(_features) && has_sparc5_instr(); }
// Fujitsu SPARC64
static bool is_sparc64() { return (_features & sparc64_family_m) != 0; }
@@ -155,7 +159,7 @@ public:
static const char* cpu_features() { return _features_str; }
static intx prefetch_data_size() {
- return is_T4() ? 32 : 64; // default prefetch block size on sparc
+ return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc
}
// Prefetch
diff --git a/src/os/bsd/vm/os_bsd.cpp b/src/os/bsd/vm/os_bsd.cpp
index 1bea78444..47e5d16ef 100644
--- a/src/os/bsd/vm/os_bsd.cpp
+++ b/src/os/bsd/vm/os_bsd.cpp
@@ -1557,6 +1557,17 @@ void * os::dll_load(const char *filename, char *ebuf, int ebuflen)
}
#endif /* !__APPLE__ */
+void* os::get_default_process_handle() {
+#ifdef __APPLE__
+ // MacOS X needs to use RTLD_FIRST instead of RTLD_LAZY
+ // to avoid finding unexpected symbols on second (or later)
+ // loads of a library.
+ return (void*)::dlopen(NULL, RTLD_FIRST);
+#else
+ return (void*)::dlopen(NULL, RTLD_LAZY);
+#endif
+}
+
// XXX: Do we need a lock around this as per Linux?
void* os::dll_lookup(void* handle, const char* name) {
return dlsym(handle, name);
diff --git a/src/os/linux/vm/os_linux.cpp b/src/os/linux/vm/os_linux.cpp
index 1bb329015..54149e182 100644
--- a/src/os/linux/vm/os_linux.cpp
+++ b/src/os/linux/vm/os_linux.cpp
@@ -2104,6 +2104,9 @@ void* os::dll_lookup(void* handle, const char* name) {
return res;
}
+void* os::get_default_process_handle() {
+ return (void*)::dlopen(NULL, RTLD_LAZY);
+}
static bool _print_ascii_file(const char* filename, outputStream* st) {
int fd = ::open(filename, O_RDONLY);
diff --git a/src/os/posix/vm/os_posix.cpp b/src/os/posix/vm/os_posix.cpp
index 6aae96e9b..633331728 100644
--- a/src/os/posix/vm/os_posix.cpp
+++ b/src/os/posix/vm/os_posix.cpp
@@ -262,10 +262,6 @@ FILE* os::open(int fd, const char* mode) {
return ::fdopen(fd, mode);
}
-void* os::get_default_process_handle() {
- return (void*)::dlopen(NULL, RTLD_LAZY);
-}
-
// Builds a platform dependent Agent_OnLoad_<lib_name> function name
// which is used to find statically linked in agents.
// Parameters:
diff --git a/src/os/solaris/vm/os_solaris.cpp b/src/os/solaris/vm/os_solaris.cpp
index 8e5984ffa..a4d0178c8 100644
--- a/src/os/solaris/vm/os_solaris.cpp
+++ b/src/os/solaris/vm/os_solaris.cpp
@@ -2146,6 +2146,10 @@ void* os::dll_lookup(void* handle, const char* name) {
return dlsym(handle, name);
}
+void* os::get_default_process_handle() {
+ return (void*)::dlopen(NULL, RTLD_LAZY);
+}
+
int os::stat(const char *path, struct stat *sbuf) {
char pathbuf[MAX_PATH];
if (strlen(path) > MAX_PATH - 1) {
diff --git a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp
index 6dca05f91..b6639c90b 100644
--- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp
+++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp
@@ -75,13 +75,19 @@ int VM_Version::platform_features(int features) {
do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m);
// Extract valid instruction set extensions.
- uint_t av;
- uint_t avn = os::Solaris::getisax(&av, 1);
- assert(avn == 1, "should only return one av");
+ uint_t avs[2];
+ uint_t avn = os::Solaris::getisax(avs, 2);
+ assert(avn <= 2, "should return two or less av's");
+ uint_t av = avs[0];
#ifndef PRODUCT
- if (PrintMiscellaneous && Verbose)
- tty->print_cr("getisax(2) returned: " PTR32_FORMAT, av);
+ if (PrintMiscellaneous && Verbose) {
+ tty->print("getisax(2) returned: " PTR32_FORMAT, av);
+ if (avn > 1) {
+ tty->print(", " PTR32_FORMAT, avs[1]);
+ }
+ tty->cr();
+ }
#endif
if (av & AV_SPARC_MUL32) features |= hardware_mul32_m;
@@ -91,6 +97,13 @@ int VM_Version::platform_features(int features) {
if (av & AV_SPARC_POPC) features |= hardware_popc_m;
if (av & AV_SPARC_VIS) features |= vis1_instructions_m;
if (av & AV_SPARC_VIS2) features |= vis2_instructions_m;
+ if (avn > 1) {
+ uint_t av2 = avs[1];
+#ifndef AV2_SPARC_SPARC5
+#define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */
+#endif
+ if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m;
+ }
// Next values are not defined before Solaris 10
// but Solaris 8 is used for jdk6 update builds.
diff --git a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp
index b87efd7bc..3484b7818 100644
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp
+++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp
@@ -1704,8 +1704,8 @@ CompactibleFreeListSpace::returnChunkToDictionary(FreeChunk* chunk) {
_dictionary->return_chunk(chunk);
#ifndef PRODUCT
if (CMSCollector::abstract_state() != CMSCollector::Sweeping) {
- TreeChunk<FreeChunk, AdaptiveFreeList>* tc = TreeChunk<FreeChunk, AdaptiveFreeList>::as_TreeChunk(chunk);
- TreeList<FreeChunk, AdaptiveFreeList>* tl = tc->list();
+ TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >* tc = TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >::as_TreeChunk(chunk);
+ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* tl = tc->list();
tl->verify_stats();
}
#endif // PRODUCT
@@ -2515,10 +2515,10 @@ void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const {
#ifndef PRODUCT
void CompactibleFreeListSpace::check_free_list_consistency() const {
- assert((TreeChunk<FreeChunk, AdaptiveFreeList>::min_size() <= IndexSetSize),
+ assert((TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >::min_size() <= IndexSetSize),
"Some sizes can't be allocated without recourse to"
" linear allocation buffers");
- assert((TreeChunk<FreeChunk, AdaptiveFreeList>::min_size()*HeapWordSize == sizeof(TreeChunk<FreeChunk, AdaptiveFreeList>)),
+ assert((TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >::min_size()*HeapWordSize == sizeof(TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >)),
"else MIN_TREE_CHUNK_SIZE is wrong");
assert(IndexSetStart != 0, "IndexSetStart not initialized");
assert(IndexSetStride != 0, "IndexSetStride not initialized");
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
index 64b2995af..91d2a1c72 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp
@@ -4539,7 +4539,7 @@ HeapWord* G1CollectedHeap::par_allocate_during_gc(GCAllocPurpose purpose,
G1ParGCAllocBuffer::G1ParGCAllocBuffer(size_t gclab_word_size) :
ParGCAllocBuffer(gclab_word_size), _retired(false) { }
-G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num)
+G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp)
: _g1h(g1h),
_refs(g1h->task_queue(queue_num)),
_dcq(&g1h->dirty_card_queue_set()),
@@ -4549,7 +4549,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num)
_term_attempts(0),
_surviving_alloc_buffer(g1h->desired_plab_sz(GCAllocForSurvived)),
_tenured_alloc_buffer(g1h->desired_plab_sz(GCAllocForTenured)),
- _age_table(false),
+ _age_table(false), _scanner(g1h, this, rp),
_strong_roots_time(0), _term_time(0),
_alloc_buffer_waste(0), _undo_waste(0) {
// we allocate G1YoungSurvRateNumRegions plus one entries, since
@@ -4658,14 +4658,10 @@ void G1ParScanThreadState::trim_queue() {
G1ParClosureSuper::G1ParClosureSuper(G1CollectedHeap* g1,
G1ParScanThreadState* par_scan_state) :
- _g1(g1), _g1_rem(_g1->g1_rem_set()), _cm(_g1->concurrent_mark()),
- _par_scan_state(par_scan_state),
- _worker_id(par_scan_state->queue_num()),
- _during_initial_mark(_g1->g1_policy()->during_initial_mark_pause()),
- _mark_in_progress(_g1->mark_in_progress()) { }
+ _g1(g1), _par_scan_state(par_scan_state),
+ _worker_id(par_scan_state->queue_num()) { }
-template <G1Barrier barrier, bool do_mark_object>
-void G1ParCopyClosure<barrier, do_mark_object>::mark_object(oop obj) {
+void G1ParCopyHelper::mark_object(oop obj) {
#ifdef ASSERT
HeapRegion* hr = _g1->heap_region_containing(obj);
assert(hr != NULL, "sanity");
@@ -4676,9 +4672,7 @@ void G1ParCopyClosure<barrier, do_mark_object>::mark_object(oop obj) {
_cm->grayRoot(obj, (size_t) obj->size(), _worker_id);
}
-template <G1Barrier barrier, bool do_mark_object>
-void G1ParCopyClosure<barrier, do_mark_object>
- ::mark_forwarded_object(oop from_obj, oop to_obj) {
+void G1ParCopyHelper::mark_forwarded_object(oop from_obj, oop to_obj) {
#ifdef ASSERT
assert(from_obj->is_forwarded(), "from obj should be forwarded");
assert(from_obj->forwardee() == to_obj, "to obj should be the forwardee");
@@ -4700,27 +4694,25 @@ void G1ParCopyClosure<barrier, do_mark_object>
_cm->grayRoot(to_obj, (size_t) from_obj->size(), _worker_id);
}
-template <G1Barrier barrier, bool do_mark_object>
-oop G1ParCopyClosure<barrier, do_mark_object>
- ::copy_to_survivor_space(oop old) {
+oop G1ParScanThreadState::copy_to_survivor_space(oop const old) {
size_t word_sz = old->size();
- HeapRegion* from_region = _g1->heap_region_containing_raw(old);
+ HeapRegion* from_region = _g1h->heap_region_containing_raw(old);
// +1 to make the -1 indexes valid...
int young_index = from_region->young_index_in_cset()+1;
assert( (from_region->is_young() && young_index > 0) ||
(!from_region->is_young() && young_index == 0), "invariant" );
- G1CollectorPolicy* g1p = _g1->g1_policy();
+ G1CollectorPolicy* g1p = _g1h->g1_policy();
markOop m = old->mark();
int age = m->has_displaced_mark_helper() ? m->displaced_mark_helper()->age()
: m->age();
GCAllocPurpose alloc_purpose = g1p->evacuation_destination(from_region, age,
word_sz);
- HeapWord* obj_ptr = _par_scan_state->allocate(alloc_purpose, word_sz);
+ HeapWord* obj_ptr = allocate(alloc_purpose, word_sz);
#ifndef PRODUCT
// Should this evacuation fail?
- if (_g1->evacuation_should_fail()) {
+ if (_g1h->evacuation_should_fail()) {
if (obj_ptr != NULL) {
- _par_scan_state->undo_allocation(alloc_purpose, obj_ptr, word_sz);
+ undo_allocation(alloc_purpose, obj_ptr, word_sz);
obj_ptr = NULL;
}
}
@@ -4729,7 +4721,7 @@ oop G1ParCopyClosure<barrier, do_mark_object>
if (obj_ptr == NULL) {
// This will either forward-to-self, or detect that someone else has
// installed a forwarding pointer.
- return _g1->handle_evacuation_failure_par(_par_scan_state, old);
+ return _g1h->handle_evacuation_failure_par(this, old);
}
oop obj = oop(obj_ptr);
@@ -4762,12 +4754,12 @@ oop G1ParCopyClosure<barrier, do_mark_object>
m = m->incr_age();
obj->set_mark(m);
}
- _par_scan_state->age_table()->add(obj, word_sz);
+ age_table()->add(obj, word_sz);
} else {
obj->set_mark(m);
}
- size_t* surv_young_words = _par_scan_state->surviving_young_words();
+ size_t* surv_young_words = surviving_young_words();
surv_young_words[young_index] += word_sz;
if (obj->is_objArray() && arrayOop(obj)->length() >= ParGCArrayScanChunk) {
@@ -4776,15 +4768,15 @@ oop G1ParCopyClosure<barrier, do_mark_object>
// length field of the from-space object.
arrayOop(obj)->set_length(0);
oop* old_p = set_partial_array_mask(old);
- _par_scan_state->push_on_queue(old_p);
+ push_on_queue(old_p);
} else {
// No point in using the slower heap_region_containing() method,
// given that we know obj is in the heap.
- _scanner.set_region(_g1->heap_region_containing_raw(obj));
+ _scanner.set_region(_g1h->heap_region_containing_raw(obj));
obj->oop_iterate_backwards(&_scanner);
}
} else {
- _par_scan_state->undo_allocation(alloc_purpose, obj_ptr, word_sz);
+ undo_allocation(alloc_purpose, obj_ptr, word_sz);
obj = forward_ptr;
}
return obj;
@@ -4799,19 +4791,23 @@ void G1ParCopyHelper::do_klass_barrier(T* p, oop new_obj) {
template <G1Barrier barrier, bool do_mark_object>
template <class T>
-void G1ParCopyClosure<barrier, do_mark_object>
-::do_oop_work(T* p) {
- oop obj = oopDesc::load_decode_heap_oop(p);
+void G1ParCopyClosure<barrier, do_mark_object>::do_oop_work(T* p) {
+ T heap_oop = oopDesc::load_heap_oop(p);
+
+ if (oopDesc::is_null(heap_oop)) {
+ return;
+ }
+
+ oop obj = oopDesc::decode_heap_oop_not_null(heap_oop);
assert(_worker_id == _par_scan_state->queue_num(), "sanity");
- // here the null check is implicit in the cset_fast_test() test
if (_g1->in_cset_fast_test(obj)) {
oop forwardee;
if (obj->is_forwarded()) {
forwardee = obj->forwardee();
} else {
- forwardee = copy_to_survivor_space(obj);
+ forwardee = _par_scan_state->copy_to_survivor_space(obj);
}
assert(forwardee != NULL, "forwardee should not be NULL");
oopDesc::encode_store_heap_oop(p, forwardee);
@@ -4828,12 +4824,12 @@ void G1ParCopyClosure<barrier, do_mark_object>
// The object is not in collection set. If we're a root scanning
// closure during an initial mark pause (i.e. do_mark_object will
// be true) then attempt to mark the object.
- if (do_mark_object && _g1->is_in_g1_reserved(obj)) {
+ if (do_mark_object) {
mark_object(obj);
}
}
- if (barrier == G1BarrierEvac && obj != NULL) {
+ if (barrier == G1BarrierEvac) {
_par_scan_state->update_rs(_from, p, _worker_id);
}
}
@@ -5030,7 +5026,7 @@ public:
ReferenceProcessor* rp = _g1h->ref_processor_stw();
- G1ParScanThreadState pss(_g1h, worker_id);
+ G1ParScanThreadState pss(_g1h, worker_id, rp);
G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, rp);
G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp);
G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, rp);
@@ -5473,7 +5469,7 @@ public:
G1STWIsAliveClosure is_alive(_g1h);
- G1ParScanThreadState pss(_g1h, worker_id);
+ G1ParScanThreadState pss(_g1h, worker_id, NULL);
G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL);
G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL);
@@ -5585,7 +5581,7 @@ public:
ResourceMark rm;
HandleMark hm;
- G1ParScanThreadState pss(_g1h, worker_id);
+ G1ParScanThreadState pss(_g1h, worker_id, NULL);
G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL);
G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL);
G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, NULL);
@@ -5711,7 +5707,7 @@ void G1CollectedHeap::process_discovered_references(uint no_of_gc_workers) {
// JNI refs.
// Use only a single queue for this PSS.
- G1ParScanThreadState pss(this, 0);
+ G1ParScanThreadState pss(this, 0, NULL);
// We do not embed a reference processor in the copying/scanning
// closures while we're actually processing the discovered
diff --git a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
index 3529c60ea..f9a19b5a8 100644
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
+++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp
@@ -606,6 +606,11 @@ protected:
// may not be a humongous - it must fit into a single heap region.
HeapWord* par_allocate_during_gc(GCAllocPurpose purpose, size_t word_size);
+ HeapWord* allocate_during_gc_slow(GCAllocPurpose purpose,
+ HeapRegion* alloc_region,
+ bool par,
+ size_t word_size);
+
// Ensure that no further allocations can happen in "r", bearing in mind
// that parallel threads might be attempting allocations.
void par_allocate_remaining_space(HeapRegion* r);
@@ -698,23 +703,20 @@ public:
}
// This is a fast test on whether a reference points into the
- // collection set or not. It does not assume that the reference
- // points into the heap; if it doesn't, it will return false.
+ // collection set or not. Assume that the reference
+ // points into the heap.
bool in_cset_fast_test(oop obj) {
assert(_in_cset_fast_test != NULL, "sanity");
- if (_g1_committed.contains((HeapWord*) obj)) {
- // no need to subtract the bottom of the heap from obj,
- // _in_cset_fast_test is biased
- uintx index = cast_from_oop<uintx>(obj) >> HeapRegion::LogOfHRGrainBytes;
- bool ret = _in_cset_fast_test[index];
- // let's make sure the result is consistent with what the slower
- // test returns
- assert( ret || !obj_in_cs(obj), "sanity");
- assert(!ret || obj_in_cs(obj), "sanity");
- return ret;
- } else {
- return false;
- }
+ assert(_g1_committed.contains((HeapWord*) obj), err_msg("Given reference outside of heap, is "PTR_FORMAT, (HeapWord*)obj));
+ // no need to subtract the bottom of the heap from obj,
+ // _in_cset_fast_test is biased
+ uintx index = cast_from_oop<uintx>(obj) >> HeapRegion::LogOfHRGrainBytes;
+ bool ret = _in_cset_fast_test[index];
+ // let's make sure the result is consistent with what the slower
+ // test returns
+ assert( ret || !obj_in_cs(obj), "sanity");
+ assert(!ret || obj_in_cs(obj), "sanity");
+ return ret;
}
void clear_cset_fast_test() {
@@ -1786,95 +1788,6 @@ public:
ParGCAllocBuffer::retire(end_of_gc, retain);
_retired = true;
}
-
- bool is_retired() {
- return _retired;
- }
-};
-
-class G1ParGCAllocBufferContainer {
-protected:
- static int const _priority_max = 2;
- G1ParGCAllocBuffer* _priority_buffer[_priority_max];
-
-public:
- G1ParGCAllocBufferContainer(size_t gclab_word_size) {
- for (int pr = 0; pr < _priority_max; ++pr) {
- _priority_buffer[pr] = new G1ParGCAllocBuffer(gclab_word_size);
- }
- }
-
- ~G1ParGCAllocBufferContainer() {
- for (int pr = 0; pr < _priority_max; ++pr) {
- assert(_priority_buffer[pr]->is_retired(), "alloc buffers should all retire at this point.");
- delete _priority_buffer[pr];
- }
- }
-
- HeapWord* allocate(size_t word_sz) {
- HeapWord* obj;
- for (int pr = 0; pr < _priority_max; ++pr) {
- obj = _priority_buffer[pr]->allocate(word_sz);
- if (obj != NULL) return obj;
- }
- return obj;
- }
-
- bool contains(void* addr) {
- for (int pr = 0; pr < _priority_max; ++pr) {
- if (_priority_buffer[pr]->contains(addr)) return true;
- }
- return false;
- }
-
- void undo_allocation(HeapWord* obj, size_t word_sz) {
- bool finish_undo;
- for (int pr = 0; pr < _priority_max; ++pr) {
- if (_priority_buffer[pr]->contains(obj)) {
- _priority_buffer[pr]->undo_allocation(obj, word_sz);
- finish_undo = true;
- }
- }
- if (!finish_undo) ShouldNotReachHere();
- }
-
- size_t words_remaining() {
- size_t result = 0;
- for (int pr = 0; pr < _priority_max; ++pr) {
- result += _priority_buffer[pr]->words_remaining();
- }
- return result;
- }
-
- size_t words_remaining_in_retired_buffer() {
- G1ParGCAllocBuffer* retired = _priority_buffer[0];
- return retired->words_remaining();
- }
-
- void flush_stats_and_retire(PLABStats* stats, bool end_of_gc, bool retain) {
- for (int pr = 0; pr < _priority_max; ++pr) {
- _priority_buffer[pr]->flush_stats_and_retire(stats, end_of_gc, retain);
- }
- }
-
- void update(bool end_of_gc, bool retain, HeapWord* buf, size_t word_sz) {
- G1ParGCAllocBuffer* retired_and_set = _priority_buffer[0];
- retired_and_set->retire(end_of_gc, retain);
- retired_and_set->set_buf(buf);
- retired_and_set->set_word_size(word_sz);
- adjust_priority_order();
- }
-
-private:
- void adjust_priority_order() {
- G1ParGCAllocBuffer* retired_and_set = _priority_buffer[0];
-
- int last = _priority_max - 1;
- for (int pr = 0; pr < last; ++pr) {
- _priority_buffer[pr] = _priority_buffer[pr + 1];
- }
- _priority_buffer[last] = retired_and_set;
- }
};
class G1ParScanThreadState : public StackObj {
@@ -1885,11 +1798,13 @@ protected:
G1SATBCardTableModRefBS* _ct_bs;
G1RemSet* _g1_rem;
- G1ParGCAllocBufferContainer _surviving_alloc_buffer;
- G1ParGCAllocBufferContainer _tenured_alloc_buffer;
- G1ParGCAllocBufferContainer* _alloc_buffers[GCAllocPurposeCount];
+ G1ParGCAllocBuffer _surviving_alloc_buffer;
+ G1ParGCAllocBuffer _tenured_alloc_buffer;
+ G1ParGCAllocBuffer* _alloc_buffers[GCAllocPurposeCount];
ageTable _age_table;
+ G1ParScanClosure _scanner;
+
size_t _alloc_buffer_waste;
size_t _undo_waste;
@@ -1942,7 +1857,7 @@ protected:
}
public:
- G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num);
+ G1ParScanThreadState(G1CollectedHeap* g1h, uint queue_num, ReferenceProcessor* rp);
~G1ParScanThreadState() {
FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base, mtGC);
@@ -1951,7 +1866,7 @@ public:
RefToScanQueue* refs() { return _refs; }
ageTable* age_table() { return &_age_table; }
- G1ParGCAllocBufferContainer* alloc_buffer(GCAllocPurpose purpose) {
+ G1ParGCAllocBuffer* alloc_buffer(GCAllocPurpose purpose) {
return _alloc_buffers[purpose];
}
@@ -1981,13 +1896,15 @@ public:
HeapWord* obj = NULL;
size_t gclab_word_size = _g1h->desired_plab_sz(purpose);
if (word_sz * 100 < gclab_word_size * ParallelGCBufferWastePct) {
- G1ParGCAllocBufferContainer* alloc_buf = alloc_buffer(purpose);
+ G1ParGCAllocBuffer* alloc_buf = alloc_buffer(purpose);
+ add_to_alloc_buffer_waste(alloc_buf->words_remaining());
+ alloc_buf->retire(false /* end_of_gc */, false /* retain */);
HeapWord* buf = _g1h->par_allocate_during_gc(purpose, gclab_word_size);
if (buf == NULL) return NULL; // Let caller handle allocation failure.
-
- add_to_alloc_buffer_waste(alloc_buf->words_remaining_in_retired_buffer());
- alloc_buf->update(false /* end_of_gc */, false /* retain */, buf, gclab_word_size);
+ // Otherwise.
+ alloc_buf->set_word_size(gclab_word_size);
+ alloc_buf->set_buf(buf);
obj = alloc_buf->allocate(word_sz);
assert(obj != NULL, "buffer was definitely big enough...");
@@ -2077,6 +1994,8 @@ public:
}
}
+ oop copy_to_survivor_space(oop const obj);
+
template <class T> void deal_with_reference(T* ref_to_scan) {
if (has_partial_array_mask(ref_to_scan)) {
_partial_scan_cl->do_oop_nv(ref_to_scan);
@@ -2099,6 +2018,7 @@ public:
}
}
+public:
void trim_queue();
};
diff --git a/src/share/vm/gc_implementation/g1/g1OopClosures.cpp b/src/share/vm/gc_implementation/g1/g1OopClosures.cpp
new file mode 100644
index 000000000..a30b00416
--- /dev/null
+++ b/src/share/vm/gc_implementation/g1/g1OopClosures.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
+#include "gc_implementation/g1/g1OopClosures.inline.hpp"
+
+G1ParCopyHelper::G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
+ G1ParClosureSuper(g1, par_scan_state), _scanned_klass(NULL),
+ _cm(_g1->concurrent_mark()) {}
diff --git a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp
index bda11dc6b..5eb5691c9 100644
--- a/src/share/vm/gc_implementation/g1/g1OopClosures.hpp
+++ b/src/share/vm/gc_implementation/g1/g1OopClosures.hpp
@@ -48,12 +48,8 @@ public:
class G1ParClosureSuper : public OopsInHeapRegionClosure {
protected:
G1CollectedHeap* _g1;
- G1RemSet* _g1_rem;
- ConcurrentMark* _cm;
G1ParScanThreadState* _par_scan_state;
uint _worker_id;
- bool _during_initial_mark;
- bool _mark_in_progress;
public:
G1ParClosureSuper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state);
bool apply_to_weak_ref_discovered_field() { return true; }
@@ -133,23 +129,10 @@ public:
// Add back base class for metadata
class G1ParCopyHelper : public G1ParClosureSuper {
+protected:
Klass* _scanned_klass;
+ ConcurrentMark* _cm;
- public:
- G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state) :
- _scanned_klass(NULL),
- G1ParClosureSuper(g1, par_scan_state) {}
-
- void set_scanned_klass(Klass* k) { _scanned_klass = k; }
- template <class T> void do_klass_barrier(T* p, oop new_obj);
-};
-
-template <G1Barrier barrier, bool do_mark_object>
-class G1ParCopyClosure : public G1ParCopyHelper {
- G1ParScanClosure _scanner;
- template <class T> void do_oop_work(T* p);
-
-protected:
// Mark the object if it's not already marked. This is used to mark
// objects pointed to by roots that are guaranteed not to move
// during the GC (i.e., non-CSet objects). It is MT-safe.
@@ -159,22 +142,26 @@ protected:
// objects pointed to by roots that have been forwarded during a
// GC. It is MT-safe.
void mark_forwarded_object(oop from_obj, oop to_obj);
+ public:
+ G1ParCopyHelper(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state);
- oop copy_to_survivor_space(oop obj);
+ void set_scanned_klass(Klass* k) { _scanned_klass = k; }
+ template <class T> void do_klass_barrier(T* p, oop new_obj);
+};
+
+template <G1Barrier barrier, bool do_mark_object>
+class G1ParCopyClosure : public G1ParCopyHelper {
+private:
+ template <class T> void do_oop_work(T* p);
public:
G1ParCopyClosure(G1CollectedHeap* g1, G1ParScanThreadState* par_scan_state,
ReferenceProcessor* rp) :
- _scanner(g1, par_scan_state, rp),
G1ParCopyHelper(g1, par_scan_state) {
assert(_ref_processor == NULL, "sanity");
}
- G1ParScanClosure* scanner() { return &_scanner; }
-
- template <class T> void do_oop_nv(T* p) {
- do_oop_work(p);
- }
+ template <class T> void do_oop_nv(T* p) { do_oop_work(p); }
virtual void do_oop(oop* p) { do_oop_nv(p); }
virtual void do_oop(narrowOop* p) { do_oop_nv(p); }
};
diff --git a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp
index e26d2a695..9374d23a2 100644
--- a/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp
+++ b/src/share/vm/gc_implementation/g1/g1OopClosures.inline.hpp
@@ -82,7 +82,7 @@ inline void G1ParScanClosure::do_oop_nv(T* p) {
_par_scan_state->push_on_queue(p);
} else {
- _par_scan_state->update_rs(_from, p, _par_scan_state->queue_num());
+ _par_scan_state->update_rs(_from, p, _worker_id);
}
}
}
diff --git a/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp b/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp
index 80a4a223c..1f76ad3e5 100644
--- a/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp
+++ b/src/share/vm/gc_implementation/shared/parGCAllocBuffer.hpp
@@ -158,7 +158,7 @@ public:
// Fills in the unallocated portion of the buffer with a garbage object.
// If "end_of_gc" is TRUE, is after the last use in the GC. IF "retain"
// is true, attempt to re-use the unused portion in the next GC.
- virtual void retire(bool end_of_gc, bool retain);
+ void retire(bool end_of_gc, bool retain);
void print() PRODUCT_RETURN;
};
diff --git a/src/share/vm/memory/binaryTreeDictionary.cpp b/src/share/vm/memory/binaryTreeDictionary.cpp
index 30b038299..0ad161ab1 100644
--- a/src/share/vm/memory/binaryTreeDictionary.cpp
+++ b/src/share/vm/memory/binaryTreeDictionary.cpp
@@ -44,16 +44,16 @@
// This is currently used in the Concurrent Mark&Sweep implementation.
////////////////////////////////////////////////////////////////////////////////
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t TreeChunk<Chunk_t, FreeList_t>::_min_tree_chunk_size = sizeof(TreeChunk<Chunk_t, FreeList_t>)/HeapWordSize;
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeChunk<Chunk_t, FreeList_t>* TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(Chunk_t* fc) {
// Do some assertion checking here.
return (TreeChunk<Chunk_t, FreeList_t>*) fc;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
TreeChunk<Chunk_t, FreeList_t>* nextTC = (TreeChunk<Chunk_t, FreeList_t>*)next();
if (prev() != NULL) { // interior list node shouldn'r have tree fields
@@ -67,11 +67,11 @@ void TreeChunk<Chunk_t, FreeList_t>::verify_tree_chunk_list() const {
}
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeList<Chunk_t, FreeList_t>::TreeList() : _parent(NULL),
_left(NULL), _right(NULL) {}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeList<Chunk_t, FreeList_t>*
TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
// This first free chunk in the list will be the tree list.
@@ -88,20 +88,7 @@ TreeList<Chunk_t, FreeList_t>::as_TreeList(TreeChunk<Chunk_t,FreeList_t>* tc) {
return tl;
}
-
-template <class Chunk_t, template <class> class FreeList_t>
-TreeList<Chunk_t, FreeList_t>*
-get_chunk(size_t size, enum FreeBlockDictionary<Chunk_t>::Dither dither) {
- FreeBlockDictionary<Chunk_t>::verify_par_locked();
- Chunk_t* res = get_chunk_from_tree(size, dither);
- assert(res == NULL || res->is_free(),
- "Should be returning a free chunk");
- assert(dither != FreeBlockDictionary<Chunk_t>::exactly ||
- res->size() == size, "Not correct size");
- return res;
-}
-
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeList<Chunk_t, FreeList_t>*
TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
TreeChunk<Chunk_t, FreeList_t>* tc = (TreeChunk<Chunk_t, FreeList_t>*) addr;
@@ -125,17 +112,17 @@ TreeList<Chunk_t, FreeList_t>::as_TreeList(HeapWord* addr, size_t size) {
// an over populated size. The general get_better_list() just returns
// the current list.
template <>
-TreeList<FreeChunk, AdaptiveFreeList>*
-TreeList<FreeChunk, AdaptiveFreeList>::get_better_list(
- BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList>* dictionary) {
+TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >*
+TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >::get_better_list(
+ BinaryTreeDictionary<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* dictionary) {
// A candidate chunk has been found. If it is already under
// populated, get a chunk associated with the hint for this
// chunk.
- TreeList<FreeChunk, ::AdaptiveFreeList>* curTL = this;
+ TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* curTL = this;
if (surplus() <= 0) {
/* Use the hint to find a size with a surplus, and reset the hint. */
- TreeList<FreeChunk, ::AdaptiveFreeList>* hintTL = this;
+ TreeList<FreeChunk, ::AdaptiveFreeList<FreeChunk> >* hintTL = this;
while (hintTL->hint() != 0) {
assert(hintTL->hint() > hintTL->size(),
"hint points in the wrong direction");
@@ -163,14 +150,14 @@ TreeList<FreeChunk, AdaptiveFreeList>::get_better_list(
}
#endif // INCLUDE_ALL_GCS
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeList<Chunk_t, FreeList_t>*
TreeList<Chunk_t, FreeList_t>::get_better_list(
BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary) {
return this;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc) {
TreeList<Chunk_t, FreeList_t>* retTL = this;
@@ -286,7 +273,7 @@ TreeList<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::remove_chunk_repla
return retTL;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* chunk) {
assert(chunk != NULL, "returning NULL chunk");
assert(chunk->list() == this, "list should be set for chunk");
@@ -301,7 +288,7 @@ void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, Free
this->link_tail(chunk);
assert(!tail() || size() == tail()->size(), "Wrong sized chunk in list");
- FreeList_t<Chunk_t>::increment_count();
+ FreeList_t::increment_count();
debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
assert(head() == NULL || head()->prev() == NULL, "list invariant");
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
@@ -311,7 +298,7 @@ void TreeList<Chunk_t, FreeList_t>::return_chunk_at_tail(TreeChunk<Chunk_t, Free
// is defined to be after the chunk pointer to by head(). This is
// because the TreeList<Chunk_t, FreeList_t> is embedded in the first TreeChunk<Chunk_t, FreeList_t> in the
// list. See the definition of TreeChunk<Chunk_t, FreeList_t>.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void TreeList<Chunk_t, FreeList_t>::return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* chunk) {
assert(chunk->list() == this, "list should be set for chunk");
assert(head() != NULL, "The tree list is embedded in the first chunk");
@@ -329,13 +316,13 @@ void TreeList<Chunk_t, FreeList_t>::return_chunk_at_head(TreeChunk<Chunk_t, Free
}
head()->link_after(chunk);
assert(!head() || size() == head()->size(), "Wrong sized chunk in list");
- FreeList_t<Chunk_t>::increment_count();
+ FreeList_t::increment_count();
debug_only(this->increment_returned_bytes_by(chunk->size()*sizeof(HeapWord));)
assert(head() == NULL || head()->prev() == NULL, "list invariant");
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void TreeChunk<Chunk_t, FreeList_t>::assert_is_mangled() const {
assert((ZapUnusedHeapArea &&
SpaceMangler::is_mangled((HeapWord*) Chunk_t::size_addr()) &&
@@ -345,14 +332,14 @@ void TreeChunk<Chunk_t, FreeList_t>::assert_is_mangled() const {
"Space should be clear or mangled");
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::head_as_TreeChunk() {
assert(head() == NULL || (TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head())->list() == this),
"Wrong type of chunk?");
return TreeChunk<Chunk_t, FreeList_t>::as_TreeChunk(head());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::first_available() {
assert(head() != NULL, "The head of the list cannot be NULL");
Chunk_t* fc = head()->next();
@@ -369,7 +356,7 @@ TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::first_available()
// Returns the block with the largest heap address amongst
// those in the list for this size; potentially slow and expensive,
// use with caution!
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::largest_address() {
assert(head() != NULL, "The head of the list cannot be NULL");
Chunk_t* fc = head()->next();
@@ -392,7 +379,7 @@ TreeChunk<Chunk_t, FreeList_t>* TreeList<Chunk_t, FreeList_t>::largest_address()
return retTC;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
BinaryTreeDictionary<Chunk_t, FreeList_t>::BinaryTreeDictionary(MemRegion mr) {
assert((mr.byte_size() > min_size()), "minimum chunk size");
@@ -405,17 +392,17 @@ BinaryTreeDictionary<Chunk_t, FreeList_t>::BinaryTreeDictionary(MemRegion mr) {
assert(total_free_blocks() == 1, "reset check failed");
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::inc_total_size(size_t inc) {
_total_size = _total_size + inc;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::dec_total_size(size_t dec) {
_total_size = _total_size - dec;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(MemRegion mr) {
assert((mr.byte_size() > min_size()), "minimum chunk size");
set_root(TreeList<Chunk_t, FreeList_t>::as_TreeList(mr.start(), mr.word_size()));
@@ -423,13 +410,13 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(MemRegion mr) {
set_total_free_blocks(1);
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset(HeapWord* addr, size_t byte_size) {
MemRegion mr(addr, heap_word_size(byte_size));
reset(mr);
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset() {
set_root(NULL);
set_total_size(0);
@@ -437,7 +424,7 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::reset() {
}
// Get a free block of size at least size from tree, or NULL.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeChunk<Chunk_t, FreeList_t>*
BinaryTreeDictionary<Chunk_t, FreeList_t>::get_chunk_from_tree(
size_t size,
@@ -496,7 +483,7 @@ BinaryTreeDictionary<Chunk_t, FreeList_t>::get_chunk_from_tree(
return retTC;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_list(size_t size) const {
TreeList<Chunk_t, FreeList_t>* curTL;
for (curTL = root(); curTL != NULL;) {
@@ -515,7 +502,7 @@ TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_l
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
bool BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_chunk_in_free_list(Chunk_t* tc) const {
size_t size = tc->size();
TreeList<Chunk_t, FreeList_t>* tl = find_list(size);
@@ -526,7 +513,7 @@ bool BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_chunk_in_free_list(Chunk_
}
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_largest_dict() const {
TreeList<Chunk_t, FreeList_t> *curTL = root();
if (curTL != NULL) {
@@ -541,7 +528,7 @@ Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_largest_dict() const {
// chunk in a list on a tree node, just unlink it.
// If it is the last chunk in the list (the next link is NULL),
// remove the node and repair the tree.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeChunk<Chunk_t, FreeList_t>*
BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc) {
assert(tc != NULL, "Should not call with a NULL chunk");
@@ -682,7 +669,7 @@ BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_chunk_from_tree(TreeChunk<Chun
// Remove the leftmost node (lm) in the tree and return it.
// If lm has a right child, link it to the left node of
// the parent of lm.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl) {
assert(tl != NULL && tl->parent() != NULL, "really need a proper sub-tree");
// locate the subtree minimum by walking down left branches
@@ -717,7 +704,7 @@ TreeList<Chunk_t, FreeList_t>* BinaryTreeDictionary<Chunk_t, FreeList_t>::remove
return curTL;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::insert_chunk_in_tree(Chunk_t* fc) {
TreeList<Chunk_t, FreeList_t> *curTL, *prevTL;
size_t size = fc->size();
@@ -783,7 +770,7 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::insert_chunk_in_tree(Chunk_t* fc
}
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::max_chunk_size() const {
FreeBlockDictionary<Chunk_t>::verify_par_locked();
TreeList<Chunk_t, FreeList_t>* tc = root();
@@ -792,7 +779,7 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::max_chunk_size() const {
return tc->size();
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const {
size_t res;
res = tl->count();
@@ -805,7 +792,7 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_list_length(TreeList<Chu
return res;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
if (tl == NULL)
return 0;
@@ -814,7 +801,7 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_size_in_tree(TreeList<Ch
total_size_in_tree(tl->right());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
double BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const {
if (tl == NULL) {
return 0.0;
@@ -826,7 +813,7 @@ double BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_of_squared_block_sizes(Tre
return curr;
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
if (tl == NULL)
return 0;
@@ -835,14 +822,14 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_free_blocks_in_tree(Tree
total_free_blocks_in_tree(tl->right());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::num_free_blocks() const {
assert(total_free_blocks_in_tree(root()) == total_free_blocks(),
"_total_free_blocks inconsistency");
return total_free_blocks();
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
if (tl == NULL)
return 0;
@@ -850,12 +837,12 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height_helper(TreeList<Ch
tree_height_helper(tl->right()));
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::tree_height() const {
return tree_height_helper(root());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
if (tl == NULL) {
return 0;
@@ -864,18 +851,18 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_helper(TreeList<Ch
total_nodes_helper(tl->right());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const {
return total_nodes_helper(root());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::dict_census_update(size_t size, bool split, bool birth){}
#if INCLUDE_ALL_GCS
template <>
-void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth){
- TreeList<FreeChunk, AdaptiveFreeList>* nd = find_list(size);
+void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool birth) {
+ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* nd = find_list(size);
if (nd) {
if (split) {
if (birth) {
@@ -903,7 +890,7 @@ void AFLBinaryTreeDictionary::dict_census_update(size_t size, bool split, bool b
}
#endif // INCLUDE_ALL_GCS
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
bool BinaryTreeDictionary<Chunk_t, FreeList_t>::coal_dict_over_populated(size_t size) {
// For the general type of freelists, encourage coalescing by
// returning true.
@@ -915,7 +902,7 @@ template <>
bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
if (FLSAlwaysCoalesceLarge) return true;
- TreeList<FreeChunk, AdaptiveFreeList>* list_of_size = find_list(size);
+ TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >* list_of_size = find_list(size);
// None of requested size implies overpopulated.
return list_of_size == NULL || list_of_size->coal_desired() <= 0 ||
list_of_size->count() > list_of_size->coal_desired();
@@ -928,15 +915,15 @@ bool AFLBinaryTreeDictionary::coal_dict_over_populated(size_t size) {
// do_tree() walks the nodes in the binary tree applying do_list()
// to each list at each node.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class TreeCensusClosure : public StackObj {
protected:
- virtual void do_list(FreeList_t<Chunk_t>* fl) = 0;
+ virtual void do_list(FreeList_t* fl) = 0;
public:
virtual void do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
public:
void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
@@ -948,7 +935,7 @@ class AscendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
}
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
public:
void do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
@@ -962,7 +949,7 @@ class DescendTreeCensusClosure : public TreeCensusClosure<Chunk_t, FreeList_t> {
// For each list in the tree, calculate the desired, desired
// coalesce, count before sweep, and surplus before sweep.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class BeginSweepClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
double _percentage;
float _inter_sweep_current;
@@ -995,16 +982,16 @@ class BeginSweepClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
// Similar to TreeCensusClosure but searches the
// tree and returns promptly when found.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class TreeSearchClosure : public StackObj {
protected:
- virtual bool do_list(FreeList_t<Chunk_t>* fl) = 0;
+ virtual bool do_list(FreeList_t* fl) = 0;
public:
virtual bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) = 0;
};
#if 0 // Don't need this yet but here for symmetry.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
public:
bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
@@ -1018,7 +1005,7 @@ class AscendTreeSearchClosure : public TreeSearchClosure<Chunk_t> {
};
#endif
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
public:
bool do_tree(TreeList<Chunk_t, FreeList_t>* tl) {
@@ -1033,14 +1020,14 @@ class DescendTreeSearchClosure : public TreeSearchClosure<Chunk_t, FreeList_t> {
// Searches the tree for a chunk that ends at the
// specified address.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class EndTreeSearchClosure : public DescendTreeSearchClosure<Chunk_t, FreeList_t> {
HeapWord* _target;
Chunk_t* _found;
public:
EndTreeSearchClosure(HeapWord* target) : _target(target), _found(NULL) {}
- bool do_list(FreeList_t<Chunk_t>* fl) {
+ bool do_list(FreeList_t* fl) {
Chunk_t* item = fl->head();
while (item != NULL) {
if (item->end() == (uintptr_t*) _target) {
@@ -1054,7 +1041,7 @@ class EndTreeSearchClosure : public DescendTreeSearchClosure<Chunk_t, FreeList_t
Chunk_t* found() { return _found; }
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord* target) const {
EndTreeSearchClosure<Chunk_t, FreeList_t> etsc(target);
bool found_target = etsc.do_tree(root());
@@ -1063,7 +1050,7 @@ Chunk_t* BinaryTreeDictionary<Chunk_t, FreeList_t>::find_chunk_ends_at(HeapWord*
return etsc.found();
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::begin_sweep_dict_census(double coalSurplusPercent,
float inter_sweep_current, float inter_sweep_estimate, float intra_sweep_estimate) {
BeginSweepClosure<Chunk_t, FreeList_t> bsc(coalSurplusPercent, inter_sweep_current,
@@ -1075,32 +1062,32 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::begin_sweep_dict_census(double c
// Closures and methods for calculating total bytes returned to the
// free lists in the tree.
#ifndef PRODUCT
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class InitializeDictReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
public:
- void do_list(FreeList_t<Chunk_t>* fl) {
+ void do_list(FreeList_t* fl) {
fl->set_returned_bytes(0);
}
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::initialize_dict_returned_bytes() {
InitializeDictReturnedBytesClosure<Chunk_t, FreeList_t> idrb;
idrb.do_tree(root());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class ReturnedBytesClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
size_t _dict_returned_bytes;
public:
ReturnedBytesClosure() { _dict_returned_bytes = 0; }
- void do_list(FreeList_t<Chunk_t>* fl) {
+ void do_list(FreeList_t* fl) {
_dict_returned_bytes += fl->returned_bytes();
}
size_t dict_returned_bytes() { return _dict_returned_bytes; }
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_dict_returned_bytes() {
ReturnedBytesClosure<Chunk_t, FreeList_t> rbc;
rbc.do_tree(root());
@@ -1109,17 +1096,17 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::sum_dict_returned_bytes() {
}
// Count the number of entries in the tree.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class treeCountClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
public:
uint count;
treeCountClosure(uint c) { count = c; }
- void do_list(FreeList_t<Chunk_t>* fl) {
+ void do_list(FreeList_t* fl) {
count++;
}
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_count() {
treeCountClosure<Chunk_t, FreeList_t> ctc(0);
ctc.do_tree(root());
@@ -1128,7 +1115,7 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::total_count() {
#endif // PRODUCT
// Calculate surpluses for the lists in the tree.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class setTreeSurplusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
double percentage;
public:
@@ -1144,14 +1131,14 @@ class setTreeSurplusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t
#endif // INCLUDE_ALL_GCS
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_surplus(double splitSurplusPercent) {
setTreeSurplusClosure<Chunk_t, FreeList_t> sts(splitSurplusPercent);
sts.do_tree(root());
}
// Set hints for the lists in the tree.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class setTreeHintsClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t> {
size_t hint;
public:
@@ -1170,14 +1157,14 @@ class setTreeHintsClosure : public DescendTreeCensusClosure<Chunk_t, FreeList_t>
#endif // INCLUDE_ALL_GCS
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::set_tree_hints(void) {
setTreeHintsClosure<Chunk_t, FreeList_t> sth(0);
sth.do_tree(root());
}
// Save count before previous sweep and splits and coalesces.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class clearTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
void do_list(FreeList<Chunk_t>* fl) {}
@@ -1192,14 +1179,14 @@ class clearTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_
#endif // INCLUDE_ALL_GCS
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::clear_tree_census(void) {
clearTreeCensusClosure<Chunk_t, FreeList_t> ctc;
ctc.do_tree(root());
}
// Do reporting and post sweep clean up.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::end_sweep_dict_census(double splitSurplusPercent) {
// Does walking the tree 3 times hurt?
set_tree_surplus(splitSurplusPercent);
@@ -1211,7 +1198,7 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::end_sweep_dict_census(double spl
}
// Print summary statistics
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics() const {
FreeBlockDictionary<Chunk_t>::verify_par_locked();
gclog_or_tty->print("Statistics for BinaryTreeDictionary:\n"
@@ -1230,22 +1217,22 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::report_statistics() const {
// Print census information - counts, births, deaths, etc.
// for each list in the tree. Also print some summary
// information.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class PrintTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
int _print_line;
size_t _total_free;
- FreeList_t<Chunk_t> _total;
+ FreeList_t _total;
public:
PrintTreeCensusClosure() {
_print_line = 0;
_total_free = 0;
}
- FreeList_t<Chunk_t>* total() { return &_total; }
+ FreeList_t* total() { return &_total; }
size_t total_free() { return _total_free; }
void do_list(FreeList<Chunk_t>* fl) {
if (++_print_line >= 40) {
- FreeList_t<Chunk_t>::print_labels_on(gclog_or_tty, "size");
+ FreeList_t::print_labels_on(gclog_or_tty, "size");
_print_line = 0;
}
fl->print_on(gclog_or_tty);
@@ -1256,7 +1243,7 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_
#if INCLUDE_ALL_GCS
void do_list(AdaptiveFreeList<Chunk_t>* fl) {
if (++_print_line >= 40) {
- FreeList_t<Chunk_t>::print_labels_on(gclog_or_tty, "size");
+ FreeList_t::print_labels_on(gclog_or_tty, "size");
_print_line = 0;
}
fl->print_on(gclog_or_tty);
@@ -1275,16 +1262,16 @@ class PrintTreeCensusClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_
#endif // INCLUDE_ALL_GCS
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_dict_census(void) const {
gclog_or_tty->print("\nBinaryTree\n");
- FreeList_t<Chunk_t>::print_labels_on(gclog_or_tty, "size");
+ FreeList_t::print_labels_on(gclog_or_tty, "size");
PrintTreeCensusClosure<Chunk_t, FreeList_t> ptc;
ptc.do_tree(root());
- FreeList_t<Chunk_t>* total = ptc.total();
- FreeList_t<Chunk_t>::print_labels_on(gclog_or_tty, " ");
+ FreeList_t* total = ptc.total();
+ FreeList_t::print_labels_on(gclog_or_tty, " ");
}
#if INCLUDE_ALL_GCS
@@ -1293,7 +1280,7 @@ void AFLBinaryTreeDictionary::print_dict_census(void) const {
gclog_or_tty->print("\nBinaryTree\n");
AdaptiveFreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
- PrintTreeCensusClosure<FreeChunk, AdaptiveFreeList> ptc;
+ PrintTreeCensusClosure<FreeChunk, AdaptiveFreeList<FreeChunk> > ptc;
ptc.do_tree(root());
AdaptiveFreeList<FreeChunk>* total = ptc.total();
@@ -1311,7 +1298,7 @@ void AFLBinaryTreeDictionary::print_dict_census(void) const {
}
#endif // INCLUDE_ALL_GCS
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t> {
outputStream* _st;
int _print_line;
@@ -1321,9 +1308,9 @@ class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t
_st = st;
_print_line = 0;
}
- void do_list(FreeList_t<Chunk_t>* fl) {
+ void do_list(FreeList_t* fl) {
if (++_print_line >= 40) {
- FreeList_t<Chunk_t>::print_labels_on(_st, "size");
+ FreeList_t::print_labels_on(_st, "size");
_print_line = 0;
}
fl->print_on(gclog_or_tty);
@@ -1337,10 +1324,10 @@ class PrintFreeListsClosure : public AscendTreeCensusClosure<Chunk_t, FreeList_t
}
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_free_lists(outputStream* st) const {
- FreeList_t<Chunk_t>::print_labels_on(st, "size");
+ FreeList_t::print_labels_on(st, "size");
PrintFreeListsClosure<Chunk_t, FreeList_t> pflc(st);
pflc.do_tree(root());
}
@@ -1349,7 +1336,7 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::print_free_lists(outputStream* s
// . _root has no parent
// . parent and child point to each other
// . each node's key correctly related to that of its child(ren)
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree() const {
guarantee(root() == NULL || total_free_blocks() == 0 ||
total_size() != 0, "_total_size should't be 0?");
@@ -1357,7 +1344,7 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree() const {
verify_tree_helper(root());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl) {
size_t ct = 0;
for (Chunk_t* curFC = tl->head(); curFC != NULL; curFC = curFC->next()) {
@@ -1371,7 +1358,7 @@ size_t BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_prev_free_ptrs(TreeList
// Note: this helper is recursive rather than iterative, so use with
// caution on very deep trees; and watch out for stack overflow errors;
// In general, to be used only for debugging.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const {
if (tl == NULL)
return;
@@ -1400,25 +1387,25 @@ void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify_tree_helper(TreeList<Chun
verify_tree_helper(tl->right());
}
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
void BinaryTreeDictionary<Chunk_t, FreeList_t>::verify() const {
verify_tree();
guarantee(total_size() == total_size_in_tree(root()), "Total Size inconsistency");
}
-template class TreeList<Metablock, FreeList>;
-template class BinaryTreeDictionary<Metablock, FreeList>;
-template class TreeChunk<Metablock, FreeList>;
+template class TreeList<Metablock, FreeList<Metablock> >;
+template class BinaryTreeDictionary<Metablock, FreeList<Metablock> >;
+template class TreeChunk<Metablock, FreeList<Metablock> >;
-template class TreeList<Metachunk, FreeList>;
-template class BinaryTreeDictionary<Metachunk, FreeList>;
-template class TreeChunk<Metachunk, FreeList>;
+template class TreeList<Metachunk, FreeList<Metachunk> >;
+template class BinaryTreeDictionary<Metachunk, FreeList<Metachunk> >;
+template class TreeChunk<Metachunk, FreeList<Metachunk> >;
#if INCLUDE_ALL_GCS
// Explicitly instantiate these types for FreeChunk.
-template class TreeList<FreeChunk, AdaptiveFreeList>;
-template class BinaryTreeDictionary<FreeChunk, AdaptiveFreeList>;
-template class TreeChunk<FreeChunk, AdaptiveFreeList>;
+template class TreeList<FreeChunk, AdaptiveFreeList<FreeChunk> >;
+template class BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> >;
+template class TreeChunk<FreeChunk, AdaptiveFreeList<FreeChunk> >;
#endif // INCLUDE_ALL_GCS
diff --git a/src/share/vm/memory/binaryTreeDictionary.hpp b/src/share/vm/memory/binaryTreeDictionary.hpp
index 23d7fe0ae..95696cfb3 100644
--- a/src/share/vm/memory/binaryTreeDictionary.hpp
+++ b/src/share/vm/memory/binaryTreeDictionary.hpp
@@ -37,18 +37,18 @@
// A TreeList is a FreeList which can be used to maintain a
// binary tree of free lists.
-template <class Chunk_t, template <class> class FreeList_t> class TreeChunk;
-template <class Chunk_t, template <class> class FreeList_t> class BinaryTreeDictionary;
-template <class Chunk_t, template <class> class FreeList_t> class AscendTreeCensusClosure;
-template <class Chunk_t, template <class> class FreeList_t> class DescendTreeCensusClosure;
-template <class Chunk_t, template <class> class FreeList_t> class DescendTreeSearchClosure;
+template <class Chunk_t, class FreeList_t> class TreeChunk;
+template <class Chunk_t, class FreeList_t> class BinaryTreeDictionary;
+template <class Chunk_t, class FreeList_t> class AscendTreeCensusClosure;
+template <class Chunk_t, class FreeList_t> class DescendTreeCensusClosure;
+template <class Chunk_t, class FreeList_t> class DescendTreeSearchClosure;
class FreeChunk;
template <class> class AdaptiveFreeList;
-typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList> AFLBinaryTreeDictionary;
+typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList<FreeChunk> > AFLBinaryTreeDictionary;
-template <class Chunk_t, template <class> class FreeList_t>
-class TreeList : public FreeList_t<Chunk_t> {
+template <class Chunk_t, class FreeList_t>
+class TreeList : public FreeList_t {
friend class TreeChunk<Chunk_t, FreeList_t>;
friend class BinaryTreeDictionary<Chunk_t, FreeList_t>;
friend class AscendTreeCensusClosure<Chunk_t, FreeList_t>;
@@ -66,12 +66,12 @@ class TreeList : public FreeList_t<Chunk_t> {
TreeList<Chunk_t, FreeList_t>* right() const { return _right; }
// Wrapper on call to base class, to get the template to compile.
- Chunk_t* head() const { return FreeList_t<Chunk_t>::head(); }
- Chunk_t* tail() const { return FreeList_t<Chunk_t>::tail(); }
- void set_head(Chunk_t* head) { FreeList_t<Chunk_t>::set_head(head); }
- void set_tail(Chunk_t* tail) { FreeList_t<Chunk_t>::set_tail(tail); }
+ Chunk_t* head() const { return FreeList_t::head(); }
+ Chunk_t* tail() const { return FreeList_t::tail(); }
+ void set_head(Chunk_t* head) { FreeList_t::set_head(head); }
+ void set_tail(Chunk_t* tail) { FreeList_t::set_tail(tail); }
- size_t size() const { return FreeList_t<Chunk_t>::size(); }
+ size_t size() const { return FreeList_t::size(); }
// Accessors for links in tree.
@@ -90,7 +90,7 @@ class TreeList : public FreeList_t<Chunk_t> {
void clear_left() { _left = NULL; }
void clear_right() { _right = NULL; }
void clear_parent() { _parent = NULL; }
- void initialize() { clear_left(); clear_right(), clear_parent(); FreeList_t<Chunk_t>::initialize(); }
+ void initialize() { clear_left(); clear_right(), clear_parent(); FreeList_t::initialize(); }
// For constructing a TreeList from a Tree chunk or
// address and size.
@@ -139,7 +139,7 @@ class TreeList : public FreeList_t<Chunk_t> {
// on the free list for a node in the tree and is only removed if
// it is the last chunk on the free list.
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class TreeChunk : public Chunk_t {
friend class TreeList<Chunk_t, FreeList_t>;
TreeList<Chunk_t, FreeList_t>* _list;
@@ -173,7 +173,7 @@ class TreeChunk : public Chunk_t {
};
-template <class Chunk_t, template <class> class FreeList_t>
+template <class Chunk_t, class FreeList_t>
class BinaryTreeDictionary: public FreeBlockDictionary<Chunk_t> {
friend class VMStructs;
size_t _total_size;
diff --git a/src/share/vm/memory/metaspace.cpp b/src/share/vm/memory/metaspace.cpp
index 5a7e4ec2f..d780cc5ce 100644
--- a/src/share/vm/memory/metaspace.cpp
+++ b/src/share/vm/memory/metaspace.cpp
@@ -46,8 +46,8 @@
#include "utilities/copy.hpp"
#include "utilities/debug.hpp"
-typedef BinaryTreeDictionary<Metablock, FreeList> BlockTreeDictionary;
-typedef BinaryTreeDictionary<Metachunk, FreeList> ChunkTreeDictionary;
+typedef BinaryTreeDictionary<Metablock, FreeList<Metablock> > BlockTreeDictionary;
+typedef BinaryTreeDictionary<Metachunk, FreeList<Metachunk> > ChunkTreeDictionary;
// Set this constant to enable slow integrity checking of the free chunk lists
const bool metaspace_slow_verify = false;
@@ -790,7 +790,7 @@ MetaWord* BlockFreelist::get_block(size_t word_size) {
return NULL;
}
- if (word_size < TreeChunk<Metablock, FreeList>::min_size()) {
+ if (word_size < TreeChunk<Metablock, FreeList<Metablock> >::min_size()) {
// Dark matter. Too small for dictionary.
return NULL;
}
@@ -810,7 +810,7 @@ MetaWord* BlockFreelist::get_block(size_t word_size) {
MetaWord* new_block = (MetaWord*)free_block;
assert(block_size >= word_size, "Incorrect size of block from freelist");
const size_t unused = block_size - word_size;
- if (unused >= TreeChunk<Metablock, FreeList>::min_size()) {
+ if (unused >= TreeChunk<Metablock, FreeList<Metablock> >::min_size()) {
return_block(new_block + word_size, unused);
}
@@ -2239,7 +2239,7 @@ ChunkIndex ChunkManager::list_index(size_t size) {
void SpaceManager::deallocate(MetaWord* p, size_t word_size) {
assert_lock_strong(_lock);
size_t raw_word_size = get_raw_word_size(word_size);
- size_t min_size = TreeChunk<Metablock, FreeList>::min_size();
+ size_t min_size = TreeChunk<Metablock, FreeList<Metablock> >::min_size();
assert(raw_word_size >= min_size,
err_msg("Should not deallocate dark matter " SIZE_FORMAT "<" SIZE_FORMAT, word_size, min_size));
block_freelists()->return_block(p, raw_word_size);
@@ -2295,7 +2295,7 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) {
void SpaceManager::retire_current_chunk() {
if (current_chunk() != NULL) {
size_t remaining_words = current_chunk()->free_word_size();
- if (remaining_words >= TreeChunk<Metablock, FreeList>::min_size()) {
+ if (remaining_words >= TreeChunk<Metablock, FreeList<Metablock> >::min_size()) {
block_freelists()->return_block(current_chunk()->allocate(remaining_words), remaining_words);
inc_used_metrics(remaining_words);
}
@@ -3278,7 +3278,7 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
assert(Thread::current()->is_VM_thread(), "should be the VM thread");
// Don't take Heap_lock
MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
- if (word_size < TreeChunk<Metablock, FreeList>::min_size()) {
+ if (word_size < TreeChunk<Metablock, FreeList<Metablock> >::min_size()) {
// Dark matter. Too small for dictionary.
#ifdef ASSERT
Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5);
@@ -3293,7 +3293,7 @@ void Metaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) {
} else {
MutexLockerEx ml(vsm()->lock(), Mutex::_no_safepoint_check_flag);
- if (word_size < TreeChunk<Metablock, FreeList>::min_size()) {
+ if (word_size < TreeChunk<Metablock, FreeList<Metablock> >::min_size()) {
// Dark matter. Too small for dictionary.
#ifdef ASSERT
Copy::fill_to_words((HeapWord*)ptr, word_size, 0xf5f5f5f5);
diff --git a/src/share/vm/oops/constantPool.cpp b/src/share/vm/oops/constantPool.cpp
index 3f37810d2..90abff7b0 100644
--- a/src/share/vm/oops/constantPool.cpp
+++ b/src/share/vm/oops/constantPool.cpp
@@ -1295,6 +1295,7 @@ void ConstantPool::copy_entry_to(constantPoolHandle from_cp, int from_i,
} break;
case JVM_CONSTANT_UnresolvedClass:
+ case JVM_CONSTANT_UnresolvedClassInError:
{
// Can be resolved after checking tag, so check the slot first.
CPSlot entry = from_cp->slot_at(from_i);
diff --git a/src/share/vm/opto/c2_globals.hpp b/src/share/vm/opto/c2_globals.hpp
index 85e4a2a59..b3b2fd234 100644
--- a/src/share/vm/opto/c2_globals.hpp
+++ b/src/share/vm/opto/c2_globals.hpp
@@ -350,6 +350,9 @@
"File to dump ideal graph to. If set overrides the " \
"use of the network") \
\
+ product(bool, UseOldInlining, true, \
+ "Enable the 1.3 inlining strategy") \
+ \
product(bool, UseBimorphicInlining, true, \
"Profiling based inlining for two receivers") \
\
diff --git a/src/share/vm/opto/output.cpp b/src/share/vm/opto/output.cpp
index f362669b5..9ddb26339 100644
--- a/src/share/vm/opto/output.cpp
+++ b/src/share/vm/opto/output.cpp
@@ -344,6 +344,11 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
uint* jmp_offset = NEW_RESOURCE_ARRAY(uint,nblocks);
uint* jmp_size = NEW_RESOURCE_ARRAY(uint,nblocks);
int* jmp_nidx = NEW_RESOURCE_ARRAY(int ,nblocks);
+
+ // Collect worst case block paddings
+ int* block_worst_case_pad = NEW_RESOURCE_ARRAY(int, nblocks);
+ memset(block_worst_case_pad, 0, nblocks * sizeof(int));
+
DEBUG_ONLY( uint *jmp_target = NEW_RESOURCE_ARRAY(uint,nblocks); )
DEBUG_ONLY( uint *jmp_rule = NEW_RESOURCE_ARRAY(uint,nblocks); )
@@ -460,6 +465,7 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
last_avoid_back_to_back_adr += max_loop_pad;
}
blk_size += max_loop_pad;
+ block_worst_case_pad[i + 1] = max_loop_pad;
}
}
@@ -499,9 +505,16 @@ void Compile::shorten_branches(uint* blk_starts, int& code_size, int& reloc_size
if (bnum > i) { // adjust following block's offset
offset -= adjust_block_start;
}
+
+ // This block can be a loop header, account for the padding
+ // in the previous block.
+ int block_padding = block_worst_case_pad[i];
+ assert(i == 0 || block_padding == 0 || br_offs >= block_padding, "Should have at least a padding on top");
// In the following code a nop could be inserted before
// the branch which will increase the backward distance.
- bool needs_padding = ((uint)br_offs == last_may_be_short_branch_adr);
+ bool needs_padding = ((uint)(br_offs - block_padding) == last_may_be_short_branch_adr);
+ assert(!needs_padding || jmp_offset[i] == 0, "padding only branches at the beginning of block");
+
if (needs_padding && offset <= 0)
offset -= nop_size;
diff --git a/src/share/vm/prims/jni.cpp b/src/share/vm/prims/jni.cpp
index 4f8f063b3..3d8943f2d 100644
--- a/src/share/vm/prims/jni.cpp
+++ b/src/share/vm/prims/jni.cpp
@@ -1356,9 +1356,13 @@ static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receive
// interface call
KlassHandle h_holder(THREAD, holder);
- int itbl_index = m->itable_index();
- Klass* k = h_recv->klass();
- selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK);
+ if (call_type == JNI_VIRTUAL) {
+ int itbl_index = m->itable_index();
+ Klass* k = h_recv->klass();
+ selected_method = InstanceKlass::cast(k)->method_at_itable(h_holder(), itbl_index, CHECK);
+ } else {
+ selected_method = m;
+ }
}
}
@@ -5061,8 +5065,8 @@ void TestVirtualSpace_test();
void TestMetaspaceAux_test();
void TestMetachunk_test();
void TestVirtualSpaceNode_test();
-void TestOldFreeSpaceCalculation_test();
#if INCLUDE_ALL_GCS
+void TestOldFreeSpaceCalculation_test();
void TestG1BiasedArray_test();
#endif
@@ -5082,11 +5086,11 @@ void execute_internal_vm_tests() {
run_unit_test(QuickSort::test_quick_sort());
run_unit_test(AltHashing::test_alt_hash());
run_unit_test(test_loggc_filename());
- run_unit_test(TestOldFreeSpaceCalculation_test());
#if INCLUDE_VM_STRUCTS
run_unit_test(VMStructs::test());
#endif
#if INCLUDE_ALL_GCS
+ run_unit_test(TestOldFreeSpaceCalculation_test());
run_unit_test(TestG1BiasedArray_test());
run_unit_test(HeapRegionRemSet::test_prt());
#endif
diff --git a/src/share/vm/prims/jvm.cpp b/src/share/vm/prims/jvm.cpp
index a757e1948..947da5f08 100644
--- a/src/share/vm/prims/jvm.cpp
+++ b/src/share/vm/prims/jvm.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -518,6 +518,12 @@ JVM_ENTRY(void, JVM_MonitorWait(JNIEnv* env, jobject handle, jlong ms))
JavaThreadInObjectWaitState jtiows(thread, ms != 0);
if (JvmtiExport::should_post_monitor_wait()) {
JvmtiExport::post_monitor_wait((JavaThread *)THREAD, (oop)obj(), ms);
+
+ // The current thread already owns the monitor and it has not yet
+ // been added to the wait queue so the current thread cannot be
+ // made the successor. This means that the JVMTI_EVENT_MONITOR_WAIT
+ // event handler cannot accidentally consume an unpark() meant for
+ // the ParkEvent associated with this ObjectMonitor.
}
ObjectSynchronizer::wait(obj, ms, CHECK);
JVM_END
diff --git a/src/share/vm/runtime/globals.cpp b/src/share/vm/runtime/globals.cpp
index fbfc08ed0..74f7acdba 100644
--- a/src/share/vm/runtime/globals.cpp
+++ b/src/share/vm/runtime/globals.cpp
@@ -31,6 +31,7 @@
#include "utilities/ostream.hpp"
#include "utilities/macros.hpp"
#include "utilities/top.hpp"
+#include "trace/tracing.hpp"
#if INCLUDE_ALL_GCS
#include "gc_implementation/g1/g1_globals.hpp"
#endif // INCLUDE_ALL_GCS
@@ -593,6 +594,17 @@ bool CommandLineFlags::wasSetOnCmdline(const char* name, bool* value) {
return true;
}
+template<class E, class T>
+static void trace_flag_changed(const char* name, const T old_value, const T new_value, const Flag::Flags origin)
+{
+ E e;
+ e.set_name(name);
+ e.set_old_value(old_value);
+ e.set_new_value(new_value);
+ e.set_origin(origin);
+ e.commit();
+}
+
bool CommandLineFlags::boolAt(char* name, size_t len, bool* value) {
Flag* result = Flag::find_flag(name, len);
if (result == NULL) return false;
@@ -606,6 +618,7 @@ bool CommandLineFlags::boolAtPut(char* name, size_t len, bool* value, Flag::Flag
if (result == NULL) return false;
if (!result->is_bool()) return false;
bool old_value = result->get_bool();
+ trace_flag_changed<EventBooleanFlagChanged, bool>(name, old_value, *value, origin);
result->set_bool(*value);
*value = old_value;
result->set_origin(origin);
@@ -615,6 +628,7 @@ bool CommandLineFlags::boolAtPut(char* name, size_t len, bool* value, Flag::Flag
void CommandLineFlagsEx::boolAtPut(CommandLineFlagWithType flag, bool value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_bool(), "wrong flag type");
+ trace_flag_changed<EventBooleanFlagChanged, bool>(faddr->_name, faddr->get_bool(), value, origin);
faddr->set_bool(value);
faddr->set_origin(origin);
}
@@ -632,6 +646,7 @@ bool CommandLineFlags::intxAtPut(char* name, size_t len, intx* value, Flag::Flag
if (result == NULL) return false;
if (!result->is_intx()) return false;
intx old_value = result->get_intx();
+ trace_flag_changed<EventLongFlagChanged, s8>(name, old_value, *value, origin);
result->set_intx(*value);
*value = old_value;
result->set_origin(origin);
@@ -641,6 +656,7 @@ bool CommandLineFlags::intxAtPut(char* name, size_t len, intx* value, Flag::Flag
void CommandLineFlagsEx::intxAtPut(CommandLineFlagWithType flag, intx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_intx(), "wrong flag type");
+ trace_flag_changed<EventLongFlagChanged, s8>(faddr->_name, faddr->get_intx(), value, origin);
faddr->set_intx(value);
faddr->set_origin(origin);
}
@@ -658,6 +674,7 @@ bool CommandLineFlags::uintxAtPut(char* name, size_t len, uintx* value, Flag::Fl
if (result == NULL) return false;
if (!result->is_uintx()) return false;
uintx old_value = result->get_uintx();
+ trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
result->set_uintx(*value);
*value = old_value;
result->set_origin(origin);
@@ -667,6 +684,7 @@ bool CommandLineFlags::uintxAtPut(char* name, size_t len, uintx* value, Flag::Fl
void CommandLineFlagsEx::uintxAtPut(CommandLineFlagWithType flag, uintx value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uintx(), "wrong flag type");
+ trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uintx(), value, origin);
faddr->set_uintx(value);
faddr->set_origin(origin);
}
@@ -684,6 +702,7 @@ bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, Fl
if (result == NULL) return false;
if (!result->is_uint64_t()) return false;
uint64_t old_value = result->get_uint64_t();
+ trace_flag_changed<EventUnsignedLongFlagChanged, u8>(name, old_value, *value, origin);
result->set_uint64_t(*value);
*value = old_value;
result->set_origin(origin);
@@ -693,6 +712,7 @@ bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, Fl
void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type");
+ trace_flag_changed<EventUnsignedLongFlagChanged, u8>(faddr->_name, faddr->get_uint64_t(), value, origin);
faddr->set_uint64_t(value);
faddr->set_origin(origin);
}
@@ -710,6 +730,7 @@ bool CommandLineFlags::doubleAtPut(char* name, size_t len, double* value, Flag::
if (result == NULL) return false;
if (!result->is_double()) return false;
double old_value = result->get_double();
+ trace_flag_changed<EventDoubleFlagChanged, double>(name, old_value, *value, origin);
result->set_double(*value);
*value = old_value;
result->set_origin(origin);
@@ -719,6 +740,7 @@ bool CommandLineFlags::doubleAtPut(char* name, size_t len, double* value, Flag::
void CommandLineFlagsEx::doubleAtPut(CommandLineFlagWithType flag, double value, Flag::Flags origin) {
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_double(), "wrong flag type");
+ trace_flag_changed<EventDoubleFlagChanged, double>(faddr->_name, faddr->get_double(), value, origin);
faddr->set_double(value);
faddr->set_origin(origin);
}
@@ -738,6 +760,7 @@ bool CommandLineFlags::ccstrAtPut(char* name, size_t len, ccstr* value, Flag::Fl
if (result == NULL) return false;
if (!result->is_ccstr()) return false;
ccstr old_value = result->get_ccstr();
+ trace_flag_changed<EventStringFlagChanged, const char*>(name, old_value, *value, origin);
char* new_value = NULL;
if (*value != NULL) {
new_value = NEW_C_HEAP_ARRAY(char, strlen(*value)+1, mtInternal);
@@ -760,6 +783,7 @@ void CommandLineFlagsEx::ccstrAtPut(CommandLineFlagWithType flag, ccstr value, F
Flag* faddr = address_of_flag(flag);
guarantee(faddr != NULL && faddr->is_ccstr(), "wrong flag type");
ccstr old_value = faddr->get_ccstr();
+ trace_flag_changed<EventStringFlagChanged, const char*>(faddr->_name, old_value, value, origin);
char* new_value = NEW_C_HEAP_ARRAY(char, strlen(value)+1, mtInternal);
strcpy(new_value, value);
faddr->set_ccstr(new_value);
diff --git a/src/share/vm/runtime/objectMonitor.cpp b/src/share/vm/runtime/objectMonitor.cpp
index 523887502..4fcbf5d55 100644
--- a/src/share/vm/runtime/objectMonitor.cpp
+++ b/src/share/vm/runtime/objectMonitor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2014, 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
@@ -382,6 +382,12 @@ void ATTR ObjectMonitor::enter(TRAPS) {
DTRACE_MONITOR_PROBE(contended__enter, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_enter()) {
JvmtiExport::post_monitor_contended_enter(jt, this);
+
+ // The current thread does not yet own the monitor and does not
+ // yet appear on any queues that would get it made the successor.
+ // This means that the JVMTI_EVENT_MONITOR_CONTENDED_ENTER event
+ // handler cannot accidentally consume an unpark() meant for the
+ // ParkEvent associated with this ObjectMonitor.
}
OSThreadContendState osts(Self->osthread());
@@ -439,6 +445,12 @@ void ATTR ObjectMonitor::enter(TRAPS) {
DTRACE_MONITOR_PROBE(contended__entered, this, object(), jt);
if (JvmtiExport::should_post_monitor_contended_entered()) {
JvmtiExport::post_monitor_contended_entered(jt, this);
+
+ // The current thread already owns the monitor and is not going to
+ // call park() for the remainder of the monitor enter protocol. So
+ // it doesn't matter if the JVMTI_EVENT_MONITOR_CONTENDED_ENTERED
+ // event handler consumed an unpark() issued by the thread that
+ // just exited the monitor.
}
if (event.should_commit()) {
@@ -1456,6 +1468,14 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
// Note: 'false' parameter is passed here because the
// wait was not timed out due to thread interrupt.
JvmtiExport::post_monitor_waited(jt, this, false);
+
+ // In this short circuit of the monitor wait protocol, the
+ // current thread never drops ownership of the monitor and
+ // never gets added to the wait queue so the current thread
+ // cannot be made the successor. This means that the
+ // JVMTI_EVENT_MONITOR_WAITED event handler cannot accidentally
+ // consume an unpark() meant for the ParkEvent associated with
+ // this ObjectMonitor.
}
if (event.should_commit()) {
post_monitor_wait_event(&event, 0, millis, false);
@@ -1499,21 +1519,6 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
exit (true, Self) ; // exit the monitor
guarantee (_owner != Self, "invariant") ;
- // As soon as the ObjectMonitor's ownership is dropped in the exit()
- // call above, another thread can enter() the ObjectMonitor, do the
- // notify(), and exit() the ObjectMonitor. If the other thread's
- // exit() call chooses this thread as the successor and the unpark()
- // call happens to occur while this thread is posting a
- // MONITOR_CONTENDED_EXIT event, then we run the risk of the event
- // handler using RawMonitors and consuming the unpark().
- //
- // To avoid the problem, we re-post the event. This does no harm
- // even if the original unpark() was not consumed because we are the
- // chosen successor for this monitor.
- if (node._notified != 0 && _succ == Self) {
- node._event->unpark();
- }
-
// The thread is on the WaitSet list - now park() it.
// On MP systems it's conceivable that a brief spin before we park
// could be profitable.
@@ -1597,6 +1602,33 @@ void ObjectMonitor::wait(jlong millis, bool interruptible, TRAPS) {
JvmtiExport::post_monitor_waited(jt, this, ret == OS_TIMEOUT);
}
+ // Without the fix for 8028280, it is possible for the above call:
+ //
+ // Thread::SpinAcquire (&_WaitSetLock, "WaitSet - unlink") ;
+ //
+ // to consume the unpark() that was done when the successor was set.
+ // The solution for this very rare possibility is to redo the unpark()
+ // outside of the JvmtiExport::should_post_monitor_waited() check.
+ //
+ if (node._notified != 0 && _succ == Self) {
+ // In this part of the monitor wait-notify-reenter protocol it
+ // is possible (and normal) for another thread to do a fastpath
+ // monitor enter-exit while this thread is still trying to get
+ // to the reenter portion of the protocol.
+ //
+ // The ObjectMonitor was notified and the current thread is
+ // the successor which also means that an unpark() has already
+ // been done. The JVMTI_EVENT_MONITOR_WAITED event handler can
+ // consume the unpark() that was done when the successor was
+ // set because the same ParkEvent is shared between Java
+ // monitors and JVM/TI RawMonitors (for now).
+ //
+ // We redo the unpark() to ensure forward progress, i.e., we
+ // don't want all pending threads hanging (parked) with none
+ // entering the unlocked monitor.
+ node._event->unpark();
+ }
+
if (event.should_commit()) {
post_monitor_wait_event(&event, node._notifier_tid, millis, ret == OS_TIMEOUT);
}
diff --git a/src/share/vm/runtime/vmStructs.cpp b/src/share/vm/runtime/vmStructs.cpp
index 0897c2518..c1191a056 100644
--- a/src/share/vm/runtime/vmStructs.cpp
+++ b/src/share/vm/runtime/vmStructs.cpp
@@ -242,7 +242,7 @@ typedef TwoOopHashtable<Klass*, mtClass> KlassTwoOopHashtable;
typedef Hashtable<Klass*, mtClass> KlassHashtable;
typedef HashtableEntry<Klass*, mtClass> KlassHashtableEntry;
typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
-typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
+typedef BinaryTreeDictionary<Metablock, FreeList<Metablock> > MetablockTreeDictionary;
//--------------------------------------------------------------------------------
// VM_STRUCTS
diff --git a/src/share/vm/trace/trace.xml b/src/share/vm/trace/trace.xml
index 218207b73..75efeea11 100644
--- a/src/share/vm/trace/trace.xml
+++ b/src/share/vm/trace/trace.xml
@@ -122,6 +122,46 @@ Declares a structure type that can be used in other events.
<value type="CLASS" field="definingClassLoader" label="Defining Class Loader"/>
</event>
+ <event id="LongFlagChanged" path="vm/flag/long_changed" label="Long Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="LONG" field="old_value" label="Old Value" />
+ <value type="LONG" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="UnsignedLongFlagChanged" path="vm/flag/ulong_changed" label="Unsigned Long Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="ULONG" field="old_value" label="Old Value" />
+ <value type="ULONG" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="DoubleFlagChanged" path="vm/flag/double_changed" label="Double Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="DOUBLE" field="old_value" label="Old Value" />
+ <value type="DOUBLE" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="BooleanFlagChanged" path="vm/flag/boolean_changed" label="Boolean Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="BOOLEAN" field="old_value" label="Old Value" />
+ <value type="BOOLEAN" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
+ <event id="StringFlagChanged" path="vm/flag/string_changed" label="String Flag Changed"
+ is_instant="true">
+ <value type="UTF8" field="name" label="Name" />
+ <value type="UTF8" field="old_value" label="Old Value" />
+ <value type="UTF8" field="new_value" label="New Value" />
+ <value type="FLAGVALUEORIGIN" field="origin" label="Origin" />
+ </event>
+
<struct id="VirtualSpace">
<value type="ADDRESS" field="start" label="Start Address" description="Start address of the virtual space" />
<value type="ADDRESS" field="committedEnd" label="Committed End Address" description="End address of the committed memory for the virtual space" />
diff --git a/src/share/vm/trace/tracetypes.xml b/src/share/vm/trace/tracetypes.xml
index ab9a95b77..9305d2fa7 100644
--- a/src/share/vm/trace/tracetypes.xml
+++ b/src/share/vm/trace/tracetypes.xml
@@ -85,12 +85,6 @@ Now we can use the content + data type in declaring event fields.
<value type="UTF8" field="name" label="Name"/>
</content_type>
- <content_type id="StackTrace" hr_name="Stacktrace"
- type="U8" builtin_type="STACKTRACE">
- <value type="BOOLEAN" field="truncated" label="Truncated"/>
- <structarray type="StackFrame" field="frames" label="Stack frames"/>
- </content_type>
-
<content_type id="Class" hr_name="Java class"
type="U8" builtin_type="CLASS">
<value type="CLASS" field="loaderClass" label="ClassLoader"/>
@@ -116,17 +110,6 @@ Now we can use the content + data type in declaring event fields.
<value type="UTF8" field="name" label="Name"/>
</content_type>
- <content_type id="FrameType" hr_name="Frame type"
- type="U1" jvm_type="FRAMETYPE">
- <value type="UTF8" field="desc" label="Description"/>
- </content_type>
-
- <struct_type id="StackFrame">
- <value type="METHOD" field="method" label="Java Method"/>
- <value type="INTEGER" field="line" label="Line number"/>
- <value type="FRAMETYPE" field="type" label="Frame type"/>
- </struct_type>
-
<content_type id="GCName" hr_name="GC Name"
type="U1" jvm_type="GCNAME">
<value type="UTF8" field="name" label="name" />
@@ -167,6 +150,11 @@ Now we can use the content + data type in declaring event fields.
<value type="UTF8" field="phase" label="phase" />
</content_type>
+ <content_type id="FlagValueOrigin" hr_name="Flag Value Origin"
+ type="U1" jvm_type="FLAGVALUEORIGIN">
+ <value type="UTF8" field="origin" label="origin" />
+ </content_type>
+
</content_types>
@@ -351,6 +339,10 @@ Now we can use the content + data type in declaring event fields.
<!-- VMOPERATIONTYPE -->
<primary_type symbol="VMOPERATIONTYPE" datatype="U2" contenttype="VMOPERATIONTYPE"
type="u2" sizeop="sizeof(u2)" />
+
+ <!-- FLAGVALUEORIGIN -->
+ <primary_type symbol="FLAGVALUEORIGIN" datatype="U1"
+ contenttype="FLAGVALUEORIGIN" type="u1" sizeop="sizeof(u1)" />
</primary_types>
</types>
diff --git a/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java b/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
new file mode 100644
index 000000000..4f929c49a
--- /dev/null
+++ b/test/serviceability/jvmti/TestRedefineWithUnresolvedClass.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2014, 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
+ * @summary Redefine a class with an UnresolvedClass reference in the constant pool.
+ * @bug 8035150
+ * @library /testlibrary
+ * @build UnresolvedClassAgent com.oracle.java.testlibrary.ProcessTools com.oracle.java.testlibrary.OutputAnalyzer
+ * @run main TestRedefineWithUnresolvedClass
+ */
+
+import java.io.File;
+import java.util.Arrays;
+
+import com.oracle.java.testlibrary.OutputAnalyzer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+public class TestRedefineWithUnresolvedClass {
+
+ final static String slash = File.separator;
+ final static String testClasses = System.getProperty("test.classes") + slash;
+
+ public static void main(String... args) throws Throwable {
+ // delete this class to cause a NoClassDefFoundError
+ File unresolved = new File(testClasses, "MyUnresolvedClass.class");
+ if (unresolved.exists() && !unresolved.delete()) {
+ throw new Exception("Could not delete: " + unresolved);
+ }
+
+ // build the javaagent
+ buildJar("UnresolvedClassAgent");
+
+ // launch a VM with the javaagent
+ launchTest();
+ }
+
+ private static void buildJar(String jarName) throws Throwable {
+ String testSrc = System.getProperty("test.src", "?") + slash;
+
+ String jarPath = String.format("%s%s.jar", testClasses, jarName);
+ String manifestPath = String.format("%s%s.mf", testSrc, jarName);
+ String className = String.format("%s.class", jarName);
+
+ String[] args = new String[] {"-cfm", jarPath, manifestPath, "-C", testClasses, className};
+
+ System.out.println("Running jar " + Arrays.toString(args));
+ sun.tools.jar.Main jarTool = new sun.tools.jar.Main(System.out, System.err, "jar");
+ if (!jarTool.run(args)) {
+ throw new Exception("jar failed: args=" + Arrays.toString(args));
+ }
+ }
+
+ private static void launchTest() throws Throwable {
+ String[] args = {
+ "-javaagent:" + testClasses + "UnresolvedClassAgent.jar",
+ "-Dtest.classes=" + testClasses,
+ "UnresolvedClassAgent" };
+ OutputAnalyzer output = ProcessTools.executeTestJvm(args);
+ output.shouldHaveExitValue(0);
+ }
+}
diff --git a/test/serviceability/jvmti/UnresolvedClassAgent.java b/test/serviceability/jvmti/UnresolvedClassAgent.java
new file mode 100644
index 000000000..efe7b25a1
--- /dev/null
+++ b/test/serviceability/jvmti/UnresolvedClassAgent.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, 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.
+ */
+
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.lang.instrument.ClassDefinition;
+import java.lang.instrument.Instrumentation;
+
+/*
+ * This class is present during compilation, but will be deleted before execution.
+ */
+class MyUnresolvedClass {
+ static void bar() {
+ }
+}
+
+class MyRedefinedClass {
+ static void foo() {
+ MyUnresolvedClass.bar();
+ }
+}
+
+public class UnresolvedClassAgent {
+ public static void main(String... args) {
+ }
+
+ public static void premain(String args, Instrumentation inst) throws Exception {
+ try {
+ MyRedefinedClass.foo();
+ } catch(NoClassDefFoundError err) {
+ System.out.println("NoClassDefFoundError (expected)");
+ }
+
+ File f = new File(System.getProperty("test.classes"), "MyRedefinedClass.class");
+ byte[] buf = new byte[(int)f.length()];
+ try (DataInputStream dis = new DataInputStream(new FileInputStream(f))) {
+ dis.readFully(buf);
+ }
+ ClassDefinition cd = new ClassDefinition(MyRedefinedClass.class, buf);
+ inst.redefineClasses(new ClassDefinition[] {cd});
+
+ try {
+ MyRedefinedClass.foo();
+ } catch(NoClassDefFoundError err) {
+ System.out.println("NoClassDefFoundError (expected again)");
+ }
+ }
+}
diff --git a/test/serviceability/jvmti/UnresolvedClassAgent.mf b/test/serviceability/jvmti/UnresolvedClassAgent.mf
new file mode 100644
index 000000000..5570570cd
--- /dev/null
+++ b/test/serviceability/jvmti/UnresolvedClassAgent.mf
@@ -0,0 +1,3 @@
+Manifest-Version: 1.0
+Premain-Class: UnresolvedClassAgent
+Can-Redefine-Classes: true
diff --git a/test/serviceability/sa/jmap-hashcode/Test8028623.java b/test/serviceability/sa/jmap-hashcode/Test8028623.java
new file mode 100644
index 000000000..bd743ab1c
--- /dev/null
+++ b/test/serviceability/sa/jmap-hashcode/Test8028623.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2014, 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 8028623
+ * @summary Test hashing of extended characters in Serviceability Agent.
+ * @library /testlibrary
+ * @compile -encoding utf8 Test8028623.java
+ * @run main Test8028623
+ */
+
+import com.oracle.java.testlibrary.JDKToolLauncher;
+import com.oracle.java.testlibrary.OutputBuffer;
+import com.oracle.java.testlibrary.ProcessTools;
+
+import java.io.File;
+
+public class Test8028623 {
+
+ public static int à = 1;
+ public static String dumpFile = "heap.out";
+
+ public static void main (String[] args) {
+
+ System.out.println(Ã);
+
+ try {
+ int pid = ProcessTools.getProcessId();
+ JDKToolLauncher jmap = JDKToolLauncher.create("jmap")
+ .addToolArg("-F")
+ .addToolArg("-dump:live,format=b,file=" + dumpFile)
+ .addToolArg(Integer.toString(pid));
+ ProcessBuilder pb = new ProcessBuilder(jmap.getCommand());
+ OutputBuffer output = ProcessTools.getOutput(pb);
+ Process p = pb.start();
+ int e = p.waitFor();
+ System.out.println("stdout:");
+ System.out.println(output.getStdout());
+ System.out.println("stderr:");
+ System.out.println(output.getStderr());
+
+ if (e != 0) {
+ throw new RuntimeException("jmap returns: " + e);
+ }
+ if (! new File(dumpFile).exists()) {
+ throw new RuntimeException("dump file NOT created: '" + dumpFile + "'");
+ }
+ } catch (Throwable t) {
+ t.printStackTrace();
+ throw new RuntimeException("Test failed with: " + t);
+ }
+ }
+}
diff --git a/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java b/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java
index 56277f046..64b1b9ea9 100644
--- a/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java
+++ b/test/testlibrary/com/oracle/java/testlibrary/ProcessTools.java
@@ -151,11 +151,88 @@ public final class ProcessTools {
// Reporting
StringBuilder cmdLine = new StringBuilder();
- for (String cmd : args)
- cmdLine.append(cmd).append(' ');
+ for (String cmd : args) {
+ cmdLine.append(cmd).append(' ');
+ }
System.out.println("Command line: [" + cmdLine.toString() + "]");
return new ProcessBuilder(args.toArray(new String[args.size()]));
}
+ /**
+ * Executes a test jvm process, waits for it to finish and returns the process output.
+ * The default jvm options from jtreg, test.vm.opts and test.java.opts, are added.
+ * The java from the test.jdk is used to execute the command.
+ *
+ * The command line will be like:
+ * {test.jdk}/bin/java {test.vm.opts} {test.java.opts} cmds
+ *
+ * @param cmds User specifed arguments.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeTestJvm(String... cmds) throws Throwable {
+ ProcessBuilder pb = createJavaProcessBuilder(Utils.addTestJavaOpts(cmds));
+ return executeProcess(pb);
+ }
+
+ /**
+ * Executes a process, waits for it to finish and returns the process output.
+ * @param pb The ProcessBuilder to execute.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeProcess(ProcessBuilder pb) throws Throwable {
+ OutputAnalyzer output = null;
+ try {
+ output = new OutputAnalyzer(pb.start());
+ return output;
+ } catch (Throwable t) {
+ System.out.println("executeProcess() failed: " + t);
+ throw t;
+ } finally {
+ System.out.println(getProcessLog(pb, output));
+ }
+ }
+
+ /**
+ * Executes a process, waits for it to finish and returns the process output.
+ * @param cmds The command line to execute.
+ * @return The output from the process.
+ */
+ public static OutputAnalyzer executeProcess(String... cmds) throws Throwable {
+ return executeProcess(new ProcessBuilder(cmds));
+ }
+
+ /**
+ * Used to log command line, stdout, stderr and exit code from an executed process.
+ * @param pb The executed process.
+ * @param output The output from the process.
+ */
+ public static String getProcessLog(ProcessBuilder pb, OutputAnalyzer output) {
+ String stderr = output == null ? "null" : output.getStderr();
+ String stdout = output == null ? "null" : output.getStdout();
+ String exitValue = output == null ? "null": Integer.toString(output.getExitValue());
+ StringBuilder logMsg = new StringBuilder();
+ final String nl = System.getProperty("line.separator");
+ logMsg.append("--- ProcessLog ---" + nl);
+ logMsg.append("cmd: " + getCommandLine(pb) + nl);
+ logMsg.append("exitvalue: " + exitValue + nl);
+ logMsg.append("stderr: " + stderr + nl);
+ logMsg.append("stdout: " + stdout + nl);
+ return logMsg.toString();
+ }
+
+ /**
+ * @return The full command line for the ProcessBuilder.
+ */
+ public static String getCommandLine(ProcessBuilder pb) {
+ if (pb == null) {
+ return "null";
+ }
+ StringBuilder cmd = new StringBuilder();
+ for (String s : pb.command()) {
+ cmd.append(s).append(" ");
+ }
+ return cmd.toString().trim();
+ }
+
}
diff --git a/test/testlibrary/com/oracle/java/testlibrary/Utils.java b/test/testlibrary/com/oracle/java/testlibrary/Utils.java
new file mode 100644
index 000000000..a0031e706
--- /dev/null
+++ b/test/testlibrary/com/oracle/java/testlibrary/Utils.java
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2013, 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 com.oracle.java.testlibrary;
+
+import static com.oracle.java.testlibrary.Asserts.assertTrue;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * Common library for various test helper functions.
+ */
+public final class Utils {
+
+ /**
+ * Returns the sequence used by operating system to separate lines.
+ */
+ public static final String NEW_LINE = System.getProperty("line.separator");
+
+ /**
+ * Returns the value of 'test.vm.opts'system property.
+ */
+ public static final String VM_OPTIONS = System.getProperty("test.vm.opts", "").trim();
+
+ /**
+ * Returns the value of 'test.java.opts'system property.
+ */
+ public static final String JAVA_OPTIONS = System.getProperty("test.java.opts", "").trim();
+
+ /**
+ * Returns the value of 'test.timeout.factor' system property
+ * converted to {@code double}.
+ */
+ public static final double TIMEOUT_FACTOR;
+ static {
+ String toFactor = System.getProperty("test.timeout.factor", "1.0");
+ TIMEOUT_FACTOR = Double.parseDouble(toFactor);
+ }
+
+ private Utils() {
+ // Private constructor to prevent class instantiation
+ }
+
+ /**
+ * Returns the list of VM options.
+ *
+ * @return List of VM options
+ */
+ public static List<String> getVmOptions() {
+ return Arrays.asList(safeSplitString(VM_OPTIONS));
+ }
+
+ /**
+ * Returns the list of VM options with -J prefix.
+ *
+ * @return The list of VM options with -J prefix
+ */
+ public static List<String> getForwardVmOptions() {
+ String[] opts = safeSplitString(VM_OPTIONS);
+ for (int i = 0; i < opts.length; i++) {
+ opts[i] = "-J" + opts[i];
+ }
+ return Arrays.asList(opts);
+ }
+
+ /**
+ * Returns the default JTReg arguments for a jvm running a test.
+ * This is the combination of JTReg arguments test.vm.opts and test.java.opts.
+ * @return An array of options, or an empty array if no opptions.
+ */
+ public static String[] getTestJavaOpts() {
+ List<String> opts = new ArrayList<String>();
+ Collections.addAll(opts, safeSplitString(VM_OPTIONS));
+ Collections.addAll(opts, safeSplitString(JAVA_OPTIONS));
+ return opts.toArray(new String[0]);
+ }
+
+ /**
+ * Combines given arguments with default JTReg arguments for a jvm running a test.
+ * This is the combination of JTReg arguments test.vm.opts and test.java.opts
+ * @return The combination of JTReg test java options and user args.
+ */
+ public static String[] addTestJavaOpts(String... userArgs) {
+ List<String> opts = new ArrayList<String>();
+ Collections.addAll(opts, getTestJavaOpts());
+ Collections.addAll(opts, userArgs);
+ return opts.toArray(new String[0]);
+ }
+
+ /**
+ * Splits a string by white space.
+ * Works like String.split(), but returns an empty array
+ * if the string is null or empty.
+ */
+ private static String[] safeSplitString(String s) {
+ if (s == null || s.trim().isEmpty()) {
+ return new String[] {};
+ }
+ return s.trim().split("\\s+");
+ }
+
+ /**
+ * @return The full command line for the ProcessBuilder.
+ */
+ public static String getCommandLine(ProcessBuilder pb) {
+ StringBuilder cmd = new StringBuilder();
+ for (String s : pb.command()) {
+ cmd.append(s).append(" ");
+ }
+ return cmd.toString();
+ }
+
+ /**
+ * Returns the free port on the local host.
+ * The function will spin until a valid port number is found.
+ *
+ * @return The port number
+ * @throws InterruptedException if any thread has interrupted the current thread
+ * @throws IOException if an I/O error occurs when opening the socket
+ */
+ public static int getFreePort() throws InterruptedException, IOException {
+ int port = -1;
+
+ while (port <= 0) {
+ Thread.sleep(100);
+
+ ServerSocket serverSocket = null;
+ try {
+ serverSocket = new ServerSocket(0);
+ port = serverSocket.getLocalPort();
+ } finally {
+ serverSocket.close();
+ }
+ }
+
+ return port;
+ }
+
+ /**
+ * Returns the name of the local host.
+ *
+ * @return The host name
+ * @throws UnknownHostException if IP address of a host could not be determined
+ */
+ public static String getHostname() throws UnknownHostException {
+ InetAddress inetAddress = InetAddress.getLocalHost();
+ String hostName = inetAddress.getHostName();
+
+ assertTrue((hostName != null && !hostName.isEmpty()),
+ "Cannot get hostname");
+
+ return hostName;
+ }
+
+ /**
+ * Uses "jcmd -l" to search for a jvm pid. This function will wait
+ * forever (until jtreg timeout) for the pid to be found.
+ * @param key Regular expression to search for
+ * @return The found pid.
+ */
+ public static int waitForJvmPid(String key) throws Throwable {
+ final long iterationSleepMillis = 250;
+ System.out.println("waitForJvmPid: Waiting for key '" + key + "'");
+ System.out.flush();
+ while (true) {
+ int pid = tryFindJvmPid(key);
+ if (pid >= 0) {
+ return pid;
+ }
+ Thread.sleep(iterationSleepMillis);
+ }
+ }
+
+ /**
+ * Searches for a jvm pid in the output from "jcmd -l".
+ *
+ * Example output from jcmd is:
+ * 12498 sun.tools.jcmd.JCmd -l
+ * 12254 /tmp/jdk8/tl/jdk/JTwork/classes/com/sun/tools/attach/Application.jar
+ *
+ * @param key A regular expression to search for.
+ * @return The found pid, or -1 if Enot found.
+ * @throws Exception If multiple matching jvms are found.
+ */
+ public static int tryFindJvmPid(String key) throws Throwable {
+ OutputAnalyzer output = null;
+ try {
+ JDKToolLauncher jcmdLauncher = JDKToolLauncher.create("jcmd");
+ jcmdLauncher.addToolArg("-l");
+ output = ProcessTools.executeProcess(jcmdLauncher.getCommand());
+ output.shouldHaveExitValue(0);
+
+ // Search for a line starting with numbers (pid), follwed by the key.
+ Pattern pattern = Pattern.compile("([0-9]+)\\s.*(" + key + ").*\\r?\\n");
+ Matcher matcher = pattern.matcher(output.getStdout());
+
+ int pid = -1;
+ if (matcher.find()) {
+ pid = Integer.parseInt(matcher.group(1));
+ System.out.println("findJvmPid.pid: " + pid);
+ if (matcher.find()) {
+ throw new Exception("Found multiple JVM pids for key: " + key);
+ }
+ }
+ return pid;
+ } catch (Throwable t) {
+ System.out.println(String.format("Utils.findJvmPid(%s) failed: %s", key, t));
+ throw t;
+ }
+ }
+
+ /**
+ * Returns file content as a list of strings
+ *
+ * @param file File to operate on
+ * @return List of strings
+ * @throws IOException
+ */
+ public static List<String> fileAsList(File file) throws IOException {
+ assertTrue(file.exists() && file.isFile(),
+ file.getAbsolutePath() + " does not exist or not a file");
+ List<String> output = new ArrayList<>();
+ try (BufferedReader reader = new BufferedReader(new FileReader(file.getAbsolutePath()))) {
+ while (reader.ready()) {
+ output.add(reader.readLine().replace(NEW_LINE, ""));
+ }
+ }
+ return output;
+ }
+
+}