mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-24 04:54:40 +02:00
Merge
This commit is contained in:
commit
eb4fc599e6
47 changed files with 937 additions and 664 deletions
|
@ -10,7 +10,6 @@
|
|||
.igv.log
|
||||
^.hgtip
|
||||
.DS_Store
|
||||
\.class$
|
||||
^\.mx.jvmci/env
|
||||
^\.mx.jvmci/.*\.pyc
|
||||
^\.mx.jvmci/eclipse-launches/.*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, Red Hat Inc. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
|
@ -32,7 +32,6 @@
|
|||
// Sets the default values for platform dependent flags used by the runtime system.
|
||||
// (see globals.hpp)
|
||||
|
||||
define_pd_global(bool, ConvertSleepToYield, true);
|
||||
define_pd_global(bool, ShareVtableStubs, true);
|
||||
define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2012, 2015 SAP SE. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
|
@ -32,7 +32,6 @@
|
|||
// Sets the default values for platform dependent flags used by the runtime system.
|
||||
// (see globals.hpp)
|
||||
|
||||
define_pd_global(bool, ConvertSleepToYield, true);
|
||||
define_pd_global(bool, ShareVtableStubs, false); // Improves performance markedly for mtrt and compress.
|
||||
define_pd_global(bool, NeedsDeoptSuspend, false); // Only register window machines need this.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -37,7 +37,6 @@
|
|||
// the load of the dispatch address and hence the jmp would still go to the location
|
||||
// according to the prior table. So, we let the thread continue and let it block by itself.
|
||||
define_pd_global(bool, DontYieldALot, true); // yield no more than 100 times per second
|
||||
define_pd_global(bool, ConvertSleepToYield, false); // do not convert sleep(0) to yield. Helps GUI
|
||||
define_pd_global(bool, ShareVtableStubs, false); // improves performance markedly for mtrt and compress
|
||||
define_pd_global(bool, NeedsDeoptSuspend, true); // register window machines need this
|
||||
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
// Sets the default values for platform dependent flags used by the runtime system.
|
||||
// (see globals.hpp)
|
||||
|
||||
define_pd_global(bool, ConvertSleepToYield, true);
|
||||
define_pd_global(bool, ShareVtableStubs, true);
|
||||
define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
|
@ -32,7 +32,6 @@
|
|||
// Set the default values for platform dependent flags used by the
|
||||
// runtime system. See globals.hpp for details of what they do.
|
||||
|
||||
define_pd_global(bool, ConvertSleepToYield, true);
|
||||
define_pd_global(bool, ShareVtableStubs, true);
|
||||
define_pd_global(bool, NeedsDeoptSuspend, false);
|
||||
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.gc.shared;
|
||||
|
||||
//These definitions should be kept in sync with the definitions in the HotSpot code.
|
||||
|
||||
public enum G1HeapRegionType {
|
||||
Free ("Free"),
|
||||
Eden ("Eden"),
|
||||
Survivor ("Survivor"),
|
||||
StartsHumongous ("Starts Humongous"),
|
||||
ContinuesHumongous ("Continues Humongous"),
|
||||
Old ("Old"),
|
||||
Archive ("Archive"),
|
||||
G1HeapRegionTypeEndSentinel ("G1HeapRegionTypeEndSentinel");
|
||||
|
||||
private final String value;
|
||||
|
||||
G1HeapRegionType(String val) {
|
||||
this.value = val;
|
||||
}
|
||||
public String value() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -4042,61 +4042,6 @@ void os::pause() {
|
|||
// could have been signaled after a wait started
|
||||
// 1 : signaled - thread is running or ready
|
||||
//
|
||||
// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can
|
||||
// hang indefinitely. For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable.
|
||||
// For specifics regarding the bug see GLIBC BUGID 261237 :
|
||||
// http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html.
|
||||
// Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future
|
||||
// will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar
|
||||
// is used. (The simple C test-case provided in the GLIBC bug report manifests the
|
||||
// hang). The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos()
|
||||
// and monitorenter when we're using 1-0 locking. All those operations may result in
|
||||
// calls to pthread_cond_timedwait(). Using LD_ASSUME_KERNEL to use an older version
|
||||
// of libpthread avoids the problem, but isn't practical.
|
||||
//
|
||||
// Possible remedies:
|
||||
//
|
||||
// 1. Establish a minimum relative wait time. 50 to 100 msecs seems to work.
|
||||
// This is palliative and probabilistic, however. If the thread is preempted
|
||||
// between the call to compute_abstime() and pthread_cond_timedwait(), more
|
||||
// than the minimum period may have passed, and the abstime may be stale (in the
|
||||
// past) resultin in a hang. Using this technique reduces the odds of a hang
|
||||
// but the JVM is still vulnerable, particularly on heavily loaded systems.
|
||||
//
|
||||
// 2. Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead
|
||||
// of the usual flag-condvar-mutex idiom. The write side of the pipe is set
|
||||
// NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo)
|
||||
// reduces to poll()+read(). This works well, but consumes 2 FDs per extant
|
||||
// thread.
|
||||
//
|
||||
// 3. Embargo pthread_cond_timedwait() and implement a native "chron" thread
|
||||
// that manages timeouts. We'd emulate pthread_cond_timedwait() by enqueuing
|
||||
// a timeout request to the chron thread and then blocking via pthread_cond_wait().
|
||||
// This also works well. In fact it avoids kernel-level scalability impediments
|
||||
// on certain platforms that don't handle lots of active pthread_cond_timedwait()
|
||||
// timers in a graceful fashion.
|
||||
//
|
||||
// 4. When the abstime value is in the past it appears that control returns
|
||||
// correctly from pthread_cond_timedwait(), but the condvar is left corrupt.
|
||||
// Subsequent timedwait/wait calls may hang indefinitely. Given that, we
|
||||
// can avoid the problem by reinitializing the condvar -- by cond_destroy()
|
||||
// followed by cond_init() -- after all calls to pthread_cond_timedwait().
|
||||
// It may be possible to avoid reinitialization by checking the return
|
||||
// value from pthread_cond_timedwait(). In addition to reinitializing the
|
||||
// condvar we must establish the invariant that cond_signal() is only called
|
||||
// within critical sections protected by the adjunct mutex. This prevents
|
||||
// cond_signal() from "seeing" a condvar that's in the midst of being
|
||||
// reinitialized or that is corrupt. Sadly, this invariant obviates the
|
||||
// desirable signal-after-unlock optimization that avoids futile context switching.
|
||||
//
|
||||
// I'm also concerned that some versions of NTPL might allocate an auxilliary
|
||||
// structure when a condvar is used or initialized. cond_destroy() would
|
||||
// release the helper structure. Our reinitialize-after-timedwait fix
|
||||
// put excessive stress on malloc/free and locks protecting the c-heap.
|
||||
//
|
||||
// We currently use (4). See the WorkAroundNTPLTimedWaitHang flag.
|
||||
// It may be possible to refine (4) by checking the kernel and NTPL verisons
|
||||
// and only enabling the work-around for vulnerable environments.
|
||||
|
||||
// utility to compute the abstime argument to timedwait:
|
||||
// millis is the relative timeout time
|
||||
|
@ -4208,10 +4153,6 @@ int os::PlatformEvent::park(jlong millis) {
|
|||
|
||||
while (_Event < 0) {
|
||||
status = pthread_cond_timedwait(_cond, _mutex, &abst);
|
||||
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
|
||||
pthread_cond_destroy(_cond);
|
||||
pthread_cond_init(_cond, NULL);
|
||||
}
|
||||
assert_status(status == 0 || status == EINTR ||
|
||||
status == ETIMEDOUT,
|
||||
status, "cond_timedwait");
|
||||
|
@ -4255,10 +4196,6 @@ void os::PlatformEvent::unpark() {
|
|||
assert_status(status == 0, status, "mutex_lock");
|
||||
int AnyWaiters = _nParked;
|
||||
assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
|
||||
if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
|
||||
AnyWaiters = 0;
|
||||
pthread_cond_signal(_cond);
|
||||
}
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert_status(status == 0, status, "mutex_unlock");
|
||||
if (AnyWaiters != 0) {
|
||||
|
@ -4391,7 +4328,7 @@ void Parker::park(bool isAbsolute, jlong time) {
|
|||
if (_counter > 0) { // no wait needed
|
||||
_counter = 0;
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
assert_status(status == 0, status, "invariant");
|
||||
// Paranoia to ensure our locked and lock-free paths interact
|
||||
// correctly with each other and Java-level accesses.
|
||||
OrderAccess::fence();
|
||||
|
@ -4414,10 +4351,6 @@ void Parker::park(bool isAbsolute, jlong time) {
|
|||
status = pthread_cond_wait(_cond, _mutex);
|
||||
} else {
|
||||
status = pthread_cond_timedwait(_cond, _mutex, &absTime);
|
||||
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
|
||||
pthread_cond_destroy(_cond);
|
||||
pthread_cond_init(_cond, NULL);
|
||||
}
|
||||
}
|
||||
assert_status(status == 0 || status == EINTR ||
|
||||
status == ETIMEDOUT,
|
||||
|
@ -4442,24 +4375,14 @@ void Parker::park(bool isAbsolute, jlong time) {
|
|||
|
||||
void Parker::unpark() {
|
||||
int status = pthread_mutex_lock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
assert_status(status == 0, status, "invariant");
|
||||
const int s = _counter;
|
||||
_counter = 1;
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert_status(status == 0, status, "invariant");
|
||||
if (s < 1) {
|
||||
if (WorkAroundNPTLTimedWaitHang) {
|
||||
status = pthread_cond_signal(_cond);
|
||||
assert(status == 0, "invariant");
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
} else {
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
status = pthread_cond_signal(_cond);
|
||||
assert(status == 0, "invariant");
|
||||
}
|
||||
} else {
|
||||
pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
assert_status(status == 0, status, "invariant");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4771,6 +4771,25 @@ void os::make_polling_page_readable(void) {
|
|||
}
|
||||
}
|
||||
|
||||
// older glibc versions don't have this macro (which expands to
|
||||
// an optimized bit-counting function) so we have to roll our own
|
||||
#ifndef CPU_COUNT
|
||||
|
||||
static int _cpu_count(const cpu_set_t* cpus) {
|
||||
int count = 0;
|
||||
// only look up to the number of configured processors
|
||||
for (int i = 0; i < os::processor_count(); i++) {
|
||||
if (CPU_ISSET(i, cpus)) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#define CPU_COUNT(cpus) _cpu_count(cpus)
|
||||
|
||||
#endif // CPU_COUNT
|
||||
|
||||
// Get the current number of available processors for this process.
|
||||
// This value can change at any time during a process's lifetime.
|
||||
// sched_getaffinity gives an accurate answer as it accounts for cpusets.
|
||||
|
@ -4786,6 +4805,9 @@ int os::active_processor_count() {
|
|||
int configured_cpus = processor_count(); // upper bound on available cpus
|
||||
int cpu_count = 0;
|
||||
|
||||
// old build platforms may not support dynamic cpu sets
|
||||
#ifdef CPU_ALLOC
|
||||
|
||||
// To enable easy testing of the dynamic path on different platforms we
|
||||
// introduce a diagnostic flag: UseCpuAllocPath
|
||||
if (configured_cpus >= CPU_SETSIZE || UseCpuAllocPath) {
|
||||
|
@ -4814,10 +4836,18 @@ int os::active_processor_count() {
|
|||
log_trace(os)("active_processor_count: using static path - configured processors: %d",
|
||||
configured_cpus);
|
||||
}
|
||||
#else // CPU_ALLOC
|
||||
// these stubs won't be executed
|
||||
#define CPU_COUNT_S(size, cpus) -1
|
||||
#define CPU_FREE(cpus)
|
||||
|
||||
log_trace(os)("active_processor_count: only static path available - configured processors: %d",
|
||||
configured_cpus);
|
||||
#endif // CPU_ALLOC
|
||||
|
||||
// pid 0 means the current thread - which we have to assume represents the process
|
||||
if (sched_getaffinity(0, cpus_size, cpus_p) == 0) {
|
||||
if (cpus_p != &cpus) {
|
||||
if (cpus_p != &cpus) { // can only be true when CPU_ALLOC used
|
||||
cpu_count = CPU_COUNT_S(cpus_size, cpus_p);
|
||||
}
|
||||
else {
|
||||
|
@ -4831,7 +4861,7 @@ int os::active_processor_count() {
|
|||
"which may exceed available processors", strerror(errno), cpu_count);
|
||||
}
|
||||
|
||||
if (cpus_p != &cpus) {
|
||||
if (cpus_p != &cpus) { // can only be true when CPU_ALLOC used
|
||||
CPU_FREE(cpus_p);
|
||||
}
|
||||
|
||||
|
@ -5349,61 +5379,6 @@ void os::pause() {
|
|||
// could have been signaled after a wait started
|
||||
// 1 : signaled - thread is running or ready
|
||||
//
|
||||
// Beware -- Some versions of NPTL embody a flaw where pthread_cond_timedwait() can
|
||||
// hang indefinitely. For instance NPTL 0.60 on 2.4.21-4ELsmp is vulnerable.
|
||||
// For specifics regarding the bug see GLIBC BUGID 261237 :
|
||||
// http://www.mail-archive.com/debian-glibc@lists.debian.org/msg10837.html.
|
||||
// Briefly, pthread_cond_timedwait() calls with an expiry time that's not in the future
|
||||
// will either hang or corrupt the condvar, resulting in subsequent hangs if the condvar
|
||||
// is used. (The simple C test-case provided in the GLIBC bug report manifests the
|
||||
// hang). The JVM is vulernable via sleep(), Object.wait(timo), LockSupport.parkNanos()
|
||||
// and monitorenter when we're using 1-0 locking. All those operations may result in
|
||||
// calls to pthread_cond_timedwait(). Using LD_ASSUME_KERNEL to use an older version
|
||||
// of libpthread avoids the problem, but isn't practical.
|
||||
//
|
||||
// Possible remedies:
|
||||
//
|
||||
// 1. Establish a minimum relative wait time. 50 to 100 msecs seems to work.
|
||||
// This is palliative and probabilistic, however. If the thread is preempted
|
||||
// between the call to compute_abstime() and pthread_cond_timedwait(), more
|
||||
// than the minimum period may have passed, and the abstime may be stale (in the
|
||||
// past) resultin in a hang. Using this technique reduces the odds of a hang
|
||||
// but the JVM is still vulnerable, particularly on heavily loaded systems.
|
||||
//
|
||||
// 2. Modify park-unpark to use per-thread (per ParkEvent) pipe-pairs instead
|
||||
// of the usual flag-condvar-mutex idiom. The write side of the pipe is set
|
||||
// NDELAY. unpark() reduces to write(), park() reduces to read() and park(timo)
|
||||
// reduces to poll()+read(). This works well, but consumes 2 FDs per extant
|
||||
// thread.
|
||||
//
|
||||
// 3. Embargo pthread_cond_timedwait() and implement a native "chron" thread
|
||||
// that manages timeouts. We'd emulate pthread_cond_timedwait() by enqueuing
|
||||
// a timeout request to the chron thread and then blocking via pthread_cond_wait().
|
||||
// This also works well. In fact it avoids kernel-level scalability impediments
|
||||
// on certain platforms that don't handle lots of active pthread_cond_timedwait()
|
||||
// timers in a graceful fashion.
|
||||
//
|
||||
// 4. When the abstime value is in the past it appears that control returns
|
||||
// correctly from pthread_cond_timedwait(), but the condvar is left corrupt.
|
||||
// Subsequent timedwait/wait calls may hang indefinitely. Given that, we
|
||||
// can avoid the problem by reinitializing the condvar -- by cond_destroy()
|
||||
// followed by cond_init() -- after all calls to pthread_cond_timedwait().
|
||||
// It may be possible to avoid reinitialization by checking the return
|
||||
// value from pthread_cond_timedwait(). In addition to reinitializing the
|
||||
// condvar we must establish the invariant that cond_signal() is only called
|
||||
// within critical sections protected by the adjunct mutex. This prevents
|
||||
// cond_signal() from "seeing" a condvar that's in the midst of being
|
||||
// reinitialized or that is corrupt. Sadly, this invariant obviates the
|
||||
// desirable signal-after-unlock optimization that avoids futile context switching.
|
||||
//
|
||||
// I'm also concerned that some versions of NTPL might allocate an auxilliary
|
||||
// structure when a condvar is used or initialized. cond_destroy() would
|
||||
// release the helper structure. Our reinitialize-after-timedwait fix
|
||||
// put excessive stress on malloc/free and locks protecting the c-heap.
|
||||
//
|
||||
// We currently use (4). See the WorkAroundNTPLTimedWaitHang flag.
|
||||
// It may be possible to refine (4) by checking the kernel and NTPL verisons
|
||||
// and only enabling the work-around for vulnerable environments.
|
||||
|
||||
// utility to compute the abstime argument to timedwait:
|
||||
// millis is the relative timeout time
|
||||
|
@ -5529,10 +5504,6 @@ int os::PlatformEvent::park(jlong millis) {
|
|||
|
||||
while (_Event < 0) {
|
||||
status = pthread_cond_timedwait(_cond, _mutex, &abst);
|
||||
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
|
||||
pthread_cond_destroy(_cond);
|
||||
pthread_cond_init(_cond, os::Linux::condAttr());
|
||||
}
|
||||
assert_status(status == 0 || status == EINTR ||
|
||||
status == ETIME || status == ETIMEDOUT,
|
||||
status, "cond_timedwait");
|
||||
|
@ -5576,10 +5547,6 @@ void os::PlatformEvent::unpark() {
|
|||
assert_status(status == 0, status, "mutex_lock");
|
||||
int AnyWaiters = _nParked;
|
||||
assert(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
|
||||
if (AnyWaiters != 0 && WorkAroundNPTLTimedWaitHang) {
|
||||
AnyWaiters = 0;
|
||||
pthread_cond_signal(_cond);
|
||||
}
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert_status(status == 0, status, "mutex_unlock");
|
||||
if (AnyWaiters != 0) {
|
||||
|
@ -5731,7 +5698,7 @@ void Parker::park(bool isAbsolute, jlong time) {
|
|||
if (_counter > 0) { // no wait needed
|
||||
_counter = 0;
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
assert_status(status == 0, status, "invariant");
|
||||
// Paranoia to ensure our locked and lock-free paths interact
|
||||
// correctly with each other and Java-level accesses.
|
||||
OrderAccess::fence();
|
||||
|
@ -5757,10 +5724,6 @@ void Parker::park(bool isAbsolute, jlong time) {
|
|||
} else {
|
||||
_cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
|
||||
status = pthread_cond_timedwait(&_cond[_cur_index], _mutex, &absTime);
|
||||
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
|
||||
pthread_cond_destroy(&_cond[_cur_index]);
|
||||
pthread_cond_init(&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
|
||||
}
|
||||
}
|
||||
_cur_index = -1;
|
||||
assert_status(status == 0 || status == EINTR ||
|
||||
|
@ -5786,33 +5749,17 @@ void Parker::park(bool isAbsolute, jlong time) {
|
|||
|
||||
void Parker::unpark() {
|
||||
int status = pthread_mutex_lock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
assert_status(status == 0, status, "invariant");
|
||||
const int s = _counter;
|
||||
_counter = 1;
|
||||
if (s < 1) {
|
||||
// thread might be parked
|
||||
if (_cur_index != -1) {
|
||||
// thread is definitely parked
|
||||
if (WorkAroundNPTLTimedWaitHang) {
|
||||
status = pthread_cond_signal(&_cond[_cur_index]);
|
||||
assert(status == 0, "invariant");
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
} else {
|
||||
// must capture correct index before unlocking
|
||||
int index = _cur_index;
|
||||
status = pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
assert_status(status == 0, status, "invariant");
|
||||
if (s < 1 && index != -1) {
|
||||
// thread is definitely parked
|
||||
status = pthread_cond_signal(&_cond[index]);
|
||||
assert(status == 0, "invariant");
|
||||
}
|
||||
} else {
|
||||
pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
}
|
||||
} else {
|
||||
pthread_mutex_unlock(_mutex);
|
||||
assert(status == 0, "invariant");
|
||||
assert_status(status == 0, status, "invariant");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -246,7 +246,6 @@ bool PICL::bind_library_functions() {
|
|||
bool PICL::open_library() {
|
||||
_dl_handle = dlopen("libpicl.so.1", RTLD_LAZY);
|
||||
if (_dl_handle == NULL) {
|
||||
warning("PICL (libpicl.so.1) is missing. Performance will not be optimal.");
|
||||
return false;
|
||||
}
|
||||
if (!bind_library_functions()) {
|
||||
|
|
|
@ -2206,13 +2206,13 @@ class VerifyAllBlksClosure: public BlkClosure {
|
|||
}
|
||||
if (res == 0) {
|
||||
LogHandle(gc, verify) log;
|
||||
log.info("Livelock: no rank reduction!");
|
||||
log.info(" Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
|
||||
log.error("Livelock: no rank reduction!");
|
||||
log.error(" Current: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n"
|
||||
" Previous: addr = " PTR_FORMAT ", size = " SIZE_FORMAT ", obj = %s, live = %s \n",
|
||||
p2i(addr), res, was_obj ?"true":"false", was_live ?"true":"false",
|
||||
p2i(_last_addr), _last_size, _last_was_obj?"true":"false", _last_was_live?"true":"false");
|
||||
ResourceMark rm;
|
||||
_sp->print_on(log.info_stream());
|
||||
_sp->print_on(log.error_stream());
|
||||
guarantee(false, "Verification failed.");
|
||||
}
|
||||
_last_addr = addr;
|
||||
|
|
|
@ -2224,8 +2224,8 @@ class VerifyMarkedClosure: public BitMapClosure {
|
|||
if (!_marks->isMarked(addr)) {
|
||||
LogHandle(gc, verify) log;
|
||||
ResourceMark rm;
|
||||
oop(addr)->print_on(log.info_stream());
|
||||
log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
|
||||
oop(addr)->print_on(log.error_stream());
|
||||
log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
|
||||
_failed = true;
|
||||
}
|
||||
return true;
|
||||
|
@ -2350,9 +2350,9 @@ void CMSCollector::verify_after_remark_work_1() {
|
|||
verification_mark_bm()->iterate(&vcl);
|
||||
if (vcl.failed()) {
|
||||
LogHandle(gc, verify) log;
|
||||
log.info("Verification failed");
|
||||
log.error("Failed marking verification after remark");
|
||||
ResourceMark rm;
|
||||
gch->print_on(log.info_stream());
|
||||
gch->print_on(log.error_stream());
|
||||
fatal("CMS: failed marking verification after remark");
|
||||
}
|
||||
}
|
||||
|
@ -2923,7 +2923,7 @@ bool CMSCollector::markFromRoots() {
|
|||
|
||||
CMSTokenSyncWithLocks ts(true, bitMapLock());
|
||||
GCTraceCPUTime tcpu;
|
||||
CMSPhaseAccounting pa(this, "Concrurrent Mark");
|
||||
CMSPhaseAccounting pa(this, "Concurrent Mark");
|
||||
bool res = markFromRootsWork();
|
||||
if (res) {
|
||||
_collectorState = Precleaning;
|
||||
|
@ -5880,8 +5880,8 @@ void MarkRefsIntoVerifyClosure::do_oop(oop obj) {
|
|||
if (!_cms_bm->isMarked(addr)) {
|
||||
LogHandle(gc, verify) log;
|
||||
ResourceMark rm;
|
||||
oop(addr)->print_on(log.info_stream());
|
||||
log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
|
||||
oop(addr)->print_on(log.error_stream());
|
||||
log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
|
||||
fatal("... aborting");
|
||||
}
|
||||
}
|
||||
|
@ -6661,8 +6661,8 @@ void PushAndMarkVerifyClosure::do_oop(oop obj) {
|
|||
if (!_cms_bm->isMarked(addr)) {
|
||||
LogHandle(gc, verify) log;
|
||||
ResourceMark rm;
|
||||
oop(addr)->print_on(log.info_stream());
|
||||
log.info(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
|
||||
oop(addr)->print_on(log.error_stream());
|
||||
log.error(" (" INTPTR_FORMAT " should have been marked)", p2i(addr));
|
||||
fatal("... aborting");
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/classLoaderData.hpp"
|
||||
#include "gc/g1/concurrentMarkThread.inline.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1CollectorPolicy.hpp"
|
||||
|
@ -123,6 +124,7 @@ void ConcurrentMarkThread::run_service() {
|
|||
// wait until started is set.
|
||||
sleepBeforeNextCycle();
|
||||
if (_should_terminate) {
|
||||
_cm->root_regions()->cancel_scan();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -132,6 +134,11 @@ void ConcurrentMarkThread::run_service() {
|
|||
HandleMark hm;
|
||||
double cycle_start = os::elapsedVTime();
|
||||
|
||||
{
|
||||
GCConcPhaseTimer(_cm, "Concurrent Clearing of Claimed Marks");
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
}
|
||||
|
||||
// We have to ensure that we finish scanning the root regions
|
||||
// before the next GC takes place. To ensure this we have to
|
||||
// make sure that we do not join the STS until the root regions
|
||||
|
@ -140,7 +147,7 @@ void ConcurrentMarkThread::run_service() {
|
|||
// without the root regions have been scanned which would be a
|
||||
// correctness issue.
|
||||
|
||||
if (!cm()->has_aborted()) {
|
||||
{
|
||||
GCConcPhaseTimer(_cm, "Concurrent Root Region Scanning");
|
||||
_cm->scanRootRegions();
|
||||
}
|
||||
|
|
|
@ -1290,8 +1290,7 @@ bool G1CollectedHeap::do_full_collection(bool explicit_gc,
|
|||
ref_processor_cm()->verify_no_references_recorded();
|
||||
|
||||
// Abandon current iterations of concurrent marking and concurrent
|
||||
// refinement, if any are in progress. We have to do this before
|
||||
// wait_until_scan_finished() below.
|
||||
// refinement, if any are in progress.
|
||||
concurrent_mark()->abort();
|
||||
|
||||
// Make sure we'll choose a new allocation region afterwards.
|
||||
|
@ -2148,7 +2147,7 @@ public:
|
|||
virtual bool doHeapRegion(HeapRegion* hr) {
|
||||
unsigned region_gc_time_stamp = hr->get_gc_time_stamp();
|
||||
if (_gc_time_stamp != region_gc_time_stamp) {
|
||||
log_info(gc, verify)("Region " HR_FORMAT " has GC time stamp = %d, expected %d", HR_FORMAT_PARAMS(hr),
|
||||
log_error(gc, verify)("Region " HR_FORMAT " has GC time stamp = %d, expected %d", HR_FORMAT_PARAMS(hr),
|
||||
region_gc_time_stamp, _gc_time_stamp);
|
||||
_failures = true;
|
||||
}
|
||||
|
@ -2848,7 +2847,7 @@ G1HeapSummary G1CollectedHeap::create_g1_heap_summary() {
|
|||
(g1_policy()->young_list_target_length() * HeapRegion::GrainBytes) - survivor_used_bytes;
|
||||
|
||||
VirtualSpaceSummary heap_summary = create_heap_space_summary();
|
||||
return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes);
|
||||
return G1HeapSummary(heap_summary, used(), eden_used_bytes, eden_capacity_bytes, survivor_used_bytes, num_regions());
|
||||
}
|
||||
|
||||
G1EvacSummary G1CollectedHeap::create_g1_evac_summary(G1EvacStats* stats) {
|
||||
|
@ -5186,7 +5185,7 @@ public:
|
|||
NoYoungRegionsClosure() : _success(true) { }
|
||||
bool doHeapRegion(HeapRegion* r) {
|
||||
if (r->is_young()) {
|
||||
log_info(gc, verify)("Region [" PTR_FORMAT ", " PTR_FORMAT ") tagged as young",
|
||||
log_error(gc, verify)("Region [" PTR_FORMAT ", " PTR_FORMAT ") tagged as young",
|
||||
p2i(r->bottom()), p2i(r->end()));
|
||||
_success = false;
|
||||
}
|
||||
|
|
|
@ -293,30 +293,84 @@ void G1CollectorPolicy::initialize_alignments() {
|
|||
_heap_alignment = MAX3(card_table_alignment, _space_alignment, page_size);
|
||||
}
|
||||
|
||||
void G1CollectorPolicy::initialize_flags() {
|
||||
if (G1HeapRegionSize != HeapRegion::GrainBytes) {
|
||||
FLAG_SET_ERGO(size_t, G1HeapRegionSize, HeapRegion::GrainBytes);
|
||||
}
|
||||
|
||||
if (SurvivorRatio < 1) {
|
||||
vm_exit_during_initialization("Invalid survivor ratio specified");
|
||||
}
|
||||
CollectorPolicy::initialize_flags();
|
||||
_young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags
|
||||
}
|
||||
|
||||
void G1CollectorPolicy::post_heap_initialize() {
|
||||
uintx max_regions = G1CollectedHeap::heap()->max_regions();
|
||||
size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes;
|
||||
if (max_young_size != MaxNewSize) {
|
||||
FLAG_SET_ERGO(size_t, MaxNewSize, max_young_size);
|
||||
}
|
||||
|
||||
_ihop_control = create_ihop_control();
|
||||
}
|
||||
|
||||
G1CollectorState* G1CollectorPolicy::collector_state() const { return _g1->collector_state(); }
|
||||
|
||||
// There are three command line options related to the young gen size:
|
||||
// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is
|
||||
// just a short form for NewSize==MaxNewSize). G1 will use its internal
|
||||
// heuristics to calculate the actual young gen size, so these options
|
||||
// basically only limit the range within which G1 can pick a young gen
|
||||
// size. Also, these are general options taking byte sizes. G1 will
|
||||
// internally work with a number of regions instead. So, some rounding
|
||||
// will occur.
|
||||
//
|
||||
// If nothing related to the the young gen size is set on the command
|
||||
// line we should allow the young gen to be between G1NewSizePercent
|
||||
// and G1MaxNewSizePercent of the heap size. This means that every time
|
||||
// the heap size changes, the limits for the young gen size will be
|
||||
// recalculated.
|
||||
//
|
||||
// If only -XX:NewSize is set we should use the specified value as the
|
||||
// minimum size for young gen. Still using G1MaxNewSizePercent of the
|
||||
// heap as maximum.
|
||||
//
|
||||
// If only -XX:MaxNewSize is set we should use the specified value as the
|
||||
// maximum size for young gen. Still using G1NewSizePercent of the heap
|
||||
// as minimum.
|
||||
//
|
||||
// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values.
|
||||
// No updates when the heap size changes. There is a special case when
|
||||
// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a
|
||||
// different heuristic for calculating the collection set when we do mixed
|
||||
// collection.
|
||||
//
|
||||
// If only -XX:NewRatio is set we should use the specified ratio of the heap
|
||||
// as both min and max. This will be interpreted as "fixed" just like the
|
||||
// NewSize==MaxNewSize case above. But we will update the min and max
|
||||
// every time the heap size changes.
|
||||
//
|
||||
// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is
|
||||
// combined with either NewSize or MaxNewSize. (A warning message is printed.)
|
||||
class G1YoungGenSizer : public CHeapObj<mtGC> {
|
||||
private:
|
||||
enum SizerKind {
|
||||
SizerDefaults,
|
||||
SizerNewSizeOnly,
|
||||
SizerMaxNewSizeOnly,
|
||||
SizerMaxAndNewSize,
|
||||
SizerNewRatio
|
||||
};
|
||||
SizerKind _sizer_kind;
|
||||
uint _min_desired_young_length;
|
||||
uint _max_desired_young_length;
|
||||
bool _adaptive_size;
|
||||
uint calculate_default_min_length(uint new_number_of_heap_regions);
|
||||
uint calculate_default_max_length(uint new_number_of_heap_regions);
|
||||
|
||||
// Update the given values for minimum and maximum young gen length in regions
|
||||
// given the number of heap regions depending on the kind of sizing algorithm.
|
||||
void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length);
|
||||
|
||||
public:
|
||||
G1YoungGenSizer();
|
||||
// Calculate the maximum length of the young gen given the number of regions
|
||||
// depending on the sizing algorithm.
|
||||
uint max_young_length(uint number_of_heap_regions);
|
||||
|
||||
void heap_size_changed(uint new_number_of_heap_regions);
|
||||
uint min_desired_young_length() {
|
||||
return _min_desired_young_length;
|
||||
}
|
||||
uint max_desired_young_length() {
|
||||
return _max_desired_young_length;
|
||||
}
|
||||
|
||||
bool adaptive_young_list_length() const {
|
||||
return _adaptive_size;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true),
|
||||
_min_desired_young_length(0), _max_desired_young_length(0) {
|
||||
if (FLAG_IS_CMDLINE(NewRatio)) {
|
||||
|
@ -412,6 +466,29 @@ void G1YoungGenSizer::heap_size_changed(uint new_number_of_heap_regions) {
|
|||
&_max_desired_young_length);
|
||||
}
|
||||
|
||||
void G1CollectorPolicy::post_heap_initialize() {
|
||||
uintx max_regions = G1CollectedHeap::heap()->max_regions();
|
||||
size_t max_young_size = (size_t)_young_gen_sizer->max_young_length(max_regions) * HeapRegion::GrainBytes;
|
||||
if (max_young_size != MaxNewSize) {
|
||||
FLAG_SET_ERGO(size_t, MaxNewSize, max_young_size);
|
||||
}
|
||||
|
||||
_ihop_control = create_ihop_control();
|
||||
}
|
||||
|
||||
void G1CollectorPolicy::initialize_flags() {
|
||||
if (G1HeapRegionSize != HeapRegion::GrainBytes) {
|
||||
FLAG_SET_ERGO(size_t, G1HeapRegionSize, HeapRegion::GrainBytes);
|
||||
}
|
||||
|
||||
if (SurvivorRatio < 1) {
|
||||
vm_exit_during_initialization("Invalid survivor ratio specified");
|
||||
}
|
||||
CollectorPolicy::initialize_flags();
|
||||
_young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags
|
||||
}
|
||||
|
||||
|
||||
void G1CollectorPolicy::init() {
|
||||
// Set aside an initial future to_space.
|
||||
_g1 = G1CollectedHeap::heap();
|
||||
|
@ -758,7 +835,7 @@ G1CollectorPolicy::verify_young_ages(HeapRegion* head,
|
|||
curr = curr->get_next_young_region()) {
|
||||
SurvRateGroup* group = curr->surv_rate_group();
|
||||
if (group == NULL && !curr->is_survivor()) {
|
||||
log_info(gc, verify)("## %s: encountered NULL surv_rate_group", name);
|
||||
log_error(gc, verify)("## %s: encountered NULL surv_rate_group", name);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
|
@ -766,12 +843,12 @@ G1CollectorPolicy::verify_young_ages(HeapRegion* head,
|
|||
int age = curr->age_in_surv_rate_group();
|
||||
|
||||
if (age < 0) {
|
||||
log_info(gc, verify)("## %s: encountered negative age", name);
|
||||
log_error(gc, verify)("## %s: encountered negative age", name);
|
||||
ret = false;
|
||||
}
|
||||
|
||||
if (age <= prev_age) {
|
||||
log_info(gc, verify)("## %s: region ages are not strictly increasing (%d, %d)", name, age, prev_age);
|
||||
log_error(gc, verify)("## %s: region ages are not strictly increasing (%d, %d)", name, age, prev_age);
|
||||
ret = false;
|
||||
}
|
||||
prev_age = age;
|
||||
|
@ -1601,6 +1678,10 @@ bool G1CollectorPolicy::can_expand_young_list() const {
|
|||
return young_list_length < young_list_max_length;
|
||||
}
|
||||
|
||||
bool G1CollectorPolicy::adaptive_young_list_length() const {
|
||||
return _young_gen_sizer->adaptive_young_list_length();
|
||||
}
|
||||
|
||||
void G1CollectorPolicy::update_max_gc_locker_expansion() {
|
||||
uint expansion_region_num = 0;
|
||||
if (GCLockerEdenExpansionPercent > 0) {
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
class HeapRegion;
|
||||
class CollectionSetChooser;
|
||||
class G1IHOPControl;
|
||||
class G1YoungGenSizer;
|
||||
|
||||
// TraceYoungGenTime collects data on _both_ young and mixed evacuation pauses
|
||||
// (the latter may contain non-young regions - i.e. regions that are
|
||||
|
@ -90,81 +91,6 @@ class TraceOldGenTimeData : public CHeapObj<mtGC> {
|
|||
void print() const;
|
||||
};
|
||||
|
||||
// There are three command line options related to the young gen size:
|
||||
// NewSize, MaxNewSize and NewRatio (There is also -Xmn, but that is
|
||||
// just a short form for NewSize==MaxNewSize). G1 will use its internal
|
||||
// heuristics to calculate the actual young gen size, so these options
|
||||
// basically only limit the range within which G1 can pick a young gen
|
||||
// size. Also, these are general options taking byte sizes. G1 will
|
||||
// internally work with a number of regions instead. So, some rounding
|
||||
// will occur.
|
||||
//
|
||||
// If nothing related to the the young gen size is set on the command
|
||||
// line we should allow the young gen to be between G1NewSizePercent
|
||||
// and G1MaxNewSizePercent of the heap size. This means that every time
|
||||
// the heap size changes, the limits for the young gen size will be
|
||||
// recalculated.
|
||||
//
|
||||
// If only -XX:NewSize is set we should use the specified value as the
|
||||
// minimum size for young gen. Still using G1MaxNewSizePercent of the
|
||||
// heap as maximum.
|
||||
//
|
||||
// If only -XX:MaxNewSize is set we should use the specified value as the
|
||||
// maximum size for young gen. Still using G1NewSizePercent of the heap
|
||||
// as minimum.
|
||||
//
|
||||
// If -XX:NewSize and -XX:MaxNewSize are both specified we use these values.
|
||||
// No updates when the heap size changes. There is a special case when
|
||||
// NewSize==MaxNewSize. This is interpreted as "fixed" and will use a
|
||||
// different heuristic for calculating the collection set when we do mixed
|
||||
// collection.
|
||||
//
|
||||
// If only -XX:NewRatio is set we should use the specified ratio of the heap
|
||||
// as both min and max. This will be interpreted as "fixed" just like the
|
||||
// NewSize==MaxNewSize case above. But we will update the min and max
|
||||
// every time the heap size changes.
|
||||
//
|
||||
// NewSize and MaxNewSize override NewRatio. So, NewRatio is ignored if it is
|
||||
// combined with either NewSize or MaxNewSize. (A warning message is printed.)
|
||||
class G1YoungGenSizer : public CHeapObj<mtGC> {
|
||||
private:
|
||||
enum SizerKind {
|
||||
SizerDefaults,
|
||||
SizerNewSizeOnly,
|
||||
SizerMaxNewSizeOnly,
|
||||
SizerMaxAndNewSize,
|
||||
SizerNewRatio
|
||||
};
|
||||
SizerKind _sizer_kind;
|
||||
uint _min_desired_young_length;
|
||||
uint _max_desired_young_length;
|
||||
bool _adaptive_size;
|
||||
uint calculate_default_min_length(uint new_number_of_heap_regions);
|
||||
uint calculate_default_max_length(uint new_number_of_heap_regions);
|
||||
|
||||
// Update the given values for minimum and maximum young gen length in regions
|
||||
// given the number of heap regions depending on the kind of sizing algorithm.
|
||||
void recalculate_min_max_young_length(uint number_of_heap_regions, uint* min_young_length, uint* max_young_length);
|
||||
|
||||
public:
|
||||
G1YoungGenSizer();
|
||||
// Calculate the maximum length of the young gen given the number of regions
|
||||
// depending on the sizing algorithm.
|
||||
uint max_young_length(uint number_of_heap_regions);
|
||||
|
||||
void heap_size_changed(uint new_number_of_heap_regions);
|
||||
uint min_desired_young_length() {
|
||||
return _min_desired_young_length;
|
||||
}
|
||||
uint max_desired_young_length() {
|
||||
return _max_desired_young_length;
|
||||
}
|
||||
|
||||
bool adaptive_young_list_length() const {
|
||||
return _adaptive_size;
|
||||
}
|
||||
};
|
||||
|
||||
class G1CollectorPolicy: public CollectorPolicy {
|
||||
private:
|
||||
G1IHOPControl* _ihop_control;
|
||||
|
@ -784,9 +710,7 @@ public:
|
|||
return _young_list_max_length;
|
||||
}
|
||||
|
||||
bool adaptive_young_list_length() const {
|
||||
return _young_gen_sizer->adaptive_young_list_length();
|
||||
}
|
||||
bool adaptive_young_list_length() const;
|
||||
|
||||
virtual bool should_process_references() const {
|
||||
return true;
|
||||
|
|
|
@ -372,6 +372,16 @@ HeapRegion* G1CMRootRegions::claim_next() {
|
|||
return res;
|
||||
}
|
||||
|
||||
void G1CMRootRegions::notify_scan_done() {
|
||||
MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
|
||||
_scan_in_progress = false;
|
||||
RootRegionScan_lock->notify_all();
|
||||
}
|
||||
|
||||
void G1CMRootRegions::cancel_scan() {
|
||||
notify_scan_done();
|
||||
}
|
||||
|
||||
void G1CMRootRegions::scan_finished() {
|
||||
assert(scan_in_progress(), "pre-condition");
|
||||
|
||||
|
@ -381,11 +391,7 @@ void G1CMRootRegions::scan_finished() {
|
|||
}
|
||||
_next_survivor = NULL;
|
||||
|
||||
{
|
||||
MutexLockerEx x(RootRegionScan_lock, Mutex::_no_safepoint_check_flag);
|
||||
_scan_in_progress = false;
|
||||
RootRegionScan_lock->notify_all();
|
||||
}
|
||||
notify_scan_done();
|
||||
}
|
||||
|
||||
bool G1CMRootRegions::wait_until_scan_finished() {
|
||||
|
@ -978,13 +984,11 @@ public:
|
|||
};
|
||||
|
||||
void G1ConcurrentMark::scanRootRegions() {
|
||||
// Start of concurrent marking.
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
|
||||
// scan_in_progress() will have been set to true only if there was
|
||||
// at least one root region to scan. So, if it's false, we
|
||||
// should not attempt to do any further work.
|
||||
if (root_regions()->scan_in_progress()) {
|
||||
assert(!has_aborted(), "Aborting before root region scanning is finished not supported.");
|
||||
GCTraceConcTime(Info, gc) tt("Concurrent Root Region Scan");
|
||||
|
||||
_parallel_marking_threads = calc_parallel_marking_threads();
|
||||
|
|
|
@ -229,6 +229,8 @@ private:
|
|||
volatile bool _should_abort;
|
||||
HeapRegion* volatile _next_survivor;
|
||||
|
||||
void notify_scan_done();
|
||||
|
||||
public:
|
||||
G1CMRootRegions();
|
||||
// We actually do most of the initialization in this method.
|
||||
|
@ -248,6 +250,8 @@ public:
|
|||
// all have been claimed.
|
||||
HeapRegion* claim_next();
|
||||
|
||||
void cancel_scan();
|
||||
|
||||
// Flag that we're done with root region scanning and notify anyone
|
||||
// who's waiting on it. If aborted is false, assume that all regions
|
||||
// have been claimed.
|
||||
|
|
58
hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp
Normal file
58
hotspot/src/share/vm/gc/g1/g1HeapRegionTraceType.hpp
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_GC_G1_G1HEAPREGIONTRACETYPE_HPP
|
||||
#define SHARE_VM_GC_G1_G1HEAPREGIONTRACETYPE_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
#include "utilities/debug.hpp"
|
||||
|
||||
class G1HeapRegionTraceType : AllStatic {
|
||||
public:
|
||||
enum Type {
|
||||
Free,
|
||||
Eden,
|
||||
Survivor,
|
||||
StartsHumongous,
|
||||
ContinuesHumongous,
|
||||
Old,
|
||||
Archive,
|
||||
G1HeapRegionTypeEndSentinel
|
||||
};
|
||||
|
||||
static const char* to_string(G1HeapRegionTraceType::Type type) {
|
||||
switch (type) {
|
||||
case Free: return "Free";
|
||||
case Eden: return "Eden";
|
||||
case Survivor: return "Survivor";
|
||||
case StartsHumongous: return "Starts Humongous";
|
||||
case ContinuesHumongous: return "Continues Humongous";
|
||||
case Old: return "Old";
|
||||
case Archive: return "Archive";
|
||||
default: ShouldNotReachHere(); return NULL;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_G1_G1HEAPREGIONTRACETYPE_HPP
|
|
@ -63,10 +63,10 @@ public:
|
|||
LogHandle(gc, verify) log;
|
||||
log.info("Root location " PTR_FORMAT " points to dead obj " PTR_FORMAT, p2i(p), p2i(obj));
|
||||
if (_vo == VerifyOption_G1UseMarkWord) {
|
||||
log.info(" Mark word: " PTR_FORMAT, p2i(obj->mark()));
|
||||
log.error(" Mark word: " PTR_FORMAT, p2i(obj->mark()));
|
||||
}
|
||||
ResourceMark rm;
|
||||
obj->print_on(log.info_stream());
|
||||
obj->print_on(log.error_stream());
|
||||
_failures = true;
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ class G1VerifyCodeRootOopClosure: public OopClosure {
|
|||
// Verify that the strong code root list for this region
|
||||
// contains the nmethod
|
||||
if (!hrrs->strong_code_roots_list_contains(_nm)) {
|
||||
log_info(gc, verify)("Code root location " PTR_FORMAT " "
|
||||
log_error(gc, verify)("Code root location " PTR_FORMAT " "
|
||||
"from nmethod " PTR_FORMAT " not in strong "
|
||||
"code roots for region [" PTR_FORMAT "," PTR_FORMAT ")",
|
||||
p2i(p), p2i(_nm), p2i(hr->bottom()), p2i(hr->end()));
|
||||
|
@ -292,7 +292,7 @@ public:
|
|||
r->object_iterate(¬_dead_yet_cl);
|
||||
if (_vo != VerifyOption_G1UseNextMarking) {
|
||||
if (r->max_live_bytes() < not_dead_yet_cl.live_bytes()) {
|
||||
log_info(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT,
|
||||
log_error(gc, verify)("[" PTR_FORMAT "," PTR_FORMAT "] max_live_bytes " SIZE_FORMAT " < calculated " SIZE_FORMAT,
|
||||
p2i(r->bottom()), p2i(r->end()), r->max_live_bytes(), not_dead_yet_cl.live_bytes());
|
||||
_failures = true;
|
||||
}
|
||||
|
@ -402,13 +402,13 @@ void G1HeapVerifier::verify(VerifyOption vo) {
|
|||
}
|
||||
|
||||
if (failures) {
|
||||
log_info(gc, verify)("Heap after failed verification:");
|
||||
log_error(gc, verify)("Heap after failed verification:");
|
||||
// It helps to have the per-region information in the output to
|
||||
// help us track down what went wrong. This is why we call
|
||||
// print_extended_on() instead of print_on().
|
||||
LogHandle(gc, verify) log;
|
||||
ResourceMark rm;
|
||||
_g1h->print_extended_on(log.info_stream());
|
||||
_g1h->print_extended_on(log.error_stream());
|
||||
}
|
||||
guarantee(!failures, "there should not have been any failures");
|
||||
}
|
||||
|
@ -597,8 +597,8 @@ bool G1HeapVerifier::verify_no_bits_over_tams(const char* bitmap_name, G1CMBitMa
|
|||
"tams: " PTR_FORMAT " end: " PTR_FORMAT, p2i(tams), p2i(end));
|
||||
HeapWord* result = bitmap->getNextMarkedWordAddress(tams, end);
|
||||
if (result < end) {
|
||||
log_info(gc, verify)("## wrong marked address on %s bitmap: " PTR_FORMAT, bitmap_name, p2i(result));
|
||||
log_info(gc, verify)("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, bitmap_name, p2i(tams), p2i(end));
|
||||
log_error(gc, verify)("## wrong marked address on %s bitmap: " PTR_FORMAT, bitmap_name, p2i(result));
|
||||
log_error(gc, verify)("## %s tams: " PTR_FORMAT " end: " PTR_FORMAT, bitmap_name, p2i(tams), p2i(end));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -623,8 +623,8 @@ bool G1HeapVerifier::verify_bitmaps(const char* caller, HeapRegion* hr) {
|
|||
res_n = verify_no_bits_over_tams("next", next_bitmap, ntams, end);
|
||||
}
|
||||
if (!res_p || !res_n) {
|
||||
log_info(gc, verify)("#### Bitmap verification failed for " HR_FORMAT, HR_FORMAT_PARAMS(hr));
|
||||
log_info(gc, verify)("#### Caller: %s", caller);
|
||||
log_error(gc, verify)("#### Bitmap verification failed for " HR_FORMAT, HR_FORMAT_PARAMS(hr));
|
||||
log_error(gc, verify)("#### Caller: %s", caller);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -676,41 +676,41 @@ class G1CheckCSetFastTableClosure : public HeapRegionClosure {
|
|||
InCSetState cset_state = (InCSetState) G1CollectedHeap::heap()->_in_cset_fast_test.get_by_index(i);
|
||||
if (hr->is_humongous()) {
|
||||
if (hr->in_collection_set()) {
|
||||
log_info(gc, verify)("## humongous region %u in CSet", i);
|
||||
log_error(gc, verify)("## humongous region %u in CSet", i);
|
||||
_failures = true;
|
||||
return true;
|
||||
}
|
||||
if (cset_state.is_in_cset()) {
|
||||
log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
|
||||
log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for humongous region %u", cset_state.value(), i);
|
||||
_failures = true;
|
||||
return true;
|
||||
}
|
||||
if (hr->is_continues_humongous() && cset_state.is_humongous()) {
|
||||
log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
|
||||
log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for continues humongous region %u", cset_state.value(), i);
|
||||
_failures = true;
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (cset_state.is_humongous()) {
|
||||
log_info(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
|
||||
log_error(gc, verify)("## inconsistent cset state " CSETSTATE_FORMAT " for non-humongous region %u", cset_state.value(), i);
|
||||
_failures = true;
|
||||
return true;
|
||||
}
|
||||
if (hr->in_collection_set() != cset_state.is_in_cset()) {
|
||||
log_info(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
|
||||
log_error(gc, verify)("## in CSet %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
|
||||
hr->in_collection_set(), cset_state.value(), i);
|
||||
_failures = true;
|
||||
return true;
|
||||
}
|
||||
if (cset_state.is_in_cset()) {
|
||||
if (hr->is_young() != (cset_state.is_young())) {
|
||||
log_info(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
|
||||
log_error(gc, verify)("## is_young %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
|
||||
hr->is_young(), cset_state.value(), i);
|
||||
_failures = true;
|
||||
return true;
|
||||
}
|
||||
if (hr->is_old() != (cset_state.is_old())) {
|
||||
log_info(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
|
||||
log_error(gc, verify)("## is_old %d / cset state " CSETSTATE_FORMAT " inconsistency for region %u",
|
||||
hr->is_old(), cset_state.value(), i);
|
||||
_failures = true;
|
||||
return true;
|
||||
|
|
|
@ -26,11 +26,13 @@
|
|||
#include "code/nmethod.hpp"
|
||||
#include "gc/g1/g1BlockOffsetTable.inline.hpp"
|
||||
#include "gc/g1/g1CollectedHeap.inline.hpp"
|
||||
#include "gc/g1/g1HeapRegionTraceType.hpp"
|
||||
#include "gc/g1/g1OopClosures.inline.hpp"
|
||||
#include "gc/g1/heapRegion.inline.hpp"
|
||||
#include "gc/g1/heapRegionBounds.inline.hpp"
|
||||
#include "gc/g1/heapRegionManager.inline.hpp"
|
||||
#include "gc/g1/heapRegionRemSet.hpp"
|
||||
#include "gc/g1/heapRegionTracer.hpp"
|
||||
#include "gc/shared/genOopClosures.inline.hpp"
|
||||
#include "gc/shared/liveRange.hpp"
|
||||
#include "gc/shared/space.inline.hpp"
|
||||
|
@ -212,10 +214,41 @@ void HeapRegion::calc_gc_efficiency() {
|
|||
_gc_efficiency = (double) reclaimable_bytes() / region_elapsed_time_ms;
|
||||
}
|
||||
|
||||
void HeapRegion::set_free() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Free);
|
||||
_type.set_free();
|
||||
}
|
||||
|
||||
void HeapRegion::set_eden() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Eden);
|
||||
_type.set_eden();
|
||||
}
|
||||
|
||||
void HeapRegion::set_eden_pre_gc() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Eden);
|
||||
_type.set_eden_pre_gc();
|
||||
}
|
||||
|
||||
void HeapRegion::set_survivor() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Survivor);
|
||||
_type.set_survivor();
|
||||
}
|
||||
|
||||
void HeapRegion::set_old() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Old);
|
||||
_type.set_old();
|
||||
}
|
||||
|
||||
void HeapRegion::set_archive() {
|
||||
report_region_type_change(G1HeapRegionTraceType::Archive);
|
||||
_type.set_archive();
|
||||
}
|
||||
|
||||
void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) {
|
||||
assert(!is_humongous(), "sanity / pre-condition");
|
||||
assert(top() == bottom(), "should be empty");
|
||||
|
||||
report_region_type_change(G1HeapRegionTraceType::StartsHumongous);
|
||||
_type.set_starts_humongous();
|
||||
_humongous_start_region = this;
|
||||
|
||||
|
@ -227,6 +260,7 @@ void HeapRegion::set_continues_humongous(HeapRegion* first_hr) {
|
|||
assert(top() == bottom(), "should be empty");
|
||||
assert(first_hr->is_starts_humongous(), "pre-condition");
|
||||
|
||||
report_region_type_change(G1HeapRegionTraceType::ContinuesHumongous);
|
||||
_type.set_continues_humongous();
|
||||
_humongous_start_region = first_hr;
|
||||
}
|
||||
|
@ -272,6 +306,15 @@ void HeapRegion::initialize(MemRegion mr, bool clear_space, bool mangle_space) {
|
|||
record_timestamp();
|
||||
}
|
||||
|
||||
void HeapRegion::report_region_type_change(G1HeapRegionTraceType::Type to) {
|
||||
HeapRegionTracer::send_region_type_change(_hrm_index,
|
||||
get_trace_type(),
|
||||
to,
|
||||
(uintptr_t)bottom(),
|
||||
used(),
|
||||
(uint)allocation_context());
|
||||
}
|
||||
|
||||
CompactibleSpace* HeapRegion::next_compaction_space() const {
|
||||
return G1CollectedHeap::heap()->next_compaction_region(this);
|
||||
}
|
||||
|
@ -479,7 +522,7 @@ class VerifyStrongCodeRootOopClosure: public OopClosure {
|
|||
// Object is in the region. Check that its less than top
|
||||
if (_hr->top() <= (HeapWord*)obj) {
|
||||
// Object is above top
|
||||
log_info(gc, verify)("Object " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ") is above top " PTR_FORMAT,
|
||||
log_error(gc, verify)("Object " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ") is above top " PTR_FORMAT,
|
||||
p2i(obj), p2i(_hr->bottom()), p2i(_hr->end()), p2i(_hr->top()));
|
||||
_failures = true;
|
||||
return;
|
||||
|
@ -513,18 +556,18 @@ public:
|
|||
if (nm != NULL) {
|
||||
// Verify that the nemthod is live
|
||||
if (!nm->is_alive()) {
|
||||
log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " PTR_FORMAT " in its strong code roots",
|
||||
log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has dead nmethod " PTR_FORMAT " in its strong code roots",
|
||||
p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
|
||||
_failures = true;
|
||||
} else {
|
||||
VerifyStrongCodeRootOopClosure oop_cl(_hr, nm);
|
||||
nm->oops_do(&oop_cl);
|
||||
if (!oop_cl.has_oops_in_region()) {
|
||||
log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its strong code roots with no pointers into region",
|
||||
log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its strong code roots with no pointers into region",
|
||||
p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
|
||||
_failures = true;
|
||||
} else if (oop_cl.failures()) {
|
||||
log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has other failures for nmethod " PTR_FORMAT,
|
||||
log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has other failures for nmethod " PTR_FORMAT,
|
||||
p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm));
|
||||
_failures = true;
|
||||
}
|
||||
|
@ -558,7 +601,7 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const
|
|||
// on its strong code root list
|
||||
if (is_empty()) {
|
||||
if (strong_code_roots_length > 0) {
|
||||
log_info(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] is empty but has " SIZE_FORMAT " code root entries",
|
||||
log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] is empty but has " SIZE_FORMAT " code root entries",
|
||||
p2i(bottom()), p2i(end()), strong_code_roots_length);
|
||||
*failures = true;
|
||||
}
|
||||
|
@ -567,7 +610,7 @@ void HeapRegion::verify_strong_code_roots(VerifyOption vo, bool* failures) const
|
|||
|
||||
if (is_continues_humongous()) {
|
||||
if (strong_code_roots_length > 0) {
|
||||
log_info(gc, verify)("region " HR_FORMAT " is a continuation of a humongous region but has " SIZE_FORMAT " code root entries",
|
||||
log_error(gc, verify)("region " HR_FORMAT " is a continuation of a humongous region but has " SIZE_FORMAT " code root entries",
|
||||
HR_FORMAT_PARAMS(this), strong_code_roots_length);
|
||||
*failures = true;
|
||||
}
|
||||
|
@ -661,26 +704,26 @@ public:
|
|||
Mutex::_no_safepoint_check_flag);
|
||||
|
||||
if (!_failures) {
|
||||
log.info("----------");
|
||||
log.error("----------");
|
||||
}
|
||||
ResourceMark rm;
|
||||
if (!_g1h->is_in_closed_subset(obj)) {
|
||||
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
|
||||
log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end()));
|
||||
print_object(log.info_stream(), _containing_obj);
|
||||
log.info("points to obj " PTR_FORMAT " not in the heap", p2i(obj));
|
||||
print_object(log.error_stream(), _containing_obj);
|
||||
log.error("points to obj " PTR_FORMAT " not in the heap", p2i(obj));
|
||||
} else {
|
||||
HeapRegion* from = _g1h->heap_region_containing((HeapWord*)p);
|
||||
HeapRegion* to = _g1h->heap_region_containing((HeapWord*)obj);
|
||||
log.info("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
log.error("Field " PTR_FORMAT " of live obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(p), p2i(_containing_obj), p2i(from->bottom()), p2i(from->end()));
|
||||
print_object(log.info_stream(), _containing_obj);
|
||||
log.info("points to dead obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
print_object(log.error_stream(), _containing_obj);
|
||||
log.error("points to dead obj " PTR_FORMAT " in region [" PTR_FORMAT ", " PTR_FORMAT ")",
|
||||
p2i(obj), p2i(to->bottom()), p2i(to->end()));
|
||||
print_object(log.info_stream(), obj);
|
||||
print_object(log.error_stream(), obj);
|
||||
}
|
||||
log.info("----------");
|
||||
log.error("----------");
|
||||
_failures = true;
|
||||
failed = true;
|
||||
_n_failures++;
|
||||
|
@ -730,17 +773,17 @@ public:
|
|||
Mutex::_no_safepoint_check_flag);
|
||||
|
||||
if (!_failures) {
|
||||
log.info("----------");
|
||||
log.error("----------");
|
||||
}
|
||||
log.info("Missing rem set entry:");
|
||||
log.info("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT,
|
||||
log.error("Missing rem set entry:");
|
||||
log.error("Field " PTR_FORMAT " of obj " PTR_FORMAT ", in region " HR_FORMAT,
|
||||
p2i(p), p2i(_containing_obj), HR_FORMAT_PARAMS(from));
|
||||
ResourceMark rm;
|
||||
_containing_obj->print_on(log.info_stream());
|
||||
log.info("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to));
|
||||
obj->print_on(log.info_stream());
|
||||
log.info("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field);
|
||||
log.info("----------");
|
||||
_containing_obj->print_on(log.error_stream());
|
||||
log.error("points to obj " PTR_FORMAT " in region " HR_FORMAT, p2i(obj), HR_FORMAT_PARAMS(to));
|
||||
obj->print_on(log.error_stream());
|
||||
log.error("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field);
|
||||
log.error("----------");
|
||||
_failures = true;
|
||||
if (!failed) _n_failures++;
|
||||
}
|
||||
|
@ -774,12 +817,12 @@ void HeapRegion::verify(VerifyOption vo,
|
|||
(vo == VerifyOption_G1UsePrevMarking &&
|
||||
ClassLoaderDataGraph::unload_list_contains(klass));
|
||||
if (!is_metaspace_object) {
|
||||
log_info(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
|
||||
log_error(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
|
||||
"not metadata", p2i(klass), p2i(obj));
|
||||
*failures = true;
|
||||
return;
|
||||
} else if (!klass->is_klass()) {
|
||||
log_info(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
|
||||
log_error(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " "
|
||||
"not a klass", p2i(klass), p2i(obj));
|
||||
*failures = true;
|
||||
return;
|
||||
|
@ -811,7 +854,7 @@ void HeapRegion::verify(VerifyOption vo,
|
|||
}
|
||||
}
|
||||
} else {
|
||||
log_info(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
|
||||
log_error(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
|
||||
*failures = true;
|
||||
return;
|
||||
}
|
||||
|
@ -827,12 +870,14 @@ void HeapRegion::verify(VerifyOption vo,
|
|||
if (is_region_humongous) {
|
||||
oop obj = oop(this->humongous_start_region()->bottom());
|
||||
if ((HeapWord*)obj > bottom() || (HeapWord*)obj + obj->size() < bottom()) {
|
||||
log_info(gc, verify)("this humongous region is not part of its' humongous object " PTR_FORMAT, p2i(obj));
|
||||
log_error(gc, verify)("this humongous region is not part of its' humongous object " PTR_FORMAT, p2i(obj));
|
||||
*failures = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_region_humongous && p != top()) {
|
||||
log_info(gc, verify)("end of last object " PTR_FORMAT " "
|
||||
log_error(gc, verify)("end of last object " PTR_FORMAT " "
|
||||
"does not match top " PTR_FORMAT, p2i(p), p2i(top()));
|
||||
*failures = true;
|
||||
return;
|
||||
|
@ -847,7 +892,7 @@ void HeapRegion::verify(VerifyOption vo,
|
|||
HeapWord* addr_1 = p;
|
||||
HeapWord* b_start_1 = _bot_part.block_start_const(addr_1);
|
||||
if (b_start_1 != p) {
|
||||
log_info(gc, verify)("BOT look up for top: " PTR_FORMAT " "
|
||||
log_error(gc, verify)("BOT look up for top: " PTR_FORMAT " "
|
||||
" yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
|
||||
p2i(addr_1), p2i(b_start_1), p2i(p));
|
||||
*failures = true;
|
||||
|
@ -859,7 +904,7 @@ void HeapRegion::verify(VerifyOption vo,
|
|||
if (addr_2 < the_end) {
|
||||
HeapWord* b_start_2 = _bot_part.block_start_const(addr_2);
|
||||
if (b_start_2 != p) {
|
||||
log_info(gc, verify)("BOT look up for top + 1: " PTR_FORMAT " "
|
||||
log_error(gc, verify)("BOT look up for top + 1: " PTR_FORMAT " "
|
||||
" yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
|
||||
p2i(addr_2), p2i(b_start_2), p2i(p));
|
||||
*failures = true;
|
||||
|
@ -873,7 +918,7 @@ void HeapRegion::verify(VerifyOption vo,
|
|||
if (addr_3 < the_end) {
|
||||
HeapWord* b_start_3 = _bot_part.block_start_const(addr_3);
|
||||
if (b_start_3 != p) {
|
||||
log_info(gc, verify)("BOT look up for top + diff: " PTR_FORMAT " "
|
||||
log_error(gc, verify)("BOT look up for top + diff: " PTR_FORMAT " "
|
||||
" yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
|
||||
p2i(addr_3), p2i(b_start_3), p2i(p));
|
||||
*failures = true;
|
||||
|
@ -885,7 +930,7 @@ void HeapRegion::verify(VerifyOption vo,
|
|||
HeapWord* addr_4 = the_end - 1;
|
||||
HeapWord* b_start_4 = _bot_part.block_start_const(addr_4);
|
||||
if (b_start_4 != p) {
|
||||
log_info(gc, verify)("BOT look up for end - 1: " PTR_FORMAT " "
|
||||
log_error(gc, verify)("BOT look up for end - 1: " PTR_FORMAT " "
|
||||
" yielded " PTR_FORMAT ", expecting " PTR_FORMAT,
|
||||
p2i(addr_4), p2i(b_start_4), p2i(p));
|
||||
*failures = true;
|
||||
|
@ -924,7 +969,7 @@ void HeapRegion::verify_rem_set(VerifyOption vo, bool* failures) const {
|
|||
return;
|
||||
}
|
||||
} else {
|
||||
log_info(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
|
||||
log_error(gc, verify)(PTR_FORMAT " not an oop", p2i(obj));
|
||||
*failures = true;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
|
||||
#include "gc/g1/g1AllocationContext.hpp"
|
||||
#include "gc/g1/g1BlockOffsetTable.hpp"
|
||||
#include "gc/g1/g1HeapRegionTraceType.hpp"
|
||||
#include "gc/g1/heapRegionTracer.hpp"
|
||||
#include "gc/g1/heapRegionType.hpp"
|
||||
#include "gc/g1/survRateGroup.hpp"
|
||||
#include "gc/shared/ageTable.hpp"
|
||||
|
@ -243,6 +245,8 @@ class HeapRegion: public G1ContiguousSpace {
|
|||
return HeapRegion::block_size(addr); // Avoid virtual call
|
||||
}
|
||||
|
||||
void report_region_type_change(G1HeapRegionTraceType::Type to);
|
||||
|
||||
protected:
|
||||
// The index of this region in the heap region sequence.
|
||||
uint _hrm_index;
|
||||
|
@ -427,6 +431,7 @@ class HeapRegion: public G1ContiguousSpace {
|
|||
|
||||
const char* get_type_str() const { return _type.get_str(); }
|
||||
const char* get_short_type_str() const { return _type.get_short_str(); }
|
||||
G1HeapRegionTraceType::Type get_trace_type() { return _type.get_trace_type(); }
|
||||
|
||||
bool is_free() const { return _type.is_free(); }
|
||||
|
||||
|
@ -637,15 +642,15 @@ class HeapRegion: public G1ContiguousSpace {
|
|||
}
|
||||
}
|
||||
|
||||
void set_free() { _type.set_free(); }
|
||||
void set_free();
|
||||
|
||||
void set_eden() { _type.set_eden(); }
|
||||
void set_eden_pre_gc() { _type.set_eden_pre_gc(); }
|
||||
void set_survivor() { _type.set_survivor(); }
|
||||
void set_eden();
|
||||
void set_eden_pre_gc();
|
||||
void set_survivor();
|
||||
|
||||
void set_old() { _type.set_old(); }
|
||||
void set_old();
|
||||
|
||||
void set_archive() { _type.set_archive(); }
|
||||
void set_archive();
|
||||
|
||||
// Determine if an object has been allocated since the last
|
||||
// mark performed by the collector. This returns true iff the object
|
||||
|
|
45
hotspot/src/share/vm/gc/g1/heapRegionTracer.cpp
Normal file
45
hotspot/src/share/vm/gc/g1/heapRegionTracer.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/heapRegionTracer.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
|
||||
void HeapRegionTracer::send_region_type_change(uint index,
|
||||
G1HeapRegionTraceType::Type from,
|
||||
G1HeapRegionTraceType::Type to,
|
||||
uintptr_t start,
|
||||
size_t used,
|
||||
uint allocationContext) {
|
||||
EventG1HeapRegionTypeChange e;
|
||||
if (e.should_commit()) {
|
||||
e.set_index(index);
|
||||
e.set_from(from);
|
||||
e.set_to(to);
|
||||
e.set_start(start);
|
||||
e.set_used(used);
|
||||
e.set_allocContext(allocationContext);
|
||||
e.commit();
|
||||
}
|
||||
}
|
41
hotspot/src/share/vm/gc/g1/heapRegionTracer.hpp
Normal file
41
hotspot/src/share/vm/gc/g1/heapRegionTracer.hpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_GC_G1_HEAPREGIONTRACER_HPP
|
||||
#define SHARE_VM_GC_G1_HEAPREGIONTRACER_HPP
|
||||
|
||||
#include "gc/g1/g1HeapRegionTraceType.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class HeapRegionTracer : AllStatic {
|
||||
public:
|
||||
static void send_region_type_change(uint index,
|
||||
G1HeapRegionTraceType::Type from,
|
||||
G1HeapRegionTraceType::Type to,
|
||||
uintptr_t start,
|
||||
size_t used,
|
||||
uint allocationContext);
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_G1_HEAPREGIONTRACER_HPP
|
|
@ -23,6 +23,7 @@
|
|||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/g1/g1HeapRegionTraceType.hpp"
|
||||
#include "gc/g1/heapRegionType.hpp"
|
||||
|
||||
bool HeapRegionType::is_valid(Tag tag) {
|
||||
|
@ -70,3 +71,19 @@ const char* HeapRegionType::get_short_str() const {
|
|||
// keep some compilers happy
|
||||
return NULL;
|
||||
}
|
||||
|
||||
G1HeapRegionTraceType::Type HeapRegionType::get_trace_type() {
|
||||
hrt_assert_is_valid(_tag);
|
||||
switch (_tag) {
|
||||
case FreeTag: return G1HeapRegionTraceType::Free;
|
||||
case EdenTag: return G1HeapRegionTraceType::Eden;
|
||||
case SurvTag: return G1HeapRegionTraceType::Survivor;
|
||||
case StartsHumongousTag: return G1HeapRegionTraceType::StartsHumongous;
|
||||
case ContinuesHumongousTag: return G1HeapRegionTraceType::ContinuesHumongous;
|
||||
case OldTag: return G1HeapRegionTraceType::Old;
|
||||
case ArchiveTag: return G1HeapRegionTraceType::Archive;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
// keep some compilers happy
|
||||
return G1HeapRegionTraceType::Free;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#ifndef SHARE_VM_GC_G1_HEAPREGIONTYPE_HPP
|
||||
#define SHARE_VM_GC_G1_HEAPREGIONTYPE_HPP
|
||||
|
||||
#include "gc/g1/g1HeapRegionTraceType.hpp"
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
#define hrt_assert_is_valid(tag) \
|
||||
|
@ -141,6 +142,7 @@ public:
|
|||
|
||||
const char* get_str() const;
|
||||
const char* get_short_str() const;
|
||||
G1HeapRegionTraceType::Type get_trace_type();
|
||||
|
||||
HeapRegionType() : _tag(FreeTag) { hrt_assert_is_valid(_tag); }
|
||||
};
|
||||
|
|
|
@ -221,13 +221,13 @@ void SATBMarkQueueSet::handle_zero_index_for_thread(JavaThread* t) {
|
|||
|
||||
#ifdef ASSERT
|
||||
void SATBMarkQueueSet::dump_active_states(bool expected_active) {
|
||||
log_info(gc, verify)("Expected SATB active state: %s", expected_active ? "ACTIVE" : "INACTIVE");
|
||||
log_info(gc, verify)("Actual SATB active states:");
|
||||
log_info(gc, verify)(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
|
||||
log_error(gc, verify)("Expected SATB active state: %s", expected_active ? "ACTIVE" : "INACTIVE");
|
||||
log_error(gc, verify)("Actual SATB active states:");
|
||||
log_error(gc, verify)(" Queue set: %s", is_active() ? "ACTIVE" : "INACTIVE");
|
||||
for (JavaThread* t = Threads::first(); t; t = t->next()) {
|
||||
log_info(gc, verify)(" Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
|
||||
log_error(gc, verify)(" Thread \"%s\" queue: %s", t->name(), t->satb_mark_queue().is_active() ? "ACTIVE" : "INACTIVE");
|
||||
}
|
||||
log_info(gc, verify)(" Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
|
||||
log_error(gc, verify)(" Shared queue: %s", shared_satb_queue()->is_active() ? "ACTIVE" : "INACTIVE");
|
||||
}
|
||||
|
||||
void SATBMarkQueueSet::verify_active_states(bool expected_active) {
|
||||
|
|
|
@ -99,7 +99,7 @@ bool YoungList::check_list_well_formed() {
|
|||
HeapRegion* last = NULL;
|
||||
while (curr != NULL) {
|
||||
if (!curr->is_young()) {
|
||||
log_info(gc, verify)("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " "
|
||||
log_error(gc, verify)("### YOUNG REGION " PTR_FORMAT "-" PTR_FORMAT " "
|
||||
"incorrectly tagged (y: %d, surv: %d)",
|
||||
p2i(curr->bottom()), p2i(curr->end()),
|
||||
curr->is_young(), curr->is_survivor());
|
||||
|
@ -112,8 +112,8 @@ bool YoungList::check_list_well_formed() {
|
|||
ret = ret && (length == _length);
|
||||
|
||||
if (!ret) {
|
||||
log_info(gc, verify)("### YOUNG LIST seems not well formed!");
|
||||
log_info(gc, verify)("### list has %u entries, _length is %u", length, _length);
|
||||
log_error(gc, verify)("### YOUNG LIST seems not well formed!");
|
||||
log_error(gc, verify)("### list has %u entries, _length is %u", length, _length);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -123,19 +123,19 @@ bool YoungList::check_list_empty(bool check_sample) {
|
|||
bool ret = true;
|
||||
|
||||
if (_length != 0) {
|
||||
log_info(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length);
|
||||
log_error(gc, verify)("### YOUNG LIST should have 0 length, not %u", _length);
|
||||
ret = false;
|
||||
}
|
||||
if (check_sample && _last_sampled_rs_lengths != 0) {
|
||||
log_info(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths");
|
||||
log_error(gc, verify)("### YOUNG LIST has non-zero last sampled RS lengths");
|
||||
ret = false;
|
||||
}
|
||||
if (_head != NULL) {
|
||||
log_info(gc, verify)("### YOUNG LIST does not have a NULL head");
|
||||
log_error(gc, verify)("### YOUNG LIST does not have a NULL head");
|
||||
ret = false;
|
||||
}
|
||||
if (!ret) {
|
||||
log_info(gc, verify)("### YOUNG LIST does not seem empty");
|
||||
log_error(gc, verify)("### YOUNG LIST does not seem empty");
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/ageTable.inline.hpp"
|
||||
#include "gc/shared/ageTableTracer.hpp"
|
||||
#include "gc/shared/collectedHeap.hpp"
|
||||
#include "gc/shared/collectorPolicy.hpp"
|
||||
#include "gc/shared/gcPolicyCounters.hpp"
|
||||
|
@ -100,17 +101,19 @@ uint AgeTable::compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCoun
|
|||
log_debug(gc, age)("Desired survivor size " SIZE_FORMAT " bytes, new threshold " UINTX_FORMAT " (max threshold " UINTX_FORMAT ")",
|
||||
desired_survivor_size*oopSize, (uintx) result, MaxTenuringThreshold);
|
||||
|
||||
if (log_is_enabled(Trace, gc, age) || UsePerfData) {
|
||||
if (log_is_enabled(Trace, gc, age) || UsePerfData || AgeTableTracer::is_tenuring_distribution_event_enabled()) {
|
||||
size_t total = 0;
|
||||
uint age = 1;
|
||||
while (age < table_size) {
|
||||
total += sizes[age];
|
||||
if (sizes[age] > 0) {
|
||||
size_t wordSize = sizes[age];
|
||||
total += wordSize;
|
||||
if (wordSize > 0) {
|
||||
log_trace(gc, age)("- age %3u: " SIZE_FORMAT_W(10) " bytes, " SIZE_FORMAT_W(10) " total",
|
||||
age, sizes[age]*oopSize, total*oopSize);
|
||||
age, wordSize*oopSize, total*oopSize);
|
||||
}
|
||||
AgeTableTracer::send_tenuring_distribution_event(age, wordSize*oopSize);
|
||||
if (UsePerfData) {
|
||||
_perf_sizes[age]->set_value(sizes[age]*oopSize);
|
||||
_perf_sizes[age]->set_value(wordSize*oopSize);
|
||||
}
|
||||
age++;
|
||||
}
|
||||
|
|
42
hotspot/src/share/vm/gc/shared/ageTableTracer.cpp
Normal file
42
hotspot/src/share/vm/gc/shared/ageTableTracer.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "gc/shared/ageTableTracer.hpp"
|
||||
#include "gc/shared/gcId.hpp"
|
||||
#include "trace/tracing.hpp"
|
||||
|
||||
void AgeTableTracer::send_tenuring_distribution_event(uint age, size_t size) {
|
||||
EventTenuringDistribution e;
|
||||
if (e.should_commit()) {
|
||||
e.set_gcId(GCId::current());
|
||||
e.set_age(age);
|
||||
e.set_size(size);
|
||||
e.commit();
|
||||
}
|
||||
}
|
||||
|
||||
bool AgeTableTracer::is_tenuring_distribution_event_enabled() {
|
||||
return EventTenuringDistribution::is_enabled();
|
||||
}
|
36
hotspot/src/share/vm/gc/shared/ageTableTracer.hpp
Normal file
36
hotspot/src/share/vm/gc/shared/ageTableTracer.hpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SHARE_VM_GC_SHARED_AGETABLETRACER_HPP
|
||||
#define SHARE_VM_GC_SHARED_AGETABLETRACER_HPP
|
||||
|
||||
#include "memory/allocation.hpp"
|
||||
|
||||
class AgeTableTracer : AllStatic {
|
||||
public:
|
||||
static void send_tenuring_distribution_event(uint age, size_t size);
|
||||
static bool is_tenuring_distribution_event_enabled();
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_SHARED_AGETABLETRACER_HPP
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -60,7 +60,7 @@ void ConcurrentGCThread::initialize_in_thread() {
|
|||
void ConcurrentGCThread::wait_for_universe_init() {
|
||||
MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
|
||||
while (!is_init_completed() && !_should_terminate) {
|
||||
CGC_lock->wait(Mutex::_no_safepoint_check_flag, 200);
|
||||
CGC_lock->wait(Mutex::_no_safepoint_check_flag, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -32,7 +32,7 @@ class ConcurrentGCThread: public NamedThread {
|
|||
friend class VMStructs;
|
||||
|
||||
protected:
|
||||
bool _should_terminate;
|
||||
bool volatile _should_terminate;
|
||||
bool _has_terminated;
|
||||
|
||||
// Create and start the thread (setting it's priority high.)
|
||||
|
|
|
@ -131,12 +131,14 @@ class G1HeapSummary : public GCHeapSummary {
|
|||
size_t _edenUsed;
|
||||
size_t _edenCapacity;
|
||||
size_t _survivorUsed;
|
||||
uint _numberOfRegions;
|
||||
public:
|
||||
G1HeapSummary(VirtualSpaceSummary& heap_space, size_t heap_used, size_t edenUsed, size_t edenCapacity, size_t survivorUsed) :
|
||||
GCHeapSummary(heap_space, heap_used), _edenUsed(edenUsed), _edenCapacity(edenCapacity), _survivorUsed(survivorUsed) { }
|
||||
G1HeapSummary(VirtualSpaceSummary& heap_space, size_t heap_used, size_t edenUsed, size_t edenCapacity, size_t survivorUsed, uint numberOfRegions) :
|
||||
GCHeapSummary(heap_space, heap_used), _edenUsed(edenUsed), _edenCapacity(edenCapacity), _survivorUsed(survivorUsed), _numberOfRegions(numberOfRegions) { }
|
||||
const size_t edenUsed() const { return _edenUsed; }
|
||||
const size_t edenCapacity() const { return _edenCapacity; }
|
||||
const size_t survivorUsed() const { return _survivorUsed; }
|
||||
const uint numberOfRegions() const { return _numberOfRegions; }
|
||||
|
||||
virtual void accept(GCHeapSummaryVisitor* visitor) const {
|
||||
visitor->visit(this);
|
||||
|
|
|
@ -359,6 +359,7 @@ class GCHeapSummaryEventSender : public GCHeapSummaryVisitor {
|
|||
e.set_edenUsedSize(g1_heap_summary->edenUsed());
|
||||
e.set_edenTotalSize(g1_heap_summary->edenCapacity());
|
||||
e.set_survivorUsedSize(g1_heap_summary->survivorUsed());
|
||||
e.set_numberOfRegions(g1_heap_summary->numberOfRegions());
|
||||
e.commit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -34,9 +34,6 @@ BytecodeStream *MethodComparator::_s_old;
|
|||
BytecodeStream *MethodComparator::_s_new;
|
||||
ConstantPool* MethodComparator::_old_cp;
|
||||
ConstantPool* MethodComparator::_new_cp;
|
||||
BciMap *MethodComparator::_bci_map;
|
||||
bool MethodComparator::_switchable_test;
|
||||
GrowableArray<int> *MethodComparator::_fwd_jmps;
|
||||
|
||||
bool MethodComparator::methods_EMCP(Method* old_method, Method* new_method) {
|
||||
if (old_method->code_size() != new_method->code_size())
|
||||
|
@ -55,7 +52,6 @@ bool MethodComparator::methods_EMCP(Method* old_method, Method* new_method) {
|
|||
BytecodeStream s_new(new_method);
|
||||
_s_old = &s_old;
|
||||
_s_new = &s_new;
|
||||
_switchable_test = false;
|
||||
Bytecodes::Code c_old, c_new;
|
||||
|
||||
while ((c_old = s_old.next()) >= 0) {
|
||||
|
@ -68,64 +64,6 @@ bool MethodComparator::methods_EMCP(Method* old_method, Method* new_method) {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool MethodComparator::methods_switchable(Method* old_method, Method* new_method,
|
||||
BciMap &bci_map) {
|
||||
if (old_method->code_size() > new_method->code_size())
|
||||
// Something has definitely been deleted in the new method, compared to the old one.
|
||||
return false;
|
||||
|
||||
if (! check_stack_and_locals_size(old_method, new_method))
|
||||
return false;
|
||||
|
||||
_old_cp = old_method->constants();
|
||||
_new_cp = new_method->constants();
|
||||
BytecodeStream s_old(old_method);
|
||||
BytecodeStream s_new(new_method);
|
||||
_s_old = &s_old;
|
||||
_s_new = &s_new;
|
||||
_bci_map = &bci_map;
|
||||
_switchable_test = true;
|
||||
GrowableArray<int> fwd_jmps(16);
|
||||
_fwd_jmps = &fwd_jmps;
|
||||
Bytecodes::Code c_old, c_new;
|
||||
|
||||
while ((c_old = s_old.next()) >= 0) {
|
||||
if ((c_new = s_new.next()) < 0)
|
||||
return false;
|
||||
if (! (c_old == c_new && args_same(c_old, c_new))) {
|
||||
int old_bci = s_old.bci();
|
||||
int new_st_bci = s_new.bci();
|
||||
bool found_match = false;
|
||||
do {
|
||||
c_new = s_new.next();
|
||||
if (c_new == c_old && args_same(c_old, c_new)) {
|
||||
found_match = true;
|
||||
break;
|
||||
}
|
||||
} while (c_new >= 0);
|
||||
if (! found_match)
|
||||
return false;
|
||||
int new_end_bci = s_new.bci();
|
||||
bci_map.store_fragment_location(old_bci, new_st_bci, new_end_bci);
|
||||
}
|
||||
}
|
||||
|
||||
// Now we can test all forward jumps
|
||||
for (int i = 0; i < fwd_jmps.length() / 2; i++) {
|
||||
if (! bci_map.old_and_new_locations_same(fwd_jmps.at(i*2), fwd_jmps.at(i*2+1))) {
|
||||
RC_TRACE(0x00800000,
|
||||
("Fwd jump miss: old dest = %d, calc new dest = %d, act new dest = %d",
|
||||
fwd_jmps.at(i*2), bci_map.new_bci_for_old(fwd_jmps.at(i*2)),
|
||||
fwd_jmps.at(i*2+1)));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
|
||||
// BytecodeStream returns the correct standard Java bytecodes for various "fast"
|
||||
// bytecode versions, so we don't have to bother about them here..
|
||||
|
@ -275,22 +213,8 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
|
|||
case Bytecodes::_jsr : {
|
||||
int old_ofs = _s_old->bytecode().get_offset_s2(c_old);
|
||||
int new_ofs = _s_new->bytecode().get_offset_s2(c_new);
|
||||
if (_switchable_test) {
|
||||
int old_dest = _s_old->bci() + old_ofs;
|
||||
int new_dest = _s_new->bci() + new_ofs;
|
||||
if (old_ofs < 0 && new_ofs < 0) {
|
||||
if (! _bci_map->old_and_new_locations_same(old_dest, new_dest))
|
||||
return false;
|
||||
} else if (old_ofs > 0 && new_ofs > 0) {
|
||||
_fwd_jmps->append(old_dest);
|
||||
_fwd_jmps->append(new_dest);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (old_ofs != new_ofs)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -312,73 +236,19 @@ bool MethodComparator::args_same(Bytecodes::Code c_old, Bytecodes::Code c_new) {
|
|||
case Bytecodes::_jsr_w : {
|
||||
int old_ofs = _s_old->bytecode().get_offset_s4(c_old);
|
||||
int new_ofs = _s_new->bytecode().get_offset_s4(c_new);
|
||||
if (_switchable_test) {
|
||||
int old_dest = _s_old->bci() + old_ofs;
|
||||
int new_dest = _s_new->bci() + new_ofs;
|
||||
if (old_ofs < 0 && new_ofs < 0) {
|
||||
if (! _bci_map->old_and_new_locations_same(old_dest, new_dest))
|
||||
return false;
|
||||
} else if (old_ofs > 0 && new_ofs > 0) {
|
||||
_fwd_jmps->append(old_dest);
|
||||
_fwd_jmps->append(new_dest);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (old_ofs != new_ofs)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case Bytecodes::_lookupswitch : // fall through
|
||||
case Bytecodes::_tableswitch : {
|
||||
if (_switchable_test) {
|
||||
address aligned_bcp_old = (address) round_to((intptr_t)_s_old->bcp() + 1, jintSize);
|
||||
address aligned_bcp_new = (address) round_to((intptr_t)_s_new->bcp() + 1, jintSize);
|
||||
int default_old = (int) Bytes::get_Java_u4(aligned_bcp_old);
|
||||
int default_new = (int) Bytes::get_Java_u4(aligned_bcp_new);
|
||||
_fwd_jmps->append(_s_old->bci() + default_old);
|
||||
_fwd_jmps->append(_s_new->bci() + default_new);
|
||||
if (c_old == Bytecodes::_lookupswitch) {
|
||||
int npairs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + jintSize);
|
||||
int npairs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + jintSize);
|
||||
if (npairs_old != npairs_new)
|
||||
return false;
|
||||
for (int i = 0; i < npairs_old; i++) {
|
||||
int match_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (2+2*i)*jintSize);
|
||||
int match_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (2+2*i)*jintSize);
|
||||
if (match_old != match_new)
|
||||
return false;
|
||||
int ofs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (2+2*i+1)*jintSize);
|
||||
int ofs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (2+2*i+1)*jintSize);
|
||||
_fwd_jmps->append(_s_old->bci() + ofs_old);
|
||||
_fwd_jmps->append(_s_new->bci() + ofs_new);
|
||||
}
|
||||
} else if (c_old == Bytecodes::_tableswitch) {
|
||||
int lo_old = (int) Bytes::get_Java_u4(aligned_bcp_old + jintSize);
|
||||
int lo_new = (int) Bytes::get_Java_u4(aligned_bcp_new + jintSize);
|
||||
if (lo_old != lo_new)
|
||||
return false;
|
||||
int hi_old = (int) Bytes::get_Java_u4(aligned_bcp_old + 2*jintSize);
|
||||
int hi_new = (int) Bytes::get_Java_u4(aligned_bcp_new + 2*jintSize);
|
||||
if (hi_old != hi_new)
|
||||
return false;
|
||||
for (int i = 0; i < hi_old - lo_old + 1; i++) {
|
||||
int ofs_old = (int) Bytes::get_Java_u4(aligned_bcp_old + (3+i)*jintSize);
|
||||
int ofs_new = (int) Bytes::get_Java_u4(aligned_bcp_new + (3+i)*jintSize);
|
||||
_fwd_jmps->append(_s_old->bci() + ofs_old);
|
||||
_fwd_jmps->append(_s_new->bci() + ofs_new);
|
||||
}
|
||||
}
|
||||
} else { // !_switchable_test, can use fast rough compare
|
||||
int len_old = _s_old->instruction_size();
|
||||
int len_new = _s_new->instruction_size();
|
||||
if (len_old != len_new)
|
||||
return false;
|
||||
if (memcmp(_s_old->bcp(), _s_new->bcp(), len_old) != 0)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -29,8 +29,6 @@
|
|||
#include "oops/constantPool.hpp"
|
||||
#include "oops/method.hpp"
|
||||
|
||||
class BciMap;
|
||||
|
||||
// methodComparator provides an interface for determining if methods of
|
||||
// different versions of classes are equivalent or switchable
|
||||
|
||||
|
@ -39,9 +37,6 @@ class MethodComparator {
|
|||
static BytecodeStream *_s_old, *_s_new;
|
||||
static ConstantPool* _old_cp;
|
||||
static ConstantPool* _new_cp;
|
||||
static BciMap *_bci_map;
|
||||
static bool _switchable_test;
|
||||
static GrowableArray<int> *_fwd_jmps;
|
||||
|
||||
static bool args_same(Bytecodes::Code c_old, Bytecodes::Code c_new);
|
||||
static bool pool_constants_same(int cpi_old, int cpi_new);
|
||||
|
@ -55,79 +50,6 @@ class MethodComparator {
|
|||
// these indices eventually point to the same constants for both method versions.
|
||||
static bool methods_EMCP(Method* old_method, Method* new_method);
|
||||
|
||||
static bool methods_switchable(Method* old_method, Method* new_method, BciMap &bci_map);
|
||||
};
|
||||
|
||||
|
||||
// ByteCode Index Map. For two versions of the same method, where the new version may contain
|
||||
// fragments not found in the old version, provides a mapping from an index of a bytecode in
|
||||
// the old method to the index of the same bytecode in the new method.
|
||||
|
||||
class BciMap {
|
||||
private:
|
||||
int *_old_bci, *_new_st_bci, *_new_end_bci;
|
||||
int _cur_size, _cur_pos;
|
||||
int _pos;
|
||||
|
||||
public:
|
||||
BciMap() {
|
||||
_cur_size = 50;
|
||||
_old_bci = (int*) malloc(sizeof(int) * _cur_size);
|
||||
_new_st_bci = (int*) malloc(sizeof(int) * _cur_size);
|
||||
_new_end_bci = (int*) malloc(sizeof(int) * _cur_size);
|
||||
_cur_pos = 0;
|
||||
}
|
||||
|
||||
~BciMap() {
|
||||
free(_old_bci);
|
||||
free(_new_st_bci);
|
||||
free(_new_end_bci);
|
||||
}
|
||||
|
||||
// Store the position of an added fragment, e.g.
|
||||
//
|
||||
// |<- old_bci
|
||||
// -----------------------------------------
|
||||
// Old method |invokevirtual 5|aload 1|...
|
||||
// -----------------------------------------
|
||||
//
|
||||
// |<- new_st_bci |<- new_end_bci
|
||||
// --------------------------------------------------------------------
|
||||
// New method |invokevirual 5|aload 2|invokevirtual 6|aload 1|...
|
||||
// --------------------------------------------------------------------
|
||||
// ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
// Added fragment
|
||||
|
||||
void store_fragment_location(int old_bci, int new_st_bci, int new_end_bci) {
|
||||
if (_cur_pos == _cur_size) {
|
||||
_cur_size += 10;
|
||||
_old_bci = (int*) realloc(_old_bci, sizeof(int) * _cur_size);
|
||||
_new_st_bci = (int*) realloc(_new_st_bci, sizeof(int) * _cur_size);
|
||||
_new_end_bci = (int*) realloc(_new_end_bci, sizeof(int) * _cur_size);
|
||||
}
|
||||
_old_bci[_cur_pos] = old_bci;
|
||||
_new_st_bci[_cur_pos] = new_st_bci;
|
||||
_new_end_bci[_cur_pos] = new_end_bci;
|
||||
_cur_pos++;
|
||||
}
|
||||
|
||||
int new_bci_for_old(int old_bci) {
|
||||
if (_cur_pos == 0 || old_bci < _old_bci[0]) return old_bci;
|
||||
_pos = 1;
|
||||
while (_pos < _cur_pos && old_bci >= _old_bci[_pos])
|
||||
_pos++;
|
||||
return _new_end_bci[_pos-1] + (old_bci - _old_bci[_pos-1]);
|
||||
}
|
||||
|
||||
// Test if two indexes - one in the old method and another in the new one - correspond
|
||||
// to the same bytecode
|
||||
bool old_and_new_locations_same(int old_dest_bci, int new_dest_bci) {
|
||||
if (new_bci_for_old(old_dest_bci) == new_dest_bci)
|
||||
return true;
|
||||
else if (_old_bci[_pos-1] == old_dest_bci)
|
||||
return (new_dest_bci == _new_st_bci[_pos-1]);
|
||||
else return false;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_PRIMS_METHODCOMPARATOR_HPP
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -660,6 +660,36 @@ UNSAFE_ENTRY(void, Unsafe_CopyMemory(JNIEnv *env, jobject unsafe, jobject srcObj
|
|||
Copy::conjoint_memory_atomic(src, dst, sz);
|
||||
UNSAFE_END
|
||||
|
||||
// This function is a leaf since if the source and destination are both in native memory
|
||||
// the copy may potentially be very large, and we don't want to disable GC if we can avoid it.
|
||||
// If either source or destination (or both) are on the heap, the function will enter VM using
|
||||
// JVM_ENTRY_FROM_LEAF
|
||||
JVM_LEAF(void, Unsafe_CopySwapMemory0(JNIEnv *env, jobject unsafe, jobject srcObj, jlong srcOffset, jobject dstObj, jlong dstOffset, jlong size, jlong elemSize)) {
|
||||
UnsafeWrapper("Unsafe_CopySwapMemory0");
|
||||
|
||||
size_t sz = (size_t)size;
|
||||
size_t esz = (size_t)elemSize;
|
||||
|
||||
if (srcObj == NULL && dstObj == NULL) {
|
||||
// Both src & dst are in native memory
|
||||
address src = (address)srcOffset;
|
||||
address dst = (address)dstOffset;
|
||||
|
||||
Copy::conjoint_swap(src, dst, sz, esz);
|
||||
} else {
|
||||
// At least one of src/dst are on heap, transition to VM to access raw pointers
|
||||
|
||||
JVM_ENTRY_FROM_LEAF(env, void, Unsafe_CopySwapMemory0) {
|
||||
oop srcp = JNIHandles::resolve(srcObj);
|
||||
oop dstp = JNIHandles::resolve(dstObj);
|
||||
|
||||
address src = (address)index_oop_from_field_offset_long(srcp, srcOffset);
|
||||
address dst = (address)index_oop_from_field_offset_long(dstp, dstOffset);
|
||||
|
||||
Copy::conjoint_swap(src, dst, sz, esz);
|
||||
} JVM_END
|
||||
}
|
||||
} JVM_END
|
||||
|
||||
////// Random queries
|
||||
|
||||
|
@ -1363,6 +1393,7 @@ static JNINativeMethod jdk_internal_misc_Unsafe_methods[] = {
|
|||
{CC "getLoadAverage", CC "([DI)I", FN_PTR(Unsafe_Loadavg)},
|
||||
|
||||
{CC "copyMemory", CC "(" OBJ "J" OBJ "JJ)V", FN_PTR(Unsafe_CopyMemory)},
|
||||
{CC "copySwapMemory0", CC "(" OBJ "J" OBJ "JJJ)V", FN_PTR(Unsafe_CopySwapMemory0)},
|
||||
{CC "setMemory", CC "(" OBJ "JJB)V", FN_PTR(Unsafe_SetMemory)},
|
||||
|
||||
{CC "defineAnonymousClass", CC "(" DAC_Args ")" CLS, FN_PTR(Unsafe_DefineAnonymousClass)},
|
||||
|
|
|
@ -333,6 +333,8 @@ static SpecialFlag const special_jvm_flags[] = {
|
|||
// --- Non-alias flags - sorted by obsolete_in then expired_in:
|
||||
{ "MaxGCMinorPauseMillis", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
|
||||
{ "UseParNewGC", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::jdk(10) },
|
||||
{ "ConvertSleepToYield", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) },
|
||||
{ "ConvertYieldToSleep", JDK_Version::jdk(9), JDK_Version::jdk(10), JDK_Version::jdk(11) },
|
||||
|
||||
// --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
|
||||
{ "DefaultMaxRAMFraction", JDK_Version::jdk(8), JDK_Version::undefined(), JDK_Version::undefined() },
|
||||
|
|
|
@ -1239,9 +1239,8 @@ public:
|
|||
product_pd(bool, DontYieldALot, \
|
||||
"Throw away obvious excess yield calls") \
|
||||
\
|
||||
product_pd(bool, ConvertSleepToYield, \
|
||||
"Convert sleep(0) to thread yield " \
|
||||
"(may be off for Solaris to improve GUI)") \
|
||||
product(bool, ConvertSleepToYield, true, \
|
||||
"Convert sleep(0) to thread yield ") \
|
||||
\
|
||||
product(bool, ConvertYieldToSleep, false, \
|
||||
"Convert yield to a sleep of MinSleepInterval to simulate Win32 " \
|
||||
|
@ -1279,10 +1278,6 @@ public:
|
|||
experimental(intx, hashCode, 5, \
|
||||
"(Unstable) select hashCode generation algorithm") \
|
||||
\
|
||||
experimental(intx, WorkAroundNPTLTimedWaitHang, 0, \
|
||||
"(Unstable, Linux-specific) " \
|
||||
"avoid NPTL-FUTEX hang pthread_cond_timedwait") \
|
||||
\
|
||||
product(bool, FilterSpuriousWakeups, true, \
|
||||
"When true prevents OS-level spurious, or premature, wakeups " \
|
||||
"from Object.wait (Ignored for Windows)") \
|
||||
|
@ -2012,11 +2007,15 @@ public:
|
|||
range(min_intx, 100) \
|
||||
\
|
||||
product(uintx, InitiatingHeapOccupancyPercent, 45, \
|
||||
"Percentage of the (entire) heap occupancy to start a " \
|
||||
"concurrent GC cycle. It is used by GCs that trigger a " \
|
||||
"concurrent GC cycle based on the occupancy of the entire heap, " \
|
||||
"not just one of the generations (e.g., G1). A value of 0 " \
|
||||
"denotes 'do constant GC cycles'.") \
|
||||
"The percent occupancy (IHOP) of the current old generation " \
|
||||
"capacity above which a concurrent mark cycle will be initiated " \
|
||||
"Its value may change over time if adaptive IHOP is enabled, " \
|
||||
"otherwise the value remains constant. " \
|
||||
"In the latter case a value of 0 will result as frequent as " \
|
||||
"possible concurrent marking cycles. A value of 100 disables " \
|
||||
"concurrent marking. " \
|
||||
"Fragmentation waste in the old generation is not considered " \
|
||||
"free space in this calculation. (G1 collector only)") \
|
||||
range(0, 100) \
|
||||
\
|
||||
manageable(intx, CMSTriggerInterval, -1, \
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -181,8 +181,7 @@ void exit_globals() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static bool _init_completed = false;
|
||||
static volatile bool _init_completed = false;
|
||||
|
||||
bool is_init_completed() {
|
||||
return _init_completed;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -417,6 +417,14 @@ class RuntimeHistogramElement : public HistogramElement {
|
|||
os::verify_stack_alignment(); \
|
||||
/* begin of body */
|
||||
|
||||
#define VM_ENTRY_BASE_FROM_LEAF(result_type, header, thread) \
|
||||
TRACE_CALL(result_type, header) \
|
||||
debug_only(ResetNoHandleMark __rnhm;) \
|
||||
HandleMarkCleaner __hm(thread); \
|
||||
Thread* THREAD = thread; \
|
||||
os::verify_stack_alignment(); \
|
||||
/* begin of body */
|
||||
|
||||
|
||||
// ENTRY routines may lock, GC and throw exceptions
|
||||
|
||||
|
@ -584,6 +592,14 @@ extern "C" { \
|
|||
VM_LEAF_BASE(result_type, header)
|
||||
|
||||
|
||||
#define JVM_ENTRY_FROM_LEAF(env, result_type, header) \
|
||||
{ { \
|
||||
JavaThread* thread=JavaThread::thread_from_jni_environment(env); \
|
||||
ThreadInVMfromNative __tiv(thread); \
|
||||
debug_only(VMNativeEntryWrapper __vew;) \
|
||||
VM_ENTRY_BASE_FROM_LEAF(result_type, header, thread)
|
||||
|
||||
|
||||
#define JVM_END } }
|
||||
|
||||
#endif // SHARE_VM_RUNTIME_INTERFACESUPPORT_HPP
|
||||
|
|
|
@ -283,6 +283,7 @@ Declares a structure type that can be used in other events.
|
|||
<value type="BYTES64" field="edenUsedSize" label="Eden Used Size" />
|
||||
<value type="BYTES64" field="edenTotalSize" label="Eden Total Size" />
|
||||
<value type="BYTES64" field="survivorUsedSize" label="Survivor Used Size" />
|
||||
<value type="UINT" field="numberOfRegions" label="Number of Regions" />
|
||||
</event>
|
||||
|
||||
<event id="GCGarbageCollection" path="vm/gc/collector/garbage_collection" label="Garbage Collection"
|
||||
|
@ -478,6 +479,23 @@ Declares a structure type that can be used in other events.
|
|||
<value type="BYTES64" field="size" label="Allocation Size" />
|
||||
</event>
|
||||
|
||||
<event id="TenuringDistribution" path="vm/gc/detailed/tenuring_distribution" label="Tenuring Distribution"
|
||||
is_instant="true">
|
||||
<value type="UINT" field="gcId" label="GC ID" relation="GC_ID"/>
|
||||
<value type="UINT" field="age" label="Age" />
|
||||
<value type="BYTES64" field="size" label="Size" />
|
||||
</event>
|
||||
|
||||
<event id="G1HeapRegionTypeChange" path="vm/gc/detailed/g1_heap_region_type_change" label="G1 Heap Region Type Change"
|
||||
description="Information about a G1 heap region type change." is_instant="true">
|
||||
<value type="UINT" field="index" label="Index" />
|
||||
<value type="G1HEAPREGIONTYPE" field="from" label="From Type" />
|
||||
<value type="G1HEAPREGIONTYPE" field="to" label="To Type" />
|
||||
<value type="ADDRESS" field="start" label="Start" />
|
||||
<value type="BYTES64" field="used" label="Used" />
|
||||
<value type="UINT" field="allocContext" label="Allocation Context" />
|
||||
</event>
|
||||
|
||||
<!-- Compiler events -->
|
||||
|
||||
<event id="Compilation" path="vm/compiler/compilation" label="Compilation"
|
||||
|
|
|
@ -126,6 +126,11 @@ Now we can use the content + data type in declaring event fields.
|
|||
<value type="UTF8" field="when" label="when" />
|
||||
</content_type>
|
||||
|
||||
<content_type id="G1HeapRegionType" hr_name="G1 Heap Region Type"
|
||||
type="U1" jvm_type="G1HEAPREGIONTYPE">
|
||||
<value type="UTF8" field="type" label="type" />
|
||||
</content_type>
|
||||
|
||||
<content_type id="G1YCType" hr_name="G1 YC Type"
|
||||
type="U1" jvm_type="G1YCTYPE">
|
||||
<value type="UTF8" field="type" label="type" />
|
||||
|
@ -345,6 +350,10 @@ Now we can use the content + data type in declaring event fields.
|
|||
<primary_type symbol="GCWHEN" datatype="U1" contenttype="GCWHEN"
|
||||
type="u1" sizeop="sizeof(u1)" />
|
||||
|
||||
<!-- G1HEAPREGIONTYPE -->
|
||||
<primary_type symbol="G1HEAPREGIONTYPE" datatype="U1" contenttype="G1HEAPREGIONTYPE"
|
||||
type="u1" sizeop="sizeof(u1)" />
|
||||
|
||||
<!-- G1YCType -->
|
||||
<primary_type symbol="G1YCTYPE" datatype="U1" contenttype="G1YCTYPE"
|
||||
type="u1" sizeop="sizeof(u1)" />
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -53,6 +53,175 @@ void Copy::conjoint_memory_atomic(void* from, void* to, size_t size) {
|
|||
}
|
||||
}
|
||||
|
||||
class CopySwap : AllStatic {
|
||||
public:
|
||||
/**
|
||||
* Copy and byte swap elements
|
||||
*
|
||||
* @param src address of source
|
||||
* @param dst address of destination
|
||||
* @param byte_count number of bytes to copy
|
||||
* @param elem_size size of the elements to copy-swap
|
||||
*/
|
||||
static void conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
|
||||
assert(src != NULL, "address must not be NULL");
|
||||
assert(dst != NULL, "address must not be NULL");
|
||||
assert(elem_size == 2 || elem_size == 4 || elem_size == 8,
|
||||
"incorrect element size: " SIZE_FORMAT, elem_size);
|
||||
assert(is_size_aligned(byte_count, elem_size),
|
||||
"byte_count " SIZE_FORMAT " must be multiple of element size " SIZE_FORMAT, byte_count, elem_size);
|
||||
|
||||
address src_end = src + byte_count;
|
||||
|
||||
if (dst <= src || dst >= src_end) {
|
||||
do_conjoint_swap<RIGHT>(src, dst, byte_count, elem_size);
|
||||
} else {
|
||||
do_conjoint_swap<LEFT>(src, dst, byte_count, elem_size);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Byte swap a 16-bit value
|
||||
*/
|
||||
static uint16_t byte_swap(uint16_t x) {
|
||||
return (x << 8) | (x >> 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte swap a 32-bit value
|
||||
*/
|
||||
static uint32_t byte_swap(uint32_t x) {
|
||||
uint16_t lo = (uint16_t)x;
|
||||
uint16_t hi = (uint16_t)(x >> 16);
|
||||
|
||||
return ((uint32_t)byte_swap(lo) << 16) | (uint32_t)byte_swap(hi);
|
||||
}
|
||||
|
||||
/**
|
||||
* Byte swap a 64-bit value
|
||||
*/
|
||||
static uint64_t byte_swap(uint64_t x) {
|
||||
uint32_t lo = (uint32_t)x;
|
||||
uint32_t hi = (uint32_t)(x >> 32);
|
||||
|
||||
return ((uint64_t)byte_swap(lo) << 32) | (uint64_t)byte_swap(hi);
|
||||
}
|
||||
|
||||
enum CopyDirection {
|
||||
RIGHT, // lower -> higher address
|
||||
LEFT // higher -> lower address
|
||||
};
|
||||
|
||||
/**
|
||||
* Copy and byte swap elements
|
||||
*
|
||||
* <T> - type of element to copy
|
||||
* <D> - copy direction
|
||||
* <is_src_aligned> - true if src argument is aligned to element size
|
||||
* <is_dst_aligned> - true if dst argument is aligned to element size
|
||||
*
|
||||
* @param src address of source
|
||||
* @param dst address of destination
|
||||
* @param byte_count number of bytes to copy
|
||||
*/
|
||||
template <typename T, CopyDirection D, bool is_src_aligned, bool is_dst_aligned>
|
||||
static void do_conjoint_swap(address src, address dst, size_t byte_count) {
|
||||
address cur_src, cur_dst;
|
||||
|
||||
switch (D) {
|
||||
case RIGHT:
|
||||
cur_src = src;
|
||||
cur_dst = dst;
|
||||
break;
|
||||
case LEFT:
|
||||
cur_src = src + byte_count - sizeof(T);
|
||||
cur_dst = dst + byte_count - sizeof(T);
|
||||
break;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < byte_count / sizeof(T); i++) {
|
||||
T tmp;
|
||||
|
||||
if (is_src_aligned) {
|
||||
tmp = *(T*)cur_src;
|
||||
} else {
|
||||
memcpy(&tmp, cur_src, sizeof(T));
|
||||
}
|
||||
|
||||
tmp = byte_swap(tmp);
|
||||
|
||||
if (is_dst_aligned) {
|
||||
*(T*)cur_dst = tmp;
|
||||
} else {
|
||||
memcpy(cur_dst, &tmp, sizeof(T));
|
||||
}
|
||||
|
||||
switch (D) {
|
||||
case RIGHT:
|
||||
cur_src += sizeof(T);
|
||||
cur_dst += sizeof(T);
|
||||
break;
|
||||
case LEFT:
|
||||
cur_src -= sizeof(T);
|
||||
cur_dst -= sizeof(T);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and byte swap elements
|
||||
*
|
||||
* <T> - type of element to copy
|
||||
* <D> - copy direction
|
||||
*
|
||||
* @param src address of source
|
||||
* @param dst address of destination
|
||||
* @param byte_count number of bytes to copy
|
||||
*/
|
||||
template <typename T, CopyDirection direction>
|
||||
static void do_conjoint_swap(address src, address dst, size_t byte_count) {
|
||||
if (is_ptr_aligned(src, sizeof(T))) {
|
||||
if (is_ptr_aligned(dst, sizeof(T))) {
|
||||
do_conjoint_swap<T,direction,true,true>(src, dst, byte_count);
|
||||
} else {
|
||||
do_conjoint_swap<T,direction,true,false>(src, dst, byte_count);
|
||||
}
|
||||
} else {
|
||||
if (is_ptr_aligned(dst, sizeof(T))) {
|
||||
do_conjoint_swap<T,direction,false,true>(src, dst, byte_count);
|
||||
} else {
|
||||
do_conjoint_swap<T,direction,false,false>(src, dst, byte_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy and byte swap elements
|
||||
*
|
||||
* <D> - copy direction
|
||||
*
|
||||
* @param src address of source
|
||||
* @param dst address of destination
|
||||
* @param byte_count number of bytes to copy
|
||||
* @param elem_size size of the elements to copy-swap
|
||||
*/
|
||||
template <CopyDirection D>
|
||||
static void do_conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
|
||||
switch (elem_size) {
|
||||
case 2: do_conjoint_swap<uint16_t,D>(src, dst, byte_count); break;
|
||||
case 4: do_conjoint_swap<uint32_t,D>(src, dst, byte_count); break;
|
||||
case 8: do_conjoint_swap<uint64_t,D>(src, dst, byte_count); break;
|
||||
default: guarantee(false, "do_conjoint_swap: Invalid elem_size %zd\n", elem_size);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void Copy::conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size) {
|
||||
CopySwap::conjoint_swap(src, dst, byte_count, elem_size);
|
||||
}
|
||||
|
||||
// Fill bytes; larger units are filled atomically if everything is aligned.
|
||||
void Copy::fill_to_memory_atomic(void* to, size_t size, jubyte value) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -227,6 +227,16 @@ class Copy : AllStatic {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy and *unconditionally* byte swap elements
|
||||
*
|
||||
* @param src address of source
|
||||
* @param dst address of destination
|
||||
* @param byte_count number of bytes to copy
|
||||
* @param elem_size size of the elements to copy-swap
|
||||
*/
|
||||
static void conjoint_swap(address src, address dst, size_t byte_count, size_t elem_size);
|
||||
|
||||
// Fill methods
|
||||
|
||||
// Fill word-aligned words, not atomic on each word
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -40,6 +40,8 @@ public class VMDeprecatedOptions {
|
|||
// deprecated non-alias flags:
|
||||
{"MaxGCMinorPauseMillis", "1032"},
|
||||
{"UseParNewGC", "false"},
|
||||
{"ConvertSleepToYield", "false" },
|
||||
{"ConvertYieldToSleep", "false" },
|
||||
|
||||
// deprecated alias flags (see also aliased_jvm_flags):
|
||||
{"DefaultMaxRAMFraction", "4"},
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue