--- a/hotspot/make/bsd/makefiles/gcc.make Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/make/bsd/makefiles/gcc.make Wed Sep 18 12:52:15 2013 -0400
@@ -80,7 +80,7 @@
HOSTCC = $(CC)
endif
- AS = $(CC) -c -x assembler-with-cpp
+ AS = $(CC) -c
endif
@@ -347,6 +347,13 @@
LDFLAGS += -mmacosx-version-min=$(MACOSX_VERSION_MIN)
endif
+
+#------------------------------------------------------------------------
+# Assembler flags
+
+# Enforce prerpocessing of .s files
+ASFLAGS += -x assembler-with-cpp
+
#------------------------------------------------------------------------
# Linker flags
--- a/hotspot/src/os/linux/vm/os_linux.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -131,6 +131,7 @@
bool os::Linux::_supports_fast_thread_cpu_time = false;
const char * os::Linux::_glibc_version = NULL;
const char * os::Linux::_libpthread_version = NULL;
+pthread_condattr_t os::Linux::_condattr[1];
static jlong initial_time_count=0;
@@ -1399,12 +1400,15 @@
clock_gettime_func(CLOCK_MONOTONIC, &tp) == 0) {
// yes, monotonic clock is supported
_clock_gettime = clock_gettime_func;
+ return;
} else {
// close librt if there is no monotonic clock
dlclose(handle);
}
}
}
+ warning("No monotonic clock was available - timed services may " \
+ "be adversely affected if the time-of-day clock changes");
}
#ifndef SYS_clock_getres
@@ -2165,23 +2169,49 @@
}
// Try to identify popular distros.
-// Most Linux distributions have /etc/XXX-release file, which contains
-// the OS version string. Some have more than one /etc/XXX-release file
-// (e.g. Mandrake has both /etc/mandrake-release and /etc/redhat-release.),
-// so the order is important.
+// Most Linux distributions have a /etc/XXX-release file, which contains
+// the OS version string. Newer Linux distributions have a /etc/lsb-release
+// file that also contains the OS version string. Some have more than one
+// /etc/XXX-release file (e.g. Mandrake has both /etc/mandrake-release and
+// /etc/redhat-release.), so the order is important.
+// Any Linux that is based on Redhat (i.e. Oracle, Mandrake, Sun JDS...) have
+// their own specific XXX-release file as well as a redhat-release file.
+// Because of this the XXX-release file needs to be searched for before the
+// redhat-release file.
+// Since Red Hat has a lsb-release file that is not very descriptive the
+// search for redhat-release needs to be before lsb-release.
+// Since the lsb-release file is the new standard it needs to be searched
+// before the older style release files.
+// Searching system-release (Red Hat) and os-release (other Linuxes) are a
+// next to last resort. The os-release file is a new standard that contains
+// distribution information and the system-release file seems to be an old
+// standard that has been replaced by the lsb-release and os-release files.
+// Searching for the debian_version file is the last resort. It contains
+// an informative string like "6.0.6" or "wheezy/sid". Because of this
+// "Debian " is printed before the contents of the debian_version file.
void os::Linux::print_distro_info(outputStream* st) {
- if (!_print_ascii_file("/etc/mandrake-release", st) &&
- !_print_ascii_file("/etc/sun-release", st) &&
- !_print_ascii_file("/etc/redhat-release", st) &&
- !_print_ascii_file("/etc/SuSE-release", st) &&
- !_print_ascii_file("/etc/turbolinux-release", st) &&
- !_print_ascii_file("/etc/gentoo-release", st) &&
- !_print_ascii_file("/etc/debian_version", st) &&
- !_print_ascii_file("/etc/ltib-release", st) &&
- !_print_ascii_file("/etc/angstrom-version", st)) {
- st->print("Linux");
- }
- st->cr();
+ if (!_print_ascii_file("/etc/oracle-release", st) &&
+ !_print_ascii_file("/etc/mandriva-release", st) &&
+ !_print_ascii_file("/etc/mandrake-release", st) &&
+ !_print_ascii_file("/etc/sun-release", st) &&
+ !_print_ascii_file("/etc/redhat-release", st) &&
+ !_print_ascii_file("/etc/lsb-release", st) &&
+ !_print_ascii_file("/etc/SuSE-release", st) &&
+ !_print_ascii_file("/etc/turbolinux-release", st) &&
+ !_print_ascii_file("/etc/gentoo-release", st) &&
+ !_print_ascii_file("/etc/ltib-release", st) &&
+ !_print_ascii_file("/etc/angstrom-version", st) &&
+ !_print_ascii_file("/etc/system-release", st) &&
+ !_print_ascii_file("/etc/os-release", st)) {
+
+ if (file_exists("/etc/debian_version")) {
+ st->print("Debian ");
+ _print_ascii_file("/etc/debian_version", st);
+ } else {
+ st->print("Linux");
+ }
+ }
+ st->cr();
}
void os::Linux::print_libversion_info(outputStream* st) {
@@ -4709,6 +4739,26 @@
Linux::clock_init();
initial_time_count = os::elapsed_counter();
+
+ // pthread_condattr initialization for monotonic clock
+ int status;
+ pthread_condattr_t* _condattr = os::Linux::condAttr();
+ if ((status = pthread_condattr_init(_condattr)) != 0) {
+ fatal(err_msg("pthread_condattr_init: %s", strerror(status)));
+ }
+ // Only set the clock if CLOCK_MONOTONIC is available
+ if (Linux::supports_monotonic_clock()) {
+ if ((status = pthread_condattr_setclock(_condattr, CLOCK_MONOTONIC)) != 0) {
+ if (status == EINVAL) {
+ warning("Unable to use monotonic clock with relative timed-waits" \
+ " - changes to the time-of-day clock may have adverse affects");
+ } else {
+ fatal(err_msg("pthread_condattr_setclock: %s", strerror(status)));
+ }
+ }
+ }
+ // else it defaults to CLOCK_REALTIME
+
pthread_mutex_init(&dl_mutex, NULL);
// If the pagesize of the VM is greater than 8K determine the appropriate
@@ -5519,21 +5569,36 @@
static struct timespec* compute_abstime(timespec* abstime, jlong millis) {
if (millis < 0) millis = 0;
- struct timeval now;
- int status = gettimeofday(&now, NULL);
- assert(status == 0, "gettimeofday");
+
jlong seconds = millis / 1000;
millis %= 1000;
if (seconds > 50000000) { // see man cond_timedwait(3T)
seconds = 50000000;
}
- abstime->tv_sec = now.tv_sec + seconds;
- long usec = now.tv_usec + millis * 1000;
- if (usec >= 1000000) {
- abstime->tv_sec += 1;
- usec -= 1000000;
- }
- abstime->tv_nsec = usec * 1000;
+
+ if (os::Linux::supports_monotonic_clock()) {
+ struct timespec now;
+ int status = os::Linux::clock_gettime(CLOCK_MONOTONIC, &now);
+ assert_status(status == 0, status, "clock_gettime");
+ abstime->tv_sec = now.tv_sec + seconds;
+ long nanos = now.tv_nsec + millis * NANOSECS_PER_MILLISEC;
+ if (nanos >= NANOSECS_PER_SEC) {
+ abstime->tv_sec += 1;
+ nanos -= NANOSECS_PER_SEC;
+ }
+ abstime->tv_nsec = nanos;
+ } else {
+ struct timeval now;
+ int status = gettimeofday(&now, NULL);
+ assert(status == 0, "gettimeofday");
+ abstime->tv_sec = now.tv_sec + seconds;
+ long usec = now.tv_usec + millis * 1000;
+ if (usec >= 1000000) {
+ abstime->tv_sec += 1;
+ usec -= 1000000;
+ }
+ abstime->tv_nsec = usec * 1000;
+ }
return abstime;
}
@@ -5625,7 +5690,7 @@
status = os::Linux::safe_cond_timedwait(_cond, _mutex, &abst);
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
pthread_cond_destroy (_cond);
- pthread_cond_init (_cond, NULL) ;
+ pthread_cond_init (_cond, os::Linux::condAttr()) ;
}
assert_status(status == 0 || status == EINTR ||
status == ETIME || status == ETIMEDOUT,
@@ -5726,32 +5791,50 @@
static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) {
assert (time > 0, "convertTime");
-
- struct timeval now;
- int status = gettimeofday(&now, NULL);
- assert(status == 0, "gettimeofday");
-
- time_t max_secs = now.tv_sec + MAX_SECS;
-
- if (isAbsolute) {
- jlong secs = time / 1000;
- if (secs > max_secs) {
- absTime->tv_sec = max_secs;
+ time_t max_secs = 0;
+
+ if (!os::Linux::supports_monotonic_clock() || isAbsolute) {
+ struct timeval now;
+ int status = gettimeofday(&now, NULL);
+ assert(status == 0, "gettimeofday");
+
+ max_secs = now.tv_sec + MAX_SECS;
+
+ if (isAbsolute) {
+ jlong secs = time / 1000;
+ if (secs > max_secs) {
+ absTime->tv_sec = max_secs;
+ } else {
+ absTime->tv_sec = secs;
+ }
+ absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC;
+ } else {
+ jlong secs = time / NANOSECS_PER_SEC;
+ if (secs >= MAX_SECS) {
+ absTime->tv_sec = max_secs;
+ absTime->tv_nsec = 0;
+ } else {
+ absTime->tv_sec = now.tv_sec + secs;
+ absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000;
+ if (absTime->tv_nsec >= NANOSECS_PER_SEC) {
+ absTime->tv_nsec -= NANOSECS_PER_SEC;
+ ++absTime->tv_sec; // note: this must be <= max_secs
+ }
+ }
}
- else {
- absTime->tv_sec = secs;
- }
- absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC;
- }
- else {
+ } else {
+ // must be relative using monotonic clock
+ struct timespec now;
+ int status = os::Linux::clock_gettime(CLOCK_MONOTONIC, &now);
+ assert_status(status == 0, status, "clock_gettime");
+ max_secs = now.tv_sec + MAX_SECS;
jlong secs = time / NANOSECS_PER_SEC;
if (secs >= MAX_SECS) {
absTime->tv_sec = max_secs;
absTime->tv_nsec = 0;
- }
- else {
+ } else {
absTime->tv_sec = now.tv_sec + secs;
- absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000;
+ absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_nsec;
if (absTime->tv_nsec >= NANOSECS_PER_SEC) {
absTime->tv_nsec -= NANOSECS_PER_SEC;
++absTime->tv_sec; // note: this must be <= max_secs
@@ -5831,15 +5914,19 @@
jt->set_suspend_equivalent();
// cleared by handle_special_suspend_equivalent_condition() or java_suspend_self()
+ assert(_cur_index == -1, "invariant");
if (time == 0) {
- status = pthread_cond_wait (_cond, _mutex) ;
+ _cur_index = REL_INDEX; // arbitrary choice when not timed
+ status = pthread_cond_wait (&_cond[_cur_index], _mutex) ;
} else {
- status = os::Linux::safe_cond_timedwait (_cond, _mutex, &absTime) ;
+ _cur_index = isAbsolute ? ABS_INDEX : REL_INDEX;
+ status = os::Linux::safe_cond_timedwait (&_cond[_cur_index], _mutex, &absTime) ;
if (status != 0 && WorkAroundNPTLTimedWaitHang) {
- pthread_cond_destroy (_cond) ;
- pthread_cond_init (_cond, NULL);
+ pthread_cond_destroy (&_cond[_cur_index]) ;
+ pthread_cond_init (&_cond[_cur_index], isAbsolute ? NULL : os::Linux::condAttr());
}
}
+ _cur_index = -1;
assert_status(status == 0 || status == EINTR ||
status == ETIME || status == ETIMEDOUT,
status, "cond_timedwait");
@@ -5868,17 +5955,24 @@
s = _counter;
_counter = 1;
if (s < 1) {
- if (WorkAroundNPTLTimedWaitHang) {
- status = pthread_cond_signal (_cond) ;
- assert (status == 0, "invariant") ;
+ // thread might be parked
+ if (_cur_index != -1) {
+ // thread is definitely parked
+ if (WorkAroundNPTLTimedWaitHang) {
+ status = pthread_cond_signal (&_cond[_cur_index]);
+ assert (status == 0, "invariant");
status = pthread_mutex_unlock(_mutex);
- assert (status == 0, "invariant") ;
- } else {
+ assert (status == 0, "invariant");
+ } else {
status = pthread_mutex_unlock(_mutex);
- assert (status == 0, "invariant") ;
- status = pthread_cond_signal (_cond) ;
- assert (status == 0, "invariant") ;
- }
+ assert (status == 0, "invariant");
+ status = pthread_cond_signal (&_cond[_cur_index]);
+ assert (status == 0, "invariant");
+ }
+ } else {
+ pthread_mutex_unlock(_mutex);
+ assert (status == 0, "invariant") ;
+ }
} else {
pthread_mutex_unlock(_mutex);
assert (status == 0, "invariant") ;
--- a/hotspot/src/os/linux/vm/os_linux.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/os/linux/vm/os_linux.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -221,6 +221,13 @@
static jlong fast_thread_cpu_time(clockid_t clockid);
+ // pthread_cond clock suppport
+ private:
+ static pthread_condattr_t _condattr[1];
+
+ public:
+ static pthread_condattr_t* condAttr() { return _condattr; }
+
// Stack repair handling
// none present
@@ -295,7 +302,7 @@
public:
PlatformEvent() {
int status;
- status = pthread_cond_init (_cond, NULL);
+ status = pthread_cond_init (_cond, os::Linux::condAttr());
assert_status(status == 0, status, "cond_init");
status = pthread_mutex_init (_mutex, NULL);
assert_status(status == 0, status, "mutex_init");
@@ -310,14 +317,19 @@
void park () ;
void unpark () ;
int TryPark () ;
- int park (jlong millis) ;
+ int park (jlong millis) ; // relative timed-wait only
void SetAssociation (Thread * a) { _Assoc = a ; }
} ;
class PlatformParker : public CHeapObj<mtInternal> {
protected:
+ enum {
+ REL_INDEX = 0,
+ ABS_INDEX = 1
+ };
+ int _cur_index; // which cond is in use: -1, 0, 1
pthread_mutex_t _mutex [1] ;
- pthread_cond_t _cond [1] ;
+ pthread_cond_t _cond [2] ; // one for relative times and one for abs.
public: // TODO-FIXME: make dtor private
~PlatformParker() { guarantee (0, "invariant") ; }
@@ -325,10 +337,13 @@
public:
PlatformParker() {
int status;
- status = pthread_cond_init (_cond, NULL);
- assert_status(status == 0, status, "cond_init");
+ status = pthread_cond_init (&_cond[REL_INDEX], os::Linux::condAttr());
+ assert_status(status == 0, status, "cond_init rel");
+ status = pthread_cond_init (&_cond[ABS_INDEX], NULL);
+ assert_status(status == 0, status, "cond_init abs");
status = pthread_mutex_init (_mutex, NULL);
assert_status(status == 0, status, "mutex_init");
+ _cur_index = -1; // mark as unused
}
};
--- a/hotspot/src/os/windows/vm/decoder_windows.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/os/windows/vm/decoder_windows.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -32,7 +32,11 @@
_can_decode_in_vm = false;
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
-
+#ifdef AMD64
+ _pfnStackWalk64 = NULL;
+ _pfnSymFunctionTableAccess64 = NULL;
+ _pfnSymGetModuleBase64 = NULL;
+#endif
_decoder_status = no_error;
initialize();
}
@@ -53,14 +57,24 @@
_pfnUndecorateSymbolName = (pfn_UndecorateSymbolName)::GetProcAddress(handle, "UnDecorateSymbolName");
if (_pfnSymSetOptions == NULL || _pfnSymInitialize == NULL || _pfnSymGetSymFromAddr64 == NULL) {
- _pfnSymGetSymFromAddr64 = NULL;
- _pfnUndecorateSymbolName = NULL;
- ::FreeLibrary(handle);
- _dbghelp_handle = NULL;
+ uninitialize();
_decoder_status = helper_func_error;
return;
}
+#ifdef AMD64
+ _pfnStackWalk64 = (pfn_StackWalk64)::GetProcAddress(handle, "StackWalk64");
+ _pfnSymFunctionTableAccess64 = (pfn_SymFunctionTableAccess64)::GetProcAddress(handle, "SymFunctionTableAccess64");
+ _pfnSymGetModuleBase64 = (pfn_SymGetModuleBase64)::GetProcAddress(handle, "SymGetModuleBase64");
+ if (_pfnStackWalk64 == NULL || _pfnSymFunctionTableAccess64 == NULL || _pfnSymGetModuleBase64 == NULL) {
+ // We can't call StackWalk64 to walk the stack, but we are still
+ // able to decode the symbols. Let's limp on.
+ _pfnStackWalk64 = NULL;
+ _pfnSymFunctionTableAccess64 = NULL;
+ _pfnSymGetModuleBase64 = NULL;
+ }
+#endif
+
HANDLE hProcess = ::GetCurrentProcess();
_pfnSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS | SYMOPT_EXACT_SYMBOLS);
if (!_pfnSymInitialize(hProcess, NULL, TRUE)) {
@@ -156,6 +170,11 @@
void WindowsDecoder::uninitialize() {
_pfnSymGetSymFromAddr64 = NULL;
_pfnUndecorateSymbolName = NULL;
+#ifdef AMD64
+ _pfnStackWalk64 = NULL;
+ _pfnSymFunctionTableAccess64 = NULL;
+ _pfnSymGetModuleBase64 = NULL;
+#endif
if (_dbghelp_handle != NULL) {
::FreeLibrary(_dbghelp_handle);
}
@@ -195,3 +214,65 @@
_pfnUndecorateSymbolName(symbol, buf, buflen, UNDNAME_COMPLETE);
}
+#ifdef AMD64
+BOOL WindowsDbgHelp::StackWalk64(DWORD MachineType,
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPSTACKFRAME64 StackFrame,
+ PVOID ContextRecord,
+ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress) {
+ DecoderLocker locker;
+ WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
+
+ if (!wd->has_error() && wd->_pfnStackWalk64) {
+ return wd->_pfnStackWalk64(MachineType,
+ hProcess,
+ hThread,
+ StackFrame,
+ ContextRecord,
+ ReadMemoryRoutine,
+ FunctionTableAccessRoutine,
+ GetModuleBaseRoutine,
+ TranslateAddress);
+ } else {
+ return false;
+ }
+}
+
+PVOID WindowsDbgHelp::SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase) {
+ DecoderLocker locker;
+ WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
+
+ if (!wd->has_error() && wd->_pfnSymFunctionTableAccess64) {
+ return wd->_pfnSymFunctionTableAccess64(hProcess, AddrBase);
+ } else {
+ return NULL;
+ }
+}
+
+pfn_SymFunctionTableAccess64 WindowsDbgHelp::pfnSymFunctionTableAccess64() {
+ DecoderLocker locker;
+ WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
+
+ if (!wd->has_error()) {
+ return wd->_pfnSymFunctionTableAccess64;
+ } else {
+ return NULL;
+ }
+}
+
+pfn_SymGetModuleBase64 WindowsDbgHelp::pfnSymGetModuleBase64() {
+ DecoderLocker locker;
+ WindowsDecoder* wd = (WindowsDecoder*)locker.decoder();
+
+ if (!wd->has_error()) {
+ return wd->_pfnSymGetModuleBase64;
+ } else {
+ return NULL;
+ }
+}
+
+#endif // AMD64
--- a/hotspot/src/os/windows/vm/decoder_windows.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/os/windows/vm/decoder_windows.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -38,6 +38,20 @@
typedef BOOL (WINAPI *pfn_SymSetSearchPath)(HANDLE, PCTSTR);
typedef BOOL (WINAPI *pfn_SymGetSearchPath)(HANDLE, PTSTR, int);
+#ifdef AMD64
+typedef BOOL (WINAPI *pfn_StackWalk64)(DWORD MachineType,
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPSTACKFRAME64 StackFrame,
+ PVOID ContextRecord,
+ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
+typedef PVOID (WINAPI *pfn_SymFunctionTableAccess64)(HANDLE hProcess, DWORD64 AddrBase);
+typedef DWORD64 (WINAPI *pfn_SymGetModuleBase64)(HANDLE hProcess, DWORD64 dwAddr);
+#endif
+
class WindowsDecoder : public AbstractDecoder {
public:
@@ -61,7 +75,34 @@
bool _can_decode_in_vm;
pfn_SymGetSymFromAddr64 _pfnSymGetSymFromAddr64;
pfn_UndecorateSymbolName _pfnUndecorateSymbolName;
+#ifdef AMD64
+ pfn_StackWalk64 _pfnStackWalk64;
+ pfn_SymFunctionTableAccess64 _pfnSymFunctionTableAccess64;
+ pfn_SymGetModuleBase64 _pfnSymGetModuleBase64;
+
+ friend class WindowsDbgHelp;
+#endif
};
+#ifdef AMD64
+// TODO: refactor and move the handling of dbghelp.dll outside of Decoder
+class WindowsDbgHelp : public Decoder {
+public:
+ static BOOL StackWalk64(DWORD MachineType,
+ HANDLE hProcess,
+ HANDLE hThread,
+ LPSTACKFRAME64 StackFrame,
+ PVOID ContextRecord,
+ PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+ PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+ PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+ PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
+ static PVOID SymFunctionTableAccess64(HANDLE hProcess, DWORD64 AddrBase);
+
+ static pfn_SymFunctionTableAccess64 pfnSymFunctionTableAccess64();
+ static pfn_SymGetModuleBase64 pfnSymGetModuleBase64();
+};
+#endif
+
#endif // OS_WINDOWS_VM_DECODER_WINDOWS_HPP
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -29,6 +29,7 @@
#include "classfile/vmSymbols.hpp"
#include "code/icBuffer.hpp"
#include "code/vtableStubs.hpp"
+#include "decoder_windows.hpp"
#include "interpreter/interpreter.hpp"
#include "jvm_windows.h"
#include "memory/allocation.inline.hpp"
@@ -327,6 +328,94 @@
cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap;
+#ifdef AMD64
+/*
+ * Windows/x64 does not use stack frames the way expected by Java:
+ * [1] in most cases, there is no frame pointer. All locals are addressed via RSP
+ * [2] in rare cases, when alloca() is used, a frame pointer is used, but this may
+ * not be RBP.
+ * See http://msdn.microsoft.com/en-us/library/ew5tede7.aspx
+ *
+ * So it's not possible to print the native stack using the
+ * while (...) {... fr = os::get_sender_for_C_frame(&fr); }
+ * loop in vmError.cpp. We need to roll our own loop.
+ */
+bool os::platform_print_native_stack(outputStream* st, void* context,
+ char *buf, int buf_size)
+{
+ CONTEXT ctx;
+ if (context != NULL) {
+ memcpy(&ctx, context, sizeof(ctx));
+ } else {
+ RtlCaptureContext(&ctx);
+ }
+
+ st->print_cr("Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)");
+
+ STACKFRAME stk;
+ memset(&stk, 0, sizeof(stk));
+ stk.AddrStack.Offset = ctx.Rsp;
+ stk.AddrStack.Mode = AddrModeFlat;
+ stk.AddrFrame.Offset = ctx.Rbp;
+ stk.AddrFrame.Mode = AddrModeFlat;
+ stk.AddrPC.Offset = ctx.Rip;
+ stk.AddrPC.Mode = AddrModeFlat;
+
+ int count = 0;
+ address lastpc = 0;
+ while (count++ < StackPrintLimit) {
+ intptr_t* sp = (intptr_t*)stk.AddrStack.Offset;
+ intptr_t* fp = (intptr_t*)stk.AddrFrame.Offset; // NOT necessarily the same as ctx.Rbp!
+ address pc = (address)stk.AddrPC.Offset;
+
+ if (pc != NULL && sp != NULL && fp != NULL) {
+ if (count == 2 && lastpc == pc) {
+ // Skip it -- StackWalk64() may return the same PC
+ // (but different SP) on the first try.
+ } else {
+ // Don't try to create a frame(sp, fp, pc) -- on WinX64, stk.AddrFrame
+ // may not contain what Java expects, and may cause the frame() constructor
+ // to crash. Let's just print out the symbolic address.
+ frame::print_C_frame(st, buf, buf_size, pc);
+ st->cr();
+ }
+ lastpc = pc;
+ } else {
+ break;
+ }
+
+ PVOID p = WindowsDbgHelp::SymFunctionTableAccess64(GetCurrentProcess(), stk.AddrPC.Offset);
+ if (!p) {
+ // StackWalk64() can't handle this PC. Calling StackWalk64 again may cause crash.
+ break;
+ }
+
+ BOOL result = WindowsDbgHelp::StackWalk64(
+ IMAGE_FILE_MACHINE_AMD64, // __in DWORD MachineType,
+ GetCurrentProcess(), // __in HANDLE hProcess,
+ GetCurrentThread(), // __in HANDLE hThread,
+ &stk, // __inout LP STACKFRAME64 StackFrame,
+ &ctx, // __inout PVOID ContextRecord,
+ NULL, // __in_opt PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
+ WindowsDbgHelp::pfnSymFunctionTableAccess64(),
+ // __in_opt PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
+ WindowsDbgHelp::pfnSymGetModuleBase64(),
+ // __in_opt PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
+ NULL); // __in_opt PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress
+
+ if (!result) {
+ break;
+ }
+ }
+ if (count > StackPrintLimit) {
+ st->print_cr("...<more frames>...");
+ }
+ st->cr();
+
+ return true;
+}
+#endif // AMD64
+
ExtendedPC os::fetch_frame_from_context(void* ucVoid,
intptr_t** ret_sp, intptr_t** ret_fp) {
@@ -401,6 +490,9 @@
StubRoutines::x86::get_previous_fp_entry());
if (func == NULL) return frame();
intptr_t* fp = (*func)();
+ if (fp == NULL) {
+ return frame();
+ }
#else
intptr_t* fp = _get_previous_fp();
#endif // AMD64
--- a/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/os_cpu/windows_x86/vm/os_windows_x86.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -62,4 +62,10 @@
static bool register_code_area(char *low, char *high);
+#ifdef AMD64
+#define PLATFORM_PRINT_NATIVE_STACK 1
+static bool platform_print_native_stack(outputStream* st, void* context,
+ char *buf, int buf_size);
+#endif
+
#endif // OS_CPU_WINDOWS_X86_VM_OS_WINDOWS_X86_HPP
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -888,6 +888,7 @@
int runtime_visible_type_annotations_length = 0;
u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
+ bool runtime_invisible_type_annotations_exists = false;
while (attributes_count--) {
cfs->guarantee_more(6, CHECK); // attribute_name_index, attribute_length
u2 attribute_name_index = cfs->get_u2_fast();
@@ -946,15 +947,27 @@
assert(runtime_invisible_annotations != NULL, "null invisible annotations");
cfs->skip_u1(runtime_invisible_annotations_length, CHECK);
} else if (attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
+ if (runtime_visible_type_annotations != NULL) {
+ classfile_parse_error(
+ "Multiple RuntimeVisibleTypeAnnotations attributes for field in class file %s", CHECK);
+ }
runtime_visible_type_annotations_length = attribute_length;
runtime_visible_type_annotations = cfs->get_u1_buffer();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
cfs->skip_u1(runtime_visible_type_annotations_length, CHECK);
- } else if (PreserveAllAnnotations && attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
- runtime_invisible_type_annotations_length = attribute_length;
- runtime_invisible_type_annotations = cfs->get_u1_buffer();
- assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
- cfs->skip_u1(runtime_invisible_type_annotations_length, CHECK);
+ } else if (attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
+ if (runtime_invisible_type_annotations_exists) {
+ classfile_parse_error(
+ "Multiple RuntimeInvisibleTypeAnnotations attributes for field in class file %s", CHECK);
+ } else {
+ runtime_invisible_type_annotations_exists = true;
+ }
+ if (PreserveAllAnnotations) {
+ runtime_invisible_type_annotations_length = attribute_length;
+ runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
+ }
+ cfs->skip_u1(attribute_length, CHECK);
} else {
cfs->skip_u1(attribute_length, CHECK); // Skip unknown attributes
}
@@ -2066,6 +2079,7 @@
int runtime_visible_type_annotations_length = 0;
u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
+ bool runtime_invisible_type_annotations_exists = false;
u1* annotation_default = NULL;
int annotation_default_length = 0;
@@ -2322,16 +2336,30 @@
assert(annotation_default != NULL, "null annotation default");
cfs->skip_u1(annotation_default_length, CHECK_(nullHandle));
} else if (method_attribute_name == vmSymbols::tag_runtime_visible_type_annotations()) {
+ if (runtime_visible_type_annotations != NULL) {
+ classfile_parse_error(
+ "Multiple RuntimeVisibleTypeAnnotations attributes for method in class file %s",
+ CHECK_(nullHandle));
+ }
runtime_visible_type_annotations_length = method_attribute_length;
runtime_visible_type_annotations = cfs->get_u1_buffer();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
// No need for the VM to parse Type annotations
cfs->skip_u1(runtime_visible_type_annotations_length, CHECK_(nullHandle));
- } else if (PreserveAllAnnotations && method_attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
- runtime_invisible_type_annotations_length = method_attribute_length;
- runtime_invisible_type_annotations = cfs->get_u1_buffer();
- assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
- cfs->skip_u1(runtime_invisible_type_annotations_length, CHECK_(nullHandle));
+ } else if (method_attribute_name == vmSymbols::tag_runtime_invisible_type_annotations()) {
+ if (runtime_invisible_type_annotations_exists) {
+ classfile_parse_error(
+ "Multiple RuntimeInvisibleTypeAnnotations attributes for method in class file %s",
+ CHECK_(nullHandle));
+ } else {
+ runtime_invisible_type_annotations_exists = true;
+ }
+ if (PreserveAllAnnotations) {
+ runtime_invisible_type_annotations_length = method_attribute_length;
+ runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
+ }
+ cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
} else {
// Skip unknown attributes
cfs->skip_u1(method_attribute_length, CHECK_(nullHandle));
@@ -2824,6 +2852,7 @@
int runtime_visible_type_annotations_length = 0;
u1* runtime_invisible_type_annotations = NULL;
int runtime_invisible_type_annotations_length = 0;
+ bool runtime_invisible_type_annotations_exists = false;
u1* inner_classes_attribute_start = NULL;
u4 inner_classes_attribute_length = 0;
u2 enclosing_method_class_index = 0;
@@ -2927,16 +2956,28 @@
parsed_bootstrap_methods_attribute = true;
parse_classfile_bootstrap_methods_attribute(attribute_length, CHECK);
} else if (tag == vmSymbols::tag_runtime_visible_type_annotations()) {
+ if (runtime_visible_type_annotations != NULL) {
+ classfile_parse_error(
+ "Multiple RuntimeVisibleTypeAnnotations attributes in class file %s", CHECK);
+ }
runtime_visible_type_annotations_length = attribute_length;
runtime_visible_type_annotations = cfs->get_u1_buffer();
assert(runtime_visible_type_annotations != NULL, "null visible type annotations");
// No need for the VM to parse Type annotations
cfs->skip_u1(runtime_visible_type_annotations_length, CHECK);
- } else if (PreserveAllAnnotations && tag == vmSymbols::tag_runtime_invisible_type_annotations()) {
- runtime_invisible_type_annotations_length = attribute_length;
- runtime_invisible_type_annotations = cfs->get_u1_buffer();
- assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
- cfs->skip_u1(runtime_invisible_type_annotations_length, CHECK);
+ } else if (tag == vmSymbols::tag_runtime_invisible_type_annotations()) {
+ if (runtime_invisible_type_annotations_exists) {
+ classfile_parse_error(
+ "Multiple RuntimeInvisibleTypeAnnotations attributes in class file %s", CHECK);
+ } else {
+ runtime_invisible_type_annotations_exists = true;
+ }
+ if (PreserveAllAnnotations) {
+ runtime_invisible_type_annotations_length = attribute_length;
+ runtime_invisible_type_annotations = cfs->get_u1_buffer();
+ assert(runtime_invisible_type_annotations != NULL, "null invisible type annotations");
+ }
+ cfs->skip_u1(attribute_length, CHECK);
} else {
// Unknown attribute
cfs->skip_u1(attribute_length, CHECK);
--- a/hotspot/src/share/vm/classfile/defaultMethods.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/classfile/defaultMethods.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -450,6 +450,10 @@
streamIndentor si(str, indent * 2);
str->indent().print("Selected method: ");
print_method(str, _selected_target);
+ Klass* method_holder = _selected_target->method_holder();
+ if (!method_holder->is_interface()) {
+ tty->print(" : in superclass");
+ }
str->print_cr("");
}
@@ -1141,19 +1145,23 @@
#endif // ndef PRODUCT
if (method->has_target()) {
Method* selected = method->get_selected_target();
- max_stack = assemble_redirect(
+ if (selected->method_holder()->is_interface()) {
+ max_stack = assemble_redirect(
&bpool, &buffer, slot->signature(), selected, CHECK);
+ }
} else if (method->throws_exception()) {
max_stack = assemble_abstract_method_error(
&bpool, &buffer, method->get_exception_message(), CHECK);
}
- AccessFlags flags = accessFlags_from(
+ if (max_stack != 0) {
+ AccessFlags flags = accessFlags_from(
JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE);
- Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(),
+ Method* m = new_method(&bpool, &buffer, slot->name(), slot->signature(),
flags, max_stack, slot->size_of_parameters(),
ConstMethod::OVERPASS, CHECK);
- if (m != NULL) {
- overpasses.push(m);
+ if (m != NULL) {
+ overpasses.push(m);
+ }
}
}
}
--- a/hotspot/src/share/vm/prims/jni.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/prims/jni.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -5037,6 +5037,7 @@
#include "gc_implementation/g1/heapRegionRemSet.hpp"
#endif
#include "utilities/quickSort.hpp"
+#include "utilities/ostream.hpp"
#if INCLUDE_VM_STRUCTS
#include "runtime/vmStructs.hpp"
#endif
@@ -5060,6 +5061,7 @@
run_unit_test(CollectedHeap::test_is_in());
run_unit_test(QuickSort::test_quick_sort());
run_unit_test(AltHashing::test_alt_hash());
+ run_unit_test(test_loggc_filename());
#if INCLUDE_VM_STRUCTS
run_unit_test(VMStructs::test());
#endif
--- a/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/prims/jvmtiRedefineClasses.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -1072,8 +1072,17 @@
}
res = merge_cp_and_rewrite(the_class, scratch_class, THREAD);
- if (res != JVMTI_ERROR_NONE) {
- return res;
+ if (HAS_PENDING_EXCEPTION) {
+ Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
+ // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
+ RC_TRACE_WITH_THREAD(0x00000002, THREAD,
+ ("merge_cp_and_rewrite exception: '%s'", ex_name->as_C_string()));
+ CLEAR_PENDING_EXCEPTION;
+ if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
+ return JVMTI_ERROR_OUT_OF_MEMORY;
+ } else {
+ return JVMTI_ERROR_INTERNAL;
+ }
}
if (VerifyMergedCPBytecodes) {
@@ -1105,6 +1114,9 @@
}
if (HAS_PENDING_EXCEPTION) {
Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
+ // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
+ RC_TRACE_WITH_THREAD(0x00000002, THREAD,
+ ("Rewriter::rewrite or link_methods exception: '%s'", ex_name->as_C_string()));
CLEAR_PENDING_EXCEPTION;
if (ex_name == vmSymbols::java_lang_OutOfMemoryError()) {
return JVMTI_ERROR_OUT_OF_MEMORY;
@@ -1395,8 +1407,8 @@
ClassLoaderData* loader_data = the_class->class_loader_data();
ConstantPool* merge_cp_oop =
ConstantPool::allocate(loader_data,
- merge_cp_length,
- THREAD);
+ merge_cp_length,
+ CHECK_(JVMTI_ERROR_OUT_OF_MEMORY));
MergeCPCleaner cp_cleaner(loader_data, merge_cp_oop);
HandleMark hm(THREAD); // make sure handles are cleared before
@@ -1472,7 +1484,8 @@
// Replace the new constant pool with a shrunken copy of the
// merged constant pool
- set_new_constant_pool(loader_data, scratch_class, merge_cp, merge_cp_length, THREAD);
+ set_new_constant_pool(loader_data, scratch_class, merge_cp, merge_cp_length,
+ CHECK_(JVMTI_ERROR_OUT_OF_MEMORY));
// The new constant pool replaces scratch_cp so have cleaner clean it up.
// It can't be cleaned up while there are handles to it.
cp_cleaner.add_scratch_cp(scratch_cp());
@@ -1502,7 +1515,8 @@
// merged constant pool so now the rewritten bytecodes have
// valid references; the previous new constant pool will get
// GCed.
- set_new_constant_pool(loader_data, scratch_class, merge_cp, merge_cp_length, THREAD);
+ set_new_constant_pool(loader_data, scratch_class, merge_cp, merge_cp_length,
+ CHECK_(JVMTI_ERROR_OUT_OF_MEMORY));
// The new constant pool replaces scratch_cp so have cleaner clean it up.
// It can't be cleaned up while there are handles to it.
cp_cleaner.add_scratch_cp(scratch_cp());
@@ -1590,11 +1604,23 @@
for (int i = methods->length() - 1; i >= 0; i--) {
methodHandle method(THREAD, methods->at(i));
methodHandle new_method;
- rewrite_cp_refs_in_method(method, &new_method, CHECK_false);
+ rewrite_cp_refs_in_method(method, &new_method, THREAD);
if (!new_method.is_null()) {
// the method has been replaced so save the new method version
+ // even in the case of an exception. original method is on the
+ // deallocation list.
methods->at_put(i, new_method());
}
+ if (HAS_PENDING_EXCEPTION) {
+ Symbol* ex_name = PENDING_EXCEPTION->klass()->name();
+ // RC_TRACE_WITH_THREAD macro has an embedded ResourceMark
+ RC_TRACE_WITH_THREAD(0x00000002, THREAD,
+ ("rewrite_cp_refs_in_method exception: '%s'", ex_name->as_C_string()));
+ // Need to clear pending exception here as the super caller sets
+ // the JVMTI_ERROR_INTERNAL if the returned value is false.
+ CLEAR_PENDING_EXCEPTION;
+ return false;
+ }
}
return true;
@@ -1674,10 +1700,7 @@
Pause_No_Safepoint_Verifier pnsv(&nsv);
// ldc is 2 bytes and ldc_w is 3 bytes
- m = rc.insert_space_at(bci, 3, inst_buffer, THREAD);
- if (m.is_null() || HAS_PENDING_EXCEPTION) {
- guarantee(false, "insert_space_at() failed");
- }
+ m = rc.insert_space_at(bci, 3, inst_buffer, CHECK);
}
// return the new method so that the caller can update
@@ -2487,8 +2510,8 @@
// scratch_cp is a merged constant pool and has enough space for a
// worst case merge situation. We want to associate the minimum
// sized constant pool with the klass to save space.
- constantPoolHandle smaller_cp(THREAD,
- ConstantPool::allocate(loader_data, scratch_cp_length, THREAD));
+ ConstantPool* cp = ConstantPool::allocate(loader_data, scratch_cp_length, CHECK);
+ constantPoolHandle smaller_cp(THREAD, cp);
// preserve version() value in the smaller copy
int version = scratch_cp->version();
@@ -2500,6 +2523,11 @@
smaller_cp->set_pool_holder(scratch_class());
scratch_cp->copy_cp_to(1, scratch_cp_length - 1, smaller_cp, 1, THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ // Exception is handled in the caller
+ loader_data->add_to_deallocate_list(smaller_cp());
+ return;
+ }
scratch_cp = smaller_cp;
// attach new constant pool to klass
--- a/hotspot/src/share/vm/runtime/arguments.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/runtime/arguments.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -1839,7 +1839,7 @@
(NumberOfGCLogFiles == 0) ||
(GCLogFileSize == 0)) {
jio_fprintf(defaultStream::output_stream(),
- "To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files> -XX:GCLogFileSize=<num_of_size>\n"
+ "To enable GC log rotation, use -Xloggc:<filename> -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<num_of_files> -XX:GCLogFileSize=<num_of_size>[k|K|m|M|g|G]\n"
"where num_of_file > 0 and num_of_size > 0\n"
"GC log rotation is turned off\n");
UseGCLogFileRotation = false;
@@ -1853,6 +1853,51 @@
}
}
+// This function is called for -Xloggc:<filename>, it can be used
+// to check if a given file name(or string) conforms to the following
+// specification:
+// A valid string only contains "[A-Z][a-z][0-9].-_%[p|t]"
+// %p and %t only allowed once. We only limit usage of filename not path
+bool is_filename_valid(const char *file_name) {
+ const char* p = file_name;
+ char file_sep = os::file_separator()[0];
+ const char* cp;
+ // skip prefix path
+ for (cp = file_name; *cp != '\0'; cp++) {
+ if (*cp == '/' || *cp == file_sep) {
+ p = cp + 1;
+ }
+ }
+
+ int count_p = 0;
+ int count_t = 0;
+ while (*p != '\0') {
+ if ((*p >= '0' && *p <= '9') ||
+ (*p >= 'A' && *p <= 'Z') ||
+ (*p >= 'a' && *p <= 'z') ||
+ *p == '-' ||
+ *p == '_' ||
+ *p == '.') {
+ p++;
+ continue;
+ }
+ if (*p == '%') {
+ if(*(p + 1) == 'p') {
+ p += 2;
+ count_p ++;
+ continue;
+ }
+ if (*(p + 1) == 't') {
+ p += 2;
+ count_t ++;
+ continue;
+ }
+ }
+ return false;
+ }
+ return count_p < 2 && count_t < 2;
+}
+
// Check consistency of GC selection
bool Arguments::check_gc_consistency() {
check_gclog_consistency();
@@ -2806,6 +2851,13 @@
// ostream_init_log(), when called will use this filename
// to initialize a fileStream.
_gc_log_filename = strdup(tail);
+ if (!is_filename_valid(_gc_log_filename)) {
+ jio_fprintf(defaultStream::output_stream(),
+ "Invalid file name for use with -Xloggc: Filename can only contain the "
+ "characters [A-Z][a-z][0-9]-_.%%[p|t] but it has been %s\n"
+ "Note %%p or %%t can only be used once\n", _gc_log_filename);
+ return JNI_EINVAL;
+ }
FLAG_SET_CMDLINE(bool, PrintGC, true);
FLAG_SET_CMDLINE(bool, PrintGCTimeStamps, true);
--- a/hotspot/src/share/vm/runtime/frame.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/runtime/frame.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -652,7 +652,7 @@
// Return whether the frame is in the VM or os indicating a Hotspot problem.
// Otherwise, it's likely a bug in the native library that the Java code calls,
// hopefully indicating where to submit bugs.
-static void print_C_frame(outputStream* st, char* buf, int buflen, address pc) {
+void frame::print_C_frame(outputStream* st, char* buf, int buflen, address pc) {
// C/C++ frame
bool in_vm = os::address_is_in_vm(pc);
st->print(in_vm ? "V" : "C");
--- a/hotspot/src/share/vm/runtime/frame.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/runtime/frame.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -406,6 +406,7 @@
void print_on(outputStream* st) const;
void interpreter_frame_print_on(outputStream* st) const;
void print_on_error(outputStream* st, char* buf, int buflen, bool verbose = false) const;
+ static void print_C_frame(outputStream* st, char* buf, int buflen, address pc);
// Add annotated descriptions of memory locations belonging to this frame to values
void describe(FrameValues& values, int frame_no);
--- a/hotspot/src/share/vm/runtime/os.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/runtime/os.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -795,6 +795,14 @@
#endif
public:
+#ifndef PLATFORM_PRINT_NATIVE_STACK
+ // No platform-specific code for printing the native stack.
+ static bool platform_print_native_stack(outputStream* st, void* context,
+ char *buf, int buf_size) {
+ return false;
+ }
+#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/hotspot/src/share/vm/runtime/thread.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/runtime/thread.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -333,6 +333,8 @@
// Reclaim the objectmonitors from the omFreeList of the moribund thread.
ObjectSynchronizer::omFlush (this) ;
+ EVENT_THREAD_DESTRUCT(this);
+
// stack_base can be NULL if the thread is never started or exited before
// record_stack_base_and_size called. Although, we would like to ensure
// that all started threads do call record_stack_base_and_size(), there is
--- a/hotspot/src/share/vm/services/gcNotifier.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/services/gcNotifier.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -209,7 +209,7 @@
GCNotificationRequest *request = getRequest();
if (request != NULL) {
NotificationMark nm(request);
- Handle objGcInfo = createGcInfo(request->gcManager, request->gcStatInfo, THREAD);
+ Handle objGcInfo = createGcInfo(request->gcManager, request->gcStatInfo, CHECK);
Handle objName = java_lang_String::create_from_str(request->gcManager->name(), CHECK);
Handle objAction = java_lang_String::create_from_str(request->gcAction, CHECK);
--- a/hotspot/src/share/vm/services/memPtr.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/services/memPtr.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,9 +34,9 @@
jint seq = Atomic::add(1, &_seq_number);
if (seq < 0) {
MemTracker::shutdown(MemTracker::NMT_sequence_overflow);
+ } else {
+ NOT_PRODUCT(_max_seq_number = (seq > _max_seq_number) ? seq : _max_seq_number;)
}
- assert(seq > 0, "counter overflow");
- NOT_PRODUCT(_max_seq_number = (seq > _max_seq_number) ? seq : _max_seq_number;)
return seq;
}
--- a/hotspot/src/share/vm/trace/traceMacros.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/trace/traceMacros.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -26,6 +26,7 @@
#define SHARE_VM_TRACE_TRACE_MACRO_HPP
#define EVENT_THREAD_EXIT(thread)
+#define EVENT_THREAD_DESTRUCT(thread)
#define TRACE_INIT_ID(k)
#define TRACE_DATA TraceThreadData
--- a/hotspot/src/share/vm/utilities/decoder.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/utilities/decoder.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -24,7 +24,6 @@
#include "precompiled.hpp"
#include "prims/jvm.h"
-#include "runtime/mutexLocker.hpp"
#include "runtime/os.hpp"
#include "utilities/decoder.hpp"
#include "utilities/vmError.hpp"
@@ -80,6 +79,23 @@
return decoder;
}
+inline bool DecoderLocker::is_first_error_thread() {
+ return (os::current_thread_id() == VMError::get_first_error_tid());
+}
+
+DecoderLocker::DecoderLocker() :
+ MutexLockerEx(DecoderLocker::is_first_error_thread() ?
+ NULL : Decoder::shared_decoder_lock(), true) {
+ _decoder = is_first_error_thread() ?
+ Decoder::get_error_handler_instance() : Decoder::get_shared_instance();
+ assert(_decoder != NULL, "null decoder");
+}
+
+Mutex* Decoder::shared_decoder_lock() {
+ assert(_shared_decoder_lock != NULL, "Just check");
+ return _shared_decoder_lock;
+}
+
bool Decoder::decode(address addr, char* buf, int buflen, int* offset, const char* modulepath) {
assert(_shared_decoder_lock != NULL, "Just check");
bool error_handling_thread = os::current_thread_id() == VMError::first_error_tid;
--- a/hotspot/src/share/vm/utilities/decoder.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/utilities/decoder.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -28,6 +28,7 @@
#include "memory/allocation.hpp"
#include "runtime/mutex.hpp"
+#include "runtime/mutexLocker.hpp"
class AbstractDecoder : public CHeapObj<mtInternal> {
public:
@@ -124,6 +125,19 @@
protected:
static Mutex* _shared_decoder_lock;
+ static Mutex* shared_decoder_lock();
+
+ friend class DecoderLocker;
+};
+
+class DecoderLocker : public MutexLockerEx {
+ AbstractDecoder* _decoder;
+ inline bool is_first_error_thread();
+public:
+ DecoderLocker();
+ AbstractDecoder* decoder() {
+ return _decoder;
+ }
};
#endif // SHARE_VM_UTILITIES_DECODER_HPP
--- a/hotspot/src/share/vm/utilities/ostream.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/utilities/ostream.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -342,7 +342,7 @@
}
char* stringStream::as_string() {
- char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos+1);
+ char* copy = NEW_RESOURCE_ARRAY(char, buffer_pos + 1);
strncpy(copy, buffer, buffer_pos);
copy[buffer_pos] = 0; // terminating null
return copy;
@@ -355,14 +355,190 @@
outputStream* gclog_or_tty;
extern Mutex* tty_lock;
+#define EXTRACHARLEN 32
+#define CURRENTAPPX ".current"
+#define FILENAMEBUFLEN 1024
+// convert YYYY-MM-DD HH:MM:SS to YYYY-MM-DD_HH-MM-SS
+char* get_datetime_string(char *buf, size_t len) {
+ os::local_time_string(buf, len);
+ int i = (int)strlen(buf);
+ while (i-- >= 0) {
+ if (buf[i] == ' ') buf[i] = '_';
+ else if (buf[i] == ':') buf[i] = '-';
+ }
+ return buf;
+}
+
+static const char* make_log_name_internal(const char* log_name, const char* force_directory,
+ int pid, const char* tms) {
+ const char* basename = log_name;
+ char file_sep = os::file_separator()[0];
+ const char* cp;
+ char pid_text[32];
+
+ for (cp = log_name; *cp != '\0'; cp++) {
+ if (*cp == '/' || *cp == file_sep) {
+ basename = cp + 1;
+ }
+ }
+ const char* nametail = log_name;
+ // Compute buffer length
+ size_t buffer_length;
+ if (force_directory != NULL) {
+ buffer_length = strlen(force_directory) + strlen(os::file_separator()) +
+ strlen(basename) + 1;
+ } else {
+ buffer_length = strlen(log_name) + 1;
+ }
+
+ // const char* star = strchr(basename, '*');
+ const char* pts = strstr(basename, "%p");
+ int pid_pos = (pts == NULL) ? -1 : (pts - nametail);
+
+ if (pid_pos >= 0) {
+ jio_snprintf(pid_text, sizeof(pid_text), "pid%u", pid);
+ buffer_length += strlen(pid_text);
+ }
+
+ pts = strstr(basename, "%t");
+ int tms_pos = (pts == NULL) ? -1 : (pts - nametail);
+ if (tms_pos >= 0) {
+ buffer_length += strlen(tms);
+ }
+
+ // Create big enough buffer.
+ char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
+
+ strcpy(buf, "");
+ if (force_directory != NULL) {
+ strcat(buf, force_directory);
+ strcat(buf, os::file_separator());
+ nametail = basename; // completely skip directory prefix
+ }
+
+ // who is first, %p or %t?
+ int first = -1, second = -1;
+ const char *p1st = NULL;
+ const char *p2nd = NULL;
+
+ if (pid_pos >= 0 && tms_pos >= 0) {
+ // contains both %p and %t
+ if (pid_pos < tms_pos) {
+ // case foo%pbar%tmonkey.log
+ first = pid_pos;
+ p1st = pid_text;
+ second = tms_pos;
+ p2nd = tms;
+ } else {
+ // case foo%tbar%pmonkey.log
+ first = tms_pos;
+ p1st = tms;
+ second = pid_pos;
+ p2nd = pid_text;
+ }
+ } else if (pid_pos >= 0) {
+ // contains %p only
+ first = pid_pos;
+ p1st = pid_text;
+ } else if (tms_pos >= 0) {
+ // contains %t only
+ first = tms_pos;
+ p1st = tms;
+ }
+
+ int buf_pos = (int)strlen(buf);
+ const char* tail = nametail;
+
+ if (first >= 0) {
+ tail = nametail + first + 2;
+ strncpy(&buf[buf_pos], nametail, first);
+ strcpy(&buf[buf_pos + first], p1st);
+ buf_pos = (int)strlen(buf);
+ if (second >= 0) {
+ strncpy(&buf[buf_pos], tail, second - first - 2);
+ strcpy(&buf[buf_pos + second - first - 2], p2nd);
+ tail = nametail + second + 2;
+ }
+ }
+ strcat(buf, tail); // append rest of name, or all of name
+ return buf;
+}
+
+// log_name comes from -XX:LogFile=log_name or -Xloggc:log_name
+// in log_name, %p => pipd1234 and
+// %t => YYYY-MM-DD_HH-MM-SS
+static const char* make_log_name(const char* log_name, const char* force_directory) {
+ char timestr[32];
+ get_datetime_string(timestr, sizeof(timestr));
+ return make_log_name_internal(log_name, force_directory, os::current_process_id(),
+ timestr);
+}
+
+#ifndef PRODUCT
+void test_loggc_filename() {
+ int pid;
+ char tms[32];
+ char i_result[FILENAMEBUFLEN];
+ const char* o_result;
+ get_datetime_string(tms, sizeof(tms));
+ pid = os::current_process_id();
+
+ // test.log
+ jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test.log", tms);
+ o_result = make_log_name_internal("test.log", NULL, pid, tms);
+ assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test.log\", NULL)");
+ FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
+
+ // test-%t-%p.log
+ jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%s-pid%u.log", tms, pid);
+ o_result = make_log_name_internal("test-%t-%p.log", NULL, pid, tms);
+ assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t-%%p.log\", NULL)");
+ FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
+
+ // test-%t%p.log
+ jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "test-%spid%u.log", tms, pid);
+ o_result = make_log_name_internal("test-%t%p.log", NULL, pid, tms);
+ assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"test-%%t%%p.log\", NULL)");
+ FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
+
+ // %p%t.log
+ jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u%s.log", pid, tms);
+ o_result = make_log_name_internal("%p%t.log", NULL, pid, tms);
+ assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p%%t.log\", NULL)");
+ FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
+
+ // %p-test.log
+ jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "pid%u-test.log", pid);
+ o_result = make_log_name_internal("%p-test.log", NULL, pid, tms);
+ assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%p-test.log\", NULL)");
+ FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
+
+ // %t.log
+ jio_snprintf(i_result, sizeof(char)*FILENAMEBUFLEN, "%s.log", tms);
+ o_result = make_log_name_internal("%t.log", NULL, pid, tms);
+ assert(strcmp(i_result, o_result) == 0, "failed on testing make_log_name(\"%%t.log\", NULL)");
+ FREE_C_HEAP_ARRAY(char, o_result, mtInternal);
+}
+#endif // PRODUCT
+
fileStream::fileStream(const char* file_name) {
_file = fopen(file_name, "w");
- _need_close = true;
+ if (_file != NULL) {
+ _need_close = true;
+ } else {
+ warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
+ _need_close = false;
+ }
}
fileStream::fileStream(const char* file_name, const char* opentype) {
_file = fopen(file_name, opentype);
- _need_close = true;
+ if (_file != NULL) {
+ _need_close = true;
+ } else {
+ warning("Cannot open file %s due to %s\n", file_name, strerror(errno));
+ _need_close = false;
+ }
}
void fileStream::write(const char* s, size_t len) {
@@ -423,34 +599,51 @@
update_position(s, len);
}
-rotatingFileStream::~rotatingFileStream() {
+// dump vm version, os version, platform info, build id,
+// memory usage and command line flags into header
+void gcLogFileStream::dump_loggc_header() {
+ if (is_open()) {
+ print_cr(Abstract_VM_Version::internal_vm_info_string());
+ os::print_memory_info(this);
+ print("CommandLine flags: ");
+ CommandLineFlags::printSetFlags(this);
+ }
+}
+
+gcLogFileStream::~gcLogFileStream() {
if (_file != NULL) {
if (_need_close) fclose(_file);
- _file = NULL;
+ _file = NULL;
+ }
+ if (_file_name != NULL) {
FREE_C_HEAP_ARRAY(char, _file_name, mtInternal);
_file_name = NULL;
}
}
-rotatingFileStream::rotatingFileStream(const char* file_name) {
+gcLogFileStream::gcLogFileStream(const char* file_name) {
_cur_file_num = 0;
_bytes_written = 0L;
- _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
- jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);
- _file = fopen(_file_name, "w");
- _need_close = true;
+ _file_name = make_log_name(file_name, NULL);
+
+ // gc log file rotation
+ if (UseGCLogFileRotation && NumberOfGCLogFiles > 1) {
+ char tempbuf[FILENAMEBUFLEN];
+ jio_snprintf(tempbuf, sizeof(tempbuf), "%s.%d" CURRENTAPPX, _file_name, _cur_file_num);
+ _file = fopen(tempbuf, "w");
+ } else {
+ _file = fopen(_file_name, "w");
+ }
+ if (_file != NULL) {
+ _need_close = true;
+ dump_loggc_header();
+ } else {
+ warning("Cannot open file %s due to %s\n", _file_name, strerror(errno));
+ _need_close = false;
+ }
}
-rotatingFileStream::rotatingFileStream(const char* file_name, const char* opentype) {
- _cur_file_num = 0;
- _bytes_written = 0L;
- _file_name = NEW_C_HEAP_ARRAY(char, strlen(file_name)+10, mtInternal);
- jio_snprintf(_file_name, strlen(file_name)+10, "%s.%d", file_name, _cur_file_num);
- _file = fopen(_file_name, opentype);
- _need_close = true;
-}
-
-void rotatingFileStream::write(const char* s, size_t len) {
+void gcLogFileStream::write(const char* s, size_t len) {
if (_file != NULL) {
size_t count = fwrite(s, 1, len, _file);
_bytes_written += count;
@@ -466,7 +659,12 @@
// write to gc log file at safepoint. If in future, changes made for mutator threads or
// concurrent GC threads to run parallel with VMThread at safepoint, write and rotate_log
// must be synchronized.
-void rotatingFileStream::rotate_log() {
+void gcLogFileStream::rotate_log() {
+ char time_msg[FILENAMEBUFLEN];
+ char time_str[EXTRACHARLEN];
+ char current_file_name[FILENAMEBUFLEN];
+ char renamed_file_name[FILENAMEBUFLEN];
+
if (_bytes_written < (jlong)GCLogFileSize) {
return;
}
@@ -481,27 +679,89 @@
// rotate in same file
rewind();
_bytes_written = 0L;
+ jio_snprintf(time_msg, sizeof(time_msg), "File %s rotated at %s\n",
+ _file_name, os::local_time_string((char *)time_str, sizeof(time_str)));
+ write(time_msg, strlen(time_msg));
+ dump_loggc_header();
return;
}
- // rotate file in names file.0, file.1, file.2, ..., file.<MaxGCLogFileNumbers-1>
- // close current file, rotate to next file
+#if defined(_WINDOWS)
+#ifndef F_OK
+#define F_OK 0
+#endif
+#endif // _WINDOWS
+
+ // rotate file in names extended_filename.0, extended_filename.1, ...,
+ // extended_filename.<NumberOfGCLogFiles - 1>. Current rotation file name will
+ // have a form of extended_filename.<i>.current where i is the current rotation
+ // file number. After it reaches max file size, the file will be saved and renamed
+ // with .current removed from its tail.
+ size_t filename_len = strlen(_file_name);
if (_file != NULL) {
- _cur_file_num ++;
- if (_cur_file_num >= NumberOfGCLogFiles) _cur_file_num = 0;
- jio_snprintf(_file_name, strlen(Arguments::gc_log_filename()) + 10, "%s.%d",
- Arguments::gc_log_filename(), _cur_file_num);
+ jio_snprintf(renamed_file_name, filename_len + EXTRACHARLEN, "%s.%d",
+ _file_name, _cur_file_num);
+ jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
+ _file_name, _cur_file_num);
+ jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file has reached the"
+ " maximum size. Saved as %s\n",
+ os::local_time_string((char *)time_str, sizeof(time_str)),
+ renamed_file_name);
+ write(time_msg, strlen(time_msg));
+
fclose(_file);
_file = NULL;
+
+ bool can_rename = true;
+ if (access(current_file_name, F_OK) != 0) {
+ // current file does not exist?
+ warning("No source file exists, cannot rename\n");
+ can_rename = false;
+ }
+ if (can_rename) {
+ if (access(renamed_file_name, F_OK) == 0) {
+ if (remove(renamed_file_name) != 0) {
+ warning("Could not delete existing file %s\n", renamed_file_name);
+ can_rename = false;
+ }
+ } else {
+ // file does not exist, ok to rename
+ }
+ }
+ if (can_rename && rename(current_file_name, renamed_file_name) != 0) {
+ warning("Could not rename %s to %s\n", _file_name, renamed_file_name);
+ }
}
- _file = fopen(_file_name, "w");
+
+ _cur_file_num++;
+ if (_cur_file_num > NumberOfGCLogFiles - 1) _cur_file_num = 0;
+ jio_snprintf(current_file_name, filename_len + EXTRACHARLEN, "%s.%d" CURRENTAPPX,
+ _file_name, _cur_file_num);
+ _file = fopen(current_file_name, "w");
+
if (_file != NULL) {
_bytes_written = 0L;
_need_close = true;
+ // reuse current_file_name for time_msg
+ jio_snprintf(current_file_name, filename_len + EXTRACHARLEN,
+ "%s.%d", _file_name, _cur_file_num);
+ jio_snprintf(time_msg, sizeof(time_msg), "%s GC log file created %s\n",
+ os::local_time_string((char *)time_str, sizeof(time_str)),
+ current_file_name);
+ write(time_msg, strlen(time_msg));
+ dump_loggc_header();
+ // remove the existing file
+ if (access(current_file_name, F_OK) == 0) {
+ if (remove(current_file_name) != 0) {
+ warning("Could not delete existing file %s\n", current_file_name);
+ }
+ }
} else {
- tty->print_cr("failed to open rotation log file %s due to %s\n",
+ warning("failed to open rotation log file %s due to %s\n"
+ "Turned off GC log file rotation\n",
_file_name, strerror(errno));
_need_close = false;
+ FLAG_SET_DEFAULT(UseGCLogFileRotation, false);
}
}
@@ -530,66 +790,6 @@
return _log_file != NULL;
}
-static const char* make_log_name(const char* log_name, const char* force_directory) {
- const char* basename = log_name;
- char file_sep = os::file_separator()[0];
- const char* cp;
- for (cp = log_name; *cp != '\0'; cp++) {
- if (*cp == '/' || *cp == file_sep) {
- basename = cp+1;
- }
- }
- const char* nametail = log_name;
-
- // Compute buffer length
- size_t buffer_length;
- if (force_directory != NULL) {
- buffer_length = strlen(force_directory) + strlen(os::file_separator()) +
- strlen(basename) + 1;
- } else {
- buffer_length = strlen(log_name) + 1;
- }
-
- const char* star = strchr(basename, '*');
- int star_pos = (star == NULL) ? -1 : (star - nametail);
- int skip = 1;
- if (star == NULL) {
- // Try %p
- star = strstr(basename, "%p");
- if (star != NULL) {
- skip = 2;
- }
- }
- star_pos = (star == NULL) ? -1 : (star - nametail);
-
- char pid[32];
- if (star_pos >= 0) {
- jio_snprintf(pid, sizeof(pid), "%u", os::current_process_id());
- buffer_length += strlen(pid);
- }
-
- // Create big enough buffer.
- char *buf = NEW_C_HEAP_ARRAY(char, buffer_length, mtInternal);
-
- strcpy(buf, "");
- if (force_directory != NULL) {
- strcat(buf, force_directory);
- strcat(buf, os::file_separator());
- nametail = basename; // completely skip directory prefix
- }
-
- if (star_pos >= 0) {
- // convert foo*bar.log or foo%pbar.log to foo123bar.log
- int buf_pos = (int) strlen(buf);
- strncpy(&buf[buf_pos], nametail, star_pos);
- strcpy(&buf[buf_pos + star_pos], pid);
- nametail += star_pos + skip; // skip prefix and pid format
- }
-
- strcat(buf, nametail); // append rest of name, or all of name
- return buf;
-}
-
void defaultStream::init_log() {
// %%% Need a MutexLocker?
const char* log_name = LogFile != NULL ? LogFile : "hotspot.log";
@@ -877,11 +1077,8 @@
gclog_or_tty = tty; // default to tty
if (Arguments::gc_log_filename() != NULL) {
- fileStream * gclog = UseGCLogFileRotation ?
- new(ResourceObj::C_HEAP, mtInternal)
- rotatingFileStream(Arguments::gc_log_filename()) :
- new(ResourceObj::C_HEAP, mtInternal)
- fileStream(Arguments::gc_log_filename());
+ fileStream * gclog = new(ResourceObj::C_HEAP, mtInternal)
+ gcLogFileStream(Arguments::gc_log_filename());
if (gclog->is_open()) {
// now we update the time stamp of the GC log to be synced up
// with tty.
--- a/hotspot/src/share/vm/utilities/ostream.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/utilities/ostream.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -231,20 +231,24 @@
void flush() {};
};
-class rotatingFileStream : public fileStream {
+class gcLogFileStream : public fileStream {
protected:
- char* _file_name;
+ const char* _file_name;
jlong _bytes_written;
- uintx _cur_file_num; // current logfile rotation number, from 0 to MaxGCLogFileNumbers-1
+ uintx _cur_file_num; // current logfile rotation number, from 0 to NumberOfGCLogFiles-1
public:
- rotatingFileStream(const char* file_name);
- rotatingFileStream(const char* file_name, const char* opentype);
- rotatingFileStream(FILE* file) : fileStream(file) {}
- ~rotatingFileStream();
+ gcLogFileStream(const char* file_name);
+ ~gcLogFileStream();
virtual void write(const char* c, size_t len);
virtual void rotate_log();
+ void dump_loggc_header();
};
+#ifndef PRODUCT
+// unit test for checking -Xloggc:<filename> parsing result
+void test_loggc_filename();
+#endif
+
void ostream_init();
void ostream_init_log();
void ostream_exit();
--- a/hotspot/src/share/vm/utilities/vmError.cpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/utilities/vmError.cpp Wed Sep 18 12:52:15 2013 -0400
@@ -574,6 +574,10 @@
STEP(120, "(printing native stack)" )
if (_verbose) {
+ if (os::platform_print_native_stack(st, _context, buf, sizeof(buf))) {
+ // We have printed the native stack in platform-specific code
+ // Windows/x64 needs special handling.
+ } else {
frame fr = _context ? os::fetch_frame_from_context(_context)
: os::current_frame();
@@ -604,6 +608,7 @@
st->cr();
}
}
+ }
STEP(130, "(printing Java stack)" )
--- a/hotspot/src/share/vm/utilities/vmError.hpp Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/src/share/vm/utilities/vmError.hpp Wed Sep 18 12:52:15 2013 -0400
@@ -136,6 +136,10 @@
// check to see if fatal error reporting is in progress
static bool fatal_error_in_progress() { return first_error != NULL; }
+
+ static jlong get_first_error_tid() {
+ return first_error_tid;
+ }
};
#endif // SHARE_VM_UTILITIES_VMERROR_HPP
--- a/hotspot/test/runtime/6878713/Test6878713.sh Fri Sep 13 00:43:01 2013 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,137 +0,0 @@
-#!/bin/sh
-
-#
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-
-
-##
-## @test
-## @bug 6878713
-## @bug 7030610
-## @bug 7037122
-## @bug 7123945
-## @summary Verifier heap corruption, relating to backward jsrs
-## @run shell Test6878713.sh
-##
-## some tests require path to find test source dir
-if [ "${TESTSRC}" = "" ]
-then
- TESTSRC=${PWD}
- echo "TESTSRC not set. Using "${TESTSRC}" as default"
-fi
-echo "TESTSRC=${TESTSRC}"
-## Adding common setup Variables for running shell tests.
-. ${TESTSRC}/../../test_env.sh
-
-TARGET_CLASS=OOMCrashClass1960_2
-
-echo "INFO: extracting the target class."
-${COMPILEJAVA}${FS}bin${FS}jar xvf \
- ${TESTSRC}${FS}testcase.jar ${TARGET_CLASS}.class
-
-# remove any hs_err_pid that might exist here
-rm -f hs_err_pid*.log
-
-echo "INFO: checking for 32-bit versus 64-bit VM."
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} -version 2>&1 \
- | grep "64-Bit [^ ][^ ]* VM" > /dev/null 2>&1
-status="$?"
-if [ "$status" = 0 ]; then
- echo "INFO: testing a 64-bit VM."
- is_64_bit=true
-else
- echo "INFO: testing a 32-bit VM."
-fi
-
-if [ "$is_64_bit" = true ]; then
- # limit is 768MB in 8-byte words (1024 * 1024 * 768 / 8) == 100663296
- MALLOC_MAX=100663296
-else
- # limit is 768MB in 4-byte words (1024 * 1024 * 768 / 4) == 201326592
- MALLOC_MAX=201326592
-fi
-echo "INFO: MALLOC_MAX=$MALLOC_MAX"
-
-echo "INFO: executing the target class."
-# -XX:+PrintCommandLineFlags for debugging purposes
-# -XX:+IgnoreUnrecognizedVMOptions so test will run on a VM without
-# the new -XX:MallocMaxTestWords option
-# -XX:+UnlockDiagnosticVMOptions so we can use -XX:MallocMaxTestWords
-# -XX:MallocMaxTestWords limits malloc to $MALLOC_MAX
-${TESTJAVA}${FS}bin${FS}java \
- -XX:+PrintCommandLineFlags \
- -XX:+IgnoreUnrecognizedVMOptions \
- -XX:+UnlockDiagnosticVMOptions \
- -XX:MallocMaxTestWords=$MALLOC_MAX \
- ${TESTVMOPTS} ${TARGET_CLASS} > test.out 2>&1
-
-echo "INFO: begin contents of test.out:"
-cat test.out
-echo "INFO: end contents of test.out."
-
-echo "INFO: checking for memory allocation error message."
-# We are looking for this specific memory allocation failure mesg so
-# we know we exercised the right allocation path with the test class:
-MESG1="Native memory allocation (malloc) failed to allocate 25696531[0-9][0-9] bytes"
-grep "$MESG1" test.out
-status="$?"
-if [ "$status" = 0 ]; then
- echo "INFO: found expected memory allocation error message."
-else
- echo "INFO: did not find expected memory allocation error message."
-
- # If we didn't find MESG1 above, then there are several scenarios:
- # 1) -XX:MallocMaxTestWords is not supported by the current VM and we
- # didn't fail TARGET_CLASS's memory allocation attempt; instead
- # we failed to find TARGET_CLASS's main() method. The TARGET_CLASS
- # is designed to provoke a memory allocation failure during class
- # loading; we actually don't care about running the class which is
- # why it doesn't have a main() method.
- # 2) we failed a memory allocation, but not the one we were looking
- # so it might be that TARGET_CLASS no longer tickles the same
- # memory allocation code path
- # 3) TARGET_CLASS reproduces the failure mode (SIGSEGV) fixed by
- # 6878713 because the test is running on a pre-fix VM.
- echo "INFO: checking for no main() method message."
- MESG2="Error: Main method not found in class"
- grep "$MESG2" test.out
- status="$?"
- if [ "$status" = 0 ]; then
- echo "INFO: found no main() method message."
- else
- echo "FAIL: did not find no main() method message."
- # status is non-zero for exit below
-
- if [ -s hs_err_pid*.log ]; then
- echo "INFO: begin contents of hs_err_pid file:"
- cat hs_err_pid*.log
- echo "INFO: end contents of hs_err_pid file."
- fi
- fi
-fi
-
-if [ "$status" = 0 ]; then
- echo "PASS: test found one of the expected messages."
-fi
-exit "$status"
Binary file hotspot/test/runtime/6878713/testcase.jar has changed
--- a/hotspot/test/runtime/7020373/Test7020373.sh Fri Sep 13 00:43:01 2013 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,43 +0,0 @@
-#!/bin/sh
-
-##
-## @test
-## @bug 7020373 7055247 7053586 7185550
-## @key cte_test
-## @summary JSR rewriting can overflow memory address size variables
-## @ignore Ignore it as 7053586 test uses lots of memory. See bug report for detail.
-## @run shell Test7020373.sh
-##
-
-if [ "${TESTSRC}" = "" ]
-then
- TESTSRC=${PWD}
- echo "TESTSRC not set. Using "${TESTSRC}" as default"
-fi
-echo "TESTSRC=${TESTSRC}"
-## Adding common setup Variables for running shell tests.
-. ${TESTSRC}/../../test_env.sh
-
-${COMPILEJAVA}${FS}bin${FS}jar xvf ${TESTSRC}${FS}testcase.jar
-
-${TESTJAVA}${FS}bin${FS}java ${TESTVMOPTS} OOMCrashClass4000_1 > test.out 2>&1
-
-cat test.out
-
-egrep "SIGSEGV|An unexpected error has been detected" test.out
-
-if [ $? = 0 ]
-then
- echo "Test Failed"
- exit 1
-else
- egrep "java.lang.LinkageError|java.lang.NoSuchMethodError|Main method not found in class OOMCrashClass4000_1|insufficient memory" test.out
- if [ $? = 0 ]
- then
- echo "Test Passed"
- exit 0
- else
- echo "Test Failed"
- exit 1
- fi
-fi
Binary file hotspot/test/runtime/7020373/testcase.jar has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassFile/JsrRewriting.java Wed Sep 18 12:52:15 2013 -0400
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+/*
+ * @test JsrRewriting
+ * @summary JSR (jump local subroutine)
+ * rewriting can overflow memory address size variables
+ * @bug 7020373
+ * @bug 7055247
+ * @bug 7053586
+ * @bug 7185550
+ * @bug 7149464
+ * @key cte_test
+ * @library /testlibrary
+ * @run main JsrRewriting
+ */
+
+import com.oracle.java.testlibrary.*;
+import java.io.File;
+
+public class JsrRewriting {
+
+ public static void main(String[] args) throws Exception {
+
+ // ======= Configure the test
+ String jarFile = System.getProperty("test.src") +
+ File.separator + "JsrRewritingTestCase.jar";
+ String className = "OOMCrashClass4000_1";
+
+ // limit is 768MB in native words
+ int mallocMaxTestWords = (1024 * 1024 * 768 / 4);
+ if (Platform.is64bit())
+ mallocMaxTestWords = (mallocMaxTestWords / 2);
+
+ // ======= extract the test class
+ ProcessBuilder pb = new ProcessBuilder(new String[] {
+ JDKToolFinder.getJDKTool("jar"),
+ "xvf", jarFile } );
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldHaveExitValue(0);
+
+ // ======= execute the test
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-cp", ".",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:MallocMaxTestWords=" + mallocMaxTestWords,
+ className);
+
+ output = new OutputAnalyzer(pb.start());
+ String[] expectedMsgs = {
+ "java.lang.LinkageError",
+ "java.lang.NoSuchMethodError",
+ "Main method not found in class " + className,
+ "insufficient memory"
+ };
+
+ MultipleOrMatch(output, expectedMsgs);
+ }
+
+ private static void
+ MultipleOrMatch(OutputAnalyzer analyzer, String[] whatToMatch) {
+ String output = analyzer.getOutput();
+
+ for (String expected : whatToMatch)
+ if (output.contains(expected))
+ return;
+
+ String err =
+ " stdout: [" + analyzer.getOutput() + "];\n" +
+ " exitValue = " + analyzer.getExitValue() + "\n";
+ System.err.println(err);
+
+ StringBuilder msg = new StringBuilder("Output did not contain " +
+ "any of the following expected messages: \n");
+ for (String expected : whatToMatch)
+ msg.append(expected).append(System.lineSeparator());
+ throw new RuntimeException(msg.toString());
+ }
+}
+
Binary file hotspot/test/runtime/ClassFile/JsrRewritingTestCase.jar has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/ClassFile/OomWhileParsingRepeatedJsr.java Wed Sep 18 12:52:15 2013 -0400
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+
+/*
+ * @test OomWhileParsingRepeatedJsr
+ * @summary Testing class file parser; specifically parsing
+ * a file with repeated JSR (jump local subroutine)
+ * bytecode command.
+ * @bug 6878713
+ * @bug 7030610
+ * @bug 7037122
+ * @bug 7123945
+ * @bug 8016029
+ * @library /testlibrary
+ * @run main OomWhileParsingRepeatedJsr
+ */
+
+import com.oracle.java.testlibrary.*;
+
+
+public class OomWhileParsingRepeatedJsr {
+
+ public static void main(String[] args) throws Exception {
+
+ // ======= Configure the test
+ String jarFile = System.getProperty("test.src") + "/testcase.jar";
+ String className = "OOMCrashClass1960_2";
+
+ // limit is 768MB in native words
+ int mallocMaxTestWords = (1024 * 1024 * 768 / 4);
+ if (Platform.is64bit())
+ mallocMaxTestWords = (mallocMaxTestWords / 2);
+
+ // ======= extract the test class
+ ProcessBuilder pb = new ProcessBuilder(new String[] {
+ JDKToolFinder.getJDKTool("jar"),
+ "xvf", jarFile } );
+ OutputAnalyzer output = new OutputAnalyzer(pb.start());
+ output.shouldHaveExitValue(0);
+
+ // ======= execute the test
+ pb = ProcessTools.createJavaProcessBuilder(
+ "-cp", ".",
+ "-XX:+UnlockDiagnosticVMOptions",
+ "-XX:MallocMaxTestWords=" + mallocMaxTestWords,
+ className );
+
+ output = new OutputAnalyzer(pb.start());
+ output.shouldContain("Cannot reserve enough memory");
+ }
+}
+
Binary file hotspot/test/runtime/ClassFile/testcase.jar has changed
--- a/hotspot/test/runtime/InitialThreadOverflow/testme.sh Fri Sep 13 00:43:01 2013 -0700
+++ b/hotspot/test/runtime/InitialThreadOverflow/testme.sh Wed Sep 18 12:52:15 2013 -0400
@@ -43,9 +43,9 @@
exit 0
fi
-gcc_cmd=`which gcc`
-if [ "x$gcc_cmd" == "x" ]; then
- echo "WARNING: gcc not found. Cannot execute test." 2>&1
+gcc_cmd=`which g++`
+if [ "x$gcc_cmd" = "x" ]; then
+ echo "WARNING: g++ not found. Cannot execute test." 2>&1
exit 0;
fi