diff options
author | Edward Nevill edward.nevill@linaro.org <Edward Nevill edward.nevill@linaro.org> | 2013-10-11 12:06:22 +0100 |
---|---|---|
committer | Edward Nevill edward.nevill@linaro.org <Edward Nevill edward.nevill@linaro.org> | 2013-10-11 12:06:22 +0100 |
commit | c9c29ea453ff939e48745c1f879819b96e63fedd (patch) | |
tree | 798259b00805bf284db2e1f4d32110b72e357364 /src/share/vm/utilities | |
parent | afedba2e348cf9b3179325f96e1ff518f8a88c5b (diff) | |
parent | 3ade2048da2eab1098270ecd3669cc49addaa142 (diff) |
Merge up to jdk8-b110
Diffstat (limited to 'src/share/vm/utilities')
26 files changed, 627 insertions, 363 deletions
diff --git a/src/share/vm/utilities/accessFlags.hpp b/src/share/vm/utilities/accessFlags.hpp index 99f9a3360..a3d3de99c 100644 --- a/src/share/vm/utilities/accessFlags.hpp +++ b/src/share/vm/utilities/accessFlags.hpp @@ -78,11 +78,13 @@ enum { JVM_ACC_FIELD_ACCESS_WATCHED = 0x00002000, // field access is watched by JVMTI JVM_ACC_FIELD_MODIFICATION_WATCHED = 0x00008000, // field modification is watched by JVMTI JVM_ACC_FIELD_INTERNAL = 0x00000400, // internal field, same as JVM_ACC_ABSTRACT + JVM_ACC_FIELD_STABLE = 0x00000020, // @Stable field, same as JVM_ACC_SYNCHRONIZED JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE = 0x00000800, // field has generic signature JVM_ACC_FIELD_INTERNAL_FLAGS = JVM_ACC_FIELD_ACCESS_WATCHED | JVM_ACC_FIELD_MODIFICATION_WATCHED | JVM_ACC_FIELD_INTERNAL | + JVM_ACC_FIELD_STABLE | JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE, // flags accepted by set_field_flags() @@ -148,6 +150,7 @@ class AccessFlags VALUE_OBJ_CLASS_SPEC { { return (_flags & JVM_ACC_FIELD_MODIFICATION_WATCHED) != 0; } bool on_stack() const { return (_flags & JVM_ACC_ON_STACK) != 0; } bool is_internal() const { return (_flags & JVM_ACC_FIELD_INTERNAL) != 0; } + bool is_stable() const { return (_flags & JVM_ACC_FIELD_STABLE) != 0; } bool field_has_generic_signature() const { return (_flags & JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE) != 0; } diff --git a/src/share/vm/utilities/array.hpp b/src/share/vm/utilities/array.hpp index 5578ed9b6..fb32f5ca8 100644 --- a/src/share/vm/utilities/array.hpp +++ b/src/share/vm/utilities/array.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -317,10 +317,10 @@ protected: Array(const Array<T>&); void operator=(const Array<T>&); - void* operator new(size_t size, ClassLoaderData* loader_data, int length, bool read_only, TRAPS) { + void* operator new(size_t size, ClassLoaderData* loader_data, int length, bool read_only, TRAPS) throw() { size_t word_size = Array::size(length); return (void*) Metaspace::allocate(loader_data, word_size, read_only, - Metaspace::NonClassType, CHECK_NULL); + MetaspaceObj::array_type(sizeof(T)), CHECK_NULL); } static size_t byte_sizeof(int length) { return sizeof(Array<T>) + MAX2(length - 1, 0) * sizeof(T); } diff --git a/src/share/vm/utilities/bitMap.cpp b/src/share/vm/utilities/bitMap.cpp index 152b40d39..01825d302 100644 --- a/src/share/vm/utilities/bitMap.cpp +++ b/src/share/vm/utilities/bitMap.cpp @@ -41,7 +41,7 @@ BitMap::BitMap(bm_word_t* map, idx_t size_in_bits) : - _map(map), _size(size_in_bits) + _map(map), _size(size_in_bits), _map_allocator(false) { assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption."); assert(size_in_bits >= 0, "just checking"); @@ -49,7 +49,7 @@ BitMap::BitMap(bm_word_t* map, idx_t size_in_bits) : BitMap::BitMap(idx_t size_in_bits, bool in_resource_area) : - _map(NULL), _size(0) + _map(NULL), _size(0), _map_allocator(false) { assert(sizeof(bm_word_t) == BytesPerWord, "Implementation assumption."); resize(size_in_bits, in_resource_area); @@ -65,8 +65,10 @@ void BitMap::resize(idx_t size_in_bits, bool in_resource_area) { if (in_resource_area) { _map = NEW_RESOURCE_ARRAY(bm_word_t, new_size_in_words); } else { - if (old_map != NULL) FREE_C_HEAP_ARRAY(bm_word_t, _map, mtInternal); - _map = NEW_C_HEAP_ARRAY(bm_word_t, new_size_in_words, mtInternal); + if (old_map != NULL) { + _map_allocator.free(); + } + _map = _map_allocator.allocate(new_size_in_words); } Copy::disjoint_words((HeapWord*)old_map, (HeapWord*) _map, MIN2(old_size_in_words, new_size_in_words)); diff --git a/src/share/vm/utilities/bitMap.hpp b/src/share/vm/utilities/bitMap.hpp index 2486533ab..c4cac118b 100644 --- a/src/share/vm/utilities/bitMap.hpp +++ b/src/share/vm/utilities/bitMap.hpp @@ -48,6 +48,7 @@ class BitMap VALUE_OBJ_CLASS_SPEC { } RangeSizeHint; private: + ArrayAllocator<bm_word_t, mtInternal> _map_allocator; bm_word_t* _map; // First word in bitmap idx_t _size; // Size of bitmap (in bits) @@ -113,7 +114,7 @@ class BitMap VALUE_OBJ_CLASS_SPEC { public: // Constructs a bitmap with no map, and size 0. - BitMap() : _map(NULL), _size(0) {} + BitMap() : _map(NULL), _size(0), _map_allocator(false) {} // Constructs a bitmap with the given map and size. BitMap(bm_word_t* map, idx_t size_in_bits); diff --git a/src/share/vm/utilities/bitMap.inline.hpp b/src/share/vm/utilities/bitMap.inline.hpp index 7bb244795..2171e849f 100644 --- a/src/share/vm/utilities/bitMap.inline.hpp +++ b/src/share/vm/utilities/bitMap.inline.hpp @@ -52,16 +52,16 @@ inline void BitMap::clear_bit(idx_t bit) { inline bool BitMap::par_set_bit(idx_t bit) { verify_index(bit); - volatile idx_t* const addr = word_addr(bit); - const idx_t mask = bit_mask(bit); - idx_t old_val = *addr; + volatile bm_word_t* const addr = word_addr(bit); + const bm_word_t mask = bit_mask(bit); + bm_word_t old_val = *addr; do { - const idx_t new_val = old_val | mask; + const bm_word_t new_val = old_val | mask; if (new_val == old_val) { return false; // Someone else beat us to it. } - const idx_t cur_val = (idx_t) Atomic::cmpxchg_ptr((void*) new_val, + const bm_word_t cur_val = (bm_word_t) Atomic::cmpxchg_ptr((void*) new_val, (volatile void*) addr, (void*) old_val); if (cur_val == old_val) { @@ -73,16 +73,16 @@ inline bool BitMap::par_set_bit(idx_t bit) { inline bool BitMap::par_clear_bit(idx_t bit) { verify_index(bit); - volatile idx_t* const addr = word_addr(bit); - const idx_t mask = ~bit_mask(bit); - idx_t old_val = *addr; + volatile bm_word_t* const addr = word_addr(bit); + const bm_word_t mask = ~bit_mask(bit); + bm_word_t old_val = *addr; do { - const idx_t new_val = old_val & mask; + const bm_word_t new_val = old_val & mask; if (new_val == old_val) { return false; // Someone else beat us to it. } - const idx_t cur_val = (idx_t) Atomic::cmpxchg_ptr((void*) new_val, + const bm_word_t cur_val = (bm_word_t) Atomic::cmpxchg_ptr((void*) new_val, (volatile void*) addr, (void*) old_val); if (cur_val == old_val) { diff --git a/src/share/vm/utilities/debug.cpp b/src/share/vm/utilities/debug.cpp index a675c27bf..31d13f794 100644 --- a/src/share/vm/utilities/debug.cpp +++ b/src/share/vm/utilities/debug.cpp @@ -314,8 +314,8 @@ bool is_error_reported() { #ifndef PRODUCT #include <signal.h> -void test_error_handler(size_t test_num) -{ +void test_error_handler() { + uintx test_num = ErrorHandlerTest; if (test_num == 0) return; // If asserts are disabled, use the corresponding guarantee instead. @@ -327,6 +327,8 @@ void test_error_handler(size_t test_num) const char* const eol = os::line_separator(); const char* const msg = "this message should be truncated during formatting"; + char * const dataPtr = NULL; // bad data pointer + const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer // Keep this in sync with test/runtime/6888954/vmerrors.sh. switch (n) { @@ -348,11 +350,16 @@ void test_error_handler(size_t test_num) case 9: ShouldNotCallThis(); case 10: ShouldNotReachHere(); case 11: Unimplemented(); - // This is last because it does not generate an hs_err* file on Windows. - case 12: os::signal_raise(SIGSEGV); - - default: ShouldNotReachHere(); + // There's no guarantee the bad data pointer will crash us + // so "break" out to the ShouldNotReachHere(). + case 12: *dataPtr = '\0'; break; + // There's no guarantee the bad function pointer will crash us + // so "break" out to the ShouldNotReachHere(). + case 13: (*funcPtr)(); break; + + default: tty->print_cr("ERROR: %d: unexpected test_num value.", n); } + ShouldNotReachHere(); } #endif // !PRODUCT @@ -665,152 +672,4 @@ void help() { tty->print_cr(" ndebug() - undo debug"); } -#if 0 - -// BobV's command parser for debugging on windows when nothing else works. - -enum CommandID { - CMDID_HELP, - CMDID_QUIT, - CMDID_HSFIND, - CMDID_PSS, - CMDID_PS, - CMDID_PSF, - CMDID_FINDM, - CMDID_FINDNM, - CMDID_PP, - CMDID_BPT, - CMDID_EXIT, - CMDID_VERIFY, - CMDID_THREADS, - CMDID_ILLEGAL = 99 -}; - -struct CommandParser { - char *name; - CommandID code; - char *description; -}; - -struct CommandParser CommandList[] = { - (char *)"help", CMDID_HELP, " Dump this list", - (char *)"quit", CMDID_QUIT, " Return from this routine", - (char *)"hsfind", CMDID_HSFIND, "Perform an hsfind on an address", - (char *)"ps", CMDID_PS, " Print Current Thread Stack Trace", - (char *)"pss", CMDID_PSS, " Print All Thread Stack Trace", - (char *)"psf", CMDID_PSF, " Print All Stack Frames", - (char *)"findm", CMDID_FINDM, " Find a Method* from a PC", - (char *)"findnm", CMDID_FINDNM, "Find an nmethod from a PC", - (char *)"pp", CMDID_PP, " Find out something about a pointer", - (char *)"break", CMDID_BPT, " Execute a breakpoint", - (char *)"exitvm", CMDID_EXIT, "Exit the VM", - (char *)"verify", CMDID_VERIFY, "Perform a Heap Verify", - (char *)"thread", CMDID_THREADS, "Dump Info on all Threads", - (char *)0, CMDID_ILLEGAL -}; - - -// get_debug_command() -// -// Read a command from standard input. -// This is useful when you have a debugger -// which doesn't support calling into functions. -// -void get_debug_command() -{ - ssize_t count; - int i,j; - bool gotcommand; - intptr_t addr; - char buffer[256]; - nmethod *nm; - Method* m; - - tty->print_cr("You have entered the diagnostic command interpreter"); - tty->print("The supported commands are:\n"); - for ( i=0; ; i++ ) { - if ( CommandList[i].code == CMDID_ILLEGAL ) - break; - tty->print_cr(" %s \n", CommandList[i].name ); - } - - while ( 1 ) { - gotcommand = false; - tty->print("Please enter a command: "); - count = scanf("%s", buffer) ; - if ( count >=0 ) { - for ( i=0; ; i++ ) { - if ( CommandList[i].code == CMDID_ILLEGAL ) { - if (!gotcommand) tty->print("Invalid command, please try again\n"); - break; - } - if ( strcmp(buffer, CommandList[i].name) == 0 ) { - gotcommand = true; - switch ( CommandList[i].code ) { - case CMDID_PS: - ps(); - break; - case CMDID_PSS: - pss(); - break; - case CMDID_PSF: - psf(); - break; - case CMDID_FINDM: - tty->print("Please enter the hex addr to pass to findm: "); - scanf("%I64X", &addr); - m = (Method*)findm(addr); - tty->print("findm(0x%I64X) returned 0x%I64X\n", addr, m); - break; - case CMDID_FINDNM: - tty->print("Please enter the hex addr to pass to findnm: "); - scanf("%I64X", &addr); - nm = (nmethod*)findnm(addr); - tty->print("findnm(0x%I64X) returned 0x%I64X\n", addr, nm); - break; - case CMDID_PP: - tty->print("Please enter the hex addr to pass to pp: "); - scanf("%I64X", &addr); - pp((void*)addr); - break; - case CMDID_EXIT: - exit(0); - case CMDID_HELP: - tty->print("Here are the supported commands: "); - for ( j=0; ; j++ ) { - if ( CommandList[j].code == CMDID_ILLEGAL ) - break; - tty->print_cr(" %s -- %s\n", CommandList[j].name, - CommandList[j].description ); - } - break; - case CMDID_QUIT: - return; - break; - case CMDID_BPT: - BREAKPOINT; - break; - case CMDID_VERIFY: - verify();; - break; - case CMDID_THREADS: - threads();; - break; - case CMDID_HSFIND: - tty->print("Please enter the hex addr to pass to hsfind: "); - scanf("%I64X", &addr); - tty->print("Calling hsfind(0x%I64X)\n", addr); - hsfind(addr); - break; - default: - case CMDID_ILLEGAL: - break; - } - } - } - } - } -} -#endif - #endif // !PRODUCT diff --git a/src/share/vm/utilities/debug.hpp b/src/share/vm/utilities/debug.hpp index 9a8332feb..85b26f35f 100644 --- a/src/share/vm/utilities/debug.hpp +++ b/src/share/vm/utilities/debug.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -225,6 +225,22 @@ void report_untested(const char* file, int line, const char* message); void warning(const char* format, ...); +#ifdef ASSERT +// Compile-time asserts. +template <bool> struct StaticAssert; +template <> struct StaticAssert<true> {}; + +// Only StaticAssert<true> is defined, so if cond evaluates to false we get +// a compile time exception when trying to use StaticAssert<false>. +#define STATIC_ASSERT(cond) \ + do { \ + StaticAssert<(cond)> DUMMY_STATIC_ASSERT; \ + (void)DUMMY_STATIC_ASSERT; /* ignore */ \ + } while (false) +#else +#define STATIC_ASSERT(cond) +#endif + // out of shared space reporting enum SharedSpaceType { SharedPermGen, @@ -243,7 +259,7 @@ bool is_error_reported(); void set_error_reported(); /* Test assert(), fatal(), guarantee(), etc. */ -NOT_PRODUCT(void test_error_handler(size_t test_num);) +NOT_PRODUCT(void test_error_handler();) void pd_ps(frame f); void pd_obfuscate_location(char *buf, size_t buflen); diff --git a/src/share/vm/utilities/decoder.cpp b/src/share/vm/utilities/decoder.cpp index 5489fe6fe..3fc934b4f 100644 --- a/src/share/vm/utilities/decoder.cpp +++ b/src/share/vm/utilities/decoder.cpp @@ -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 @@ AbstractDecoder* Decoder::create_decoder() { 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; diff --git a/src/share/vm/utilities/decoder.hpp b/src/share/vm/utilities/decoder.hpp index 0d2af8098..0cc880f19 100644 --- a/src/share/vm/utilities/decoder.hpp +++ b/src/share/vm/utilities/decoder.hpp @@ -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 @@ private: 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 diff --git a/src/share/vm/utilities/events.hpp b/src/share/vm/utilities/events.hpp index c2e543da9..804fe77df 100644 --- a/src/share/vm/utilities/events.hpp +++ b/src/share/vm/utilities/events.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -69,7 +69,7 @@ class EventLog : public CHeapObj<mtInternal> { // semantics aren't appropriate. The name is used as the label of the // log when it is dumped during a crash. template <class T> class EventLogBase : public EventLog { - template <class X> class EventRecord { + template <class X> class EventRecord : public CHeapObj<mtInternal> { public: double timestamp; Thread* thread; diff --git a/src/share/vm/utilities/exceptions.cpp b/src/share/vm/utilities/exceptions.cpp index 6083c555c..af5f974f1 100644 --- a/src/share/vm/utilities/exceptions.cpp +++ b/src/share/vm/utilities/exceptions.cpp @@ -125,13 +125,13 @@ void Exceptions::_throw_oop(Thread* thread, const char* file, int line, oop exce } void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exception, const char* message) { + ResourceMark rm; assert(h_exception() != NULL, "exception should not be NULL"); // tracing (do this up front - so it works during boot strapping) if (TraceExceptions) { ttyLocker ttyl; - ResourceMark rm; - tty->print_cr("Exception <%s>%s%s (" INTPTR_FORMAT " ) \n" + tty->print_cr("Exception <%s%s%s> (" INTPTR_FORMAT ") \n" "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, h_exception->print_value_string(), message ? ": " : "", message ? message : "", @@ -141,7 +141,9 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc NOT_PRODUCT(Exceptions::debug_check_abort(h_exception, message)); // Check for special boot-strapping/vm-thread handling - if (special_exception(thread, file, line, h_exception)) return; + if (special_exception(thread, file, line, h_exception)) { + return; + } assert(h_exception->is_a(SystemDictionary::Throwable_klass()), "exception is not a subclass of java/lang/Throwable"); @@ -149,7 +151,9 @@ void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exc thread->set_pending_exception(h_exception(), file, line); // vm log - Events::log_exception(thread, "Threw " INTPTR_FORMAT " at %s:%d", (address)h_exception(), file, line); + Events::log_exception(thread, "Exception <%s%s%s> (" INTPTR_FORMAT ") thrown at [%s, line %d]", + h_exception->print_value_string(), message ? ": " : "", message ? message : "", + (address)h_exception(), file, line); } diff --git a/src/share/vm/utilities/exceptions.hpp b/src/share/vm/utilities/exceptions.hpp index 089cd3e08..beaabf8dc 100644 --- a/src/share/vm/utilities/exceptions.hpp +++ b/src/share/vm/utilities/exceptions.hpp @@ -194,15 +194,15 @@ class Exceptions { #define HAS_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->has_pending_exception()) #define CLEAR_PENDING_EXCEPTION (((ThreadShadow*)THREAD)->clear_pending_exception()) -#define CHECK THREAD); if (HAS_PENDING_EXCEPTION) return ; (0 -#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (0 +#define CHECK THREAD); if (HAS_PENDING_EXCEPTION) return ; (void)(0 +#define CHECK_(result) THREAD); if (HAS_PENDING_EXCEPTION) return result; (void)(0 #define CHECK_0 CHECK_(0) #define CHECK_NH CHECK_(Handle()) #define CHECK_NULL CHECK_(NULL) #define CHECK_false CHECK_(false) -#define CHECK_AND_CLEAR THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return; } (0 -#define CHECK_AND_CLEAR_(result) THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return result; } (0 +#define CHECK_AND_CLEAR THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return; } (void)(0 +#define CHECK_AND_CLEAR_(result) THREAD); if (HAS_PENDING_EXCEPTION) { CLEAR_PENDING_EXCEPTION; return result; } (void)(0 #define CHECK_AND_CLEAR_0 CHECK_AND_CLEAR_(0) #define CHECK_AND_CLEAR_NH CHECK_AND_CLEAR_(Handle()) #define CHECK_AND_CLEAR_NULL CHECK_AND_CLEAR_(NULL) @@ -282,7 +282,7 @@ class Exceptions { CLEAR_PENDING_EXCEPTION; \ ex->print(); \ ShouldNotReachHere(); \ - } (0 + } (void)(0 // ExceptionMark is a stack-allocated helper class for local exception handling. // It is used with the EXCEPTION_MARK macro. @@ -306,6 +306,6 @@ class ExceptionMark { // which preserves pre-existing exceptions and does not allow new // exceptions. -#define EXCEPTION_MARK Thread* THREAD; ExceptionMark __em(THREAD); +#define EXCEPTION_MARK Thread* THREAD = NULL; ExceptionMark __em(THREAD); #endif // SHARE_VM_UTILITIES_EXCEPTIONS_HPP diff --git a/src/share/vm/utilities/globalDefinitions.hpp b/src/share/vm/utilities/globalDefinitions.hpp index 8a6467bf2..bc3401de9 100644 --- a/src/share/vm/utilities/globalDefinitions.hpp +++ b/src/share/vm/utilities/globalDefinitions.hpp @@ -362,6 +362,8 @@ const int KlassAlignment = KlassAlignmentInBytes / HeapWordSize; // Klass encoding metaspace max size const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlassAlignmentInBytes; +const jlong CompressedKlassPointersBase = NOT_LP64(0) LP64_ONLY(CONST64(0x800000000)); // 32*G + // Machine dependent stuff #ifdef TARGET_ARCH_x86 @@ -383,6 +385,14 @@ const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlass # include "globalDefinitions_ppc.hpp" #endif +/* + * If a platform does not support native stack walking + * the platform specific globalDefinitions (above) + * can set PLATFORM_NATIVE_STACK_WALKING_SUPPORTED to 0 + */ +#ifndef PLATFORM_NATIVE_STACK_WALKING_SUPPORTED +#define PLATFORM_NATIVE_STACK_WALKING_SUPPORTED 1 +#endif // The byte alignment to be used by Arena::Amalloc. See bugid 4169348. // Note: this value must be a power of 2 @@ -395,6 +405,14 @@ const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlass #define align_size_up_(size, alignment) (((size) + ((alignment) - 1)) & ~((alignment) - 1)) +inline bool is_size_aligned(size_t size, size_t alignment) { + return align_size_up_(size, alignment) == size; +} + +inline bool is_ptr_aligned(void* ptr, size_t alignment) { + return align_size_up_((intptr_t)ptr, (intptr_t)alignment) == (intptr_t)ptr; +} + inline intptr_t align_size_up(intptr_t size, intptr_t alignment) { return align_size_up_(size, alignment); } @@ -405,6 +423,16 @@ inline intptr_t align_size_down(intptr_t size, intptr_t alignment) { return align_size_down_(size, alignment); } +#define is_size_aligned_(size, alignment) ((size) == (align_size_up_(size, alignment))) + +inline void* align_ptr_up(void* ptr, size_t alignment) { + return (void*)align_size_up((intptr_t)ptr, (intptr_t)alignment); +} + +inline void* align_ptr_down(void* ptr, size_t alignment) { + return (void*)align_size_down((intptr_t)ptr, (intptr_t)alignment); +} + // Align objects by rounding up their size, in HeapWord units. #define align_object_size_(size) align_size_up_(size, MinObjAlignment) @@ -423,6 +451,10 @@ inline intptr_t align_object_offset(intptr_t offset) { return align_size_up(offset, HeapWordsPerLong); } +inline void* align_pointer_up(const void* addr, size_t size) { + return (void*) align_size_up_((uintptr_t)addr, size); +} + // Clamp an address to be within a specific page // 1. If addr is on the page it is returned as is // 2. If addr is above the page_address the start of the *next* page will be returned @@ -444,32 +476,6 @@ inline address clamp_address_in_page(address addr, address page_address, intptr_ // The expected size in bytes of a cache line, used to pad data structures. #define DEFAULT_CACHE_LINE_SIZE 64 -// Bytes needed to pad type to avoid cache-line sharing; alignment should be the -// expected cache line size (a power of two). The first addend avoids sharing -// when the start address is not a multiple of alignment; the second maintains -// alignment of starting addresses that happen to be a multiple. -#define PADDING_SIZE(type, alignment) \ - ((alignment) + align_size_up_(sizeof(type), alignment)) - -// Templates to create a subclass padded to avoid cache line sharing. These are -// effective only when applied to derived-most (leaf) classes. - -// When no args are passed to the base ctor. -template <class T, size_t alignment = DEFAULT_CACHE_LINE_SIZE> -class Padded: public T { -private: - char _pad_buf_[PADDING_SIZE(T, alignment)]; -}; - -// When either 0 or 1 args may be passed to the base ctor. -template <class T, typename Arg1T, size_t alignment = DEFAULT_CACHE_LINE_SIZE> -class Padded01: public T { -public: - Padded01(): T() { } - Padded01(Arg1T arg1): T(arg1) { } -private: - char _pad_buf_[PADDING_SIZE(T, alignment)]; -}; //---------------------------------------------------------------------------------------------------- // Utility macros for compilers @@ -758,18 +764,6 @@ inline BasicType as_BasicType(TosState state) { TosState as_TosState(BasicType type); -// ReferenceType is used to distinguish between java/lang/ref/Reference subclasses - -enum ReferenceType { - REF_NONE, // Regular class - REF_OTHER, // Subclass of java/lang/ref/Reference, but not subclass of one of the classes below - REF_SOFT, // Subclass of java/lang/ref/SoftReference - REF_WEAK, // Subclass of java/lang/ref/WeakReference - REF_FINAL, // Subclass of java/lang/ref/FinalReference - REF_PHANTOM // Subclass of java/lang/ref/PhantomReference -}; - - // JavaThreadState keeps track of which part of the code a thread is executing in. This // information is needed by the safepoint code. // diff --git a/src/share/vm/utilities/growableArray.hpp b/src/share/vm/utilities/growableArray.hpp index 932d0a202..866a23ad9 100644 --- a/src/share/vm/utilities/growableArray.hpp +++ b/src/share/vm/utilities/growableArray.hpp @@ -194,6 +194,7 @@ template<class E> class GrowableArray : public GenericGrowableArray { void clear() { _len = 0; } int length() const { return _len; } + int max_length() const { return _max; } void trunc_to(int l) { assert(l <= _len,"cannot increase length"); _len = l; } bool is_empty() const { return _len == 0; } bool is_nonempty() const { return _len != 0; } diff --git a/src/share/vm/utilities/hashtable.cpp b/src/share/vm/utilities/hashtable.cpp index 960474aba..ecb43da83 100644 --- a/src/share/vm/utilities/hashtable.cpp +++ b/src/share/vm/utilities/hashtable.cpp @@ -33,6 +33,7 @@ #include "utilities/dtrace.hpp" #include "utilities/hashtable.hpp" #include "utilities/hashtable.inline.hpp" +#include "utilities/numberSeq.hpp" // This is a generic hashtable, designed to be used for the symbol @@ -237,6 +238,57 @@ template <class T, MEMFLAGS F> void Hashtable<T, F>::reverse(void* boundary) { } } +template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(Symbol *symbol) { + return symbol->size() * HeapWordSize; +} + +template <class T, MEMFLAGS F> int Hashtable<T, F>::literal_size(oop oop) { + // NOTE: this would over-count if (pre-JDK8) java_lang_Class::has_offset_field() is true, + // and the String.value array is shared by several Strings. However, starting from JDK8, + // the String.value array is not shared anymore. + assert(oop != NULL && oop->klass() == SystemDictionary::String_klass(), "only strings are supported"); + return (oop->size() + java_lang_String::value(oop)->size()) * HeapWordSize; +} + +// Dump footprint and bucket length statistics +// +// Note: if you create a new subclass of Hashtable<MyNewType, F>, you will need to +// add a new function Hashtable<T, F>::literal_size(MyNewType lit) + +template <class T, MEMFLAGS F> void Hashtable<T, F>::dump_table(outputStream* st, const char *table_name) { + NumberSeq summary; + int literal_bytes = 0; + for (int i = 0; i < this->table_size(); ++i) { + int count = 0; + for (HashtableEntry<T, F>* e = bucket(i); + e != NULL; e = e->next()) { + count++; + literal_bytes += literal_size(e->literal()); + } + summary.add((double)count); + } + double num_buckets = summary.num(); + double num_entries = summary.sum(); + + int bucket_bytes = (int)num_buckets * sizeof(bucket(0)); + int entry_bytes = (int)num_entries * sizeof(HashtableEntry<T, F>); + int total_bytes = literal_bytes + bucket_bytes + entry_bytes; + + double bucket_avg = (num_buckets <= 0) ? 0 : (bucket_bytes / num_buckets); + double entry_avg = (num_entries <= 0) ? 0 : (entry_bytes / num_entries); + double literal_avg = (num_entries <= 0) ? 0 : (literal_bytes / num_entries); + + st->print_cr("%s statistics:", table_name); + st->print_cr("Number of buckets : %9d = %9d bytes, avg %7.3f", (int)num_buckets, bucket_bytes, bucket_avg); + st->print_cr("Number of entries : %9d = %9d bytes, avg %7.3f", (int)num_entries, entry_bytes, entry_avg); + st->print_cr("Number of literals : %9d = %9d bytes, avg %7.3f", (int)num_entries, literal_bytes, literal_avg); + st->print_cr("Total footprint : %9s = %9d bytes", "", total_bytes); + st->print_cr("Average bucket size : %9.3f", summary.avg()); + st->print_cr("Variance of bucket size : %9.3f", summary.variance()); + st->print_cr("Std. dev. of bucket size: %9.3f", summary.sd()); + st->print_cr("Maximum bucket size : %9d", (int)summary.maximum()); +} + // Dump the hash table buckets. diff --git a/src/share/vm/utilities/hashtable.hpp b/src/share/vm/utilities/hashtable.hpp index f170e6018..826823bdc 100644 --- a/src/share/vm/utilities/hashtable.hpp +++ b/src/share/vm/utilities/hashtable.hpp @@ -282,6 +282,19 @@ protected: static bool use_alternate_hashcode() { return _seed != 0; } static jint seed() { return _seed; } + static int literal_size(Symbol *symbol); + static int literal_size(oop oop); + + // The following two are currently not used, but are needed anyway because some + // C++ compilers (MacOS and Solaris) force the instantiation of + // Hashtable<ConstantPool*, mtClass>::dump_table() even though we never call this function + // in the VM code. + static int literal_size(ConstantPool *cp) {Unimplemented(); return 0;} + static int literal_size(Klass *k) {Unimplemented(); return 0;} + +public: + void dump_table(outputStream* st, const char *table_name); + private: static jint _seed; }; diff --git a/src/share/vm/utilities/macros.hpp b/src/share/vm/utilities/macros.hpp index 10f5fc0d4..f2b4ec9d2 100644 --- a/src/share/vm/utilities/macros.hpp +++ b/src/share/vm/utilities/macros.hpp @@ -160,6 +160,10 @@ #define NOT_NMT_RETURN_(code) { return code; } #endif // INCLUDE_NMT +#ifndef INCLUDE_TRACE +#define INCLUDE_TRACE 1 +#endif // INCLUDE_TRACE + // COMPILER1 variant #ifdef COMPILER1 #ifdef COMPILER2 diff --git a/src/share/vm/utilities/ostream.cpp b/src/share/vm/utilities/ostream.cpp index 1d066ddde..e4215504a 100644 --- a/src/share/vm/utilities/ostream.cpp +++ b/src/share/vm/utilities/ostream.cpp @@ -296,6 +296,7 @@ stringStream::stringStream(size_t initial_size) : outputStream() { buffer = NEW_RESOURCE_ARRAY(char, buffer_length); buffer_pos = 0; buffer_fixed = false; + DEBUG_ONLY(rm = Thread::current()->current_resource_mark();) } // useful for output to fixed chunks of memory, such as performance counters @@ -321,6 +322,8 @@ void stringStream::write(const char* s, size_t len) { end = buffer_length * 2; } char* oldbuf = buffer; + assert(rm == NULL || Thread::current()->current_resource_mark() == rm, + "stringStream is re-allocated with a different ResourceMark"); buffer = NEW_RESOURCE_ARRAY(char, end); strncpy(buffer, oldbuf, buffer_pos); buffer_length = end; @@ -339,7 +342,7 @@ void stringStream::write(const char* s, size_t len) { } 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; @@ -352,14 +355,190 @@ outputStream* tty; 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) { @@ -420,34 +599,51 @@ void fdStream::write(const char* s, size_t len) { 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); -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; + // 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; + } } -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; @@ -463,7 +659,12 @@ void rotatingFileStream::write(const char* s, size_t len) { // 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; } @@ -478,27 +679,89 @@ void rotatingFileStream::rotate_log() { // 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); } } @@ -527,69 +790,9 @@ bool defaultStream::has_log_file() { 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"; + const char* log_name = LogFile != NULL ? LogFile : "hotspot_pid%p.log"; const char* try_name = make_log_name(log_name, NULL); fileStream* file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); if (!file->is_open()) { @@ -600,14 +803,15 @@ void defaultStream::init_log() { // Note: This feature is for maintainer use only. No need for L10N. jio_print(warnbuf); FREE_C_HEAP_ARRAY(char, try_name, mtInternal); - try_name = make_log_name("hs_pid%p.log", os::get_temp_directory()); + try_name = make_log_name(log_name, os::get_temp_directory()); jio_snprintf(warnbuf, sizeof(warnbuf), "Warning: Forcing option -XX:LogFile=%s\n", try_name); jio_print(warnbuf); delete file; file = new(ResourceObj::C_HEAP, mtInternal) fileStream(try_name); - FREE_C_HEAP_ARRAY(char, try_name, mtInternal); } + FREE_C_HEAP_ARRAY(char, try_name, mtInternal); + if (file->is_open()) { _log_file = file; xmlStream* xs = new(ResourceObj::C_HEAP, mtInternal) xmlStream(file); @@ -874,11 +1078,8 @@ void ostream_init_log() { 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. diff --git a/src/share/vm/utilities/ostream.hpp b/src/share/vm/utilities/ostream.hpp index 6b154184b..9b1b1217b 100644 --- a/src/share/vm/utilities/ostream.hpp +++ b/src/share/vm/utilities/ostream.hpp @@ -28,6 +28,8 @@ #include "memory/allocation.hpp" #include "runtime/timer.hpp" +DEBUG_ONLY(class ResourceMark;) + // Output streams for printing // // Printing guidelines: @@ -177,6 +179,7 @@ class stringStream : public outputStream { size_t buffer_pos; size_t buffer_length; bool buffer_fixed; + DEBUG_ONLY(ResourceMark* rm;) public: stringStream(size_t initial_bufsize = 256); stringStream(char* fixed_buffer, size_t fixed_buffer_size); @@ -228,20 +231,24 @@ class fdStream : public outputStream { 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(); diff --git a/src/share/vm/utilities/quickSort.cpp b/src/share/vm/utilities/quickSort.cpp index e3cfa1efa..0cb7f6ef8 100644 --- a/src/share/vm/utilities/quickSort.cpp +++ b/src/share/vm/utilities/quickSort.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -30,8 +30,11 @@ #include "runtime/os.hpp" #include "utilities/quickSort.hpp" +#include "memory/allocation.hpp" +#include "memory/allocation.inline.hpp" #include <stdlib.h> +#ifdef ASSERT static int test_comparator(int a, int b) { if (a == b) { return 0; @@ -41,6 +44,7 @@ static int test_comparator(int a, int b) { } return 1; } +#endif // ASSERT static int test_even_odd_comparator(int a, int b) { bool a_is_odd = (a % 2) == 1; @@ -187,8 +191,8 @@ void QuickSort::test_quick_sort() { // test sorting random arrays for (int i = 0; i < 1000; i++) { int length = os::random() % 100; - int* test_array = new int[length]; - int* expected_array = new int[length]; + int* test_array = NEW_C_HEAP_ARRAY(int, length, mtInternal); + int* expected_array = NEW_C_HEAP_ARRAY(int, length, mtInternal); for (int j = 0; j < length; j++) { // Choose random values, but get a chance of getting duplicates test_array[j] = os::random() % (length * 2); @@ -210,8 +214,8 @@ void QuickSort::test_quick_sort() { sort(test_array, length, test_even_odd_comparator, true); assert(compare_arrays(test_array, expected_array, length), "Sorting already sorted array changed order of elements - not idempotent"); - delete[] test_array; - delete[] expected_array; + FREE_C_HEAP_ARRAY(int, test_array, mtInternal); + FREE_C_HEAP_ARRAY(int, expected_array, mtInternal); } } diff --git a/src/share/vm/utilities/taskqueue.hpp b/src/share/vm/utilities/taskqueue.hpp index 0dcc7c262..8b558c988 100644 --- a/src/share/vm/utilities/taskqueue.hpp +++ b/src/share/vm/utilities/taskqueue.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -135,6 +135,8 @@ void TaskQueueStats::reset() { } #endif // TASKQUEUE_STATS +// TaskQueueSuper collects functionality common to all GenericTaskQueue instances. + template <unsigned int N, MEMFLAGS F> class TaskQueueSuper: public CHeapObj<F> { protected: @@ -252,7 +254,36 @@ public: TASKQUEUE_STATS_ONLY(TaskQueueStats stats;) }; - +// +// GenericTaskQueue implements an ABP, Aurora-Blumofe-Plaxton, double- +// ended-queue (deque), intended for use in work stealing. Queue operations +// are non-blocking. +// +// A queue owner thread performs push() and pop_local() operations on one end +// of the queue, while other threads may steal work using the pop_global() +// method. +// +// The main difference to the original algorithm is that this +// implementation allows wrap-around at the end of its allocated +// storage, which is an array. +// +// The original paper is: +// +// Arora, N. S., Blumofe, R. D., and Plaxton, C. G. +// Thread scheduling for multiprogrammed multiprocessors. +// Theory of Computing Systems 34, 2 (2001), 115-144. +// +// The following paper provides an correctness proof and an +// implementation for weakly ordered memory models including (pseudo-) +// code containing memory barriers for a Chase-Lev deque. Chase-Lev is +// similar to ABP, with the main difference that it allows resizing of the +// underlying storage: +// +// Le, N. M., Pop, A., Cohen A., and Nardell, F. Z. +// Correct and efficient work-stealing for weak memory models +// Proceedings of the 18th ACM SIGPLAN symposium on Principles and +// practice of parallel programming (PPoPP 2013), 69-80 +// template <class E, MEMFLAGS F, unsigned int N = TASKQUEUE_SIZE> class GenericTaskQueue: public TaskQueueSuper<N, F> { @@ -343,8 +374,12 @@ bool GenericTaskQueue<E, F, N>::push_slow(E t, uint dirty_n_elems) { if (dirty_n_elems == N - 1) { // Actually means 0, so do the push. uint localBot = _bottom; - // g++ complains if the volatile result of the assignment is unused. - const_cast<E&>(_elems[localBot] = t); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void)const_cast<E&>(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); TASKQUEUE_STATS_ONLY(stats.record_push()); return true; @@ -394,13 +429,24 @@ bool GenericTaskQueue<E, F, N>::pop_local_slow(uint localBot, Age oldAge) { template<class E, MEMFLAGS F, unsigned int N> bool GenericTaskQueue<E, F, N>::pop_global(E& t) { Age oldAge = _age.get(); - uint localBot = _bottom; + // Architectures with weak memory model require a barrier here + // to guarantee that bottom is not older than age, + // which is crucial for the correctness of the algorithm. +#if !(defined SPARC || defined IA32 || defined AMD64) + OrderAccess::fence(); +#endif + uint localBot = OrderAccess::load_acquire((volatile juint*)&_bottom); uint n_elems = size(localBot, oldAge.top()); if (n_elems == 0) { return false; } - const_cast<E&>(t = _elems[oldAge.top()]); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void) const_cast<E&>(t = _elems[oldAge.top()]); Age newAge(oldAge); newAge.increment(); Age resAge = _age.cmpxchg(newAge, oldAge); @@ -638,13 +684,17 @@ public: template<class E, MEMFLAGS F, unsigned int N> inline bool GenericTaskQueue<E, F, N>::push(E t) { uint localBot = _bottom; - assert((localBot >= 0) && (localBot < N), "_bottom out of range."); + assert(localBot < N, "_bottom out of range."); idx_t top = _age.top(); uint dirty_n_elems = dirty_size(localBot, top); assert(dirty_n_elems < N, "n_elems out of range."); if (dirty_n_elems < max_elems()) { - // g++ complains if the volatile result of the assignment is unused. - const_cast<E&>(_elems[localBot] = t); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void) const_cast<E&>(_elems[localBot] = t); OrderAccess::release_store(&_bottom, increment_index(localBot)); TASKQUEUE_STATS_ONLY(stats.record_push()); return true; @@ -668,7 +718,12 @@ GenericTaskQueue<E, F, N>::pop_local(E& t) { // This is necessary to prevent any read below from being reordered // before the store just above. OrderAccess::fence(); - const_cast<E&>(t = _elems[localBot]); + // g++ complains if the volatile result of the assignment is + // unused, so we cast the volatile away. We cannot cast directly + // to void, because gcc treats that as not using the result of the + // assignment. However, casting to E& means that we trigger an + // unused-value warning. So, we cast the E& to void. + (void) const_cast<E&>(t = _elems[localBot]); // This is a second read of "age"; the "size()" above is the first. // If there's still at least one element in the queue, based on the // "_bottom" and "age" we've read, then there can be no interference with diff --git a/src/share/vm/utilities/vmError.cpp b/src/share/vm/utilities/vmError.cpp index f7b940b52..79769aeb3 100644 --- a/src/share/vm/utilities/vmError.cpp +++ b/src/share/vm/utilities/vmError.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -574,6 +574,10 @@ void VMError::report(outputStream* st) { 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(); @@ -586,6 +590,13 @@ void VMError::report(outputStream* st) { while (count++ < StackPrintLimit) { fr.print_on_error(st, buf, sizeof(buf)); st->cr(); + // Compiled code may use EBP register on x86 so it looks like + // non-walkable C frame. Use frame.sender() for java frames. + if (_thread && _thread->is_Java_thread() && fr.is_java_frame()) { + RegisterMap map((JavaThread*)_thread, false); // No update + fr = fr.sender(&map); + continue; + } if (os::is_first_C_frame(&fr)) break; fr = os::get_sender_for_C_frame(&fr); } @@ -597,6 +608,7 @@ void VMError::report(outputStream* st) { st->cr(); } } + } STEP(130, "(printing Java stack)" ) @@ -799,6 +811,14 @@ void VMError::report(outputStream* st) { VMError* volatile VMError::first_error = NULL; volatile jlong VMError::first_error_tid = -1; +// An error could happen before tty is initialized or after it has been +// destroyed. Here we use a very simple unbuffered fdStream for printing. +// Only out.print_raw() and out.print_raw_cr() should be used, as other +// printing methods need to allocate large buffer on stack. To format a +// string, use jio_snprintf() with a static buffer or use staticBufferStream. +fdStream VMError::out(defaultStream::output_fd()); +fdStream VMError::log; // error log used by VMError::report_and_die() + /** Expand a pattern into a buffer starting at pos and open a file using constructed path */ static int expand_and_open(const char* pattern, char* buf, size_t buflen, size_t pos) { int fd = -1; @@ -853,13 +873,6 @@ void VMError::report_and_die() { // Don't allocate large buffer on stack static char buffer[O_BUFLEN]; - // An error could happen before tty is initialized or after it has been - // destroyed. Here we use a very simple unbuffered fdStream for printing. - // Only out.print_raw() and out.print_raw_cr() should be used, as other - // printing methods need to allocate large buffer on stack. To format a - // string, use jio_snprintf() with a static buffer or use staticBufferStream. - static fdStream out(defaultStream::output_fd()); - // How many errors occurred in error handler when reporting first_error. static int recursive_error_count; @@ -868,7 +881,6 @@ void VMError::report_and_die() { static bool out_done = false; // done printing to standard out static bool log_done = false; // done saving error log static bool transmit_report_done = false; // done error reporting - static fdStream log; // error log // disble NMT to avoid further exception MemTracker::shutdown(MemTracker::NMT_error_reporting); @@ -908,10 +920,11 @@ void VMError::report_and_die() { // This is not the first error, see if it happened in a different thread // or in the same thread during error reporting. if (first_error_tid != mytid) { - jio_snprintf(buffer, sizeof(buffer), + char msgbuf[64]; + jio_snprintf(msgbuf, sizeof(msgbuf), "[thread " INT64_FORMAT " also had an error]", mytid); - out.print_raw_cr(buffer); + out.print_raw_cr(msgbuf); // error reporting is not MT-safe, block current thread os::infinite_sleep(); diff --git a/src/share/vm/utilities/vmError.hpp b/src/share/vm/utilities/vmError.hpp index f298c1edb..299cfaa6f 100644 --- a/src/share/vm/utilities/vmError.hpp +++ b/src/share/vm/utilities/vmError.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 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 @@ -96,6 +96,9 @@ class VMError : public StackObj { return (id != OOM_MALLOC_ERROR) && (id != OOM_MMAP_ERROR); } + static fdStream out; + static fdStream log; // error log used by VMError::report_and_die() + public: // Constructor for crashes @@ -133,6 +136,10 @@ public: // 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 diff --git a/src/share/vm/utilities/workgroup.cpp b/src/share/vm/utilities/workgroup.cpp index 5db6344fd..479cd0402 100644 --- a/src/share/vm/utilities/workgroup.cpp +++ b/src/share/vm/utilities/workgroup.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -529,7 +529,7 @@ bool FreeIdSet::_safepoint; FreeIdSet::FreeIdSet(int sz, Monitor* mon) : _sz(sz), _mon(mon), _hd(0), _waiters(0), _index(-1), _claimed(0) { - _ids = new int[sz]; + _ids = NEW_C_HEAP_ARRAY(int, sz, mtInternal); for (int i = 0; i < sz; i++) _ids[i] = i+1; _ids[sz-1] = end_of_list; // end of list. if (_stat_init) { @@ -549,6 +549,7 @@ FreeIdSet::FreeIdSet(int sz, Monitor* mon) : FreeIdSet::~FreeIdSet() { _sets[_index] = NULL; + FREE_C_HEAP_ARRAY(int, _ids, mtInternal); } void FreeIdSet::set_safepoint(bool b) { diff --git a/src/share/vm/utilities/workgroup.hpp b/src/share/vm/utilities/workgroup.hpp index 6a9353624..e1184a679 100644 --- a/src/share/vm/utilities/workgroup.hpp +++ b/src/share/vm/utilities/workgroup.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -494,7 +494,7 @@ public: }; // Represents a set of free small integer ids. -class FreeIdSet { +class FreeIdSet : public CHeapObj<mtInternal> { enum { end_of_list = -1, claimed = -2 diff --git a/src/share/vm/utilities/yieldingWorkgroup.hpp b/src/share/vm/utilities/yieldingWorkgroup.hpp index 5a626ce7f..98d8f438e 100644 --- a/src/share/vm/utilities/yieldingWorkgroup.hpp +++ b/src/share/vm/utilities/yieldingWorkgroup.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -26,10 +26,7 @@ #define SHARE_VM_UTILITIES_YIELDINGWORKGROUP_HPP #include "utilities/macros.hpp" -#if INCLUDE_ALL_GCS #include "utilities/workgroup.hpp" -#endif // INCLUDE_ALL_GCS - // Forward declarations class YieldingFlexibleWorkGang; |