# HG changeset patch # User andrew # Date 1422319577 0 # Node ID bbda609c9d24364fd233db29d24285251fd61685 # Parent 5c948ad57906413ede3a3bbfcde59c10888d06ec# Parent db9672d640ffd4e81348bdb718afab76032d8858 Merge jdk7u75-b31 diff -r 5c948ad57906 -r bbda609c9d24 .hgtags --- a/.hgtags Wed Jan 21 03:56:44 2015 +0000 +++ b/.hgtags Tue Jan 27 00:46:17 2015 +0000 @@ -725,6 +725,11 @@ 1d8226b3e9896656451801393eb3ae394faeb638 jdk7u65-b40 cf8b3a090e597e59177c5f67d44cdec12309777f jdk7u65-b31 df855c3f4d31dd7db081d68e3054518380127893 jdk7u65-b33 +39776d90970221dd260187acb4c37631e41a66a9 jdk7u67-b01 +7152f5f6395c66c8d6389100d880882d5cfe9af3 jdk7u67-b31 +4fb7952ebba8ba45be16bdc64184259e8076ffcf jdk7u67-b32 +a20f1b6311e10b755d949a088e7aeca2ba088a59 jdk7u67-b33 +39c07d2fb4d3d97bf3bb53c1c1e199709c5c49fe jdk7u67-b34 6b37a189944aaa09e81d97d394496464d16bee42 jdk7u66-b00 121dc94194d9234e2b13c867d875e23e1bdd6abd jdk7u66-b01 f28ea516eb0b9e99f1e342954ab4642456af4da1 jdk7u66-b09 @@ -754,3 +759,35 @@ 7a4b0596c5395b5836faee96923b83444cc8a266 icedtea-2.5.4pre02 606de1136fd1eee950092d6beb14d0b03e8d408e icedtea-2.5.4pre03 6144ca9b6a72e11575ea5e16751180645d8fbd5d icedtea-2.5.4 +ad909197a1ce2df483a20ff9ac380382f779a9d3 jdk7u71-b14 +1bd3adac3aac3c29c81303812b35f484ff90cb2b jdk7u72-b01 +0caed46767e35c00eff69b22acf984d98eb66b3d jdk7u72-b02 +3a2934191de4bb8ca9d2faca93f3381e521e8cac jdk7u72-b03 +e4708cde2898df4c936595aacb57bc5b4e15869a jdk7u72-b04 +137e0859cd296cb8d9f9e327112ddc793ed59318 jdk7u72-b05 +4d9d227d70f33b70461230172386217317954312 jdk7u72-b06 +ece56f93f37b41b9c8875e54fbd8010277f6b460 jdk7u72-b07 +439c695a7aa03652ab92681120434b9ce8cdd2b7 jdk7u72-b08 +a27f16d45457a68a723acca621cb11bc173a0eb6 jdk7u72-b09 +e6508ab77271d1d3ce7b5f60d91a7334fdacb03a jdk7u72-b10 +c17a8487086433e14cd22373039a8b6b48e7cbb8 jdk7u72-b11 +a9e695f0d831f115720a4dcad3d33e0003b0acad jdk7u72-b12 +ac701f87d1ea46033c69f3e1cb84fc0a971da70c jdk7u72-b13 +d9b56c6bdddb6f9d8242230f5fdd58f9c7d30ea5 jdk7u72-b14 +a6ae698522bfab3c595a4f8c2c3ee7e8939eb1bb jdk7u72-b30 +492a2abed4ca015459e24f7348233531b7e929d2 jdk7u72-b31 +e6b6d91b3934c281086f8efacb0926e7451cc18b jdk7u75-b00 +9096ac248b379a0f3012f18c7289ec47cdef8459 jdk7u75-b01 +a6964b2822d906eab9c923cdd723cf3dd4facfcd jdk7u75-b02 +6c1a8b7ed616311a932715428620e262076bb68a jdk7u75-b03 +2480d9d778301a3f88b0ab8ee35a585df82528e5 jdk7u75-b04 +d81faf9016ce5c9f98264b1f724b3d6d85b12c07 jdk7u75-b05 +2ec4b796b1de3cfe58f051111dfd70ab367e553e jdk7u75-b06 +1d3906064cae18fdb0ff9a2045f2d8d48067bcd1 jdk7u75-b07 +dfcf951330b6f7c1a3cb88c819e94f680054a970 jdk7u75-b08 +ca20e7886db63792593f048f7308aed383775829 jdk7u75-b09 +5a0321dcf89383c31f3c6e4827b3275f9ef09a5e jdk7u75-b10 +82dcfb646bd5bc9f3674cb02ea9ba2598cff6bbe jdk7u75-b11 +18b74ded3ffc2e6fc5a3853f923c8dd49849dee1 jdk7u75-b12 +384fba17a49738baddeb55a4bfcf00b01af199ef jdk7u75-b13 +0c7d7c067c46fa0ddcb9170bed1d52f52a9ec831 jdk7u75-b30 diff -r 5c948ad57906 -r bbda609c9d24 agent/src/os/linux/libproc.h --- a/agent/src/os/linux/libproc.h Wed Jan 21 03:56:44 2015 +0000 +++ b/agent/src/os/linux/libproc.h Tue Jan 27 00:46:17 2015 +0000 @@ -34,44 +34,7 @@ #include "libproc_md.h" #endif -#if defined(sparc) || defined(sparcv9) -/* - If _LP64 is defined ptrace.h should be taken from /usr/include/asm-sparc64 - otherwise it should be from /usr/include/asm-sparc - These two files define pt_regs structure differently -*/ -#ifdef _LP64 -struct pt_regs { - unsigned long u_regs[16]; /* globals and ins */ - unsigned long tstate; - unsigned long tpc; - unsigned long tnpc; - unsigned int y; - - /* We encode a magic number, PT_REGS_MAGIC, along - * with the %tt (trap type) register value at trap - * entry time. The magic number allows us to identify - * accurately a trap stack frame in the stack - * unwinder, and the %tt value allows us to test - * things like "in a system call" etc. for an arbitray - * process. - * - * The PT_REGS_MAGIC is chosen such that it can be - * loaded completely using just a sethi instruction. - */ - unsigned int magic; -}; -#else -struct pt_regs { - unsigned long psr; - unsigned long pc; - unsigned long npc; - unsigned long y; - unsigned long u_regs[16]; /* globals and ins */ -}; -#endif - -#endif //sparc or sparcv9 +#include /************************************************************************************ diff -r 5c948ad57906 -r bbda609c9d24 make/hotspot_version diff -r 5c948ad57906 -r bbda609c9d24 src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -1745,7 +1745,7 @@ inline void swap( Register s1, Register s2, Register d ); inline void swap( Register s1, int simm13a, Register d); - inline void swap( Address& a, Register d, int offset = 0 ); + inline void swap( const Address& a, Register d, int offset = 0 ); // pp 232 diff -r 5c948ad57906 -r bbda609c9d24 src/cpu/sparc/vm/assembler_sparc.inline.hpp --- a/src/cpu/sparc/vm/assembler_sparc.inline.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/cpu/sparc/vm/assembler_sparc.inline.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -347,7 +347,7 @@ inline void Assembler::swap( Register s1, Register s2, Register d) { v9_dep(); emit_long( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | rs2(s2) ); } inline void Assembler::swap( Register s1, int simm13a, Register d) { v9_dep(); emit_data( op(ldst_op) | rd(d) | op3(swap_op3) | rs1(s1) | immed(true) | simm(simm13a, 13)); } -inline void Assembler::swap( Address& a, Register d, int offset ) { +inline void Assembler::swap( const Address& a, Register d, int offset ) { relocate(a.rspec(offset)); if (a.has_index()) { assert(offset == 0, ""); swap( a.base(), a.index(), d ); } else { swap( a.base(), a.disp() + offset, d ); } diff -r 5c948ad57906 -r bbda609c9d24 src/cpu/sparc/vm/copy_sparc.hpp --- a/src/cpu/sparc/vm/copy_sparc.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/cpu/sparc/vm/copy_sparc.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -184,7 +184,7 @@ assert(MinObjAlignmentInBytes >= BytesPerLong, "need alternate implementation"); if (value == 0 && UseBlockZeroing && - (count > (BlockZeroingLowLimit >> LogHeapWordSize))) { + (count > (size_t)(BlockZeroingLowLimit >> LogHeapWordSize))) { // Call it only when block zeroing is used ((_zero_Fn)StubRoutines::zero_aligned_words())(tohw, count); } else { diff -r 5c948ad57906 -r bbda609c9d24 src/cpu/sparc/vm/frame_sparc.hpp --- a/src/cpu/sparc/vm/frame_sparc.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/cpu/sparc/vm/frame_sparc.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -282,8 +282,8 @@ // next two fns read and write Lmonitors value, private: - BasicObjectLock* interpreter_frame_monitors() const { return *interpreter_frame_monitors_addr(); } - void interpreter_frame_set_monitors(BasicObjectLock* monitors) { *interpreter_frame_monitors_addr() = monitors; } + BasicObjectLock* interpreter_frame_monitors() const; + void interpreter_frame_set_monitors(BasicObjectLock* monitors); #else public: inline interpreterState get_interpreterState() const { diff -r 5c948ad57906 -r bbda609c9d24 src/cpu/sparc/vm/frame_sparc.inline.hpp --- a/src/cpu/sparc/vm/frame_sparc.inline.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/cpu/sparc/vm/frame_sparc.inline.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -217,6 +217,13 @@ return (methodOop*)sp_addr_at( Lmethod->sp_offset_in_saved_window()); } +inline BasicObjectLock* frame::interpreter_frame_monitors() const { + return *interpreter_frame_monitors_addr(); +} + +inline void frame::interpreter_frame_set_monitors(BasicObjectLock* monitors) { + *interpreter_frame_monitors_addr() = monitors; +} // Constant pool cache diff -r 5c948ad57906 -r bbda609c9d24 src/cpu/sparc/vm/stubGenerator_sparc.cpp --- a/src/cpu/sparc/vm/stubGenerator_sparc.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/cpu/sparc/vm/stubGenerator_sparc.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -89,7 +89,7 @@ private: #ifdef PRODUCT -#define inc_counter_np(a,b,c) (0) +#define inc_counter_np(a,b,c) #else #define inc_counter_np(counter, t1, t2) \ BLOCK_COMMENT("inc_counter " #counter); \ @@ -1126,7 +1126,7 @@ Label& L_loop, bool use_prefetch, bool use_bis); void disjoint_copy_core(Register from, Register to, Register count, int log2_elem_size, - int iter_size, CopyLoopFunc copy_loop_func) { + int iter_size, StubGenerator::CopyLoopFunc copy_loop_func) { Label L_copy; assert(log2_elem_size <= 3, "the following code should be changed"); @@ -1277,7 +1277,7 @@ __ inc(from, 8); __ sllx(O3, left_shift, O3); - disjoint_copy_core(from, to, count, log2_elem_size, 16, copy_16_bytes_shift_loop); + disjoint_copy_core(from, to, count, log2_elem_size, 16, &StubGenerator::copy_16_bytes_shift_loop); __ inccc(count, count_dec>>1 ); // + 8 bytes __ brx(Assembler::negative, true, Assembler::pn, L_copy_last_bytes); @@ -2156,7 +2156,7 @@ __ dec(count, 4); // The cmp at the beginning guaranty count >= 4 __ sllx(O3, 32, O3); - disjoint_copy_core(from, to, count, 2, 16, copy_16_bytes_loop); + disjoint_copy_core(from, to, count, 2, 16, &StubGenerator::copy_16_bytes_loop); __ br(Assembler::always, false, Assembler::pt, L_copy_4_bytes); __ delayed()->inc(count, 4); // restore 'count' @@ -2437,7 +2437,7 @@ // count >= 0 (original count - 8) __ mov(from, from64); - disjoint_copy_core(from64, to64, count, 3, 64, copy_64_bytes_loop); + disjoint_copy_core(from64, to64, count, 3, 64, &StubGenerator::copy_64_bytes_loop); // Restore O4(offset0), O5(offset8) __ sub(from64, from, offset0); diff -r 5c948ad57906 -r bbda609c9d24 src/cpu/sparc/vm/vm_version_sparc.hpp --- a/src/cpu/sparc/vm/vm_version_sparc.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/cpu/sparc/vm/vm_version_sparc.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -48,7 +48,8 @@ sparc64_family = 14, M_family = 15, T_family = 16, - T1_model = 17 + T1_model = 17, + sparc5_instructions = 18 }; enum Feature_Flag_Set { @@ -73,6 +74,7 @@ M_family_m = 1 << M_family, T_family_m = 1 << T_family, T1_model_m = 1 << T1_model, + sparc5_instructions_m = 1 << sparc5_instructions, generic_v8_m = v8_instructions_m | hardware_mul32_m | hardware_div32_m | hardware_fsmuld_m, generic_v9_m = generic_v8_m | v9_instructions_m, @@ -117,6 +119,7 @@ static bool has_vis3() { return (_features & vis3_instructions_m) != 0; } static bool has_blk_init() { return (_features & blk_init_instructions_m) != 0; } static bool has_cbcond() { return (_features & cbcond_instructions_m) != 0; } + static bool has_sparc5_instr() { return (_features & sparc5_instructions_m) != 0; } static bool supports_compare_and_exchange() { return has_v9(); } @@ -127,6 +130,7 @@ static bool is_M_series() { return is_M_family(_features); } static bool is_T4() { return is_T_family(_features) && has_cbcond(); } + static bool is_T7() { return is_T_family(_features) && has_sparc5_instr(); } // Fujitsu SPARC64 static bool is_sparc64() { return (_features & sparc64_family_m) != 0; } @@ -146,7 +150,7 @@ static const char* cpu_features() { return _features_str; } static intx prefetch_data_size() { - return is_T4() ? 32 : 64; // default prefetch block size on sparc + return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc } // Prefetch diff -r 5c948ad57906 -r bbda609c9d24 src/os/bsd/vm/os_bsd.cpp --- a/src/os/bsd/vm/os_bsd.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/os/bsd/vm/os_bsd.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1297,9 +1297,20 @@ ////////////////////////////////////////////////////////////////////////////// // thread local storage +// Restore the thread pointer if the destructor is called. This is in case +// someone from JNI code sets up a destructor with pthread_key_create to run +// detachCurrentThread on thread death. Unless we restore the thread pointer we +// will hang or crash. When detachCurrentThread is called the key will be set +// to null and we will not be called again. If detachCurrentThread is never +// called we could loop forever depending on the pthread implementation. +static void restore_thread_pointer(void* p) { + Thread* thread = (Thread*) p; + os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread); +} + int os::allocate_thread_local_storage() { pthread_key_t key; - int rslt = pthread_key_create(&key, NULL); + int rslt = pthread_key_create(&key, restore_thread_pointer); assert(rslt == 0, "cannot allocate thread local storage"); return (int)key; } diff -r 5c948ad57906 -r bbda609c9d24 src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/os/linux/vm/os_linux.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1113,9 +1113,20 @@ ////////////////////////////////////////////////////////////////////////////// // thread local storage +// Restore the thread pointer if the destructor is called. This is in case +// someone from JNI code sets up a destructor with pthread_key_create to run +// detachCurrentThread on thread death. Unless we restore the thread pointer we +// will hang or crash. When detachCurrentThread is called the key will be set +// to null and we will not be called again. If detachCurrentThread is never +// called we could loop forever depending on the pthread implementation. +static void restore_thread_pointer(void* p) { + Thread* thread = (Thread*) p; + os::thread_local_storage_at_put(ThreadLocalStorage::thread_index(), thread); +} + int os::allocate_thread_local_storage() { pthread_key_t key; - int rslt = pthread_key_create(&key, NULL); + int rslt = pthread_key_create(&key, restore_thread_pointer); assert(rslt == 0, "cannot allocate thread local storage"); return (int)key; } diff -r 5c948ad57906 -r bbda609c9d24 src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp --- a/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/os_cpu/linux_sparc/vm/assembler_linux_sparc.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -28,16 +28,7 @@ #include "runtime/os.hpp" #include "runtime/threadLocalStorage.hpp" -/* Headers for 32bit sparc with a 32bit userland end up in asm/ - * Headers for 32bit sparc with a 64bit userland end up in asm-sparc/ - * There is no traps.h in asm-sparc64/ - */ - -#if defined(__sparc__) && defined(__arch64__) -# include -#else -# include -#endif +#include void MacroAssembler::read_ccr_trap(Register ccr_save) { // No implementation diff -r 5c948ad57906 -r bbda609c9d24 src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp --- a/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/os_cpu/linux_sparc/vm/atomic_linux_sparc.inline.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -79,12 +79,12 @@ __asm__ volatile( "1: \n\t" " ldx [%2], %%o2\n\t" - " add %0, %%o2, %%o3\n\t" + " add %1, %%o2, %%o3\n\t" " casx [%2], %%o2, %%o3\n\t" " cmp %%o2, %%o3\n\t" " bne %%xcc, 1b\n\t" " nop\n\t" - " add %0, %%o2, %0\n\t" + " add %1, %%o2, %0\n\t" : "=r" (rv) : "r" (add_value), "r" (dest) : "memory", "o2", "o3"); diff -r 5c948ad57906 -r bbda609c9d24 src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp --- a/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/os_cpu/linux_sparc/vm/os_linux_sparc.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -118,7 +118,7 @@ *ret_sp = os::Linux::ucontext_get_sp(uc); } if (ret_fp) { - *ret_fp = os::Linux::ucontext_get_fp(uc); + *ret_fp = (intptr_t*)NULL; } } else { // construct empty ExtendedPC for return value checking @@ -136,18 +136,15 @@ frame os::fetch_frame_from_context(void* ucVoid) { intptr_t* sp; - intptr_t* fp; - ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, &fp); - return frame(sp, fp, epc.pc()); + ExtendedPC epc = fetch_frame_from_context(ucVoid, &sp, NULL); + return frame(sp, frame::unpatchable, epc.pc()); } frame os::get_sender_for_C_frame(frame* fr) { - return frame(fr->sender_sp(), fr->link(), fr->sender_pc()); + return frame(fr->sender_sp(), frame::unpatchable, fr->sender_pc()); } frame os::current_frame() { - fprintf(stderr, "current_frame()"); - intptr_t* sp = StubRoutines::Sparc::flush_callers_register_windows_func()(); frame myframe(sp, frame::unpatchable, CAST_FROM_FN_PTR(address, os::current_frame)); @@ -526,7 +523,7 @@ if (nativeInstruction_at(*pc)->is_ic_miss_trap()) { #ifdef ASSERT #ifdef TIERED - CodeBlob* cb = CodeCache::find_blob_unsafe(pc); + CodeBlob* cb = CodeCache::find_blob_unsafe(*pc); assert(cb->is_compiled_by_c2(), "Wrong compiler"); #endif // TIERED #endif // ASSERT diff -r 5c948ad57906 -r bbda609c9d24 src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp --- a/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/os_cpu/linux_sparc/vm/vm_version_linux_sparc.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -55,7 +55,7 @@ if (detect_niagara()) { NOT_PRODUCT(if (PrintMiscellaneous && Verbose) tty->print_cr("Detected Linux on Niagara");) - features = niagara1_m; + features = niagara1_m | T_family_m; } return features; diff -r 5c948ad57906 -r bbda609c9d24 src/os_cpu/linux_x86/vm/os_linux_x86.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp --- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -75,13 +75,19 @@ do_sysinfo(SI_ARCHITECTURE_64, "sparcv9", &features, generic_v9_m); // Extract valid instruction set extensions. - uint_t av; - uint_t avn = os::Solaris::getisax(&av, 1); - assert(avn == 1, "should only return one av"); + uint_t avs[2]; + uint_t avn = os::Solaris::getisax(avs, 2); + assert(avn <= 2, "should return two or less av's"); + uint_t av = avs[0]; #ifndef PRODUCT - if (PrintMiscellaneous && Verbose) - tty->print_cr("getisax(2) returned: " PTR32_FORMAT, av); + if (PrintMiscellaneous && Verbose) { + tty->print("getisax(2) returned: " PTR32_FORMAT, av); + if (avn > 1) { + tty->print(", " PTR32_FORMAT, avs[1]); + } + tty->cr(); + } #endif if (av & AV_SPARC_MUL32) features |= hardware_mul32_m; @@ -91,6 +97,13 @@ if (av & AV_SPARC_POPC) features |= hardware_popc_m; if (av & AV_SPARC_VIS) features |= vis1_instructions_m; if (av & AV_SPARC_VIS2) features |= vis2_instructions_m; + if (avn > 1) { + uint_t av2 = avs[1]; +#ifndef AV2_SPARC_SPARC5 +#define AV2_SPARC_SPARC5 0x00000008 /* The 29 new fp and sub instructions */ +#endif + if (av2 & AV2_SPARC_SPARC5) features |= sparc5_instructions_m; + } // Next values are not defined before Solaris 10 // but Solaris 8 is used for jdk6 update builds. diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/classfile/systemDictionary.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/classfile/verifier.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/memory/threadLocalAllocBuffer.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/oops/cpCacheOop.hpp --- a/src/share/vm/oops/cpCacheOop.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/oops/cpCacheOop.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -140,14 +140,15 @@ oop_store(&_f1, f1); } void release_set_f1(oop f1); - void set_f2(intx f2) { - assert(_f2 == 0 || _f2 == f2, "illegal field change"); - _f2 = f2; + void set_f2(intx f2) { + intx existing_f2 = _f2; // read once + assert(existing_f2 == 0 || existing_f2 == f2, "illegal field change"); + _f2 = f2; } - void set_f2_as_vfinal_method(methodOop f2) { - assert(_f2 == 0 || _f2 == (intptr_t) f2, "illegal field change"); - assert(is_vfinal(), "flags must be set"); - _f2 = (intptr_t) f2; } + void set_f2_as_vfinal_method(methodOop f2) { + assert(is_vfinal(), "flags must be set"); + set_f2((intx)f2); + } int make_flags(TosState state, int option_bits, int field_index_or_method_params); void set_flags(intx flags) { _flags = flags; } bool init_flags_atomic(intx flags); diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/oops/typeArrayOop.hpp --- a/src/share/vm/oops/typeArrayOop.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/oops/typeArrayOop.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -165,7 +165,7 @@ DEBUG_ONLY(BasicType etype = Klass::layout_helper_element_type(lh)); assert(length <= arrayOopDesc::max_array_length(etype), "no overflow"); - julong size_in_bytes = length; + julong size_in_bytes = (juint)length; size_in_bytes <<= element_shift; size_in_bytes += instance_header_size; julong size_in_words = ((size_in_bytes + (HeapWordSize-1)) >> LogHeapWordSize); diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/compile.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -688,6 +688,7 @@ #endif set_print_inlining(PrintInlining || method()->has_option("PrintInlining") NOT_PRODUCT( || PrintOptoInlining)); set_print_intrinsics(PrintIntrinsics || method()->has_option("PrintIntrinsics")); + set_has_irreducible_loop(true); // conservative until build_loop_tree() reset it if (ProfileTraps) { // Make sure the method being compiled gets its own MDO, @@ -956,6 +957,8 @@ set_print_assembly(PrintFrameConverterAssembly); set_parsed_irreducible_loop(false); #endif + set_has_irreducible_loop(false); // no loops + CompileWrapper cw(this); Init(/*AliasLevel=*/ 0); init_tf((*generator)()); @@ -1129,7 +1132,7 @@ if( start->is_Start() ) return start->as_Start(); } - ShouldNotReachHere(); + fatal("Did not find Start node!"); return NULL; } diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/compile.hpp Tue Jan 27 00:46:17 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -293,6 +293,7 @@ bool _trace_opto_output; bool _parsed_irreducible_loop; // True if ciTypeFlow detected irreducible loops during parsing #endif + bool _has_irreducible_loop; // Found irreducible loops // JSR 292 bool _has_method_handle_invokes; // True if this method has MethodHandle invokes. @@ -555,6 +556,8 @@ void set_parsed_irreducible_loop(bool z) { _parsed_irreducible_loop = z; } int _in_dump_cnt; // Required for dumping ir nodes. #endif + bool has_irreducible_loop() const { return _has_irreducible_loop; } + void set_has_irreducible_loop(bool z) { _has_irreducible_loop = z; } // JSR 292 bool has_method_handle_invokes() const { return _has_method_handle_invokes; } diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/library_call.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2014, 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 @@ -3715,8 +3715,11 @@ } -//------------------------------inline_native_hashcode-------------------- -// Build special case code for calls to hashCode on an object. +/** + * Build special case code for calls to hashCode on an object. This call may + * be virtual (invokevirtual) or bound (invokespecial). For each case we generate + * slightly different code. + */ bool LibraryCallKit::inline_native_hashcode(bool is_virtual, bool is_static) { assert(is_static == callee()->is_static(), "correct intrinsic selection"); assert(!(is_virtual && is_static), "either virtual, special, or static"); @@ -3724,11 +3727,9 @@ enum { _slow_path = 1, _fast_path, _null_path, PATH_LIMIT }; RegionNode* result_reg = new(C) RegionNode(PATH_LIMIT); - PhiNode* result_val = new(C) PhiNode(result_reg, - TypeInt::INT); + PhiNode* result_val = new(C) PhiNode(result_reg, TypeInt::INT); PhiNode* result_io = new(C) PhiNode(result_reg, Type::ABIO); - PhiNode* result_mem = new(C) PhiNode(result_reg, Type::MEMORY, - TypePtr::BOTTOM); + PhiNode* result_mem = new(C) PhiNode(result_reg, Type::MEMORY, TypePtr::BOTTOM); Node* obj = NULL; if (!is_static) { // Check for hashing null object @@ -3754,12 +3755,6 @@ return true; } - // After null check, get the object's klass. - Node* obj_klass = load_object_klass(obj); - - // This call may be virtual (invokevirtual) or bound (invokespecial). - // For each case we generate slightly different code. - // We only go to the fast case code if we pass a number of guards. The // paths which do not pass are accumulated in the slow_region. RegionNode* slow_region = new (C) RegionNode(1); @@ -3772,19 +3767,24 @@ // guard for non-virtual calls -- the caller is known to be the native // Object hashCode(). if (is_virtual) { + // After null check, get the object's klass. + Node* obj_klass = load_object_klass(obj); generate_virtual_guard(obj_klass, slow_region); } // Get the header out of the object, use LoadMarkNode when available Node* header_addr = basic_plus_adr(obj, oopDesc::mark_offset_in_bytes()); - Node* header = make_load(control(), header_addr, TypeX_X, TypeX_X->basic_type()); + // The control of the load must be NULL. Otherwise, the load can move before + // the null check after castPP removal. + Node* no_ctrl = NULL; + Node* header = make_load(no_ctrl, header_addr, TypeX_X, TypeX_X->basic_type()); // Test the header to see if it is unlocked. - Node *lock_mask = _gvn.MakeConX(markOopDesc::biased_lock_mask_in_place); - Node *lmasked_header = _gvn.transform( new (C) AndXNode(header, lock_mask) ); - Node *unlocked_val = _gvn.MakeConX(markOopDesc::unlocked_value); - Node *chk_unlocked = _gvn.transform( new (C) CmpXNode( lmasked_header, unlocked_val)); - Node *test_unlocked = _gvn.transform( new (C) BoolNode( chk_unlocked, BoolTest::ne) ); + Node* lock_mask = _gvn.MakeConX(markOopDesc::biased_lock_mask_in_place); + Node* lmasked_header = _gvn.transform(new (C) AndXNode(header, lock_mask)); + Node* unlocked_val = _gvn.MakeConX(markOopDesc::unlocked_value); + Node* chk_unlocked = _gvn.transform(new (C) CmpXNode( lmasked_header, unlocked_val)); + Node* test_unlocked = _gvn.transform(new (C) BoolNode( chk_unlocked, BoolTest::ne)); generate_slow_guard(test_unlocked, slow_region); @@ -3792,19 +3792,19 @@ // We depend on hash_mask being at most 32 bits and avoid the use of // hash_mask_in_place because it could be larger than 32 bits in a 64-bit // vm: see markOop.hpp. - Node *hash_mask = _gvn.intcon(markOopDesc::hash_mask); - Node *hash_shift = _gvn.intcon(markOopDesc::hash_shift); - Node *hshifted_header= _gvn.transform( new (C) URShiftXNode(header, hash_shift) ); + Node* hash_mask = _gvn.intcon(markOopDesc::hash_mask); + Node* hash_shift = _gvn.intcon(markOopDesc::hash_shift); + Node* hshifted_header= _gvn.transform(new (C) URShiftXNode(header, hash_shift)); // This hack lets the hash bits live anywhere in the mark object now, as long // as the shift drops the relevant bits into the low 32 bits. Note that // Java spec says that HashCode is an int so there's no point in capturing // an 'X'-sized hashcode (32 in 32-bit build or 64 in 64-bit build). hshifted_header = ConvX2I(hshifted_header); - Node *hash_val = _gvn.transform( new (C) AndINode(hshifted_header, hash_mask) ); - - Node *no_hash_val = _gvn.intcon(markOopDesc::no_hash); - Node *chk_assigned = _gvn.transform( new (C) CmpINode( hash_val, no_hash_val)); - Node *test_assigned = _gvn.transform( new (C) BoolNode( chk_assigned, BoolTest::eq) ); + Node* hash_val = _gvn.transform(new (C) AndINode(hshifted_header, hash_mask)); + + Node* no_hash_val = _gvn.intcon(markOopDesc::no_hash); + Node* chk_assigned = _gvn.transform(new (C) CmpINode( hash_val, no_hash_val)); + Node* test_assigned = _gvn.transform(new (C) BoolNode( chk_assigned, BoolTest::eq)); generate_slow_guard(test_assigned, slow_region); diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/loopTransform.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1127,6 +1127,7 @@ // Now force out all loop-invariant dominating tests. The optimizer // finds some, but we _know_ they are all useless. peeled_dom_test_elim(loop,old_new); + loop->record_for_igvn(); } //------------------------------is_invariant----------------------------- diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/loopnode.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2014, 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 @@ -266,9 +266,9 @@ // Counted loop head must be a good RegionNode with only 3 not NULL // control input edges: Self, Entry, LoopBack. - if (x->in(LoopNode::Self) == NULL || x->req() != 3) + if (x->in(LoopNode::Self) == NULL || x->req() != 3 || loop->_irreducible) { return false; - + } Node *init_control = x->in(LoopNode::EntryControl); Node *back_control = x->in(LoopNode::LoopBackControl); if (init_control == NULL || back_control == NULL) // Partially dead @@ -1522,11 +1522,11 @@ // If I have one hot backedge, peel off myself loop. // I better be the outermost loop. - if( _head->req() > 3 ) { + if (_head->req() > 3 && !_irreducible) { split_outer_loop( phase ); result = true; - } else if( !_head->is_Loop() && !_irreducible ) { + } else if (!_head->is_Loop() && !_irreducible) { // Make a new LoopNode to replace the old loop head Node *l = new (phase->C) LoopNode( _head->in(1), _head->in(2) ); l = igvn.register_new_node_with_optimizer(l, _head); @@ -2938,6 +2938,7 @@ return pre_order; } } + C->set_has_irreducible_loop(_has_irreducible_loops); } // This Node might be a decision point for loops. It is only if @@ -3171,17 +3172,16 @@ bool had_error = false; #ifdef ASSERT if (early != C->root()) { - // Make sure that there's a dominance path from use to LCA - Node* d = use; - while (d != LCA) { - d = idom(d); + // Make sure that there's a dominance path from LCA to early + Node* d = LCA; + while (d != early) { if (d == C->root()) { - tty->print_cr("*** Use %d isn't dominated by def %s", use->_idx, n->_idx); - n->dump(); - use->dump(); + dump_bad_graph("Bad graph detected in compute_lca_of_uses", n, early, LCA); + tty->print_cr("*** Use %d isn't dominated by def %d ***", use->_idx, n->_idx); had_error = true; break; } + d = idom(d); } } #endif @@ -3434,6 +3434,13 @@ _igvn._worklist.push(n); // Maybe we'll normalize it, if no more loops. } +#ifdef ASSERT + if (_verify_only && !n->is_CFG()) { + // Check def-use domination. + compute_lca_of_uses(n, get_ctrl(n), true /* verify */); + } +#endif + // CFG and pinned nodes already handled if( n->in(0) ) { if( n->in(0)->is_top() ) return; // Dead? diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/loopopts.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -2684,6 +2684,7 @@ // Inhibit more partial peeling on this loop new_head_clone->set_partial_peel_loop(); C->set_major_progress(); + loop->record_for_igvn(); #if !defined(PRODUCT) if (TracePartialPeeling) { diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/memnode.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -292,33 +292,16 @@ int alias_idx = phase->C->get_alias_index(t_adr->is_ptr()); } -#ifdef ASSERT Node* base = NULL; - if (address->is_AddP()) + if (address->is_AddP()) { base = address->in(AddPNode::Base); + } if (base != NULL && phase->type(base)->higher_equal(TypePtr::NULL_PTR) && !t_adr->isa_rawptr()) { // Note: raw address has TOP base and top->higher_equal(TypePtr::NULL_PTR) is true. - Compile* C = phase->C; - tty->cr(); - tty->print_cr("===== NULL+offs not RAW address ====="); - if (C->is_dead_node(this->_idx)) tty->print_cr("'this' is dead"); - if ((ctl != NULL) && C->is_dead_node(ctl->_idx)) tty->print_cr("'ctl' is dead"); - if (C->is_dead_node(mem->_idx)) tty->print_cr("'mem' is dead"); - if (C->is_dead_node(address->_idx)) tty->print_cr("'address' is dead"); - if (C->is_dead_node(base->_idx)) tty->print_cr("'base' is dead"); - tty->cr(); - base->dump(1); - tty->cr(); - this->dump(2); - tty->print("this->adr_type(): "); adr_type()->dump(); tty->cr(); - tty->print("phase->type(address): "); t_adr->dump(); tty->cr(); - tty->print("phase->type(base): "); phase->type(address)->dump(); tty->cr(); - tty->cr(); + // Skip this node optimization if its address has TOP base. + return NodeSentinel; // caller will return NULL } - assert(base == NULL || t_adr->isa_rawptr() || - !phase->type(base)->higher_equal(TypePtr::NULL_PTR), "NULL+offs not RAW address?"); -#endif // Avoid independent memory operations Node* old_mem = mem; diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/opto/node.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2014, 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 @@ -27,6 +27,7 @@ #include "memory/allocation.inline.hpp" #include "opto/cfgnode.hpp" #include "opto/connode.hpp" +#include "opto/loopnode.hpp" #include "opto/machnode.hpp" #include "opto/matcher.hpp" #include "opto/node.hpp" @@ -1228,6 +1229,7 @@ Node *top = igvn->C->top(); nstack.push(dead); + bool has_irreducible_loop = igvn->C->has_irreducible_loop(); while (nstack.size() > 0) { dead = nstack.pop(); @@ -1242,13 +1244,31 @@ assert (!use->is_Con(), "Control for Con node should be Root node."); use->set_req(0, top); // Cut dead edge to prevent processing nstack.push(use); // the dead node again. + } else if (!has_irreducible_loop && // Backedge could be alive in irreducible loop + use->is_Loop() && !use->is_Root() && // Don't kill Root (RootNode extends LoopNode) + use->in(LoopNode::EntryControl) == dead) { // Dead loop if its entry is dead + use->set_req(LoopNode::EntryControl, top); // Cut dead edge to prevent processing + use->set_req(0, top); // Cut self edge + nstack.push(use); } else { // Else found a not-dead user + // Dead if all inputs are top or null + bool dead_use = !use->is_Root(); // Keep empty graph alive for (uint j = 1; j < use->req(); j++) { - if (use->in(j) == dead) { // Turn all dead inputs into TOP + Node* in = use->in(j); + if (in == dead) { // Turn all dead inputs into TOP use->set_req(j, top); + } else if (in != NULL && !in->is_top()) { + dead_use = false; } } - igvn->_worklist.push(use); + if (dead_use) { + if (use->is_Region()) { + use->set_req(0, top); // Cut self edge + } + nstack.push(use); + } else { + igvn->_worklist.push(use); + } } // Refresh the iterator, since any number of kills might have happened. k = dead->last_outs(kmin); diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/prims/jni.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/runtime/vmStructs.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/runtime/vmThread.cpp --- a/src/share/vm/runtime/vmThread.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/runtime/vmThread.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -330,6 +330,9 @@ _terminate_lock->notify(); } + // Thread destructor usually does this. + ThreadLocalStorage::set_thread(NULL); + // Deletion must be done synchronously by the JNI DestroyJavaVM thread // so that the VMThread deletion completes before the main thread frees // up the CodeHeap. diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/services/heapDumper.cpp --- a/src/share/vm/services/heapDumper.cpp Wed Jan 21 03:56:44 2015 +0000 +++ b/src/share/vm/services/heapDumper.cpp Tue Jan 27 00:46:17 2015 +0000 @@ -720,7 +720,7 @@ // reflection and sun.misc.Unsafe classes may have a reference to a // klassOop so filter it out. - if (o != NULL && o->is_klass()) { + if (o != NULL && o->is_perm() && o->is_klass()) { o = NULL; } diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/utilities/ostream.cpp diff -r 5c948ad57906 -r bbda609c9d24 src/share/vm/utilities/vmError.cpp diff -r 5c948ad57906 -r bbda609c9d24 test/compiler/intrinsics/hashcode/TestHashCode.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/intrinsics/hashcode/TestHashCode.java Tue Jan 27 00:46:17 2015 +0000 @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014, 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 8011646 + * @summary SEGV in compiled code with loop predication + * @run main/othervm -XX:-TieredCompilation -XX:CompileOnly=TestHashCode.m1,Object.hashCode TestHashCode + * + */ + +public class TestHashCode { + static class A { + int i; + } + + static class B extends A { + } + + static boolean crash = false; + + static A m2() { + if (crash) { + return null; + } + return new A(); + } + + static int m1(A aa) { + int res = 0; + for (int i = 0; i < 10; i++) { + A a = m2(); + int j = a.i; + if (aa instanceof B) { + } + res += a.hashCode(); + } + return res; + } + + public static void main(String[] args) { + A a = new A(); + for (int i = 0; i < 20000; i++) { + m1(a); + } + crash = true; + try { + m1(a); + } catch (NullPointerException e) { + System.out.println("Test passed"); + } + } +} diff -r 5c948ad57906 -r bbda609c9d24 test/gc/heap_inspection/TestG1ConcurrentGCHeapDump.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/heap_inspection/TestG1ConcurrentGCHeapDump.java Tue Jan 27 00:46:17 2015 +0000 @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2014, 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 TestG1ConcurrentGCHeapDump + * @bug 8038925 + * @summary Checks that a heap dump can be made with G1 when no fullgc + * has been made + * @run main/othervm -Xms512m -Xmx1024m -XX:+ExplicitGCInvokesConcurrent TestG1ConcurrentGCHeapDump + */ +import java.util.List; +import java.util.ArrayList; +import java.util.LinkedList; + +import javax.management.MBeanServer; +import java.lang.management.ManagementFactory; +import java.lang.management.GarbageCollectorMXBean; + +import sun.management.ManagementFactoryHelper; +import com.sun.management.HotSpotDiagnosticMXBean; +import com.sun.management.VMOption; + +import java.io.IOException; + +import java.io.File; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.Files; + +public class TestG1ConcurrentGCHeapDump { + + private static final String HOTSPOT_BEAN_NAME = + "com.sun.management:type=HotSpotDiagnostic"; + + private static final String G1_OLD_BEAN_NAME = + "java.lang:type=GarbageCollector,name=G1 Old Generation"; + + private static MBeanServer server = ManagementFactory.getPlatformMBeanServer(); + + private static void dumpHeap() throws IOException { + HotSpotDiagnosticMXBean hotspot_bean = + ManagementFactory.newPlatformMXBeanProxy(server, + HOTSPOT_BEAN_NAME, HotSpotDiagnosticMXBean.class); + + Path dir = Files.createTempDirectory("JDK-8038925_"); + String file = dir + File.separator + "heapdump"; + hotspot_bean.dumpHeap(file, false); + Files.delete(Paths.get(file)); + Files.delete(dir); + } + + private static void verifyNoFullGC() throws IOException { + GarbageCollectorMXBean g1_old_bean = + ManagementFactory.newPlatformMXBeanProxy(server, + G1_OLD_BEAN_NAME, GarbageCollectorMXBean.class); + + if (g1_old_bean.getCollectionCount() != 0) { + throw new RuntimeException("A full GC has occured, this test will not work."); + } + } + + public static void main(String[] args) throws IOException { + HotSpotDiagnosticMXBean diagnostic = ManagementFactoryHelper.getDiagnosticMXBean(); + VMOption option = diagnostic.getVMOption("UseG1GC"); + if (option.getValue().equals("false")) { + System.out.println("Skipping this test. It is only a G1 test."); + return; + } + + // Create some dead objects + ArrayList> arraylist = new ArrayList>(); + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 100; j++) { + LinkedList li = new LinkedList(); + arraylist.add(li); + for (int k = 0; k < 10000; k++) { + li.add(k); + } + } + arraylist = new ArrayList>(); + System.gc(); + } + // Try to dump heap + dumpHeap(); + // Make sure no full GC has happened, since test won't work if that is the case + verifyNoFullGC(); + } +}