Mercurial > hg > truffle
changeset 4745:05de27e852c4
Merge
author | jiangli |
---|---|
date | Wed, 04 Jan 2012 12:36:07 -0500 |
parents | 5ee33ff9b1c4 (diff) cd5d8cafcc84 (current diff) |
children | 2ee4167627a3 |
files | src/share/vm/classfile/classFileParser.cpp |
diffstat | 73 files changed, 1268 insertions(+), 919 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Wed Dec 28 12:15:57 2011 -0500 +++ b/.hgtags Wed Jan 04 12:36:07 2012 -0500 @@ -201,4 +201,9 @@ 088d09a130ff02d8f5f05e92256baabe412f0439 jdk8-b14 6c2a55d4902f202e1c2de1df17b7da083a2c31e8 hs23-b06 fde2a39ed7f39233b287fbc278f437aac06c275b jdk8-b15 +d1f29d4e0bc60e8bd7ae961f1306d8ab33290212 jdk8-b17 +d1f29d4e0bc60e8bd7ae961f1306d8ab33290212 jdk8-b16 6de8c9ba5907e4c5ca05ac4b8d84a8e2cbd92399 hs23-b07 +a2fef924d8e6f37dac2a887315e3502876cc8e24 hs23-b08 +61165f53f1656b9f99e4fb806429bf98b99d59c3 jdk8-b18 +4bcf61041217f8677dcec18e90e9196acc945bba hs23-b09
--- a/make/hotspot_version Wed Dec 28 12:15:57 2011 -0500 +++ b/make/hotspot_version Wed Jan 04 12:36:07 2012 -0500 @@ -35,7 +35,7 @@ HS_MAJOR_VER=23 HS_MINOR_VER=0 -HS_BUILD_NUMBER=08 +HS_BUILD_NUMBER=10 JDK_MAJOR_VER=1 JDK_MINOR_VER=8
--- a/src/cpu/x86/vm/assembler_x86.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/cpu/x86/vm/assembler_x86.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -5968,7 +5968,9 @@ assert(number_of_arguments >= 0 , "cannot have negative number of arguments"); LP64_ONLY(assert(java_thread == r15_thread, "unexpected register")); #ifdef ASSERT - LP64_ONLY(if (UseCompressedOops) verify_heapbase("call_VM_base");) + // TraceBytecodes does not use r12 but saves it over the call, so don't verify + // r12 is the heapbase. + LP64_ONLY(if (UseCompressedOops && !TraceBytecodes) verify_heapbase("call_VM_base");) #endif // ASSERT assert(java_thread != oop_result , "cannot use the same register for java_thread & oop_result");
--- a/src/os/bsd/vm/jvm_bsd.h Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/bsd/vm/jvm_bsd.h Wed Jan 04 12:36:07 2012 -0500 @@ -33,7 +33,6 @@ // All local includes have been commented out. */ - #ifndef JVM_MD_H #define JVM_MD_H @@ -59,6 +58,7 @@ #include <dirent.h> /* For DIR */ #include <sys/param.h> /* For MAXPATHLEN */ +#include <sys/socket.h> /* For socklen_t */ #include <unistd.h> /* For F_OK, R_OK, W_OK */ #define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"} @@ -128,8 +128,4 @@ #endif #endif /* JVM_MD_H */ -// Reconciliation History -// jvm_solaris.h 1.6 99/06/22 16:38:47 -// End - #endif // OS_BSD_VM_JVM_BSD_H
--- a/src/os/bsd/vm/os_bsd.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/bsd/vm/os_bsd.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -150,7 +150,6 @@ // for timer info max values which include all bits #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) -#define SEC_IN_NANOSECS 1000000000LL #define LARGEPAGES_BIT (1 << 6) //////////////////////////////////////////////////////////////////////////////// @@ -2836,7 +2835,7 @@ #endif } -void os::free_memory(char *addr, size_t bytes) { +void os::free_memory(char *addr, size_t bytes, size_t alignment_hint) { ::madvise(addr, bytes, MADV_DONTNEED); } @@ -3445,8 +3444,6 @@ // generates a SIGUSRx signal. Note that SIGUSR1 can interfere with // SIGSEGV, see 4355769. -const int NANOSECS_PER_MILLISECS = 1000000; - int os::sleep(Thread* thread, jlong millis, bool interruptible) { assert(thread == Thread::current(), "thread consistency check"); @@ -3469,7 +3466,7 @@ // not a guarantee() because JVM should not abort on kernel/glibc bugs assert(!Bsd::supports_monotonic_clock(), "time moving backwards"); } else { - millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS; + millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC; } if(millis <= 0) { @@ -3508,7 +3505,7 @@ // not a guarantee() because JVM should not abort on kernel/glibc bugs assert(!Bsd::supports_monotonic_clock(), "time moving backwards"); } else { - millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS; + millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC; } if(millis <= 0) break ; @@ -4197,7 +4194,7 @@ int rc = os::Bsd::clock_gettime(clockid, &tp); assert(rc == 0, "clock_gettime is expected to return 0 code"); - return (tp.tv_sec * SEC_IN_NANOSECS) + tp.tv_nsec; + return (tp.tv_sec * NANOSECS_PER_SEC) + tp.tv_nsec; } #endif @@ -5522,9 +5519,6 @@ * is no need to track notifications. */ - -#define NANOSECS_PER_SEC 1000000000 -#define NANOSECS_PER_MILLISEC 1000000 #define MAX_SECS 100000000 /* * This code is common to bsd and solaris and will be moved to a
--- a/src/os/bsd/vm/os_bsd.inline.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/bsd/vm/os_bsd.inline.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -198,15 +198,15 @@ return ::socket(domain, type, protocol); } -inline int os::recv(int fd, char *buf, int nBytes, int flags) { - RESTARTABLE_RETURN_INT(::recv(fd, buf, nBytes, (unsigned int) flags)); +inline int os::recv(int fd, char* buf, size_t nBytes, uint flags) { + RESTARTABLE_RETURN_INT(::recv(fd, buf, nBytes, flags)); } -inline int os::send(int fd, char *buf, int nBytes, int flags) { - RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, (unsigned int) flags)); +inline int os::send(int fd, char* buf, size_t nBytes, uint flags) { + RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, flags)); } -inline int os::raw_send(int fd, char *buf, int nBytes, int flags) { +inline int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { return os::send(fd, buf, nBytes, flags); } @@ -246,57 +246,52 @@ return ::listen(fd, count); } -inline int os::connect(int fd, struct sockaddr *him, int len) { +inline int os::connect(int fd, struct sockaddr* him, socklen_t len) { RESTARTABLE_RETURN_INT(::connect(fd, him, len)); } -inline int os::accept(int fd, struct sockaddr *him, int *len) { - // This cast is from int to unsigned int on bsd. Since we - // only pass the parameter "len" around the vm and don't try to - // fetch it's value, this cast is safe for now. The java.net group - // may need and want to change this interface someday if socklen_t goes - // to 64 bits on some platform that we support. - +inline int os::accept(int fd, struct sockaddr* him, socklen_t* len) { // At least OpenBSD and FreeBSD can return EINTR from accept. - RESTARTABLE_RETURN_INT(::accept(fd, him, (socklen_t *)len)); + RESTARTABLE_RETURN_INT(::accept(fd, him, len)); } -inline int os::recvfrom(int fd, char *buf, int nBytes, int flags, - sockaddr *from, int *fromlen) { - RESTARTABLE_RETURN_INT(::recvfrom(fd, buf, nBytes, (unsigned int) flags, from, (socklen_t *)fromlen)); +inline int os::recvfrom(int fd, char* buf, size_t nBytes, uint flags, + sockaddr* from, socklen_t* fromlen) { + RESTARTABLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes, flags, from, fromlen)); } -inline int os::sendto(int fd, char *buf, int len, int flags, - struct sockaddr *to, int tolen) { - RESTARTABLE_RETURN_INT(::sendto(fd, buf, len, (unsigned int) flags, to, tolen)); +inline int os::sendto(int fd, char* buf, size_t len, uint flags, + struct sockaddr *to, socklen_t tolen) { + RESTARTABLE_RETURN_INT((int)::sendto(fd, buf, len, flags, to, tolen)); } -inline int os::socket_shutdown(int fd, int howto){ +inline int os::socket_shutdown(int fd, int howto) { return ::shutdown(fd, howto); } -inline int os::bind(int fd, struct sockaddr *him, int len){ +inline int os::bind(int fd, struct sockaddr* him, socklen_t len) { return ::bind(fd, him, len); } -inline int os::get_sock_name(int fd, struct sockaddr *him, int *len){ - return ::getsockname(fd, him, (socklen_t *)len); +inline int os::get_sock_name(int fd, struct sockaddr* him, socklen_t* len) { + return ::getsockname(fd, him, len); } -inline int os::get_host_name(char* name, int namelen){ +inline int os::get_host_name(char* name, int namelen) { return ::gethostname(name, namelen); } -inline struct hostent* os::get_host_by_name(char* name) { +inline struct hostent* os::get_host_by_name(char* name) { return ::gethostbyname(name); } + inline int os::get_sock_opt(int fd, int level, int optname, - char *optval, int* optlen){ - return ::getsockopt(fd, level, optname, optval, (socklen_t *)optlen); + char *optval, socklen_t* optlen) { + return ::getsockopt(fd, level, optname, optval, optlen); } inline int os::set_sock_opt(int fd, int level, int optname, - const char *optval, int optlen){ + const char* optval, socklen_t optlen) { return ::setsockopt(fd, level, optname, optval, optlen); } #endif // OS_BSD_VM_OS_BSD_INLINE_HPP
--- a/src/os/linux/vm/jvm_linux.h Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/linux/vm/jvm_linux.h Wed Jan 04 12:36:07 2012 -0500 @@ -33,7 +33,6 @@ // All local includes have been commented out. */ - #ifndef JVM_MD_H #define JVM_MD_H @@ -44,6 +43,7 @@ #include <dirent.h> /* For DIR */ #include <sys/param.h> /* For MAXPATHLEN */ +#include <sys/socket.h> /* For socklen_t */ #include <unistd.h> /* For F_OK, R_OK, W_OK */ #define JNI_ONLOAD_SYMBOLS {"JNI_OnLoad"} @@ -95,8 +95,4 @@ #endif /* JVM_MD_H */ -// Reconciliation History -// jvm_solaris.h 1.6 99/06/22 16:38:47 -// End - #endif // OS_LINUX_VM_JVM_LINUX_H
--- a/src/os/linux/vm/os_linux.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/linux/vm/os_linux.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -127,7 +127,6 @@ // for timer info max values which include all bits #define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF) -#define SEC_IN_NANOSECS 1000000000LL #define LARGEPAGES_BIT (1 << 6) //////////////////////////////////////////////////////////////////////////////// @@ -2547,8 +2546,8 @@ } } -void os::free_memory(char *addr, size_t bytes) { - commit_memory(addr, bytes, false); +void os::free_memory(char *addr, size_t bytes, size_t alignment_hint) { + commit_memory(addr, bytes, alignment_hint, false); } void os::numa_make_global(char *addr, size_t bytes) { @@ -3259,8 +3258,6 @@ // generates a SIGUSRx signal. Note that SIGUSR1 can interfere with // SIGSEGV, see 4355769. -const int NANOSECS_PER_MILLISECS = 1000000; - int os::sleep(Thread* thread, jlong millis, bool interruptible) { assert(thread == Thread::current(), "thread consistency check"); @@ -3283,7 +3280,7 @@ // not a guarantee() because JVM should not abort on kernel/glibc bugs assert(!Linux::supports_monotonic_clock(), "time moving backwards"); } else { - millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS; + millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC; } if(millis <= 0) { @@ -3322,7 +3319,7 @@ // not a guarantee() because JVM should not abort on kernel/glibc bugs assert(!Linux::supports_monotonic_clock(), "time moving backwards"); } else { - millis -= (newtime - prevtime) / NANOSECS_PER_MILLISECS; + millis -= (newtime - prevtime) / NANOSECS_PER_MILLISEC; } if(millis <= 0) break ; @@ -3924,7 +3921,7 @@ int rc = os::Linux::clock_gettime(clockid, &tp); assert(rc == 0, "clock_gettime is expected to return 0 code"); - return (tp.tv_sec * SEC_IN_NANOSECS) + tp.tv_nsec; + return (tp.tv_sec * NANOSECS_PER_SEC) + tp.tv_nsec; } ///// @@ -5165,9 +5162,6 @@ * is no need to track notifications. */ - -#define NANOSECS_PER_SEC 1000000000 -#define NANOSECS_PER_MILLISEC 1000000 #define MAX_SECS 100000000 /* * This code is common to linux and solaris and will be moved to a
--- a/src/os/linux/vm/os_linux.inline.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/linux/vm/os_linux.inline.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -202,15 +202,15 @@ return ::socket(domain, type, protocol); } -inline int os::recv(int fd, char *buf, int nBytes, int flags) { - RESTARTABLE_RETURN_INT(::recv(fd, buf, nBytes, (unsigned int) flags)); +inline int os::recv(int fd, char* buf, size_t nBytes, uint flags) { + RESTARTABLE_RETURN_INT(::recv(fd, buf, nBytes, flags)); } -inline int os::send(int fd, char *buf, int nBytes, int flags) { - RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, (unsigned int) flags)); +inline int os::send(int fd, char* buf, size_t nBytes, uint flags) { + RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, flags)); } -inline int os::raw_send(int fd, char *buf, int nBytes, int flags) { +inline int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { return os::send(fd, buf, nBytes, flags); } @@ -250,57 +250,53 @@ return ::listen(fd, count); } -inline int os::connect(int fd, struct sockaddr *him, int len) { +inline int os::connect(int fd, struct sockaddr* him, socklen_t len) { RESTARTABLE_RETURN_INT(::connect(fd, him, len)); } -inline int os::accept(int fd, struct sockaddr *him, int *len) { - // This cast is from int to unsigned int on linux. Since we - // only pass the parameter "len" around the vm and don't try to - // fetch it's value, this cast is safe for now. The java.net group - // may need and want to change this interface someday if socklen_t goes - // to 64 bits on some platform that we support. - // Linux doc says this can't return EINTR, unlike accept() on Solaris - - return ::accept(fd, him, (socklen_t *)len); +inline int os::accept(int fd, struct sockaddr* him, socklen_t* len) { + // Linux doc says this can't return EINTR, unlike accept() on Solaris. + // But see attachListener_linux.cpp, LinuxAttachListener::dequeue(). + return (int)::accept(fd, him, len); } -inline int os::recvfrom(int fd, char *buf, int nBytes, int flags, - sockaddr *from, int *fromlen) { - RESTARTABLE_RETURN_INT(::recvfrom(fd, buf, nBytes, (unsigned int) flags, from, (socklen_t *)fromlen)); +inline int os::recvfrom(int fd, char* buf, size_t nBytes, uint flags, + sockaddr* from, socklen_t* fromlen) { + RESTARTABLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes, flags, from, fromlen)); } -inline int os::sendto(int fd, char *buf, int len, int flags, - struct sockaddr *to, int tolen) { - RESTARTABLE_RETURN_INT(::sendto(fd, buf, len, (unsigned int) flags, to, tolen)); +inline int os::sendto(int fd, char* buf, size_t len, uint flags, + struct sockaddr* to, socklen_t tolen) { + RESTARTABLE_RETURN_INT((int)::sendto(fd, buf, len, flags, to, tolen)); } -inline int os::socket_shutdown(int fd, int howto){ +inline int os::socket_shutdown(int fd, int howto) { return ::shutdown(fd, howto); } -inline int os::bind(int fd, struct sockaddr *him, int len){ +inline int os::bind(int fd, struct sockaddr* him, socklen_t len) { return ::bind(fd, him, len); } -inline int os::get_sock_name(int fd, struct sockaddr *him, int *len){ - return ::getsockname(fd, him, (socklen_t *)len); +inline int os::get_sock_name(int fd, struct sockaddr* him, socklen_t* len) { + return ::getsockname(fd, him, len); } -inline int os::get_host_name(char* name, int namelen){ +inline int os::get_host_name(char* name, int namelen) { return ::gethostname(name, namelen); } -inline struct hostent* os::get_host_by_name(char* name) { +inline struct hostent* os::get_host_by_name(char* name) { return ::gethostbyname(name); } + inline int os::get_sock_opt(int fd, int level, int optname, - char *optval, int* optlen){ - return ::getsockopt(fd, level, optname, optval, (socklen_t *)optlen); + char* optval, socklen_t* optlen) { + return ::getsockopt(fd, level, optname, optval, optlen); } inline int os::set_sock_opt(int fd, int level, int optname, - const char *optval, int optlen){ + const char* optval, socklen_t optlen) { return ::setsockopt(fd, level, optname, optval, optlen); } #endif // OS_LINUX_VM_OS_LINUX_INLINE_HPP
--- a/src/os/solaris/vm/jvm_solaris.h Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/solaris/vm/jvm_solaris.h Wed Jan 04 12:36:07 2012 -0500 @@ -33,7 +33,6 @@ // All local includes have been commented out. */ - #ifndef JVM_MD_H #define JVM_MD_H @@ -44,6 +43,7 @@ #include <dirent.h> /* For DIR */ #include <sys/param.h> /* For MAXPATHLEN */ +#include <sys/socket.h> /* For socklen_t */ #include <unistd.h> /* For F_OK, R_OK, W_OK */ #include <sys/int_types.h> /* for intptr_t types (64 Bit cleanliness) */ @@ -82,7 +82,6 @@ #define JVM_O_EXCL O_EXCL #define JVM_O_CREAT O_CREAT - /* Signal definitions */ #define BREAK_SIGNAL SIGQUIT /* Thread dumping support. */
--- a/src/os/solaris/vm/os_solaris.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/solaris/vm/os_solaris.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -1674,7 +1674,6 @@ } -const int NANOSECS_PER_MILLISECS = 1000000; // gethrtime can move backwards if read from one cpu and then a different cpu // getTimeNanos is guaranteed to not move backward on Solaris // local spinloop created as faster for a CAS on an int than @@ -1803,7 +1802,7 @@ // getTimeMillis guaranteed to not move backwards on Solaris jlong getTimeMillis() { jlong nanotime = getTimeNanos(); - return (jlong)(nanotime / NANOSECS_PER_MILLISECS); + return (jlong)(nanotime / NANOSECS_PER_MILLISEC); } // Must return millis since Jan 1 1970 for JVM_CurrentTimeMillis @@ -2822,7 +2821,7 @@ } // Uncommit the pages in a specified region. -void os::free_memory(char* addr, size_t bytes) { +void os::free_memory(char* addr, size_t bytes, size_t alignment_hint) { if (madvise(addr, bytes, MADV_FREE) < 0) { debug_only(warning("MADV_FREE failed.")); return; @@ -6064,10 +6063,7 @@ * is no need to track notifications. */ -#define NANOSECS_PER_SEC 1000000000 -#define NANOSECS_PER_MILLISEC 1000000 #define MAX_SECS 100000000 - /* * This code is common to linux and solaris and will be moved to a * common place in dolphin. @@ -6363,17 +6359,16 @@ RESTARTABLE_RETURN_INT(::close(fd)); } -int os::recv(int fd, char *buf, int nBytes, int flags) { - INTERRUPTIBLE_RETURN_INT(::recv(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); -} - - -int os::send(int fd, char *buf, int nBytes, int flags) { - INTERRUPTIBLE_RETURN_INT(::send(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); -} - -int os::raw_send(int fd, char *buf, int nBytes, int flags) { - RESTARTABLE_RETURN_INT(::send(fd, buf, nBytes, flags)); +int os::recv(int fd, char* buf, size_t nBytes, uint flags) { + INTERRUPTIBLE_RETURN_INT((int)::recv(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); +} + +int os::send(int fd, char* buf, size_t nBytes, uint flags) { + INTERRUPTIBLE_RETURN_INT((int)::send(fd, buf, nBytes, flags), os::Solaris::clear_interrupted); +} + +int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { + RESTARTABLE_RETURN_INT((int)::send(fd, buf, nBytes, flags)); } // As both poll and select can be interrupted by signals, we have to be @@ -6408,19 +6403,19 @@ } } -int os::connect(int fd, struct sockaddr *him, int len) { +int os::connect(int fd, struct sockaddr *him, socklen_t len) { int _result; - INTERRUPTIBLE_NORESTART(::connect(fd, him, len), _result, + INTERRUPTIBLE_NORESTART(::connect(fd, him, len), _result,\ os::Solaris::clear_interrupted); // Depending on when thread interruption is reset, _result could be // one of two values when errno == EINTR if (((_result == OS_INTRPT) || (_result == OS_ERR)) - && (errno == EINTR)) { + && (errno == EINTR)) { /* restarting a connect() changes its errno semantics */ - INTERRUPTIBLE(::connect(fd, him, len), _result, - os::Solaris::clear_interrupted); + INTERRUPTIBLE(::connect(fd, him, len), _result,\ + os::Solaris::clear_interrupted); /* undo these changes */ if (_result == OS_ERR) { if (errno == EALREADY) { @@ -6434,43 +6429,38 @@ return _result; } -int os::accept(int fd, struct sockaddr *him, int *len) { - if (fd < 0) - return OS_ERR; - INTERRUPTIBLE_RETURN_INT((int)::accept(fd, him,\ - (socklen_t*) len), os::Solaris::clear_interrupted); - } - -int os::recvfrom(int fd, char *buf, int nBytes, int flags, - sockaddr *from, int *fromlen) { - //%%note jvm_r11 - INTERRUPTIBLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes,\ - flags, from, fromlen), os::Solaris::clear_interrupted); -} - -int os::sendto(int fd, char *buf, int len, int flags, - struct sockaddr *to, int tolen) { - //%%note jvm_r11 - INTERRUPTIBLE_RETURN_INT((int)::sendto(fd, buf, len, flags,\ - to, tolen), os::Solaris::clear_interrupted); +int os::accept(int fd, struct sockaddr* him, socklen_t* len) { + if (fd < 0) { + return OS_ERR; + } + INTERRUPTIBLE_RETURN_INT((int)::accept(fd, him, len),\ + os::Solaris::clear_interrupted); +} + +int os::recvfrom(int fd, char* buf, size_t nBytes, uint flags, + sockaddr* from, socklen_t* fromlen) { + INTERRUPTIBLE_RETURN_INT((int)::recvfrom(fd, buf, nBytes, flags, from, fromlen),\ + os::Solaris::clear_interrupted); +} + +int os::sendto(int fd, char* buf, size_t len, uint flags, + struct sockaddr* to, socklen_t tolen) { + INTERRUPTIBLE_RETURN_INT((int)::sendto(fd, buf, len, flags, to, tolen),\ + os::Solaris::clear_interrupted); } int os::socket_available(int fd, jint *pbytes) { - if (fd < 0) - return OS_OK; - - int ret; - - RESTARTABLE(::ioctl(fd, FIONREAD, pbytes), ret); - - //%% note ioctl can return 0 when successful, JVM_SocketAvailable - // is expected to return 0 on failure and 1 on success to the jdk. - - return (ret == OS_ERR) ? 0 : 1; -} - - -int os::bind(int fd, struct sockaddr *him, int len) { + if (fd < 0) { + return OS_OK; + } + int ret; + RESTARTABLE(::ioctl(fd, FIONREAD, pbytes), ret); + // note: ioctl can return 0 when successful, JVM_SocketAvailable + // is expected to return 0 on failure and 1 on success to the jdk. + return (ret == OS_ERR) ? 0 : 1; +} + +int os::bind(int fd, struct sockaddr* him, socklen_t len) { INTERRUPTIBLE_RETURN_INT_NORESTART(::bind(fd, him, len),\ - os::Solaris::clear_interrupted); -} + os::Solaris::clear_interrupted); +}
--- a/src/os/solaris/vm/os_solaris.inline.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/solaris/vm/os_solaris.inline.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -243,24 +243,25 @@ return ::shutdown(fd, howto); } -inline int os::get_sock_name(int fd, struct sockaddr *him, int *len){ - return ::getsockname(fd, him, (socklen_t*) len); +inline int os::get_sock_name(int fd, struct sockaddr* him, socklen_t* len){ + return ::getsockname(fd, him, len); } inline int os::get_host_name(char* name, int namelen){ return ::gethostname(name, namelen); } -inline struct hostent* os::get_host_by_name(char* name) { +inline struct hostent* os::get_host_by_name(char* name) { return ::gethostbyname(name); } + inline int os::get_sock_opt(int fd, int level, int optname, - char *optval, int* optlen){ - return ::getsockopt(fd, level, optname, optval, (socklen_t*) optlen); + char* optval, socklen_t* optlen) { + return ::getsockopt(fd, level, optname, optval, optlen); } inline int os::set_sock_opt(int fd, int level, int optname, - const char *optval, int optlen){ + const char *optval, socklen_t optlen) { return ::setsockopt(fd, level, optname, optval, optlen); } #endif // OS_SOLARIS_VM_OS_SOLARIS_INLINE_HPP
--- a/src/os/windows/vm/jvm_windows.h Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/windows/vm/jvm_windows.h Wed Jan 04 12:36:07 2012 -0500 @@ -22,6 +22,9 @@ * */ +#ifndef OS_WINDOWS_VM_JVM_WINDOWS_H +#define OS_WINDOWS_VM_JVM_WINDOWS_H + #ifndef _JAVASOFT_JVM_MD_H_ #define _JAVASOFT_JVM_MD_H_ @@ -54,9 +57,9 @@ #include <Psapi.h> #endif - +#include <Tlhelp32.h> -#include <Tlhelp32.h> +typedef unsigned int socklen_t; // #include "jni.h" @@ -129,3 +132,5 @@ #define SHUTDOWN2_SIGNAL SIGTERM #endif /* !_JAVASOFT_JVM_MD_H_ */ + +#endif // OS_WINDOWS_VM_JVM_WINDOWS_H
--- a/src/os/windows/vm/os_windows.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/os/windows/vm/os_windows.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -821,17 +821,15 @@ } } -#define NANOS_PER_SEC CONST64(1000000000) -#define NANOS_PER_MILLISEC 1000000 jlong os::javaTimeNanos() { if (!has_performance_count) { - return javaTimeMillis() * NANOS_PER_MILLISEC; // the best we can do. + return javaTimeMillis() * NANOSECS_PER_MILLISEC; // the best we can do. } else { LARGE_INTEGER current_count; QueryPerformanceCounter(¤t_count); double current = as_long(current_count); double freq = performance_frequency; - jlong time = (jlong)((current/freq) * NANOS_PER_SEC); + jlong time = (jlong)((current/freq) * NANOSECS_PER_SEC); return time; } } @@ -847,15 +845,15 @@ info_ptr->may_skip_forward = true; } else { jlong freq = performance_frequency; - if (freq < NANOS_PER_SEC) { + if (freq < NANOSECS_PER_SEC) { // the performance counter is 64 bits and we will // be multiplying it -- so no wrap in 64 bits info_ptr->max_value = ALL_64_BITS; - } else if (freq > NANOS_PER_SEC) { + } else if (freq > NANOSECS_PER_SEC) { // use the max value the counter can reach to // determine the max value which could be returned julong max_counter = (julong)ALL_64_BITS; - info_ptr->max_value = (jlong)(max_counter / (freq / NANOS_PER_SEC)); + info_ptr->max_value = (jlong)(max_counter / (freq / NANOSECS_PER_SEC)); } else { // the performance counter is 64 bits and we will // be using it directly -- so no wrap in 64 bits @@ -3132,7 +3130,7 @@ } void os::realign_memory(char *addr, size_t bytes, size_t alignment_hint) { } -void os::free_memory(char *addr, size_t bytes) { } +void os::free_memory(char *addr, size_t bytes, size_t alignment_hint) { } void os::numa_make_global(char *addr, size_t bytes) { } void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) { } bool os::numa_topology_changed() { return false; } @@ -4851,7 +4849,7 @@ ::mutexUnlock(&sockFnTableMutex); } -struct hostent* os::get_host_by_name(char* name) { +struct hostent* os::get_host_by_name(char* name) { if (!sock_initialized) { initSock(); } @@ -4882,39 +4880,39 @@ return 0; } -int os::connect(int fd, struct sockaddr *him, int len) { +int os::connect(int fd, struct sockaddr* him, socklen_t len) { ShouldNotReachHere(); return 0; } -int os::accept(int fd, struct sockaddr *him, int *len) { +int os::accept(int fd, struct sockaddr* him, socklen_t* len) { ShouldNotReachHere(); return 0; } -int os::sendto(int fd, char *buf, int len, int flags, - struct sockaddr *to, int tolen) { +int os::sendto(int fd, char* buf, size_t len, uint flags, + struct sockaddr* to, socklen_t tolen) { ShouldNotReachHere(); return 0; } -int os::recvfrom(int fd, char *buf, int nBytes, int flags, - sockaddr *from, int *fromlen) { +int os::recvfrom(int fd, char *buf, size_t nBytes, uint flags, + sockaddr* from, socklen_t* fromlen) { ShouldNotReachHere(); return 0; } -int os::recv(int fd, char *buf, int nBytes, int flags) { +int os::recv(int fd, char* buf, size_t nBytes, uint flags) { ShouldNotReachHere(); return 0; } -int os::send(int fd, char *buf, int nBytes, int flags) { +int os::send(int fd, char* buf, size_t nBytes, uint flags) { ShouldNotReachHere(); return 0; } -int os::raw_send(int fd, char *buf, int nBytes, int flags) { +int os::raw_send(int fd, char* buf, size_t nBytes, uint flags) { ShouldNotReachHere(); return 0; } @@ -4934,24 +4932,24 @@ return 0; } -int os::bind(int fd, struct sockaddr *him, int len) { +int os::bind(int fd, struct sockaddr* him, socklen_t len) { ShouldNotReachHere(); return 0; } -int os::get_sock_name(int fd, struct sockaddr *him, int *len) { +int os::get_sock_name(int fd, struct sockaddr* him, socklen_t* len) { ShouldNotReachHere(); return 0; } int os::get_sock_opt(int fd, int level, int optname, - char *optval, int* optlen) { + char* optval, socklen_t* optlen) { ShouldNotReachHere(); return 0; } int os::set_sock_opt(int fd, int level, int optname, - const char *optval, int optlen) { + const char* optval, socklen_t optlen) { ShouldNotReachHere(); return 0; }
--- a/src/share/vm/classfile/classFileParser.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/classfile/classFileParser.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -45,6 +45,7 @@ #include "oops/methodOop.hpp" #include "oops/symbol.hpp" #include "prims/jvmtiExport.hpp" +#include "prims/jvmtiThreadState.hpp" #include "runtime/javaCalls.hpp" #include "runtime/perfData.hpp" #include "runtime/reflection.hpp" @@ -2641,8 +2642,11 @@ TempNewSymbol& parsed_name, bool verify, TRAPS) { - // So that JVMTI can cache class file in the state before retransformable agents - // have modified it + // When a retransformable agent is attached, JVMTI caches the + // class bytes that existed before the first retransformation. + // If RedefineClasses() was used before the retransformable + // agent attached, then the cached class bytes may not be the + // original class bytes. unsigned char *cached_class_file_bytes = NULL; jint cached_class_file_length; @@ -2662,6 +2666,20 @@ _max_bootstrap_specifier_index = -1; if (JvmtiExport::should_post_class_file_load_hook()) { + // Get the cached class file bytes (if any) from the + // class that is being redefined. + JvmtiThreadState *state = JvmtiThreadState::state_for(jt); + KlassHandle *h_class_being_redefined = + state->get_class_being_redefined(); + if (h_class_being_redefined != NULL) { + instanceKlassHandle ikh_class_being_redefined = + instanceKlassHandle(THREAD, (*h_class_being_redefined)()); + cached_class_file_bytes = + ikh_class_being_redefined->get_cached_class_file_bytes(); + cached_class_file_length = + ikh_class_being_redefined->get_cached_class_file_len(); + } + unsigned char* ptr = cfs->buffer(); unsigned char* end_ptr = cfs->buffer() + cfs->length();
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -2598,7 +2598,7 @@ AdaptiveWeightedAverage CFLS_LAB::_blocks_to_claim[] = VECTOR_257(AdaptiveWeightedAverage(OldPLABWeight, (float)CMSParPromoteBlocksToClaim)); size_t CFLS_LAB::_global_num_blocks[] = VECTOR_257(0); -int CFLS_LAB::_global_num_workers[] = VECTOR_257(0); +uint CFLS_LAB::_global_num_workers[] = VECTOR_257(0); CFLS_LAB::CFLS_LAB(CompactibleFreeListSpace* cfls) : _cfls(cfls) @@ -2732,7 +2732,7 @@ // Update globals stats for num_blocks used _global_num_blocks[i] += (_num_blocks[i] - num_retire); _global_num_workers[i]++; - assert(_global_num_workers[i] <= (ssize_t)ParallelGCThreads, "Too big"); + assert(_global_num_workers[i] <= ParallelGCThreads, "Too big"); if (num_retire > 0) { _cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]); // Reset this list.
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -336,12 +336,6 @@ unallocated_block() : end()); } - // This is needed because the default implementation uses block_start() - // which can;t be used at certain times (for example phase 3 of mark-sweep). - // A better fix is to change the assertions in phase 3 of mark-sweep to - // use is_in_reserved(), but that is deferred since the is_in() assertions - // are buried through several layers of callers and are used elsewhere - // as well. bool is_in(const void* p) const { return used_region().contains(p); } @@ -637,7 +631,7 @@ static AdaptiveWeightedAverage _blocks_to_claim [CompactibleFreeListSpace::IndexSetSize]; static size_t _global_num_blocks [CompactibleFreeListSpace::IndexSetSize]; - static int _global_num_workers[CompactibleFreeListSpace::IndexSetSize]; + static uint _global_num_workers[CompactibleFreeListSpace::IndexSetSize]; size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize]; // Internal work method
--- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -3779,7 +3779,7 @@ terminator()->reset_for_reuse(active_workers); } - void work(int i); + void work(uint worker_id); bool should_yield() { return ConcurrentMarkSweepThread::should_yield() && !_collector->foregroundGCIsActive() @@ -3852,7 +3852,7 @@ // . if neither is available, offer termination // -- Terminate and return result // -void CMSConcMarkingTask::work(int i) { +void CMSConcMarkingTask::work(uint worker_id) { elapsedTimer _timer; ResourceMark rm; HandleMark hm; @@ -3860,37 +3860,40 @@ DEBUG_ONLY(_collector->verify_overflow_empty();) // Before we begin work, our work queue should be empty - assert(work_queue(i)->size() == 0, "Expected to be empty"); + assert(work_queue(worker_id)->size() == 0, "Expected to be empty"); // Scan the bitmap covering _cms_space, tracing through grey objects. _timer.start(); - do_scan_and_mark(i, _cms_space); + do_scan_and_mark(worker_id, _cms_space); _timer.stop(); if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr("Finished cms space scanning in %dth thread: %3.3f sec", - i, _timer.seconds()); // XXX: need xxx/xxx type of notation, two timers + worker_id, _timer.seconds()); + // XXX: need xxx/xxx type of notation, two timers } // ... do the same for the _perm_space _timer.reset(); _timer.start(); - do_scan_and_mark(i, _perm_space); + do_scan_and_mark(worker_id, _perm_space); _timer.stop(); if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr("Finished perm space scanning in %dth thread: %3.3f sec", - i, _timer.seconds()); // XXX: need xxx/xxx type of notation, two timers + worker_id, _timer.seconds()); + // XXX: need xxx/xxx type of notation, two timers } // ... do work stealing _timer.reset(); _timer.start(); - do_work_steal(i); + do_work_steal(worker_id); _timer.stop(); if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr("Finished work stealing in %dth thread: %3.3f sec", - i, _timer.seconds()); // XXX: need xxx/xxx type of notation, two timers + worker_id, _timer.seconds()); + // XXX: need xxx/xxx type of notation, two timers } assert(_collector->_markStack.isEmpty(), "Should have been emptied"); - assert(work_queue(i)->size() == 0, "Should have been emptied"); + assert(work_queue(worker_id)->size() == 0, "Should have been emptied"); // Note that under the current task protocol, the // following assertion is true even of the spaces // expanded since the completion of the concurrent @@ -3946,7 +3949,7 @@ // We allow that there may be no tasks to do here because // we are restarting after a stack overflow. assert(pst->valid() || n_tasks == 0, "Uninitialized use?"); - int nth_task = 0; + uint nth_task = 0; HeapWord* aligned_start = sp->bottom(); if (sp->used_region().contains(_restart_addr)) { @@ -5075,7 +5078,7 @@ ParallelTaskTerminator* terminator() { return &_term; } int n_workers() { return _n_workers; } - void work(int i); + void work(uint worker_id); private: // Work method in support of parallel rescan ... of young gen spaces @@ -5096,7 +5099,7 @@ // also is passed to do_dirty_card_rescan_tasks() and to // do_work_steal() to select the i-th task_queue. -void CMSParRemarkTask::work(int i) { +void CMSParRemarkTask::work(uint worker_id) { elapsedTimer _timer; ResourceMark rm; HandleMark hm; @@ -5107,7 +5110,7 @@ Par_MarkRefsIntoAndScanClosure par_mrias_cl(_collector, _collector->_span, _collector->ref_processor(), &(_collector->_markBitMap), - work_queue(i), &(_collector->_revisitStack)); + work_queue(worker_id), &(_collector->_revisitStack)); // Rescan young gen roots first since these are likely // coarsely partitioned and may, on that account, constitute @@ -5128,15 +5131,15 @@ assert(ect <= _collector->_eden_chunk_capacity, "out of bounds"); assert(sct <= _collector->_survivor_chunk_capacity, "out of bounds"); - do_young_space_rescan(i, &par_mrias_cl, to_space, NULL, 0); - do_young_space_rescan(i, &par_mrias_cl, from_space, sca, sct); - do_young_space_rescan(i, &par_mrias_cl, eden_space, eca, ect); + do_young_space_rescan(worker_id, &par_mrias_cl, to_space, NULL, 0); + do_young_space_rescan(worker_id, &par_mrias_cl, from_space, sca, sct); + do_young_space_rescan(worker_id, &par_mrias_cl, eden_space, eca, ect); _timer.stop(); if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr( "Finished young gen rescan work in %dth thread: %3.3f sec", - i, _timer.seconds()); + worker_id, _timer.seconds()); } } @@ -5158,7 +5161,7 @@ if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr( "Finished remaining root rescan work in %dth thread: %3.3f sec", - i, _timer.seconds()); + worker_id, _timer.seconds()); } // ---------- rescan dirty cards ------------ @@ -5167,26 +5170,26 @@ // Do the rescan tasks for each of the two spaces // (cms_space and perm_space) in turn. - // "i" is passed to select the "i-th" task_queue - do_dirty_card_rescan_tasks(_cms_space, i, &par_mrias_cl); - do_dirty_card_rescan_tasks(_perm_space, i, &par_mrias_cl); + // "worker_id" is passed to select the task_queue for "worker_id" + do_dirty_card_rescan_tasks(_cms_space, worker_id, &par_mrias_cl); + do_dirty_card_rescan_tasks(_perm_space, worker_id, &par_mrias_cl); _timer.stop(); if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr( "Finished dirty card rescan work in %dth thread: %3.3f sec", - i, _timer.seconds()); + worker_id, _timer.seconds()); } // ---------- steal work from other threads ... // ---------- ... and drain overflow list. _timer.reset(); _timer.start(); - do_work_steal(i, &par_mrias_cl, _collector->hash_seed(i)); + do_work_steal(worker_id, &par_mrias_cl, _collector->hash_seed(worker_id)); _timer.stop(); if (PrintCMSStatistics != 0) { gclog_or_tty->print_cr( "Finished work stealing in %dth thread: %3.3f sec", - i, _timer.seconds()); + worker_id, _timer.seconds()); } } @@ -5207,8 +5210,8 @@ SequentialSubTasksDone* pst = space->par_seq_tasks(); assert(pst->valid(), "Uninitialized use?"); - int nth_task = 0; - int n_tasks = pst->n_tasks(); + uint nth_task = 0; + uint n_tasks = pst->n_tasks(); HeapWord *start, *end; while (!pst->is_task_claimed(/* reference */ nth_task)) { @@ -5220,12 +5223,12 @@ } else if (nth_task == 0) { start = space->bottom(); end = chunk_array[nth_task]; - } else if (nth_task < (jint)chunk_top) { + } else if (nth_task < (uint)chunk_top) { assert(nth_task >= 1, "Control point invariant"); start = chunk_array[nth_task - 1]; end = chunk_array[nth_task]; } else { - assert(nth_task == (jint)chunk_top, "Control point invariant"); + assert(nth_task == (uint)chunk_top, "Control point invariant"); start = chunk_array[chunk_top - 1]; end = space->top(); } @@ -5288,7 +5291,7 @@ SequentialSubTasksDone* pst = sp->conc_par_seq_tasks(); assert(pst->valid(), "Uninitialized use?"); - int nth_task = 0; + uint nth_task = 0; const int alignment = CardTableModRefBS::card_size * BitsPerWord; MemRegion span = sp->used_region(); HeapWord* start_addr = span.start(); @@ -5736,26 +5739,26 @@ CMSParKeepAliveClosure* keep_alive, int* seed); - virtual void work(int i); + virtual void work(uint worker_id); }; -void CMSRefProcTaskProxy::work(int i) { +void CMSRefProcTaskProxy::work(uint worker_id) { assert(_collector->_span.equals(_span), "Inconsistency in _span"); CMSParKeepAliveClosure par_keep_alive(_collector, _span, _mark_bit_map, &_collector->_revisitStack, - work_queue(i)); + work_queue(worker_id)); CMSParDrainMarkingStackClosure par_drain_stack(_collector, _span, _mark_bit_map, &_collector->_revisitStack, - work_queue(i)); + work_queue(worker_id)); CMSIsAliveClosure is_alive_closure(_span, _mark_bit_map); - _task.work(i, is_alive_closure, par_keep_alive, par_drain_stack); + _task.work(worker_id, is_alive_closure, par_keep_alive, par_drain_stack); if (_task.marks_oops_alive()) { - do_work_steal(i, &par_drain_stack, &par_keep_alive, - _collector->hash_seed(i)); - } - assert(work_queue(i)->size() == 0, "work_queue should be empty"); + do_work_steal(worker_id, &par_drain_stack, &par_keep_alive, + _collector->hash_seed(worker_id)); + } + assert(work_queue(worker_id)->size() == 0, "work_queue should be empty"); assert(_collector->_overflow_list == NULL, "non-empty _overflow_list"); } @@ -5769,9 +5772,9 @@ _task(task) { } - virtual void work(int i) + virtual void work(uint worker_id) { - _task.work(i); + _task.work(worker_id); } };
--- a/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -264,7 +264,7 @@ // or some improperly initialized variable with leads to no // active threads, protect against that in a product build. n_threads = MAX2(G1CollectedHeap::heap()->workers()->active_workers(), - 1); + 1U); } size_t max_waste = n_threads * chunkSize; // it should be aligned with respect to chunkSize
--- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -458,8 +458,8 @@ #pragma warning( disable:4355 ) // 'this' : used in base member initializer list #endif // _MSC_VER -size_t ConcurrentMark::scale_parallel_threads(size_t n_par_threads) { - return MAX2((n_par_threads + 2) / 4, (size_t)1); +uint ConcurrentMark::scale_parallel_threads(uint n_par_threads) { + return MAX2((n_par_threads + 2) / 4, 1U); } ConcurrentMark::ConcurrentMark(ReservedSpace rs, @@ -486,7 +486,7 @@ _regionStack(), // _finger set in set_non_marking_state - _max_task_num(MAX2(ParallelGCThreads, (size_t)1)), + _max_task_num(MAX2((uint)ParallelGCThreads, 1U)), // _active_tasks set in set_non_marking_state // _tasks set inside the constructor _task_queues(new CMTaskQueueSet((int) _max_task_num)), @@ -506,7 +506,6 @@ _cleanup_times(), _total_counting_time(0.0), _total_rs_scrub_time(0.0), - _parallel_workers(NULL) { CMVerboseLevel verbose_level = (CMVerboseLevel) G1MarkingVerboseLevel; if (verbose_level < no_verbose) { @@ -568,7 +567,7 @@ // notice that ConcGCThreads overwrites G1MarkingOverheadPercent // if both are set - _parallel_marking_threads = ConcGCThreads; + _parallel_marking_threads = (uint) ConcGCThreads; _max_parallel_marking_threads = _parallel_marking_threads; _sleep_factor = 0.0; _marking_task_overhead = 1.0; @@ -589,12 +588,12 @@ double sleep_factor = (1.0 - marking_task_overhead) / marking_task_overhead; - _parallel_marking_threads = (size_t) marking_thread_num; + _parallel_marking_threads = (uint) marking_thread_num; _max_parallel_marking_threads = _parallel_marking_threads; _sleep_factor = sleep_factor; _marking_task_overhead = marking_task_overhead; } else { - _parallel_marking_threads = scale_parallel_threads(ParallelGCThreads); + _parallel_marking_threads = scale_parallel_threads((uint)ParallelGCThreads); _max_parallel_marking_threads = _parallel_marking_threads; _sleep_factor = 0.0; _marking_task_overhead = 1.0; @@ -618,7 +617,7 @@ guarantee(parallel_marking_threads() > 0, "peace of mind"); _parallel_workers = new FlexibleWorkGang("G1 Parallel Marking Threads", - (int) _max_parallel_marking_threads, false, true); + _max_parallel_marking_threads, false, true); if (_parallel_workers == NULL) { vm_exit_during_initialization("Failed necessary allocation."); } else { @@ -691,7 +690,7 @@ set_concurrent_marking_in_progress(); } -void ConcurrentMark::set_phase(size_t active_tasks, bool concurrent) { +void ConcurrentMark::set_phase(uint active_tasks, bool concurrent) { assert(active_tasks <= _max_task_num, "we should not have more"); _active_tasks = active_tasks; @@ -727,12 +726,8 @@ } ConcurrentMark::~ConcurrentMark() { - for (int i = 0; i < (int) _max_task_num; ++i) { - delete _task_queues->queue(i); - delete _tasks[i]; - } - delete _task_queues; - FREE_C_HEAP_ARRAY(CMTask*, _max_task_num); + // The ConcurrentMark instance is never freed. + ShouldNotReachHere(); } // This closure is used to mark refs into the g1 generation @@ -1048,7 +1043,7 @@ ConcurrentMarkThread* _cmt; public: - void work(int worker_i) { + void work(uint worker_id) { assert(Thread::current()->is_ConcurrentGC_thread(), "this should only be done by a conc GC thread"); ResourceMark rm; @@ -1057,8 +1052,8 @@ ConcurrentGCThread::stsJoin(); - assert((size_t) worker_i < _cm->active_tasks(), "invariant"); - CMTask* the_task = _cm->task(worker_i); + assert(worker_id < _cm->active_tasks(), "invariant"); + CMTask* the_task = _cm->task(worker_id); the_task->record_start_time(); if (!_cm->has_aborted()) { do { @@ -1076,7 +1071,7 @@ double elapsed_time_sec = end_time_sec - start_time_sec; _cm->clear_has_overflown(); - bool ret = _cm->do_yield_check(worker_i); + bool ret = _cm->do_yield_check(worker_id); jlong sleep_time_ms; if (!_cm->has_aborted() && the_task->has_aborted()) { @@ -1105,7 +1100,7 @@ ConcurrentGCThread::stsLeave(); double end_vtime = os::elapsedVTime(); - _cm->update_accum_task_vtime(worker_i, end_vtime - start_vtime); + _cm->update_accum_task_vtime(worker_id, end_vtime - start_vtime); } CMConcurrentMarkingTask(ConcurrentMark* cm, @@ -1117,12 +1112,9 @@ // Calculates the number of active workers for a concurrent // phase. -int ConcurrentMark::calc_parallel_marking_threads() { - - size_t n_conc_workers; - if (!G1CollectedHeap::use_parallel_gc_threads()) { - n_conc_workers = 1; - } else { +uint ConcurrentMark::calc_parallel_marking_threads() { + if (G1CollectedHeap::use_parallel_gc_threads()) { + uint n_conc_workers = 0; if (!UseDynamicNumberOfGCThreads || (!FLAG_IS_DEFAULT(ConcGCThreads) && !ForceDynamicNumberOfGCThreads)) { @@ -1137,9 +1129,13 @@ // Don't scale down "n_conc_workers" by scale_parallel_threads() because // that scaling has already gone into "_max_parallel_marking_threads". } + assert(n_conc_workers > 0, "Always need at least 1"); + return n_conc_workers; } - assert(n_conc_workers > 0, "Always need at least 1"); - return (int) MAX2(n_conc_workers, (size_t) 1); + // If we are not running with any parallel GC threads we will not + // have spawned any marking threads either. Hence the number of + // concurrent workers should be 0. + return 0; } void ConcurrentMark::markFromRoots() { @@ -1151,24 +1147,24 @@ // stop-the-world GC happens even as we mark in this generation. _restart_for_overflow = false; - - // Parallel task terminator is set in "set_phase()". force_overflow_conc()->init(); // _g1h has _n_par_threads - _parallel_marking_threads = calc_parallel_marking_threads(); assert(parallel_marking_threads() <= max_parallel_marking_threads(), "Maximum number of marking threads exceeded"); - _parallel_workers->set_active_workers((int)_parallel_marking_threads); - // Don't set _n_par_threads because it affects MT in proceess_strong_roots() - // and the decisions on that MT processing is made elsewhere. - - assert( _parallel_workers->active_workers() > 0, "Should have been set"); - set_phase(_parallel_workers->active_workers(), true /* concurrent */); + + uint active_workers = MAX2(1U, parallel_marking_threads()); + + // Parallel task terminator is set in "set_phase()" + set_phase(active_workers, true /* concurrent */); CMConcurrentMarkingTask markingTask(this, cmThread()); if (parallel_marking_threads() > 0) { + _parallel_workers->set_active_workers((int)active_workers); + // Don't set _n_par_threads because it affects MT in proceess_strong_roots() + // and the decisions on that MT processing is made elsewhere. + assert(_parallel_workers->active_workers() > 0, "Should have been set"); _parallel_workers->run_task(&markingTask); } else { markingTask.work(0); @@ -1502,7 +1498,7 @@ protected: G1CollectedHeap* _g1h; CMBitMap* _bm; - size_t _n_workers; + uint _n_workers; size_t *_live_bytes; size_t *_used_bytes; BitMap* _region_bm; @@ -1534,13 +1530,13 @@ FREE_C_HEAP_ARRAY(size_t, _used_bytes); } - void work(int i) { + void work(uint worker_id) { CalcLiveObjectsClosure calccl(true /*final*/, _bm, _g1h->concurrent_mark(), _region_bm, _card_bm); calccl.no_yield(); if (G1CollectedHeap::use_parallel_gc_threads()) { - _g1h->heap_region_par_iterate_chunked(&calccl, i, + _g1h->heap_region_par_iterate_chunked(&calccl, worker_id, (int) _n_workers, HeapRegion::FinalCountClaimValue); } else { @@ -1548,19 +1544,19 @@ } assert(calccl.complete(), "Shouldn't have yielded!"); - assert((size_t) i < _n_workers, "invariant"); - _live_bytes[i] = calccl.tot_live(); - _used_bytes[i] = calccl.tot_used(); + assert(worker_id < _n_workers, "invariant"); + _live_bytes[worker_id] = calccl.tot_live(); + _used_bytes[worker_id] = calccl.tot_used(); } size_t live_bytes() { size_t live_bytes = 0; - for (size_t i = 0; i < _n_workers; ++i) + for (uint i = 0; i < _n_workers; ++i) live_bytes += _live_bytes[i]; return live_bytes; } size_t used_bytes() { size_t used_bytes = 0; - for (size_t i = 0; i < _n_workers; ++i) + for (uint i = 0; i < _n_workers; ++i) used_bytes += _used_bytes[i]; return used_bytes; } @@ -1645,18 +1641,18 @@ AbstractGangTask("G1 note end"), _g1h(g1h), _max_live_bytes(0), _freed_bytes(0), _cleanup_list(cleanup_list) { } - void work(int i) { + void work(uint worker_id) { double start = os::elapsedTime(); FreeRegionList local_cleanup_list("Local Cleanup List"); OldRegionSet old_proxy_set("Local Cleanup Old Proxy Set"); HumongousRegionSet humongous_proxy_set("Local Cleanup Humongous Proxy Set"); HRRSCleanupTask hrrs_cleanup_task; - G1NoteEndOfConcMarkClosure g1_note_end(_g1h, i, &local_cleanup_list, + G1NoteEndOfConcMarkClosure g1_note_end(_g1h, worker_id, &local_cleanup_list, &old_proxy_set, &humongous_proxy_set, &hrrs_cleanup_task); if (G1CollectedHeap::use_parallel_gc_threads()) { - _g1h->heap_region_par_iterate_chunked(&g1_note_end, i, + _g1h->heap_region_par_iterate_chunked(&g1_note_end, worker_id, _g1h->workers()->active_workers(), HeapRegion::NoteEndClaimValue); } else { @@ -1700,8 +1696,8 @@ double end = os::elapsedTime(); if (G1PrintParCleanupStats) { gclog_or_tty->print(" Worker thread %d [%8.3f..%8.3f = %8.3f ms] " - "claimed %d regions (tot = %8.3f ms, max = %8.3f ms).\n", - i, start, end, (end-start)*1000.0, + "claimed %u regions (tot = %8.3f ms, max = %8.3f ms).\n", + worker_id, start, end, (end-start)*1000.0, g1_note_end.regions_claimed(), g1_note_end.claimed_region_time_sec()*1000.0, g1_note_end.max_region_time_sec()*1000.0); @@ -1723,9 +1719,9 @@ _region_bm(region_bm), _card_bm(card_bm) {} - void work(int i) { + void work(uint worker_id) { if (G1CollectedHeap::use_parallel_gc_threads()) { - _g1rs->scrub_par(_region_bm, _card_bm, i, + _g1rs->scrub_par(_region_bm, _card_bm, worker_id, HeapRegion::ScrubRemSetClaimValue); } else { _g1rs->scrub(_region_bm, _card_bm); @@ -1765,8 +1761,7 @@ HeapRegionRemSet::reset_for_cleanup_tasks(); - g1h->set_par_threads(); - size_t n_workers = g1h->n_par_threads(); + uint n_workers; // Do counting once more with the world stopped for good measure. G1ParFinalCountTask g1_par_count_task(g1h, nextMarkBitMap(), @@ -1776,8 +1771,10 @@ HeapRegion::InitialClaimValue), "sanity check"); - assert(g1h->n_par_threads() == (int) n_workers, - "Should not have been reset"); + g1h->set_par_threads(); + n_workers = g1h->n_par_threads(); + assert(g1h->n_par_threads() == n_workers, + "Should not have been reset"); g1h->workers()->run_task(&g1_par_count_task); // Done with the parallel phase so reset to 0. g1h->set_par_threads(0); @@ -1786,6 +1783,7 @@ HeapRegion::FinalCountClaimValue), "sanity check"); } else { + n_workers = 1; g1_par_count_task.work(0); } @@ -1851,7 +1849,6 @@ (note_end_end - note_end_start)*1000.0); } - // call below, since it affects the metric by which we sort the heap // regions. if (G1ScrubRemSets) { @@ -2167,13 +2164,13 @@ AbstractGangTask("Process reference objects in parallel"), _proc_task(proc_task), _g1h(g1h), _cm(cm) { } - virtual void work(int i) { - CMTask* marking_task = _cm->task(i); + virtual void work(uint worker_id) { + CMTask* marking_task = _cm->task(worker_id); G1CMIsAliveClosure g1_is_alive(_g1h); G1CMParKeepAliveAndDrainClosure g1_par_keep_alive(_cm, marking_task); G1CMParDrainMarkingStackClosure g1_par_drain(_cm, marking_task); - _proc_task.work(i, g1_is_alive, g1_par_keep_alive, g1_par_drain); + _proc_task.work(worker_id, g1_is_alive, g1_par_keep_alive, g1_par_drain); } }; @@ -2199,8 +2196,8 @@ AbstractGangTask("Enqueue reference objects in parallel"), _enq_task(enq_task) { } - virtual void work(int i) { - _enq_task.work(i); + virtual void work(uint worker_id) { + _enq_task.work(worker_id); } }; @@ -2247,8 +2244,8 @@ // We use the work gang from the G1CollectedHeap and we utilize all // the worker threads. - int active_workers = g1h->workers() ? g1h->workers()->active_workers() : 1; - active_workers = MAX2(MIN2(active_workers, (int)_max_task_num), 1); + uint active_workers = g1h->workers() ? g1h->workers()->active_workers() : 1U; + active_workers = MAX2(MIN2(active_workers, _max_task_num), 1U); G1CMRefProcTaskExecutor par_task_executor(g1h, this, g1h->workers(), active_workers); @@ -2312,11 +2309,11 @@ ConcurrentMark *_cm; public: - void work(int worker_i) { + void work(uint worker_id) { // Since all available tasks are actually started, we should // only proceed if we're supposed to be actived. - if ((size_t)worker_i < _cm->active_tasks()) { - CMTask* task = _cm->task(worker_i); + if (worker_id < _cm->active_tasks()) { + CMTask* task = _cm->task(worker_id); task->record_start_time(); do { task->do_marking_step(1000000000.0 /* something very large */, @@ -2329,9 +2326,9 @@ } } - CMRemarkTask(ConcurrentMark* cm) : + CMRemarkTask(ConcurrentMark* cm, int active_workers) : AbstractGangTask("Par Remark"), _cm(cm) { - _cm->terminator()->reset_for_reuse(cm->_g1h->workers()->active_workers()); + _cm->terminator()->reset_for_reuse(active_workers); } }; @@ -2345,10 +2342,10 @@ if (G1CollectedHeap::use_parallel_gc_threads()) { G1CollectedHeap::StrongRootsScope srs(g1h); // this is remark, so we'll use up all active threads - int active_workers = g1h->workers()->active_workers(); + uint active_workers = g1h->workers()->active_workers(); if (active_workers == 0) { assert(active_workers > 0, "Should have been set earlier"); - active_workers = ParallelGCThreads; + active_workers = (uint) ParallelGCThreads; g1h->workers()->set_active_workers(active_workers); } set_phase(active_workers, false /* concurrent */); @@ -2357,17 +2354,17 @@ // constructor and pass values of the active workers // through the gang in the task. - CMRemarkTask remarkTask(this); + CMRemarkTask remarkTask(this, active_workers); g1h->set_par_threads(active_workers); g1h->workers()->run_task(&remarkTask); g1h->set_par_threads(0); } else { G1CollectedHeap::StrongRootsScope srs(g1h); // this is remark, so we'll use up all available threads - int active_workers = 1; + uint active_workers = 1; set_phase(active_workers, false /* concurrent */); - CMRemarkTask remarkTask(this); + CMRemarkTask remarkTask(this, active_workers); // We will start all available threads, even if we decide that the // active_workers will be fewer. The extra ones will just bail out // immediately. @@ -2919,7 +2916,7 @@ int _ms_size; int _ms_ind; int _array_increment; - int _worker_i; + uint _worker_id; bool push(oop obj, int arr_ind = 0) { if (_ms_ind == _ms_size) { @@ -2969,7 +2966,7 @@ } public: - CSetMarkOopClosure(ConcurrentMark* cm, int ms_size, int worker_i) : + CSetMarkOopClosure(ConcurrentMark* cm, int ms_size, uint worker_id) : _g1h(G1CollectedHeap::heap()), _cm(cm), _bm(cm->nextMarkBitMap()), @@ -2977,7 +2974,7 @@ _ms(NEW_C_HEAP_ARRAY(oop, ms_size)), _array_ind_stack(NEW_C_HEAP_ARRAY(jint, ms_size)), _array_increment(MAX2(ms_size/8, 16)), - _worker_i(worker_i) { } + _worker_id(worker_id) { } ~CSetMarkOopClosure() { FREE_C_HEAP_ARRAY(oop, _ms); @@ -3022,14 +3019,14 @@ CMBitMap* _bitMap; ConcurrentMark* _cm; CSetMarkOopClosure _oop_cl; - int _worker_i; + uint _worker_id; public: - CSetMarkBitMapClosure(ConcurrentMark* cm, int ms_size, int worker_i) : + CSetMarkBitMapClosure(ConcurrentMark* cm, int ms_size, int worker_id) : _g1h(G1CollectedHeap::heap()), _bitMap(cm->nextMarkBitMap()), - _oop_cl(cm, ms_size, worker_i), - _worker_i(worker_i) { } + _oop_cl(cm, ms_size, worker_id), + _worker_id(worker_id) { } bool do_bit(size_t offset) { // convert offset into a HeapWord* @@ -3054,17 +3051,17 @@ class CompleteMarkingInCSetHRClosure: public HeapRegionClosure { CMBitMap* _bm; CSetMarkBitMapClosure _bit_cl; - int _worker_i; + uint _worker_id; enum SomePrivateConstants { MSSize = 1000 }; public: - CompleteMarkingInCSetHRClosure(ConcurrentMark* cm, int worker_i) : + CompleteMarkingInCSetHRClosure(ConcurrentMark* cm, int worker_id) : _bm(cm->nextMarkBitMap()), - _bit_cl(cm, MSSize, worker_i), - _worker_i(worker_i) { } + _bit_cl(cm, MSSize, worker_id), + _worker_id(worker_id) { } bool doHeapRegion(HeapRegion* hr) { if (hr->claimHeapRegion(HeapRegion::CompleteMarkCSetClaimValue)) { @@ -3107,9 +3104,9 @@ AbstractGangTask("Complete Mark in CSet"), _g1h(g1h), _cm(cm) { } - void work(int worker_i) { - CompleteMarkingInCSetHRClosure cmplt(_cm, worker_i); - HeapRegion* hr = _g1h->start_cset_region_for_worker(worker_i); + void work(uint worker_id) { + CompleteMarkingInCSetHRClosure cmplt(_cm, worker_id); + HeapRegion* hr = _g1h->start_cset_region_for_worker(worker_id); _g1h->collection_set_iterate_from(hr, &cmplt); } }; @@ -3123,13 +3120,12 @@ } double start = os::elapsedTime(); - int n_workers = g1h->workers()->total_workers(); - G1ParCompleteMarkInCSetTask complete_mark_task(g1h, this); assert(g1h->check_cset_heap_region_claim_values(HeapRegion::InitialClaimValue), "sanity"); if (G1CollectedHeap::use_parallel_gc_threads()) { + int n_workers = g1h->workers()->active_workers(); g1h->set_par_threads(n_workers); g1h->workers()->run_task(&complete_mark_task); g1h->set_par_threads(0); @@ -3306,13 +3302,13 @@ // the CMS bit map. Called at the first checkpoint. // We take a break if someone is trying to stop the world. -bool ConcurrentMark::do_yield_check(int worker_i) { +bool ConcurrentMark::do_yield_check(uint worker_id) { if (should_yield()) { - if (worker_i == 0) { + if (worker_id == 0) { _g1h->g1_policy()->record_concurrent_pause(); } cmThread()->yield(); - if (worker_i == 0) { + if (worker_id == 0) { _g1h->g1_policy()->record_concurrent_pause_end(); } return true;
--- a/src/share/vm/gc_implementation/g1/concurrentMark.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -374,9 +374,9 @@ protected: ConcurrentMarkThread* _cmThread; // the thread doing the work G1CollectedHeap* _g1h; // the heap. - size_t _parallel_marking_threads; // the number of marking + uint _parallel_marking_threads; // the number of marking // threads we're use - size_t _max_parallel_marking_threads; // max number of marking + uint _max_parallel_marking_threads; // max number of marking // threads we'll ever use double _sleep_factor; // how much we have to sleep, with // respect to the work we just did, to @@ -412,8 +412,8 @@ // last claimed region // marking tasks - size_t _max_task_num; // maximum task number - size_t _active_tasks; // task num currently active + uint _max_task_num; // maximum task number + uint _active_tasks; // task num currently active CMTask** _tasks; // task queue array (max_task_num len) CMTaskQueueSet* _task_queues; // task queue set ParallelTaskTerminator _terminator; // for termination @@ -492,7 +492,7 @@ // It should be called to indicate which phase we're in (concurrent // mark or remark) and how many threads are currently active. - void set_phase(size_t active_tasks, bool concurrent); + void set_phase(uint active_tasks, bool concurrent); // We do this after we're done with marking so that the marking data // structures are initialised to a sensible and predictable state. void set_non_marking_state(); @@ -505,8 +505,8 @@ } // accessor methods - size_t parallel_marking_threads() { return _parallel_marking_threads; } - size_t max_parallel_marking_threads() { return _max_parallel_marking_threads;} + uint parallel_marking_threads() { return _parallel_marking_threads; } + uint max_parallel_marking_threads() { return _max_parallel_marking_threads;} double sleep_factor() { return _sleep_factor; } double marking_task_overhead() { return _marking_task_overhead;} double cleanup_sleep_factor() { return _cleanup_sleep_factor; } @@ -514,7 +514,7 @@ HeapWord* finger() { return _finger; } bool concurrent() { return _concurrent; } - size_t active_tasks() { return _active_tasks; } + uint active_tasks() { return _active_tasks; } ParallelTaskTerminator* terminator() { return &_terminator; } // It claims the next available region to be scanned by a marking @@ -715,10 +715,10 @@ // Returns the number of GC threads to be used in a concurrent // phase based on the number of GC threads being used in a STW // phase. - size_t scale_parallel_threads(size_t n_par_threads); + uint scale_parallel_threads(uint n_par_threads); // Calculates the number of GC threads to be used in a concurrent phase. - int calc_parallel_marking_threads(); + uint calc_parallel_marking_threads(); // The following three are interaction between CM and // G1CollectedHeap @@ -873,7 +873,7 @@ return _prevMarkBitMap->isMarked(addr); } - inline bool do_yield_check(int worker_i = 0); + inline bool do_yield_check(uint worker_i = 0); inline bool should_yield(); // Called to abort the marking cycle after a Full GC takes palce.
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -1165,9 +1165,9 @@ _g1(g1) { } - void work(int i) { - RebuildRSOutOfRegionClosure rebuild_rs(_g1, i); - _g1->heap_region_par_iterate_chunked(&rebuild_rs, i, + void work(uint worker_id) { + RebuildRSOutOfRegionClosure rebuild_rs(_g1, worker_id); + _g1->heap_region_par_iterate_chunked(&rebuild_rs, worker_id, _g1->workers()->active_workers(), HeapRegion::RebuildRSClaimValue); } @@ -1294,7 +1294,7 @@ g1_policy()->stop_incremental_cset_building(); tear_down_region_sets(false /* free_list_only */); - g1_policy()->set_full_young_gcs(true); + g1_policy()->set_gcs_are_young(true); // See the comments in g1CollectedHeap.hpp and // G1CollectedHeap::ref_processing_init() about @@ -1374,7 +1374,7 @@ // Rebuild remembered sets of all regions. if (G1CollectedHeap::use_parallel_gc_threads()) { - int n_workers = + uint n_workers = AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(), workers()->active_workers(), Threads::number_of_non_daemon_threads()); @@ -1842,7 +1842,9 @@ _full_collections_completed(0), _in_cset_fast_test(NULL), _in_cset_fast_test_base(NULL), - _dirty_cards_region_list(NULL) { + _dirty_cards_region_list(NULL), + _worker_cset_start_region(NULL), + _worker_cset_start_region_time_stamp(NULL) { _g1h = this; // To catch bugs. if (_process_strong_tasks == NULL || !_process_strong_tasks->valid()) { vm_exit_during_initialization("Failed necessary allocation."); @@ -1863,12 +1865,17 @@ } _rem_set_iterator = iter_arr; + _worker_cset_start_region = NEW_C_HEAP_ARRAY(HeapRegion*, n_queues); + _worker_cset_start_region_time_stamp = NEW_C_HEAP_ARRAY(unsigned int, n_queues); + for (int i = 0; i < n_queues; i++) { RefToScanQueue* q = new RefToScanQueue(); q->initialize(); _task_queues->register_queue(i, q); } + clear_cset_start_regions(); + guarantee(_task_queues != NULL, "task_queues allocation failure."); } @@ -2411,8 +2418,11 @@ } bool G1CollectedHeap::is_in(const void* p) const { - HeapRegion* hr = _hrs.addr_to_region((HeapWord*) p); - if (hr != NULL) { + if (_g1_committed.contains(p)) { + // Given that we know that p is in the committed space, + // heap_region_containing_raw() should successfully + // return the containing region. + HeapRegion* hr = heap_region_containing_raw(p); return hr->is_in(p); } else { return _perm_gen->as_gen()->is_in(p); @@ -2509,11 +2519,11 @@ void G1CollectedHeap::heap_region_par_iterate_chunked(HeapRegionClosure* cl, - int worker, - int no_of_par_workers, + uint worker, + uint no_of_par_workers, jint claim_value) { const size_t regions = n_regions(); - const size_t max_workers = (G1CollectedHeap::use_parallel_gc_threads() ? + const uint max_workers = (G1CollectedHeap::use_parallel_gc_threads() ? no_of_par_workers : 1); assert(UseDynamicNumberOfGCThreads || @@ -2684,25 +2694,80 @@ } #endif // ASSERT -// We want the parallel threads to start their collection -// set iteration at different collection set regions to -// avoid contention. -// If we have: -// n collection set regions -// p threads -// Then thread t will start at region t * floor (n/p) - +// Clear the cached CSet starting regions and (more importantly) +// the time stamps. Called when we reset the GC time stamp. +void G1CollectedHeap::clear_cset_start_regions() { + assert(_worker_cset_start_region != NULL, "sanity"); + assert(_worker_cset_start_region_time_stamp != NULL, "sanity"); + + int n_queues = MAX2((int)ParallelGCThreads, 1); + for (int i = 0; i < n_queues; i++) { + _worker_cset_start_region[i] = NULL; + _worker_cset_start_region_time_stamp[i] = 0; + } +} + +// Given the id of a worker, obtain or calculate a suitable +// starting region for iterating over the current collection set. HeapRegion* G1CollectedHeap::start_cset_region_for_worker(int worker_i) { - HeapRegion* result = g1_policy()->collection_set(); + assert(get_gc_time_stamp() > 0, "should have been updated by now"); + + HeapRegion* result = NULL; + unsigned gc_time_stamp = get_gc_time_stamp(); + + if (_worker_cset_start_region_time_stamp[worker_i] == gc_time_stamp) { + // Cached starting region for current worker was set + // during the current pause - so it's valid. + // Note: the cached starting heap region may be NULL + // (when the collection set is empty). + result = _worker_cset_start_region[worker_i]; + assert(result == NULL || result->in_collection_set(), "sanity"); + return result; + } + + // The cached entry was not valid so let's calculate + // a suitable starting heap region for this worker. + + // We want the parallel threads to start their collection + // set iteration at different collection set regions to + // avoid contention. + // If we have: + // n collection set regions + // p threads + // Then thread t will start at region floor ((t * n) / p) + + result = g1_policy()->collection_set(); if (G1CollectedHeap::use_parallel_gc_threads()) { size_t cs_size = g1_policy()->cset_region_length(); - int n_workers = workers()->total_workers(); - size_t cs_spans = cs_size / n_workers; - size_t ind = cs_spans * worker_i; - for (size_t i = 0; i < ind; i++) { + uint active_workers = workers()->active_workers(); + assert(UseDynamicNumberOfGCThreads || + active_workers == workers()->total_workers(), + "Unless dynamic should use total workers"); + + size_t end_ind = (cs_size * worker_i) / active_workers; + size_t start_ind = 0; + + if (worker_i > 0 && + _worker_cset_start_region_time_stamp[worker_i - 1] == gc_time_stamp) { + // Previous workers starting region is valid + // so let's iterate from there + start_ind = (cs_size * (worker_i - 1)) / active_workers; + result = _worker_cset_start_region[worker_i - 1]; + } + + for (size_t i = start_ind; i < end_ind; i++) { result = result->next_in_collection_set(); } } + + // Note: the calculated starting heap region may be NULL + // (when the collection set is empty). + assert(result == NULL || result->in_collection_set(), "sanity"); + assert(_worker_cset_start_region_time_stamp[worker_i] != gc_time_stamp, + "should be updated only once per pause"); + _worker_cset_start_region[worker_i] = result; + OrderAccess::storestore(); + _worker_cset_start_region_time_stamp[worker_i] = gc_time_stamp; return result; } @@ -3010,10 +3075,10 @@ return _failures; } - void work(int worker_i) { + void work(uint worker_id) { HandleMark hm; VerifyRegionClosure blk(_allow_dirty, true, _vo); - _g1h->heap_region_par_iterate_chunked(&blk, worker_i, + _g1h->heap_region_par_iterate_chunked(&blk, worker_id, _g1h->workers()->active_workers(), HeapRegion::ParVerifyClaimValue); if (blk.failures()) { @@ -3461,20 +3526,19 @@ // for the duration of this pause. g1_policy()->decide_on_conc_mark_initiation(); - // We do not allow initial-mark to be piggy-backed on a - // partially-young GC. + // We do not allow initial-mark to be piggy-backed on a mixed GC. assert(!g1_policy()->during_initial_mark_pause() || - g1_policy()->full_young_gcs(), "sanity"); - - // We also do not allow partially-young GCs during marking. - assert(!mark_in_progress() || g1_policy()->full_young_gcs(), "sanity"); + g1_policy()->gcs_are_young(), "sanity"); + + // We also do not allow mixed GCs during marking. + assert(!mark_in_progress() || g1_policy()->gcs_are_young(), "sanity"); char verbose_str[128]; sprintf(verbose_str, "GC pause "); - if (g1_policy()->full_young_gcs()) { + if (g1_policy()->gcs_are_young()) { strcat(verbose_str, "(young)"); } else { - strcat(verbose_str, "(partial)"); + strcat(verbose_str, "(mixed)"); } if (g1_policy()->during_initial_mark_pause()) { strcat(verbose_str, " (initial-mark)"); @@ -3723,8 +3787,9 @@ double end_time_sec = os::elapsedTime(); double pause_time_ms = (end_time_sec - start_time_sec) * MILLIUNITS; g1_policy()->record_pause_time_ms(pause_time_ms); - int active_gc_threads = workers()->active_workers(); - g1_policy()->record_collection_pause_end(active_gc_threads); + int active_workers = (G1CollectedHeap::use_parallel_gc_threads() ? + workers()->active_workers() : 1); + g1_policy()->record_collection_pause_end(active_workers); MemoryService::track_memory_usage(); @@ -4660,7 +4725,7 @@ G1CollectedHeap* _g1h; RefToScanQueueSet *_queues; ParallelTaskTerminator _terminator; - int _n_workers; + uint _n_workers; Mutex _stats_lock; Mutex* stats_lock() { return &_stats_lock; } @@ -4700,18 +4765,18 @@ _n_workers = active_workers; } - void work(int i) { - if (i >= _n_workers) return; // no work needed this round + void work(uint worker_id) { + if (worker_id >= _n_workers) return; // no work needed this round double start_time_ms = os::elapsedTime() * 1000.0; - _g1h->g1_policy()->record_gc_worker_start_time(i, start_time_ms); + _g1h->g1_policy()->record_gc_worker_start_time(worker_id, start_time_ms); ResourceMark rm; HandleMark hm; ReferenceProcessor* rp = _g1h->ref_processor_stw(); - G1ParScanThreadState pss(_g1h, i); + G1ParScanThreadState pss(_g1h, worker_id); G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, rp); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, rp); G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, rp); @@ -4743,7 +4808,7 @@ scan_root_cl, &push_heap_rs_cl, scan_perm_cl, - i); + worker_id); pss.end_strong_roots(); { @@ -4752,8 +4817,8 @@ evac.do_void(); double elapsed_ms = (os::elapsedTime()-start)*1000.0; double term_ms = pss.term_time()*1000.0; - _g1h->g1_policy()->record_obj_copy_time(i, elapsed_ms-term_ms); - _g1h->g1_policy()->record_termination(i, term_ms, pss.term_attempts()); + _g1h->g1_policy()->record_obj_copy_time(worker_id, elapsed_ms-term_ms); + _g1h->g1_policy()->record_termination(worker_id, term_ms, pss.term_attempts()); } _g1h->g1_policy()->record_thread_age_table(pss.age_table()); _g1h->update_surviving_young_words(pss.surviving_young_words()+1); @@ -4763,12 +4828,12 @@ if (ParallelGCVerbose) { MutexLocker x(stats_lock()); - pss.print_termination_stats(i); + pss.print_termination_stats(worker_id); } assert(pss.refs()->is_empty(), "should be empty"); double end_time_ms = os::elapsedTime() * 1000.0; - _g1h->g1_policy()->record_gc_worker_end_time(i, end_time_ms); + _g1h->g1_policy()->record_gc_worker_end_time(worker_id, end_time_ms); } }; @@ -5026,14 +5091,14 @@ _terminator(terminator) {} - virtual void work(int i) { + virtual void work(uint worker_id) { // The reference processing task executed by a single worker. ResourceMark rm; HandleMark hm; G1STWIsAliveClosure is_alive(_g1h); - G1ParScanThreadState pss(_g1h, i); + G1ParScanThreadState pss(_g1h, worker_id); G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); @@ -5065,7 +5130,7 @@ G1ParEvacuateFollowersClosure drain_queue(_g1h, &pss, _task_queues, _terminator); // Call the reference processing task's work routine. - _proc_task.work(i, is_alive, keep_alive, drain_queue); + _proc_task.work(worker_id, is_alive, keep_alive, drain_queue); // Note we cannot assert that the refs array is empty here as not all // of the processing tasks (specifically phase2 - pp2_work) execute @@ -5100,8 +5165,8 @@ _enq_task(enq_task) { } - virtual void work(int i) { - _enq_task.work(i); + virtual void work(uint worker_id) { + _enq_task.work(worker_id); } }; @@ -5130,7 +5195,7 @@ G1CollectedHeap* _g1h; RefToScanQueueSet *_queues; ParallelTaskTerminator _terminator; - int _n_workers; + uint _n_workers; public: G1ParPreserveCMReferentsTask(G1CollectedHeap* g1h,int workers, RefToScanQueueSet *task_queues) : @@ -5141,11 +5206,11 @@ _n_workers(workers) { } - void work(int i) { + void work(uint worker_id) { ResourceMark rm; HandleMark hm; - G1ParScanThreadState pss(_g1h, i); + G1ParScanThreadState pss(_g1h, worker_id); G1ParScanHeapEvacClosure scan_evac_cl(_g1h, &pss, NULL); G1ParScanHeapEvacFailureClosure evac_failure_cl(_g1h, &pss, NULL); G1ParScanPartialArrayClosure partial_scan_cl(_g1h, &pss, NULL); @@ -5181,17 +5246,17 @@ ReferenceProcessor* rp = _g1h->ref_processor_cm(); - int limit = ReferenceProcessor::number_of_subclasses_of_ref() * rp->max_num_q(); - int stride = MIN2(MAX2(_n_workers, 1), limit); + uint limit = ReferenceProcessor::number_of_subclasses_of_ref() * rp->max_num_q(); + uint stride = MIN2(MAX2(_n_workers, 1U), limit); // limit is set using max_num_q() - which was set using ParallelGCThreads. // So this must be true - but assert just in case someone decides to // change the worker ids. - assert(0 <= i && i < limit, "sanity"); + assert(0 <= worker_id && worker_id < limit, "sanity"); assert(!rp->discovery_is_atomic(), "check this code"); // Select discovered lists [i, i+stride, i+2*stride,...,limit) - for (int idx = i; idx < limit; idx += stride) { + for (uint idx = worker_id; idx < limit; idx += stride) { DiscoveredList& ref_list = rp->discovered_refs()[idx]; DiscoveredListIterator iter(ref_list, &keep_alive, &always_alive); @@ -5245,11 +5310,13 @@ // referents points to another object which is also referenced by an // object discovered by the STW ref processor. - int active_workers = (G1CollectedHeap::use_parallel_gc_threads() ? + uint active_workers = (G1CollectedHeap::use_parallel_gc_threads() ? workers()->active_workers() : 1); - assert(active_workers == workers()->active_workers(), - "Need to reset active_workers"); + assert(!G1CollectedHeap::use_parallel_gc_threads() || + active_workers == workers()->active_workers(), + "Need to reset active_workers"); + set_par_threads(active_workers); G1ParPreserveCMReferentsTask keep_cm_referents(this, active_workers, _task_queues); @@ -5349,7 +5416,7 @@ } else { // Parallel reference enqueuing - int active_workers = (ParallelGCThreads > 0 ? workers()->active_workers() : 1); + uint active_workers = (ParallelGCThreads > 0 ? workers()->active_workers() : 1); assert(active_workers == workers()->active_workers(), "Need to reset active_workers"); assert(rp->num_q() == active_workers, "sanity"); @@ -5378,7 +5445,7 @@ concurrent_g1_refine()->set_use_cache(false); concurrent_g1_refine()->clear_hot_cache_claimed_index(); - int n_workers; + uint n_workers; if (G1CollectedHeap::use_parallel_gc_threads()) { n_workers = AdaptiveSizePolicy::calc_active_workers(workers()->total_workers(), @@ -5387,13 +5454,13 @@ assert(UseDynamicNumberOfGCThreads || n_workers == workers()->total_workers(), "If not dynamic should be using all the workers"); + workers()->set_active_workers(n_workers); set_par_threads(n_workers); } else { assert(n_par_threads() == 0, "Should be the original non-parallel value"); n_workers = 1; } - workers()->set_active_workers(n_workers); G1ParTask g1_par_task(this, _task_queues); @@ -5415,6 +5482,7 @@ workers()->run_task(&g1_par_task); } else { StrongRootsScope srs(this); + g1_par_task.set_for_termination(n_workers); g1_par_task.work(0); } @@ -5590,7 +5658,7 @@ AbstractGangTask("G1 Par Cleanup CT Task"), _ct_bs(ct_bs), _g1h(g1h) { } - void work(int i) { + void work(uint worker_id) { HeapRegion* r; while (r = _g1h->pop_dirty_cards_region()) { clear_cards(r); @@ -5663,8 +5731,8 @@ // Iterate over the dirty cards region list. G1ParCleanupCTTask cleanup_task(ct_bs, this); - if (ParallelGCThreads > 0) { - set_par_threads(workers()->total_workers()); + if (G1CollectedHeap::use_parallel_gc_threads()) { + set_par_threads(); workers()->run_task(&cleanup_task); set_par_threads(0); } else { @@ -6072,8 +6140,9 @@ void G1CollectedHeap::set_par_threads() { // Don't change the number of workers. Use the value previously set // in the workgroup. - int n_workers = workers()->active_workers(); - assert(UseDynamicNumberOfGCThreads || + assert(G1CollectedHeap::use_parallel_gc_threads(), "shouldn't be here otherwise"); + uint n_workers = workers()->active_workers(); + assert(UseDynamicNumberOfGCThreads || n_workers == workers()->total_workers(), "Otherwise should be using the total number of workers"); if (n_workers == 0) {
--- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -943,6 +943,16 @@ // discovery. G1CMIsAliveClosure _is_alive_closure_cm; + // Cache used by G1CollectedHeap::start_cset_region_for_worker(). + HeapRegion** _worker_cset_start_region; + + // Time stamp to validate the regions recorded in the cache + // used by G1CollectedHeap::start_cset_region_for_worker(). + // The heap region entry for a given worker is valid iff + // the associated time stamp value matches the current value + // of G1CollectedHeap::_gc_time_stamp. + unsigned int* _worker_cset_start_region_time_stamp; + enum G1H_process_strong_roots_tasks { G1H_PS_mark_stack_oops_do, G1H_PS_refProcessor_oops_do, @@ -985,7 +995,7 @@ // Initialize weak reference processing. virtual void ref_processing_init(); - void set_par_threads(int t) { + void set_par_threads(uint t) { SharedHeap::set_par_threads(t); // Done in SharedHeap but oddly there are // two _process_strong_tasks's in a G1CollectedHeap @@ -1030,6 +1040,9 @@ void reset_gc_time_stamp() { _gc_time_stamp = 0; OrderAccess::fence(); + // Clear the cached CSet starting regions and time stamps. + // Their validity is dependent on the GC timestamp. + clear_cset_start_regions(); } void increment_gc_time_stamp() { @@ -1196,7 +1209,7 @@ HumongousRegionSet* humongous_proxy_set, bool par); - // Returns "TRUE" iff "p" points into the allocated area of the heap. + // Returns "TRUE" iff "p" points into the committed areas of the heap. virtual bool is_in(const void* p) const; // Return "TRUE" iff the given object address is within the collection @@ -1285,8 +1298,8 @@ // chunk.) For now requires that "doHeapRegion" always returns "false", // i.e., that a closure never attempt to abort a traversal. void heap_region_par_iterate_chunked(HeapRegionClosure* blk, - int worker, - int no_of_par_workers, + uint worker, + uint no_of_par_workers, jint claim_value); // It resets all the region claim values to the default. @@ -1300,9 +1313,12 @@ bool check_cset_heap_region_claim_values(jint claim_value); #endif // ASSERT - // Given the id of a worker, calculate a suitable - // starting region for iterating over the current - // collection set. + // Clear the cached cset start regions and (more importantly) + // the time stamps. Called when we reset the GC time stamp. + void clear_cset_start_regions(); + + // Given the id of a worker, obtain or calculate a suitable + // starting region for iterating over the current collection set. HeapRegion* start_cset_region_for_worker(int worker_i); // Iterate over the regions (if any) in the current collection set.
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -50,7 +50,7 @@ }; // all the same -static double fully_young_cards_per_entry_ratio_defaults[] = { +static double young_cards_per_entry_ratio_defaults[] = { 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; @@ -136,7 +136,6 @@ _stop_world_start(0.0), _all_stop_world_times_ms(new NumberSeq()), _all_yield_times_ms(new NumberSeq()), - _using_new_ratio_calculations(false), _summary(new Summary()), @@ -168,11 +167,10 @@ _pending_card_diff_seq(new TruncatedSeq(TruncatedSeqLength)), _rs_length_diff_seq(new TruncatedSeq(TruncatedSeqLength)), _cost_per_card_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _fully_young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), - _partially_young_cards_per_entry_ratio_seq( - new TruncatedSeq(TruncatedSeqLength)), + _young_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), + _mixed_cards_per_entry_ratio_seq(new TruncatedSeq(TruncatedSeqLength)), _cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), - _partially_young_cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), + _mixed_cost_per_entry_ms_seq(new TruncatedSeq(TruncatedSeqLength)), _cost_per_byte_ms_seq(new TruncatedSeq(TruncatedSeqLength)), _cost_per_byte_ms_during_cm_seq(new TruncatedSeq(TruncatedSeqLength)), _constant_other_time_ms_seq(new TruncatedSeq(TruncatedSeqLength)), @@ -185,9 +183,9 @@ _pause_time_target_ms((double) MaxGCPauseMillis), - _full_young_gcs(true), - _full_young_pause_num(0), - _partial_young_pause_num(0), + _gcs_are_young(true), + _young_pause_num(0), + _mixed_pause_num(0), _during_marking(false), _in_marking_window(false), @@ -198,7 +196,8 @@ _young_gc_eff_seq(new TruncatedSeq(TruncatedSeqLength)), - _recent_prev_end_times_for_all_gcs_sec(new TruncatedSeq(NumPrevPausesForHeuristics)), + _recent_prev_end_times_for_all_gcs_sec( + new TruncatedSeq(NumPrevPausesForHeuristics)), _recent_avg_pause_time_ratio(0.0), @@ -206,8 +205,9 @@ _initiate_conc_mark_if_possible(false), _during_initial_mark_pause(false), - _should_revert_to_full_young_gcs(false), - _last_full_young_gc(false), + _should_revert_to_young_gcs(false), + _last_young_gc(false), + _last_gc_was_young(false), _eden_bytes_before_gc(0), _survivor_bytes_before_gc(0), @@ -229,7 +229,9 @@ _inc_cset_bytes_used_before(0), _inc_cset_max_finger(NULL), _inc_cset_recorded_rs_lengths(0), + _inc_cset_recorded_rs_lengths_diffs(0), _inc_cset_predicted_elapsed_time_ms(0.0), + _inc_cset_predicted_elapsed_time_ms_diffs(0.0), #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away #pragma warning( disable:4355 ) // 'this' : used in base member initializer list @@ -308,8 +310,8 @@ _pending_card_diff_seq->add(0.0); _rs_length_diff_seq->add(rs_length_diff_defaults[index]); _cost_per_card_ms_seq->add(cost_per_card_ms_defaults[index]); - _fully_young_cards_per_entry_ratio_seq->add( - fully_young_cards_per_entry_ratio_defaults[index]); + _young_cards_per_entry_ratio_seq->add( + young_cards_per_entry_ratio_defaults[index]); _cost_per_entry_ms_seq->add(cost_per_entry_ms_defaults[index]); _cost_per_byte_ms_seq->add(cost_per_byte_ms_defaults[index]); _constant_other_time_ms_seq->add(constant_other_time_ms_defaults[index]); @@ -406,11 +408,7 @@ initialize_all(); _collectionSetChooser = new CollectionSetChooser(); -} - -// Increment "i", mod "len" -static void inc_mod(int& i, int len) { - i++; if (i == len) i = 0; + _young_gen_sizer = new G1YoungGenSizer(); // Must be after call to initialize_flags } void G1CollectorPolicy::initialize_flags() { @@ -422,39 +420,74 @@ CollectorPolicy::initialize_flags(); } -// The easiest way to deal with the parsing of the NewSize / -// MaxNewSize / etc. parameteres is to re-use the code in the -// TwoGenerationCollectorPolicy class. This is similar to what -// ParallelScavenge does with its GenerationSizer class (see -// ParallelScavengeHeap::initialize()). We might change this in the -// future, but it's a good start. -class G1YoungGenSizer : public TwoGenerationCollectorPolicy { -private: - size_t size_to_region_num(size_t byte_size) { - return MAX2((size_t) 1, byte_size / HeapRegion::GrainBytes); +G1YoungGenSizer::G1YoungGenSizer() : _sizer_kind(SizerDefaults), _adaptive_size(true) { + assert(G1DefaultMinNewGenPercent <= G1DefaultMaxNewGenPercent, "Min larger than max"); + assert(G1DefaultMinNewGenPercent > 0 && G1DefaultMinNewGenPercent < 100, "Min out of bounds"); + assert(G1DefaultMaxNewGenPercent > 0 && G1DefaultMaxNewGenPercent < 100, "Max out of bounds"); + + if (FLAG_IS_CMDLINE(NewRatio)) { + if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { + warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); + } else { + _sizer_kind = SizerNewRatio; + _adaptive_size = false; + return; + } } -public: - G1YoungGenSizer() { - initialize_flags(); - initialize_size_info(); + if (FLAG_IS_CMDLINE(NewSize)) { + _min_desired_young_length = MAX2((size_t) 1, NewSize / HeapRegion::GrainBytes); + if (FLAG_IS_CMDLINE(MaxNewSize)) { + _max_desired_young_length = MAX2((size_t) 1, MaxNewSize / HeapRegion::GrainBytes); + _sizer_kind = SizerMaxAndNewSize; + _adaptive_size = _min_desired_young_length == _max_desired_young_length; + } else { + _sizer_kind = SizerNewSizeOnly; + } + } else if (FLAG_IS_CMDLINE(MaxNewSize)) { + _max_desired_young_length = MAX2((size_t) 1, MaxNewSize / HeapRegion::GrainBytes); + _sizer_kind = SizerMaxNewSizeOnly; } - size_t min_young_region_num() { - return size_to_region_num(_min_gen0_size); - } - size_t initial_young_region_num() { - return size_to_region_num(_initial_gen0_size); +} + +size_t G1YoungGenSizer::calculate_default_min_length(size_t new_number_of_heap_regions) { + size_t default_value = (new_number_of_heap_regions * G1DefaultMinNewGenPercent) / 100; + return MAX2((size_t)1, default_value); +} + +size_t G1YoungGenSizer::calculate_default_max_length(size_t new_number_of_heap_regions) { + size_t default_value = (new_number_of_heap_regions * G1DefaultMaxNewGenPercent) / 100; + return MAX2((size_t)1, default_value); +} + +void G1YoungGenSizer::heap_size_changed(size_t new_number_of_heap_regions) { + assert(new_number_of_heap_regions > 0, "Heap must be initialized"); + + switch (_sizer_kind) { + case SizerDefaults: + _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); + _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); + break; + case SizerNewSizeOnly: + _max_desired_young_length = calculate_default_max_length(new_number_of_heap_regions); + _max_desired_young_length = MAX2(_min_desired_young_length, _max_desired_young_length); + break; + case SizerMaxNewSizeOnly: + _min_desired_young_length = calculate_default_min_length(new_number_of_heap_regions); + _min_desired_young_length = MIN2(_min_desired_young_length, _max_desired_young_length); + break; + case SizerMaxAndNewSize: + // Do nothing. Values set on the command line, don't update them at runtime. + break; + case SizerNewRatio: + _min_desired_young_length = new_number_of_heap_regions / (NewRatio + 1); + _max_desired_young_length = _min_desired_young_length; + break; + default: + ShouldNotReachHere(); } - size_t max_young_region_num() { - return size_to_region_num(_max_gen0_size); - } -}; - -void G1CollectorPolicy::update_young_list_size_using_newratio(size_t number_of_heap_regions) { - assert(number_of_heap_regions > 0, "Heap must be initialized"); - size_t young_size = number_of_heap_regions / (NewRatio + 1); - _min_desired_young_length = young_size; - _max_desired_young_length = young_size; + + assert(_min_desired_young_length <= _max_desired_young_length, "Invalid min/max young gen size values"); } void G1CollectorPolicy::init() { @@ -465,28 +498,10 @@ initialize_gc_policy_counters(); - G1YoungGenSizer sizer; - _min_desired_young_length = sizer.min_young_region_num(); - _max_desired_young_length = sizer.max_young_region_num(); - - if (FLAG_IS_CMDLINE(NewRatio)) { - if (FLAG_IS_CMDLINE(NewSize) || FLAG_IS_CMDLINE(MaxNewSize)) { - warning("-XX:NewSize and -XX:MaxNewSize override -XX:NewRatio"); - } else { - // Treat NewRatio as a fixed size that is only recalculated when the heap size changes - update_young_list_size_using_newratio(_g1->n_regions()); - _using_new_ratio_calculations = true; - } - } - - assert(_min_desired_young_length <= _max_desired_young_length, "Invalid min/max young gen size values"); - - set_adaptive_young_list_length(_min_desired_young_length < _max_desired_young_length); if (adaptive_young_list_length()) { _young_list_fixed_length = 0; } else { - assert(_min_desired_young_length == _max_desired_young_length, "Min and max young size differ"); - _young_list_fixed_length = _min_desired_young_length; + _young_list_fixed_length = _young_gen_sizer->min_desired_young_length(); } _free_regions_at_end_of_collection = _g1->free_regions(); update_young_list_target_length(); @@ -540,11 +555,7 @@ // smaller than 1.0) we'll get 1. _reserve_regions = (size_t) ceil(reserve_regions_d); - if (_using_new_ratio_calculations) { - // -XX:NewRatio was specified so we need to update the - // young gen length when the heap size has changed. - update_young_list_size_using_newratio(new_number_of_regions); - } + _young_gen_sizer->heap_size_changed(new_number_of_regions); } size_t G1CollectorPolicy::calculate_young_list_desired_min_length( @@ -562,14 +573,14 @@ } desired_min_length += base_min_length; // make sure we don't go below any user-defined minimum bound - return MAX2(_min_desired_young_length, desired_min_length); + return MAX2(_young_gen_sizer->min_desired_young_length(), desired_min_length); } size_t G1CollectorPolicy::calculate_young_list_desired_max_length() { // Here, we might want to also take into account any additional // constraints (i.e., user-defined minimum bound). Currently, we // effectively don't set this bound. - return _max_desired_young_length; + return _young_gen_sizer->max_desired_young_length(); } void G1CollectorPolicy::update_young_list_target_length(size_t rs_lengths) { @@ -606,7 +617,7 @@ size_t young_list_target_length = 0; if (adaptive_young_list_length()) { - if (full_young_gcs()) { + if (gcs_are_young()) { young_list_target_length = calculate_young_list_target_length(rs_lengths, base_min_length, @@ -619,10 +630,10 @@ // possible to maximize how many old regions we can add to it. } } else { - if (full_young_gcs()) { + if (gcs_are_young()) { young_list_target_length = _young_list_fixed_length; } else { - // A bit arbitrary: during partially-young GCs we allocate half + // A bit arbitrary: during mixed GCs we allocate half // the young regions to try to add old regions to the CSet. young_list_target_length = _young_list_fixed_length / 2; // We choose to accept that we might go under the desired min @@ -655,7 +666,7 @@ size_t desired_min_length, size_t desired_max_length) { assert(adaptive_young_list_length(), "pre-condition"); - assert(full_young_gcs(), "only call this for fully-young GCs"); + assert(gcs_are_young(), "only call this for young GCs"); // In case some edge-condition makes the desired max length too small... if (desired_max_length <= desired_min_length) { @@ -858,12 +869,11 @@ _g1->clear_full_collection(); - // "Nuke" the heuristics that control the fully/partially young GC - // transitions and make sure we start with fully young GCs after the - // Full GC. - set_full_young_gcs(true); - _last_full_young_gc = false; - _should_revert_to_full_young_gcs = false; + // "Nuke" the heuristics that control the young/mixed GC + // transitions and make sure we start with young GCs after the Full GC. + set_gcs_are_young(true); + _last_young_gc = false; + _should_revert_to_young_gcs = false; clear_initiate_conc_mark_if_possible(); clear_during_initial_mark_pause(); _known_garbage_bytes = 0; @@ -892,7 +902,7 @@ if (PrintGCDetails) { gclog_or_tty->stamp(PrintGCTimeStamps); gclog_or_tty->print("[GC pause"); - gclog_or_tty->print(" (%s)", full_young_gcs() ? "young" : "partial"); + gclog_or_tty->print(" (%s)", gcs_are_young() ? "young" : "mixed"); } // We only need to do this here as the policy will only be applied @@ -951,7 +961,7 @@ // the evacuation pause if marking is in progress. _cur_satb_drain_time_ms = 0.0; - _last_young_gc_full = false; + _last_gc_was_young = false; // do that for any other surv rate groups _short_lived_surv_rate_group->stop_adding_regions(); @@ -988,8 +998,8 @@ } void G1CollectorPolicy::record_concurrent_mark_cleanup_completed() { - _should_revert_to_full_young_gcs = false; - _last_full_young_gc = true; + _should_revert_to_young_gcs = false; + _last_young_gc = true; _in_marking_window = false; } @@ -1153,7 +1163,7 @@ size_t marking_initiating_used_threshold = (_g1->capacity() / 100) * InitiatingHeapOccupancyPercent; - if (!_g1->mark_in_progress() && !_last_full_young_gc) { + if (!_g1->mark_in_progress() && !_last_young_gc) { assert(!last_pause_included_initial_mark, "invariant"); if (cur_used_bytes > marking_initiating_used_threshold) { if (cur_used_bytes > _prev_collection_pause_used_at_end_bytes) { @@ -1458,57 +1468,57 @@ new_in_marking_window_im = true; } - if (_last_full_young_gc) { + if (_last_young_gc) { if (!last_pause_included_initial_mark) { - ergo_verbose2(ErgoPartiallyYoungGCs, - "start partially-young GCs", + ergo_verbose2(ErgoMixedGCs, + "start mixed GCs", ergo_format_byte_perc("known garbage"), _known_garbage_bytes, _known_garbage_ratio * 100.0); - set_full_young_gcs(false); + set_gcs_are_young(false); } else { - ergo_verbose0(ErgoPartiallyYoungGCs, - "do not start partially-young GCs", + ergo_verbose0(ErgoMixedGCs, + "do not start mixed GCs", ergo_format_reason("concurrent cycle is about to start")); } - _last_full_young_gc = false; + _last_young_gc = false; } - if ( !_last_young_gc_full ) { - if (_should_revert_to_full_young_gcs) { - ergo_verbose2(ErgoPartiallyYoungGCs, - "end partially-young GCs", - ergo_format_reason("partially-young GCs end requested") + if (!_last_gc_was_young) { + if (_should_revert_to_young_gcs) { + ergo_verbose2(ErgoMixedGCs, + "end mixed GCs", + ergo_format_reason("mixed GCs end requested") ergo_format_byte_perc("known garbage"), _known_garbage_bytes, _known_garbage_ratio * 100.0); - set_full_young_gcs(true); + set_gcs_are_young(true); } else if (_known_garbage_ratio < 0.05) { - ergo_verbose3(ErgoPartiallyYoungGCs, - "end partially-young GCs", + ergo_verbose3(ErgoMixedGCs, + "end mixed GCs", ergo_format_reason("known garbage percent lower than threshold") ergo_format_byte_perc("known garbage") ergo_format_perc("threshold"), _known_garbage_bytes, _known_garbage_ratio * 100.0, 0.05 * 100.0); - set_full_young_gcs(true); + set_gcs_are_young(true); } else if (adaptive_young_list_length() && (get_gc_eff_factor() * cur_efficiency < predict_young_gc_eff())) { - ergo_verbose5(ErgoPartiallyYoungGCs, - "end partially-young GCs", + ergo_verbose5(ErgoMixedGCs, + "end mixed GCs", ergo_format_reason("current GC efficiency lower than " - "predicted fully-young GC efficiency") + "predicted young GC efficiency") ergo_format_double("GC efficiency factor") ergo_format_double("current GC efficiency") - ergo_format_double("predicted fully-young GC efficiency") + ergo_format_double("predicted young GC efficiency") ergo_format_byte_perc("known garbage"), get_gc_eff_factor(), cur_efficiency, predict_young_gc_eff(), _known_garbage_bytes, _known_garbage_ratio * 100.0); - set_full_young_gcs(true); + set_gcs_are_young(true); } } - _should_revert_to_full_young_gcs = false; - - if (_last_young_gc_full && !_during_marking) { + _should_revert_to_young_gcs = false; + + if (_last_gc_was_young && !_during_marking) { _young_gc_eff_seq->add(cur_efficiency); } @@ -1534,25 +1544,36 @@ double cost_per_entry_ms = 0.0; if (cards_scanned > 10) { cost_per_entry_ms = scan_rs_time / (double) cards_scanned; - if (_last_young_gc_full) + if (_last_gc_was_young) { _cost_per_entry_ms_seq->add(cost_per_entry_ms); - else - _partially_young_cost_per_entry_ms_seq->add(cost_per_entry_ms); + } else { + _mixed_cost_per_entry_ms_seq->add(cost_per_entry_ms); + } } if (_max_rs_lengths > 0) { double cards_per_entry_ratio = (double) cards_scanned / (double) _max_rs_lengths; - if (_last_young_gc_full) - _fully_young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); - else - _partially_young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); + if (_last_gc_was_young) { + _young_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); + } else { + _mixed_cards_per_entry_ratio_seq->add(cards_per_entry_ratio); + } } - // It turns out that, sometimes, _max_rs_lengths can get smaller - // than _recorded_rs_lengths which causes rs_length_diff to get - // very large and mess up the RSet length predictions. We'll be - // defensive until we work out why this happens. + // This is defensive. For a while _max_rs_lengths could get + // smaller than _recorded_rs_lengths which was causing + // rs_length_diff to get very large and mess up the RSet length + // predictions. The reason was unsafe concurrent updates to the + // _inc_cset_recorded_rs_lengths field which the code below guards + // against (see CR 7118202). This bug has now been fixed (see CR + // 7119027). However, I'm still worried that + // _inc_cset_recorded_rs_lengths might still end up somewhat + // inaccurate. The concurrent refinement thread calculates an + // RSet's length concurrently with other CR threads updating it + // which might cause it to calculate the length incorrectly (if, + // say, it's in mid-coarsening). So I'll leave in the defensive + // conditional below just in case. size_t rs_length_diff = 0; if (_max_rs_lengths > _recorded_rs_lengths) { rs_length_diff = _max_rs_lengths - _recorded_rs_lengths; @@ -1563,10 +1584,11 @@ double cost_per_byte_ms = 0.0; if (copied_bytes > 0) { cost_per_byte_ms = obj_copy_time / (double) copied_bytes; - if (_in_marking_window) + if (_in_marking_window) { _cost_per_byte_ms_during_cm_seq->add(cost_per_byte_ms); - else + } else { _cost_per_byte_ms_seq->add(cost_per_byte_ms); + } } double all_other_time_ms = pause_time_ms - @@ -1722,10 +1744,11 @@ size_t rs_lengths = g1h->young_list()->sampled_rs_lengths() + predict_rs_length_diff(); size_t card_num; - if (full_young_gcs()) + if (gcs_are_young()) { card_num = predict_young_card_num(rs_lengths); - else + } else { card_num = predict_non_young_card_num(rs_lengths); + } size_t young_byte_size = young_num * HeapRegion::GrainBytes; double accum_yg_surv_rate = _short_lived_surv_rate_group->accum_surv_rate(adjustment); @@ -1745,10 +1768,11 @@ G1CollectorPolicy::predict_base_elapsed_time_ms(size_t pending_cards) { size_t rs_length = predict_rs_length_diff(); size_t card_num; - if (full_young_gcs()) + if (gcs_are_young()) { card_num = predict_young_card_num(rs_length); - else + } else { card_num = predict_non_young_card_num(rs_length); + } return predict_base_elapsed_time_ms(pending_cards, card_num); } @@ -1766,10 +1790,11 @@ bool young) { size_t rs_length = hr->rem_set()->occupied(); size_t card_num; - if (full_young_gcs()) + if (gcs_are_young()) { card_num = predict_young_card_num(rs_length); - else + } else { card_num = predict_non_young_card_num(rs_length); + } size_t bytes_to_copy = predict_bytes_to_copy(hr); double region_elapsed_time_ms = @@ -1817,14 +1842,14 @@ // I don't think we need to do this when in young GC mode since // marking will be initiated next time we hit the soft limit anyway... if (predicted_time_ms > _expensive_region_limit_ms) { - ergo_verbose2(ErgoPartiallyYoungGCs, - "request partially-young GCs end", + ergo_verbose2(ErgoMixedGCs, + "request mixed GCs end", ergo_format_reason("predicted region time higher than threshold") ergo_format_ms("predicted region time") ergo_format_ms("threshold"), predicted_time_ms, _expensive_region_limit_ms); - // no point in doing another partial one - _should_revert_to_full_young_gcs = true; + // no point in doing another mixed GC + _should_revert_to_young_gcs = true; } } @@ -2033,8 +2058,8 @@ print_summary_sd(0, "Total", _all_pause_times_ms); gclog_or_tty->print_cr(""); gclog_or_tty->print_cr(""); - gclog_or_tty->print_cr(" Full Young GC Pauses: %8d", _full_young_pause_num); - gclog_or_tty->print_cr(" Partial Young GC Pauses: %8d", _partial_young_pause_num); + gclog_or_tty->print_cr(" Young GC Pauses: %8d", _young_pause_num); + gclog_or_tty->print_cr(" Mixed GC Pauses: %8d", _mixed_pause_num); gclog_or_tty->print_cr(""); gclog_or_tty->print_cr("EVACUATION PAUSES"); @@ -2188,11 +2213,11 @@ // initiate a new cycle. set_during_initial_mark_pause(); - // We do not allow non-full young GCs during marking. - if (!full_young_gcs()) { - set_full_young_gcs(true); - ergo_verbose0(ErgoPartiallyYoungGCs, - "end partially-young GCs", + // We do not allow mixed GCs during marking. + if (!gcs_are_young()) { + set_gcs_are_young(true); + ergo_verbose0(ErgoMixedGCs, + "end mixed GCs", ergo_format_reason("concurrent cycle is about to start")); } @@ -2315,17 +2340,19 @@ _g1(G1CollectedHeap::heap()) {} - void work(int i) { - ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, _chunk_size, i); + void work(uint worker_id) { + ParKnownGarbageHRClosure parKnownGarbageCl(_hrSorted, + _chunk_size, + worker_id); // Back to zero for the claim value. - _g1->heap_region_par_iterate_chunked(&parKnownGarbageCl, i, + _g1->heap_region_par_iterate_chunked(&parKnownGarbageCl, worker_id, _g1->workers()->active_workers(), HeapRegion::InitialClaimValue); jint regions_added = parKnownGarbageCl.marked_regions_added(); _hrSorted->incNumMarkedHeapRegions(regions_added); if (G1PrintParCleanupStats) { gclog_or_tty->print_cr(" Thread %d called %d times, added %d regions to list.", - i, parKnownGarbageCl.invokes(), regions_added); + worker_id, parKnownGarbageCl.invokes(), regions_added); } } }; @@ -2430,10 +2457,45 @@ _inc_cset_max_finger = 0; _inc_cset_recorded_rs_lengths = 0; - _inc_cset_predicted_elapsed_time_ms = 0; + _inc_cset_recorded_rs_lengths_diffs = 0; + _inc_cset_predicted_elapsed_time_ms = 0.0; + _inc_cset_predicted_elapsed_time_ms_diffs = 0.0; _inc_cset_build_state = Active; } +void G1CollectorPolicy::finalize_incremental_cset_building() { + assert(_inc_cset_build_state == Active, "Precondition"); + assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); + + // The two "main" fields, _inc_cset_recorded_rs_lengths and + // _inc_cset_predicted_elapsed_time_ms, are updated by the thread + // that adds a new region to the CSet. Further updates by the + // concurrent refinement thread that samples the young RSet lengths + // are accumulated in the *_diffs fields. Here we add the diffs to + // the "main" fields. + + if (_inc_cset_recorded_rs_lengths_diffs >= 0) { + _inc_cset_recorded_rs_lengths += _inc_cset_recorded_rs_lengths_diffs; + } else { + // This is defensive. The diff should in theory be always positive + // as RSets can only grow between GCs. However, given that we + // sample their size concurrently with other threads updating them + // it's possible that we might get the wrong size back, which + // could make the calculations somewhat inaccurate. + size_t diffs = (size_t) (-_inc_cset_recorded_rs_lengths_diffs); + if (_inc_cset_recorded_rs_lengths >= diffs) { + _inc_cset_recorded_rs_lengths -= diffs; + } else { + _inc_cset_recorded_rs_lengths = 0; + } + } + _inc_cset_predicted_elapsed_time_ms += + _inc_cset_predicted_elapsed_time_ms_diffs; + + _inc_cset_recorded_rs_lengths_diffs = 0; + _inc_cset_predicted_elapsed_time_ms_diffs = 0.0; +} + void G1CollectorPolicy::add_to_incremental_cset_info(HeapRegion* hr, size_t rs_length) { // This routine is used when: // * adding survivor regions to the incremental cset at the end of an @@ -2449,10 +2511,8 @@ double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, true); size_t used_bytes = hr->used(); - _inc_cset_recorded_rs_lengths += rs_length; _inc_cset_predicted_elapsed_time_ms += region_elapsed_time_ms; - _inc_cset_bytes_used_before += used_bytes; // Cache the values we have added to the aggregated informtion @@ -2463,37 +2523,33 @@ hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms); } -void G1CollectorPolicy::remove_from_incremental_cset_info(HeapRegion* hr) { - // This routine is currently only called as part of the updating of - // existing policy information for regions in the incremental cset that - // is performed by the concurrent refine thread(s) as part of young list - // RSet sampling. Therefore we should not be at a safepoint. - - assert(!SafepointSynchronize::is_at_safepoint(), "should not be at safepoint"); - assert(hr->is_young(), "it should be"); - - size_t used_bytes = hr->used(); - size_t old_rs_length = hr->recorded_rs_length(); +void G1CollectorPolicy::update_incremental_cset_info(HeapRegion* hr, + size_t new_rs_length) { + // Update the CSet information that is dependent on the new RS length + assert(hr->is_young(), "Precondition"); + assert(!SafepointSynchronize::is_at_safepoint(), + "should not be at a safepoint"); + + // We could have updated _inc_cset_recorded_rs_lengths and + // _inc_cset_predicted_elapsed_time_ms directly but we'd need to do + // that atomically, as this code is executed by a concurrent + // refinement thread, potentially concurrently with a mutator thread + // allocating a new region and also updating the same fields. To + // avoid the atomic operations we accumulate these updates on two + // separate fields (*_diffs) and we'll just add them to the "main" + // fields at the start of a GC. + + ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length(); + ssize_t rs_lengths_diff = (ssize_t) new_rs_length - old_rs_length; + _inc_cset_recorded_rs_lengths_diffs += rs_lengths_diff; + double old_elapsed_time_ms = hr->predicted_elapsed_time_ms(); - - // Subtract the old recorded/predicted policy information for - // the given heap region from the collection set info. - _inc_cset_recorded_rs_lengths -= old_rs_length; - _inc_cset_predicted_elapsed_time_ms -= old_elapsed_time_ms; - - _inc_cset_bytes_used_before -= used_bytes; - - // Clear the values cached in the heap region - hr->set_recorded_rs_length(0); - hr->set_predicted_elapsed_time_ms(0); -} - -void G1CollectorPolicy::update_incremental_cset_info(HeapRegion* hr, size_t new_rs_length) { - // Update the collection set information that is dependent on the new RS length - assert(hr->is_young(), "Precondition"); - - remove_from_incremental_cset_info(hr); - add_to_incremental_cset_info(hr, new_rs_length); + double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, true); + double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms; + _inc_cset_predicted_elapsed_time_ms_diffs += elapsed_ms_diff; + + hr->set_recorded_rs_length(new_rs_length); + hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms); } void G1CollectorPolicy::add_region_to_incremental_cset_common(HeapRegion* hr) { @@ -2585,6 +2641,7 @@ double non_young_start_time_sec = os::elapsedTime(); YoungList* young_list = _g1->young_list(); + finalize_incremental_cset_building(); guarantee(target_pause_time_ms > 0.0, err_msg("target_pause_time_ms = %1.6lf should be positive", @@ -2623,12 +2680,12 @@ double young_start_time_sec = os::elapsedTime(); _collection_set_bytes_used_before = 0; - _last_young_gc_full = full_young_gcs() ? true : false; - - if (_last_young_gc_full) { - ++_full_young_pause_num; + _last_gc_was_young = gcs_are_young() ? true : false; + + if (_last_gc_was_young) { + ++_young_pause_num; } else { - ++_partial_young_pause_num; + ++_mixed_pause_num; } // The young list is laid with the survivor regions from the previous @@ -2675,7 +2732,7 @@ // We are doing young collections so reset this. non_young_start_time_sec = young_end_time_sec; - if (!full_young_gcs()) { + if (!gcs_are_young()) { bool should_continue = true; NumberSeq seq; double avg_prediction = 100000000000000000.0; // something very large @@ -2732,14 +2789,14 @@ } while (should_continue); if (!adaptive_young_list_length() && - cset_region_length() < _young_list_fixed_length) { + cset_region_length() < _young_list_fixed_length) { ergo_verbose2(ErgoCSetConstruction, - "request partially-young GCs end", + "request mixed GCs end", ergo_format_reason("CSet length lower than target") ergo_format_region("CSet") ergo_format_region("young target"), cset_region_length(), _young_list_fixed_length); - _should_revert_to_full_young_gcs = true; + _should_revert_to_young_gcs = true; } ergo_verbose2(ErgoCSetConstruction | ErgoHigh,
--- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -83,6 +83,72 @@ virtual MainBodySummary* main_body_summary() { return this; } }; +// 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 +// G1DefaultMinNewGenPercent and G1DefaultMaxNewGenPercent of the +// heap size. This means that every time the heap size changes the +// limits for the young gen size will be updated. +// +// If only -XX:NewSize is set we should use the specified value as the +// minimum size for young gen. Still using G1DefaultMaxNewGenPercent +// 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 G1DefaultMinNewGenPercent +// 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 +// everytime 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 { +private: + enum SizerKind { + SizerDefaults, + SizerNewSizeOnly, + SizerMaxNewSizeOnly, + SizerMaxAndNewSize, + SizerNewRatio + }; + SizerKind _sizer_kind; + size_t _min_desired_young_length; + size_t _max_desired_young_length; + bool _adaptive_size; + size_t calculate_default_min_length(size_t new_number_of_heap_regions); + size_t calculate_default_max_length(size_t new_number_of_heap_regions); + +public: + G1YoungGenSizer(); + void heap_size_changed(size_t new_number_of_heap_regions); + size_t min_desired_young_length() { + return _min_desired_young_length; + } + size_t max_desired_young_length() { + return _max_desired_young_length; + } + bool adaptive_young_list_length() { + return _adaptive_size; + } +}; + class G1CollectorPolicy: public CollectorPolicy { private: // either equal to the number of parallel threads, if ParallelGCThreads @@ -164,12 +230,9 @@ // times for a given worker thread. double* _par_last_gc_worker_other_times_ms; - // indicates whether we are in full young or partially young GC mode - bool _full_young_gcs; + // indicates whether we are in young or mixed GC mode + bool _gcs_are_young; - // if true, then it tries to dynamically adjust the length of the - // young list - bool _adaptive_young_list_length; size_t _young_list_target_length; size_t _young_list_fixed_length; size_t _prev_eden_capacity; // used for logging @@ -178,10 +241,10 @@ // locker is active. This should be >= _young_list_target_length; size_t _young_list_max_length; - bool _last_young_gc_full; + bool _last_gc_was_young; - unsigned _full_young_pause_num; - unsigned _partial_young_pause_num; + unsigned _young_pause_num; + unsigned _mixed_pause_num; bool _during_marking; bool _in_marking_window; @@ -211,10 +274,10 @@ TruncatedSeq* _pending_card_diff_seq; TruncatedSeq* _rs_length_diff_seq; TruncatedSeq* _cost_per_card_ms_seq; - TruncatedSeq* _fully_young_cards_per_entry_ratio_seq; - TruncatedSeq* _partially_young_cards_per_entry_ratio_seq; + TruncatedSeq* _young_cards_per_entry_ratio_seq; + TruncatedSeq* _mixed_cards_per_entry_ratio_seq; TruncatedSeq* _cost_per_entry_ms_seq; - TruncatedSeq* _partially_young_cost_per_entry_ms_seq; + TruncatedSeq* _mixed_cost_per_entry_ms_seq; TruncatedSeq* _cost_per_byte_ms_seq; TruncatedSeq* _constant_other_time_ms_seq; TruncatedSeq* _young_other_cost_per_region_ms_seq; @@ -227,9 +290,7 @@ TruncatedSeq* _young_gc_eff_seq; - bool _using_new_ratio_calculations; - size_t _min_desired_young_length; // as set on the command line or default calculations - size_t _max_desired_young_length; // as set on the command line or default calculations + G1YoungGenSizer* _young_gen_sizer; size_t _eden_cset_region_length; size_t _survivor_cset_region_length; @@ -322,20 +383,22 @@ size_t predict_pending_card_diff() { double prediction = get_new_neg_prediction(_pending_card_diff_seq); - if (prediction < 0.00001) + if (prediction < 0.00001) { return 0; - else + } else { return (size_t) prediction; + } } size_t predict_pending_cards() { size_t max_pending_card_num = _g1->max_pending_card_num(); size_t diff = predict_pending_card_diff(); size_t prediction; - if (diff > max_pending_card_num) + if (diff > max_pending_card_num) { prediction = max_pending_card_num; - else + } else { prediction = max_pending_card_num - diff; + } return prediction; } @@ -356,57 +419,62 @@ return (double) pending_cards * predict_cost_per_card_ms(); } - double predict_fully_young_cards_per_entry_ratio() { - return get_new_prediction(_fully_young_cards_per_entry_ratio_seq); + double predict_young_cards_per_entry_ratio() { + return get_new_prediction(_young_cards_per_entry_ratio_seq); } - double predict_partially_young_cards_per_entry_ratio() { - if (_partially_young_cards_per_entry_ratio_seq->num() < 2) - return predict_fully_young_cards_per_entry_ratio(); - else - return get_new_prediction(_partially_young_cards_per_entry_ratio_seq); + double predict_mixed_cards_per_entry_ratio() { + if (_mixed_cards_per_entry_ratio_seq->num() < 2) { + return predict_young_cards_per_entry_ratio(); + } else { + return get_new_prediction(_mixed_cards_per_entry_ratio_seq); + } } size_t predict_young_card_num(size_t rs_length) { return (size_t) ((double) rs_length * - predict_fully_young_cards_per_entry_ratio()); + predict_young_cards_per_entry_ratio()); } size_t predict_non_young_card_num(size_t rs_length) { return (size_t) ((double) rs_length * - predict_partially_young_cards_per_entry_ratio()); + predict_mixed_cards_per_entry_ratio()); } double predict_rs_scan_time_ms(size_t card_num) { - if (full_young_gcs()) + if (gcs_are_young()) { return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); - else - return predict_partially_young_rs_scan_time_ms(card_num); + } else { + return predict_mixed_rs_scan_time_ms(card_num); + } } - double predict_partially_young_rs_scan_time_ms(size_t card_num) { - if (_partially_young_cost_per_entry_ms_seq->num() < 3) + double predict_mixed_rs_scan_time_ms(size_t card_num) { + if (_mixed_cost_per_entry_ms_seq->num() < 3) { return (double) card_num * get_new_prediction(_cost_per_entry_ms_seq); - else - return (double) card_num * - get_new_prediction(_partially_young_cost_per_entry_ms_seq); + } else { + return (double) (card_num * + get_new_prediction(_mixed_cost_per_entry_ms_seq)); + } } double predict_object_copy_time_ms_during_cm(size_t bytes_to_copy) { - if (_cost_per_byte_ms_during_cm_seq->num() < 3) - return 1.1 * (double) bytes_to_copy * - get_new_prediction(_cost_per_byte_ms_seq); - else + if (_cost_per_byte_ms_during_cm_seq->num() < 3) { + return (1.1 * (double) bytes_to_copy) * + get_new_prediction(_cost_per_byte_ms_seq); + } else { return (double) bytes_to_copy * - get_new_prediction(_cost_per_byte_ms_during_cm_seq); + get_new_prediction(_cost_per_byte_ms_during_cm_seq); + } } double predict_object_copy_time_ms(size_t bytes_to_copy) { - if (_in_marking_window && !_in_marking_window_im) + if (_in_marking_window && !_in_marking_window_im) { return predict_object_copy_time_ms_during_cm(bytes_to_copy); - else + } else { return (double) bytes_to_copy * - get_new_prediction(_cost_per_byte_ms_seq); + get_new_prediction(_cost_per_byte_ms_seq); + } } double predict_constant_other_time_ms() { @@ -414,15 +482,13 @@ } double predict_young_other_time_ms(size_t young_num) { - return - (double) young_num * - get_new_prediction(_young_other_cost_per_region_ms_seq); + return (double) young_num * + get_new_prediction(_young_other_cost_per_region_ms_seq); } double predict_non_young_other_time_ms(size_t non_young_num) { - return - (double) non_young_num * - get_new_prediction(_non_young_other_cost_per_region_ms_seq); + return (double) non_young_num * + get_new_prediction(_non_young_other_cost_per_region_ms_seq); } void check_if_region_is_too_expensive(double predicted_time_ms); @@ -456,7 +522,7 @@ double predict_survivor_regions_evac_time(); void cset_regions_freed() { - bool propagate = _last_young_gc_full && !_in_marking_window; + bool propagate = _last_gc_was_young && !_in_marking_window; _short_lived_surv_rate_group->all_surviving_words_recorded(propagate); _survivor_surv_rate_group->all_surviving_words_recorded(propagate); // also call it on any more surv rate groups @@ -583,16 +649,29 @@ // Used to record the highest end of heap region in collection set HeapWord* _inc_cset_max_finger; - // The RSet lengths recorded for regions in the collection set - // (updated by the periodic sampling of the regions in the - // young list/collection set). + // The RSet lengths recorded for regions in the CSet. It is updated + // by the thread that adds a new region to the CSet. We assume that + // only one thread can be allocating a new CSet region (currently, + // it does so after taking the Heap_lock) hence no need to + // synchronize updates to this field. size_t _inc_cset_recorded_rs_lengths; - // The predicted elapsed time it will take to collect the regions - // in the collection set (updated by the periodic sampling of the - // regions in the young list/collection set). + // A concurrent refinement thread periodcially samples the young + // region RSets and needs to update _inc_cset_recorded_rs_lengths as + // the RSets grow. Instead of having to syncronize updates to that + // field we accumulate them in this field and add it to + // _inc_cset_recorded_rs_lengths_diffs at the start of a GC. + ssize_t _inc_cset_recorded_rs_lengths_diffs; + + // The predicted elapsed time it will take to collect the regions in + // the CSet. This is updated by the thread that adds a new region to + // the CSet. See the comment for _inc_cset_recorded_rs_lengths about + // MT-safety assumptions. double _inc_cset_predicted_elapsed_time_ms; + // See the comment for _inc_cset_recorded_rs_lengths_diffs. + double _inc_cset_predicted_elapsed_time_ms_diffs; + // Stash a pointer to the g1 heap. G1CollectedHeap* _g1; @@ -628,8 +707,8 @@ // initial-mark work. volatile bool _during_initial_mark_pause; - bool _should_revert_to_full_young_gcs; - bool _last_full_young_gc; + bool _should_revert_to_young_gcs; + bool _last_young_gc; // This set of variables tracks the collector efficiency, in order to // determine whether we should initiate a new marking. @@ -677,8 +756,6 @@ // Count the number of bytes used in the CS. void count_CS_bytes_used(); - void update_young_list_size_using_newratio(size_t number_of_heap_regions); - public: G1CollectorPolicy(); @@ -705,8 +782,6 @@ // This should be called after the heap is resized. void record_new_heap_size(size_t new_number_of_regions); -public: - void init(); // Create jstat counters for the policy. @@ -889,6 +964,10 @@ // Initialize incremental collection set info. void start_incremental_cset_building(); + // Perform any final calculations on the incremental CSet fields + // before we can use them. + void finalize_incremental_cset_building(); + void clear_incremental_cset() { _inc_cset_head = NULL; _inc_cset_tail = NULL; @@ -897,10 +976,9 @@ // Stop adding regions to the incremental collection set void stop_incremental_cset_building() { _inc_cset_build_state = Inactive; } - // Add/remove information about hr to the aggregated information - // for the incrementally built collection set. + // Add information about hr to the aggregated information for the + // incrementally built collection set. void add_to_incremental_cset_info(HeapRegion* hr, size_t rs_length); - void remove_from_incremental_cset_info(HeapRegion* hr); // Update information about hr in the aggregated information for // the incrementally built collection set. @@ -985,18 +1063,15 @@ return _young_list_max_length; } - bool full_young_gcs() { - return _full_young_gcs; + bool gcs_are_young() { + return _gcs_are_young; } - void set_full_young_gcs(bool full_young_gcs) { - _full_young_gcs = full_young_gcs; + void set_gcs_are_young(bool gcs_are_young) { + _gcs_are_young = gcs_are_young; } bool adaptive_young_list_length() { - return _adaptive_young_list_length; - } - void set_adaptive_young_list_length(bool adaptive_young_list_length) { - _adaptive_young_list_length = adaptive_young_list_length; + return _young_gen_sizer->adaptive_young_list_length(); } inline double get_gc_eff_factor() {
--- a/src/share/vm/gc_implementation/g1/g1ErgoVerbose.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1ErgoVerbose.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -52,14 +52,13 @@ const char* G1ErgoVerbose::to_string(int tag) { ErgoHeuristic n = extract_heuristic(tag); switch (n) { - case ErgoHeapSizing: return "Heap Sizing"; - case ErgoCSetConstruction: return "CSet Construction"; - case ErgoConcCycles: return "Concurrent Cycles"; - case ErgoPartiallyYoungGCs: return "Partially-Young GCs"; + case ErgoHeapSizing: return "Heap Sizing"; + case ErgoCSetConstruction: return "CSet Construction"; + case ErgoConcCycles: return "Concurrent Cycles"; + case ErgoMixedGCs: return "Mixed GCs"; default: ShouldNotReachHere(); // Keep the Windows compiler happy return NULL; } } -
--- a/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -69,7 +69,7 @@ ErgoHeapSizing = 0, ErgoCSetConstruction, ErgoConcCycles, - ErgoPartiallyYoungGCs, + ErgoMixedGCs, ErgoHeuristicNum } ErgoHeuristic;
--- a/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -119,7 +119,7 @@ G1CollectedHeap* _g1h; // jstat performance counters - // incremental collections both fully and partially young + // incremental collections both young and mixed CollectorCounters* _incremental_collection_counters; // full stop-the-world collections CollectorCounters* _full_collection_counters;
--- a/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -558,11 +558,11 @@ } void G1RemSet::scrub_par(BitMap* region_bm, BitMap* card_bm, - int worker_num, int claim_val) { + uint worker_num, int claim_val) { ScrubRSClosure scrub_cl(region_bm, card_bm); _g1->heap_region_par_iterate_chunked(&scrub_cl, worker_num, - (int) n_workers(), + n_workers(), claim_val); }
--- a/src/share/vm/gc_implementation/g1/g1RemSet.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -40,7 +40,7 @@ protected: G1CollectedHeap* _g1; unsigned _conc_refine_cards; - size_t n_workers(); + uint n_workers(); protected: enum SomePrivateConstants { @@ -122,7 +122,7 @@ // parallel thread id of the current thread, and "claim_val" is the // value that should be used to claim heap regions. void scrub_par(BitMap* region_bm, BitMap* card_bm, - int worker_num, int claim_val); + uint worker_num, int claim_val); // Refine the card corresponding to "card_ptr". If "sts" is non-NULL, // join and leave around parts that must be atomic wrt GC. (NULL means
--- a/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -29,7 +29,7 @@ #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "oops/oop.inline.hpp" -inline size_t G1RemSet::n_workers() { +inline uint G1RemSet::n_workers() { if (_g1->workers() != NULL) { return _g1->workers()->total_workers(); } else {
--- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -289,7 +289,15 @@ \ develop(uintx, G1ConcMarkForceOverflow, 0, \ "The number of times we'll force an overflow during " \ - "concurrent marking") + "concurrent marking") \ + \ + develop(uintx, G1DefaultMinNewGenPercent, 20, \ + "Percentage (0-100) of the heap size to use as minimum " \ + "young gen size.") \ + \ + develop(uintx, G1DefaultMaxNewGenPercent, 50, \ + "Percentage (0-100) of the heap size to use as maximum " \ + "young gen size.") G1_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG, DECLARE_MANAGEABLE_FLAG, DECLARE_PRODUCT_RW_FLAG)
--- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -94,7 +94,8 @@ #endif // PRODUCT } - template <class T> void do_oop_work(T* p) { + template <class T> + void do_oop_work(T* p) { assert(_containing_obj != NULL, "Precondition"); assert(!_g1h->is_obj_dead_cond(_containing_obj, _vo), "Precondition"); @@ -102,8 +103,10 @@ if (!oopDesc::is_null(heap_oop)) { oop obj = oopDesc::decode_heap_oop_not_null(heap_oop); bool failed = false; - if (!_g1h->is_in_closed_subset(obj) || - _g1h->is_obj_dead_cond(obj, _vo)) { + if (!_g1h->is_in_closed_subset(obj) || _g1h->is_obj_dead_cond(obj, _vo)) { + MutexLockerEx x(ParGCRareEvent_lock, + Mutex::_no_safepoint_check_flag); + if (!_failures) { gclog_or_tty->print_cr(""); gclog_or_tty->print_cr("----------"); @@ -133,6 +136,7 @@ print_object(gclog_or_tty, obj); } gclog_or_tty->print_cr("----------"); + gclog_or_tty->flush(); _failures = true; failed = true; _n_failures++; @@ -155,6 +159,9 @@ cv_field == dirty : cv_obj == dirty || cv_field == dirty)); if (is_bad) { + MutexLockerEx x(ParGCRareEvent_lock, + Mutex::_no_safepoint_check_flag); + if (!_failures) { gclog_or_tty->print_cr(""); gclog_or_tty->print_cr("----------"); @@ -174,6 +181,7 @@ gclog_or_tty->print_cr("Obj head CTE = %d, field CTE = %d.", cv_obj, cv_field); gclog_or_tty->print_cr("----------"); + gclog_or_tty->flush(); _failures = true; if (!failed) _n_failures++; }
--- a/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -56,14 +56,14 @@ lowest_non_clean_base_chunk_index, lowest_non_clean_chunk_size); - int n_strides = n_threads * ParGCStridesPerThread; + uint n_strides = n_threads * ParGCStridesPerThread; SequentialSubTasksDone* pst = sp->par_seq_tasks(); // Sets the condition for completion of the subtask (how many threads // need to finish in order to be done). pst->set_n_threads(n_threads); pst->set_n_tasks(n_strides); - int stride = 0; + uint stride = 0; while (!pst->is_task_claimed(/* reference */ stride)) { process_stride(sp, mr, stride, n_strides, cl, ct, lowest_non_clean,
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -590,7 +590,7 @@ // called after a task is started. So "i" is based on // first-come-first-served. -void ParNewGenTask::work(int i) { +void ParNewGenTask::work(uint worker_id) { GenCollectedHeap* gch = GenCollectedHeap::heap(); // Since this is being done in a separate thread, need new resource // and handle marks. @@ -601,8 +601,8 @@ Generation* old_gen = gch->next_gen(_gen); - ParScanThreadState& par_scan_state = _state_set->thread_state(i); - assert(_state_set->is_valid(i), "Should not have been called"); + ParScanThreadState& par_scan_state = _state_set->thread_state(worker_id); + assert(_state_set->is_valid(worker_id), "Should not have been called"); par_scan_state.set_young_old_boundary(_young_old_boundary); @@ -755,7 +755,7 @@ ParScanThreadStateSet& state_set); private: - virtual void work(int i); + virtual void work(uint worker_id); virtual void set_for_termination(int active_workers) { _state_set.terminator()->reset_for_reuse(active_workers); } @@ -781,13 +781,13 @@ { } -void ParNewRefProcTaskProxy::work(int i) +void ParNewRefProcTaskProxy::work(uint worker_id) { ResourceMark rm; HandleMark hm; - ParScanThreadState& par_scan_state = _state_set.thread_state(i); + ParScanThreadState& par_scan_state = _state_set.thread_state(worker_id); par_scan_state.set_young_old_boundary(_young_old_boundary); - _task.work(i, par_scan_state.is_alive_closure(), + _task.work(worker_id, par_scan_state.is_alive_closure(), par_scan_state.keep_alive_closure(), par_scan_state.evacuate_followers_closure()); } @@ -802,9 +802,9 @@ _task(task) { } - virtual void work(int i) + virtual void work(uint worker_id) { - _task.work(i); + _task.work(worker_id); } };
--- a/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -239,7 +239,7 @@ HeapWord* young_old_boundary() { return _young_old_boundary; } - void work(int i); + void work(uint worker_id); // Reset the terminator in ParScanThreadStateSet for // "active_workers" threads.
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -672,15 +672,20 @@ } jlong PSMarkSweep::millis_since_last_gc() { - jlong ret_val = os::javaTimeMillis() - _time_of_last_gc; + // We need a monotonically non-deccreasing time in ms but + // os::javaTimeMillis() does not guarantee monotonicity. + jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; + jlong ret_val = now - _time_of_last_gc; // XXX See note in genCollectedHeap::millis_since_last_gc(). if (ret_val < 0) { - NOT_PRODUCT(warning("time warp: %d", ret_val);) + NOT_PRODUCT(warning("time warp: "INT64_FORMAT, ret_val);) return 0; } return ret_val; } void PSMarkSweep::reset_millis_since_last_gc() { - _time_of_last_gc = os::javaTimeMillis(); + // We need a monotonically non-deccreasing time in ms but + // os::javaTimeMillis() does not guarantee monotonicity. + _time_of_last_gc = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; }
--- a/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -3398,17 +3398,22 @@ } jlong PSParallelCompact::millis_since_last_gc() { - jlong ret_val = os::javaTimeMillis() - _time_of_last_gc; + // We need a monotonically non-deccreasing time in ms but + // os::javaTimeMillis() does not guarantee monotonicity. + jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; + jlong ret_val = now - _time_of_last_gc; // XXX See note in genCollectedHeap::millis_since_last_gc(). if (ret_val < 0) { - NOT_PRODUCT(warning("time warp: %d", ret_val);) + NOT_PRODUCT(warning("time warp: "INT64_FORMAT, ret_val);) return 0; } return ret_val; } void PSParallelCompact::reset_millis_since_last_gc() { - _time_of_last_gc = os::javaTimeMillis(); + // We need a monotonically non-deccreasing time in ms but + // os::javaTimeMillis() does not guarantee monotonicity. + _time_of_last_gc = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; } ParMarkBitMap::IterationStatus MoveAndUpdateClosure::copy_until_full()
--- a/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/shared/mutableNUMASpace.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -282,7 +282,7 @@ // large page can be broken down if we require small pages. os::realign_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size()); // Then we uncommit the pages in the range. - os::free_memory((char*)aligned_region.start(), aligned_region.byte_size()); + os::free_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size()); // And make them local/first-touch biased. os::numa_make_local((char*)aligned_region.start(), aligned_region.byte_size(), lgrp_id); } @@ -297,7 +297,7 @@ assert((intptr_t)aligned_region.start() % page_size() == 0 && (intptr_t)aligned_region.byte_size() % page_size() == 0, "Bad alignment"); assert(region().contains(aligned_region), "Sanity"); - os::free_memory((char*)aligned_region.start(), aligned_region.byte_size()); + os::free_memory((char*)aligned_region.start(), aligned_region.byte_size(), page_size()); } } @@ -954,7 +954,7 @@ if (e != scan_end) { if ((page_expected.size != page_size || page_expected.lgrp_id != lgrp_id()) && page_expected.size != 0) { - os::free_memory(s, pointer_delta(e, s, sizeof(char))); + os::free_memory(s, pointer_delta(e, s, sizeof(char)), page_size); } page_expected = page_found; }
--- a/src/share/vm/gc_implementation/shared/mutableSpace.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_implementation/shared/mutableSpace.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -51,7 +51,7 @@ size_t size = pointer_delta(end, start, sizeof(char)); if (clear_space) { // Prefer page reallocation to migration. - os::free_memory((char*)start, size); + os::free_memory((char*)start, size, page_size); } os::numa_make_global((char*)start, size); }
--- a/src/share/vm/gc_interface/collectedHeap.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_interface/collectedHeap.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -471,3 +471,26 @@ return mirror; } + +/////////////// Unit tests /////////////// + +#ifndef PRODUCT +void CollectedHeap::test_is_in() { + CollectedHeap* heap = Universe::heap(); + + // Test that NULL is not in the heap. + assert(!heap->is_in(NULL), "NULL is unexpectedly in the heap"); + + // Test that a pointer to before the heap start is reported as outside the heap. + assert(heap->_reserved.start() >= (void*)MinObjAlignment, "sanity"); + void* before_heap = (void*)((intptr_t)heap->_reserved.start() - MinObjAlignment); + assert(!heap->is_in(before_heap), + err_msg("before_heap: " PTR_FORMAT " is unexpectedly in the heap", before_heap)); + + // Test that a pointer to after the heap end is reported as outside the heap. + assert(heap->_reserved.end() <= (void*)(uintptr_t(-1) - (uint)MinObjAlignment), "sanity"); + void* after_heap = (void*)((intptr_t)heap->_reserved.end() + MinObjAlignment); + assert(!heap->is_in(after_heap), + err_msg("after_heap: " PTR_FORMAT " is unexpectedly in the heap", after_heap)); +} +#endif
--- a/src/share/vm/gc_interface/collectedHeap.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -69,7 +69,7 @@ MemRegion _reserved; BarrierSet* _barrier_set; bool _is_gc_active; - int _n_par_threads; + uint _n_par_threads; unsigned int _total_collections; // ... started unsigned int _total_full_collections; // ... started @@ -217,8 +217,8 @@ return p == NULL || is_in_reserved(p); } - // Returns "TRUE" if "p" points to the head of an allocated object in the - // heap. Since this method can be expensive in general, we restrict its + // Returns "TRUE" iff "p" points into the committed areas of the heap. + // Since this method can be expensive in general, we restrict its // use to assertion checking only. virtual bool is_in(const void* p) const = 0; @@ -309,10 +309,10 @@ GCCause::Cause gc_cause() { return _gc_cause; } // Number of threads currently working on GC tasks. - int n_par_threads() { return _n_par_threads; } + uint n_par_threads() { return _n_par_threads; } // May be overridden to set additional parallelism. - virtual void set_par_threads(int t) { _n_par_threads = t; }; + virtual void set_par_threads(uint t) { _n_par_threads = t; }; // Preload classes into the shared portion of the heap, and then dump // that data to a file so that it can be loaded directly by another @@ -648,6 +648,10 @@ // reduce the occurrence of ParallelGCThreads to uses where the // actual number may be germane. static bool use_parallel_gc_threads() { return ParallelGCThreads > 0; } + + /////////////// Unit tests /////////////// + + NOT_PRODUCT(static void test_is_in();) }; // Class to set and reset the GC cause for a CollectedHeap.
--- a/src/share/vm/memory/genCollectedHeap.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/genCollectedHeap.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -703,7 +703,7 @@ return collector_policy()->satisfy_failed_allocation(size, is_tlab); } -void GenCollectedHeap::set_par_threads(int t) { +void GenCollectedHeap::set_par_threads(uint t) { SharedHeap::set_par_threads(t); _gen_process_strong_tasks->set_n_threads(t); } @@ -957,7 +957,7 @@ return result; } -// Returns "TRUE" iff "p" points into the allocated area of the heap. +// Returns "TRUE" iff "p" points into the committed areas of the heap. bool GenCollectedHeap::is_in(const void* p) const { #ifndef ASSERT guarantee(VerifyBeforeGC || @@ -1460,26 +1460,22 @@ }; jlong GenCollectedHeap::millis_since_last_gc() { - jlong now = os::javaTimeMillis(); + // We need a monotonically non-deccreasing time in ms but + // os::javaTimeMillis() does not guarantee monotonicity. + jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; GenTimeOfLastGCClosure tolgc_cl(now); // iterate over generations getting the oldest // time that a generation was collected generation_iterate(&tolgc_cl, false); tolgc_cl.do_generation(perm_gen()); - // XXX Despite the assert above, since javaTimeMillis() - // doesnot guarantee monotonically increasing return - // values (note, i didn't say "strictly monotonic"), - // we need to guard against getting back a time - // later than now. This should be fixed by basing - // on someting like gethrtime() which guarantees - // monotonicity. Note that cond_wait() is susceptible - // to a similar problem, because its interface is - // based on absolute time in the form of the - // system time's notion of UCT. See also 4506635 - // for yet another problem of similar nature. XXX + + // javaTimeNanos() is guaranteed to be monotonically non-decreasing + // provided the underlying platform provides such a time source + // (and it is bug free). So we still have to guard against getting + // back a time later than 'now'. jlong retVal = now - tolgc_cl.time(); if (retVal < 0) { - NOT_PRODUCT(warning("time warp: %d", retVal);) + NOT_PRODUCT(warning("time warp: "INT64_FORMAT, retVal);) return 0; } return retVal;
--- a/src/share/vm/memory/genCollectedHeap.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/genCollectedHeap.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -198,7 +198,7 @@ // Mostly used for testing purposes. Caller does not hold the Heap_lock on entry. void collect(GCCause::Cause cause, int max_level); - // Returns "TRUE" iff "p" points into the allocated area of the heap. + // Returns "TRUE" iff "p" points into the committed areas of the heap. // The methods is_in(), is_in_closed_subset() and is_in_youngest() may // be expensive to compute in general, so, to prevent // their inadvertent use in product jvm's, we restrict their use to @@ -419,8 +419,7 @@ // asserted to be this type. static GenCollectedHeap* heap(); - void set_par_threads(int t); - + void set_par_threads(uint t); // Invoke the "do_oop" method of one of the closures "not_older_gens" // or "older_gens" on root locations for the generation at
--- a/src/share/vm/memory/generation.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/generation.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -220,7 +220,7 @@ MemRegion prev_used_region() const { return _prev_used_region; } virtual void save_used_region() { _prev_used_region = used_region(); } - // Returns "TRUE" iff "p" points into an allocated object in the generation. + // Returns "TRUE" iff "p" points into the committed areas in the generation. // For some kinds of generations, this may be an expensive operation. // To avoid performance problems stemming from its inadvertent use in // product jvm's, we restrict its use to assertion checking or @@ -413,10 +413,13 @@ // Time (in ms) when we were last collected or now if a collection is // in progress. virtual jlong time_of_last_gc(jlong now) { - // XXX See note in genCollectedHeap::millis_since_last_gc() + // Both _time_of_last_gc and now are set using a time source + // that guarantees monotonically non-decreasing values provided + // the underlying platform provides such a source. So we still + // have to guard against non-monotonicity. NOT_PRODUCT( if (now < _time_of_last_gc) { - warning("time warp: %d to %d", _time_of_last_gc, now); + warning("time warp: "INT64_FORMAT" to "INT64_FORMAT, _time_of_last_gc, now); } ) return _time_of_last_gc;
--- a/src/share/vm/memory/referenceProcessor.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/referenceProcessor.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -43,7 +43,9 @@ } void ReferenceProcessor::init_statics() { - jlong now = os::javaTimeMillis(); + // We need a monotonically non-deccreasing time in ms but + // os::javaTimeMillis() does not guarantee monotonicity. + jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; // Initialize the soft ref timestamp clock. _soft_ref_timestamp_clock = now; @@ -86,9 +88,9 @@ ReferenceProcessor::ReferenceProcessor(MemRegion span, bool mt_processing, - int mt_processing_degree, + uint mt_processing_degree, bool mt_discovery, - int mt_discovery_degree, + uint mt_discovery_degree, bool atomic_discovery, BoolObjectClosure* is_alive_non_header, bool discovered_list_needs_barrier) : @@ -103,7 +105,7 @@ _span = span; _discovery_is_atomic = atomic_discovery; _discovery_is_mt = mt_discovery; - _num_q = MAX2(1, mt_processing_degree); + _num_q = MAX2(1U, mt_processing_degree); _max_num_q = MAX2(_num_q, mt_discovery_degree); _discovered_refs = NEW_C_HEAP_ARRAY(DiscoveredList, _max_num_q * number_of_subclasses_of_ref()); @@ -116,7 +118,7 @@ _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q]; // Initialize all entries to NULL - for (int i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { _discovered_refs[i].set_head(NULL); _discovered_refs[i].set_length(0); } @@ -131,7 +133,7 @@ #ifndef PRODUCT void ReferenceProcessor::verify_no_references_recorded() { guarantee(!_discovering_refs, "Discovering refs?"); - for (int i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { guarantee(_discovered_refs[i].is_empty(), "Found non-empty discovered list"); } @@ -139,7 +141,7 @@ #endif void ReferenceProcessor::weak_oops_do(OopClosure* f) { - for (int i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { if (UseCompressedOops) { f->do_oop((narrowOop*)_discovered_refs[i].adr_head()); } else { @@ -151,7 +153,10 @@ void ReferenceProcessor::update_soft_ref_master_clock() { // Update (advance) the soft ref master clock field. This must be done // after processing the soft ref list. - jlong now = os::javaTimeMillis(); + + // We need a monotonically non-deccreasing time in ms but + // os::javaTimeMillis() does not guarantee monotonicity. + jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC; jlong soft_ref_clock = java_lang_ref_SoftReference::clock(); assert(soft_ref_clock == _soft_ref_timestamp_clock, "soft ref clocks out of sync"); @@ -161,10 +166,11 @@ _soft_ref_timestamp_clock, now); } ) - // In product mode, protect ourselves from system time being adjusted - // externally and going backward; see note in the implementation of - // GenCollectedHeap::time_since_last_gc() for the right way to fix - // this uniformly throughout the VM; see bug-id 4741166. XXX + // The values of now and _soft_ref_timestamp_clock are set using + // javaTimeNanos(), which is guaranteed to be monotonically + // non-decreasing provided the underlying platform provides such + // a time source (and it is bug free). + // In product mode, however, protect ourselves from non-monotonicty. if (now > _soft_ref_timestamp_clock) { _soft_ref_timestamp_clock = now; java_lang_ref_SoftReference::set_clock(now); @@ -431,7 +437,7 @@ task_executor->execute(tsk); } else { // Serial code: call the parent class's implementation - for (int i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { enqueue_discovered_reflist(_discovered_refs[i], pending_list_addr); _discovered_refs[i].set_head(NULL); _discovered_refs[i].set_length(0); @@ -690,7 +696,7 @@ void ReferenceProcessor::abandon_partial_discovery() { // loop over the lists - for (int i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) { gclog_or_tty->print_cr("\nAbandoning %s discovered list", list_name(i)); } @@ -781,7 +787,7 @@ gclog_or_tty->print_cr("\nBalance ref_lists "); } - for (int i = 0; i < _max_num_q; ++i) { + for (uint i = 0; i < _max_num_q; ++i) { total_refs += ref_lists[i].length(); if (TraceReferenceGC && PrintGCDetails) { gclog_or_tty->print("%d ", ref_lists[i].length()); @@ -791,8 +797,8 @@ gclog_or_tty->print_cr(" = %d", total_refs); } size_t avg_refs = total_refs / _num_q + 1; - int to_idx = 0; - for (int from_idx = 0; from_idx < _max_num_q; from_idx++) { + uint to_idx = 0; + for (uint from_idx = 0; from_idx < _max_num_q; from_idx++) { bool move_all = false; if (from_idx >= _num_q) { move_all = ref_lists[from_idx].length() > 0; @@ -851,7 +857,7 @@ } #ifdef ASSERT size_t balanced_total_refs = 0; - for (int i = 0; i < _max_num_q; ++i) { + for (uint i = 0; i < _max_num_q; ++i) { balanced_total_refs += ref_lists[i].length(); if (TraceReferenceGC && PrintGCDetails) { gclog_or_tty->print("%d ", ref_lists[i].length()); @@ -897,7 +903,7 @@ } if (PrintReferenceGC && PrintGCDetails) { size_t total = 0; - for (int i = 0; i < _max_num_q; ++i) { + for (uint i = 0; i < _max_num_q; ++i) { total += refs_lists[i].length(); } gclog_or_tty->print(", %u refs", total); @@ -913,7 +919,7 @@ RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/); task_executor->execute(phase1); } else { - for (int i = 0; i < _max_num_q; i++) { + for (uint i = 0; i < _max_num_q; i++) { process_phase1(refs_lists[i], policy, is_alive, keep_alive, complete_gc); } @@ -929,7 +935,7 @@ RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/); task_executor->execute(phase2); } else { - for (int i = 0; i < _max_num_q; i++) { + for (uint i = 0; i < _max_num_q; i++) { process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc); } } @@ -940,7 +946,7 @@ RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/); task_executor->execute(phase3); } else { - for (int i = 0; i < _max_num_q; i++) { + for (uint i = 0; i < _max_num_q; i++) { process_phase3(refs_lists[i], clear_referent, is_alive, keep_alive, complete_gc); } @@ -949,7 +955,7 @@ void ReferenceProcessor::clean_up_discovered_references() { // loop over the lists - for (int i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { if (TraceReferenceGC && PrintGCDetails && ((i % _max_num_q) == 0)) { gclog_or_tty->print_cr( "\nScrubbing %s discovered list of Null referents", @@ -994,7 +1000,7 @@ } inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) { - int id = 0; + uint id = 0; // Determine the queue index to use for this object. if (_discovery_is_mt) { // During a multi-threaded discovery phase, @@ -1276,7 +1282,7 @@ { TraceTime tt("Preclean SoftReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); - for (int i = 0; i < _max_num_q; i++) { + for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; } @@ -1289,7 +1295,7 @@ { TraceTime tt("Preclean WeakReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); - for (int i = 0; i < _max_num_q; i++) { + for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; } @@ -1302,7 +1308,7 @@ { TraceTime tt("Preclean FinalReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); - for (int i = 0; i < _max_num_q; i++) { + for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; } @@ -1315,7 +1321,7 @@ { TraceTime tt("Preclean PhantomReferences", PrintGCDetails && PrintReferenceGC, false, gclog_or_tty); - for (int i = 0; i < _max_num_q; i++) { + for (uint i = 0; i < _max_num_q; i++) { if (yield->should_return()) { return; } @@ -1380,7 +1386,7 @@ ) } -const char* ReferenceProcessor::list_name(int i) { +const char* ReferenceProcessor::list_name(uint i) { assert(i >= 0 && i <= _max_num_q * number_of_subclasses_of_ref(), "Out of bounds index"); @@ -1404,7 +1410,7 @@ #ifndef PRODUCT void ReferenceProcessor::clear_discovered_references() { guarantee(!_discovering_refs, "Discovering refs?"); - for (int i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { + for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { clear_discovered_references(_discovered_refs[i]); } }
--- a/src/share/vm/memory/referenceProcessor.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/referenceProcessor.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -231,7 +231,7 @@ bool _enqueuing_is_done; // true if all weak references enqueued bool _processing_is_mt; // true during phases when // reference processing is MT. - int _next_id; // round-robin mod _num_q counter in + uint _next_id; // round-robin mod _num_q counter in // support of work distribution // For collectors that do not keep GC liveness information @@ -252,9 +252,9 @@ // The discovered ref lists themselves // The active MT'ness degree of the queues below - int _num_q; + uint _num_q; // The maximum MT'ness degree of the queues below - int _max_num_q; + uint _max_num_q; // Master array of discovered oops DiscoveredList* _discovered_refs; @@ -268,9 +268,9 @@ public: static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); } - int num_q() { return _num_q; } - int max_num_q() { return _max_num_q; } - void set_active_mt_degree(int v) { _num_q = v; } + uint num_q() { return _num_q; } + uint max_num_q() { return _max_num_q; } + void set_active_mt_degree(uint v) { _num_q = v; } DiscoveredList* discovered_refs() { return _discovered_refs; } @@ -368,7 +368,7 @@ // Returns the name of the discovered reference list // occupying the i / _num_q slot. - const char* list_name(int i); + const char* list_name(uint i); void enqueue_discovered_reflists(HeapWord* pending_list_addr, AbstractRefProcTaskExecutor* task_executor); @@ -388,8 +388,8 @@ YieldClosure* yield); // round-robin mod _num_q (not: _not_ mode _max_num_q) - int next_id() { - int id = _next_id; + uint next_id() { + uint id = _next_id; if (++_next_id == _num_q) { _next_id = 0; } @@ -434,8 +434,8 @@ // Default parameters give you a vanilla reference processor. ReferenceProcessor(MemRegion span, - bool mt_processing = false, int mt_processing_degree = 1, - bool mt_discovery = false, int mt_discovery_degree = 1, + bool mt_processing = false, uint mt_processing_degree = 1, + bool mt_discovery = false, uint mt_discovery_degree = 1, bool atomic_discovery = true, BoolObjectClosure* is_alive_non_header = NULL, bool discovered_list_needs_barrier = false);
--- a/src/share/vm/memory/sharedHeap.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/sharedHeap.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -94,7 +94,7 @@ && _thread_holds_heap_lock_for_gc); } -void SharedHeap::set_par_threads(int t) { +void SharedHeap::set_par_threads(uint t) { assert(t == 0 || !UseSerialGC, "Cannot have parallel threads"); _n_par_threads = t; _process_strong_tasks->set_n_threads(t);
--- a/src/share/vm/memory/sharedHeap.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/sharedHeap.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -287,7 +287,7 @@ // Sets the number of parallel threads that will be doing tasks // (such as process strong roots) subsequently. - virtual void set_par_threads(int t); + virtual void set_par_threads(uint t); int n_termination(); void set_n_termination(int t);
--- a/src/share/vm/memory/space.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/space.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -304,11 +304,6 @@ CompactibleSpace::clear(mangle_space); } -bool Space::is_in(const void* p) const { - HeapWord* b = block_start_const(p); - return b != NULL && block_is_obj(b); -} - bool ContiguousSpace::is_in(const void* p) const { return _bottom <= p && p < _top; }
--- a/src/share/vm/memory/space.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/memory/space.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -187,7 +187,7 @@ // expensive operation. To prevent performance problems // on account of its inadvertent use in product jvm's, // we restrict its use to assertion checks only. - virtual bool is_in(const void* p) const; + virtual bool is_in(const void* p) const = 0; // Returns true iff the given reserved memory of the space contains the // given address.
--- a/src/share/vm/oops/arrayOop.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/oops/arrayOop.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -38,9 +38,7 @@ return (julong)(size_t)bytes == bytes; } -bool arrayOopDesc::test_max_array_length() { - tty->print_cr("test_max_array_length"); - +void arrayOopDesc::test_max_array_length() { assert(check_max_length_overflow(T_BOOLEAN), "size_t overflow for boolean array"); assert(check_max_length_overflow(T_CHAR), "size_t overflow for char array"); assert(check_max_length_overflow(T_FLOAT), "size_t overflow for float array"); @@ -54,8 +52,6 @@ assert(check_max_length_overflow(T_NARROWOOP), "size_t overflow for narrowOop array"); // T_VOID and T_ADDRESS are not supported by max_array_length() - - return true; }
--- a/src/share/vm/oops/arrayOop.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/oops/arrayOop.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -128,7 +128,7 @@ #ifndef PRODUCT static bool check_max_length_overflow(BasicType type); static int32_t old_max_array_length(BasicType type); - static bool test_max_array_length(); + static void test_max_array_length(); #endif };
--- a/src/share/vm/prims/jni.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/prims/jni.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -5037,16 +5037,25 @@ #ifndef PRODUCT +#include "gc_interface/collectedHeap.hpp" #include "utilities/quickSort.hpp" +#define run_unit_test(unit_test_function_call) \ + tty->print_cr("Running test: " #unit_test_function_call); \ + unit_test_function_call + void execute_internal_vm_tests() { if (ExecuteInternalVMTests) { - assert(QuickSort::test_quick_sort(), "test_quick_sort failed"); - assert(arrayOopDesc::test_max_array_length(), "test_max_array_length failed"); + tty->print_cr("Running internal VM tests"); + run_unit_test(arrayOopDesc::test_max_array_length()); + run_unit_test(CollectedHeap::test_is_in()); + run_unit_test(QuickSort::test_quick_sort()); tty->print_cr("All internal VM tests passed"); } } +#undef run_unit_test + #endif #ifndef USDT2
--- a/src/share/vm/prims/jvm.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/prims/jvm.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -3515,14 +3515,14 @@ JVM_LEAF(jint, JVM_Recv(jint fd, char *buf, jint nBytes, jint flags)) JVMWrapper2("JVM_Recv (0x%x)", fd); //%note jvm_r6 - return os::recv(fd, buf, nBytes, flags); + return os::recv(fd, buf, (size_t)nBytes, (uint)flags); JVM_END JVM_LEAF(jint, JVM_Send(jint fd, char *buf, jint nBytes, jint flags)) JVMWrapper2("JVM_Send (0x%x)", fd); //%note jvm_r6 - return os::send(fd, buf, nBytes, flags); + return os::send(fd, buf, (size_t)nBytes, (uint)flags); JVM_END @@ -3543,42 +3543,51 @@ JVM_LEAF(jint, JVM_Connect(jint fd, struct sockaddr *him, jint len)) JVMWrapper2("JVM_Connect (0x%x)", fd); //%note jvm_r6 - return os::connect(fd, him, len); + return os::connect(fd, him, (socklen_t)len); JVM_END JVM_LEAF(jint, JVM_Bind(jint fd, struct sockaddr *him, jint len)) JVMWrapper2("JVM_Bind (0x%x)", fd); //%note jvm_r6 - return os::bind(fd, him, len); + return os::bind(fd, him, (socklen_t)len); JVM_END JVM_LEAF(jint, JVM_Accept(jint fd, struct sockaddr *him, jint *len)) JVMWrapper2("JVM_Accept (0x%x)", fd); //%note jvm_r6 - return os::accept(fd, him, (int *)len); + socklen_t socklen = (socklen_t)(*len); + jint result = os::accept(fd, him, &socklen); + *len = (jint)socklen; + return result; JVM_END JVM_LEAF(jint, JVM_RecvFrom(jint fd, char *buf, int nBytes, int flags, struct sockaddr *from, int *fromlen)) JVMWrapper2("JVM_RecvFrom (0x%x)", fd); //%note jvm_r6 - return os::recvfrom(fd, buf, nBytes, flags, from, fromlen); + socklen_t socklen = (socklen_t)(*fromlen); + jint result = os::recvfrom(fd, buf, (size_t)nBytes, (uint)flags, from, &socklen); + *fromlen = (int)socklen; + return result; JVM_END JVM_LEAF(jint, JVM_GetSockName(jint fd, struct sockaddr *him, int *len)) JVMWrapper2("JVM_GetSockName (0x%x)", fd); //%note jvm_r6 - return os::get_sock_name(fd, him, len); + socklen_t socklen = (socklen_t)(*len); + jint result = os::get_sock_name(fd, him, &socklen); + *len = (int)socklen; + return result; JVM_END JVM_LEAF(jint, JVM_SendTo(jint fd, char *buf, int len, int flags, struct sockaddr *to, int tolen)) JVMWrapper2("JVM_SendTo (0x%x)", fd); //%note jvm_r6 - return os::sendto(fd, buf, len, flags, to, tolen); + return os::sendto(fd, buf, (size_t)len, (uint)flags, to, (socklen_t)tolen); JVM_END @@ -3592,21 +3601,26 @@ JVM_LEAF(jint, JVM_GetSockOpt(jint fd, int level, int optname, char *optval, int *optlen)) JVMWrapper2("JVM_GetSockOpt (0x%x)", fd); //%note jvm_r6 - return os::get_sock_opt(fd, level, optname, optval, optlen); + socklen_t socklen = (socklen_t)(*optlen); + jint result = os::get_sock_opt(fd, level, optname, optval, &socklen); + *optlen = (int)socklen; + return result; JVM_END JVM_LEAF(jint, JVM_SetSockOpt(jint fd, int level, int optname, const char *optval, int optlen)) JVMWrapper2("JVM_GetSockOpt (0x%x)", fd); //%note jvm_r6 - return os::set_sock_opt(fd, level, optname, optval, optlen); + return os::set_sock_opt(fd, level, optname, optval, (socklen_t)optlen); JVM_END + JVM_LEAF(int, JVM_GetHostName(char* name, int namelen)) JVMWrapper("JVM_GetHostName"); return os::get_host_name(name, namelen); JVM_END + // Library support /////////////////////////////////////////////////////////////////////////// JVM_ENTRY_NO_ENV(void*, JVM_LoadLibrary(const char* name)) @@ -3647,6 +3661,7 @@ return os::dll_lookup(handle, name); JVM_END + // Floating point support //////////////////////////////////////////////////////////////////// JVM_LEAF(jboolean, JVM_IsNaN(jdouble a)) @@ -3655,7 +3670,6 @@ JVM_END - // JNI version /////////////////////////////////////////////////////////////////////////////// JVM_LEAF(jboolean, JVM_IsSupportedJNIVersion(jint version))
--- a/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -43,7 +43,7 @@ #ifdef TARGET_ARCH_ppc # include "bytes_ppc.hpp" #endif -// FIXME: add Deprecated, LVT, LVTT attributes +// FIXME: add Deprecated, LVTT attributes // FIXME: fix Synthetic attribute // FIXME: per Serguei, add error return handling for constantPoolOopDesc::copy_cpool_bytes() @@ -136,8 +136,9 @@ constMethodHandle const_method(thread(), method->constMethod()); u2 line_num_cnt = 0; int stackmap_len = 0; + int local_variable_table_length = 0; - // compute number and length of attributes -- FIXME: for now no LVT + // compute number and length of attributes int attr_count = 0; int attr_size = 0; if (const_method->has_linenumber_table()) { @@ -170,6 +171,25 @@ attr_size += 2 + 4 + stackmap_len; } } + if (method->has_localvariable_table()) { + local_variable_table_length = method->localvariable_table_length(); + ++attr_count; + if (local_variable_table_length != 0) { + // Compute the size of the local variable table attribute (VM stores raw): + // LocalVariableTable_attribute { + // u2 attribute_name_index; + // u4 attribute_length; + // u2 local_variable_table_length; + // { + // u2 start_pc; + // u2 length; + // u2 name_index; + // u2 descriptor_index; + // u2 index; + // } + attr_size += 2 + 4 + 2 + local_variable_table_length * (2 + 2 + 2 + 2 + 2); + } + } typeArrayHandle exception_table(thread(), const_method->exception_table()); int exception_table_length = exception_table->length(); @@ -203,8 +223,9 @@ if (stackmap_len != 0) { write_stackmap_table_attribute(method, stackmap_len); } - - // FIXME: write LVT attribute + if (local_variable_table_length != 0) { + write_local_variable_table_attribute(method, local_variable_table_length); + } } // Write Exceptions attribute @@ -371,6 +392,36 @@ } } +// Write LineNumberTable attribute +// JVMSpec| LocalVariableTable_attribute { +// JVMSpec| u2 attribute_name_index; +// JVMSpec| u4 attribute_length; +// JVMSpec| u2 local_variable_table_length; +// JVMSpec| { u2 start_pc; +// JVMSpec| u2 length; +// JVMSpec| u2 name_index; +// JVMSpec| u2 descriptor_index; +// JVMSpec| u2 index; +// JVMSpec| } local_variable_table[local_variable_table_length]; +// JVMSpec| } +void JvmtiClassFileReconstituter::write_local_variable_table_attribute(methodHandle method, u2 num_entries) { + write_attribute_name_index("LocalVariableTable"); + write_u4(2 + num_entries * (2 + 2 + 2 + 2 + 2)); + write_u2(num_entries); + + assert(method->localvariable_table_length() == num_entries, "just checking"); + + LocalVariableTableElement *elem = method->localvariable_table_start(); + for (int j=0; j<method->localvariable_table_length(); j++) { + write_u2(elem->start_bci); + write_u2(elem->length); + write_u2(elem->name_cp_index); + write_u2(elem->descriptor_cp_index); + write_u2(elem->slot); + elem++; + } +} + // Write stack map table attribute // JSR-202| StackMapTable_attribute { // JSR-202| u2 attribute_name_index;
--- a/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -119,6 +119,7 @@ void write_source_debug_extension_attribute(); u2 line_number_table_entries(methodHandle method); void write_line_number_table_attribute(methodHandle method, u2 num_entries); + void write_local_variable_table_attribute(methodHandle method, u2 num_entries); void write_stackmap_table_attribute(methodHandle method, int stackmap_table_len); u2 inner_classes_attribute_length(); void write_inner_classes_attribute(int length);
--- a/src/share/vm/prims/jvmtiEnv.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/prims/jvmtiEnv.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -267,7 +267,10 @@ instanceKlassHandle ikh(current_thread, k_oop); if (ikh->get_cached_class_file_bytes() == NULL) { - // not cached, we need to reconstitute the class file from VM representation + // Not cached, we need to reconstitute the class file from the + // VM representation. We don't attach the reconstituted class + // bytes to the instanceKlass here because they have not been + // validated and we're not at a safepoint. constantPoolHandle constants(current_thread, ikh->constants()); ObjectLocker ol(constants, current_thread); // lock constant pool while we query it
--- a/src/share/vm/prims/jvmtiExport.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/prims/jvmtiExport.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -538,8 +538,6 @@ _curr_env = NULL; _cached_length_ptr = cached_length_ptr; _cached_data_ptr = cached_data_ptr; - *_cached_length_ptr = 0; - *_cached_data_ptr = NULL; _state = _thread->jvmti_thread_state(); if (_state != NULL) {
--- a/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -854,8 +854,9 @@ // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark RC_TRACE_WITH_THREAD(0x00000001, THREAD, - ("loading name=%s (avail_mem=" UINT64_FORMAT "K)", - the_class->external_name(), os::available_memory() >> 10)); + ("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)", + the_class->external_name(), _class_load_kind, + os::available_memory() >> 10)); ClassFileStream st((u1*) _class_defs[i].class_bytes, _class_defs[i].class_byte_count, (char *)"__VM_RedefineClasses__"); @@ -3205,8 +3206,20 @@ // with them was cached on the scratch class, move to the_class. // Note: we still want to do this if nothing needed caching since it // should get cleared in the_class too. - the_class->set_cached_class_file(scratch_class->get_cached_class_file_bytes(), - scratch_class->get_cached_class_file_len()); + if (the_class->get_cached_class_file_bytes() == 0) { + // the_class doesn't have a cache yet so copy it + the_class->set_cached_class_file( + scratch_class->get_cached_class_file_bytes(), + scratch_class->get_cached_class_file_len()); + } +#ifndef PRODUCT + else { + assert(the_class->get_cached_class_file_bytes() == + scratch_class->get_cached_class_file_bytes(), "cache ptrs must match"); + assert(the_class->get_cached_class_file_len() == + scratch_class->get_cached_class_file_len(), "cache lens must match"); + } +#endif // Replace inner_classes typeArrayOop old_inner_classes = the_class->inner_classes();
--- a/src/share/vm/runtime/globals.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/runtime/globals.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -82,16 +82,19 @@ } bool Flag::is_writeable() const { - return (strcmp(kind, "{manageable}") == 0 || strcmp(kind, "{product rw}") == 0); + return strcmp(kind, "{manageable}") == 0 || + strcmp(kind, "{product rw}") == 0 || + is_writeable_ext(); } -// All flags except "manageable" are assumed internal flags. +// All flags except "manageable" are assumed to be internal flags. // Long term, we need to define a mechanism to specify which flags // are external/stable and change this function accordingly. bool Flag::is_external() const { - return (strcmp(kind, "{manageable}") == 0); + return strcmp(kind, "{manageable}") == 0 || is_external_ext(); } + // Length of format string (e.g. "%.1234s") for printing ccstr below #define FORMAT_BUFFER_LEN 16
--- a/src/share/vm/runtime/globals.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/runtime/globals.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -245,6 +245,8 @@ bool is_unlocker_ext() const; bool is_unlocked_ext() const; + bool is_writeable_ext() const; + bool is_external_ext() const; void print_on(outputStream* st, bool withComments = false ); void print_as_flag(outputStream* st); @@ -1551,7 +1553,7 @@ product(uintx, ParGCDesiredObjsFromOverflowList, 20, \ "The desired number of objects to claim from the overflow list") \ \ - diagnostic(intx, ParGCStridesPerThread, 2, \ + diagnostic(uintx, ParGCStridesPerThread, 2, \ "The number of strides per worker thread that we divide up the " \ "card table scanning work into") \ \
--- a/src/share/vm/runtime/globals_ext.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/runtime/globals_ext.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -53,4 +53,12 @@ return true; } +inline bool Flag::is_writeable_ext() const { + return false; +} + +inline bool Flag::is_external_ext() const { + return false; +} + #endif // SHARE_VM_RUNTIME_GLOBALS_EXT_HPP
--- a/src/share/vm/runtime/os.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/runtime/os.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -256,7 +256,7 @@ char *addr, size_t bytes, bool read_only, bool allow_exec); static bool unmap_memory(char *addr, size_t bytes); - static void free_memory(char *addr, size_t bytes); + static void free_memory(char *addr, size_t bytes, size_t alignment_hint); static void realign_memory(char *addr, size_t bytes, size_t alignment_hint); // NUMA-specific interface @@ -584,28 +584,28 @@ static int socket(int domain, int type, int protocol); static int socket_close(int fd); static int socket_shutdown(int fd, int howto); - static int recv(int fd, char *buf, int nBytes, int flags); - static int send(int fd, char *buf, int nBytes, int flags); - static int raw_send(int fd, char *buf, int nBytes, int flags); + static int recv(int fd, char* buf, size_t nBytes, uint flags); + static int send(int fd, char* buf, size_t nBytes, uint flags); + static int raw_send(int fd, char* buf, size_t nBytes, uint flags); static int timeout(int fd, long timeout); static int listen(int fd, int count); - static int connect(int fd, struct sockaddr *him, int len); - static int bind(int fd, struct sockaddr *him, int len); - static int accept(int fd, struct sockaddr *him, int *len); - static int recvfrom(int fd, char *buf, int nbytes, int flags, - struct sockaddr *from, int *fromlen); - static int get_sock_name(int fd, struct sockaddr *him, int *len); - static int sendto(int fd, char *buf, int len, int flags, - struct sockaddr *to, int tolen); - static int socket_available(int fd, jint *pbytes); + static int connect(int fd, struct sockaddr* him, socklen_t len); + static int bind(int fd, struct sockaddr* him, socklen_t len); + static int accept(int fd, struct sockaddr* him, socklen_t* len); + static int recvfrom(int fd, char* buf, size_t nbytes, uint flags, + struct sockaddr* from, socklen_t* fromlen); + static int get_sock_name(int fd, struct sockaddr* him, socklen_t* len); + static int sendto(int fd, char* buf, size_t len, uint flags, + struct sockaddr* to, socklen_t tolen); + static int socket_available(int fd, jint* pbytes); static int get_sock_opt(int fd, int level, int optname, - char *optval, int* optlen); + char* optval, socklen_t* optlen); static int set_sock_opt(int fd, int level, int optname, - const char *optval, int optlen); + const char* optval, socklen_t optlen); static int get_host_name(char* name, int namelen); - static struct hostent* get_host_by_name(char* name); + static struct hostent* get_host_by_name(char* name); // Printing 64 bit integers static const char* jlong_format_specifier(); @@ -715,7 +715,6 @@ # include "os_bsd_zero.hpp" #endif - // debugging support (mostly used by debug.cpp but also fatal error handler) static bool find(address pc, outputStream* st = tty); // OS specific function to make sense out of an address
--- a/src/share/vm/services/management.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/services/management.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -33,6 +33,7 @@ #include "oops/objArrayKlass.hpp" #include "oops/oop.inline.hpp" #include "runtime/arguments.hpp" +#include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/javaCalls.hpp"
--- a/src/share/vm/utilities/globalDefinitions.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/globalDefinitions.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -175,6 +175,9 @@ const int MICROUNITS = 1000000; // micro units per base unit const int NANOUNITS = 1000000000; // nano units per base unit +const jlong NANOSECS_PER_SEC = CONST64(1000000000); +const jint NANOSECS_PER_MILLISEC = 1000000; + inline const char* proper_unit_for_byte_size(size_t s) { if (s >= 10*M) { return "M";
--- a/src/share/vm/utilities/ostream.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/ostream.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -1021,7 +1021,7 @@ void networkStream::flush() { if (size() != 0) { - int result = os::raw_send(_socket, (char *)base(), (int)size(), 0); + int result = os::raw_send(_socket, (char *)base(), size(), 0); assert(result != -1, "connection error"); assert(result == (int)size(), "didn't send enough data"); }
--- a/src/share/vm/utilities/quickSort.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/quickSort.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -93,8 +93,7 @@ return compare_arrays(arrayToSort, expectedResult, length); } -bool QuickSort::test_quick_sort() { - tty->print_cr("test_quick_sort"); +void QuickSort::test_quick_sort() { { int* test_array = NULL; int* expected_array = NULL; @@ -214,7 +213,6 @@ delete[] test_array; delete[] expected_array; } - return true; } #endif
--- a/src/share/vm/utilities/quickSort.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/quickSort.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -130,7 +130,7 @@ static void print_array(const char* prefix, int* array, int length); static bool compare_arrays(int* actual, int* expected, int length); template <class C> static bool sort_and_compare(int* arrayToSort, int* expectedResult, int length, C comparator, bool idempotent = false); - static bool test_quick_sort(); + static void test_quick_sort(); #endif };
--- a/src/share/vm/utilities/workgroup.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/workgroup.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -53,14 +53,14 @@ } WorkGang::WorkGang(const char* name, - int workers, + uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads) : AbstractWorkGang(name, are_GC_task_threads, are_ConcurrentGC_threads) { _total_workers = workers; } -GangWorker* WorkGang::allocate_worker(int which) { +GangWorker* WorkGang::allocate_worker(uint which) { GangWorker* new_worker = new GangWorker(this, which); return new_worker; } @@ -88,7 +88,7 @@ } else { worker_type = os::pgc_thread; } - for (int worker = 0; worker < total_workers(); worker += 1) { + for (uint worker = 0; worker < total_workers(); worker += 1) { GangWorker* new_worker = allocate_worker(worker); assert(new_worker != NULL, "Failed to allocate GangWorker"); _gang_workers[worker] = new_worker; @@ -108,14 +108,14 @@ tty->print_cr("Destructing work gang %s", name()); } stop(); // stop all the workers - for (int worker = 0; worker < total_workers(); worker += 1) { + for (uint worker = 0; worker < total_workers(); worker += 1) { delete gang_worker(worker); } delete gang_workers(); delete monitor(); } -GangWorker* AbstractWorkGang::gang_worker(int i) const { +GangWorker* AbstractWorkGang::gang_worker(uint i) const { // Array index bounds checking. GangWorker* result = NULL; assert(gang_workers() != NULL, "No workers for indexing"); @@ -148,7 +148,7 @@ // Tell the workers to get to work. monitor()->notify_all(); // Wait for them to be finished - while (finished_workers() < (int) no_of_parallel_workers) { + while (finished_workers() < no_of_parallel_workers) { if (TraceWorkGang) { tty->print_cr("Waiting in work gang %s: %d/%d finished sequence %d", name(), finished_workers(), no_of_parallel_workers, @@ -377,12 +377,12 @@ _n_workers(0), _n_completed(0), _should_reset(false) { } -WorkGangBarrierSync::WorkGangBarrierSync(int n_workers, const char* name) +WorkGangBarrierSync::WorkGangBarrierSync(uint n_workers, const char* name) : _monitor(Mutex::safepoint, name, true), _n_workers(n_workers), _n_completed(0), _should_reset(false) { } -void WorkGangBarrierSync::set_n_workers(int n_workers) { +void WorkGangBarrierSync::set_n_workers(uint n_workers) { _n_workers = n_workers; _n_completed = 0; _should_reset = false; @@ -419,9 +419,9 @@ // SubTasksDone functions. -SubTasksDone::SubTasksDone(int n) : +SubTasksDone::SubTasksDone(uint n) : _n_tasks(n), _n_threads(1), _tasks(NULL) { - _tasks = NEW_C_HEAP_ARRAY(jint, n); + _tasks = NEW_C_HEAP_ARRAY(uint, n); guarantee(_tasks != NULL, "alloc failure"); clear(); } @@ -430,14 +430,14 @@ return _tasks != NULL; } -void SubTasksDone::set_n_threads(int t) { +void SubTasksDone::set_n_threads(uint t) { assert(_claimed == 0 || _threads_completed == _n_threads, "should not be called while tasks are being processed!"); _n_threads = (t == 0 ? 1 : t); } void SubTasksDone::clear() { - for (int i = 0; i < _n_tasks; i++) { + for (uint i = 0; i < _n_tasks; i++) { _tasks[i] = 0; } _threads_completed = 0; @@ -446,9 +446,9 @@ #endif } -bool SubTasksDone::is_task_claimed(int t) { +bool SubTasksDone::is_task_claimed(uint t) { assert(0 <= t && t < _n_tasks, "bad task id."); - jint old = _tasks[t]; + uint old = _tasks[t]; if (old == 0) { old = Atomic::cmpxchg(1, &_tasks[t], 0); } @@ -457,7 +457,7 @@ #ifdef ASSERT if (!res) { assert(_claimed < _n_tasks, "Too many tasks claimed; missing clear?"); - Atomic::inc(&_claimed); + Atomic::inc((volatile jint*) &_claimed); } #endif return res; @@ -471,7 +471,7 @@ observed = Atomic::cmpxchg(old+1, &_threads_completed, old); } while (observed != old); // If this was the last thread checking in, clear the tasks. - if (observed+1 == _n_threads) clear(); + if (observed+1 == (jint)_n_threads) clear(); } @@ -490,12 +490,12 @@ return _n_threads > 0; } -bool SequentialSubTasksDone::is_task_claimed(int& t) { - jint* n_claimed_ptr = &_n_claimed; +bool SequentialSubTasksDone::is_task_claimed(uint& t) { + uint* n_claimed_ptr = &_n_claimed; t = *n_claimed_ptr; while (t < _n_tasks) { jint res = Atomic::cmpxchg(t+1, n_claimed_ptr, t); - if (res == t) { + if (res == (jint)t) { return false; } t = *n_claimed_ptr; @@ -504,10 +504,10 @@ } bool SequentialSubTasksDone::all_tasks_completed() { - jint* n_completed_ptr = &_n_completed; - jint complete = *n_completed_ptr; + uint* n_completed_ptr = &_n_completed; + uint complete = *n_completed_ptr; while (true) { - jint res = Atomic::cmpxchg(complete+1, n_completed_ptr, complete); + uint res = Atomic::cmpxchg(complete+1, n_completed_ptr, complete); if (res == complete) { break; }
--- a/src/share/vm/utilities/workgroup.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/workgroup.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -68,7 +68,7 @@ public: // The abstract work method. // The argument tells you which member of the gang you are. - virtual void work(int i) = 0; + virtual void work(uint worker_id) = 0; // This method configures the task for proper termination. // Some tasks do not have any requirements on termination @@ -149,7 +149,7 @@ // and notifies of changes in it. Monitor* _monitor; // The count of the number of workers in the gang. - int _total_workers; + uint _total_workers; // Whether the workers should terminate. bool _terminate; // The array of worker threads for this gang. @@ -160,18 +160,18 @@ // A sequence number for the current task. int _sequence_number; // The number of started workers. - int _started_workers; + uint _started_workers; // The number of finished workers. - int _finished_workers; + uint _finished_workers; public: // Accessors for fields Monitor* monitor() const { return _monitor; } - int total_workers() const { + uint total_workers() const { return _total_workers; } - virtual int active_workers() const { + virtual uint active_workers() const { return _total_workers; } bool terminate() const { @@ -186,10 +186,10 @@ int sequence_number() const { return _sequence_number; } - int started_workers() const { + uint started_workers() const { return _started_workers; } - int finished_workers() const { + uint finished_workers() const { return _finished_workers; } bool are_GC_task_threads() const { @@ -203,7 +203,7 @@ return (task() == NULL); } // Return the Ith gang worker. - GangWorker* gang_worker(int i) const; + GangWorker* gang_worker(uint i) const; void threads_do(ThreadClosure* tc) const; @@ -255,13 +255,13 @@ class WorkGang: public AbstractWorkGang { public: // Constructor - WorkGang(const char* name, int workers, + WorkGang(const char* name, uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads); // Run a task, returns when the task is done (or terminated). virtual void run_task(AbstractGangTask* task); void run_task(AbstractGangTask* task, uint no_of_parallel_workers); // Allocate a worker and return a pointer to it. - virtual GangWorker* allocate_worker(int which); + virtual GangWorker* allocate_worker(uint which); // Initialize workers in the gang. Return true if initialization // succeeded. The type of the worker can be overridden in a derived // class with the appropriate implementation of allocate_worker(). @@ -323,25 +323,25 @@ // determine completion. protected: - int _active_workers; + uint _active_workers; public: // Constructor and destructor. // Initialize active_workers to a minimum value. Setting it to // the parameter "workers" will initialize it to a maximum // value which is not desirable. - FlexibleWorkGang(const char* name, int workers, + FlexibleWorkGang(const char* name, uint workers, bool are_GC_task_threads, bool are_ConcurrentGC_threads) : WorkGang(name, workers, are_GC_task_threads, are_ConcurrentGC_threads), - _active_workers(UseDynamicNumberOfGCThreads ? 1 : ParallelGCThreads) {}; + _active_workers(UseDynamicNumberOfGCThreads ? 1U : ParallelGCThreads) {} // Accessors for fields - virtual int active_workers() const { return _active_workers; } - void set_active_workers(int v) { + virtual uint active_workers() const { return _active_workers; } + void set_active_workers(uint v) { assert(v <= _total_workers, "Trying to set more workers active than there are"); _active_workers = MIN2(v, _total_workers); assert(v != 0, "Trying to set active workers to 0"); - _active_workers = MAX2(1, _active_workers); + _active_workers = MAX2(1U, _active_workers); assert(UseDynamicNumberOfGCThreads || _active_workers == _total_workers, "Unless dynamic should use total workers"); } @@ -370,13 +370,13 @@ class WorkGangBarrierSync : public StackObj { protected: Monitor _monitor; - int _n_workers; - int _n_completed; + uint _n_workers; + uint _n_completed; bool _should_reset; Monitor* monitor() { return &_monitor; } - int n_workers() { return _n_workers; } - int n_completed() { return _n_completed; } + uint n_workers() { return _n_workers; } + uint n_completed() { return _n_completed; } bool should_reset() { return _should_reset; } void zero_completed() { _n_completed = 0; } @@ -386,11 +386,11 @@ public: WorkGangBarrierSync(); - WorkGangBarrierSync(int n_workers, const char* name); + WorkGangBarrierSync(uint n_workers, const char* name); // Set the number of workers that will use the barrier. // Must be called before any of the workers start running. - void set_n_workers(int n_workers); + void set_n_workers(uint n_workers); // Enter the barrier. A worker that enters the barrier will // not be allowed to leave until all other threads have @@ -402,18 +402,18 @@ // subtasks will be identified by integer indices, usually elements of an // enumeration type. -class SubTasksDone: public CHeapObj { - jint* _tasks; - int _n_tasks; +class SubTasksDone : public CHeapObj { + uint* _tasks; + uint _n_tasks; // _n_threads is used to determine when a sub task is done. // It does not control how many threads will execute the subtask // but must be initialized to the number that do execute the task // in order to correctly decide when the subtask is done (all the // threads working on the task have finished). - int _n_threads; - jint _threads_completed; + uint _n_threads; + uint _threads_completed; #ifdef ASSERT - volatile jint _claimed; + volatile uint _claimed; #endif // Set all tasks to unclaimed. @@ -423,19 +423,19 @@ // Initializes "this" to a state in which there are "n" tasks to be // processed, none of the which are originally claimed. The number of // threads doing the tasks is initialized 1. - SubTasksDone(int n); + SubTasksDone(uint n); // True iff the object is in a valid state. bool valid(); // Get/set the number of parallel threads doing the tasks to "t". Can only // be called before tasks start or after they are complete. - int n_threads() { return _n_threads; } - void set_n_threads(int t); + uint n_threads() { return _n_threads; } + void set_n_threads(uint t); // Returns "false" if the task "t" is unclaimed, and ensures that task is // claimed. The task "t" is required to be within the range of "this". - bool is_task_claimed(int t); + bool is_task_claimed(uint t); // The calling thread asserts that it has attempted to claim all the // tasks that it will try to claim. Every thread in the parallel task @@ -456,12 +456,12 @@ class SequentialSubTasksDone : public StackObj { protected: - jint _n_tasks; // Total number of tasks available. - jint _n_claimed; // Number of tasks claimed. + uint _n_tasks; // Total number of tasks available. + uint _n_claimed; // Number of tasks claimed. // _n_threads is used to determine when a sub task is done. // See comments on SubTasksDone::_n_threads - jint _n_threads; // Total number of parallel threads. - jint _n_completed; // Number of completed threads. + uint _n_threads; // Total number of parallel threads. + uint _n_completed; // Number of completed threads. void clear(); @@ -475,26 +475,26 @@ bool valid(); // number of tasks - jint n_tasks() const { return _n_tasks; } + uint n_tasks() const { return _n_tasks; } // Get/set the number of parallel threads doing the tasks to t. // Should be called before the task starts but it is safe // to call this once a task is running provided that all // threads agree on the number of threads. - int n_threads() { return _n_threads; } - void set_n_threads(int t) { _n_threads = t; } + uint n_threads() { return _n_threads; } + void set_n_threads(uint t) { _n_threads = t; } // Set the number of tasks to be claimed to t. As above, // should be called before the tasks start but it is safe // to call this once a task is running provided all threads // agree on the number of tasks. - void set_n_tasks(int t) { _n_tasks = t; } + void set_n_tasks(uint t) { _n_tasks = t; } // Returns false if the next task in the sequence is unclaimed, // and ensures that it is claimed. Will set t to be the index // of the claimed task in the sequence. Will return true if // the task cannot be claimed and there are none left to claim. - bool is_task_claimed(int& t); + bool is_task_claimed(uint& t); // The calling thread asserts that it has attempted to claim // all the tasks it possibly can in the sequence. Every thread
--- a/src/share/vm/utilities/yieldingWorkgroup.cpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/yieldingWorkgroup.cpp Wed Jan 04 12:36:07 2012 -0500 @@ -33,11 +33,11 @@ class WorkData; YieldingFlexibleWorkGang::YieldingFlexibleWorkGang( - const char* name, int workers, bool are_GC_task_threads) : + const char* name, uint workers, bool are_GC_task_threads) : FlexibleWorkGang(name, workers, are_GC_task_threads, false), _yielded_workers(0) {} -GangWorker* YieldingFlexibleWorkGang::allocate_worker(int which) { +GangWorker* YieldingFlexibleWorkGang::allocate_worker(uint which) { YieldingFlexibleGangWorker* new_member = new YieldingFlexibleGangWorker(this, which); return (YieldingFlexibleGangWorker*) new_member; @@ -120,7 +120,7 @@ new_task->set_gang(this); // Establish 2-way binding to support yielding _sequence_number++; - int requested_size = new_task->requested_size(); + uint requested_size = new_task->requested_size(); assert(requested_size >= 0, "Should be non-negative"); if (requested_size != 0) { _active_workers = MIN2(requested_size, total_workers());
--- a/src/share/vm/utilities/yieldingWorkgroup.hpp Wed Dec 28 12:15:57 2011 -0500 +++ b/src/share/vm/utilities/yieldingWorkgroup.hpp Wed Jan 04 12:36:07 2012 -0500 @@ -71,7 +71,7 @@ // The abstract work method. // The argument tells you which member of the gang you are. - virtual void work(int i) = 0; + virtual void work(uint worker_id) = 0; int requested_size() const { return _requested_size; } int actual_size() const { return _actual_size; } @@ -128,7 +128,7 @@ public: // The abstract work method. // The argument tells you which member of the gang you are. - virtual void work(int i) = 0; + virtual void work(uint worker_id) = 0; // Subclasses should call the parent's yield() method // after having done any work specific to the subclass. @@ -159,7 +159,7 @@ // Here's the public interface to this class. public: // Constructor and destructor. - YieldingFlexibleWorkGang(const char* name, int workers, + YieldingFlexibleWorkGang(const char* name, uint workers, bool are_GC_task_threads); YieldingFlexibleGangTask* yielding_task() const { @@ -168,7 +168,7 @@ return (YieldingFlexibleGangTask*)task(); } // Allocate a worker and return a pointer to it. - GangWorker* allocate_worker(int which); + GangWorker* allocate_worker(uint which); // Run a task; returns when the task is done, or the workers yield, // or the task is aborted, or the work gang is terminated via stop(). @@ -199,12 +199,12 @@ void abort(); private: - int _yielded_workers; + uint _yielded_workers; void wait_for_gang(); public: // Accessors for fields - int yielded_workers() const { + uint yielded_workers() const { return _yielded_workers; }