mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 22:34:27 +02:00
Merge
This commit is contained in:
commit
b12896283b
65 changed files with 879 additions and 456 deletions
|
@ -958,7 +958,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||
|
||||
// reset handle block
|
||||
__ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), G3_scratch);
|
||||
__ st_ptr(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
||||
__ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
||||
|
||||
|
||||
// handle exceptions (exception handling will handle unlocking!)
|
||||
|
|
|
@ -2687,7 +2687,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||
if (!is_critical_native) {
|
||||
// reset handle block
|
||||
__ ld_ptr(G2_thread, in_bytes(JavaThread::active_handles_offset()), L5);
|
||||
__ st_ptr(G0, L5, JNIHandleBlock::top_offset_in_bytes());
|
||||
__ st(G0, L5, JNIHandleBlock::top_offset_in_bytes());
|
||||
|
||||
__ ld_ptr(G2_thread, in_bytes(Thread::pending_exception_offset()), G3_scratch);
|
||||
check_forward_pending_exception(masm, G3_scratch);
|
||||
|
|
|
@ -1147,7 +1147,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||
|
||||
// reset handle block
|
||||
__ ld_ptr(G2_thread, JavaThread::active_handles_offset(), G3_scratch);
|
||||
__ st_ptr(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
||||
__ st(G0, G3_scratch, JNIHandleBlock::top_offset_in_bytes());
|
||||
|
||||
// If we have an oop result store it where it will be safe for any further gc
|
||||
// until we return now that we've released the handle it might be protected by
|
||||
|
|
|
@ -1358,7 +1358,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||
|
||||
// reset handle block
|
||||
__ movptr(t, Address(thread, JavaThread::active_handles_offset()));
|
||||
__ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||
__ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||
|
||||
// If result was an oop then unbox and save it in the frame
|
||||
{ Label L;
|
||||
|
|
|
@ -162,7 +162,7 @@ define_pd_global(uintx, TypeProfileLevel, 111);
|
|||
"Number of milliseconds to wait before start calculating aborts " \
|
||||
"for RTM locking") \
|
||||
\
|
||||
experimental(bool, UseRTMXendForLockBusy, false, \
|
||||
experimental(bool, UseRTMXendForLockBusy, true, \
|
||||
"Use RTM Xend instead of Xabort when lock busy") \
|
||||
\
|
||||
/* assembler */ \
|
||||
|
|
|
@ -1488,11 +1488,10 @@ void MacroAssembler::rtm_stack_locking(Register objReg, Register tmpReg, Registe
|
|||
movl(retry_on_abort_count_Reg, RTMRetryCount); // Retry on abort
|
||||
bind(L_rtm_retry);
|
||||
}
|
||||
if (!UseRTMXendForLockBusy) {
|
||||
movptr(tmpReg, Address(objReg, 0));
|
||||
testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased
|
||||
jcc(Assembler::notZero, IsInflated);
|
||||
}
|
||||
|
||||
if (PrintPreciseRTMLockingStatistics || profile_rtm) {
|
||||
Label L_noincrement;
|
||||
if (RTMTotalCountIncrRate > 1) {
|
||||
|
@ -1512,10 +1511,7 @@ void MacroAssembler::rtm_stack_locking(Register objReg, Register tmpReg, Registe
|
|||
Register abort_status_Reg = tmpReg; // status of abort is stored in RAX
|
||||
if (UseRTMXendForLockBusy) {
|
||||
xend();
|
||||
movptr(tmpReg, Address(objReg, 0));
|
||||
testptr(tmpReg, markOopDesc::monitor_value); // inflated vs stack-locked|neutral|biased
|
||||
jcc(Assembler::notZero, IsInflated);
|
||||
movptr(abort_status_Reg, 0x1); // Set the abort status to 1 (as xabort does)
|
||||
movptr(abort_status_Reg, 0x2); // Set the abort status to 2 (so we can retry)
|
||||
jmp(L_decrement_retry);
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -2266,7 +2266,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||
if (!is_critical_native) {
|
||||
// reset handle block
|
||||
__ movptr(rcx, Address(thread, JavaThread::active_handles_offset()));
|
||||
__ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
||||
__ movl(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
||||
|
||||
// Any exception pending?
|
||||
__ cmpptr(Address(thread, in_bytes(Thread::pending_exception_offset())), (int32_t)NULL_WORD);
|
||||
|
|
|
@ -2509,7 +2509,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
|
|||
if (!is_critical_native) {
|
||||
// reset handle block
|
||||
__ movptr(rcx, Address(r15_thread, JavaThread::active_handles_offset()));
|
||||
__ movptr(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||
__ movl(Address(rcx, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||
}
|
||||
|
||||
// pop our frame
|
||||
|
|
|
@ -1287,7 +1287,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||
|
||||
// reset handle block
|
||||
__ movptr(t, Address(thread, JavaThread::active_handles_offset()));
|
||||
__ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
||||
__ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), NULL_WORD);
|
||||
|
||||
// If result was an oop then unbox and save it in the frame
|
||||
{ Label L;
|
||||
|
|
|
@ -1259,7 +1259,7 @@ address InterpreterGenerator::generate_native_entry(bool synchronized) {
|
|||
|
||||
// reset handle block
|
||||
__ movptr(t, Address(r15_thread, JavaThread::active_handles_offset()));
|
||||
__ movptr(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||
__ movl(Address(t, JNIHandleBlock::top_offset_in_bytes()), (int32_t)NULL_WORD);
|
||||
|
||||
// If result is an oop unbox and store it in frame where gc will see it
|
||||
// and result handler will pick it up
|
||||
|
|
|
@ -810,11 +810,11 @@ void StringTable::buckets_oops_do(OopClosure* f, int start_idx, int end_idx) {
|
|||
const int limit = the_table()->table_size();
|
||||
|
||||
assert(0 <= start_idx && start_idx <= limit,
|
||||
err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx));
|
||||
err_msg("start_idx (%d) is out of bounds", start_idx));
|
||||
assert(0 <= end_idx && end_idx <= limit,
|
||||
err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx));
|
||||
err_msg("end_idx (%d) is out of bounds", end_idx));
|
||||
assert(start_idx <= end_idx,
|
||||
err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT,
|
||||
err_msg("Index ordering: start_idx=%d, end_idx=%d",
|
||||
start_idx, end_idx));
|
||||
|
||||
for (int i = start_idx; i < end_idx; i += 1) {
|
||||
|
@ -833,11 +833,11 @@ void StringTable::buckets_unlink_or_oops_do(BoolObjectClosure* is_alive, OopClos
|
|||
const int limit = the_table()->table_size();
|
||||
|
||||
assert(0 <= start_idx && start_idx <= limit,
|
||||
err_msg("start_idx (" INT32_FORMAT ") is out of bounds", start_idx));
|
||||
err_msg("start_idx (%d) is out of bounds", start_idx));
|
||||
assert(0 <= end_idx && end_idx <= limit,
|
||||
err_msg("end_idx (" INT32_FORMAT ") is out of bounds", end_idx));
|
||||
err_msg("end_idx (%d) is out of bounds", end_idx));
|
||||
assert(start_idx <= end_idx,
|
||||
err_msg("Index ordering: start_idx=" INT32_FORMAT", end_idx=" INT32_FORMAT,
|
||||
err_msg("Index ordering: start_idx=%d, end_idx=%d",
|
||||
start_idx, end_idx));
|
||||
|
||||
for (int i = start_idx; i < end_idx; ++i) {
|
||||
|
|
|
@ -57,10 +57,10 @@ ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) :
|
|||
|
||||
_threads = NEW_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _n_threads, mtGC);
|
||||
|
||||
int worker_id_offset = (int)DirtyCardQueueSet::num_par_ids();
|
||||
uint worker_id_offset = DirtyCardQueueSet::num_par_ids();
|
||||
|
||||
ConcurrentG1RefineThread *next = NULL;
|
||||
for (int i = _n_threads - 1; i >= 0; i--) {
|
||||
for (uint i = _n_threads - 1; i != UINT_MAX; i--) {
|
||||
ConcurrentG1RefineThread* t = new ConcurrentG1RefineThread(this, next, worker_id_offset, i);
|
||||
assert(t != NULL, "Conc refine should have been created");
|
||||
if (t->osthread() == NULL) {
|
||||
|
@ -87,7 +87,7 @@ void ConcurrentG1Refine::init() {
|
|||
|
||||
void ConcurrentG1Refine::stop() {
|
||||
if (_threads != NULL) {
|
||||
for (int i = 0; i < _n_threads; i++) {
|
||||
for (uint i = 0; i < _n_threads; i++) {
|
||||
_threads[i]->stop();
|
||||
}
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ void ConcurrentG1Refine::stop() {
|
|||
void ConcurrentG1Refine::reinitialize_threads() {
|
||||
reset_threshold_step();
|
||||
if (_threads != NULL) {
|
||||
for (int i = 0; i < _n_threads; i++) {
|
||||
for (uint i = 0; i < _n_threads; i++) {
|
||||
_threads[i]->initialize();
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ void ConcurrentG1Refine::reinitialize_threads() {
|
|||
|
||||
ConcurrentG1Refine::~ConcurrentG1Refine() {
|
||||
if (_threads != NULL) {
|
||||
for (int i = 0; i < _n_threads; i++) {
|
||||
for (uint i = 0; i < _n_threads; i++) {
|
||||
delete _threads[i];
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(ConcurrentG1RefineThread*, _threads, mtGC);
|
||||
|
@ -113,7 +113,7 @@ ConcurrentG1Refine::~ConcurrentG1Refine() {
|
|||
|
||||
void ConcurrentG1Refine::threads_do(ThreadClosure *tc) {
|
||||
if (_threads != NULL) {
|
||||
for (int i = 0; i < _n_threads; i++) {
|
||||
for (uint i = 0; i < _n_threads; i++) {
|
||||
tc->do_thread(_threads[i]);
|
||||
}
|
||||
}
|
||||
|
@ -121,20 +121,20 @@ void ConcurrentG1Refine::threads_do(ThreadClosure *tc) {
|
|||
|
||||
void ConcurrentG1Refine::worker_threads_do(ThreadClosure * tc) {
|
||||
if (_threads != NULL) {
|
||||
for (int i = 0; i < worker_thread_num(); i++) {
|
||||
for (uint i = 0; i < worker_thread_num(); i++) {
|
||||
tc->do_thread(_threads[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ConcurrentG1Refine::thread_num() {
|
||||
int n_threads = (G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads
|
||||
uint ConcurrentG1Refine::thread_num() {
|
||||
uint n_threads = (G1ConcRefinementThreads > 0) ? G1ConcRefinementThreads
|
||||
: ParallelGCThreads;
|
||||
return MAX2<int>(n_threads, 1);
|
||||
return MAX2<uint>(n_threads, 1);
|
||||
}
|
||||
|
||||
void ConcurrentG1Refine::print_worker_threads_on(outputStream* st) const {
|
||||
for (int i = 0; i < _n_threads; ++i) {
|
||||
for (uint i = 0; i < _n_threads; ++i) {
|
||||
_threads[i]->print_on(st);
|
||||
st->cr();
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ class DirtyCardQueue;
|
|||
|
||||
class ConcurrentG1Refine: public CHeapObj<mtGC> {
|
||||
ConcurrentG1RefineThread** _threads;
|
||||
int _n_threads;
|
||||
int _n_worker_threads;
|
||||
uint _n_threads;
|
||||
uint _n_worker_threads;
|
||||
/*
|
||||
* The value of the update buffer queue length falls into one of 3 zones:
|
||||
* green, yellow, red. If the value is in [0, green) nothing is
|
||||
|
@ -88,7 +88,7 @@ class ConcurrentG1Refine: public CHeapObj<mtGC> {
|
|||
// The RS sampling thread
|
||||
ConcurrentG1RefineThread * sampling_thread() const;
|
||||
|
||||
static int thread_num();
|
||||
static uint thread_num();
|
||||
|
||||
void print_worker_threads_on(outputStream* st) const;
|
||||
|
||||
|
@ -100,8 +100,8 @@ class ConcurrentG1Refine: public CHeapObj<mtGC> {
|
|||
int yellow_zone() const { return _yellow_zone; }
|
||||
int red_zone() const { return _red_zone; }
|
||||
|
||||
int total_thread_num() const { return _n_threads; }
|
||||
int worker_thread_num() const { return _n_worker_threads; }
|
||||
uint total_thread_num() const { return _n_threads; }
|
||||
uint worker_thread_num() const { return _n_worker_threads; }
|
||||
|
||||
int thread_threshold_step() const { return _thread_threshold_step; }
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
|
||||
ConcurrentG1RefineThread::
|
||||
ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
|
||||
int worker_id_offset, int worker_id) :
|
||||
uint worker_id_offset, uint worker_id) :
|
||||
ConcurrentGCThread(),
|
||||
_worker_id_offset(worker_id_offset),
|
||||
_worker_id(worker_id),
|
||||
|
|
|
@ -38,8 +38,8 @@ class ConcurrentG1RefineThread: public ConcurrentGCThread {
|
|||
|
||||
double _vtime_start; // Initial virtual time.
|
||||
double _vtime_accum; // Initial virtual time.
|
||||
int _worker_id;
|
||||
int _worker_id_offset;
|
||||
uint _worker_id;
|
||||
uint _worker_id_offset;
|
||||
|
||||
// The refinement threads collection is linked list. A predecessor can activate a successor
|
||||
// when the number of the rset update buffer crosses a certain threshold. A successor
|
||||
|
@ -71,7 +71,7 @@ public:
|
|||
virtual void run();
|
||||
// Constructor
|
||||
ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread* next,
|
||||
int worker_id_offset, int worker_id);
|
||||
uint worker_id_offset, uint worker_id);
|
||||
|
||||
void initialize();
|
||||
|
||||
|
|
|
@ -567,8 +567,8 @@ ConcurrentMark::ConcurrentMark(G1CollectedHeap* g1h, ReservedSpace heap_rs) :
|
|||
_root_regions.init(_g1h, this);
|
||||
|
||||
if (ConcGCThreads > ParallelGCThreads) {
|
||||
warning("Can't have more ConcGCThreads (" UINT32_FORMAT ") "
|
||||
"than ParallelGCThreads (" UINT32_FORMAT ").",
|
||||
warning("Can't have more ConcGCThreads (" UINTX_FORMAT ") "
|
||||
"than ParallelGCThreads (" UINTX_FORMAT ").",
|
||||
ConcGCThreads, ParallelGCThreads);
|
||||
return;
|
||||
}
|
||||
|
@ -1804,7 +1804,6 @@ class G1ParNoteEndTask;
|
|||
|
||||
class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
|
||||
G1CollectedHeap* _g1;
|
||||
int _worker_num;
|
||||
size_t _max_live_bytes;
|
||||
uint _regions_claimed;
|
||||
size_t _freed_bytes;
|
||||
|
@ -1817,10 +1816,9 @@ class G1NoteEndOfConcMarkClosure : public HeapRegionClosure {
|
|||
|
||||
public:
|
||||
G1NoteEndOfConcMarkClosure(G1CollectedHeap* g1,
|
||||
int worker_num,
|
||||
FreeRegionList* local_cleanup_list,
|
||||
HRRSCleanupTask* hrrs_cleanup_task) :
|
||||
_g1(g1), _worker_num(worker_num),
|
||||
_g1(g1),
|
||||
_max_live_bytes(0), _regions_claimed(0),
|
||||
_freed_bytes(0),
|
||||
_claimed_region_time(0.0), _max_region_time(0.0),
|
||||
|
@ -1893,7 +1891,7 @@ public:
|
|||
double start = os::elapsedTime();
|
||||
FreeRegionList local_cleanup_list("Local Cleanup List");
|
||||
HRRSCleanupTask hrrs_cleanup_task;
|
||||
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, worker_id, &local_cleanup_list,
|
||||
G1NoteEndOfConcMarkClosure g1_note_end(_g1h, &local_cleanup_list,
|
||||
&hrrs_cleanup_task);
|
||||
if (G1CollectedHeap::use_parallel_gc_threads()) {
|
||||
_g1h->heap_region_par_iterate_chunked(&g1_note_end, worker_id,
|
||||
|
@ -2145,7 +2143,7 @@ void ConcurrentMark::completeCleanup() {
|
|||
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
|
||||
_cleanup_list.verify_list();
|
||||
_cleanup_list.verify_optional();
|
||||
FreeRegionList tmp_free_list("Tmp Free List");
|
||||
|
||||
if (G1ConcRegionFreeingVerbose) {
|
||||
|
|
|
@ -34,12 +34,12 @@
|
|||
|
||||
bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl,
|
||||
bool consume,
|
||||
size_t worker_i) {
|
||||
uint worker_i) {
|
||||
bool res = true;
|
||||
if (_buf != NULL) {
|
||||
res = apply_closure_to_buffer(cl, _buf, _index, _sz,
|
||||
consume,
|
||||
(int) worker_i);
|
||||
worker_i);
|
||||
if (res && consume) _index = _sz;
|
||||
}
|
||||
return res;
|
||||
|
@ -49,7 +49,7 @@ bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl,
|
|||
void** buf,
|
||||
size_t index, size_t sz,
|
||||
bool consume,
|
||||
int worker_i) {
|
||||
uint worker_i) {
|
||||
if (cl == NULL) return true;
|
||||
for (size_t i = index; i < sz; i += oopSize) {
|
||||
int ind = byte_index_to_index((int)i);
|
||||
|
@ -79,8 +79,8 @@ DirtyCardQueueSet::DirtyCardQueueSet(bool notify_when_complete) :
|
|||
}
|
||||
|
||||
// Determines how many mutator threads can process the buffers in parallel.
|
||||
size_t DirtyCardQueueSet::num_par_ids() {
|
||||
return os::processor_count();
|
||||
uint DirtyCardQueueSet::num_par_ids() {
|
||||
return (uint)os::processor_count();
|
||||
}
|
||||
|
||||
void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock,
|
||||
|
@ -103,7 +103,7 @@ void DirtyCardQueueSet::set_closure(CardTableEntryClosure* closure) {
|
|||
}
|
||||
|
||||
void DirtyCardQueueSet::iterate_closure_all_threads(bool consume,
|
||||
size_t worker_i) {
|
||||
uint worker_i) {
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint.");
|
||||
for(JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
bool b = t->dirty_card_queue().apply_closure(_closure, consume);
|
||||
|
@ -126,11 +126,11 @@ bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
|
|||
|
||||
// We get the the number of any par_id that this thread
|
||||
// might have already claimed.
|
||||
int worker_i = thread->get_claimed_par_id();
|
||||
uint worker_i = thread->get_claimed_par_id();
|
||||
|
||||
// If worker_i is not -1 then the thread has already claimed
|
||||
// If worker_i is not UINT_MAX then the thread has already claimed
|
||||
// a par_id. We make note of it using the already_claimed value
|
||||
if (worker_i != -1) {
|
||||
if (worker_i != UINT_MAX) {
|
||||
already_claimed = true;
|
||||
} else {
|
||||
|
||||
|
@ -142,7 +142,7 @@ bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
|
|||
}
|
||||
|
||||
bool b = false;
|
||||
if (worker_i != -1) {
|
||||
if (worker_i != UINT_MAX) {
|
||||
b = DirtyCardQueue::apply_closure_to_buffer(_closure, buf, 0,
|
||||
_sz, true, worker_i);
|
||||
if (b) Atomic::inc(&_processed_buffers_mut);
|
||||
|
@ -154,8 +154,8 @@ bool DirtyCardQueueSet::mut_process_buffer(void** buf) {
|
|||
// we release the id
|
||||
_free_ids->release_par_id(worker_i);
|
||||
|
||||
// and set the claimed_id in the thread to -1
|
||||
thread->set_claimed_par_id(-1);
|
||||
// and set the claimed_id in the thread to UINT_MAX
|
||||
thread->set_claimed_par_id(UINT_MAX);
|
||||
}
|
||||
}
|
||||
return b;
|
||||
|
@ -186,7 +186,7 @@ DirtyCardQueueSet::get_completed_buffer(int stop_at) {
|
|||
|
||||
bool DirtyCardQueueSet::
|
||||
apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
|
||||
int worker_i,
|
||||
uint worker_i,
|
||||
BufferNode* nd) {
|
||||
if (nd != NULL) {
|
||||
void **buf = BufferNode::make_buffer_from_node(nd);
|
||||
|
@ -208,7 +208,7 @@ apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
|
|||
}
|
||||
|
||||
bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
|
||||
int worker_i,
|
||||
uint worker_i,
|
||||
int stop_at,
|
||||
bool during_pause) {
|
||||
assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause");
|
||||
|
@ -218,7 +218,7 @@ bool DirtyCardQueueSet::apply_closure_to_completed_buffer(CardTableEntryClosure*
|
|||
return res;
|
||||
}
|
||||
|
||||
bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i,
|
||||
bool DirtyCardQueueSet::apply_closure_to_completed_buffer(uint worker_i,
|
||||
int stop_at,
|
||||
bool during_pause) {
|
||||
return apply_closure_to_completed_buffer(_closure, worker_i,
|
||||
|
|
|
@ -36,7 +36,7 @@ class CardTableEntryClosure: public CHeapObj<mtGC> {
|
|||
public:
|
||||
// Process the card whose card table entry is "card_ptr". If returns
|
||||
// "false", terminate the iteration early.
|
||||
virtual bool do_card_ptr(jbyte* card_ptr, int worker_i = 0) = 0;
|
||||
virtual bool do_card_ptr(jbyte* card_ptr, uint worker_i = 0) = 0;
|
||||
};
|
||||
|
||||
// A ptrQueue whose elements are "oops", pointers to object heads.
|
||||
|
@ -53,7 +53,7 @@ public:
|
|||
// deletes processed entries from logs.
|
||||
bool apply_closure(CardTableEntryClosure* cl,
|
||||
bool consume = true,
|
||||
size_t worker_i = 0);
|
||||
uint worker_i = 0);
|
||||
|
||||
// Apply the closure to all elements of "buf", down to "index"
|
||||
// (inclusive.) If returns "false", then a closure application returned
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
static bool apply_closure_to_buffer(CardTableEntryClosure* cl,
|
||||
void** buf, size_t index, size_t sz,
|
||||
bool consume = true,
|
||||
int worker_i = 0);
|
||||
uint worker_i = 0);
|
||||
void **get_buf() { return _buf;}
|
||||
void set_buf(void **buf) {_buf = buf;}
|
||||
size_t get_index() { return _index;}
|
||||
|
@ -98,7 +98,7 @@ public:
|
|||
|
||||
// The number of parallel ids that can be claimed to allow collector or
|
||||
// mutator threads to do card-processing work.
|
||||
static size_t num_par_ids();
|
||||
static uint num_par_ids();
|
||||
|
||||
static void handle_zero_index_for_thread(JavaThread* t);
|
||||
|
||||
|
@ -115,7 +115,7 @@ public:
|
|||
// change in the future.) If "consume" is true, processed entries are
|
||||
// discarded.
|
||||
void iterate_closure_all_threads(bool consume = true,
|
||||
size_t worker_i = 0);
|
||||
uint worker_i = 0);
|
||||
|
||||
// If there exists some completed buffer, pop it, then apply the
|
||||
// registered closure to all its elements, nulling out those elements
|
||||
|
@ -124,7 +124,7 @@ public:
|
|||
// but is only partially completed before a "yield" happens, the
|
||||
// partially completed buffer (with its processed elements set to NULL)
|
||||
// is returned to the completed buffer set, and this call returns false.
|
||||
bool apply_closure_to_completed_buffer(int worker_i = 0,
|
||||
bool apply_closure_to_completed_buffer(uint worker_i = 0,
|
||||
int stop_at = 0,
|
||||
bool during_pause = false);
|
||||
|
||||
|
@ -136,13 +136,13 @@ public:
|
|||
// partially completed buffer (with its processed elements set to NULL)
|
||||
// is returned to the completed buffer set, and this call returns false.
|
||||
bool apply_closure_to_completed_buffer(CardTableEntryClosure* cl,
|
||||
int worker_i = 0,
|
||||
uint worker_i = 0,
|
||||
int stop_at = 0,
|
||||
bool during_pause = false);
|
||||
|
||||
// Helper routine for the above.
|
||||
bool apply_closure_to_completed_buffer_helper(CardTableEntryClosure* cl,
|
||||
int worker_i,
|
||||
uint worker_i,
|
||||
BufferNode* nd);
|
||||
|
||||
BufferNode* get_completed_buffer(int stop_at);
|
||||
|
|
|
@ -304,26 +304,26 @@ void G1BlockOffsetArray::check_all_cards(size_t start_card, size_t end_card) con
|
|||
if (c - start_card > BlockOffsetArray::power_to_cards_back(1)) {
|
||||
guarantee(entry > N_words,
|
||||
err_msg("Should be in logarithmic region - "
|
||||
"entry: " UINT32_FORMAT ", "
|
||||
"_array->offset_array(c): " UINT32_FORMAT ", "
|
||||
"N_words: " UINT32_FORMAT,
|
||||
entry, _array->offset_array(c), N_words));
|
||||
"entry: %u, "
|
||||
"_array->offset_array(c): %u, "
|
||||
"N_words: %u",
|
||||
(uint)entry, (uint)_array->offset_array(c), (uint)N_words));
|
||||
}
|
||||
size_t backskip = BlockOffsetArray::entry_to_cards_back(entry);
|
||||
size_t landing_card = c - backskip;
|
||||
guarantee(landing_card >= (start_card - 1), "Inv");
|
||||
if (landing_card >= start_card) {
|
||||
guarantee(_array->offset_array(landing_card) <= entry,
|
||||
err_msg("Monotonicity - landing_card offset: " UINT32_FORMAT ", "
|
||||
"entry: " UINT32_FORMAT,
|
||||
_array->offset_array(landing_card), entry));
|
||||
err_msg("Monotonicity - landing_card offset: %u, "
|
||||
"entry: %u",
|
||||
(uint)_array->offset_array(landing_card), (uint)entry));
|
||||
} else {
|
||||
guarantee(landing_card == start_card - 1, "Tautology");
|
||||
// Note that N_words is the maximum offset value
|
||||
guarantee(_array->offset_array(landing_card) <= N_words,
|
||||
err_msg("landing card offset: " UINT32_FORMAT ", "
|
||||
"N_words: " UINT32_FORMAT,
|
||||
_array->offset_array(landing_card), N_words));
|
||||
err_msg("landing card offset: %u, "
|
||||
"N_words: %u",
|
||||
(uint)_array->offset_array(landing_card), (uint)N_words));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -554,21 +554,20 @@ void G1BlockOffsetArray::alloc_block_work2(HeapWord** threshold_, size_t* index_
|
|||
(_array->offset_array(orig_index) > 0 &&
|
||||
_array->offset_array(orig_index) <= N_words),
|
||||
err_msg("offset array should have been set - "
|
||||
"orig_index offset: " UINT32_FORMAT ", "
|
||||
"orig_index offset: %u, "
|
||||
"blk_start: " PTR_FORMAT ", "
|
||||
"boundary: " PTR_FORMAT,
|
||||
_array->offset_array(orig_index),
|
||||
(uint)_array->offset_array(orig_index),
|
||||
blk_start, boundary));
|
||||
for (size_t j = orig_index + 1; j <= end_index; j++) {
|
||||
assert(_array->offset_array(j) > 0 &&
|
||||
_array->offset_array(j) <=
|
||||
(u_char) (N_words+BlockOffsetArray::N_powers-1),
|
||||
err_msg("offset array should have been set - "
|
||||
UINT32_FORMAT " not > 0 OR "
|
||||
UINT32_FORMAT " not <= " UINT32_FORMAT,
|
||||
_array->offset_array(j),
|
||||
_array->offset_array(j),
|
||||
(u_char) (N_words+BlockOffsetArray::N_powers-1)));
|
||||
"%u not > 0 OR %u not <= %u",
|
||||
(uint) _array->offset_array(j),
|
||||
(uint) _array->offset_array(j),
|
||||
(uint) (N_words+BlockOffsetArray::N_powers-1)));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -146,8 +146,8 @@ private:
|
|||
void check_offset(size_t offset, const char* msg) const {
|
||||
assert(offset <= N_words,
|
||||
err_msg("%s - "
|
||||
"offset: " UINT32_FORMAT", N_words: " UINT32_FORMAT,
|
||||
msg, offset, N_words));
|
||||
"offset: " SIZE_FORMAT", N_words: %u",
|
||||
msg, offset, (uint)N_words));
|
||||
}
|
||||
|
||||
// Bounds checking accessors:
|
||||
|
|
|
@ -102,7 +102,7 @@ public:
|
|||
ConcurrentG1Refine* cg1r) :
|
||||
_sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true)
|
||||
{}
|
||||
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
|
||||
bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
|
||||
bool oops_into_cset = _g1rs->refine_card(card_ptr, worker_i, false);
|
||||
// This path is executed by the concurrent refine or mutator threads,
|
||||
// concurrently, and so we do not care if card_ptr contains references
|
||||
|
@ -131,7 +131,7 @@ public:
|
|||
{
|
||||
for (int i = 0; i < 256; i++) _histo[i] = 0;
|
||||
}
|
||||
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
|
||||
bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
|
||||
if (_g1h->is_in_reserved(_ctbs->addr_for(card_ptr))) {
|
||||
_calls++;
|
||||
unsigned char* ujb = (unsigned char*)card_ptr;
|
||||
|
@ -160,7 +160,7 @@ public:
|
|||
RedirtyLoggedCardTableEntryClosure() :
|
||||
_calls(0), _g1h(G1CollectedHeap::heap()), _ctbs(_g1h->g1_barrier_set()) {}
|
||||
|
||||
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
|
||||
bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
|
||||
if (_g1h->is_in_reserved(_ctbs->addr_for(card_ptr))) {
|
||||
_calls++;
|
||||
*card_ptr = 0;
|
||||
|
@ -1288,7 +1288,7 @@ bool G1CollectedHeap::do_collection(bool explicit_gc,
|
|||
print_heap_before_gc();
|
||||
trace_heap_before_gc(gc_tracer);
|
||||
|
||||
size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
|
||||
size_t metadata_prev_used = MetaspaceAux::used_bytes();
|
||||
|
||||
verify_region_sets_optional();
|
||||
|
||||
|
@ -2314,7 +2314,7 @@ void G1CollectedHeap::check_gc_time_stamps() {
|
|||
void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl,
|
||||
DirtyCardQueue* into_cset_dcq,
|
||||
bool concurrent,
|
||||
int worker_i) {
|
||||
uint worker_i) {
|
||||
// Clean cards in the hot card cache
|
||||
G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache();
|
||||
hot_card_cache->drain(worker_i, g1_rem_set(), into_cset_dcq);
|
||||
|
@ -2843,7 +2843,7 @@ void G1CollectedHeap::clear_cset_start_regions() {
|
|||
|
||||
// Given the id of a worker, obtain or calculate a suitable
|
||||
// starting region for iterating over the current collection set.
|
||||
HeapRegion* G1CollectedHeap::start_cset_region_for_worker(int worker_i) {
|
||||
HeapRegion* G1CollectedHeap::start_cset_region_for_worker(uint worker_i) {
|
||||
assert(get_gc_time_stamp() > 0, "should have been updated by now");
|
||||
|
||||
HeapRegion* result = NULL;
|
||||
|
@ -5103,7 +5103,7 @@ g1_process_strong_roots(bool is_scavenging,
|
|||
OopClosure* scan_non_heap_roots,
|
||||
OopsInHeapRegionClosure* scan_rs,
|
||||
G1KlassScanClosure* scan_klasses,
|
||||
int worker_i) {
|
||||
uint worker_i) {
|
||||
|
||||
// First scan the strong roots
|
||||
double ext_roots_start = os::elapsedTime();
|
||||
|
@ -5207,10 +5207,10 @@ public:
|
|||
|
||||
~G1StringSymbolTableUnlinkTask() {
|
||||
guarantee(!_process_strings || !_do_in_parallel || StringTable::parallel_claimed_index() >= _initial_string_table_size,
|
||||
err_msg("claim value "INT32_FORMAT" after unlink less than initial string table size "INT32_FORMAT,
|
||||
err_msg("claim value %d after unlink less than initial string table size %d",
|
||||
StringTable::parallel_claimed_index(), _initial_string_table_size));
|
||||
guarantee(!_process_symbols || !_do_in_parallel || SymbolTable::parallel_claimed_index() >= _initial_symbol_table_size,
|
||||
err_msg("claim value "INT32_FORMAT" after unlink less than initial symbol table size "INT32_FORMAT,
|
||||
err_msg("claim value %d after unlink less than initial symbol table size %d",
|
||||
SymbolTable::parallel_claimed_index(), _initial_symbol_table_size));
|
||||
}
|
||||
|
||||
|
@ -5275,7 +5275,7 @@ void G1CollectedHeap::unlink_string_and_symbol_table(BoolObjectClosure* is_alive
|
|||
|
||||
class RedirtyLoggedCardTableEntryFastClosure : public CardTableEntryClosure {
|
||||
public:
|
||||
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
|
||||
bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
|
||||
*card_ptr = CardTableModRefBS::dirty_card_val();
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -845,7 +845,7 @@ protected:
|
|||
OopClosure* scan_non_heap_roots,
|
||||
OopsInHeapRegionClosure* scan_rs,
|
||||
G1KlassScanClosure* scan_klasses,
|
||||
int worker_i);
|
||||
uint worker_i);
|
||||
|
||||
// Notifies all the necessary spaces that the committed space has
|
||||
// been updated (either expanded or shrunk). It should be called
|
||||
|
@ -1139,7 +1139,7 @@ public:
|
|||
|
||||
void iterate_dirty_card_closure(CardTableEntryClosure* cl,
|
||||
DirtyCardQueue* into_cset_dcq,
|
||||
bool concurrent, int worker_i);
|
||||
bool concurrent, uint worker_i);
|
||||
|
||||
// The shared block offset table array.
|
||||
G1BlockOffsetSharedArray* bot_shared() const { return _bot_shared; }
|
||||
|
@ -1370,7 +1370,7 @@ public:
|
|||
|
||||
// Given the id of a worker, obtain or calculate a suitable
|
||||
// starting region for iterating over the current collection set.
|
||||
HeapRegion* start_cset_region_for_worker(int worker_i);
|
||||
HeapRegion* start_cset_region_for_worker(uint worker_i);
|
||||
|
||||
// This is a convenience method that is used by the
|
||||
// HeapRegionIterator classes to calculate the starting region for
|
||||
|
|
|
@ -1204,7 +1204,7 @@ void G1CollectorPolicy::record_heap_size_info_at_start(bool full) {
|
|||
(_young_list_target_length * HeapRegion::GrainBytes) - _survivor_used_bytes_before_gc;
|
||||
|
||||
if (full) {
|
||||
_metaspace_used_bytes_before_gc = MetaspaceAux::allocated_used_bytes();
|
||||
_metaspace_used_bytes_before_gc = MetaspaceAux::used_bytes();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -147,7 +147,7 @@ template <class T>
|
|||
void WorkerDataArray<T>::verify() {
|
||||
for (uint i = 0; i < _length; i++) {
|
||||
assert(_data[i] != _uninitialized,
|
||||
err_msg("Invalid data for worker " UINT32_FORMAT ", data: %lf, uninitialized: %lf",
|
||||
err_msg("Invalid data for worker %u, data: %lf, uninitialized: %lf",
|
||||
i, (double)_data[i], (double)_uninitialized));
|
||||
}
|
||||
}
|
||||
|
@ -246,8 +246,8 @@ void G1GCPhaseTimes::print_stats(int level, const char* str, double value) {
|
|||
LineBuffer(level).append_and_print_cr("[%s: %.1lf ms]", str, value);
|
||||
}
|
||||
|
||||
void G1GCPhaseTimes::print_stats(int level, const char* str, double value, int workers) {
|
||||
LineBuffer(level).append_and_print_cr("[%s: %.1lf ms, GC Workers: %d]", str, value, workers);
|
||||
void G1GCPhaseTimes::print_stats(int level, const char* str, double value, uint workers) {
|
||||
LineBuffer(level).append_and_print_cr("[%s: %.1lf ms, GC Workers: %u]", str, value, workers);
|
||||
}
|
||||
|
||||
double G1GCPhaseTimes::accounted_time_ms() {
|
||||
|
|
|
@ -161,7 +161,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
|||
|
||||
// Helper methods for detailed logging
|
||||
void print_stats(int level, const char* str, double value);
|
||||
void print_stats(int level, const char* str, double value, int workers);
|
||||
void print_stats(int level, const char* str, double value, uint workers);
|
||||
|
||||
public:
|
||||
G1GCPhaseTimes(uint max_gc_threads);
|
||||
|
|
|
@ -44,9 +44,9 @@ void G1HotCardCache::initialize() {
|
|||
_hot_cache_idx = 0;
|
||||
|
||||
// For refining the cards in the hot cache in parallel
|
||||
int n_workers = (ParallelGCThreads > 0 ?
|
||||
uint n_workers = (ParallelGCThreads > 0 ?
|
||||
_g1h->workers()->total_workers() : 1);
|
||||
_hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / n_workers);
|
||||
_hot_cache_par_chunk_size = MAX2(1, _hot_cache_size / (int)n_workers);
|
||||
_hot_cache_par_claimed_idx = 0;
|
||||
|
||||
_card_counts.initialize();
|
||||
|
@ -89,7 +89,7 @@ jbyte* G1HotCardCache::insert(jbyte* card_ptr) {
|
|||
return res;
|
||||
}
|
||||
|
||||
void G1HotCardCache::drain(int worker_i,
|
||||
void G1HotCardCache::drain(uint worker_i,
|
||||
G1RemSet* g1rs,
|
||||
DirtyCardQueue* into_cset_dcq) {
|
||||
if (!default_use_cache()) {
|
||||
|
@ -122,8 +122,8 @@ void G1HotCardCache::drain(int worker_i,
|
|||
// RSet updating while within an evacuation pause.
|
||||
// In this case worker_i should be the id of a GC worker thread
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "Should be at a safepoint");
|
||||
assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads),
|
||||
err_msg("incorrect worker id: "INT32_FORMAT, worker_i));
|
||||
assert(worker_i < (ParallelGCThreads == 0 ? 1 : ParallelGCThreads),
|
||||
err_msg("incorrect worker id: %u", worker_i));
|
||||
|
||||
into_cset_dcq->enqueue(card_ptr);
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ class G1HotCardCache: public CHeapObj<mtGC> {
|
|||
|
||||
// Refine the cards that have delayed as a result of
|
||||
// being in the cache.
|
||||
void drain(int worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq);
|
||||
void drain(uint worker_i, G1RemSet* g1rs, DirtyCardQueue* into_cset_dcq);
|
||||
|
||||
// Set up for parallel processing of the cards in the hot cache
|
||||
void reset_hot_cache_claimed_index() {
|
||||
|
|
|
@ -234,14 +234,14 @@ class G1UpdateRSOrPushRefOopClosure: public ExtendedOopClosure {
|
|||
HeapRegion* _from;
|
||||
OopsInHeapRegionClosure* _push_ref_cl;
|
||||
bool _record_refs_into_cset;
|
||||
int _worker_i;
|
||||
uint _worker_i;
|
||||
|
||||
public:
|
||||
G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h,
|
||||
G1RemSet* rs,
|
||||
OopsInHeapRegionClosure* push_ref_cl,
|
||||
bool record_refs_into_cset,
|
||||
int worker_i = 0);
|
||||
uint worker_i = 0);
|
||||
|
||||
void set_from(HeapRegion* from) {
|
||||
assert(from != NULL, "from region must be non-NULL");
|
||||
|
|
|
@ -113,14 +113,14 @@ class ScanRSClosure : public HeapRegionClosure {
|
|||
G1SATBCardTableModRefBS *_ct_bs;
|
||||
|
||||
double _strong_code_root_scan_time_sec;
|
||||
int _worker_i;
|
||||
uint _worker_i;
|
||||
int _block_size;
|
||||
bool _try_claimed;
|
||||
|
||||
public:
|
||||
ScanRSClosure(OopsInHeapRegionClosure* oc,
|
||||
CodeBlobToOopClosure* code_root_cl,
|
||||
int worker_i) :
|
||||
uint worker_i) :
|
||||
_oc(oc),
|
||||
_code_root_cl(code_root_cl),
|
||||
_strong_code_root_scan_time_sec(0.0),
|
||||
|
@ -162,7 +162,7 @@ public:
|
|||
|
||||
void printCard(HeapRegion* card_region, size_t card_index,
|
||||
HeapWord* card_start) {
|
||||
gclog_or_tty->print_cr("T %d Region [" PTR_FORMAT ", " PTR_FORMAT ") "
|
||||
gclog_or_tty->print_cr("T %u Region [" PTR_FORMAT ", " PTR_FORMAT ") "
|
||||
"RS names card %p: "
|
||||
"[" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
_worker_i,
|
||||
|
@ -241,7 +241,7 @@ public:
|
|||
|
||||
void G1RemSet::scanRS(OopsInHeapRegionClosure* oc,
|
||||
CodeBlobToOopClosure* code_root_cl,
|
||||
int worker_i) {
|
||||
uint worker_i) {
|
||||
double rs_time_start = os::elapsedTime();
|
||||
HeapRegion *startRegion = _g1->start_cset_region_for_worker(worker_i);
|
||||
|
||||
|
@ -274,13 +274,13 @@ public:
|
|||
DirtyCardQueue* into_cset_dcq) :
|
||||
_g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq)
|
||||
{}
|
||||
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
|
||||
bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
|
||||
// The only time we care about recording cards that
|
||||
// contain references that point into the collection set
|
||||
// is during RSet updating within an evacuation pause.
|
||||
// In this case worker_i should be the id of a GC worker thread.
|
||||
assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause");
|
||||
assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker");
|
||||
assert(worker_i < (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker");
|
||||
|
||||
if (_g1rs->refine_card(card_ptr, worker_i, true)) {
|
||||
// 'card_ptr' contains references that point into the collection
|
||||
|
@ -295,7 +295,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) {
|
||||
void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i) {
|
||||
double start = os::elapsedTime();
|
||||
// Apply the given closure to all remaining log entries.
|
||||
RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq);
|
||||
|
@ -320,14 +320,14 @@ void G1RemSet::cleanupHRRS() {
|
|||
|
||||
void G1RemSet::oops_into_collection_set_do(OopsInHeapRegionClosure* oc,
|
||||
CodeBlobToOopClosure* code_root_cl,
|
||||
int worker_i) {
|
||||
uint worker_i) {
|
||||
#if CARD_REPEAT_HISTO
|
||||
ct_freq_update_histo_and_reset();
|
||||
#endif
|
||||
|
||||
// We cache the value of 'oc' closure into the appropriate slot in the
|
||||
// _cset_rs_update_cl for this worker
|
||||
assert(worker_i < (int)n_workers(), "sanity");
|
||||
assert(worker_i < n_workers(), "sanity");
|
||||
_cset_rs_update_cl[worker_i] = oc;
|
||||
|
||||
// A DirtyCardQueue that is used to hold cards containing references
|
||||
|
@ -399,7 +399,7 @@ public:
|
|||
_g1(g1), _ct_bs(bs)
|
||||
{ }
|
||||
|
||||
bool do_card_ptr(jbyte* card_ptr, int worker_i) {
|
||||
bool do_card_ptr(jbyte* card_ptr, uint worker_i) {
|
||||
// Construct the region representing the card.
|
||||
HeapWord* start = _ct_bs->addr_for(card_ptr);
|
||||
// And find the region containing it.
|
||||
|
@ -543,7 +543,7 @@ G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h,
|
|||
G1RemSet* rs,
|
||||
OopsInHeapRegionClosure* push_ref_cl,
|
||||
bool record_refs_into_cset,
|
||||
int worker_i) :
|
||||
uint worker_i) :
|
||||
_g1(g1h), _g1_rem_set(rs), _from(NULL),
|
||||
_record_refs_into_cset(record_refs_into_cset),
|
||||
_push_ref_cl(push_ref_cl), _worker_i(worker_i) { }
|
||||
|
@ -552,7 +552,7 @@ G1UpdateRSOrPushRefOopClosure(G1CollectedHeap* g1h,
|
|||
// into the collection set, if we're checking for such references;
|
||||
// false otherwise.
|
||||
|
||||
bool G1RemSet::refine_card(jbyte* card_ptr, int worker_i,
|
||||
bool G1RemSet::refine_card(jbyte* card_ptr, uint worker_i,
|
||||
bool check_for_refs_into_cset) {
|
||||
|
||||
// If the card is no longer dirty, nothing to do.
|
||||
|
|
|
@ -97,7 +97,7 @@ public:
|
|||
// In the sequential case this param will be ignored.
|
||||
void oops_into_collection_set_do(OopsInHeapRegionClosure* blk,
|
||||
CodeBlobToOopClosure* code_root_cl,
|
||||
int worker_i);
|
||||
uint worker_i);
|
||||
|
||||
// Prepare for and cleanup after an oops_into_collection_set_do
|
||||
// call. Must call each of these once before and after (in sequential
|
||||
|
@ -109,9 +109,9 @@ public:
|
|||
|
||||
void scanRS(OopsInHeapRegionClosure* oc,
|
||||
CodeBlobToOopClosure* code_root_cl,
|
||||
int worker_i);
|
||||
uint worker_i);
|
||||
|
||||
void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i);
|
||||
void updateRS(DirtyCardQueue* into_cset_dcq, uint worker_i);
|
||||
|
||||
CardTableModRefBS* ct_bs() { return _ct_bs; }
|
||||
size_t cardsScanned() { return _total_cards_scanned; }
|
||||
|
@ -138,7 +138,7 @@ public:
|
|||
// if the given card contains oops that have references into the
|
||||
// current collection set.
|
||||
virtual bool refine_card(jbyte* card_ptr,
|
||||
int worker_i,
|
||||
uint worker_i,
|
||||
bool check_for_refs_into_cset);
|
||||
|
||||
// Print accumulated summary info from the start of the VM.
|
||||
|
@ -171,12 +171,12 @@ public:
|
|||
class UpdateRSOopClosure: public ExtendedOopClosure {
|
||||
HeapRegion* _from;
|
||||
G1RemSet* _rs;
|
||||
int _worker_i;
|
||||
uint _worker_i;
|
||||
|
||||
template <class T> void do_oop_work(T* p);
|
||||
|
||||
public:
|
||||
UpdateRSOopClosure(G1RemSet* rs, int worker_i = 0) :
|
||||
UpdateRSOopClosure(G1RemSet* rs, uint worker_i = 0) :
|
||||
_from(NULL), _rs(rs), _worker_i(worker_i)
|
||||
{}
|
||||
|
||||
|
|
|
@ -390,7 +390,7 @@ void FromCardCache::shrink(uint new_num_regions) {
|
|||
void FromCardCache::print(outputStream* out) {
|
||||
for (uint i = 0; i < HeapRegionRemSet::num_par_rem_sets(); i++) {
|
||||
for (uint j = 0; j < _max_regions; j++) {
|
||||
out->print_cr("_from_card_cache["UINT32_FORMAT"]["UINT32_FORMAT"] = "INT32_FORMAT".",
|
||||
out->print_cr("_from_card_cache[%u][%u] = %d.",
|
||||
i, j, at(i, j));
|
||||
}
|
||||
}
|
||||
|
@ -430,7 +430,7 @@ void OtherRegionsTable::add_reference(OopOrNarrowOopStar from, int tid) {
|
|||
int from_card = (int)(uintptr_t(from) >> CardTableModRefBS::card_shift);
|
||||
|
||||
if (G1TraceHeapRegionRememberedSet) {
|
||||
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = "INT32_FORMAT")",
|
||||
gclog_or_tty->print_cr("Table for [" PTR_FORMAT "...): card %d (cache = %d)",
|
||||
hr()->bottom(), from_card,
|
||||
FromCardCache::at((uint)tid, cur_hrs_ind));
|
||||
}
|
||||
|
@ -853,13 +853,13 @@ OtherRegionsTable::do_cleanup_work(HRRSCleanupTask* hrrs_cleanup_task) {
|
|||
// This can be done by either mutator threads together with the
|
||||
// concurrent refinement threads or GC threads.
|
||||
uint HeapRegionRemSet::num_par_rem_sets() {
|
||||
return (uint)MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), ParallelGCThreads);
|
||||
return MAX2(DirtyCardQueueSet::num_par_ids() + ConcurrentG1Refine::thread_num(), (uint)ParallelGCThreads);
|
||||
}
|
||||
|
||||
HeapRegionRemSet::HeapRegionRemSet(G1BlockOffsetSharedArray* bosa,
|
||||
HeapRegion* hr)
|
||||
: _bosa(bosa),
|
||||
_m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #"UINT32_FORMAT, hr->hrs_index()), true),
|
||||
_m(Mutex::leaf, FormatBuffer<128>("HeapRegionRemSet lock #%u", hr->hrs_index()), true),
|
||||
_code_roots(), _other_regions(hr, &_m) {
|
||||
reset_for_par_iteration();
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
inline void HeapRegionSetBase::add(HeapRegion* hr) {
|
||||
check_mt_safety();
|
||||
assert(hr->containing_set() == NULL, hrs_ext_msg(this, "should not already have a containing set %u"));
|
||||
assert(hr->next() == NULL, hrs_ext_msg(this, "should not already be linked"));
|
||||
assert(hr->next() == NULL && hr->prev() == NULL, hrs_ext_msg(this, "should not already be linked"));
|
||||
|
||||
_count.increment(1u, hr->capacity());
|
||||
hr->set_containing_set(this);
|
||||
|
@ -40,7 +40,7 @@ inline void HeapRegionSetBase::add(HeapRegion* hr) {
|
|||
inline void HeapRegionSetBase::remove(HeapRegion* hr) {
|
||||
check_mt_safety();
|
||||
verify_region(hr);
|
||||
assert(hr->next() == NULL, hrs_ext_msg(this, "should already be unlinked"));
|
||||
assert(hr->next() == NULL && hr->prev() == NULL, hrs_ext_msg(this, "should already be unlinked"));
|
||||
|
||||
hr->set_containing_set(NULL);
|
||||
assert(_count.length() > 0, hrs_ext_msg(this, "pre-condition"));
|
||||
|
|
|
@ -290,7 +290,7 @@ void SATBMarkQueueSet::iterate_closure_all_threads() {
|
|||
shared_satb_queue()->apply_closure_and_empty(_closure);
|
||||
}
|
||||
|
||||
void SATBMarkQueueSet::par_iterate_closure_all_threads(int worker) {
|
||||
void SATBMarkQueueSet::par_iterate_closure_all_threads(uint worker) {
|
||||
SharedHeap* sh = SharedHeap::heap();
|
||||
int parity = sh->strong_roots_parity();
|
||||
|
||||
|
@ -315,7 +315,7 @@ void SATBMarkQueueSet::par_iterate_closure_all_threads(int worker) {
|
|||
}
|
||||
|
||||
bool SATBMarkQueueSet::apply_closure_to_completed_buffer_work(bool par,
|
||||
int worker) {
|
||||
uint worker) {
|
||||
BufferNode* nd = NULL;
|
||||
{
|
||||
MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
|
||||
|
|
|
@ -84,7 +84,7 @@ class SATBMarkQueueSet: public PtrQueueSet {
|
|||
// Utility function to support sequential and parallel versions. If
|
||||
// "par" is true, then "worker" is the par thread id; if "false", worker
|
||||
// is ignored.
|
||||
bool apply_closure_to_completed_buffer_work(bool par, int worker);
|
||||
bool apply_closure_to_completed_buffer_work(bool par, uint worker);
|
||||
|
||||
#ifdef ASSERT
|
||||
void dump_active_states(bool expected_active);
|
||||
|
@ -124,7 +124,7 @@ public:
|
|||
// be called serially and at a safepoint.
|
||||
void iterate_closure_all_threads();
|
||||
// Parallel version of the above.
|
||||
void par_iterate_closure_all_threads(int worker);
|
||||
void par_iterate_closure_all_threads(uint worker);
|
||||
|
||||
// If there exists some completed buffer, pop it, then apply the
|
||||
// registered closure to all its elements, and return true. If no
|
||||
|
@ -133,7 +133,7 @@ public:
|
|||
return apply_closure_to_completed_buffer_work(false, 0);
|
||||
}
|
||||
// Parallel version of the above.
|
||||
bool par_apply_closure_to_completed_buffer(int worker) {
|
||||
bool par_apply_closure_to_completed_buffer(uint worker) {
|
||||
return apply_closure_to_completed_buffer_work(true, worker);
|
||||
}
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ bool PSMarkSweep::invoke_no_policy(bool clear_all_softrefs) {
|
|||
size_t prev_used = heap->used();
|
||||
|
||||
// Capture metadata size before collection for sizing.
|
||||
size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
|
||||
size_t metadata_prev_used = MetaspaceAux::used_bytes();
|
||||
|
||||
// For PrintGCDetails
|
||||
size_t old_gen_prev_used = old_gen->used_in_bytes();
|
||||
|
|
|
@ -928,7 +928,7 @@ public:
|
|||
_heap_used = heap->used();
|
||||
_young_gen_used = heap->young_gen()->used_in_bytes();
|
||||
_old_gen_used = heap->old_gen()->used_in_bytes();
|
||||
_metadata_used = MetaspaceAux::allocated_used_bytes();
|
||||
_metadata_used = MetaspaceAux::used_bytes();
|
||||
};
|
||||
|
||||
size_t heap_used() const { return _heap_used; }
|
||||
|
|
|
@ -62,16 +62,16 @@ public:
|
|||
};
|
||||
|
||||
class MetaspaceSizes : public StackObj {
|
||||
size_t _capacity;
|
||||
size_t _committed;
|
||||
size_t _used;
|
||||
size_t _reserved;
|
||||
|
||||
public:
|
||||
MetaspaceSizes() : _capacity(0), _used(0), _reserved(0) {}
|
||||
MetaspaceSizes(size_t capacity, size_t used, size_t reserved) :
|
||||
_capacity(capacity), _used(used), _reserved(reserved) {}
|
||||
MetaspaceSizes() : _committed(0), _used(0), _reserved(0) {}
|
||||
MetaspaceSizes(size_t committed, size_t used, size_t reserved) :
|
||||
_committed(committed), _used(used), _reserved(reserved) {}
|
||||
|
||||
size_t capacity() const { return _capacity; }
|
||||
size_t committed() const { return _committed; }
|
||||
size_t used() const { return _used; }
|
||||
size_t reserved() const { return _reserved; }
|
||||
};
|
||||
|
|
|
@ -258,7 +258,7 @@ void GCTracer::send_gc_heap_summary_event(GCWhen::Type when, const GCHeapSummary
|
|||
static TraceStructMetaspaceSizes to_trace_struct(const MetaspaceSizes& sizes) {
|
||||
TraceStructMetaspaceSizes meta_sizes;
|
||||
|
||||
meta_sizes.set_capacity(sizes.capacity());
|
||||
meta_sizes.set_committed(sizes.committed());
|
||||
meta_sizes.set_used(sizes.used());
|
||||
meta_sizes.set_reserved(sizes.reserved());
|
||||
|
||||
|
|
|
@ -85,16 +85,16 @@ GCHeapSummary CollectedHeap::create_heap_summary() {
|
|||
|
||||
MetaspaceSummary CollectedHeap::create_metaspace_summary() {
|
||||
const MetaspaceSizes meta_space(
|
||||
MetaspaceAux::allocated_capacity_bytes(),
|
||||
MetaspaceAux::allocated_used_bytes(),
|
||||
MetaspaceAux::committed_bytes(),
|
||||
MetaspaceAux::used_bytes(),
|
||||
MetaspaceAux::reserved_bytes());
|
||||
const MetaspaceSizes data_space(
|
||||
MetaspaceAux::allocated_capacity_bytes(Metaspace::NonClassType),
|
||||
MetaspaceAux::allocated_used_bytes(Metaspace::NonClassType),
|
||||
MetaspaceAux::committed_bytes(Metaspace::NonClassType),
|
||||
MetaspaceAux::used_bytes(Metaspace::NonClassType),
|
||||
MetaspaceAux::reserved_bytes(Metaspace::NonClassType));
|
||||
const MetaspaceSizes class_space(
|
||||
MetaspaceAux::allocated_capacity_bytes(Metaspace::ClassType),
|
||||
MetaspaceAux::allocated_used_bytes(Metaspace::ClassType),
|
||||
MetaspaceAux::committed_bytes(Metaspace::ClassType),
|
||||
MetaspaceAux::used_bytes(Metaspace::ClassType),
|
||||
MetaspaceAux::reserved_bytes(Metaspace::ClassType));
|
||||
|
||||
const MetaspaceChunkFreeListSummary& ms_chunk_free_list_summary =
|
||||
|
|
|
@ -257,6 +257,12 @@ void GenCollectorPolicy::assert_size_info() {
|
|||
assert(_min_gen0_size % _gen_alignment == 0, "_min_gen0_size alignment");
|
||||
assert(_initial_gen0_size % _gen_alignment == 0, "_initial_gen0_size alignment");
|
||||
assert(_max_gen0_size % _gen_alignment == 0, "_max_gen0_size alignment");
|
||||
assert(_min_gen0_size <= bound_minus_alignment(_min_gen0_size, _min_heap_byte_size),
|
||||
"Ergonomics made minimum young generation larger than minimum heap");
|
||||
assert(_initial_gen0_size <= bound_minus_alignment(_initial_gen0_size, _initial_heap_byte_size),
|
||||
"Ergonomics made initial young generation larger than initial heap");
|
||||
assert(_max_gen0_size <= bound_minus_alignment(_max_gen0_size, _max_heap_byte_size),
|
||||
"Ergonomics made maximum young generation lager than maximum heap");
|
||||
}
|
||||
|
||||
void TwoGenerationCollectorPolicy::assert_size_info() {
|
||||
|
@ -267,6 +273,9 @@ void TwoGenerationCollectorPolicy::assert_size_info() {
|
|||
assert(_max_gen1_size % _gen_alignment == 0, "_max_gen1_size alignment");
|
||||
assert(_initial_gen1_size % _gen_alignment == 0, "_initial_gen1_size alignment");
|
||||
assert(_max_heap_byte_size <= (_max_gen0_size + _max_gen1_size), "Total maximum heap sizes must be sum of generation maximum sizes");
|
||||
assert(_min_gen0_size + _min_gen1_size <= _min_heap_byte_size, "Minimum generation sizes exceed minimum heap size");
|
||||
assert(_initial_gen0_size + _initial_gen1_size == _initial_heap_byte_size, "Initial generation sizes should match initial heap size");
|
||||
assert(_max_gen0_size + _max_gen1_size == _max_heap_byte_size, "Maximum generation sizes should match maximum heap size");
|
||||
}
|
||||
#endif // ASSERT
|
||||
|
||||
|
@ -303,20 +312,26 @@ void GenCollectorPolicy::initialize_flags() {
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure NewSize allows an old generation to fit even if set on the command line
|
||||
if (FLAG_IS_CMDLINE(NewSize) && NewSize >= _initial_heap_byte_size) {
|
||||
warning("NewSize was set larger than initial heap size, will use initial heap size.");
|
||||
NewSize = bound_minus_alignment(NewSize, _initial_heap_byte_size);
|
||||
}
|
||||
|
||||
// Now take the actual NewSize into account. We will silently increase NewSize
|
||||
// if the user specified a smaller or unaligned value.
|
||||
smallest_new_size = MAX2(smallest_new_size, (uintx)align_size_down(NewSize, _gen_alignment));
|
||||
if (smallest_new_size != NewSize) {
|
||||
uintx bounded_new_size = bound_minus_alignment(NewSize, MaxHeapSize);
|
||||
bounded_new_size = MAX2(smallest_new_size, (uintx)align_size_down(bounded_new_size, _gen_alignment));
|
||||
if (bounded_new_size != NewSize) {
|
||||
// Do not use FLAG_SET_ERGO to update NewSize here, since this will override
|
||||
// if NewSize was set on the command line or not. This information is needed
|
||||
// later when setting the initial and minimum young generation size.
|
||||
NewSize = smallest_new_size;
|
||||
NewSize = bounded_new_size;
|
||||
}
|
||||
_min_gen0_size = smallest_new_size;
|
||||
_initial_gen0_size = NewSize;
|
||||
|
||||
if (!FLAG_IS_DEFAULT(MaxNewSize)) {
|
||||
uintx min_new_size = MAX2(_gen_alignment, _min_gen0_size);
|
||||
|
||||
if (MaxNewSize >= MaxHeapSize) {
|
||||
// Make sure there is room for an old generation
|
||||
uintx smaller_max_new_size = MaxHeapSize - _gen_alignment;
|
||||
|
@ -330,8 +345,8 @@ void GenCollectorPolicy::initialize_flags() {
|
|||
FLAG_SET_ERGO(uintx, NewSize, MaxNewSize);
|
||||
_initial_gen0_size = NewSize;
|
||||
}
|
||||
} else if (MaxNewSize < min_new_size) {
|
||||
FLAG_SET_ERGO(uintx, MaxNewSize, min_new_size);
|
||||
} else if (MaxNewSize < _initial_gen0_size) {
|
||||
FLAG_SET_ERGO(uintx, MaxNewSize, _initial_gen0_size);
|
||||
} else if (!is_size_aligned(MaxNewSize, _gen_alignment)) {
|
||||
FLAG_SET_ERGO(uintx, MaxNewSize, align_size_down(MaxNewSize, _gen_alignment));
|
||||
}
|
||||
|
@ -361,7 +376,9 @@ void TwoGenerationCollectorPolicy::initialize_flags() {
|
|||
GenCollectorPolicy::initialize_flags();
|
||||
|
||||
if (!is_size_aligned(OldSize, _gen_alignment)) {
|
||||
FLAG_SET_ERGO(uintx, OldSize, align_size_down(OldSize, _gen_alignment));
|
||||
// Setting OldSize directly to preserve information about the possible
|
||||
// setting of OldSize on the command line.
|
||||
OldSize = align_size_down(OldSize, _gen_alignment);
|
||||
}
|
||||
|
||||
if (FLAG_IS_CMDLINE(OldSize) && FLAG_IS_DEFAULT(MaxHeapSize)) {
|
||||
|
@ -400,6 +417,20 @@ void TwoGenerationCollectorPolicy::initialize_flags() {
|
|||
}
|
||||
}
|
||||
|
||||
// Update NewSize, if possible, to avoid sizing gen0 to small when only
|
||||
// OldSize is set on the command line.
|
||||
if (FLAG_IS_CMDLINE(OldSize) && !FLAG_IS_CMDLINE(NewSize)) {
|
||||
if (OldSize < _initial_heap_byte_size) {
|
||||
size_t new_size = _initial_heap_byte_size - OldSize;
|
||||
// Need to compare against the flag value for max since _max_gen0_size
|
||||
// might not have been set yet.
|
||||
if (new_size >= _min_gen0_size && new_size <= MaxNewSize) {
|
||||
FLAG_SET_ERGO(uintx, NewSize, new_size);
|
||||
_initial_gen0_size = NewSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
always_do_update_barrier = UseConcMarkSweepGC;
|
||||
|
||||
DEBUG_ONLY(TwoGenerationCollectorPolicy::assert_flags();)
|
||||
|
@ -441,57 +472,37 @@ void GenCollectorPolicy::initialize_size_info() {
|
|||
// Given the maximum gen0 size, determine the initial and
|
||||
// minimum gen0 sizes.
|
||||
|
||||
if (_max_heap_byte_size == _initial_heap_byte_size) {
|
||||
// The maxium and initial heap sizes are the same so the generation's
|
||||
// initial size must be the same as it maximum size. Use NewSize as the
|
||||
// size if set on command line.
|
||||
size_t fixed_young_size = FLAG_IS_CMDLINE(NewSize) ? NewSize : max_new_size;
|
||||
|
||||
_initial_gen0_size = fixed_young_size;
|
||||
_max_gen0_size = fixed_young_size;
|
||||
|
||||
// Also update the minimum size if min == initial == max.
|
||||
if (_max_heap_byte_size == _min_heap_byte_size) {
|
||||
// The maximum and minimum heap sizes are the same so the generations
|
||||
// minimum and initial must be the same as its maximum.
|
||||
_min_gen0_size = max_new_size;
|
||||
_initial_gen0_size = max_new_size;
|
||||
_max_gen0_size = max_new_size;
|
||||
_min_gen0_size = fixed_young_size;
|
||||
}
|
||||
} else {
|
||||
size_t desired_new_size = 0;
|
||||
if (FLAG_IS_CMDLINE(NewSize)) {
|
||||
// If NewSize is set on the command line, we must use it as
|
||||
// the initial size and it also makes sense to use it as the
|
||||
// lower limit.
|
||||
_min_gen0_size = NewSize;
|
||||
desired_new_size = NewSize;
|
||||
max_new_size = MAX2(max_new_size, NewSize);
|
||||
} else if (FLAG_IS_ERGO(NewSize)) {
|
||||
// If NewSize is set ergonomically, we should use it as a lower
|
||||
// limit, but use NewRatio to calculate the initial size.
|
||||
_min_gen0_size = NewSize;
|
||||
// If NewSize is set on the command line, we should use it as
|
||||
// the initial size, but make sure it is within the heap bounds.
|
||||
desired_new_size =
|
||||
MAX2(scale_by_NewRatio_aligned(_initial_heap_byte_size), NewSize);
|
||||
max_new_size = MAX2(max_new_size, NewSize);
|
||||
MIN2(max_new_size, bound_minus_alignment(NewSize, _initial_heap_byte_size));
|
||||
_min_gen0_size = bound_minus_alignment(desired_new_size, _min_heap_byte_size);
|
||||
} else {
|
||||
// For the case where NewSize is the default, use NewRatio
|
||||
// to size the minimum and initial generation sizes.
|
||||
// Use the default NewSize as the floor for these values. If
|
||||
// NewRatio is overly large, the resulting sizes can be too small.
|
||||
_min_gen0_size = MAX2(scale_by_NewRatio_aligned(_min_heap_byte_size), NewSize);
|
||||
// For the case where NewSize is not set on the command line, use
|
||||
// NewRatio to size the initial generation size. Use the current
|
||||
// NewSize as the floor, because if NewRatio is overly large, the resulting
|
||||
// size can be too small.
|
||||
desired_new_size =
|
||||
MAX2(scale_by_NewRatio_aligned(_initial_heap_byte_size), NewSize);
|
||||
MIN2(max_new_size, MAX2(scale_by_NewRatio_aligned(_initial_heap_byte_size), NewSize));
|
||||
}
|
||||
|
||||
assert(_min_gen0_size > 0, "Sanity check");
|
||||
_initial_gen0_size = desired_new_size;
|
||||
_max_gen0_size = max_new_size;
|
||||
|
||||
// At this point the desirable initial and minimum sizes have been
|
||||
// determined without regard to the maximum sizes.
|
||||
|
||||
// Bound the sizes by the corresponding overall heap sizes.
|
||||
_min_gen0_size = bound_minus_alignment(_min_gen0_size, _min_heap_byte_size);
|
||||
_initial_gen0_size = bound_minus_alignment(_initial_gen0_size, _initial_heap_byte_size);
|
||||
_max_gen0_size = bound_minus_alignment(_max_gen0_size, _max_heap_byte_size);
|
||||
|
||||
// At this point all three sizes have been checked against the
|
||||
// maximum sizes but have not been checked for consistency among the three.
|
||||
|
||||
// Final check min <= initial <= max
|
||||
_min_gen0_size = MIN2(_min_gen0_size, _max_gen0_size);
|
||||
_initial_gen0_size = MAX2(MIN2(_initial_gen0_size, _max_gen0_size), _min_gen0_size);
|
||||
_min_gen0_size = MIN2(_min_gen0_size, _initial_gen0_size);
|
||||
}
|
||||
|
||||
// Write back to flags if necessary.
|
||||
|
@ -512,33 +523,6 @@ void GenCollectorPolicy::initialize_size_info() {
|
|||
DEBUG_ONLY(GenCollectorPolicy::assert_size_info();)
|
||||
}
|
||||
|
||||
// Call this method during the sizing of the gen1 to make
|
||||
// adjustments to gen0 because of gen1 sizing policy. gen0 initially has
|
||||
// the most freedom in sizing because it is done before the
|
||||
// policy for gen1 is applied. Once gen1 policies have been applied,
|
||||
// there may be conflicts in the shape of the heap and this method
|
||||
// is used to make the needed adjustments. The application of the
|
||||
// policies could be more sophisticated (iterative for example) but
|
||||
// keeping it simple also seems a worthwhile goal.
|
||||
bool TwoGenerationCollectorPolicy::adjust_gen0_sizes(size_t* gen0_size_ptr,
|
||||
size_t* gen1_size_ptr,
|
||||
const size_t heap_size) {
|
||||
bool result = false;
|
||||
|
||||
if ((*gen0_size_ptr + *gen1_size_ptr) > heap_size) {
|
||||
uintx smallest_new_size = young_gen_size_lower_bound();
|
||||
if ((heap_size < (*gen0_size_ptr + _min_gen1_size)) &&
|
||||
(heap_size >= _min_gen1_size + smallest_new_size)) {
|
||||
// Adjust gen0 down to accommodate _min_gen1_size
|
||||
*gen0_size_ptr = align_size_down_bounded(heap_size - _min_gen1_size, _gen_alignment);
|
||||
result = true;
|
||||
} else {
|
||||
*gen1_size_ptr = align_size_down_bounded(heap_size - *gen0_size_ptr, _gen_alignment);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Minimum sizes of the generations may be different than
|
||||
// the initial sizes. An inconsistency is permitted here
|
||||
// in the total size that can be specified explicitly by
|
||||
|
@ -564,56 +548,63 @@ void TwoGenerationCollectorPolicy::initialize_size_info() {
|
|||
// with the overall heap size). In either case make
|
||||
// the minimum, maximum and initial sizes consistent
|
||||
// with the gen0 sizes and the overall heap sizes.
|
||||
_min_gen1_size = MAX2(_min_heap_byte_size - _min_gen0_size, _gen_alignment);
|
||||
_initial_gen1_size = MAX2(_initial_heap_byte_size - _initial_gen0_size, _gen_alignment);
|
||||
_min_gen1_size = _gen_alignment;
|
||||
_initial_gen1_size = MIN2(_max_gen1_size, MAX2(_initial_heap_byte_size - _initial_gen0_size, _min_gen1_size));
|
||||
// _max_gen1_size has already been made consistent above
|
||||
FLAG_SET_ERGO(uintx, OldSize, _initial_gen1_size);
|
||||
} else {
|
||||
// OldSize has been explicitly set on the command line. Use the
|
||||
// OldSize and then determine the consequences.
|
||||
_min_gen1_size = MIN2(OldSize, _min_heap_byte_size - _min_gen0_size);
|
||||
_initial_gen1_size = OldSize;
|
||||
|
||||
// OldSize has been explicitly set on the command line. Use it
|
||||
// for the initial size but make sure the minimum allow a young
|
||||
// generation to fit as well.
|
||||
// If the user has explicitly set an OldSize that is inconsistent
|
||||
// with other command line flags, issue a warning.
|
||||
// The generation minimums and the overall heap minimum should
|
||||
// be within one generation alignment.
|
||||
if ((_min_gen1_size + _min_gen0_size + _gen_alignment) < _min_heap_byte_size) {
|
||||
warning("Inconsistency between minimum heap size and minimum "
|
||||
"generation sizes: using minimum heap = " SIZE_FORMAT,
|
||||
_min_heap_byte_size);
|
||||
}
|
||||
if (OldSize > _max_gen1_size) {
|
||||
warning("Inconsistency between maximum heap size and maximum "
|
||||
"generation sizes: using maximum heap = " SIZE_FORMAT
|
||||
" -XX:OldSize flag is being ignored",
|
||||
_max_heap_byte_size);
|
||||
FLAG_SET_ERGO(uintx, OldSize, _max_gen1_size);
|
||||
}
|
||||
// If there is an inconsistency between the OldSize and the minimum and/or
|
||||
// initial size of gen0, since OldSize was explicitly set, OldSize wins.
|
||||
if (adjust_gen0_sizes(&_min_gen0_size, &_min_gen1_size, _min_heap_byte_size)) {
|
||||
|
||||
_min_gen1_size = MIN2(OldSize, _min_heap_byte_size - _min_gen0_size);
|
||||
_initial_gen1_size = OldSize;
|
||||
}
|
||||
|
||||
// The initial generation sizes should match the initial heap size,
|
||||
// if not issue a warning and resize the generations. This behavior
|
||||
// differs from JDK8 where the generation sizes have higher priority
|
||||
// than the initial heap size.
|
||||
if ((_initial_gen1_size + _initial_gen0_size) != _initial_heap_byte_size) {
|
||||
warning("Inconsistency between generation sizes and heap size, resizing "
|
||||
"the generations to fit the heap.");
|
||||
|
||||
size_t desired_gen0_size = _initial_heap_byte_size - _initial_gen1_size;
|
||||
if (_initial_heap_byte_size < _initial_gen1_size) {
|
||||
// Old want all memory, use minimum for young and rest for old
|
||||
_initial_gen0_size = _min_gen0_size;
|
||||
_initial_gen1_size = _initial_heap_byte_size - _min_gen0_size;
|
||||
} else if (desired_gen0_size > _max_gen0_size) {
|
||||
// Need to increase both young and old generation
|
||||
_initial_gen0_size = _max_gen0_size;
|
||||
_initial_gen1_size = _initial_heap_byte_size - _max_gen0_size;
|
||||
} else if (desired_gen0_size < _min_gen0_size) {
|
||||
// Need to decrease both young and old generation
|
||||
_initial_gen0_size = _min_gen0_size;
|
||||
_initial_gen1_size = _initial_heap_byte_size - _min_gen0_size;
|
||||
} else {
|
||||
// The young generation boundaries allow us to only update the
|
||||
// young generation.
|
||||
_initial_gen0_size = desired_gen0_size;
|
||||
}
|
||||
|
||||
if (PrintGCDetails && Verbose) {
|
||||
gclog_or_tty->print_cr("2: Minimum gen0 " SIZE_FORMAT " Initial gen0 "
|
||||
SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT,
|
||||
_min_gen0_size, _initial_gen0_size, _max_gen0_size);
|
||||
}
|
||||
}
|
||||
// The same as above for the old gen initial size.
|
||||
if (adjust_gen0_sizes(&_initial_gen0_size, &_initial_gen1_size,
|
||||
_initial_heap_byte_size)) {
|
||||
if (PrintGCDetails && Verbose) {
|
||||
gclog_or_tty->print_cr("3: Minimum gen0 " SIZE_FORMAT " Initial gen0 "
|
||||
SIZE_FORMAT " Maximum gen0 " SIZE_FORMAT,
|
||||
_min_gen0_size, _initial_gen0_size, _max_gen0_size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_min_gen1_size = MIN2(_min_gen1_size, _max_gen1_size);
|
||||
|
||||
// Make sure that min gen1 <= initial gen1 <= max gen1.
|
||||
_initial_gen1_size = MAX2(_initial_gen1_size, _min_gen1_size);
|
||||
_initial_gen1_size = MIN2(_initial_gen1_size, _max_gen1_size);
|
||||
|
||||
// Write back to flags if necessary
|
||||
if (NewSize != _initial_gen0_size) {
|
||||
|
@ -994,56 +985,88 @@ void MarkSweepPolicy::initialize_gc_policy_counters() {
|
|||
// verify that there are some basic rules for NewSize honored by the policies.
|
||||
class TestGenCollectorPolicy {
|
||||
public:
|
||||
static void test() {
|
||||
static void test_new_size() {
|
||||
size_t flag_value;
|
||||
|
||||
save_flags();
|
||||
|
||||
// Set some limits that makes the math simple.
|
||||
FLAG_SET_ERGO(uintx, MaxHeapSize, 180 * M);
|
||||
FLAG_SET_ERGO(uintx, InitialHeapSize, 120 * M);
|
||||
Arguments::set_min_heap_size(40 * M);
|
||||
|
||||
// If NewSize is set on the command line, it should be used
|
||||
// for both min and initial young size if less than min heap.
|
||||
flag_value = 20 * M;
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_CMDLINE(uintx, NewSize, flag_value);
|
||||
verify_min(flag_value);
|
||||
verify_initial(flag_value);
|
||||
verify_gen0_min(flag_value);
|
||||
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_CMDLINE(uintx, NewSize, flag_value);
|
||||
verify_gen0_initial(flag_value);
|
||||
|
||||
// If NewSize is set on command line, but is larger than the min
|
||||
// heap size, it should only be used for initial young size.
|
||||
flag_value = 80 * M;
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_CMDLINE(uintx, NewSize, flag_value);
|
||||
verify_initial(flag_value);
|
||||
verify_gen0_initial(flag_value);
|
||||
|
||||
// If NewSize has been ergonomically set, the collector policy
|
||||
// should use it for min but calculate the initial young size
|
||||
// using NewRatio.
|
||||
flag_value = 20 * M;
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_ERGO(uintx, NewSize, flag_value);
|
||||
verify_min(flag_value);
|
||||
verify_scaled_initial(InitialHeapSize);
|
||||
verify_gen0_min(flag_value);
|
||||
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_ERGO(uintx, NewSize, flag_value);
|
||||
verify_scaled_gen0_initial(InitialHeapSize);
|
||||
|
||||
restore_flags();
|
||||
}
|
||||
|
||||
static void test_old_size() {
|
||||
size_t flag_value;
|
||||
|
||||
save_flags();
|
||||
|
||||
// If OldSize is set on the command line, it should be used
|
||||
// for both min and initial old size if less than min heap.
|
||||
flag_value = 20 * M;
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_CMDLINE(uintx, OldSize, flag_value);
|
||||
verify_gen1_min(flag_value);
|
||||
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_CMDLINE(uintx, OldSize, flag_value);
|
||||
verify_gen1_initial(flag_value);
|
||||
|
||||
// If MaxNewSize is large, the maximum OldSize will be less than
|
||||
// what's requested on the command line and it should be reset
|
||||
// ergonomically.
|
||||
flag_value = 30 * M;
|
||||
set_basic_flag_values();
|
||||
FLAG_SET_CMDLINE(uintx, OldSize, flag_value);
|
||||
FLAG_SET_CMDLINE(uintx, MaxNewSize, 170*M);
|
||||
// Calculate what we expect the flag to be.
|
||||
flag_value = MaxHeapSize - MaxNewSize;
|
||||
verify_gen1_initial(flag_value);
|
||||
|
||||
}
|
||||
|
||||
static void verify_min(size_t expected) {
|
||||
static void verify_gen0_min(size_t expected) {
|
||||
MarkSweepPolicy msp;
|
||||
msp.initialize_all();
|
||||
|
||||
assert(msp.min_gen0_size() <= expected, err_msg("%zu > %zu", msp.min_gen0_size(), expected));
|
||||
}
|
||||
|
||||
static void verify_initial(size_t expected) {
|
||||
static void verify_gen0_initial(size_t expected) {
|
||||
MarkSweepPolicy msp;
|
||||
msp.initialize_all();
|
||||
|
||||
assert(msp.initial_gen0_size() == expected, err_msg("%zu != %zu", msp.initial_gen0_size(), expected));
|
||||
}
|
||||
|
||||
static void verify_scaled_initial(size_t initial_heap_size) {
|
||||
static void verify_scaled_gen0_initial(size_t initial_heap_size) {
|
||||
MarkSweepPolicy msp;
|
||||
msp.initialize_all();
|
||||
|
||||
|
@ -1053,6 +1076,21 @@ public:
|
|||
err_msg("NewSize should have been set ergonomically to %zu, but was %zu", expected, NewSize));
|
||||
}
|
||||
|
||||
static void verify_gen1_min(size_t expected) {
|
||||
MarkSweepPolicy msp;
|
||||
msp.initialize_all();
|
||||
|
||||
assert(msp.min_gen1_size() <= expected, err_msg("%zu > %zu", msp.min_gen1_size(), expected));
|
||||
}
|
||||
|
||||
static void verify_gen1_initial(size_t expected) {
|
||||
MarkSweepPolicy msp;
|
||||
msp.initialize_all();
|
||||
|
||||
assert(msp.initial_gen1_size() == expected, err_msg("%zu != %zu", msp.initial_gen1_size(), expected));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static size_t original_InitialHeapSize;
|
||||
static size_t original_MaxHeapSize;
|
||||
|
@ -1061,6 +1099,15 @@ private:
|
|||
static size_t original_NewSize;
|
||||
static size_t original_OldSize;
|
||||
|
||||
static void set_basic_flag_values() {
|
||||
FLAG_SET_ERGO(uintx, MaxHeapSize, 180 * M);
|
||||
FLAG_SET_ERGO(uintx, InitialHeapSize, 100 * M);
|
||||
FLAG_SET_ERGO(uintx, OldSize, 4 * M);
|
||||
FLAG_SET_ERGO(uintx, NewSize, 1 * M);
|
||||
FLAG_SET_ERGO(uintx, MaxNewSize, 80 * M);
|
||||
Arguments::set_min_heap_size(40 * M);
|
||||
}
|
||||
|
||||
static void save_flags() {
|
||||
original_InitialHeapSize = InitialHeapSize;
|
||||
original_MaxHeapSize = MaxHeapSize;
|
||||
|
@ -1088,7 +1135,11 @@ size_t TestGenCollectorPolicy::original_NewSize = 0;
|
|||
size_t TestGenCollectorPolicy::original_OldSize = 0;
|
||||
|
||||
void TestNewSize_test() {
|
||||
TestGenCollectorPolicy::test();
|
||||
TestGenCollectorPolicy::test_new_size();
|
||||
}
|
||||
|
||||
void TestOldSize_test() {
|
||||
TestGenCollectorPolicy::test_old_size();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -335,10 +335,6 @@ class TwoGenerationCollectorPolicy : public GenCollectorPolicy {
|
|||
virtual CollectorPolicy::Name kind() {
|
||||
return CollectorPolicy::TwoGenerationCollectorPolicyKind;
|
||||
}
|
||||
|
||||
// Returns true if gen0 sizes were adjusted
|
||||
bool adjust_gen0_sizes(size_t* gen0_size_ptr, size_t* gen1_size_ptr,
|
||||
const size_t heap_size);
|
||||
};
|
||||
|
||||
class MarkSweepPolicy : public TwoGenerationCollectorPolicy {
|
||||
|
|
|
@ -374,7 +374,7 @@ void GenCollectedHeap::do_collection(bool full,
|
|||
|
||||
ClearedAllSoftRefs casr(do_clear_all_soft_refs, collector_policy());
|
||||
|
||||
const size_t metadata_prev_used = MetaspaceAux::allocated_used_bytes();
|
||||
const size_t metadata_prev_used = MetaspaceAux::used_bytes();
|
||||
|
||||
print_heap_before_gc();
|
||||
|
||||
|
|
|
@ -1447,7 +1447,7 @@ void MetaspaceGC::compute_new_size() {
|
|||
uint current_shrink_factor = _shrink_factor;
|
||||
_shrink_factor = 0;
|
||||
|
||||
const size_t used_after_gc = MetaspaceAux::allocated_capacity_bytes();
|
||||
const size_t used_after_gc = MetaspaceAux::capacity_bytes();
|
||||
const size_t capacity_until_GC = MetaspaceGC::capacity_until_GC();
|
||||
|
||||
const double minimum_free_percentage = MinMetaspaceFreeRatio / 100.0;
|
||||
|
@ -2538,8 +2538,8 @@ void SpaceManager::mangle_freed_chunks() {
|
|||
// MetaspaceAux
|
||||
|
||||
|
||||
size_t MetaspaceAux::_allocated_capacity_words[] = {0, 0};
|
||||
size_t MetaspaceAux::_allocated_used_words[] = {0, 0};
|
||||
size_t MetaspaceAux::_capacity_words[] = {0, 0};
|
||||
size_t MetaspaceAux::_used_words[] = {0, 0};
|
||||
|
||||
size_t MetaspaceAux::free_bytes(Metaspace::MetadataType mdtype) {
|
||||
VirtualSpaceList* list = Metaspace::get_space_list(mdtype);
|
||||
|
@ -2552,38 +2552,38 @@ size_t MetaspaceAux::free_bytes() {
|
|||
|
||||
void MetaspaceAux::dec_capacity(Metaspace::MetadataType mdtype, size_t words) {
|
||||
assert_lock_strong(SpaceManager::expand_lock());
|
||||
assert(words <= allocated_capacity_words(mdtype),
|
||||
assert(words <= capacity_words(mdtype),
|
||||
err_msg("About to decrement below 0: words " SIZE_FORMAT
|
||||
" is greater than _allocated_capacity_words[%u] " SIZE_FORMAT,
|
||||
words, mdtype, allocated_capacity_words(mdtype)));
|
||||
_allocated_capacity_words[mdtype] -= words;
|
||||
" is greater than _capacity_words[%u] " SIZE_FORMAT,
|
||||
words, mdtype, capacity_words(mdtype)));
|
||||
_capacity_words[mdtype] -= words;
|
||||
}
|
||||
|
||||
void MetaspaceAux::inc_capacity(Metaspace::MetadataType mdtype, size_t words) {
|
||||
assert_lock_strong(SpaceManager::expand_lock());
|
||||
// Needs to be atomic
|
||||
_allocated_capacity_words[mdtype] += words;
|
||||
_capacity_words[mdtype] += words;
|
||||
}
|
||||
|
||||
void MetaspaceAux::dec_used(Metaspace::MetadataType mdtype, size_t words) {
|
||||
assert(words <= allocated_used_words(mdtype),
|
||||
assert(words <= used_words(mdtype),
|
||||
err_msg("About to decrement below 0: words " SIZE_FORMAT
|
||||
" is greater than _allocated_used_words[%u] " SIZE_FORMAT,
|
||||
words, mdtype, allocated_used_words(mdtype)));
|
||||
" is greater than _used_words[%u] " SIZE_FORMAT,
|
||||
words, mdtype, used_words(mdtype)));
|
||||
// For CMS deallocation of the Metaspaces occurs during the
|
||||
// sweep which is a concurrent phase. Protection by the expand_lock()
|
||||
// is not enough since allocation is on a per Metaspace basis
|
||||
// and protected by the Metaspace lock.
|
||||
jlong minus_words = (jlong) - (jlong) words;
|
||||
Atomic::add_ptr(minus_words, &_allocated_used_words[mdtype]);
|
||||
Atomic::add_ptr(minus_words, &_used_words[mdtype]);
|
||||
}
|
||||
|
||||
void MetaspaceAux::inc_used(Metaspace::MetadataType mdtype, size_t words) {
|
||||
// _allocated_used_words tracks allocations for
|
||||
// _used_words tracks allocations for
|
||||
// each piece of metadata. Those allocations are
|
||||
// generally done concurrently by different application
|
||||
// threads so must be done atomically.
|
||||
Atomic::add_ptr(words, &_allocated_used_words[mdtype]);
|
||||
Atomic::add_ptr(words, &_used_words[mdtype]);
|
||||
}
|
||||
|
||||
size_t MetaspaceAux::used_bytes_slow(Metaspace::MetadataType mdtype) {
|
||||
|
@ -2630,16 +2630,16 @@ size_t MetaspaceAux::capacity_bytes_slow(Metaspace::MetadataType mdtype) {
|
|||
|
||||
size_t MetaspaceAux::capacity_bytes_slow() {
|
||||
#ifdef PRODUCT
|
||||
// Use allocated_capacity_bytes() in PRODUCT instead of this function.
|
||||
// Use capacity_bytes() in PRODUCT instead of this function.
|
||||
guarantee(false, "Should not call capacity_bytes_slow() in the PRODUCT");
|
||||
#endif
|
||||
size_t class_capacity = capacity_bytes_slow(Metaspace::ClassType);
|
||||
size_t non_class_capacity = capacity_bytes_slow(Metaspace::NonClassType);
|
||||
assert(allocated_capacity_bytes() == class_capacity + non_class_capacity,
|
||||
err_msg("bad accounting: allocated_capacity_bytes() " SIZE_FORMAT
|
||||
assert(capacity_bytes() == class_capacity + non_class_capacity,
|
||||
err_msg("bad accounting: capacity_bytes() " SIZE_FORMAT
|
||||
" class_capacity + non_class_capacity " SIZE_FORMAT
|
||||
" class_capacity " SIZE_FORMAT " non_class_capacity " SIZE_FORMAT,
|
||||
allocated_capacity_bytes(), class_capacity + non_class_capacity,
|
||||
capacity_bytes(), class_capacity + non_class_capacity,
|
||||
class_capacity, non_class_capacity));
|
||||
|
||||
return class_capacity + non_class_capacity;
|
||||
|
@ -2699,14 +2699,14 @@ void MetaspaceAux::print_metaspace_change(size_t prev_metadata_used) {
|
|||
"->" SIZE_FORMAT
|
||||
"(" SIZE_FORMAT ")",
|
||||
prev_metadata_used,
|
||||
allocated_used_bytes(),
|
||||
used_bytes(),
|
||||
reserved_bytes());
|
||||
} else {
|
||||
gclog_or_tty->print(" " SIZE_FORMAT "K"
|
||||
"->" SIZE_FORMAT "K"
|
||||
"(" SIZE_FORMAT "K)",
|
||||
prev_metadata_used/K,
|
||||
allocated_used_bytes()/K,
|
||||
used_bytes()/K,
|
||||
reserved_bytes()/K);
|
||||
}
|
||||
|
||||
|
@ -2722,8 +2722,8 @@ void MetaspaceAux::print_on(outputStream* out) {
|
|||
"capacity " SIZE_FORMAT "K, "
|
||||
"committed " SIZE_FORMAT "K, "
|
||||
"reserved " SIZE_FORMAT "K",
|
||||
allocated_used_bytes()/K,
|
||||
allocated_capacity_bytes()/K,
|
||||
used_bytes()/K,
|
||||
capacity_bytes()/K,
|
||||
committed_bytes()/K,
|
||||
reserved_bytes()/K);
|
||||
|
||||
|
@ -2734,8 +2734,8 @@ void MetaspaceAux::print_on(outputStream* out) {
|
|||
"capacity " SIZE_FORMAT "K, "
|
||||
"committed " SIZE_FORMAT "K, "
|
||||
"reserved " SIZE_FORMAT "K",
|
||||
allocated_used_bytes(ct)/K,
|
||||
allocated_capacity_bytes(ct)/K,
|
||||
used_bytes(ct)/K,
|
||||
capacity_bytes(ct)/K,
|
||||
committed_bytes(ct)/K,
|
||||
reserved_bytes(ct)/K);
|
||||
}
|
||||
|
@ -2837,42 +2837,42 @@ void MetaspaceAux::verify_free_chunks() {
|
|||
|
||||
void MetaspaceAux::verify_capacity() {
|
||||
#ifdef ASSERT
|
||||
size_t running_sum_capacity_bytes = allocated_capacity_bytes();
|
||||
size_t running_sum_capacity_bytes = capacity_bytes();
|
||||
// For purposes of the running sum of capacity, verify against capacity
|
||||
size_t capacity_in_use_bytes = capacity_bytes_slow();
|
||||
assert(running_sum_capacity_bytes == capacity_in_use_bytes,
|
||||
err_msg("allocated_capacity_words() * BytesPerWord " SIZE_FORMAT
|
||||
err_msg("capacity_words() * BytesPerWord " SIZE_FORMAT
|
||||
" capacity_bytes_slow()" SIZE_FORMAT,
|
||||
running_sum_capacity_bytes, capacity_in_use_bytes));
|
||||
for (Metaspace::MetadataType i = Metaspace::ClassType;
|
||||
i < Metaspace:: MetadataTypeCount;
|
||||
i = (Metaspace::MetadataType)(i + 1)) {
|
||||
size_t capacity_in_use_bytes = capacity_bytes_slow(i);
|
||||
assert(allocated_capacity_bytes(i) == capacity_in_use_bytes,
|
||||
err_msg("allocated_capacity_bytes(%u) " SIZE_FORMAT
|
||||
assert(capacity_bytes(i) == capacity_in_use_bytes,
|
||||
err_msg("capacity_bytes(%u) " SIZE_FORMAT
|
||||
" capacity_bytes_slow(%u)" SIZE_FORMAT,
|
||||
i, allocated_capacity_bytes(i), i, capacity_in_use_bytes));
|
||||
i, capacity_bytes(i), i, capacity_in_use_bytes));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void MetaspaceAux::verify_used() {
|
||||
#ifdef ASSERT
|
||||
size_t running_sum_used_bytes = allocated_used_bytes();
|
||||
size_t running_sum_used_bytes = used_bytes();
|
||||
// For purposes of the running sum of used, verify against used
|
||||
size_t used_in_use_bytes = used_bytes_slow();
|
||||
assert(allocated_used_bytes() == used_in_use_bytes,
|
||||
err_msg("allocated_used_bytes() " SIZE_FORMAT
|
||||
assert(used_bytes() == used_in_use_bytes,
|
||||
err_msg("used_bytes() " SIZE_FORMAT
|
||||
" used_bytes_slow()" SIZE_FORMAT,
|
||||
allocated_used_bytes(), used_in_use_bytes));
|
||||
used_bytes(), used_in_use_bytes));
|
||||
for (Metaspace::MetadataType i = Metaspace::ClassType;
|
||||
i < Metaspace:: MetadataTypeCount;
|
||||
i = (Metaspace::MetadataType)(i + 1)) {
|
||||
size_t used_in_use_bytes = used_bytes_slow(i);
|
||||
assert(allocated_used_bytes(i) == used_in_use_bytes,
|
||||
err_msg("allocated_used_bytes(%u) " SIZE_FORMAT
|
||||
assert(used_bytes(i) == used_in_use_bytes,
|
||||
err_msg("used_bytes(%u) " SIZE_FORMAT
|
||||
" used_bytes_slow(%u)" SIZE_FORMAT,
|
||||
i, allocated_used_bytes(i), i, used_in_use_bytes));
|
||||
i, used_bytes(i), i, used_in_use_bytes));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -280,11 +280,11 @@ class MetaspaceAux : AllStatic {
|
|||
// allocated to a Metaspace. This is used instead of
|
||||
// iterating over all the classloaders. One for each
|
||||
// type of Metadata
|
||||
static size_t _allocated_capacity_words[Metaspace:: MetadataTypeCount];
|
||||
// Running sum of space in all Metachunks that have
|
||||
static size_t _capacity_words[Metaspace:: MetadataTypeCount];
|
||||
// Running sum of space in all Metachunks that
|
||||
// are being used for metadata. One for each
|
||||
// type of Metadata.
|
||||
static size_t _allocated_used_words[Metaspace:: MetadataTypeCount];
|
||||
static size_t _used_words[Metaspace:: MetadataTypeCount];
|
||||
|
||||
public:
|
||||
// Decrement and increment _allocated_capacity_words
|
||||
|
@ -308,32 +308,32 @@ class MetaspaceAux : AllStatic {
|
|||
static size_t free_chunks_total_bytes();
|
||||
static size_t free_chunks_total_bytes(Metaspace::MetadataType mdtype);
|
||||
|
||||
static size_t allocated_capacity_words(Metaspace::MetadataType mdtype) {
|
||||
return _allocated_capacity_words[mdtype];
|
||||
static size_t capacity_words(Metaspace::MetadataType mdtype) {
|
||||
return _capacity_words[mdtype];
|
||||
}
|
||||
static size_t allocated_capacity_words() {
|
||||
return allocated_capacity_words(Metaspace::NonClassType) +
|
||||
allocated_capacity_words(Metaspace::ClassType);
|
||||
static size_t capacity_words() {
|
||||
return capacity_words(Metaspace::NonClassType) +
|
||||
capacity_words(Metaspace::ClassType);
|
||||
}
|
||||
static size_t allocated_capacity_bytes(Metaspace::MetadataType mdtype) {
|
||||
return allocated_capacity_words(mdtype) * BytesPerWord;
|
||||
static size_t capacity_bytes(Metaspace::MetadataType mdtype) {
|
||||
return capacity_words(mdtype) * BytesPerWord;
|
||||
}
|
||||
static size_t allocated_capacity_bytes() {
|
||||
return allocated_capacity_words() * BytesPerWord;
|
||||
static size_t capacity_bytes() {
|
||||
return capacity_words() * BytesPerWord;
|
||||
}
|
||||
|
||||
static size_t allocated_used_words(Metaspace::MetadataType mdtype) {
|
||||
return _allocated_used_words[mdtype];
|
||||
static size_t used_words(Metaspace::MetadataType mdtype) {
|
||||
return _used_words[mdtype];
|
||||
}
|
||||
static size_t allocated_used_words() {
|
||||
return allocated_used_words(Metaspace::NonClassType) +
|
||||
allocated_used_words(Metaspace::ClassType);
|
||||
static size_t used_words() {
|
||||
return used_words(Metaspace::NonClassType) +
|
||||
used_words(Metaspace::ClassType);
|
||||
}
|
||||
static size_t allocated_used_bytes(Metaspace::MetadataType mdtype) {
|
||||
return allocated_used_words(mdtype) * BytesPerWord;
|
||||
static size_t used_bytes(Metaspace::MetadataType mdtype) {
|
||||
return used_words(mdtype) * BytesPerWord;
|
||||
}
|
||||
static size_t allocated_used_bytes() {
|
||||
return allocated_used_words() * BytesPerWord;
|
||||
static size_t used_bytes() {
|
||||
return used_words() * BytesPerWord;
|
||||
}
|
||||
|
||||
static size_t free_bytes();
|
||||
|
|
|
@ -66,7 +66,7 @@ class MetaspacePerfCounters: public CHeapObj<mtInternal> {
|
|||
MetaspacePerfCounters* MetaspaceCounters::_perf_counters = NULL;
|
||||
|
||||
size_t MetaspaceCounters::used() {
|
||||
return MetaspaceAux::allocated_used_bytes();
|
||||
return MetaspaceAux::used_bytes();
|
||||
}
|
||||
|
||||
size_t MetaspaceCounters::capacity() {
|
||||
|
@ -98,7 +98,7 @@ void MetaspaceCounters::update_performance_counters() {
|
|||
MetaspacePerfCounters* CompressedClassSpaceCounters::_perf_counters = NULL;
|
||||
|
||||
size_t CompressedClassSpaceCounters::used() {
|
||||
return MetaspaceAux::allocated_used_bytes(Metaspace::ClassType);
|
||||
return MetaspaceAux::used_bytes(Metaspace::ClassType);
|
||||
}
|
||||
|
||||
size_t CompressedClassSpaceCounters::capacity() {
|
||||
|
|
|
@ -3408,6 +3408,10 @@ static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_
|
|||
("purge: %s(%s): prev method @%d in version @%d is alive",
|
||||
method->name()->as_C_string(),
|
||||
method->signature()->as_C_string(), j, i));
|
||||
if (method->method_data() != NULL) {
|
||||
// Clean out any weak method links
|
||||
method->method_data()->clean_weak_method_links();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3417,6 +3421,14 @@ static void purge_previous_versions_internal(InstanceKlass* ik, int emcp_method_
|
|||
("purge: previous version stats: live=%d, deleted=%d", live_count,
|
||||
deleted_count));
|
||||
}
|
||||
|
||||
Array<Method*>* methods = ik->methods();
|
||||
int num_methods = methods->length();
|
||||
for (int index2 = 0; index2 < num_methods; ++index2) {
|
||||
if (methods->at(index2)->method_data() != NULL) {
|
||||
methods->at(index2)->method_data()->clean_weak_method_links();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// External interface for use during class unloading.
|
||||
|
|
|
@ -1531,9 +1531,35 @@ void MethodData::clean_extra_data_helper(DataLayout* dp, int shift, bool reset)
|
|||
}
|
||||
}
|
||||
|
||||
// Remove SpeculativeTrapData entries that reference an unloaded
|
||||
// method
|
||||
void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
|
||||
class CleanExtraDataClosure : public StackObj {
|
||||
public:
|
||||
virtual bool is_live(Method* m) = 0;
|
||||
};
|
||||
|
||||
// Check for entries that reference an unloaded method
|
||||
class CleanExtraDataKlassClosure : public CleanExtraDataClosure {
|
||||
private:
|
||||
BoolObjectClosure* _is_alive;
|
||||
public:
|
||||
CleanExtraDataKlassClosure(BoolObjectClosure* is_alive) : _is_alive(is_alive) {}
|
||||
bool is_live(Method* m) {
|
||||
return m->method_holder()->is_loader_alive(_is_alive);
|
||||
}
|
||||
};
|
||||
|
||||
// Check for entries that reference a redefined method
|
||||
class CleanExtraDataMethodClosure : public CleanExtraDataClosure {
|
||||
public:
|
||||
CleanExtraDataMethodClosure() {}
|
||||
bool is_live(Method* m) {
|
||||
return m->on_stack();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Remove SpeculativeTrapData entries that reference an unloaded or
|
||||
// redefined method
|
||||
void MethodData::clean_extra_data(CleanExtraDataClosure* cl) {
|
||||
DataLayout* dp = extra_data_base();
|
||||
DataLayout* end = extra_data_limit();
|
||||
|
||||
|
@ -1544,7 +1570,7 @@ void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
|
|||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
Method* m = data->method();
|
||||
assert(m != NULL, "should have a method");
|
||||
if (!m->method_holder()->is_loader_alive(is_alive)) {
|
||||
if (!cl->is_live(m)) {
|
||||
// "shift" accumulates the number of cells for dead
|
||||
// SpeculativeTrapData entries that have been seen so
|
||||
// far. Following entries must be shifted left by that many
|
||||
|
@ -1575,9 +1601,9 @@ void MethodData::clean_extra_data(BoolObjectClosure* is_alive) {
|
|||
}
|
||||
}
|
||||
|
||||
// Verify there's no unloaded method referenced by a
|
||||
// Verify there's no unloaded or redefined method referenced by a
|
||||
// SpeculativeTrapData entry
|
||||
void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) {
|
||||
void MethodData::verify_extra_data_clean(CleanExtraDataClosure* cl) {
|
||||
#ifdef ASSERT
|
||||
DataLayout* dp = extra_data_base();
|
||||
DataLayout* end = extra_data_limit();
|
||||
|
@ -1587,7 +1613,7 @@ void MethodData::verify_extra_data_clean(BoolObjectClosure* is_alive) {
|
|||
case DataLayout::speculative_trap_data_tag: {
|
||||
SpeculativeTrapData* data = new SpeculativeTrapData(dp);
|
||||
Method* m = data->method();
|
||||
assert(m != NULL && m->method_holder()->is_loader_alive(is_alive), "Method should exist");
|
||||
assert(m != NULL && cl->is_live(m), "Method should exist");
|
||||
break;
|
||||
}
|
||||
case DataLayout::bit_data_tag:
|
||||
|
@ -1613,6 +1639,19 @@ void MethodData::clean_method_data(BoolObjectClosure* is_alive) {
|
|||
parameters->clean_weak_klass_links(is_alive);
|
||||
}
|
||||
|
||||
clean_extra_data(is_alive);
|
||||
verify_extra_data_clean(is_alive);
|
||||
CleanExtraDataKlassClosure cl(is_alive);
|
||||
clean_extra_data(&cl);
|
||||
verify_extra_data_clean(&cl);
|
||||
}
|
||||
|
||||
void MethodData::clean_weak_method_links() {
|
||||
for (ProfileData* data = first_data();
|
||||
is_valid(data);
|
||||
data = next_data(data)) {
|
||||
data->clean_weak_method_links();
|
||||
}
|
||||
|
||||
CleanExtraDataMethodClosure cl;
|
||||
clean_extra_data(&cl);
|
||||
verify_extra_data_clean(&cl);
|
||||
}
|
||||
|
|
|
@ -251,6 +251,9 @@ public:
|
|||
|
||||
// GC support
|
||||
void clean_weak_klass_links(BoolObjectClosure* cl);
|
||||
|
||||
// Redefinition support
|
||||
void clean_weak_method_links();
|
||||
};
|
||||
|
||||
|
||||
|
@ -506,6 +509,9 @@ public:
|
|||
// GC support
|
||||
virtual void clean_weak_klass_links(BoolObjectClosure* is_alive_closure) {}
|
||||
|
||||
// Redefinition support
|
||||
virtual void clean_weak_method_links() {}
|
||||
|
||||
// CI translation: ProfileData can represent both MethodDataOop data
|
||||
// as well as CIMethodData data. This function is provided for translating
|
||||
// an oop in a ProfileData to the ci equivalent. Generally speaking,
|
||||
|
@ -1989,6 +1995,7 @@ public:
|
|||
//
|
||||
|
||||
CC_INTERP_ONLY(class BytecodeInterpreter;)
|
||||
class CleanExtraDataClosure;
|
||||
|
||||
class MethodData : public Metadata {
|
||||
friend class VMStructs;
|
||||
|
@ -2146,9 +2153,9 @@ private:
|
|||
static bool profile_parameters_jsr292_only();
|
||||
static bool profile_all_parameters();
|
||||
|
||||
void clean_extra_data(BoolObjectClosure* is_alive);
|
||||
void clean_extra_data(CleanExtraDataClosure* cl);
|
||||
void clean_extra_data_helper(DataLayout* dp, int shift, bool reset = false);
|
||||
void verify_extra_data_clean(BoolObjectClosure* is_alive);
|
||||
void verify_extra_data_clean(CleanExtraDataClosure* cl);
|
||||
|
||||
public:
|
||||
static int header_size() {
|
||||
|
@ -2440,6 +2447,8 @@ public:
|
|||
static bool profile_return_jsr292_only();
|
||||
|
||||
void clean_method_data(BoolObjectClosure* is_alive);
|
||||
|
||||
void clean_weak_method_links();
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_OOPS_METHODDATAOOP_HPP
|
||||
|
|
|
@ -70,6 +70,7 @@ public:
|
|||
|
||||
JVMState* ParseGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile* C = Compile::current();
|
||||
C->print_inlining_update(this);
|
||||
|
||||
if (is_osr()) {
|
||||
// The JVMS for a OSR has a single argument (see its TypeFunc).
|
||||
|
@ -126,6 +127,7 @@ class DirectCallGenerator : public CallGenerator {
|
|||
|
||||
JVMState* DirectCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
kit.C->print_inlining_update(this);
|
||||
bool is_static = method()->is_static();
|
||||
address target = is_static ? SharedRuntime::get_resolve_static_call_stub()
|
||||
: SharedRuntime::get_resolve_opt_virtual_call_stub();
|
||||
|
@ -178,6 +180,8 @@ JVMState* VirtualCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
|||
GraphKit kit(jvms);
|
||||
Node* receiver = kit.argument(0);
|
||||
|
||||
kit.C->print_inlining_update(this);
|
||||
|
||||
if (kit.C->log() != NULL) {
|
||||
kit.C->log()->elem("virtual_call bci='%d'", jvms->bci());
|
||||
}
|
||||
|
@ -278,7 +282,6 @@ class LateInlineCallGenerator : public DirectCallGenerator {
|
|||
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile *C = Compile::current();
|
||||
C->print_inlining_skip(this);
|
||||
|
||||
// Record that this call site should be revisited once the main
|
||||
// parse is finished.
|
||||
|
@ -296,10 +299,11 @@ class LateInlineCallGenerator : public DirectCallGenerator {
|
|||
virtual void print_inlining_late(const char* msg) {
|
||||
CallNode* call = call_node();
|
||||
Compile* C = Compile::current();
|
||||
C->print_inlining_insert(this);
|
||||
C->print_inlining_assert_ready();
|
||||
C->print_inlining(method(), call->jvms()->depth()-1, call->jvms()->bci(), msg);
|
||||
C->print_inlining_move_to(this);
|
||||
C->print_inlining_update_delayed(this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void LateInlineCallGenerator::do_late_inline() {
|
||||
|
@ -360,6 +364,10 @@ void LateInlineCallGenerator::do_late_inline() {
|
|||
map->set_argument(jvms, i1, call->in(TypeFunc::Parms + i1));
|
||||
}
|
||||
|
||||
C->print_inlining_assert_ready();
|
||||
|
||||
C->print_inlining_move_to(this);
|
||||
|
||||
// This check is done here because for_method_handle_inline() method
|
||||
// needs jvms for inlined state.
|
||||
if (!do_late_inline_check(jvms)) {
|
||||
|
@ -367,8 +375,6 @@ void LateInlineCallGenerator::do_late_inline() {
|
|||
return;
|
||||
}
|
||||
|
||||
C->print_inlining_insert(this);
|
||||
|
||||
CompileLog* log = C->log();
|
||||
if (log != NULL) {
|
||||
log->head("late_inline method='%d'", log->identify(method()));
|
||||
|
@ -388,7 +394,7 @@ void LateInlineCallGenerator::do_late_inline() {
|
|||
C->set_default_node_notes(entry_nn);
|
||||
}
|
||||
|
||||
// Now perform the inling using the synthesized JVMState
|
||||
// Now perform the inlining using the synthesized JVMState
|
||||
JVMState* new_jvms = _inline_cg->generate(jvms, NULL);
|
||||
if (new_jvms == NULL) return; // no change
|
||||
if (C->failing()) return;
|
||||
|
@ -431,6 +437,7 @@ class LateInlineMHCallGenerator : public LateInlineCallGenerator {
|
|||
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
JVMState* new_jvms = LateInlineCallGenerator::generate(jvms, parent_parser);
|
||||
|
||||
if (_input_not_const) {
|
||||
// inlining won't be possible so no need to enqueue right now.
|
||||
call_node()->set_generator(this);
|
||||
|
@ -439,17 +446,14 @@ class LateInlineMHCallGenerator : public LateInlineCallGenerator {
|
|||
}
|
||||
return new_jvms;
|
||||
}
|
||||
|
||||
virtual void print_inlining_late(const char* msg) {
|
||||
if (!_input_not_const) return;
|
||||
LateInlineCallGenerator::print_inlining_late(msg);
|
||||
}
|
||||
};
|
||||
|
||||
bool LateInlineMHCallGenerator::do_late_inline_check(JVMState* jvms) {
|
||||
|
||||
CallGenerator* cg = for_method_handle_inline(jvms, _caller, method(), _input_not_const);
|
||||
|
||||
Compile::current()->print_inlining_update_delayed(this);
|
||||
|
||||
if (!_input_not_const) {
|
||||
_attempt++;
|
||||
}
|
||||
|
@ -479,8 +483,6 @@ class LateInlineStringCallGenerator : public LateInlineCallGenerator {
|
|||
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile *C = Compile::current();
|
||||
C->print_inlining_skip(this);
|
||||
|
||||
C->add_string_late_inline(this);
|
||||
|
||||
JVMState* new_jvms = DirectCallGenerator::generate(jvms, parent_parser);
|
||||
|
@ -502,7 +504,6 @@ class LateInlineBoxingCallGenerator : public LateInlineCallGenerator {
|
|||
|
||||
virtual JVMState* generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile *C = Compile::current();
|
||||
C->print_inlining_skip(this);
|
||||
|
||||
C->add_boxing_late_inline(this);
|
||||
|
||||
|
@ -554,6 +555,8 @@ CallGenerator* CallGenerator::for_warm_call(WarmCallInfo* ci,
|
|||
|
||||
JVMState* WarmCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
Compile* C = Compile::current();
|
||||
C->print_inlining_update(this);
|
||||
|
||||
if (C->log() != NULL) {
|
||||
C->log()->elem("warm_call bci='%d'", jvms->bci());
|
||||
}
|
||||
|
@ -632,6 +635,7 @@ CallGenerator* CallGenerator::for_predicted_call(ciKlass* predicted_receiver,
|
|||
|
||||
JVMState* PredictedCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
kit.C->print_inlining_update(this);
|
||||
PhaseGVN& gvn = kit.gvn();
|
||||
// We need an explicit receiver null_check before checking its type.
|
||||
// We share a map with the caller, so his JVMS gets adjusted.
|
||||
|
@ -779,6 +783,9 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
|||
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
||||
if (cg != NULL && cg->is_inline())
|
||||
return cg;
|
||||
} else {
|
||||
const char* msg = "receiver not constant";
|
||||
if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -844,11 +851,13 @@ CallGenerator* CallGenerator::for_method_handle_inline(JVMState* jvms, ciMethod*
|
|||
// provide us with a type
|
||||
speculative_receiver_type = receiver_type->speculative_type();
|
||||
}
|
||||
|
||||
CallGenerator* cg = C->call_generator(target, vtable_index, call_does_dispatch, jvms, true, PROB_ALWAYS, speculative_receiver_type, true, true);
|
||||
assert(cg == NULL || !cg->is_late_inline() || cg->is_mh_late_inline(), "no late inline here");
|
||||
if (cg != NULL && cg->is_inline())
|
||||
return cg;
|
||||
} else {
|
||||
const char* msg = "member_name not constant";
|
||||
if (PrintInlining) C->print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -904,6 +913,7 @@ JVMState* PredictedIntrinsicGenerator::generate(JVMState* jvms, Parse* parent_pa
|
|||
if (kit.failing())
|
||||
return NULL; // might happen because of NodeCountInliningCutoff
|
||||
|
||||
kit.C->print_inlining_update(this);
|
||||
SafePointNode* slow_map = NULL;
|
||||
JVMState* slow_jvms;
|
||||
if (slow_ctl != NULL) {
|
||||
|
@ -1017,6 +1027,7 @@ CallGenerator::for_uncommon_trap(ciMethod* m,
|
|||
|
||||
JVMState* UncommonTrapCallGenerator::generate(JVMState* jvms, Parse* parent_parser) {
|
||||
GraphKit kit(jvms);
|
||||
kit.C->print_inlining_update(this);
|
||||
// Take the trap with arguments pushed on the stack. (Cf. null_check_receiver).
|
||||
int nargs = method()->arg_size();
|
||||
kit.inc_sp(nargs);
|
||||
|
|
|
@ -662,6 +662,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
|||
_inlining_progress(false),
|
||||
_inlining_incrementally(false),
|
||||
_print_inlining_list(NULL),
|
||||
_print_inlining_stream(NULL),
|
||||
_print_inlining_idx(0),
|
||||
_preserve_jvm_state(0) {
|
||||
C = this;
|
||||
|
@ -723,9 +724,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
|
|||
PhaseGVN gvn(node_arena(), estimated_size);
|
||||
set_initial_gvn(&gvn);
|
||||
|
||||
if (print_inlining() || print_intrinsics()) {
|
||||
_print_inlining_list = new (comp_arena())GrowableArray<PrintInliningBuffer>(comp_arena(), 1, 1, PrintInliningBuffer());
|
||||
}
|
||||
print_inlining_init();
|
||||
{ // Scope for timing the parser
|
||||
TracePhase t3("parse", &_t_parser, true);
|
||||
|
||||
|
@ -967,6 +966,7 @@ Compile::Compile( ciEnv* ci_env,
|
|||
_inlining_progress(false),
|
||||
_inlining_incrementally(false),
|
||||
_print_inlining_list(NULL),
|
||||
_print_inlining_stream(NULL),
|
||||
_print_inlining_idx(0),
|
||||
_preserve_jvm_state(0),
|
||||
_allowed_reasons(0) {
|
||||
|
@ -2023,6 +2023,8 @@ void Compile::Optimize() {
|
|||
ResourceMark rm;
|
||||
int loop_opts_cnt;
|
||||
|
||||
print_inlining_reinit();
|
||||
|
||||
NOT_PRODUCT( verify_graph_edges(); )
|
||||
|
||||
print_method(PHASE_AFTER_PARSING);
|
||||
|
@ -3755,30 +3757,114 @@ void Compile::ConstantTable::fill_jump_table(CodeBuffer& cb, MachConstantNode* n
|
|||
}
|
||||
}
|
||||
|
||||
void Compile::dump_inlining() {
|
||||
// The message about the current inlining is accumulated in
|
||||
// _print_inlining_stream and transfered into the _print_inlining_list
|
||||
// once we know whether inlining succeeds or not. For regular
|
||||
// inlining, messages are appended to the buffer pointed by
|
||||
// _print_inlining_idx in the _print_inlining_list. For late inlining,
|
||||
// a new buffer is added after _print_inlining_idx in the list. This
|
||||
// way we can update the inlining message for late inlining call site
|
||||
// when the inlining is attempted again.
|
||||
void Compile::print_inlining_init() {
|
||||
if (print_inlining() || print_intrinsics()) {
|
||||
_print_inlining_stream = new stringStream();
|
||||
_print_inlining_list = new (comp_arena())GrowableArray<PrintInliningBuffer>(comp_arena(), 1, 1, PrintInliningBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
void Compile::print_inlining_reinit() {
|
||||
if (print_inlining() || print_intrinsics()) {
|
||||
// Re allocate buffer when we change ResourceMark
|
||||
_print_inlining_stream = new stringStream();
|
||||
}
|
||||
}
|
||||
|
||||
void Compile::print_inlining_reset() {
|
||||
_print_inlining_stream->reset();
|
||||
}
|
||||
|
||||
void Compile::print_inlining_commit() {
|
||||
assert(print_inlining() || print_intrinsics(), "PrintInlining off?");
|
||||
// Transfer the message from _print_inlining_stream to the current
|
||||
// _print_inlining_list buffer and clear _print_inlining_stream.
|
||||
_print_inlining_list->at(_print_inlining_idx).ss()->write(_print_inlining_stream->as_string(), _print_inlining_stream->size());
|
||||
print_inlining_reset();
|
||||
}
|
||||
|
||||
void Compile::print_inlining_push() {
|
||||
// Add new buffer to the _print_inlining_list at current position
|
||||
_print_inlining_idx++;
|
||||
_print_inlining_list->insert_before(_print_inlining_idx, PrintInliningBuffer());
|
||||
}
|
||||
|
||||
Compile::PrintInliningBuffer& Compile::print_inlining_current() {
|
||||
return _print_inlining_list->at(_print_inlining_idx);
|
||||
}
|
||||
|
||||
void Compile::print_inlining_update(CallGenerator* cg) {
|
||||
if (print_inlining() || print_intrinsics()) {
|
||||
if (!cg->is_late_inline()) {
|
||||
if (print_inlining_current().cg() != NULL) {
|
||||
print_inlining_push();
|
||||
}
|
||||
print_inlining_commit();
|
||||
} else {
|
||||
if (print_inlining_current().cg() != cg &&
|
||||
(print_inlining_current().cg() != NULL ||
|
||||
print_inlining_current().ss()->size() != 0)) {
|
||||
print_inlining_push();
|
||||
}
|
||||
print_inlining_commit();
|
||||
print_inlining_current().set_cg(cg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Compile::print_inlining_move_to(CallGenerator* cg) {
|
||||
// We resume inlining at a late inlining call site. Locate the
|
||||
// corresponding inlining buffer so that we can update it.
|
||||
if (print_inlining()) {
|
||||
for (int i = 0; i < _print_inlining_list->length(); i++) {
|
||||
if (_print_inlining_list->adr_at(i)->cg() == cg) {
|
||||
_print_inlining_idx = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
|
||||
void Compile::print_inlining_update_delayed(CallGenerator* cg) {
|
||||
if (print_inlining()) {
|
||||
assert(_print_inlining_stream->size() > 0, "missing inlining msg");
|
||||
assert(print_inlining_current().cg() == cg, "wrong entry");
|
||||
// replace message with new message
|
||||
_print_inlining_list->at_put(_print_inlining_idx, PrintInliningBuffer());
|
||||
print_inlining_commit();
|
||||
print_inlining_current().set_cg(cg);
|
||||
}
|
||||
}
|
||||
|
||||
void Compile::print_inlining_assert_ready() {
|
||||
assert(!_print_inlining || _print_inlining_stream->size() == 0, "loosing data");
|
||||
}
|
||||
|
||||
void Compile::dump_inlining() {
|
||||
bool do_print_inlining = print_inlining() || print_intrinsics();
|
||||
if (do_print_inlining) {
|
||||
// Print inlining message for candidates that we couldn't inline
|
||||
// for lack of space or non constant receiver
|
||||
// for lack of space
|
||||
for (int i = 0; i < _late_inlines.length(); i++) {
|
||||
CallGenerator* cg = _late_inlines.at(i);
|
||||
cg->print_inlining_late("live nodes > LiveNodeCountInliningCutoff");
|
||||
}
|
||||
Unique_Node_List useful;
|
||||
useful.push(root());
|
||||
for (uint next = 0; next < useful.size(); ++next) {
|
||||
Node* n = useful.at(next);
|
||||
if (n->is_Call() && n->as_Call()->generator() != NULL && n->as_Call()->generator()->call_node() == n) {
|
||||
CallNode* call = n->as_Call();
|
||||
CallGenerator* cg = call->generator();
|
||||
cg->print_inlining_late("receiver not constant");
|
||||
}
|
||||
uint max = n->len();
|
||||
for ( uint i = 0; i < max; ++i ) {
|
||||
Node *m = n->in(i);
|
||||
if ( m == NULL ) continue;
|
||||
useful.push(m);
|
||||
if (!cg->is_mh_late_inline()) {
|
||||
const char* msg = "live nodes > LiveNodeCountInliningCutoff";
|
||||
if (do_print_inlining) {
|
||||
cg->print_inlining_late(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (do_print_inlining) {
|
||||
for (int i = 0; i < _print_inlining_list->length(); i++) {
|
||||
tty->print(_print_inlining_list->adr_at(i)->ss()->as_string());
|
||||
}
|
||||
|
|
|
@ -416,6 +416,7 @@ class Compile : public Phase {
|
|||
void set_cg(CallGenerator* cg) { _cg = cg; }
|
||||
};
|
||||
|
||||
stringStream* _print_inlining_stream;
|
||||
GrowableArray<PrintInliningBuffer>* _print_inlining_list;
|
||||
int _print_inlining_idx;
|
||||
|
||||
|
@ -433,33 +434,24 @@ class Compile : public Phase {
|
|||
|
||||
void* _replay_inline_data; // Pointer to data loaded from file
|
||||
|
||||
void print_inlining_init();
|
||||
void print_inlining_reinit();
|
||||
void print_inlining_commit();
|
||||
void print_inlining_push();
|
||||
PrintInliningBuffer& print_inlining_current();
|
||||
|
||||
public:
|
||||
|
||||
outputStream* print_inlining_stream() const {
|
||||
return _print_inlining_list->adr_at(_print_inlining_idx)->ss();
|
||||
assert(print_inlining() || print_intrinsics(), "PrintInlining off?");
|
||||
return _print_inlining_stream;
|
||||
}
|
||||
|
||||
void print_inlining_skip(CallGenerator* cg) {
|
||||
if (_print_inlining) {
|
||||
_print_inlining_list->adr_at(_print_inlining_idx)->set_cg(cg);
|
||||
_print_inlining_idx++;
|
||||
_print_inlining_list->insert_before(_print_inlining_idx, PrintInliningBuffer());
|
||||
}
|
||||
}
|
||||
|
||||
void print_inlining_insert(CallGenerator* cg) {
|
||||
if (_print_inlining) {
|
||||
for (int i = 0; i < _print_inlining_list->length(); i++) {
|
||||
if (_print_inlining_list->adr_at(i)->cg() == cg) {
|
||||
_print_inlining_list->insert_before(i+1, PrintInliningBuffer());
|
||||
_print_inlining_idx = i+1;
|
||||
_print_inlining_list->adr_at(i)->set_cg(NULL);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
}
|
||||
void print_inlining_update(CallGenerator* cg);
|
||||
void print_inlining_update_delayed(CallGenerator* cg);
|
||||
void print_inlining_move_to(CallGenerator* cg);
|
||||
void print_inlining_assert_ready();
|
||||
void print_inlining_reset();
|
||||
|
||||
void print_inlining(ciMethod* method, int inline_level, int bci, const char* msg = NULL) {
|
||||
stringStream ss;
|
||||
|
|
|
@ -294,6 +294,8 @@ CallGenerator* Compile::call_generator(ciMethod* callee, int vtable_index, bool
|
|||
// There was no special inlining tactic, or it bailed out.
|
||||
// Use a more generic tactic, like a simple call.
|
||||
if (call_does_dispatch) {
|
||||
const char* msg = "virtual call";
|
||||
if (PrintInlining) print_inlining(callee, jvms->depth() - 1, jvms->bci(), msg);
|
||||
return CallGenerator::for_virtual_call(callee, vtable_index);
|
||||
} else {
|
||||
// Class Hierarchy Analysis or Type Profile reveals a unique target,
|
||||
|
@ -396,6 +398,8 @@ void Parse::do_call() {
|
|||
// our contribution to it is cleaned up right here.
|
||||
kill_dead_locals();
|
||||
|
||||
C->print_inlining_assert_ready();
|
||||
|
||||
// Set frequently used booleans
|
||||
const bool is_virtual = bc() == Bytecodes::_invokevirtual;
|
||||
const bool is_virtual_or_interface = is_virtual || bc() == Bytecodes::_invokeinterface;
|
||||
|
@ -531,7 +535,8 @@ void Parse::do_call() {
|
|||
// intrinsic was expecting to optimize. Should always be possible to
|
||||
// get a normal java call that may inline in that case
|
||||
cg = C->call_generator(cg->method(), vtable_index, call_does_dispatch, jvms, try_inline, prof_factor(), speculative_receiver_type, /* allow_intrinsics= */ false);
|
||||
if ((new_jvms = cg->generate(jvms, this)) == NULL) {
|
||||
new_jvms = cg->generate(jvms, this);
|
||||
if (new_jvms == NULL) {
|
||||
guarantee(failing(), "call failed to generate: calls should work");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -620,6 +620,7 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms, Parse* parent_parser) {
|
|||
}
|
||||
// Push the result from the inlined method onto the stack.
|
||||
kit.push_result();
|
||||
C->print_inlining_update(this);
|
||||
return kit.transfer_exceptions_into_jvms();
|
||||
}
|
||||
|
||||
|
@ -637,6 +638,7 @@ JVMState* LibraryIntrinsic::generate(JVMState* jvms, Parse* parent_parser) {
|
|||
}
|
||||
}
|
||||
C->gather_intrinsic_statistics(intrinsic_id(), is_virtual(), Compile::_intrinsic_failed);
|
||||
C->print_inlining_update(this);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -3877,6 +3877,7 @@ void TestMetaspaceAux_test();
|
|||
void TestMetachunk_test();
|
||||
void TestVirtualSpaceNode_test();
|
||||
void TestNewSize_test();
|
||||
void TestOldSize_test();
|
||||
void TestKlass_test();
|
||||
void TestBitMap_test();
|
||||
#if INCLUDE_ALL_GCS
|
||||
|
@ -3903,6 +3904,7 @@ void execute_internal_vm_tests() {
|
|||
run_unit_test(AltHashing::test_alt_hash());
|
||||
run_unit_test(test_loggc_filename());
|
||||
run_unit_test(TestNewSize_test());
|
||||
run_unit_test(TestOldSize_test());
|
||||
run_unit_test(TestKlass_test());
|
||||
run_unit_test(TestBitMap_test());
|
||||
#if INCLUDE_VM_STRUCTS
|
||||
|
|
|
@ -438,6 +438,30 @@ WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobjec
|
|||
return (mh->queued_for_compilation() || nm != NULL);
|
||||
WB_END
|
||||
|
||||
class VM_WhiteBoxOperation : public VM_Operation {
|
||||
public:
|
||||
VM_WhiteBoxOperation() { }
|
||||
VMOp_Type type() const { return VMOp_WhiteBoxOperation; }
|
||||
bool allow_nested_vm_operations() const { return true; }
|
||||
};
|
||||
|
||||
class AlwaysFalseClosure : public BoolObjectClosure {
|
||||
public:
|
||||
bool do_object_b(oop p) { return false; }
|
||||
};
|
||||
|
||||
static AlwaysFalseClosure always_false;
|
||||
|
||||
class VM_WhiteBoxCleanMethodData : public VM_WhiteBoxOperation {
|
||||
public:
|
||||
VM_WhiteBoxCleanMethodData(MethodData* mdo) : _mdo(mdo) { }
|
||||
void doit() {
|
||||
_mdo->clean_method_data(&always_false);
|
||||
}
|
||||
private:
|
||||
MethodData* _mdo;
|
||||
};
|
||||
|
||||
WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
||||
jmethodID jmid = reflected_method_to_jmid(thread, env, method);
|
||||
CHECK_JNI_EXCEPTION(env);
|
||||
|
@ -453,6 +477,8 @@ WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
|
|||
for (int i = 0; i < arg_count; i++) {
|
||||
mdo->set_arg_modified(i, 0);
|
||||
}
|
||||
VM_WhiteBoxCleanMethodData op(mdo);
|
||||
VMThread::execute(&op);
|
||||
}
|
||||
|
||||
mh->clear_not_c1_compilable();
|
||||
|
|
|
@ -1262,8 +1262,6 @@ methodHandle SharedRuntime::resolve_sub_helper(JavaThread *thread,
|
|||
}
|
||||
#endif
|
||||
if (is_virtual) {
|
||||
nmethod* nm = callee_nm;
|
||||
if (nm == NULL) CodeCache::find_blob(caller_frame.pc());
|
||||
CompiledIC* inline_cache = CompiledIC_before(caller_nm, caller_frame.pc());
|
||||
if (inline_cache->is_clean()) {
|
||||
inline_cache->set_to_monomorphic(virtual_call_info);
|
||||
|
|
|
@ -1394,8 +1394,8 @@ void WatcherThread::print_on(outputStream* st) const {
|
|||
void JavaThread::initialize() {
|
||||
// Initialize fields
|
||||
|
||||
// Set the claimed par_id to -1 (ie not claiming any par_ids)
|
||||
set_claimed_par_id(-1);
|
||||
// Set the claimed par_id to UINT_MAX (ie not claiming any par_ids)
|
||||
set_claimed_par_id(UINT_MAX);
|
||||
|
||||
set_saved_exception_pc(NULL);
|
||||
set_threadObj(NULL);
|
||||
|
|
|
@ -1778,12 +1778,12 @@ public:
|
|||
void set_done_attaching_via_jni() { _jni_attach_state = _attached_via_jni; OrderAccess::fence(); }
|
||||
private:
|
||||
// This field is used to determine if a thread has claimed
|
||||
// a par_id: it is -1 if the thread has not claimed a par_id;
|
||||
// a par_id: it is UINT_MAX if the thread has not claimed a par_id;
|
||||
// otherwise its value is the par_id that has been claimed.
|
||||
int _claimed_par_id;
|
||||
uint _claimed_par_id;
|
||||
public:
|
||||
int get_claimed_par_id() { return _claimed_par_id; }
|
||||
void set_claimed_par_id(int id) { _claimed_par_id = id;}
|
||||
uint get_claimed_par_id() { return _claimed_par_id; }
|
||||
void set_claimed_par_id(uint id) { _claimed_par_id = id;}
|
||||
};
|
||||
|
||||
// Inline implementation of JavaThread::current
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
template(Exit) \
|
||||
template(LinuxDllLoad) \
|
||||
template(RotateGCLog) \
|
||||
template(WhiteBoxOperation) \
|
||||
|
||||
class VM_Operation: public CHeapObj<mtInternal> {
|
||||
public:
|
||||
|
|
|
@ -268,7 +268,7 @@ MemoryUsage MetaspacePool::get_memory_usage() {
|
|||
}
|
||||
|
||||
size_t MetaspacePool::used_in_bytes() {
|
||||
return MetaspaceAux::allocated_used_bytes();
|
||||
return MetaspaceAux::used_bytes();
|
||||
}
|
||||
|
||||
size_t MetaspacePool::calculate_max_size() const {
|
||||
|
@ -280,7 +280,7 @@ CompressedKlassSpacePool::CompressedKlassSpacePool() :
|
|||
MemoryPool("Compressed Class Space", NonHeap, 0, CompressedClassSpaceSize, true, false) { }
|
||||
|
||||
size_t CompressedKlassSpacePool::used_in_bytes() {
|
||||
return MetaspaceAux::allocated_used_bytes(Metaspace::ClassType);
|
||||
return MetaspaceAux::used_bytes(Metaspace::ClassType);
|
||||
}
|
||||
|
||||
MemoryUsage CompressedKlassSpacePool::get_memory_usage() {
|
||||
|
|
|
@ -185,7 +185,7 @@ Declares a structure type that can be used in other events.
|
|||
</event>
|
||||
|
||||
<struct id="MetaspaceSizes">
|
||||
<value type="BYTES64" field="capacity" label="Capacity" description="Total available memory to allocate in" />
|
||||
<value type="BYTES64" field="committed" label="Committed" description="Committed memory for this space" />
|
||||
<value type="BYTES64" field="used" label="Used" description="Bytes allocated by objects in the space" />
|
||||
<value type="BYTES64" field="reserved" label="Reserved" description="Reserved memory for this space" />
|
||||
</struct>
|
||||
|
|
|
@ -239,8 +239,8 @@ ParallelTaskTerminator::offer_termination(TerminatorTerminator* terminator) {
|
|||
|
||||
#ifdef TRACESPINNING
|
||||
void ParallelTaskTerminator::print_termination_counts() {
|
||||
gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: " UINT32_FORMAT
|
||||
" Total spins: " UINT32_FORMAT " Total peeks: " UINT32_FORMAT,
|
||||
gclog_or_tty->print_cr("ParallelTaskTerminator Total yields: %u"
|
||||
" Total spins: %u Total peeks: %u",
|
||||
total_yields(),
|
||||
total_spins(),
|
||||
total_peeks());
|
||||
|
|
142
hotspot/test/compiler/profiling/spectrapredefineclass/Agent.java
Normal file
142
hotspot/test/compiler/profiling/spectrapredefineclass/Agent.java
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* 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.security.*;
|
||||
import java.lang.instrument.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import com.sun.tools.attach.VirtualMachine;
|
||||
|
||||
class A {
|
||||
void m() {
|
||||
}
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
void m() {
|
||||
}
|
||||
}
|
||||
|
||||
class C extends A {
|
||||
void m() {
|
||||
}
|
||||
}
|
||||
|
||||
class Test {
|
||||
|
||||
static public void m() throws Exception {
|
||||
for (int i = 0; i < 20000; i++) {
|
||||
m1(a);
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
m1(b);
|
||||
}
|
||||
}
|
||||
|
||||
static boolean m1(A a) {
|
||||
boolean res = Agent.m2(a);
|
||||
return res;
|
||||
}
|
||||
|
||||
static public A a = new A();
|
||||
static public B b = new B();
|
||||
static public C c = new C();
|
||||
}
|
||||
|
||||
public class Agent implements ClassFileTransformer {
|
||||
|
||||
|
||||
static class MemoryChunk {
|
||||
MemoryChunk other;
|
||||
long[] array;
|
||||
MemoryChunk(MemoryChunk other) {
|
||||
other = other;
|
||||
array = new long[1024 * 1024 * 1024];
|
||||
}
|
||||
}
|
||||
|
||||
static public boolean m2(A a) {
|
||||
boolean res = false;
|
||||
if (a.getClass() == B.class) {
|
||||
a.m();
|
||||
} else {
|
||||
res = true;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static public void main(String[] args) throws Exception {
|
||||
// Create speculative trap entries
|
||||
Test.m();
|
||||
|
||||
String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName();
|
||||
int p = nameOfRunningVM.indexOf('@');
|
||||
String pid = nameOfRunningVM.substring(0, p);
|
||||
|
||||
// Make the nmethod go away
|
||||
for (int i = 0; i < 10; i++) {
|
||||
System.gc();
|
||||
}
|
||||
|
||||
// Redefine class
|
||||
try {
|
||||
VirtualMachine vm = VirtualMachine.attach(pid);
|
||||
vm.loadAgent(System.getProperty("test.classes",".") + "/agent.jar", "");
|
||||
vm.detach();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
Test.m();
|
||||
// GC will hit dead method pointer
|
||||
for (int i = 0; i < 10; i++) {
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized byte[] transform(final ClassLoader classLoader,
|
||||
final String className,
|
||||
Class<?> classBeingRedefined,
|
||||
ProtectionDomain protectionDomain,
|
||||
byte[] classfileBuffer) {
|
||||
System.out.println("Transforming class " + className);
|
||||
return classfileBuffer;
|
||||
}
|
||||
|
||||
public static void redefine(String agentArgs, Instrumentation instrumentation, Class to_redefine) {
|
||||
|
||||
try {
|
||||
instrumentation.retransformClasses(to_redefine);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void agentmain(String agentArgs, Instrumentation instrumentation) throws Exception {
|
||||
Agent transformer = new Agent();
|
||||
instrumentation.addTransformer(transformer, true);
|
||||
|
||||
redefine(agentArgs, instrumentation, Test.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.PrintWriter;
|
||||
import com.oracle.java.testlibrary.*;
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8038636
|
||||
* @library /testlibrary
|
||||
* @build Agent
|
||||
* @run main ClassFileInstaller Agent
|
||||
* @run main Launcher
|
||||
* @run main/othervm -XX:-TieredCompilation -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=222 -Xmx1M -XX:ReservedCodeCacheSize=3M Agent
|
||||
*/
|
||||
public class Launcher {
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
PrintWriter pw = new PrintWriter("MANIFEST.MF");
|
||||
pw.println("Agent-Class: Agent");
|
||||
pw.println("Can-Retransform-Classes: true");
|
||||
pw.close();
|
||||
|
||||
ProcessBuilder pb = new ProcessBuilder();
|
||||
pb.command(new String[] { JDKToolFinder.getJDKTool("jar"), "cmf", "MANIFEST.MF", System.getProperty("test.classes",".") + "/agent.jar", "Agent.class"});
|
||||
pb.start().waitFor();
|
||||
}
|
||||
}
|
|
@ -310,7 +310,9 @@ class TestStringDeduplicationTools {
|
|||
}
|
||||
|
||||
System.gc();
|
||||
|
||||
System.out.println("Heap Memory Usage: " + ManagementFactory.getMemoryMXBean().getHeapMemoryUsage().getUsed());
|
||||
System.out.println("Array Header Size: " + unsafe.ARRAY_CHAR_BASE_OFFSET);
|
||||
|
||||
System.out.println("End: MemoryUsageTest");
|
||||
}
|
||||
|
@ -482,31 +484,40 @@ class TestStringDeduplicationTools {
|
|||
public static void testMemoryUsage() throws Exception {
|
||||
// Test that memory usage is reduced after deduplication
|
||||
OutputAnalyzer output;
|
||||
final String usagePattern = "Heap Memory Usage: (\\d+)";
|
||||
final String heapMemoryUsagePattern = "Heap Memory Usage: (\\d+)";
|
||||
final String arrayHeaderSizePattern = "Array Header Size: (\\d+)";
|
||||
|
||||
// Run without deduplication
|
||||
output = MemoryUsageTest.run(false);
|
||||
output.shouldHaveExitValue(0);
|
||||
final long memoryUsageWithoutDedup = Long.parseLong(output.firstMatch(usagePattern, 1));
|
||||
final long heapMemoryUsageWithoutDedup = Long.parseLong(output.firstMatch(heapMemoryUsagePattern, 1));
|
||||
final long arrayHeaderSizeWithoutDedup = Long.parseLong(output.firstMatch(arrayHeaderSizePattern, 1));
|
||||
|
||||
// Run with deduplication
|
||||
output = MemoryUsageTest.run(true);
|
||||
output.shouldHaveExitValue(0);
|
||||
final long memoryUsageWithDedup = Long.parseLong(output.firstMatch(usagePattern, 1));
|
||||
final long heapMemoryUsageWithDedup = Long.parseLong(output.firstMatch(heapMemoryUsagePattern, 1));
|
||||
final long arrayHeaderSizeWithDedup = Long.parseLong(output.firstMatch(arrayHeaderSizePattern, 1));
|
||||
|
||||
// Sanity check to make sure one instance isn't using compressed class pointers and the other not
|
||||
if (arrayHeaderSizeWithoutDedup != arrayHeaderSizeWithDedup) {
|
||||
throw new Exception("Unexpected difference between array header sizes");
|
||||
}
|
||||
|
||||
// Calculate expected memory usage with deduplication enabled. This calculation does
|
||||
// not take alignment and padding into account, so it's a conservative estimate.
|
||||
final long sizeOfChar = 2; // bytes
|
||||
final long bytesSaved = (LargeNumberOfStrings - 1) * (StringLength * sizeOfChar + unsafe.ARRAY_CHAR_BASE_OFFSET);
|
||||
final long memoryUsageWithDedupExpected = memoryUsageWithoutDedup - bytesSaved;
|
||||
final long sizeOfChar = unsafe.ARRAY_CHAR_INDEX_SCALE;
|
||||
final long sizeOfCharArray = StringLength * sizeOfChar + arrayHeaderSizeWithoutDedup;
|
||||
final long bytesSaved = (LargeNumberOfStrings - 1) * sizeOfCharArray;
|
||||
final long heapMemoryUsageWithDedupExpected = heapMemoryUsageWithoutDedup - bytesSaved;
|
||||
|
||||
System.out.println("Memory usage summary:");
|
||||
System.out.println(" memoryUsageWithoutDedup: " + memoryUsageWithoutDedup);
|
||||
System.out.println(" memoryUsageWithDedup: " + memoryUsageWithDedup);
|
||||
System.out.println(" memoryUsageWithDedupExpected: " + memoryUsageWithDedupExpected);
|
||||
System.out.println(" heapMemoryUsageWithoutDedup: " + heapMemoryUsageWithoutDedup);
|
||||
System.out.println(" heapMemoryUsageWithDedup: " + heapMemoryUsageWithDedup);
|
||||
System.out.println(" heapMemoryUsageWithDedupExpected: " + heapMemoryUsageWithDedupExpected);
|
||||
|
||||
if (memoryUsageWithDedup > memoryUsageWithDedupExpected) {
|
||||
throw new Exception("Unexpected memory usage, memoryUsageWithDedup should less or equal to memoryUsageWithDedupExpected");
|
||||
if (heapMemoryUsageWithDedup > heapMemoryUsageWithDedupExpected) {
|
||||
throw new Exception("Unexpected memory usage, heapMemoryUsageWithDedup should be less or equal to heapMemoryUsageWithDedupExpected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue