Mercurial > hg > truffle
changeset 4768:8940fd98d540
Merge
author | kvn |
---|---|
date | Thu, 29 Dec 2011 11:37:50 -0800 |
parents | 7faca6dfa2ed (diff) d12a66fa3820 (current diff) |
children | 9c87bcb3b4dd |
files | src/cpu/x86/vm/assembler_x86.cpp src/share/vm/runtime/globals.hpp |
diffstat | 77 files changed, 2649 insertions(+), 899 deletions(-) [+] |
line wrap: on
line diff
--- a/.hgtags Tue Dec 27 15:08:43 2011 -0800 +++ b/.hgtags Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/make/hotspot_version Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/cpu/x86/vm/assembler_x86.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -6299,7 +6299,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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/bsd/vm/jvm_bsd.h Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/bsd/vm/os_bsd.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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) //////////////////////////////////////////////////////////////////////////////// @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/bsd/vm/os_bsd.inline.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/linux/vm/jvm_linux.h Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/linux/vm/os_linux.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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) //////////////////////////////////////////////////////////////////////////////// @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/linux/vm/os_linux.inline.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/solaris/vm/jvm_solaris.h Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/solaris/vm/os_solaris.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/solaris/vm/os_solaris.inline.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/windows/vm/jvm_windows.h Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/os/windows/vm/os_windows.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 @@ -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/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/compactibleFreeListSpace.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/collectionSetChooser.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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; @@ -1048,7 +1047,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 +1056,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 +1075,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 +1104,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 +1116,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 +1133,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 +1151,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 +1502,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 +1534,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 +1548,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 +1645,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 +1700,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 +1723,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 +1765,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 +1775,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 +1787,7 @@ HeapRegion::FinalCountClaimValue), "sanity check"); } else { + n_workers = 1; g1_par_count_task.work(0); } @@ -1851,7 +1853,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 +2168,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 +2200,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 +2248,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 +2313,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 +2330,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 +2346,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 +2358,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 +2920,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 +2970,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 +2978,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 +3023,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 +3055,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 +3108,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 +3124,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 +3306,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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1ErgoVerbose.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1ErgoVerbose.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -69,7 +69,7 @@ ErgoHeapSizing = 0, ErgoCSetConstruction, ErgoConcCycles, - ErgoPartiallyYoungGCs, + ErgoMixedGCs, ErgoHeuristicNum } ErgoHeuristic;
--- a/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1MonitoringSupport.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1RemSet.inline.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/parNew/parCardTableModRefBS.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/parNew/parNewGeneration.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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/gcTaskManager.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,6 +53,9 @@ case noop_task: result = "noop task"; break; + case idle_task: + result = "idle task"; + break; } return result; }; @@ -782,6 +785,12 @@ void GCTaskManager::execute_and_wait(GCTaskQueue* list) { WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create(); list->enqueue(fin); + // The barrier task will be read by one of the GC + // workers once it is added to the list of tasks. + // Be sure that is globally visible before the + // GC worker reads it (which is after the task is added + // to the list of tasks below). + OrderAccess::storestore(); add_list(list); fin->wait_for(true /* reset */); // We have to release the barrier tasks! @@ -833,11 +842,15 @@ IdleGCTask* IdleGCTask::create() { IdleGCTask* result = new IdleGCTask(false); + assert(UseDynamicNumberOfGCThreads, + "Should only be used with dynamic GC thread"); return result; } IdleGCTask* IdleGCTask::create_on_c_heap() { IdleGCTask* result = new(ResourceObj::C_HEAP) IdleGCTask(true); + assert(UseDynamicNumberOfGCThreads, + "Should only be used with dynamic GC thread"); return result; }
--- a/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskThread.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -1,6 +1,6 @@ /* - * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -129,6 +129,8 @@ for (; /* break */; ) { // This will block until there is a task to be gotten. GCTask* task = manager()->get_task(which()); + // Record if this is an idle task for later use. + bool is_idle_task = task->is_idle_task(); // In case the update is costly if (PrintGCTaskTimeStamps) { timer.update(); @@ -137,9 +139,13 @@ jlong entry_time = timer.ticks(); char* name = task->name(); + // If this is the barrier task, it can be destroyed + // by the GC task manager once the do_it() executes. task->do_it(manager(), which()); - if (!task->is_idle_task()) { + // Use the saved value of is_idle_task because references + // using "task" are not reliable for the barrier task. + if (!is_idle_task) { manager()->note_completion(which()); if (PrintGCTaskTimeStamps) {
--- a/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psMarkSweep.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psParallelCompact.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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_interface/collectedHeap.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_interface/collectedHeap.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/genCollectedHeap.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/genCollectedHeap.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/generation.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/referenceProcessor.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/referenceProcessor.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/sharedHeap.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/sharedHeap.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/space.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/memory/space.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/oops/arrayOop.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/oops/arrayOop.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/prims/jni.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/prims/jvm.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/prims/jvmtiClassFileReconstituter.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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/runtime/globals.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/runtime/globals.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/runtime/globals.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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); @@ -1554,7 +1556,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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/runtime/globals_ext.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/runtime/os.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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/attachListener.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/services/attachListener.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -34,6 +34,7 @@ #include "runtime/javaCalls.hpp" #include "runtime/os.hpp" #include "services/attachListener.hpp" +#include "services/diagnosticCommand.hpp" #include "services/heapDumper.hpp" volatile bool AttachListener::_initialized; @@ -148,6 +149,24 @@ return JNI_OK; } +// A jcmd attach operation request was received, which will now +// dispatch to the diagnostic commands used for serviceability functions. +static jint jcmd(AttachOperation* op, outputStream* out) { + Thread* THREAD = Thread::current(); + // All the supplied jcmd arguments are stored as a single + // string (op->arg(0)). This is parsed by the Dcmd framework. + DCmd::parse_and_execute(out, op->arg(0), ' ', THREAD); + if (HAS_PENDING_EXCEPTION) { + java_lang_Throwable::print(PENDING_EXCEPTION, out); + CLEAR_PENDING_EXCEPTION; + // The exception has been printed on the output stream + // If the JVM returns JNI_ERR, the attachAPI throws a generic I/O + // exception and the content of the output stream is not processed. + // By returning JNI_OK, the exception will be displayed on the client side + } + return JNI_OK; +} + #ifndef SERVICES_KERNEL // Heap dumping not supported // Implementation of "dumpheap" command. // @@ -366,6 +385,7 @@ { "inspectheap", heap_inspection }, { "setflag", set_flag }, { "printflag", print_flag }, + { "jcmd", jcmd }, { NULL, NULL } };
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/diagnosticArgument.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/allocation.inline.hpp" +#include "runtime/thread.hpp" +#include "services/diagnosticArgument.hpp" + +void GenDCmdArgument::read_value(const char* str, size_t len, TRAPS) { + if (is_set()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Duplicates in diagnostic command arguments"); + } + parse_value(str, len, CHECK); + set_is_set(true); +} + +template <> void DCmdArgument<jlong>::parse_value(const char* str, + size_t len, TRAPS) { + if (sscanf(str, INT64_FORMAT, &_value) != 1) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Integer parsing error in diagnostic command arguments"); + } +} + +template <> void DCmdArgument<jlong>::init_value(TRAPS) { + if (has_default()) { + this->parse_value(_default_string, strlen(_default_string), THREAD); + if (HAS_PENDING_EXCEPTION) { + fatal("Default string must be parsable"); + } + } else { + set_value(0); + } +} + +template <> void DCmdArgument<jlong>::destroy_value() { } + +template <> void DCmdArgument<bool>::parse_value(const char* str, + size_t len, TRAPS) { + if (len == 0) { + set_value(true); + } else { + if (strcasecmp(str, "true") == 0) { + set_value(true); + } else if (strcasecmp(str, "false") == 0) { + set_value(false); + } else { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Boolean parsing error in diagnostic command arguments"); + } + } +} + +template <> void DCmdArgument<bool>::init_value(TRAPS) { + if (has_default()) { + this->parse_value(_default_string, strlen(_default_string), THREAD); + if (HAS_PENDING_EXCEPTION) { + fatal("Default string must be parsable"); + } + } else { + set_value(false); + } +} + +template <> void DCmdArgument<bool>::destroy_value() { } + +template <> void DCmdArgument<char*>::parse_value(const char* str, + size_t len, TRAPS) { + _value = NEW_C_HEAP_ARRAY(char, len+1); + strncpy(_value, str, len); + _value[len] = 0; +} + +template <> void DCmdArgument<char*>::init_value(TRAPS) { + if (has_default()) { + this->parse_value(_default_string, strlen(_default_string), THREAD); + if (HAS_PENDING_EXCEPTION) { + fatal("Default string must be parsable"); + } + } else { + set_value(NULL); + } +} + +template <> void DCmdArgument<char*>::destroy_value() { + if (_value != NULL) { + FREE_C_HEAP_ARRAY(char, _value); + set_value(NULL); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/diagnosticArgument.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP +#define SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP + +#include "classfile/vmSymbols.hpp" +#include "memory/allocation.hpp" +#include "runtime/os.hpp" +#include "runtime/thread.hpp" +#include "utilities/exceptions.hpp" + +class GenDCmdArgument : public ResourceObj { +protected: + GenDCmdArgument* _next; + const char* _name; + const char* _description; + const char* _type; + const char* _default_string; + bool _is_set; + bool _is_mandatory; + GenDCmdArgument(const char* name, const char* description, const char* type, + const char* default_string, bool mandatory) { + _name = name; + _description = description; + _type = type; + _default_string = default_string; + _is_mandatory = mandatory; + _is_set = false; + }; +public: + const char* name() { return _name; } + const char* description() { return _description; } + const char* type() { return _type; } + const char* default_string() { return _default_string; } + bool is_set() { return _is_set; } + void set_is_set(bool b) { _is_set = b; } + bool is_mandatory() { return _is_mandatory; } + bool has_value() { return _is_set || _default_string != NULL; } + bool has_default() { return _default_string != NULL; } + void read_value(const char* str, size_t len, TRAPS); + virtual void parse_value(const char* str, size_t len, TRAPS) = 0; + virtual void init_value(TRAPS) = 0; + virtual void reset(TRAPS) = 0; + virtual void cleanup() = 0; + void set_next(GenDCmdArgument* arg) { + _next = arg; + } + GenDCmdArgument* next() { + return _next; + } +}; + +template <class ArgType> class DCmdArgument: public GenDCmdArgument { +private: + ArgType _value; +public: + DCmdArgument(const char* name, const char* description, const char* type, + bool mandatory) : + GenDCmdArgument(name, description, type, NULL, mandatory) { } + DCmdArgument(const char* name, const char* description, const char* type, + bool mandatory, const char* defaultvalue) : + GenDCmdArgument(name, description, type, defaultvalue, mandatory) + { } + ~DCmdArgument() { destroy_value(); } + ArgType value() { return _value;} + void set_value(ArgType v) { _value = v; } + void reset(TRAPS) { + destroy_value(); + init_value(CHECK); + _is_set = false; + } + void cleanup() { + destroy_value(); + } + void parse_value(const char* str, size_t len, TRAPS); + void init_value(TRAPS); + void destroy_value(); +}; + +#endif /* SHARE_VM_SERVICES_DIAGNOSTICARGUMENT_HPP */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/diagnosticCommand.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "services/diagnosticArgument.hpp" +#include "services/diagnosticCommand.hpp" +#include "services/diagnosticFramework.hpp" + +HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmd(output, heap), + _all("-all", "Show help for all commands", "BOOLEAN", false, "false"), + _cmd("command name", "The name of the command for which we want help", + "STRING", false) { + _dcmdparser.add_dcmd_option(&_all); + _dcmdparser.add_dcmd_argument(&_cmd); +}; + +void HelpDCmd::parse(CmdLine* line, char delim, TRAPS) { + _dcmdparser.parse(line, delim, CHECK); +} + +void HelpDCmd::print_help(outputStream* out) { + _dcmdparser.print_help(out, name()); +} + +void HelpDCmd::execute(TRAPS) { + if (_all.value()) { + GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(); + for (int i = 0; i < cmd_list->length(); i++) { + DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), + strlen(cmd_list->at(i))); + if (!factory->is_hidden()) { + output()->print_cr("%s%s", factory->name(), + factory->is_enabled() ? "" : " [disabled]"); + output()->print_cr("\t%s", factory->description()); + output()->cr(); + } + factory = factory->next(); + } + } else if (_cmd.has_value()) { + DCmd* cmd = NULL; + DCmdFactory* factory = DCmdFactory::factory(_cmd.value(), + strlen(_cmd.value())); + if (factory != NULL) { + output()->print_cr("%s%s", factory->name(), + factory->is_enabled() ? "" : " [disabled]"); + output()->print_cr(factory->description()); + output()->print_cr("\nImpact: %s", factory->impact()); + cmd = factory->create_resource_instance(output()); + if (cmd != NULL) { + DCmdMark mark(cmd); + cmd->print_help(output()); + } + } else { + output()->print_cr("Help unavailable : '%s' : No such command", _cmd.value()); + } + } else { + output()->print_cr("The following commands are available:"); + GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(); + for (int i = 0; i < cmd_list->length(); i++) { + DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), + strlen(cmd_list->at(i))); + if (!factory->is_hidden()) { + output()->print_cr("%s%s", factory->name(), + factory->is_enabled() ? "" : " [disabled]"); + } + factory = factory->_next; + } + output()->print_cr("\nFor more information about a specific command use 'help <command>'."); + } +} + +void HelpDCmd::reset(TRAPS) { + _dcmdparser.reset(CHECK); +} + +void HelpDCmd::cleanup() { + _dcmdparser.cleanup(); +} + +int HelpDCmd::num_arguments() { + ResourceMark rm; + HelpDCmd* dcmd = new HelpDCmd(NULL, false); + if (dcmd != NULL) { + DCmdMark mark(dcmd); + return dcmd->_dcmdparser.num_arguments(); + } else { + return 0; + } +} + +GrowableArray<const char*>* HelpDCmd::argument_name_array() { + return _dcmdparser.argument_name_array(); +} + +GrowableArray<DCmdArgumentInfo*>* HelpDCmd::argument_info_array() { + return _dcmdparser.argument_info_array(); +} + +void VersionDCmd::execute(TRAPS) { + output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(), + Abstract_VM_Version::vm_release()); + JDK_Version jdk_version = JDK_Version::current(); + if (jdk_version.update_version() > 0) { + output()->print_cr("JDK %d.%d_%02d", jdk_version.major_version(), + jdk_version.minor_version(), jdk_version.update_version()); + } else { + output()->print_cr("JDK %d.%d", jdk_version.major_version(), + jdk_version.minor_version()); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/diagnosticCommand.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP +#define SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP + +#include "runtime/arguments.hpp" +#include "classfile/vmSymbols.hpp" +#include "utilities/ostream.hpp" +#include "runtime/vm_version.hpp" +#include "runtime/vmThread.hpp" +#include "runtime/os.hpp" +#include "services/diagnosticArgument.hpp" +#include "services/diagnosticCommand.hpp" +#include "services/diagnosticFramework.hpp" + +class HelpDCmd : public DCmd { +protected: + DCmdParser _dcmdparser; + DCmdArgument<bool> _all; + DCmdArgument<char*> _cmd; +public: + HelpDCmd(outputStream* output, bool heap); + static const char* name() { return "help"; } + static const char* description() { + return "For more information about a specific command use 'help <command>'. " + "With no argument this will show a list of available commands. " + "'help all' will show help for all commands."; + } + static const char* impact() { return "Low: "; } + static int num_arguments(); + virtual void parse(CmdLine* line, char delim, TRAPS); + virtual void execute(TRAPS); + virtual void reset(TRAPS); + virtual void cleanup(); + virtual void print_help(outputStream* out); + virtual GrowableArray<const char*>* argument_name_array(); + virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array(); +}; + +class VersionDCmd : public DCmd { +public: + VersionDCmd(outputStream* output, bool heap) : DCmd(output,heap) { } + static const char* name() { return "VM.version"; } + static const char* description() { + return "Print JVM version information."; + } + static const char* impact() { return "Low: "; } + static int num_arguments() { return 0; } + virtual void parse(CmdLine* line, char delim, TRAPS) { } + virtual void execute(TRAPS); + virtual void print_help(outputStream* out) { } +}; + +#endif // SHARE_VM_SERVICES_DIAGNOSTICCOMMAND_HPP
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/diagnosticFramework.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -0,0 +1,450 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#include "precompiled.hpp" +#include "memory/oopFactory.hpp" +#include "runtime/javaCalls.hpp" +#include "runtime/mutexLocker.hpp" +#include "services/diagnosticArgument.hpp" +#include "services/diagnosticFramework.hpp" +#include "services/management.hpp" + +CmdLine::CmdLine(const char* line, size_t len, bool no_command_name) { + assert(line != NULL, "Command line string should not be NULL"); + const char* line_end; + const char* cmd_end; + + _cmd = line; + line_end = &line[len]; + + // Skip whitespace in the beginning of the line. + while (_cmd < line_end && isspace((int) _cmd[0])) { + _cmd++; + } + cmd_end = _cmd; + + if (no_command_name) { + _cmd = NULL; + _cmd_len = 0; + } else { + // Look for end of the command name + while (cmd_end < line_end && !isspace((int) cmd_end[0])) { + cmd_end++; + } + _cmd_len = cmd_end - _cmd; + } + _args = cmd_end; + _args_len = line_end - _args; +} + +bool DCmdArgIter::next(TRAPS) { + if (_len == 0) return false; + // skipping spaces + while (_cursor < _len - 1 && isspace(_buffer[_cursor])) { + _cursor++; + } + // handling end of command line + if (_cursor >= _len - 1) { + _cursor = _len - 1; + _key_addr = &_buffer[_len - 1]; + _key_len = 0; + _value_addr = &_buffer[_len - 1]; + _value_len = 0; + return false; + } + // extracting first item, argument or option name + _key_addr = &_buffer[_cursor]; + while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) { + // argument can be surrounded by single or double quotes + if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { + _key_addr++; + char quote = _buffer[_cursor]; + while (_cursor < _len - 1) { + _cursor++; + if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { + break; + } + } + if (_buffer[_cursor] != quote) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Format error in diagnostic command arguments", false); + } + break; + } + _cursor++; + } + _key_len = &_buffer[_cursor] - _key_addr; + // check if the argument has the <key>=<value> format + if (_cursor <= _len -1 && _buffer[_cursor] == '=') { + _cursor++; + _value_addr = &_buffer[_cursor]; + // extract the value + while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) { + // value can be surrounded by simple or double quotes + if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { + _value_addr++; + char quote = _buffer[_cursor]; + while (_cursor < _len - 1) { + _cursor++; + if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { + break; + } + } + if (_buffer[_cursor] != quote) { + THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), + "Format error in diagnostic command arguments", false); + } + break; + } + _cursor++; + } + _value_len = &_buffer[_cursor] - _value_addr; + } else { + _value_addr = NULL; + _value_len = 0; + } + return _key_len != 0; +} + +bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) { + if (info == NULL) return false; + return strcmp((const char*)cmd_name, info->name()) == 0; +} + +void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) { + assert(arg != NULL, "Sanity"); + if (_options == NULL) { + _options = arg; + } else { + GenDCmdArgument* o = _options; + while (o->next() != NULL) { + o = o->next(); + } + o->set_next(arg); + } + arg->set_next(NULL); + Thread* THREAD = Thread::current(); + arg->init_value(THREAD); + if (HAS_PENDING_EXCEPTION) { + fatal("Initialization must be successful"); + } +} + +void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) { + assert(arg != NULL, "Sanity"); + if (_arguments_list == NULL) { + _arguments_list = arg; + } else { + GenDCmdArgument* a = _arguments_list; + while (a->next() != NULL) { + a = a->next(); + } + a->set_next(arg); + } + arg->set_next(NULL); + Thread* THREAD = Thread::current(); + arg->init_value(THREAD); + if (HAS_PENDING_EXCEPTION) { + fatal("Initialization must be successful"); + } +} + +void DCmdParser::parse(CmdLine* line, char delim, TRAPS) { + GenDCmdArgument* next_argument = _arguments_list; + DCmdArgIter iter(line->args_addr(), line->args_len(), delim); + bool cont = iter.next(CHECK); + while (cont) { + GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(), + iter.key_length()); + if (arg != NULL) { + arg->read_value(iter.value_addr(), iter.value_length(), CHECK); + } else { + if (next_argument != NULL) { + arg = next_argument; + arg->read_value(iter.key_addr(), iter.key_length(), CHECK); + next_argument = next_argument->next(); + } else { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Unknown argument in diagnostic command"); + } + } + cont = iter.next(CHECK); + } + check(CHECK); +} + +GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) { + GenDCmdArgument* arg = _options; + while (arg != NULL) { + if (strlen(arg->name()) == len && + strncmp(name, arg->name(), len) == 0) { + return arg; + } + arg = arg->next(); + } + return NULL; +} + +void DCmdParser::check(TRAPS) { + GenDCmdArgument* arg = _arguments_list; + while (arg != NULL) { + if (arg->is_mandatory() && !arg->has_value()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Missing argument for diagnostic command"); + } + arg = arg->next(); + } + arg = _options; + while (arg != NULL) { + if (arg->is_mandatory() && !arg->has_value()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Missing option for diagnostic command"); + } + arg = arg->next(); + } +} + +void DCmdParser::print_help(outputStream* out, const char* cmd_name) { + out->print("\nSyntax : %s %s", cmd_name, _options == NULL ? "" : "[options]"); + GenDCmdArgument* arg = _arguments_list; + while (arg != NULL) { + if (arg->is_mandatory()) { + out->print(" <%s>", arg->name()); + } else { + out->print(" [<%s>]", arg->name()); + } + arg = arg->next(); + } + out->print_cr(""); + if (_arguments_list != NULL) { + out->print_cr("\nArguments:"); + arg = _arguments_list; + while (arg != NULL) { + out->print("\t%s : %s %s (%s, ", arg->name(), + arg->is_mandatory() ? "" : "[optional]", + arg->description(), arg->type()); + if (arg->has_default()) { + out->print(arg->default_string()); + } else { + out->print("no default value"); + } + out->print_cr(")"); + arg = arg->next(); + } + } + if (_options != NULL) { + out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)"); + arg = _options; + while (arg != NULL) { + out->print("\t%s : %s %s (%s, ", arg->name(), + arg->is_mandatory() ? "" : "[optional]", + arg->description(), arg->type()); + if (arg->has_default()) { + out->print(arg->default_string()); + } else { + out->print("no default value"); + } + out->print_cr(")"); + arg = arg->next(); + } + } +} + +void DCmdParser::reset(TRAPS) { + GenDCmdArgument* arg = _arguments_list; + while (arg != NULL) { + arg->reset(CHECK); + arg = arg->next(); + } + arg = _options; + while (arg != NULL) { + arg->reset(CHECK); + arg = arg->next(); + } +} + +void DCmdParser::cleanup() { + GenDCmdArgument* arg = _arguments_list; + while (arg != NULL) { + arg->cleanup(); + arg = arg->next(); + } + arg = _options; + while (arg != NULL) { + arg->cleanup(); + arg = arg->next(); + } +} + +int DCmdParser::num_arguments() { + GenDCmdArgument* arg = _arguments_list; + int count = 0; + while (arg != NULL) { + count++; + arg = arg->next(); + } + arg = _options; + while (arg != NULL) { + count++; + arg = arg->next(); + } + return count; +} + +GrowableArray<const char *>* DCmdParser::argument_name_array() { + int count = num_arguments(); + GrowableArray<const char *>* array = new GrowableArray<const char *>(count); + GenDCmdArgument* arg = _arguments_list; + while (arg != NULL) { + array->append(arg->name()); + arg = arg->next(); + } + arg = _options; + while (arg != NULL) { + array->append(arg->name()); + arg = arg->next(); + } + return array; +} + +GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() { + int count = num_arguments(); + GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count); + int idx = 0; + GenDCmdArgument* arg = _arguments_list; + while (arg != NULL) { + array->append(new DCmdArgumentInfo(arg->name(), arg->description(), + arg->type(), arg->default_string(), arg->is_mandatory(), + false, idx)); + idx++; + arg = arg->next(); + } + arg = _options; + while (arg != NULL) { + array->append(new DCmdArgumentInfo(arg->name(), arg->description(), + arg->type(), arg->default_string(), arg->is_mandatory(), + true)); + arg = arg->next(); + } + return array; +} + +DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL; + +void DCmd::parse_and_execute(outputStream* out, const char* cmdline, + char delim, TRAPS) { + + if (cmdline == NULL) return; // Nothing to do! + DCmdIter iter(cmdline, '\n'); + + while (iter.has_next()) { + CmdLine line = iter.next(); + if (line.is_stop()) { + break; + } + if (line.is_executable()) { + DCmd* command = DCmdFactory::create_local_DCmd(line, out, CHECK); + assert(command != NULL, "command error must be handled before this line"); + DCmdMark mark(command); + command->parse(&line, delim, CHECK); + command->execute(CHECK); + } + } +} + +Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true); + +DCmdFactory* DCmdFactory::factory(const char* name, size_t len) { + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); + DCmdFactory* factory = _DCmdFactoryList; + while (factory != NULL) { + if (strlen(factory->name()) == len && + strncmp(name, factory->name(), len) == 0) { + return factory; + } + factory = factory->_next; + } + return NULL; +} + +int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) { + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); + factory->_next = _DCmdFactoryList; + _DCmdFactoryList = factory; + return 0; // Actually, there's no checks for duplicates +} + +DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) { + DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); + if (f != NULL) { + if (f->is_enabled()) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + f->disabled_message()); + } + return f->create_Cheap_instance(out); + } + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "Unknown diagnostic command"); +} + +DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) { + DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); + if (f != NULL) { + if (!f->is_enabled()) { + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + f->disabled_message()); + } + return f->create_resource_instance(out); + } + THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), + "Unknown diagnostic command"); +} + +GrowableArray<const char*>* DCmdFactory::DCmd_list() { + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); + GrowableArray<const char*>* array = new GrowableArray<const char*>(); + DCmdFactory* factory = _DCmdFactoryList; + while (factory != NULL) { + if (!factory->is_hidden()) { + array->append(factory->name()); + } + factory = factory->next(); + } + return array; +} + +GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list() { + MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); + GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>(); + DCmdFactory* factory = _DCmdFactoryList; + while (factory != NULL) { + if (!factory->is_hidden()) { + array->append(new DCmdInfo(factory->name(), + factory->description(), factory->impact(), + factory->num_arguments(), factory->is_enabled())); + } + factory = factory->next(); + } + return array; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/diagnosticFramework.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -0,0 +1,362 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +#ifndef SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP +#define SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP + +#include "classfile/vmSymbols.hpp" +#include "memory/allocation.hpp" +#include "runtime/arguments.hpp" +#include "runtime/os.hpp" +#include "runtime/vm_version.hpp" +#include "runtime/vmThread.hpp" +#include "utilities/ostream.hpp" + + +// CmdLine is the class used to handle a command line containing a single +// diagnostic command and its arguments. It provides methods to access the +// command name and the beginning of the arguments. The class is also +// able to identify commented command lines and the "stop" keyword +class CmdLine : public StackObj { +private: + const char* _cmd; + size_t _cmd_len; + const char* _args; + size_t _args_len; +public: + CmdLine(const char* line, size_t len, bool no_command_name); + const char* args_addr() const { return _args; } + size_t args_len() const { return _args_len; } + const char* cmd_addr() const { return _cmd; } + size_t cmd_len() const { return _cmd_len; } + bool is_empty() { return _cmd_len == 0; } + bool is_executable() { return is_empty() || _cmd[0] != '#'; } + bool is_stop() { return !is_empty() && strncmp("stop", _cmd, _cmd_len) == 0; } +}; + +// Iterator class taking a character string in input and returning a CmdLine +// instance for each command line. The argument delimiter has to be specified. +class DCmdIter : public StackObj { + friend class DCmd; +private: + const char* _str; + char _delim; + size_t _len; + size_t _cursor; +public: + + DCmdIter(const char* str, char delim) { + _str = str; + _delim = delim; + _len = strlen(str); + _cursor = 0; + } + bool has_next() { return _cursor < _len; } + CmdLine next() { + assert(_cursor <= _len, "Cannot iterate more"); + size_t n = _cursor; + while (n < _len && _str[n] != _delim) n++; + CmdLine line(&(_str[_cursor]), n - _cursor, false); + _cursor = n + 1; + // The default copy constructor of CmdLine is used to return a CmdLine + // instance to the caller. + return line; + } +}; + +// Iterator class to iterate over diagnostic command arguments +class DCmdArgIter : public ResourceObj { + const char* _buffer; + size_t _len; + size_t _cursor; + const char* _key_addr; + size_t _key_len; + const char* _value_addr; + size_t _value_len; + char _delim; +public: + DCmdArgIter(const char* buf, size_t len, char delim) { + _buffer = buf; + _len = len; + _delim = delim; + _cursor = 0; + } + bool next(TRAPS); + const char* key_addr() { return _key_addr; } + size_t key_length() { return _key_len; } + const char* value_addr() { return _value_addr; } + size_t value_length() { return _value_len; } +}; + +// A DCmdInfo instance provides a description of a diagnostic command. It is +// used to export the description to the JMX interface of the framework. +class DCmdInfo : public ResourceObj { +protected: + const char* _name; + const char* _description; + const char* _impact; + int _num_arguments; + bool _is_enabled; +public: + DCmdInfo(const char* name, + const char* description, + const char* impact, + int num_arguments, + bool enabled) { + this->_name = name; + this->_description = description; + this->_impact = impact; + this->_num_arguments = num_arguments; + this->_is_enabled = enabled; + } + const char* name() const { return _name; } + const char* description() const { return _description; } + const char* impact() const { return _impact; } + int num_arguments() const { return _num_arguments; } + bool is_enabled() const { return _is_enabled; } + + static bool by_name(void* name, DCmdInfo* info); +}; + +// A DCmdArgumentInfo instance provides a description of a diagnostic command +// argument. It is used to export the description to the JMX interface of the +// framework. +class DCmdArgumentInfo : public ResourceObj { +protected: + const char* _name; + const char* _description; + const char* _type; + const char* _default_string; + bool _mandatory; + bool _option; + int _position; +public: + DCmdArgumentInfo(const char* name, const char* description, const char* type, + const char* default_string, bool mandatory, bool option) { + this->_name = name; + this->_description = description; + this->_type = type; + this->_default_string = default_string; + this->_option = option; + this->_mandatory = mandatory; + this->_option = option; + this->_position = -1; + } + DCmdArgumentInfo(const char* name, const char* description, const char* type, + const char* default_string, bool mandatory, bool option, + int position) { + this->_name = name; + this->_description = description; + this->_type = type; + this->_default_string = default_string; + this->_option = option; + this->_mandatory = mandatory; + this->_option = option; + this->_position = position; + } + const char* name() const { return _name; } + const char* description() const { return _description; } + const char* type() const { return _type; } + const char* default_string() const { return _default_string; } + bool is_mandatory() const { return _mandatory; } + bool is_option() const { return _option; } + int position() const { return _position; } +}; + +// The DCmdParser class can be used to create an argument parser for a +// diagnostic command. It is not mandatory to use it to parse arguments. +class DCmdParser { +private: + GenDCmdArgument* _options; + GenDCmdArgument* _arguments_list; + char _delim; +public: + DCmdParser() { + _options = NULL; + _arguments_list = NULL; + } + void add_dcmd_option(GenDCmdArgument* arg); + void add_dcmd_argument(GenDCmdArgument* arg); + GenDCmdArgument* lookup_dcmd_option(const char* name, size_t len); + GenDCmdArgument* arguments_list() { return _arguments_list; }; + void check(TRAPS); + void parse(CmdLine* line, char delim, TRAPS); + void print_help(outputStream* out, const char* cmd_name); + void reset(TRAPS); + void cleanup(); + int num_arguments(); + GrowableArray<const char*>* argument_name_array(); + GrowableArray<DCmdArgumentInfo*>* argument_info_array(); +}; + +// The DCmd class is the parent class of all diagnostic commands +// Diagnostic command instances should not be instantiated directly but +// created using the associated factory. The factory can be retrieved with +// the DCmdFactory::getFactory() method. +// A diagnostic command instance can either be allocated in the resource Area +// or in the C-heap. Allocation in the resource area is recommended when the +// current thread is the only one which will access the diagnostic command +// instance. Allocation in the C-heap is required when the diagnostic command +// is accessed by several threads (for instance to perform asynchronous +// execution). +// To ensure a proper cleanup, it's highly recommended to use a DCmdMark for +// each diagnostic command instance. In case of a C-heap allocated diagnostic +// command instance, the DCmdMark must be created in the context of the last +// thread that will access the instance. +class DCmd : public ResourceObj { +protected: + outputStream* _output; + bool _is_heap_allocated; +public: + DCmd(outputStream* output, bool heap_allocated) { + _output = output; + _is_heap_allocated = heap_allocated; + } + + static const char* name() { return "No Name";} + static const char* description() { return "No Help";} + static const char* disabled_message() { return "Diagnostic command currently disabled"; } + static const char* impact() { return "Low: No impact"; } + static int num_arguments() { return 0; } + outputStream* output() { return _output; } + bool is_heap_allocated() { return _is_heap_allocated; } + virtual void print_help(outputStream* out) { }; + virtual void parse(CmdLine* line, char delim, TRAPS) { } + virtual void execute(TRAPS) { } + virtual void reset(TRAPS) { } + virtual void cleanup() { } + + // support for the JMX interface + virtual GrowableArray<const char*>* argument_name_array() { + GrowableArray<const char*>* array = new GrowableArray<const char*>(0); + return array; + } + virtual GrowableArray<DCmdArgumentInfo*>* argument_info_array() { + GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo*>(0); + return array; + } + + // main method to invoke the framework + static void parse_and_execute(outputStream* out, const char* cmdline, + char delim, TRAPS); +}; + +class DCmdMark : public StackObj { + DCmd* _ref; +public: + DCmdMark(DCmd* cmd) { _ref = cmd; } + ~DCmdMark() { + if (_ref != NULL) { + _ref->cleanup(); + if (_ref->is_heap_allocated()) { + delete _ref; + } + } + } +}; + +// Diagnostic commands are not directly instantiated but created with a factory. +// Each diagnostic command class has its own factory. The DCmdFactory class also +// manages the status of the diagnostic command (hidden, enabled). A DCmdFactory +// has to be registered to make the diagnostic command available (see +// management.cpp) +class DCmdFactory: public CHeapObj { +private: + static Mutex* _dcmdFactory_lock; + // Pointer to the next factory in the singly-linked list of registered + // diagnostic commands + DCmdFactory* _next; + // When disabled, a diagnostic command cannot be executed. Any attempt to + // execute it will result in the printing of the disabled message without + // instantiating the command. + bool _enabled; + // When hidden, a diagnostic command doesn't appear in the list of commands + // provided by the 'help' command. + bool _hidden; + int _num_arguments; + static DCmdFactory* _DCmdFactoryList; +public: + DCmdFactory(int num_arguments, bool enabled, bool hidden) { + _next = NULL; + _enabled = enabled; + _hidden = hidden; + _num_arguments = num_arguments; + } + bool is_enabled() const { return _enabled; } + void set_enabled(bool b) { _enabled = b; } + bool is_hidden() const { return _hidden; } + void set_hidden(bool b) { _hidden = b; } + int num_arguments() { return _num_arguments; } + DCmdFactory* next() { return _next; } + virtual DCmd* create_Cheap_instance(outputStream* output) = 0; + virtual DCmd* create_resource_instance(outputStream* output) = 0; + virtual const char* name() const = 0; + virtual const char* description() const = 0; + virtual const char* impact() const = 0; + virtual const char* disabled_message() const = 0; + // Register a DCmdFactory to make a diagnostic command available. + // Once registered, a diagnostic command must not be unregistered. + // To prevent a diagnostic command from being executed, just set the + // enabled flag to false. + static int register_DCmdFactory(DCmdFactory* factory); + static DCmdFactory* factory(const char* cmd, size_t len); + // Returns a C-heap allocated diagnostic command for the given command line + static DCmd* create_global_DCmd(CmdLine &line, outputStream* out, TRAPS); + // Returns a resourceArea allocated diagnostic command for the given command line + static DCmd* create_local_DCmd(CmdLine &line, outputStream* out, TRAPS); + static GrowableArray<const char*>* DCmd_list(); + static GrowableArray<DCmdInfo*>* DCmdInfo_list(); + + friend class HelpDCmd; +}; + +// Template to easily create DCmdFactory instances. See management.cpp +// where this template is used to create and register factories. +template <class DCmdClass> class DCmdFactoryImpl : public DCmdFactory { +public: + DCmdFactoryImpl(bool enabled, bool hidden) : + DCmdFactory(DCmdClass::num_arguments(), enabled, hidden) { } + // Returns a C-heap allocated instance + virtual DCmd* create_Cheap_instance(outputStream* output) { + return new (ResourceObj::C_HEAP) DCmdClass(output, true); + } + // Returns a resourceArea allocated instance + virtual DCmd* create_resource_instance(outputStream* output) { + return new DCmdClass(output, false); + } + virtual const char* name() const { + return DCmdClass::name(); + } + virtual const char* description() const { + return DCmdClass::description(); + } + virtual const char* impact() const { + return DCmdClass::impact(); + } + virtual const char* disabled_message() const { + return DCmdClass::disabled_message(); + } +}; + +#endif // SHARE_VM_SERVICES_DIAGNOSTICFRAMEWORK_HPP
--- a/src/share/vm/services/jmm.h Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/services/jmm.h Thu Dec 29 11:37:50 2011 -0800 @@ -48,7 +48,8 @@ JMM_VERSION_1_0 = 0x20010000, JMM_VERSION_1_1 = 0x20010100, // JDK 6 JMM_VERSION_1_2 = 0x20010200, // JDK 7 - JMM_VERSION = 0x20010201 + JMM_VERSION_1_2_1 = 0x20010201, // JDK 7 GA + JMM_VERSION = 0x20010202 }; typedef struct { @@ -188,6 +189,24 @@ /* -1 indicates gc_ext_attribute_values is not big enough */ } jmmGCStat; +typedef struct { + const char* name; + const char* description; + const char* impact; + int num_arguments; + jboolean enabled; +} dcmdInfo; + +typedef struct { + const char* name; + const char* description; + const char* type; + const char* default_string; + jboolean mandatory; + jboolean option; + int position; +} dcmdArgInfo; + typedef struct jmmInterface_1_ { void* reserved1; void* reserved2; @@ -296,6 +315,18 @@ void (JNICALL *SetGCNotificationEnabled) (JNIEnv *env, jobject mgr, jboolean enabled); + jobjectArray (JNICALL *GetDiagnosticCommands) (JNIEnv *env); + void (JNICALL *GetDiagnosticCommandInfo) + (JNIEnv *env, + jobjectArray cmds, + dcmdInfo *infoArray); + void (JNICALL *GetDiagnosticCommandArgumentsInfo) + (JNIEnv *env, + jstring commandName, + dcmdArgInfo *infoArray); + jstring (JNICALL *ExecuteDiagnosticCommand) + (JNIEnv *env, + jstring command); } JmmInterface; #ifdef __cplusplus
--- a/src/share/vm/services/management.cpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/services/management.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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" @@ -40,7 +41,10 @@ #include "runtime/os.hpp" #include "runtime/serviceThread.hpp" #include "services/classLoadingService.hpp" +#include "services/diagnosticCommand.hpp" +#include "services/diagnosticFramework.hpp" #include "services/heapDumper.hpp" +#include "services/jmm.h" #include "services/lowMemoryDetector.hpp" #include "services/gcNotifier.hpp" #include "services/management.hpp" @@ -113,6 +117,9 @@ _optional_support.isSynchronizerUsageSupported = 1; #endif // SERVICES_KERNEL _optional_support.isThreadAllocatedMemorySupported = 1; + + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(true, false)); + DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(true, false)); } void Management::initialize(TRAPS) { @@ -2107,6 +2114,122 @@ #endif // SERVICES_KERNEL JVM_END +JVM_ENTRY(jobjectArray, jmm_GetDiagnosticCommands(JNIEnv *env)) + ResourceMark rm(THREAD); + GrowableArray<const char *>* dcmd_list = DCmdFactory::DCmd_list(); + objArrayOop cmd_array_oop = oopFactory::new_objArray(SystemDictionary::String_klass(), + dcmd_list->length(), CHECK_NULL); + objArrayHandle cmd_array(THREAD, cmd_array_oop); + for (int i = 0; i < dcmd_list->length(); i++) { + oop cmd_name = java_lang_String::create_oop_from_str(dcmd_list->at(i), CHECK_NULL); + cmd_array->obj_at_put(i, cmd_name); + } + return (jobjectArray) JNIHandles::make_local(env, cmd_array()); +JVM_END + +JVM_ENTRY(void, jmm_GetDiagnosticCommandInfo(JNIEnv *env, jobjectArray cmds, + dcmdInfo* infoArray)) + if (cmds == NULL || infoArray == NULL) { + THROW(vmSymbols::java_lang_NullPointerException()); + } + + ResourceMark rm(THREAD); + + objArrayOop ca = objArrayOop(JNIHandles::resolve_non_null(cmds)); + objArrayHandle cmds_ah(THREAD, ca); + + // Make sure we have a String array + klassOop element_klass = objArrayKlass::cast(cmds_ah->klass())->element_klass(); + if (element_klass != SystemDictionary::String_klass()) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Array element type is not String class"); + } + + GrowableArray<DCmdInfo *>* info_list = DCmdFactory::DCmdInfo_list(); + + int num_cmds = cmds_ah->length(); + for (int i = 0; i < num_cmds; i++) { + oop cmd = cmds_ah->obj_at(i); + if (cmd == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "Command name cannot be null."); + } + char* cmd_name = java_lang_String::as_utf8_string(cmd); + if (cmd_name == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "Command name cannot be null."); + } + int pos = info_list->find((void*)cmd_name,DCmdInfo::by_name); + if (pos == -1) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Unknown diagnostic command"); + } + DCmdInfo* info = info_list->at(pos); + infoArray[i].name = info->name(); + infoArray[i].description = info->description(); + infoArray[i].impact = info->impact(); + infoArray[i].num_arguments = info->num_arguments(); + infoArray[i].enabled = info->is_enabled(); + } +JVM_END + +JVM_ENTRY(void, jmm_GetDiagnosticCommandArgumentsInfo(JNIEnv *env, + jstring command, dcmdArgInfo* infoArray)) + ResourceMark rm(THREAD); + oop cmd = JNIHandles::resolve_external_guard(command); + if (cmd == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "Command line cannot be null."); + } + char* cmd_name = java_lang_String::as_utf8_string(cmd); + if (cmd_name == NULL) { + THROW_MSG(vmSymbols::java_lang_NullPointerException(), + "Command line content cannot be null."); + } + DCmd* dcmd = NULL; + DCmdFactory*factory = DCmdFactory::factory(cmd_name, strlen(cmd_name)); + if (factory != NULL) { + dcmd = factory->create_resource_instance(NULL); + } + if (dcmd == NULL) { + THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), + "Unknown diagnostic command"); + } + DCmdMark mark(dcmd); + GrowableArray<DCmdArgumentInfo*>* array = dcmd->argument_info_array(); + if (array->length() == 0) { + return; + } + for (int i = 0; i < array->length(); i++) { + infoArray[i].name = array->at(i)->name(); + infoArray[i].description = array->at(i)->description(); + infoArray[i].type = array->at(i)->type(); + infoArray[i].default_string = array->at(i)->default_string(); + infoArray[i].mandatory = array->at(i)->is_mandatory(); + infoArray[i].option = array->at(i)->is_option(); + infoArray[i].position = array->at(i)->position(); + } + return; +JVM_END + +JVM_ENTRY(jstring, jmm_ExecuteDiagnosticCommand(JNIEnv *env, jstring commandline)) + ResourceMark rm(THREAD); + oop cmd = JNIHandles::resolve_external_guard(commandline); + if (cmd == NULL) { + THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), + "Command line cannot be null."); + } + char* cmdline = java_lang_String::as_utf8_string(cmd); + if (cmdline == NULL) { + THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(), + "Command line content cannot be null."); + } + bufferedStream output; + DCmd::parse_and_execute(&output, cmdline, ' ', CHECK_NULL); + oop result = java_lang_String::create_oop_from_str(output.as_string(), CHECK_NULL); + return (jstring) JNIHandles::make_local(env, result); +JVM_END + jlong Management::ticks_to_ms(jlong ticks) { assert(os::elapsed_frequency() > 0, "Must be non-zero"); return (jlong)(((double)ticks / (double)os::elapsed_frequency()) @@ -2149,7 +2272,11 @@ jmm_SetVMGlobal, NULL, jmm_DumpThreads, - jmm_SetGCNotificationEnabled + jmm_SetGCNotificationEnabled, + jmm_GetDiagnosticCommands, + jmm_GetDiagnosticCommandInfo, + jmm_GetDiagnosticCommandArgumentsInfo, + jmm_ExecuteDiagnosticCommand }; void* Management::get_jmm_interface(int version) {
--- a/src/share/vm/utilities/globalDefinitions.hpp Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/globalDefinitions.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/ostream.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/quickSort.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/quickSort.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/workgroup.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/workgroup.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/yieldingWorkgroup.cpp Thu Dec 29 11:37:50 2011 -0800 @@ -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 Tue Dec 27 15:08:43 2011 -0800 +++ b/src/share/vm/utilities/yieldingWorkgroup.hpp Thu Dec 29 11:37:50 2011 -0800 @@ -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; }