# HG changeset patch # User asaha # Date 1410900938 25200 # Node ID f0bedf980c65dd06f2d4288265c035cd5faa6b17 # Parent 8cb56c8cb30d07a72d7655690cc16c6391180d28# Parent 3702eb6ec7086186211ab7763a44c68fc7a898eb Merge diff -r 8cb56c8cb30d -r f0bedf980c65 .hgtags --- a/.hgtags Mon Sep 15 16:39:00 2014 -0400 +++ b/.hgtags Tue Sep 16 13:55:38 2014 -0700 @@ -516,3 +516,4 @@ fd4dbaff30027832dd21bcc7171ddb466ca2924f jdk8u40-b04 c9635cad4a5d794a96b4a26d3e7ad1d783133add hs25.40-b09 232b50b20797424c64da115ca48db131b1489ac1 jdk8u40-b05 +47ec483b936ee8cd2b26752e0aba3d5e6caab393 hs25.40-b10 diff -r 8cb56c8cb30d -r f0bedf980c65 agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java --- a/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Mon Sep 15 16:39:00 2014 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/oops/ConstantPool.java Tue Sep 16 13:55:38 2014 -0700 @@ -152,7 +152,7 @@ private long indexOffset(long index) { if (Assert.ASSERTS_ENABLED) { - Assert.that(index > 0 && index < getLength(), "invalid cp index " + index + " " + getLength()); + Assert.that(index >= 0 && index < getLength(), "invalid cp index " + index + " " + getLength()); } return (index * getElementSize()) + headerSize; } diff -r 8cb56c8cb30d -r f0bedf980c65 agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java --- a/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java Mon Sep 15 16:39:00 2014 -0400 +++ b/agent/src/share/classes/sun/jvm/hotspot/tools/jcore/ByteCodeRewriter.java Tue Sep 16 13:55:38 2014 -0700 @@ -98,11 +98,14 @@ break; default: throw new IllegalArgumentException(); } + if (cpCache == null) { return (short) cpCacheIndex; } else if (fmt.indexOf("JJJJ") >= 0) { - // change byte-ordering and go via secondary cache entry - throw new InternalError("unimplemented"); + // Invokedynamic require special handling + cpCacheIndex = ~cpCacheIndex; + cpCacheIndex = bytes.swapInt(cpCacheIndex); + return (short) cpCache.getEntryAt(cpCacheIndex).getConstantPoolIndex(); } else if (fmt.indexOf("JJ") >= 0) { // change byte-ordering and go via cache return (short) cpCache.getEntryAt((int) (0xFFFF & bytes.swapShort((short)cpCacheIndex))).getConstantPoolIndex(); diff -r 8cb56c8cb30d -r f0bedf980c65 make/Makefile --- a/make/Makefile Mon Sep 15 16:39:00 2014 -0400 +++ b/make/Makefile Tue Sep 16 13:55:38 2014 -0700 @@ -95,6 +95,7 @@ COMMON_VM_PRODUCT_TARGETS=product product1 docs export_product COMMON_VM_FASTDEBUG_TARGETS=fastdebug fastdebug1 docs export_fastdebug COMMON_VM_DEBUG_TARGETS=debug debug1 docs export_debug +COMMON_VM_OPTIMIZED_TARGETS=optimized optimized1 docs export_optimized # JDK directory list JDK_DIRS=bin include jre lib demo @@ -111,20 +112,21 @@ all_product: product1 docs export_product all_fastdebug: fastdebug1 docs export_fastdebug all_debug: debug1 docs export_debug +all_optimized: optimized1 docs export_optimized else ifeq ($(MACOSX_UNIVERSAL),true) all_product: universal_product all_fastdebug: universal_fastdebug all_debug: universal_debug +all_optimized: universal_optimized else all_product: $(COMMON_VM_PRODUCT_TARGETS) all_fastdebug: $(COMMON_VM_FASTDEBUG_TARGETS) all_debug: $(COMMON_VM_DEBUG_TARGETS) +all_optimized: $(COMMON_VM_OPTIMIZED_TARGETS) endif endif -all_optimized: optimized optimized1 docs export_optimized - allzero: all_productzero all_fastdebugzero all_productzero: productzero docs export_product all_fastdebugzero: fastdebugzero docs export_fastdebug diff -r 8cb56c8cb30d -r f0bedf980c65 make/bsd/makefiles/universal.gmk --- a/make/bsd/makefiles/universal.gmk Mon Sep 15 16:39:00 2014 -0400 +++ b/make/bsd/makefiles/universal.gmk Tue Sep 16 13:55:38 2014 -0700 @@ -25,6 +25,8 @@ # macosx universal builds universal_product: $(MAKE) MACOSX_UNIVERSAL=true all_product_universal +universal_optimized: + $(MAKE) MACOSX_UNIVERSAL=true all_optimized_universal universal_fastdebug: $(MAKE) MACOSX_UNIVERSAL=true all_fastdebug_universal universal_debug: @@ -36,6 +38,10 @@ # $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_PRODUCT_TARGETS) $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_PRODUCT_TARGETS) $(QUIETLY) $(MAKE) BUILD_FLAVOR=product EXPORT_SUBDIR= universalize +all_optimized_universal: +# $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_OPTIMIZED_TARGETS) + $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_OPTIMIZED_TARGETS) + $(QUIETLY) $(MAKE) BUILD_FLAVOR=optimized EXPORT_SUBDIR=/optimized universalize all_fastdebug_universal: # $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=32 $(COMMON_VM_FASTDEBUG_TARGETS) $(QUIETLY) $(MAKE) ARCH_DATA_MODEL=64 $(COMMON_VM_FASTDEBUG_TARGETS) @@ -98,13 +104,15 @@ export_product_jdk:: $(MAKE) EXPORT_SUBDIR= export_universal export_optimized_jdk:: - $(MAKE) EXPORT_SUBDIR= export_universal + $(MAKE) EXPORT_SUBDIR=/optimized export_universal export_fastdebug_jdk:: $(MAKE) EXPORT_SUBDIR=/fastdebug export_universal export_debug_jdk:: $(MAKE) EXPORT_SUBDIR=/debug export_universal copy_product_jdk:: $(MAKE) COPY_SUBDIR= copy_universal +copy_optimized_jdk:: + $(MAKE) COPY_SUBDIR=/optimized copy_universal copy_fastdebug_jdk:: $(MAKE) COPY_SUBDIR=/fastdebug copy_universal copy_debug_jdk:: @@ -112,5 +120,6 @@ .PHONY: universal_product universal_fastdebug universal_debug \ all_product_universal all_fastdebug_universal all_debug_universal \ + universal_optimized all_optimized_universal \ universalize export_universal copy_universal \ $(UNIVERSAL_LIPO_LIST) $(UNIVERSAL_COPY_LIST) diff -r 8cb56c8cb30d -r f0bedf980c65 make/hotspot_version --- a/make/hotspot_version Mon Sep 15 16:39:00 2014 -0400 +++ b/make/hotspot_version Tue Sep 16 13:55:38 2014 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=25 HS_MINOR_VER=40 -HS_BUILD_NUMBER=09 +HS_BUILD_NUMBER=10 JDK_MAJOR_VER=1 JDK_MINOR_VER=8 diff -r 8cb56c8cb30d -r f0bedf980c65 make/solaris/makefiles/vm.make --- a/make/solaris/makefiles/vm.make Mon Sep 15 16:39:00 2014 -0400 +++ b/make/solaris/makefiles/vm.make Tue Sep 16 13:55:38 2014 -0700 @@ -141,7 +141,7 @@ LIBS += -lsocket -lsched -ldl $(LIBM) -lthread -lc -ldemangle endif # sparcWorks -LIBS += -lkstat +LIBS += -lkstat -lpicl # By default, link the *.o into the library, not the executable. LINK_INTO$(LINK_INTO) = LIBJVM diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/ppc/vm/assembler_ppc.hpp --- a/src/cpu/ppc/vm/assembler_ppc.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/ppc/vm/assembler_ppc.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -298,6 +298,7 @@ LWZ_OPCODE = (32u << OPCODE_SHIFT), LWZX_OPCODE = (31u << OPCODE_SHIFT | 23u << 1), LWZU_OPCODE = (33u << OPCODE_SHIFT), + LWBRX_OPCODE = (31u << OPCODE_SHIFT | 534 << 1), LHA_OPCODE = (42u << OPCODE_SHIFT), LHAX_OPCODE = (31u << OPCODE_SHIFT | 343u << 1), @@ -306,6 +307,7 @@ LHZ_OPCODE = (40u << OPCODE_SHIFT), LHZX_OPCODE = (31u << OPCODE_SHIFT | 279u << 1), LHZU_OPCODE = (41u << OPCODE_SHIFT), + LHBRX_OPCODE = (31u << OPCODE_SHIFT | 790 << 1), LBZ_OPCODE = (34u << OPCODE_SHIFT), LBZX_OPCODE = (31u << OPCODE_SHIFT | 87u << 1), @@ -1364,11 +1366,17 @@ inline void lwax( Register d, Register s1, Register s2); inline void lwa( Register d, int si16, Register s1); + // 4 bytes reversed + inline void lwbrx( Register d, Register s1, Register s2); + // 2 bytes inline void lhzx( Register d, Register s1, Register s2); inline void lhz( Register d, int si16, Register s1); inline void lhzu( Register d, int si16, Register s1); + // 2 bytes reversed + inline void lhbrx( Register d, Register s1, Register s2); + // 2 bytes inline void lhax( Register d, Register s1, Register s2); inline void lha( Register d, int si16, Register s1); @@ -1858,10 +1866,12 @@ inline void lwz( Register d, int si16); inline void lwax( Register d, Register s2); inline void lwa( Register d, int si16); + inline void lwbrx(Register d, Register s2); inline void lhzx( Register d, Register s2); inline void lhz( Register d, int si16); inline void lhax( Register d, Register s2); inline void lha( Register d, int si16); + inline void lhbrx(Register d, Register s2); inline void lbzx( Register d, Register s2); inline void lbz( Register d, int si16); inline void ldx( Register d, Register s2); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/ppc/vm/assembler_ppc.inline.hpp --- a/src/cpu/ppc/vm/assembler_ppc.inline.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/ppc/vm/assembler_ppc.inline.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -263,10 +263,14 @@ inline void Assembler::lwax( Register d, Register s1, Register s2) { emit_int32(LWAX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lwa( Register d, int si16, Register s1) { emit_int32(LWA_OPCODE | rt(d) | ds(si16) | ra0mem(s1));} +inline void Assembler::lwbrx( Register d, Register s1, Register s2) { emit_int32(LWBRX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} + inline void Assembler::lhzx( Register d, Register s1, Register s2) { emit_int32(LHZX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lhz( Register d, int si16, Register s1) { emit_int32(LHZ_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lhzu( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LHZU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} +inline void Assembler::lhbrx( Register d, Register s1, Register s2) { emit_int32(LHBRX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} + inline void Assembler::lhax( Register d, Register s1, Register s2) { emit_int32(LHAX_OPCODE | rt(d) | ra0mem(s1) | rb(s2));} inline void Assembler::lha( Register d, int si16, Register s1) { emit_int32(LHA_OPCODE | rt(d) | d1(si16) | ra0mem(s1));} inline void Assembler::lhau( Register d, int si16, Register s1) { assert(d != s1, "according to ibm manual"); emit_int32(LHAU_OPCODE | rt(d) | d1(si16) | rta0mem(s1));} @@ -736,10 +740,12 @@ inline void Assembler::lwz( Register d, int si16 ) { emit_int32( LWZ_OPCODE | rt(d) | d1(si16));} inline void Assembler::lwax( Register d, Register s2) { emit_int32( LWAX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lwa( Register d, int si16 ) { emit_int32( LWA_OPCODE | rt(d) | ds(si16));} +inline void Assembler::lwbrx(Register d, Register s2) { emit_int32( LWBRX_OPCODE| rt(d) | rb(s2));} inline void Assembler::lhzx( Register d, Register s2) { emit_int32( LHZX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lhz( Register d, int si16 ) { emit_int32( LHZ_OPCODE | rt(d) | d1(si16));} inline void Assembler::lhax( Register d, Register s2) { emit_int32( LHAX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lha( Register d, int si16 ) { emit_int32( LHA_OPCODE | rt(d) | d1(si16));} +inline void Assembler::lhbrx(Register d, Register s2) { emit_int32( LHBRX_OPCODE| rt(d) | rb(s2));} inline void Assembler::lbzx( Register d, Register s2) { emit_int32( LBZX_OPCODE | rt(d) | rb(s2));} inline void Assembler::lbz( Register d, int si16 ) { emit_int32( LBZ_OPCODE | rt(d) | d1(si16));} inline void Assembler::ld( Register d, int si16 ) { emit_int32( LD_OPCODE | rt(d) | ds(si16));} diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/ppc/vm/interp_masm_ppc_64.cpp --- a/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -119,9 +119,15 @@ // Call the Interpreter::remove_activation_preserving_args_entry() // func to get the address of the same-named entrypoint in the // generated interpreter code. +#if defined(ABI_ELFv2) + call_c(CAST_FROM_FN_PTR(address, + Interpreter::remove_activation_preserving_args_entry), + relocInfo::none); +#else call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, Interpreter::remove_activation_preserving_args_entry), relocInfo::none); +#endif // Jump to Interpreter::_remove_activation_preserving_args_entry. mtctr(R3_RET); @@ -331,29 +337,40 @@ void InterpreterMacroAssembler::get_2_byte_integer_at_bcp(int bcp_offset, Register Rdst, signedOrNot is_signed) { +#if defined(VM_LITTLE_ENDIAN) + if (bcp_offset) { + load_const_optimized(Rdst, bcp_offset); + lhbrx(Rdst, R14_bcp, Rdst); + } else { + lhbrx(Rdst, R14_bcp); + } + if (is_signed == Signed) { + extsh(Rdst, Rdst); + } +#else // Read Java big endian format. if (is_signed == Signed) { lha(Rdst, bcp_offset, R14_bcp); } else { lhz(Rdst, bcp_offset, R14_bcp); } -#if 0 - assert(Rtmp != Rdst, "need separate temp register"); - Register Rfirst = Rtmp; - lbz(Rfirst, bcp_offset, R14_bcp); // first byte - lbz(Rdst, bcp_offset+1, R14_bcp); // second byte - - // Rdst = ((Rfirst<<8) & 0xFF00) | (Rdst &~ 0xFF00) - rldimi(/*RA=*/Rdst, /*RS=*/Rfirst, /*sh=*/8, /*mb=*/48); - if (is_signed == Signed) { - extsh(Rdst, Rdst); - } #endif } void InterpreterMacroAssembler::get_4_byte_integer_at_bcp(int bcp_offset, Register Rdst, signedOrNot is_signed) { +#if defined(VM_LITTLE_ENDIAN) + if (bcp_offset) { + load_const_optimized(Rdst, bcp_offset); + lwbrx(Rdst, R14_bcp, Rdst); + } else { + lwbrx(Rdst, R14_bcp); + } + if (is_signed == Signed) { + extsw(Rdst, Rdst); + } +#else // Read Java big endian format. if (bcp_offset & 3) { // Offset unaligned? load_const_optimized(Rdst, bcp_offset); @@ -369,19 +386,27 @@ lwz(Rdst, bcp_offset, R14_bcp); } } +#endif } + // Load the constant pool cache index from the bytecode stream. // // Kills / writes: // - Rdst, Rscratch void InterpreterMacroAssembler::get_cache_index_at_bcp(Register Rdst, int bcp_offset, size_t index_size) { assert(bcp_offset > 0, "bcp is still pointing to start of bytecode"); + // Cache index is always in the native format, courtesy of Rewriter. if (index_size == sizeof(u2)) { - get_2_byte_integer_at_bcp(bcp_offset, Rdst, Unsigned); + lhz(Rdst, bcp_offset, R14_bcp); } else if (index_size == sizeof(u4)) { assert(EnableInvokeDynamic, "giant index used only for JSR 292"); - get_4_byte_integer_at_bcp(bcp_offset, Rdst, Signed); + if (bcp_offset & 3) { + load_const_optimized(Rdst, bcp_offset); + lwax(Rdst, R14_bcp, Rdst); + } else { + lwa(Rdst, bcp_offset, R14_bcp); + } assert(ConstantPool::decode_invokedynamic_index(~123) == 123, "else change next line"); nand(Rdst, Rdst, Rdst); // convert to plain index } else if (index_size == sizeof(u1)) { @@ -398,6 +423,29 @@ add(cache, R27_constPoolCache, cache); } +// Load 4-byte signed or unsigned integer in Java format (that is, big-endian format) +// from (Rsrc)+offset. +void InterpreterMacroAssembler::get_u4(Register Rdst, Register Rsrc, int offset, + signedOrNot is_signed) { +#if defined(VM_LITTLE_ENDIAN) + if (offset) { + load_const_optimized(Rdst, offset); + lwbrx(Rdst, Rdst, Rsrc); + } else { + lwbrx(Rdst, Rsrc); + } + if (is_signed == Signed) { + extsw(Rdst, Rdst); + } +#else + if (is_signed == Signed) { + lwa(Rdst, offset, Rsrc); + } else { + lwz(Rdst, offset, Rsrc); + } +#endif +} + // Load object from cpool->resolved_references(index). void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result, Register index) { assert_different_registers(result, index); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/ppc/vm/interp_masm_ppc_64.hpp --- a/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/ppc/vm/interp_masm_ppc_64.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -130,6 +130,7 @@ void get_cache_and_index_at_bcp(Register cache, int bcp_offset, size_t index_size = sizeof(u2)); + void get_u4(Register Rdst, Register Rsrc, int offset, signedOrNot is_signed); // common code diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/ppc/vm/templateInterpreter_ppc.cpp --- a/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/ppc/vm/templateInterpreter_ppc.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -175,8 +175,12 @@ const Register size = R12_scratch2; __ get_cache_and_index_at_bcp(cache, 1, index_size); - // Big Endian (get least significant byte of 64 bit value): + // Get least significant byte of 64 bit value: +#if defined(VM_LITTLE_ENDIAN) + __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()), cache); +#else __ lbz(size, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::flags_offset()) + 7, cache); +#endif __ sldi(size, size, Interpreter::logStackElementSize); __ add(R15_esp, R15_esp, size); __ dispatch_next(state, step); @@ -857,7 +861,9 @@ // Our signature handlers copy required arguments to the C stack // (outgoing C args), R3_ARG1 to R10_ARG8, and FARG1 to FARG13. __ mr(R3_ARG1, R18_locals); +#if !defined(ABI_ELFv2) __ ld(signature_handler_fd, 0, signature_handler_fd); +#endif __ call_stub(signature_handler_fd); @@ -1019,8 +1025,13 @@ // native result across the call. No oop is present. __ mr(R3_ARG1, R16_thread); +#if defined(ABI_ELFv2) + __ call_c(CAST_FROM_FN_PTR(address, JavaThread::check_special_condition_for_native_trans), + relocInfo::none); +#else __ call_c(CAST_FROM_FN_PTR(FunctionDescriptor*, JavaThread::check_special_condition_for_native_trans), relocInfo::none); +#endif __ bind(sync_check_done); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/ppc/vm/templateTable_ppc_64.cpp --- a/src/cpu/ppc/vm/templateTable_ppc_64.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/ppc/vm/templateTable_ppc_64.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -188,8 +188,12 @@ assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); assert(load_bc_into_bc_reg, "we use bc_reg as temp"); __ get_cache_and_index_at_bcp(Rtemp /* dst = cache */, 1); - // Big Endian: ((*(cache+indices))>>((1+byte_no)*8))&0xFF + // ((*(cache+indices))>>((1+byte_no)*8))&0xFF: +#if defined(VM_LITTLE_ENDIAN) + __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 1 + byte_no, Rtemp); +#else __ lbz(Rnew_bc, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (1 + byte_no), Rtemp); +#endif __ cmpwi(CCR0, Rnew_bc, 0); __ li(Rnew_bc, (unsigned int)(unsigned char)new_bc); __ beq(CCR0, L_patch_done); @@ -1838,8 +1842,8 @@ __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); // Load lo & hi. - __ lwz(Rlow_byte, BytesPerInt, Rdef_offset_addr); - __ lwz(Rhigh_byte, BytesPerInt * 2, Rdef_offset_addr); + __ get_u4(Rlow_byte, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned); + __ get_u4(Rhigh_byte, Rdef_offset_addr, 2 *BytesPerInt, InterpreterMacroAssembler::Unsigned); // Check for default case (=index outside [low,high]). __ cmpw(CCR0, R17_tos, Rlow_byte); @@ -1853,12 +1857,17 @@ __ profile_switch_case(Rindex, Rhigh_byte /* scratch */, Rscratch1, Rscratch2); __ sldi(Rindex, Rindex, LogBytesPerInt); __ addi(Rindex, Rindex, 3 * BytesPerInt); +#if defined(VM_LITTLE_ENDIAN) + __ lwbrx(Roffset, Rdef_offset_addr, Rindex); + __ extsw(Roffset, Roffset); +#else __ lwax(Roffset, Rdef_offset_addr, Rindex); +#endif __ b(Ldispatch); __ bind(Ldefault_case); __ profile_switch_default(Rhigh_byte, Rscratch1); - __ lwa(Roffset, 0, Rdef_offset_addr); + __ get_u4(Roffset, Rdef_offset_addr, 0, InterpreterMacroAssembler::Signed); __ bind(Ldispatch); @@ -1874,12 +1883,11 @@ // Table switch using linear search through cases. // Bytecode stream format: // Bytecode (1) | 4-byte padding | default offset (4) | count (4) | value/offset pair1 (8) | value/offset pair2 (8) | ... -// Note: Everything is big-endian format here. So on little endian machines, we have to revers offset and count and cmp value. +// Note: Everything is big-endian format here. void TemplateTable::fast_linearswitch() { transition(itos, vtos); - Label Lloop_entry, Lsearch_loop, Lfound, Lcontinue_execution, Ldefault_case; - + Label Lloop_entry, Lsearch_loop, Lcontinue_execution, Ldefault_case; Register Rcount = R3_ARG1, Rcurrent_pair = R4_ARG2, Rdef_offset_addr = R5_ARG3, // Is going to contain address of default offset. @@ -1893,47 +1901,40 @@ __ clrrdi(Rdef_offset_addr, Rdef_offset_addr, log2_long((jlong)BytesPerInt)); // Setup loop counter and limit. - __ lwz(Rcount, BytesPerInt, Rdef_offset_addr); // Load count. + __ get_u4(Rcount, Rdef_offset_addr, BytesPerInt, InterpreterMacroAssembler::Unsigned); __ addi(Rcurrent_pair, Rdef_offset_addr, 2 * BytesPerInt); // Rcurrent_pair now points to first pair. - // Set up search loop. - __ cmpwi(CCR0, Rcount, 0); - __ beq(CCR0, Ldefault_case); - __ mtctr(Rcount); - - // linear table search - __ bind(Lsearch_loop); - - __ lwz(Rvalue, 0, Rcurrent_pair); - __ lwa(Roffset, 1 * BytesPerInt, Rcurrent_pair); - - __ cmpw(CCR0, Rvalue, Rcmp_value); - __ beq(CCR0, Lfound); - - __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt); - __ bdnz(Lsearch_loop); - - // default case + __ cmpwi(CCR0, Rcount, 0); + __ bne(CCR0, Lloop_entry); + + // Default case __ bind(Ldefault_case); - - __ lwa(Roffset, 0, Rdef_offset_addr); + __ get_u4(Roffset, Rdef_offset_addr, 0, InterpreterMacroAssembler::Signed); if (ProfileInterpreter) { __ profile_switch_default(Rdef_offset_addr, Rcount/* scratch */); - __ b(Lcontinue_execution); } - - // Entry found, skip Roffset bytecodes and continue. - __ bind(Lfound); + __ b(Lcontinue_execution); + + // Next iteration + __ bind(Lsearch_loop); + __ bdz(Ldefault_case); + __ addi(Rcurrent_pair, Rcurrent_pair, 2 * BytesPerInt); + __ bind(Lloop_entry); + __ get_u4(Rvalue, Rcurrent_pair, 0, InterpreterMacroAssembler::Unsigned); + __ cmpw(CCR0, Rvalue, Rcmp_value); + __ bne(CCR0, Lsearch_loop); + + // Found, load offset. + __ get_u4(Roffset, Rcurrent_pair, BytesPerInt, InterpreterMacroAssembler::Signed); + // Calculate case index and profile + __ mfctr(Rcurrent_pair); if (ProfileInterpreter) { - // Calc the num of the pair we hit. Careful, Rcurrent_pair points 2 ints - // beyond the actual current pair due to the auto update load above! - __ sub(Rcurrent_pair, Rcurrent_pair, Rdef_offset_addr); - __ addi(Rcurrent_pair, Rcurrent_pair, - 2 * BytesPerInt); - __ srdi(Rcurrent_pair, Rcurrent_pair, LogBytesPerInt + 1); + __ sub(Rcurrent_pair, Rcount, Rcurrent_pair); __ profile_switch_case(Rcurrent_pair, Rcount /*scratch*/, Rdef_offset_addr/*scratch*/, Rscratch); - __ bind(Lcontinue_execution); } + + __ bind(Lcontinue_execution); __ add(R14_bcp, Roffset, R14_bcp); __ dispatch_next(vtos); } @@ -1989,7 +1990,7 @@ // initialize i & j __ li(Ri,0); - __ lwz(Rj, -BytesPerInt, Rarray); + __ get_u4(Rj, Rarray, -BytesPerInt, InterpreterMacroAssembler::Unsigned); // and start. Label entry; @@ -2006,7 +2007,11 @@ // i = h; // } __ sldi(Rscratch, Rh, log_entry_size); +#if defined(VM_LITTLE_ENDIAN) + __ lwbrx(Rscratch, Rscratch, Rarray); +#else __ lwzx(Rscratch, Rscratch, Rarray); +#endif // if (key < current value) // Rh = Rj @@ -2038,20 +2043,20 @@ // Ri = value offset __ sldi(Ri, Ri, log_entry_size); __ add(Ri, Ri, Rarray); - __ lwz(Rscratch, 0, Ri); + __ get_u4(Rscratch, Ri, 0, InterpreterMacroAssembler::Unsigned); Label not_found; // Ri = offset offset __ cmpw(CCR0, Rkey, Rscratch); __ beq(CCR0, not_found); // entry not found -> j = default offset - __ lwz(Rj, -2 * BytesPerInt, Rarray); + __ get_u4(Rj, Rarray, -2 * BytesPerInt, InterpreterMacroAssembler::Unsigned); __ b(default_case); __ bind(not_found); // entry found -> j = offset __ profile_switch_case(Rh, Rj, Rscratch, Rkey); - __ lwz(Rj, BytesPerInt, Ri); + __ get_u4(Rj, Ri, BytesPerInt, InterpreterMacroAssembler::Unsigned); if (ProfileInterpreter) { __ b(continue_execution); @@ -2146,8 +2151,11 @@ assert(byte_no == f1_byte || byte_no == f2_byte, "byte_no out of range"); // We are resolved if the indices offset contains the current bytecode. - // Big Endian: +#if defined(VM_LITTLE_ENDIAN) + __ lbz(Rscratch, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + byte_no + 1, Rcache); +#else __ lbz(Rscratch, in_bytes(ConstantPoolCache::base_offset() + ConstantPoolCacheEntry::indices_offset()) + 7 - (byte_no + 1), Rcache); +#endif // Acquire by cmp-br-isync (see below). __ cmpdi(CCR0, Rscratch, (int)bytecode()); __ beq(CCR0, Lresolved); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/sparc/vm/vm_version_sparc.cpp --- a/src/cpu/sparc/vm/vm_version_sparc.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -37,6 +37,7 @@ int VM_Version::_features = VM_Version::unknown_m; const char* VM_Version::_features_str = ""; +unsigned int VM_Version::_L2_cache_line_size = 0; void VM_Version::initialize() { _features = determine_features(); @@ -197,7 +198,7 @@ } assert(BlockZeroingLowLimit > 0, "invalid value"); - if (has_block_zeroing()) { + if (has_block_zeroing() && cache_line_size > 0) { if (FLAG_IS_DEFAULT(UseBlockZeroing)) { FLAG_SET_DEFAULT(UseBlockZeroing, true); } @@ -207,7 +208,7 @@ } assert(BlockCopyLowLimit > 0, "invalid value"); - if (has_block_zeroing()) { // has_blk_init() && is_T4(): core's local L2 cache + if (has_block_zeroing() && cache_line_size > 0) { // has_blk_init() && is_T4(): core's local L2 cache if (FLAG_IS_DEFAULT(UseBlockCopy)) { FLAG_SET_DEFAULT(UseBlockCopy, true); } @@ -362,6 +363,7 @@ #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { + tty->print_cr("L2 cache line size: %u", L2_cache_line_size()); tty->print("Allocation"); if (AllocatePrefetchStyle <= 0) { tty->print_cr(": no prefetching"); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/sparc/vm/vm_version_sparc.hpp --- a/src/cpu/sparc/vm/vm_version_sparc.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/sparc/vm/vm_version_sparc.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -96,6 +96,9 @@ static int _features; static const char* _features_str; + static unsigned int _L2_cache_line_size; + static unsigned int L2_cache_line_size() { return _L2_cache_line_size; } + static void print_features(); static int determine_features(); static int platform_features(int features); @@ -167,9 +170,8 @@ static const char* cpu_features() { return _features_str; } - static intx prefetch_data_size() { - return is_T4() && !is_T7() ? 32 : 64; // default prefetch block size on sparc - } + // default prefetch block size on sparc + static intx prefetch_data_size() { return L2_cache_line_size(); } // Prefetch static intx prefetch_copy_interval_in_bytes() { diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/assembler_x86.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -4937,6 +4937,26 @@ emit_arith(0x03, 0xC0, dst, src); } +void Assembler::adcxq(Register dst, Register src) { + //assert(VM_Version::supports_adx(), "adx instructions not supported"); + emit_int8((unsigned char)0x66); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int8(0x0F); + emit_int8(0x38); + emit_int8((unsigned char)0xF6); + emit_int8((unsigned char)(0xC0 | encode)); +} + +void Assembler::adoxq(Register dst, Register src) { + //assert(VM_Version::supports_adx(), "adx instructions not supported"); + emit_int8((unsigned char)0xF3); + int encode = prefixq_and_encode(dst->encoding(), src->encoding()); + emit_int8(0x0F); + emit_int8(0x38); + emit_int8((unsigned char)0xF6); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::andq(Address dst, int32_t imm32) { InstructionMark im(this); prefixq(dst); @@ -5444,6 +5464,26 @@ emit_int8((unsigned char)(0xC0 | encode)); } +void Assembler::mulq(Address src) { + InstructionMark im(this); + prefixq(src); + emit_int8((unsigned char)0xF7); + emit_operand(rsp, src); +} + +void Assembler::mulq(Register src) { + int encode = prefixq_and_encode(src->encoding()); + emit_int8((unsigned char)0xF7); + emit_int8((unsigned char)(0xE0 | encode)); +} + +void Assembler::mulxq(Register dst1, Register dst2, Register src) { + assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); + int encode = vex_prefix_and_encode(dst1->encoding(), dst2->encoding(), src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_38, true, false); + emit_int8((unsigned char)0xF6); + emit_int8((unsigned char)(0xC0 | encode)); +} + void Assembler::negq(Register dst) { int encode = prefixq_and_encode(dst->encoding()); emit_int8((unsigned char)0xF7); @@ -5572,6 +5612,28 @@ emit_int8(imm8); } } + +void Assembler::rorq(Register dst, int imm8) { + assert(isShiftCount(imm8 >> 1), "illegal shift count"); + int encode = prefixq_and_encode(dst->encoding()); + if (imm8 == 1) { + emit_int8((unsigned char)0xD1); + emit_int8((unsigned char)(0xC8 | encode)); + } else { + emit_int8((unsigned char)0xC1); + emit_int8((unsigned char)(0xc8 | encode)); + emit_int8(imm8); + } +} + +void Assembler::rorxq(Register dst, Register src, int imm8) { + assert(VM_Version::supports_bmi2(), "bit manipulation instructions not supported"); + int encode = vex_prefix_and_encode(dst->encoding(), 0, src->encoding(), VEX_SIMD_F2, VEX_OPCODE_0F_3A, true, false); + emit_int8((unsigned char)0xF0); + emit_int8((unsigned char)(0xC0 | encode)); + emit_int8(imm8); +} + void Assembler::sarq(Register dst, int imm8) { assert(isShiftCount(imm8 >> 1), "illegal shift count"); int encode = prefixq_and_encode(dst->encoding()); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/assembler_x86.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -888,6 +888,14 @@ void addq(Register dst, Address src); void addq(Register dst, Register src); +#ifdef _LP64 + //Add Unsigned Integers with Carry Flag + void adcxq(Register dst, Register src); + + //Add Unsigned Integers with Overflow Flag + void adoxq(Register dst, Register src); +#endif + void addr_nop_4(); void addr_nop_5(); void addr_nop_7(); @@ -1204,19 +1212,20 @@ void idivl(Register src); void divl(Register src); // Unsigned division +#ifdef _LP64 void idivq(Register src); +#endif void imull(Register dst, Register src); void imull(Register dst, Register src, int value); void imull(Register dst, Address src); +#ifdef _LP64 void imulq(Register dst, Register src); void imulq(Register dst, Register src, int value); -#ifdef _LP64 void imulq(Register dst, Address src); #endif - // jcc is the generic conditional branch generator to run- // time routines, jcc is used for branches to labels. jcc // takes a branch opcode (cc) and a label (L) and generates @@ -1408,9 +1417,16 @@ void movzwq(Register dst, Register src); #endif + // Unsigned multiply with RAX destination register void mull(Address src); void mull(Register src); +#ifdef _LP64 + void mulq(Address src); + void mulq(Register src); + void mulxq(Register dst1, Register dst2, Register src); +#endif + // Multiply Scalar Double-Precision Floating-Point Values void mulsd(XMMRegister dst, Address src); void mulsd(XMMRegister dst, XMMRegister src); @@ -1541,6 +1557,11 @@ void ret(int imm16); +#ifdef _LP64 + void rorq(Register dst, int imm8); + void rorxq(Register dst, Register src, int imm8); +#endif + void sahf(); void sarl(Register dst, int imm8); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/globals_x86.hpp --- a/src/cpu/x86/vm/globals_x86.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/globals_x86.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -176,6 +176,8 @@ "Use count trailing zeros instruction") \ \ product(bool, UseBMI1Instructions, false, \ - "Use BMI instructions") - + "Use BMI1 instructions") \ + \ + product(bool, UseBMI2Instructions, false, \ + "Use BMI2 instructions") #endif // CPU_X86_VM_GLOBALS_X86_HPP diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/macroAssembler_x86.cpp --- a/src/cpu/x86/vm/macroAssembler_x86.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/macroAssembler_x86.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -7293,6 +7293,467 @@ bind(L_done); } +#ifdef _LP64 +/** + * Helper for multiply_to_len(). + */ +void MacroAssembler::add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2) { + addq(dest_lo, src1); + adcq(dest_hi, 0); + addq(dest_lo, src2); + adcq(dest_hi, 0); +} + +/** + * Multiply 64 bit by 64 bit first loop. + */ +void MacroAssembler::multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx) { + // + // jlong carry, x[], y[], z[]; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // huge_128 product = y[idx] * x[xstart] + carry; + // z[kdx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // z[xstart] = carry; + // + + Label L_first_loop, L_first_loop_exit; + Label L_one_x, L_one_y, L_multiply; + + decrementl(xstart); + jcc(Assembler::negative, L_one_x); + + movq(x_xstart, Address(x, xstart, Address::times_4, 0)); + rorq(x_xstart, 32); // convert big-endian to little-endian + + bind(L_first_loop); + decrementl(idx); + jcc(Assembler::negative, L_first_loop_exit); + decrementl(idx); + jcc(Assembler::negative, L_one_y); + movq(y_idx, Address(y, idx, Address::times_4, 0)); + rorq(y_idx, 32); // convert big-endian to little-endian + bind(L_multiply); + movq(product, x_xstart); + mulq(y_idx); // product(rax) * y_idx -> rdx:rax + addq(product, carry); + adcq(rdx, 0); + subl(kdx, 2); + movl(Address(z, kdx, Address::times_4, 4), product); + shrq(product, 32); + movl(Address(z, kdx, Address::times_4, 0), product); + movq(carry, rdx); + jmp(L_first_loop); + + bind(L_one_y); + movl(y_idx, Address(y, 0)); + jmp(L_multiply); + + bind(L_one_x); + movl(x_xstart, Address(x, 0)); + jmp(L_first_loop); + + bind(L_first_loop_exit); +} + +/** + * Multiply 64 bit by 64 bit and add 128 bit. + */ +void MacroAssembler::multiply_add_128_x_128(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, + Register carry, Register product, int offset) { + // huge_128 product = (y[idx] * x_xstart) + z[kdx] + carry; + // z[kdx] = (jlong)product; + + movq(yz_idx, Address(y, idx, Address::times_4, offset)); + rorq(yz_idx, 32); // convert big-endian to little-endian + movq(product, x_xstart); + mulq(yz_idx); // product(rax) * yz_idx -> rdx:product(rax) + movq(yz_idx, Address(z, idx, Address::times_4, offset)); + rorq(yz_idx, 32); // convert big-endian to little-endian + + add2_with_carry(rdx, product, carry, yz_idx); + + movl(Address(z, idx, Address::times_4, offset+4), product); + shrq(product, 32); + movl(Address(z, idx, Address::times_4, offset), product); + +} + +/** + * Multiply 128 bit by 128 bit. Unrolled inner loop. + */ +void MacroAssembler::multiply_128_x_128_loop(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, Register jdx, + Register carry, Register product, + Register carry2) { + // jlong carry, x[], y[], z[]; + // int kdx = ystart+1; + // for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop + // huge_128 product = (y[idx+1] * x_xstart) + z[kdx+idx+1] + carry; + // z[kdx+idx+1] = (jlong)product; + // jlong carry2 = (jlong)(product >>> 64); + // product = (y[idx] * x_xstart) + z[kdx+idx] + carry2; + // z[kdx+idx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // idx += 2; + // if (idx > 0) { + // product = (y[idx] * x_xstart) + z[kdx+idx] + carry; + // z[kdx+idx] = (jlong)product; + // carry = (jlong)(product >>> 64); + // } + // + + Label L_third_loop, L_third_loop_exit, L_post_third_loop_done; + + movl(jdx, idx); + andl(jdx, 0xFFFFFFFC); + shrl(jdx, 2); + + bind(L_third_loop); + subl(jdx, 1); + jcc(Assembler::negative, L_third_loop_exit); + subl(idx, 4); + + multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product, 8); + movq(carry2, rdx); + + multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry2, product, 0); + movq(carry, rdx); + jmp(L_third_loop); + + bind (L_third_loop_exit); + + andl (idx, 0x3); + jcc(Assembler::zero, L_post_third_loop_done); + + Label L_check_1; + subl(idx, 2); + jcc(Assembler::negative, L_check_1); + + multiply_add_128_x_128(x_xstart, y, z, yz_idx, idx, carry, product, 0); + movq(carry, rdx); + + bind (L_check_1); + addl (idx, 0x2); + andl (idx, 0x1); + subl(idx, 1); + jcc(Assembler::negative, L_post_third_loop_done); + + movl(yz_idx, Address(y, idx, Address::times_4, 0)); + movq(product, x_xstart); + mulq(yz_idx); // product(rax) * yz_idx -> rdx:product(rax) + movl(yz_idx, Address(z, idx, Address::times_4, 0)); + + add2_with_carry(rdx, product, yz_idx, carry); + + movl(Address(z, idx, Address::times_4, 0), product); + shrq(product, 32); + + shlq(rdx, 32); + orq(product, rdx); + movq(carry, product); + + bind(L_post_third_loop_done); +} + +/** + * Multiply 128 bit by 128 bit using BMI2. Unrolled inner loop. + * + */ +void MacroAssembler::multiply_128_x_128_bmi2_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4) { + assert(UseBMI2Instructions, "should be used only when BMI2 is available"); + + // jlong carry, x[], y[], z[]; + // int kdx = ystart+1; + // for (int idx=ystart-2; idx >= 0; idx -= 2) { // Third loop + // huge_128 tmp3 = (y[idx+1] * rdx) + z[kdx+idx+1] + carry; + // jlong carry2 = (jlong)(tmp3 >>> 64); + // huge_128 tmp4 = (y[idx] * rdx) + z[kdx+idx] + carry2; + // carry = (jlong)(tmp4 >>> 64); + // z[kdx+idx+1] = (jlong)tmp3; + // z[kdx+idx] = (jlong)tmp4; + // } + // idx += 2; + // if (idx > 0) { + // yz_idx1 = (y[idx] * rdx) + z[kdx+idx] + carry; + // z[kdx+idx] = (jlong)yz_idx1; + // carry = (jlong)(yz_idx1 >>> 64); + // } + // + + Label L_third_loop, L_third_loop_exit, L_post_third_loop_done; + + movl(jdx, idx); + andl(jdx, 0xFFFFFFFC); + shrl(jdx, 2); + + bind(L_third_loop); + subl(jdx, 1); + jcc(Assembler::negative, L_third_loop_exit); + subl(idx, 4); + + movq(yz_idx1, Address(y, idx, Address::times_4, 8)); + rorxq(yz_idx1, yz_idx1, 32); // convert big-endian to little-endian + movq(yz_idx2, Address(y, idx, Address::times_4, 0)); + rorxq(yz_idx2, yz_idx2, 32); + + mulxq(tmp4, tmp3, yz_idx1); // yz_idx1 * rdx -> tmp4:tmp3 + mulxq(carry2, tmp, yz_idx2); // yz_idx2 * rdx -> carry2:tmp + + movq(yz_idx1, Address(z, idx, Address::times_4, 8)); + rorxq(yz_idx1, yz_idx1, 32); + movq(yz_idx2, Address(z, idx, Address::times_4, 0)); + rorxq(yz_idx2, yz_idx2, 32); + + if (VM_Version::supports_adx()) { + adcxq(tmp3, carry); + adoxq(tmp3, yz_idx1); + + adcxq(tmp4, tmp); + adoxq(tmp4, yz_idx2); + + movl(carry, 0); // does not affect flags + adcxq(carry2, carry); + adoxq(carry2, carry); + } else { + add2_with_carry(tmp4, tmp3, carry, yz_idx1); + add2_with_carry(carry2, tmp4, tmp, yz_idx2); + } + movq(carry, carry2); + + movl(Address(z, idx, Address::times_4, 12), tmp3); + shrq(tmp3, 32); + movl(Address(z, idx, Address::times_4, 8), tmp3); + + movl(Address(z, idx, Address::times_4, 4), tmp4); + shrq(tmp4, 32); + movl(Address(z, idx, Address::times_4, 0), tmp4); + + jmp(L_third_loop); + + bind (L_third_loop_exit); + + andl (idx, 0x3); + jcc(Assembler::zero, L_post_third_loop_done); + + Label L_check_1; + subl(idx, 2); + jcc(Assembler::negative, L_check_1); + + movq(yz_idx1, Address(y, idx, Address::times_4, 0)); + rorxq(yz_idx1, yz_idx1, 32); + mulxq(tmp4, tmp3, yz_idx1); // yz_idx1 * rdx -> tmp4:tmp3 + movq(yz_idx2, Address(z, idx, Address::times_4, 0)); + rorxq(yz_idx2, yz_idx2, 32); + + add2_with_carry(tmp4, tmp3, carry, yz_idx2); + + movl(Address(z, idx, Address::times_4, 4), tmp3); + shrq(tmp3, 32); + movl(Address(z, idx, Address::times_4, 0), tmp3); + movq(carry, tmp4); + + bind (L_check_1); + addl (idx, 0x2); + andl (idx, 0x1); + subl(idx, 1); + jcc(Assembler::negative, L_post_third_loop_done); + movl(tmp4, Address(y, idx, Address::times_4, 0)); + mulxq(carry2, tmp3, tmp4); // tmp4 * rdx -> carry2:tmp3 + movl(tmp4, Address(z, idx, Address::times_4, 0)); + + add2_with_carry(carry2, tmp3, tmp4, carry); + + movl(Address(z, idx, Address::times_4, 0), tmp3); + shrq(tmp3, 32); + + shlq(carry2, 32); + orq(tmp3, carry2); + movq(carry, tmp3); + + bind(L_post_third_loop_done); +} + +/** + * Code for BigInteger::multiplyToLen() instrinsic. + * + * rdi: x + * rax: xlen + * rsi: y + * rcx: ylen + * r8: z + * r11: zlen + * r12: tmp1 + * r13: tmp2 + * r14: tmp3 + * r15: tmp4 + * rbx: tmp5 + * + */ +void MacroAssembler::multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5) { + ShortBranchVerifier sbv(this); + assert_different_registers(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5, rdx); + + push(tmp1); + push(tmp2); + push(tmp3); + push(tmp4); + push(tmp5); + + push(xlen); + push(zlen); + + const Register idx = tmp1; + const Register kdx = tmp2; + const Register xstart = tmp3; + + const Register y_idx = tmp4; + const Register carry = tmp5; + const Register product = xlen; + const Register x_xstart = zlen; // reuse register + + // First Loop. + // + // final static long LONG_MASK = 0xffffffffL; + // int xstart = xlen - 1; + // int ystart = ylen - 1; + // long carry = 0; + // for (int idx=ystart, kdx=ystart+1+xstart; idx >= 0; idx-, kdx--) { + // long product = (y[idx] & LONG_MASK) * (x[xstart] & LONG_MASK) + carry; + // z[kdx] = (int)product; + // carry = product >>> 32; + // } + // z[xstart] = (int)carry; + // + + movl(idx, ylen); // idx = ylen; + movl(kdx, zlen); // kdx = xlen+ylen; + xorq(carry, carry); // carry = 0; + + Label L_done; + + movl(xstart, xlen); + decrementl(xstart); + jcc(Assembler::negative, L_done); + + multiply_64_x_64_loop(x, xstart, x_xstart, y, y_idx, z, carry, product, idx, kdx); + + Label L_second_loop; + testl(kdx, kdx); + jcc(Assembler::zero, L_second_loop); + + Label L_carry; + subl(kdx, 1); + jcc(Assembler::zero, L_carry); + + movl(Address(z, kdx, Address::times_4, 0), carry); + shrq(carry, 32); + subl(kdx, 1); + + bind(L_carry); + movl(Address(z, kdx, Address::times_4, 0), carry); + + // Second and third (nested) loops. + // + // for (int i = xstart-1; i >= 0; i--) { // Second loop + // carry = 0; + // for (int jdx=ystart, k=ystart+1+i; jdx >= 0; jdx--, k--) { // Third loop + // long product = (y[jdx] & LONG_MASK) * (x[i] & LONG_MASK) + + // (z[k] & LONG_MASK) + carry; + // z[k] = (int)product; + // carry = product >>> 32; + // } + // z[i] = (int)carry; + // } + // + // i = xlen, j = tmp1, k = tmp2, carry = tmp5, x[i] = rdx + + const Register jdx = tmp1; + + bind(L_second_loop); + xorl(carry, carry); // carry = 0; + movl(jdx, ylen); // j = ystart+1 + + subl(xstart, 1); // i = xstart-1; + jcc(Assembler::negative, L_done); + + push (z); + + Label L_last_x; + lea(z, Address(z, xstart, Address::times_4, 4)); // z = z + k - j + subl(xstart, 1); // i = xstart-1; + jcc(Assembler::negative, L_last_x); + + if (UseBMI2Instructions) { + movq(rdx, Address(x, xstart, Address::times_4, 0)); + rorxq(rdx, rdx, 32); // convert big-endian to little-endian + } else { + movq(x_xstart, Address(x, xstart, Address::times_4, 0)); + rorq(x_xstart, 32); // convert big-endian to little-endian + } + + Label L_third_loop_prologue; + bind(L_third_loop_prologue); + + push (x); + push (xstart); + push (ylen); + + + if (UseBMI2Instructions) { + multiply_128_x_128_bmi2_loop(y, z, carry, x, jdx, ylen, product, tmp2, x_xstart, tmp3, tmp4); + } else { // !UseBMI2Instructions + multiply_128_x_128_loop(x_xstart, y, z, y_idx, jdx, ylen, carry, product, x); + } + + pop(ylen); + pop(xlen); + pop(x); + pop(z); + + movl(tmp3, xlen); + addl(tmp3, 1); + movl(Address(z, tmp3, Address::times_4, 0), carry); + subl(tmp3, 1); + jccb(Assembler::negative, L_done); + + shrq(carry, 32); + movl(Address(z, tmp3, Address::times_4, 0), carry); + jmp(L_second_loop); + + // Next infrequent code is moved outside loops. + bind(L_last_x); + if (UseBMI2Instructions) { + movl(rdx, Address(x, 0)); + } else { + movl(x_xstart, Address(x, 0)); + } + jmp(L_third_loop_prologue); + + bind(L_done); + + pop(zlen); + pop(xlen); + + pop(tmp5); + pop(tmp4); + pop(tmp3); + pop(tmp2); + pop(tmp1); +} +#endif + /** * Emits code to update CRC-32 with a byte value according to constants in table * diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/macroAssembler_x86.hpp --- a/src/cpu/x86/vm/macroAssembler_x86.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/macroAssembler_x86.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -1221,6 +1221,28 @@ XMMRegister tmp1, XMMRegister tmp2, XMMRegister tmp3, XMMRegister tmp4, Register tmp5, Register result); +#ifdef _LP64 + void add2_with_carry(Register dest_hi, Register dest_lo, Register src1, Register src2); + void multiply_64_x_64_loop(Register x, Register xstart, Register x_xstart, + Register y, Register y_idx, Register z, + Register carry, Register product, + Register idx, Register kdx); + void multiply_add_128_x_128(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, + Register carry, Register product, int offset); + void multiply_128_x_128_bmi2_loop(Register y, Register z, + Register carry, Register carry2, + Register idx, Register jdx, + Register yz_idx1, Register yz_idx2, + Register tmp, Register tmp3, Register tmp4); + void multiply_128_x_128_loop(Register x_xstart, Register y, Register z, + Register yz_idx, Register idx, Register jdx, + Register carry, Register product, + Register carry2); + void multiply_to_len(Register x, Register xlen, Register y, Register ylen, Register z, Register zlen, + Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5); +#endif + // CRC32 code for java.util.zip.CRC32::updateBytes() instrinsic. void update_byte_crc32(Register crc, Register val, Register table); void kernel_crc32(Register crc, Register buf, Register len, Register table, Register tmp); diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -3677,6 +3677,70 @@ return start; } + + /** + * Arguments: + * + * Input: + * c_rarg0 - x address + * c_rarg1 - x length + * c_rarg2 - y address + * c_rarg3 - y lenth + * not Win64 + * c_rarg4 - z address + * c_rarg5 - z length + * Win64 + * rsp+40 - z address + * rsp+48 - z length + */ + address generate_multiplyToLen() { + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "multiplyToLen"); + + address start = __ pc(); + // Win64: rcx, rdx, r8, r9 (c_rarg0, c_rarg1, ...) + // Unix: rdi, rsi, rdx, rcx, r8, r9 (c_rarg0, c_rarg1, ...) + const Register x = rdi; + const Register xlen = rax; + const Register y = rsi; + const Register ylen = rcx; + const Register z = r8; + const Register zlen = r11; + + // Next registers will be saved on stack in multiply_to_len(). + const Register tmp1 = r12; + const Register tmp2 = r13; + const Register tmp3 = r14; + const Register tmp4 = r15; + const Register tmp5 = rbx; + + BLOCK_COMMENT("Entry:"); + __ enter(); // required for proper stackwalking of RuntimeStub frame + +#ifndef _WIN64 + __ movptr(zlen, r9); // Save r9 in r11 - zlen +#endif + setup_arg_regs(4); // x => rdi, xlen => rsi, y => rdx + // ylen => rcx, z => r8, zlen => r11 + // r9 and r10 may be used to save non-volatile registers +#ifdef _WIN64 + // last 2 arguments (#4, #5) are on stack on Win64 + __ movptr(z, Address(rsp, 6 * wordSize)); + __ movptr(zlen, Address(rsp, 7 * wordSize)); +#endif + + __ movptr(xlen, rsi); + __ movptr(y, rdx); + __ multiply_to_len(x, xlen, y, ylen, z, zlen, tmp1, tmp2, tmp3, tmp4, tmp5); + + restore_arg_regs(); + + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; + } + #undef __ #define __ masm-> @@ -3917,6 +3981,11 @@ generate_safefetch("SafeFetchN", sizeof(intptr_t), &StubRoutines::_safefetchN_entry, &StubRoutines::_safefetchN_fault_pc, &StubRoutines::_safefetchN_continuation_pc); +#ifdef COMPILER2 + if (UseMultiplyToLenIntrinsic) { + StubRoutines::_multiplyToLen = generate_multiplyToLen(); + } +#endif } public: diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/vm_version_x86.cpp --- a/src/cpu/x86/vm/vm_version_x86.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/vm_version_x86.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -493,7 +493,7 @@ } char buf[256]; - jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + jio_snprintf(buf, sizeof(buf), "(%u cores per cpu, %u threads per core) family %d model %d stepping %d%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", cores_per_cpu(), threads_per_core(), cpu_family(), _model, _stepping, (supports_cmov() ? ", cmov" : ""), @@ -522,7 +522,8 @@ (supports_tscinv_bit() ? ", tscinvbit": ""), (supports_tscinv() ? ", tscinv": ""), (supports_bmi1() ? ", bmi1" : ""), - (supports_bmi2() ? ", bmi2" : "")); + (supports_bmi2() ? ", bmi2" : ""), + (supports_adx() ? ", adx" : "")); _features_str = strdup(buf); // UseSSE is set to the smaller of what hardware supports and what @@ -574,7 +575,7 @@ } } else if (UseCRC32Intrinsics) { if (!FLAG_IS_DEFAULT(UseCRC32Intrinsics)) - warning("CRC32 Intrinsics requires AVX and CLMUL instructions (not available on this CPU)"); + warning("CRC32 Intrinsics requires CLMUL instructions (not available on this CPU)"); FLAG_SET_DEFAULT(UseCRC32Intrinsics, false); } @@ -697,7 +698,20 @@ } #endif } + +#ifdef _LP64 + if (FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + UseMultiplyToLenIntrinsic = true; + } +#else + if (UseMultiplyToLenIntrinsic) { + if (!FLAG_IS_DEFAULT(UseMultiplyToLenIntrinsic)) { + warning("multiplyToLen intrinsic is not available in 32-bit VM"); + } + FLAG_SET_DEFAULT(UseMultiplyToLenIntrinsic, false); + } #endif +#endif // COMPILER2 // On new cpus instructions which update whole XMM register should be used // to prevent partial register stall due to dependencies on high half. @@ -840,6 +854,9 @@ } } } + if(FLAG_IS_DEFAULT(AllocatePrefetchInstr) && supports_3dnow_prefetch()) { + AllocatePrefetchInstr = 3; + } } // Use count leading zeros count instruction if available. @@ -852,23 +869,35 @@ FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false); } + // Use count trailing zeros instruction if available if (supports_bmi1()) { + // tzcnt does not require VEX prefix + if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { + UseCountTrailingZerosInstruction = true; + } + } else if (UseCountTrailingZerosInstruction) { + warning("tzcnt instruction is not available on this CPU"); + FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false); + } + + // BMI instructions use an encoding with VEX prefix. + // VEX prefix is generated only when AVX > 0. + if (supports_bmi1() && supports_avx()) { if (FLAG_IS_DEFAULT(UseBMI1Instructions)) { UseBMI1Instructions = true; } } else if (UseBMI1Instructions) { - warning("BMI1 instructions are not available on this CPU"); + warning("BMI1 instructions are not available on this CPU (AVX is also required)"); FLAG_SET_DEFAULT(UseBMI1Instructions, false); } - // Use count trailing zeros instruction if available - if (supports_bmi1()) { - if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { - UseCountTrailingZerosInstruction = UseBMI1Instructions; + if (supports_bmi2() && supports_avx()) { + if (FLAG_IS_DEFAULT(UseBMI2Instructions)) { + UseBMI2Instructions = true; } - } else if (UseCountTrailingZerosInstruction) { - warning("tzcnt instruction is not available on this CPU"); - FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false); + } else if (UseBMI2Instructions) { + warning("BMI2 instructions are not available on this CPU (AVX is also required)"); + FLAG_SET_DEFAULT(UseBMI2Instructions, false); } // Use population count instruction if available. diff -r 8cb56c8cb30d -r f0bedf980c65 src/cpu/x86/vm/vm_version_x86.hpp --- a/src/cpu/x86/vm/vm_version_x86.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/cpu/x86/vm/vm_version_x86.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -209,7 +209,9 @@ erms : 1, : 1, rtm : 1, - : 20; + : 7, + adx : 1, + : 12; } bits; }; @@ -260,7 +262,8 @@ CPU_CLMUL = (1 << 21), // carryless multiply for CRC CPU_BMI1 = (1 << 22), CPU_BMI2 = (1 << 23), - CPU_RTM = (1 << 24) // Restricted Transactional Memory instructions + CPU_RTM = (1 << 24), // Restricted Transactional Memory instructions + CPU_ADX = (1 << 25) } cpuFeatureFlags; enum { @@ -465,10 +468,16 @@ } // Intel features. if(is_intel()) { + if(_cpuid_info.sef_cpuid7_ebx.bits.adx != 0) + result |= CPU_ADX; if(_cpuid_info.sef_cpuid7_ebx.bits.bmi2 != 0) result |= CPU_BMI2; if(_cpuid_info.ext_cpuid1_ecx.bits.lzcnt_intel != 0) result |= CPU_LZCNT; + // for Intel, ecx.bits.misalignsse bit (bit 8) indicates support for prefetchw + if (_cpuid_info.ext_cpuid1_ecx.bits.misalignsse != 0) { + result |= CPU_3DNOW_PREFETCH; + } } return result; @@ -621,6 +630,7 @@ static bool supports_rtm() { return (_cpuFeatures & CPU_RTM) != 0; } static bool supports_bmi1() { return (_cpuFeatures & CPU_BMI1) != 0; } static bool supports_bmi2() { return (_cpuFeatures & CPU_BMI2) != 0; } + static bool supports_adx() { return (_cpuFeatures & CPU_ADX) != 0; } // Intel features static bool is_intel_family_core() { return is_intel() && extended_cpu_family() == CPU_FAMILY_INTEL_CORE; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp --- a/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/os_cpu/solaris_sparc/vm/vm_version_solaris_sparc.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -26,10 +26,140 @@ #include "runtime/os.hpp" #include "vm_version_sparc.hpp" -# include -# include -# include -# include +#include +#include +#include +#include +#include + +extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); +extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result); + +class PICL { + // Get a value of the integer property. The value in the tree can be either 32 or 64 bit + // depending on the platform. The result is converted to int. + static int get_int_property(picl_nodehdl_t nodeh, const char* name, int* result) { + picl_propinfo_t pinfo; + picl_prophdl_t proph; + if (picl_get_prop_by_name(nodeh, name, &proph) != PICL_SUCCESS || + picl_get_propinfo(proph, &pinfo) != PICL_SUCCESS) { + return PICL_FAILURE; + } + + if (pinfo.type != PICL_PTYPE_INT && pinfo.type != PICL_PTYPE_UNSIGNED_INT) { + assert(false, "Invalid property type"); + return PICL_FAILURE; + } + if (pinfo.size == sizeof(int64_t)) { + int64_t val; + if (picl_get_propval(proph, &val, sizeof(int64_t)) != PICL_SUCCESS) { + return PICL_FAILURE; + } + *result = static_cast(val); + } else if (pinfo.size == sizeof(int32_t)) { + int32_t val; + if (picl_get_propval(proph, &val, sizeof(int32_t)) != PICL_SUCCESS) { + return PICL_FAILURE; + } + *result = static_cast(val); + } else { + assert(false, "Unexpected integer property size"); + return PICL_FAILURE; + } + return PICL_SUCCESS; + } + + // Visitor and a state machine that visits integer properties and verifies that the + // values are the same. Stores the unique value observed. + class UniqueValueVisitor { + enum { + INITIAL, // Start state, no assignments happened + ASSIGNED, // Assigned a value + INCONSISTENT // Inconsistent value seen + } _state; + int _value; + public: + UniqueValueVisitor() : _state(INITIAL) { } + int value() { + assert(_state == ASSIGNED, "Precondition"); + return _value; + } + void set_value(int value) { + assert(_state == INITIAL, "Precondition"); + _value = value; + _state = ASSIGNED; + } + bool is_initial() { return _state == INITIAL; } + bool is_assigned() { return _state == ASSIGNED; } + bool is_inconsistent() { return _state == INCONSISTENT; } + void set_inconsistent() { _state = INCONSISTENT; } + + static int visit(picl_nodehdl_t nodeh, const char* name, void *arg) { + UniqueValueVisitor *state = static_cast(arg); + assert(!state->is_inconsistent(), "Precondition"); + int curr; + if (PICL::get_int_property(nodeh, name, &curr) == PICL_SUCCESS) { + if (!state->is_assigned()) { // first iteration + state->set_value(curr); + } else if (curr != state->value()) { // following iterations + state->set_inconsistent(); + } + } + if (state->is_inconsistent()) { + return PICL_WALK_TERMINATE; + } + return PICL_WALK_CONTINUE; + } + }; + + int _L1_data_cache_line_size; + int _L2_cache_line_size; +public: + static int get_l1_data_cache_line_size(picl_nodehdl_t nodeh, void *state) { + return UniqueValueVisitor::visit(nodeh, "l1-dcache-line-size", state); + } + static int get_l2_cache_line_size(picl_nodehdl_t nodeh, void *state) { + return UniqueValueVisitor::visit(nodeh, "l2-cache-line-size", state); + } + + PICL() : _L1_data_cache_line_size(0), _L2_cache_line_size(0) { + if (picl_initialize() == PICL_SUCCESS) { + picl_nodehdl_t rooth; + if (picl_get_root(&rooth) == PICL_SUCCESS) { + UniqueValueVisitor L1_state; + // Visit all "cpu" class instances + picl_walk_tree_by_class(rooth, "cpu", &L1_state, PICL_get_l1_data_cache_line_size_helper); + if (L1_state.is_initial()) { // Still initial, iteration found no values + // Try walk all "core" class instances, it might be a Fujitsu machine + picl_walk_tree_by_class(rooth, "core", &L1_state, PICL_get_l1_data_cache_line_size_helper); + } + if (L1_state.is_assigned()) { // Is there a value? + _L1_data_cache_line_size = L1_state.value(); + } + + UniqueValueVisitor L2_state; + picl_walk_tree_by_class(rooth, "cpu", &L2_state, PICL_get_l2_cache_line_size_helper); + if (L2_state.is_initial()) { + picl_walk_tree_by_class(rooth, "core", &L2_state, PICL_get_l2_cache_line_size_helper); + } + if (L2_state.is_assigned()) { + _L2_cache_line_size = L2_state.value(); + } + } + picl_shutdown(); + } + } + + unsigned int L1_data_cache_line_size() const { return _L1_data_cache_line_size; } + unsigned int L2_cache_line_size() const { return _L2_cache_line_size; } +}; + +extern "C" static int PICL_get_l1_data_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { + return PICL::get_l1_data_cache_line_size(nodeh, result); +} +extern "C" static int PICL_get_l2_cache_line_size_helper(picl_nodehdl_t nodeh, void *result) { + return PICL::get_l2_cache_line_size(nodeh, result); +} // We need to keep these here as long as we have to build on Solaris // versions before 10. @@ -263,5 +393,9 @@ kstat_close(kc); } + // Figure out cache line sizes using PICL + PICL picl; + _L2_cache_line_size = picl.L2_cache_line_size(); + return features; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java --- a/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/tools/LogCompilation/src/com/sun/hotspot/tools/compiler/LogParser.java Tue Sep 16 13:55:38 2014 -0700 @@ -406,9 +406,17 @@ } else if (scopes.peek().getCalls().size() > 2 && m == scopes.peek().last(-2).getMethod()) { scopes.push(scopes.peek().last(-2)); } else { - System.out.println(site.getMethod()); - System.out.println(m); - throw new InternalError("call site and parse don't match"); + // C1 prints multiple method tags during inlining when it narrows method being inlinied. + // Example: + // ... + // + // + // + // + // + // ... + site.setMethod(m); + scopes.push(site); } } } else if (qname.equals("parse_done")) { diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/asm/codeBuffer.cpp --- a/src/share/vm/asm/codeBuffer.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/asm/codeBuffer.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -133,6 +133,10 @@ // free any overflow storage delete _overflow_arena; + // Claim is that stack allocation ensures resources are cleaned up. + // This is resource clean up, let's hope that all were properly copied out. + free_strings(); + #ifdef ASSERT // Save allocation type to execute assert in ~ResourceObj() // which is called after this destructor. @@ -704,7 +708,7 @@ relocate_code_to(&dest); // transfer strings and comments from buffer to blob - dest_blob->set_strings(_strings); + dest_blob->set_strings(_code_strings); // Done moving code bytes; were they the right size? assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity"); @@ -1003,11 +1007,11 @@ void CodeBuffer::block_comment(intptr_t offset, const char * comment) { - _strings.add_comment(offset, comment); + _code_strings.add_comment(offset, comment); } const char* CodeBuffer::code_string(const char* str) { - return _strings.add_string(str); + return _code_strings.add_string(str); } class CodeString: public CHeapObj { @@ -1073,6 +1077,7 @@ } void CodeStrings::add_comment(intptr_t offset, const char * comment) { + check_valid(); CodeString* c = new CodeString(comment, offset); CodeString* inspos = (_strings == NULL) ? NULL : find_last(offset); @@ -1088,11 +1093,32 @@ } void CodeStrings::assign(CodeStrings& other) { + other.check_valid(); + // Cannot do following because CodeStrings constructor is not alway run! + assert(is_null(), "Cannot assign onto non-empty CodeStrings"); _strings = other._strings; + other.set_null_and_invalidate(); +} + +// Deep copy of CodeStrings for consistent memory management. +// Only used for actual disassembly so this is cheaper than reference counting +// for the "normal" fastdebug case. +void CodeStrings::copy(CodeStrings& other) { + other.check_valid(); + check_valid(); + assert(is_null(), "Cannot copy onto non-empty CodeStrings"); + CodeString* n = other._strings; + CodeString** ps = &_strings; + while (n != NULL) { + *ps = new CodeString(n->string(),n->offset()); + ps = &((*ps)->_next); + n = n->next(); + } } void CodeStrings::print_block_comment(outputStream* stream, intptr_t offset) const { - if (_strings != NULL) { + check_valid(); + if (_strings != NULL) { CodeString* c = find(offset); while (c && c->offset() == offset) { stream->bol(); @@ -1103,7 +1129,7 @@ } } - +// Also sets isNull() void CodeStrings::free() { CodeString* n = _strings; while (n) { @@ -1113,10 +1139,11 @@ delete n; n = p; } - _strings = NULL; + set_null_and_invalidate(); } const char* CodeStrings::add_string(const char * string) { + check_valid(); CodeString* s = new CodeString(string); s->set_next(_strings); _strings = s; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/asm/codeBuffer.hpp --- a/src/share/vm/asm/codeBuffer.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/asm/codeBuffer.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -27,6 +27,7 @@ #include "code/oopRecorder.hpp" #include "code/relocInfo.hpp" +#include "utilities/debug.hpp" class CodeStrings; class PhaseCFG; @@ -245,15 +246,39 @@ private: #ifndef PRODUCT CodeString* _strings; +#ifdef ASSERT + // Becomes true after copy-out, forbids further use. + bool _defunct; // Zero bit pattern is "valid", see memset call in decode_env::decode_env +#endif #endif CodeString* find(intptr_t offset) const; CodeString* find_last(intptr_t offset) const; + void set_null_and_invalidate() { +#ifndef PRODUCT + _strings = NULL; +#ifdef ASSERT + _defunct = true; +#endif +#endif + } + public: CodeStrings() { #ifndef PRODUCT _strings = NULL; +#ifdef ASSERT + _defunct = false; +#endif +#endif + } + + bool is_null() { +#ifdef ASSERT + return _strings == NULL; +#else + return true; #endif } @@ -261,8 +286,17 @@ void add_comment(intptr_t offset, const char * comment) PRODUCT_RETURN; void print_block_comment(outputStream* stream, intptr_t offset) const PRODUCT_RETURN; + // MOVE strings from other to this; invalidate other. void assign(CodeStrings& other) PRODUCT_RETURN; + // COPY strings from other to this; leave other valid. + void copy(CodeStrings& other) PRODUCT_RETURN; void free() PRODUCT_RETURN; + // Guarantee that _strings are used at most once; assign invalidates a buffer. + inline void check_valid() const { +#ifdef ASSERT + assert(!_defunct, "Use of invalid CodeStrings"); +#endif + } }; // A CodeBuffer describes a memory space into which assembly @@ -330,7 +364,7 @@ csize_t _total_size; // size in bytes of combined memory buffer OopRecorder* _oop_recorder; - CodeStrings _strings; + CodeStrings _code_strings; OopRecorder _default_oop_recorder; // override with initialize_oop_recorder Arena* _overflow_arena; @@ -531,7 +565,13 @@ void initialize_oop_recorder(OopRecorder* r); OopRecorder* oop_recorder() const { return _oop_recorder; } - CodeStrings& strings() { return _strings; } + CodeStrings& strings() { return _code_strings; } + + void free_strings() { + if (!_code_strings.is_null()) { + _code_strings.free(); // sets _strings Null as a side-effect. + } + } // Code generation void relocate(address at, RelocationHolder const& rspec, int format = 0) { diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/asm/register.hpp --- a/src/share/vm/asm/register.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/asm/register.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -275,4 +275,101 @@ ); } +inline void assert_different_registers( + AbstractRegister a, + AbstractRegister b, + AbstractRegister c, + AbstractRegister d, + AbstractRegister e, + AbstractRegister f, + AbstractRegister g, + AbstractRegister h, + AbstractRegister i, + AbstractRegister j +) { + assert( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j + && c != d && c != e && c != f && c != g && c != h && c != i && c != j + && d != e && d != f && d != g && d != h && d != i && d != j + && e != f && e != g && e != h && e != i && e != j + && f != g && f != h && f != i && f != j + && g != h && g != i && g != j + && h != i && h != j + && i != j, + err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j)) + ); +} + +inline void assert_different_registers( + AbstractRegister a, + AbstractRegister b, + AbstractRegister c, + AbstractRegister d, + AbstractRegister e, + AbstractRegister f, + AbstractRegister g, + AbstractRegister h, + AbstractRegister i, + AbstractRegister j, + AbstractRegister k +) { + assert( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k + && c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k + && d != e && d != f && d != g && d != h && d != i && d != j && d !=k + && e != f && e != g && e != h && e != i && e != j && e !=k + && f != g && f != h && f != i && f != j && f !=k + && g != h && g != i && g != j && g !=k + && h != i && h != j && h !=k + && i != j && i !=k + && j !=k, + err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k)) + ); +} + +inline void assert_different_registers( + AbstractRegister a, + AbstractRegister b, + AbstractRegister c, + AbstractRegister d, + AbstractRegister e, + AbstractRegister f, + AbstractRegister g, + AbstractRegister h, + AbstractRegister i, + AbstractRegister j, + AbstractRegister k, + AbstractRegister l +) { + assert( + a != b && a != c && a != d && a != e && a != f && a != g && a != h && a != i && a != j && a !=k && a !=l + && b != c && b != d && b != e && b != f && b != g && b != h && b != i && b != j && b !=k && b !=l + && c != d && c != e && c != f && c != g && c != h && c != i && c != j && c !=k && c !=l + && d != e && d != f && d != g && d != h && d != i && d != j && d !=k && d !=l + && e != f && e != g && e != h && e != i && e != j && e !=k && e !=l + && f != g && f != h && f != i && f != j && f !=k && f !=l + && g != h && g != i && g != j && g !=k && g !=l + && h != i && h != j && h !=k && h !=l + && i != j && i !=k && i !=l + && j !=k && j !=l + && k !=l, + err_msg_res("registers must be different: a=" INTPTR_FORMAT ", b=" INTPTR_FORMAT + ", c=" INTPTR_FORMAT ", d=" INTPTR_FORMAT ", e=" INTPTR_FORMAT + ", f=" INTPTR_FORMAT ", g=" INTPTR_FORMAT ", h=" INTPTR_FORMAT + ", i=" INTPTR_FORMAT ", j=" INTPTR_FORMAT ", k=" INTPTR_FORMAT + ", l=" INTPTR_FORMAT "", + p2i(a), p2i(b), p2i(c), p2i(d), p2i(e), p2i(f), p2i(g), p2i(h), p2i(i), p2i(j), p2i(k), p2i(l)) + ); +} + #endif // SHARE_VM_ASM_REGISTER_HPP diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -3960,10 +3960,15 @@ // Clear out bytecode stream scope_data()->set_stream(NULL); + CompileLog* log = compilation()->log(); + if (log != NULL) log->head("parse method='%d'", log->identify(callee)); + // Ready to resume parsing in callee (either in the same block we // were in before or in the callee's start block) iterate_all_blocks(callee_start_block == NULL); + if (log != NULL) log->done("parse"); + // If we bailed out during parsing, return immediately (this is bad news) if (bailed_out()) return false; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/c1/c1_Runtime1.cpp --- a/src/share/vm/c1/c1_Runtime1.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/c1/c1_Runtime1.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -544,13 +544,18 @@ // normal bytecode execution. thread->clear_exception_oop_and_pc(); + Handle original_exception(thread, exception()); + continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); // If an exception was thrown during exception dispatch, the exception oop may have changed thread->set_exception_oop(exception()); thread->set_exception_pc(pc); // the exception cache is used only by non-implicit exceptions - if (continuation != NULL) { + // Update the exception cache only when there didn't happen + // another exception during the computation of the compiled + // exception handler. + if (continuation != NULL && original_exception() == exception()) { nm->add_handler_for_exception_and_pc(exception, pc, continuation); } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/ci/ciEnv.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -1112,9 +1112,6 @@ // ------------------------------------------------------------------ // ciEnv::record_failure() void ciEnv::record_failure(const char* reason) { - if (log() != NULL) { - log()->elem("failure reason='%s'", reason); - } if (_failure_reason == NULL) { // Record the first failure reason. _failure_reason = reason; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/ci/ciMethod.cpp --- a/src/share/vm/ci/ciMethod.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/ci/ciMethod.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -1106,6 +1106,22 @@ } // ------------------------------------------------------------------ +// ciMethod::has_option_value +// +template +bool ciMethod::has_option_value(const char* option, T& value) { + check_is_loaded(); + VM_ENTRY_MARK; + methodHandle mh(THREAD, get_Method()); + return CompilerOracle::has_option_value(mh, option, value); +} +// Explicit instantiation for all OptionTypes supported. +template bool ciMethod::has_option_value(const char* option, intx& value); +template bool ciMethod::has_option_value(const char* option, uintx& value); +template bool ciMethod::has_option_value(const char* option, bool& value); +template bool ciMethod::has_option_value(const char* option, ccstr& value); + +// ------------------------------------------------------------------ // ciMethod::can_be_compiled // // Have previous compilations of this method succeeded? diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/ci/ciMethod.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -264,6 +264,8 @@ bool should_print_assembly(); bool break_at_execute(); bool has_option(const char *option); + template + bool has_option_value(const char* option, T& value); bool can_be_compiled(); bool can_be_osr_compiled(int entry_bci); void set_not_compilable(const char* reason = NULL); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/classfile/classFileParser.cpp --- a/src/share/vm/classfile/classFileParser.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/classfile/classFileParser.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -4142,8 +4142,8 @@ } // Allocate mirror and initialize static fields - java_lang_Class::create_mirror(this_klass, protection_domain, CHECK_(nullHandle)); - + java_lang_Class::create_mirror(this_klass, class_loader, protection_domain, + CHECK_(nullHandle)); // Generate any default methods - default methods are interface methods // that have a default implementation. This is new with Lambda project. diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/classfile/classLoader.cpp --- a/src/share/vm/classfile/classLoader.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/classfile/classLoader.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -1618,7 +1618,7 @@ if (TieredCompilation && TieredStopAtLevel >= CompLevel_full_optimization) { // Clobber the first compile and force second tier compilation nmethod* nm = m->code(); - if (nm != NULL) { + if (nm != NULL && !m->is_method_handle_intrinsic()) { // Throw out the code so that the code cache doesn't fill up nm->make_not_entrant(); m->clear_code(); @@ -1637,7 +1637,7 @@ } nmethod* nm = m->code(); - if (nm != NULL) { + if (nm != NULL && !m->is_method_handle_intrinsic()) { // Throw out the code so that the code cache doesn't fill up nm->make_not_entrant(); m->clear_code(); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/classfile/javaClasses.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -548,7 +548,7 @@ } } } - create_mirror(k, Handle(NULL), CHECK); + create_mirror(k, Handle(NULL), Handle(NULL), CHECK); } void java_lang_Class::initialize_mirror_fields(KlassHandle k, @@ -568,7 +568,8 @@ InstanceKlass::cast(k())->do_local_static_fields(&initialize_static_field, mirror, CHECK); } -void java_lang_Class::create_mirror(KlassHandle k, Handle protection_domain, TRAPS) { +void java_lang_Class::create_mirror(KlassHandle k, Handle class_loader, + Handle protection_domain, TRAPS) { assert(k->java_mirror() == NULL, "should only assign mirror once"); // Use this moment of initialization to cache modifier_flags also, // to support Class.getModifiers(). Instance classes recalculate @@ -623,6 +624,9 @@ } } + // set the classLoader field in the java_lang_Class instance + set_class_loader(mirror(), class_loader()); + // Setup indirection from klass->mirror last // after any exceptions can happen during allocations. if (!k.is_null()) { @@ -684,6 +688,18 @@ } +void java_lang_Class::set_class_loader(oop java_class, oop loader) { + // jdk7 runs Queens in bootstrapping and jdk8-9 has no coordinated pushes yet. + if (_class_loader_offset != 0) { + java_class->obj_field_put(_class_loader_offset, loader); + } +} + +oop java_lang_Class::class_loader(oop java_class) { + assert(_class_loader_offset != 0, "must be set"); + return java_class->obj_field(_class_loader_offset); +} + oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS) { // This should be improved by adding a field at the Java level or by // introducing a new VM klass (see comment in ClassFileParser) @@ -843,6 +859,12 @@ compute_optional_offset(classRedefinedCount_offset, klass_oop, vmSymbols::classRedefinedCount_name(), vmSymbols::int_signature()); + // Needs to be optional because the old build runs Queens during bootstrapping + // and jdk8-9 doesn't have coordinated pushes yet. + compute_optional_offset(_class_loader_offset, + klass_oop, vmSymbols::classLoader_name(), + vmSymbols::classloader_signature()); + CLASS_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET); } @@ -3082,6 +3104,7 @@ int java_lang_Class::_array_klass_offset; int java_lang_Class::_oop_size_offset; int java_lang_Class::_static_oop_field_count_offset; +int java_lang_Class::_class_loader_offset; int java_lang_Class::_protection_domain_offset; int java_lang_Class::_init_lock_offset; int java_lang_Class::_signers_offset; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/classfile/javaClasses.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -239,19 +239,23 @@ static int _protection_domain_offset; static int _init_lock_offset; static int _signers_offset; + static int _class_loader_offset; static bool offsets_computed; static int classRedefinedCount_offset; + static GrowableArray* _fixup_mirror_list; static void set_init_lock(oop java_class, oop init_lock); static void set_protection_domain(oop java_class, oop protection_domain); + static void set_class_loader(oop java_class, oop class_loader); static void initialize_mirror_fields(KlassHandle k, Handle mirror, Handle protection_domain, TRAPS); public: static void compute_offsets(); // Instance creation - static void create_mirror(KlassHandle k, Handle protection_domain, TRAPS); + static void create_mirror(KlassHandle k, Handle class_loader, + Handle protection_domain, TRAPS); static void fixup_mirror(KlassHandle k, TRAPS); static oop create_basic_type_mirror(const char* basic_type_name, BasicType type, TRAPS); // Conversion @@ -289,6 +293,8 @@ static objArrayOop signers(oop java_class); static void set_signers(oop java_class, objArrayOop signers); + static oop class_loader(oop java_class); + static int oop_size(oop java_class); static void set_oop_size(oop java_class, int size); static int static_oop_field_count(oop java_class); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/classfile/systemDictionary.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -51,6 +51,7 @@ #include "oops/typeArrayKlass.hpp" #include "prims/jvmtiEnvBase.hpp" #include "prims/methodHandles.hpp" +#include "runtime/arguments.hpp" #include "runtime/biasedLocking.hpp" #include "runtime/fieldType.hpp" #include "runtime/handles.inline.hpp" @@ -2277,7 +2278,11 @@ m = Method::make_method_handle_intrinsic(iid, signature, CHECK_(empty)); CompileBroker::compile_method(m, InvocationEntryBci, CompLevel_highest_tier, methodHandle(), CompileThreshold, "MH", CHECK_(empty)); - + // Check if we need to have compiled code but we don't. + if (!Arguments::is_interpreter_only() && !m->has_compiled_code()) { + THROW_MSG_(vmSymbols::java_lang_VirtualMachineError(), + "out of space in CodeCache for method handle intrinsic", empty); + } // Now grab the lock. We might have to throw away the new method, // if a racing thread has managed to install one at the same time. { @@ -2291,6 +2296,9 @@ } assert(spe != NULL && spe->method() != NULL, ""); + assert(Arguments::is_interpreter_only() || (spe->method()->has_compiled_code() && + spe->method()->code()->entry_point() == spe->method()->from_compiled_entry()), + "MH intrinsic invariant"); return spe->method(); } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/classfile/vmSymbols.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -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 @@ -587,6 +587,7 @@ template(serializePropertiesToByteArray_signature, "()[B") \ template(serializeAgentPropertiesToByteArray_name, "serializeAgentPropertiesToByteArray") \ template(classRedefinedCount_name, "classRedefinedCount") \ + template(classLoader_name, "classLoader") \ \ /* trace signatures */ \ TRACE_TEMPLATES(template) \ @@ -786,6 +787,11 @@ do_name( encodeISOArray_name, "encodeISOArray") \ do_signature(encodeISOArray_signature, "([CI[BII)I") \ \ + do_class(java_math_BigInteger, "java/math/BigInteger") \ + do_intrinsic(_multiplyToLen, java_math_BigInteger, multiplyToLen_name, multiplyToLen_signature, F_R) \ + do_name( multiplyToLen_name, "multiplyToLen") \ + do_signature(multiplyToLen_signature, "([II[II[I)[I") \ + \ /* java/lang/ref/Reference */ \ do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \ \ diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/code/codeBlob.cpp --- a/src/share/vm/code/codeBlob.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/code/codeBlob.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -253,6 +253,7 @@ void BufferBlob::free( BufferBlob *blob ) { ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + blob->flush(); { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::free((CodeBlob*)blob); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/code/codeCache.cpp --- a/src/share/vm/code/codeCache.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/code/codeCache.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -712,7 +712,9 @@ void CodeCache::mark_all_nmethods_for_deoptimization() { MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); FOR_ALL_ALIVE_NMETHODS(nm) { - nm->mark_for_deoptimization(); + if (!nm->method()->is_method_handle_intrinsic()) { + nm->mark_for_deoptimization(); + } } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/code/compiledIC.cpp --- a/src/share/vm/code/compiledIC.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/code/compiledIC.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -595,6 +595,7 @@ } else { // Callee is interpreted code. In any case entering the interpreter // puts a converter-frame on the stack to save arguments. + assert(!m->is_method_handle_intrinsic(), "Compiled code should never call interpreter MH intrinsics"); info._to_interpreter = true; info._entry = m()->get_c2i_entry(); } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/code/nmethod.hpp --- a/src/share/vm/code/nmethod.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/code/nmethod.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -448,7 +448,10 @@ // alive. It is used when an uncommon trap happens. Returns true // if this thread changed the state of the nmethod or false if // another thread performed the transition. - bool make_not_entrant() { return make_not_entrant_or_zombie(not_entrant); } + bool make_not_entrant() { + assert(!method()->is_method_handle_intrinsic(), "Cannot make MH intrinsic not entrant"); + return make_not_entrant_or_zombie(not_entrant); + } bool make_zombie() { return make_not_entrant_or_zombie(zombie); } // used by jvmti to track if the unload event has been reported diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/compiler/compileBroker.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -287,6 +287,7 @@ _hot_count = hot_count; _time_queued = 0; // tidy _comment = comment; + _failure_reason = NULL; if (LogCompilation) { _time_queued = os::elapsed_counter(); @@ -565,6 +566,11 @@ methodHandle method(thread, this->method()); ResourceMark rm(thread); + if (!_is_success) { + const char* reason = _failure_reason != NULL ? _failure_reason : "unknown"; + log->elem("failure reason='%s'", reason); + } + // nmethod* nm = code(); log->begin_elem("task_done success='%d' nmsize='%d' count='%d'", @@ -688,13 +694,40 @@ return NULL; } - CompileTask* task = CompilationPolicy::policy()->select_task(this); + CompileTask* task; + { + No_Safepoint_Verifier nsv; + task = CompilationPolicy::policy()->select_task(this); + } remove(task); + purge_stale_tasks(); // may temporarily release MCQ lock return task; } -void CompileQueue::remove(CompileTask* task) -{ +// Clean & deallocate stale compile tasks. +// Temporarily releases MethodCompileQueue lock. +void CompileQueue::purge_stale_tasks() { + assert(lock()->owned_by_self(), "must own lock"); + if (_first_stale != NULL) { + // Stale tasks are purged when MCQ lock is released, + // but _first_stale updates are protected by MCQ lock. + // Once task processing starts and MCQ lock is released, + // other compiler threads can reuse _first_stale. + CompileTask* head = _first_stale; + _first_stale = NULL; + { + MutexUnlocker ul(lock()); + for (CompileTask* task = head; task != NULL; ) { + CompileTask* next_task = task->next(); + CompileTaskWrapper ctw(task); // Frees the task + task->set_failure_reason("stale task"); + task = next_task; + } + } + } +} + +void CompileQueue::remove(CompileTask* task) { assert(lock()->owned_by_self(), "must own lock"); if (task->prev() != NULL) { task->prev()->set_next(task->next()); @@ -714,6 +747,16 @@ --_size; } +void CompileQueue::remove_and_mark_stale(CompileTask* task) { + assert(lock()->owned_by_self(), "must own lock"); + remove(task); + + // Enqueue the task for reclamation (should be done outside MCQ lock) + task->set_next(_first_stale); + task->set_prev(NULL); + _first_stale = task; +} + // methods in the compile queue need to be marked as used on the stack // so that they don't get reclaimed by Redefine Classes void CompileQueue::mark_on_stack() { @@ -1752,6 +1795,7 @@ } else { // After compilation is disabled, remove remaining methods from queue method->clear_queued_for_compilation(); + task->set_failure_reason("compilation is disabled"); } } } @@ -1939,6 +1983,7 @@ compilable = ci_env.compilable(); if (ci_env.failing()) { + task->set_failure_reason(ci_env.failure_reason()); const char* retry_message = ci_env.retry_message(); if (_compilation_log != NULL) { _compilation_log->log_failure(thread, task, ci_env.failure_reason(), retry_message); @@ -2011,7 +2056,7 @@ // Note that the queued_for_compilation bits are cleared without // protection of a mutex. [They were set by the requester thread, - // when adding the task to the complie queue -- at which time the + // when adding the task to the compile queue -- at which time the // compile queue lock was held. Subsequently, we acquired the compile // queue lock to get this task off the compile queue; thus (to belabour // the point somewhat) our clearing of the bits must be occurring diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/compiler/compileBroker.hpp --- a/src/share/vm/compiler/compileBroker.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/compiler/compileBroker.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -59,6 +59,7 @@ jobject _hot_method_holder; int _hot_count; // information about its invocation counter const char* _comment; // more info about the task + const char* _failure_reason; public: CompileTask() { @@ -130,6 +131,10 @@ void log_task_queued(); void log_task_start(CompileLog* log); void log_task_done(CompileLog* log); + + void set_failure_reason(const char* reason) { + _failure_reason = reason; + } }; // CompilerCounters @@ -188,7 +193,11 @@ CompileTask* _first; CompileTask* _last; + CompileTask* _first_stale; + int _size; + + void purge_stale_tasks(); public: CompileQueue(const char* name, Monitor* lock) { _name = name; @@ -196,6 +205,7 @@ _first = NULL; _last = NULL; _size = 0; + _first_stale = NULL; } const char* name() const { return _name; } @@ -203,6 +213,7 @@ void add(CompileTask* task); void remove(CompileTask* task); + void remove_and_mark_stale(CompileTask* task); CompileTask* first() { return _first; } CompileTask* last() { return _last; } @@ -211,6 +222,7 @@ bool is_empty() const { return _first == NULL; } int size() const { return _size; } + // Redefine Classes support void mark_on_stack(); void delete_all(); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/compiler/compilerOracle.cpp --- a/src/share/vm/compiler/compilerOracle.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/compiler/compilerOracle.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -167,44 +167,134 @@ } } +enum OptionType { + IntxType, + UintxType, + BoolType, + CcstrType, + UnknownType +}; -class MethodOptionMatcher: public MethodMatcher { - const char * option; - public: - MethodOptionMatcher(Symbol* class_name, Mode class_mode, - Symbol* method_name, Mode method_mode, - Symbol* signature, const char * opt, MethodMatcher* next): - MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next) { - option = opt; +/* Methods to map real type names to OptionType */ +template +static OptionType get_type_for() { + return UnknownType; +}; + +template<> OptionType get_type_for() { + return IntxType; +} + +template<> OptionType get_type_for() { + return UintxType; +} + +template<> OptionType get_type_for() { + return BoolType; +} + +template<> OptionType get_type_for() { + return CcstrType; +} + +template +static const T copy_value(const T value) { + return value; +} + +template<> const ccstr copy_value(const ccstr value) { + return (const ccstr)strdup(value); +} + +template +class TypedMethodOptionMatcher : public MethodMatcher { + const char* _option; + OptionType _type; + const T _value; + +public: + TypedMethodOptionMatcher(Symbol* class_name, Mode class_mode, + Symbol* method_name, Mode method_mode, + Symbol* signature, const char* opt, + const T value, MethodMatcher* next) : + MethodMatcher(class_name, class_mode, method_name, method_mode, signature, next), + _type(get_type_for()), _value(copy_value(value)) { + _option = strdup(opt); } - bool match(methodHandle method, const char* opt) { - MethodOptionMatcher* current = this; + ~TypedMethodOptionMatcher() { + free((void*)_option); + } + + TypedMethodOptionMatcher* match(methodHandle method, const char* opt) { + TypedMethodOptionMatcher* current = this; while (current != NULL) { - current = (MethodOptionMatcher*)current->find(method); + current = (TypedMethodOptionMatcher*)current->find(method); if (current == NULL) { - return false; + return NULL; } - if (strcmp(current->option, opt) == 0) { - return true; + if (strcmp(current->_option, opt) == 0) { + return current; } current = current->next(); } - return false; + return NULL; + } + + TypedMethodOptionMatcher* next() { + return (TypedMethodOptionMatcher*)_next; } - MethodOptionMatcher* next() { - return (MethodOptionMatcher*)_next; - } + OptionType get_type(void) { + return _type; + }; + + T value() { return _value; } - virtual void print() { + void print() { + ttyLocker ttyl; print_base(); - tty->print(" %s", option); + tty->print(" %s", _option); + tty->print(" "); tty->cr(); } }; +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" intx %s", _option); + tty->print(" = " INTX_FORMAT, _value); + tty->cr(); +}; +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" uintx %s", _option); + tty->print(" = " UINTX_FORMAT, _value); + tty->cr(); +}; + +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" bool %s", _option); + tty->print(" = %s", _value ? "true" : "false"); + tty->cr(); +}; + +template<> +void TypedMethodOptionMatcher::print() { + ttyLocker ttyl; + print_base(); + tty->print(" const char* %s", _option); + tty->print(" = '%s'", _value); + tty->cr(); +}; // this must parallel the command_names below enum OracleCommand { @@ -259,23 +349,46 @@ return lists[command]; } - - +template static MethodMatcher* add_option_string(Symbol* class_name, MethodMatcher::Mode c_mode, Symbol* method_name, MethodMatcher::Mode m_mode, Symbol* signature, - const char* option) { - lists[OptionCommand] = new MethodOptionMatcher(class_name, c_mode, method_name, m_mode, - signature, option, lists[OptionCommand]); + const char* option, + T value) { + lists[OptionCommand] = new TypedMethodOptionMatcher(class_name, c_mode, method_name, m_mode, + signature, option, value, lists[OptionCommand]); return lists[OptionCommand]; } +template +static bool get_option_value(methodHandle method, const char* option, T& value) { + TypedMethodOptionMatcher* m; + if (lists[OptionCommand] != NULL + && (m = ((TypedMethodOptionMatcher*)lists[OptionCommand])->match(method, option)) != NULL + && m->get_type() == get_type_for()) { + value = m->value(); + return true; + } else { + return false; + } +} bool CompilerOracle::has_option_string(methodHandle method, const char* option) { - return lists[OptionCommand] != NULL && - ((MethodOptionMatcher*)lists[OptionCommand])->match(method, option); + bool value = false; + get_option_value(method, option, value); + return value; } +template +bool CompilerOracle::has_option_value(methodHandle method, const char* option, T& value) { + return ::get_option_value(method, option, value); +} + +// Explicit instantiation for all OptionTypes supported. +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, intx& value); +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, uintx& value); +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, bool& value); +template bool CompilerOracle::has_option_value(methodHandle method, const char* option, ccstr& value); bool CompilerOracle::should_exclude(methodHandle method, bool& quietly) { quietly = true; @@ -433,6 +546,94 @@ +// Scan next flag and value in line, return MethodMatcher object on success, NULL on failure. +// On failure, error_msg contains description for the first error. +// For future extensions: set error_msg on first error. +static MethodMatcher* scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, + Symbol* c_name, MethodMatcher::Mode c_match, + Symbol* m_name, MethodMatcher::Mode m_match, + Symbol* signature, + char* errorbuf, const int buf_size) { + total_bytes_read = 0; + int bytes_read = 0; + char flag[256]; + + // Read flag name. + if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", flag, &bytes_read) == 1) { + line += bytes_read; + total_bytes_read += bytes_read; + + // Read value. + if (strcmp(type, "intx") == 0) { + intx value; + if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n", &value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s ", flag, type); + } + } else if (strcmp(type, "uintx") == 0) { + uintx value; + if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n", &value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else if (strcmp(type, "ccstr") == 0) { + ResourceMark rm; + char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); + if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else if (strcmp(type, "ccstrlist") == 0) { + // Accumulates several strings into one. The internal type is ccstr. + ResourceMark rm; + char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); + char* next_value = value; + if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + line += bytes_read; + next_value += bytes_read; + char* end_value = next_value-1; + while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n", next_value, &bytes_read) == 1) { + total_bytes_read += bytes_read; + line += bytes_read; + *end_value = ' '; // override '\0' + next_value += bytes_read; + end_value = next_value-1; + } + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, (ccstr)value); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else if (strcmp(type, "bool") == 0) { + char value[256]; + if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n", value, &bytes_read) == 1) { + if (strcmp(value, "true") == 0) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, true); + } else if (strcmp(value, "false") == 0) { + total_bytes_read += bytes_read; + return add_option_string(c_name, c_match, m_name, m_match, signature, flag, false); + } else { + jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s", flag, type); + } + } else { + jio_snprintf(errorbuf, sizeof(errorbuf), " Value cannot be read for flag %s of type %s", flag, type); + } + } else { + jio_snprintf(errorbuf, sizeof(errorbuf), " Type %s not supported ", type); + } + } else { + jio_snprintf(errorbuf, sizeof(errorbuf), " Flag name for type %s should be alphanumeric ", type); + } + return NULL; +} + void CompilerOracle::parse_from_line(char* line) { if (line[0] == '\0') return; if (line[0] == '#') return; @@ -462,8 +663,10 @@ int bytes_read; OracleCommand command = parse_command_name(line, &bytes_read); line += bytes_read; + ResourceMark rm; if (command == UnknownCommand) { + ttyLocker ttyl; tty->print_cr("CompilerOracle: unrecognized line"); tty->print_cr(" \"%s\"", original_line); return; @@ -485,7 +688,7 @@ char method_name[256]; char sig[1024]; char errorbuf[1024]; - const char* error_msg = NULL; + const char* error_msg = NULL; // description of first error that appears MethodMatcher* match = NULL; if (scan_line(line, class_name, &c_match, method_name, &m_match, &bytes_read, error_msg)) { @@ -504,43 +707,77 @@ } if (command == OptionCommand) { - // Look for trailing options to support - // ciMethod::has_option("string") to control features in the - // compiler. Multiple options may follow the method name. - char option[256]; + // Look for trailing options. + // + // Two types of trailing options are + // supported: + // + // (1) CompileCommand=option,Klass::method,flag + // (2) CompileCommand=option,Klass::method,type,flag,value + // + // Type (1) is used to support ciMethod::has_option("someflag") + // (i.e., to check if a flag "someflag" is enabled for a method). + // + // Type (2) is used to support options with a value. Values can have the + // the following types: intx, uintx, bool, ccstr, and ccstrlist. + // + // For future extensions: extend scan_flag_and_value() + char option[256]; // stores flag for Type (1) and type of Type (2) while (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", option, &bytes_read) == 1) { if (match != NULL && !_quiet) { // Print out the last match added + ttyLocker ttyl; tty->print("CompilerOracle: %s ", command_names[command]); match->print(); } - match = add_option_string(c_name, c_match, m_name, m_match, signature, strdup(option)); line += bytes_read; - } + + if (strcmp(option, "intx") == 0 + || strcmp(option, "uintx") == 0 + || strcmp(option, "bool") == 0 + || strcmp(option, "ccstr") == 0 + || strcmp(option, "ccstrlist") == 0 + ) { + + // Type (2) option: parse flag name and value. + match = scan_flag_and_value(option, line, bytes_read, + c_name, c_match, m_name, m_match, signature, + errorbuf, sizeof(errorbuf)); + if (match == NULL) { + error_msg = errorbuf; + break; + } + line += bytes_read; + } else { + // Type (1) option + match = add_option_string(c_name, c_match, m_name, m_match, signature, option, true); + } + } // while( } else { - bytes_read = 0; - sscanf(line, "%*[ \t]%n", &bytes_read); - if (line[bytes_read] != '\0') { - jio_snprintf(errorbuf, sizeof(errorbuf), " Unrecognized text after command: %s", line); - error_msg = errorbuf; - } else { - match = add_predicate(command, c_name, c_match, m_name, m_match, signature); - } + match = add_predicate(command, c_name, c_match, m_name, m_match, signature); } } - if (match != NULL) { - if (!_quiet) { - ResourceMark rm; - tty->print("CompilerOracle: %s ", command_names[command]); - match->print(); - } - } else { + ttyLocker ttyl; + if (error_msg != NULL) { + // an error has happened tty->print_cr("CompilerOracle: unrecognized line"); tty->print_cr(" \"%s\"", original_line); if (error_msg != NULL) { tty->print_cr("%s", error_msg); } + } else { + // check for remaining characters + bytes_read = 0; + sscanf(line, "%*[ \t]%n", &bytes_read); + if (line[bytes_read] != '\0') { + tty->print_cr("CompilerOracle: unrecognized line"); + tty->print_cr(" \"%s\"", original_line); + tty->print_cr(" Unrecognized text %s after command ", line); + } else if (match != NULL && !_quiet) { + tty->print("CompilerOracle: %s ", command_names[command]); + match->print(); + } } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/compiler/compilerOracle.hpp --- a/src/share/vm/compiler/compilerOracle.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/compiler/compilerOracle.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -64,6 +64,11 @@ // Check to see if this method has option set for it static bool has_option_string(methodHandle method, const char * option); + // Check if method has option and value set. If yes, overwrite value and return true, + // otherwise leave value unchanged and return false. + template + static bool has_option_value(methodHandle method, const char* option, T& value); + // Reads from string instead of file static void parse_from_string(const char* command_string, void (*parser)(char*)); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/compiler/disassembler.cpp --- a/src/share/vm/compiler/disassembler.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/compiler/disassembler.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -245,12 +245,12 @@ }; decode_env::decode_env(CodeBlob* code, outputStream* output, CodeStrings c) { - memset(this, 0, sizeof(*this)); + memset(this, 0, sizeof(*this)); // Beware, this zeroes bits of fields. _output = output ? output : tty; _code = code; if (code != NULL && code->is_nmethod()) _nm = (nmethod*) code; - _strings.assign(c); + _strings.copy(c); // by default, output pc but not bytes: _print_pc = true; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/concurrentMark.cpp --- a/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/concurrentMark.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -3332,6 +3332,7 @@ } else { g1_par_agg_task.work(0); } + _g1h->allocation_context_stats().update_at_remark(); } // Clear the per-worker arrays used to store the per-region counting data diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1AllocationContext.hpp --- a/src/share/vm/gc_implementation/g1/g1AllocationContext.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/g1AllocationContext.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -41,4 +41,12 @@ } }; +class AllocationContextStats: public StackObj { +public: + inline void clear() { } + inline void update(bool full_gc) { } + inline void update_at_remark() { } + inline bool available() { return false; } +}; + #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1ALLOCATIONCONTEXT_HPP diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1Allocator.hpp --- a/src/share/vm/gc_implementation/g1/g1Allocator.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/g1Allocator.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -86,6 +86,12 @@ void set_used(size_t bytes) { _summary_bytes_used = bytes; } + + virtual HeapRegion* new_heap_region(uint hrs_index, + G1BlockOffsetSharedArray* sharedOffsetArray, + MemRegion mr) { + return new HeapRegion(hrs_index, sharedOffsetArray, mr); + } }; // The default allocator for G1. diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -3585,7 +3585,7 @@ } } -void G1CollectedHeap::gc_epilogue(bool full /* Ignored */) { +void G1CollectedHeap::gc_epilogue(bool full) { if (G1SummarizeRSetStats && (G1SummarizeRSetStatsPeriod > 0) && @@ -3602,6 +3602,7 @@ // always_do_update_barrier = true; resize_all_tlabs(); + allocation_context_stats().update(full); // We have just completed a GC. Update the soft reference // policy with the new heap occupancy diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -263,6 +263,9 @@ // Class that handles the different kinds of allocations. G1Allocator* _allocator; + // Statistics for each allocation context + AllocationContextStats _allocation_context_stats; + // PLAB sizing policy for survivors. PLABStats _survivor_plab_stats; @@ -620,6 +623,10 @@ public: + G1Allocator* allocator() { + return _allocator; + } + G1MonitoringSupport* g1mm() { assert(_g1mm != NULL, "should have been initialized"); return _g1mm; @@ -652,6 +659,8 @@ // Determines PLAB size for a particular allocation purpose. size_t desired_plab_sz(GCAllocPurpose purpose); + inline AllocationContextStats& allocation_context_stats(); + // Do anything common to GC's. virtual void gc_prologue(bool full); virtual void gc_epilogue(bool full); @@ -1240,6 +1249,11 @@ // The same as above but assume that the caller holds the Heap_lock. void collect_locked(GCCause::Cause cause); + virtual void copy_allocation_context_stats(const jint* contexts, + jlong* totals, + jbyte* accuracy, + jint len); + // True iff an evacuation has failed in the most-recent collection. bool evacuation_failed() { return _evacuation_failed; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.inline.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -37,6 +37,10 @@ // Inline functions for G1CollectedHeap +inline AllocationContextStats& G1CollectedHeap::allocation_context_stats() { + return _allocation_context_stats; +} + // Return the region with the given index. It assumes the index is valid. inline HeapRegion* G1CollectedHeap::region_at(uint index) const { return _hrm.at(index); } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1CollectedHeap_ext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap_ext.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,32 @@ +/* + * 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/g1CollectedHeap.hpp" + +void G1CollectedHeap::copy_allocation_context_stats(const jint* contexts, + jlong* totals, + jbyte* accuracy, + jint len) { +} diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1MarkSweep.cpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -194,76 +194,6 @@ gc_tracer()->report_object_count_after_gc(&GenMarkSweep::is_alive); } -class G1PrepareCompactClosure: public HeapRegionClosure { - G1CollectedHeap* _g1h; - ModRefBarrierSet* _mrbs; - CompactPoint _cp; - HeapRegionSetCount _humongous_regions_removed; - - bool is_cp_initialized() const { - return _cp.space != NULL; - } - - void prepare_for_compaction(HeapRegion* hr, HeapWord* end) { - // If this is the first live region that we came across which we can compact, - // initialize the CompactPoint. - if (!is_cp_initialized()) { - _cp.space = hr; - _cp.threshold = hr->initialize_threshold(); - } - hr->prepare_for_compaction(&_cp); - // Also clear the part of the card table that will be unused after - // compaction. - _mrbs->clear(MemRegion(hr->compaction_top(), end)); - } - - void free_humongous_region(HeapRegion* hr) { - HeapWord* end = hr->end(); - FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); - - assert(hr->startsHumongous(), - "Only the start of a humongous region should be freed."); - - hr->set_containing_set(NULL); - _humongous_regions_removed.increment(1u, hr->capacity()); - - _g1h->free_humongous_region(hr, &dummy_free_list, false /* par */); - prepare_for_compaction(hr, end); - dummy_free_list.remove_all(); - } - -public: - G1PrepareCompactClosure() - : _g1h(G1CollectedHeap::heap()), - _mrbs(_g1h->g1_barrier_set()), - _cp(NULL), - _humongous_regions_removed() { } - - void update_sets() { - // We'll recalculate total used bytes and recreate the free list - // at the end of the GC, so no point in updating those values here. - HeapRegionSetCount empty_set; - _g1h->remove_from_old_sets(empty_set, _humongous_regions_removed); - } - - bool doHeapRegion(HeapRegion* hr) { - if (hr->isHumongous()) { - if (hr->startsHumongous()) { - oop obj = oop(hr->bottom()); - if (obj->is_gc_marked()) { - obj->forward_to(obj); - } else { - free_humongous_region(hr); - } - } else { - assert(hr->continuesHumongous(), "Invalid humongous."); - } - } else { - prepare_for_compaction(hr, hr->end()); - } - return false; - } -}; void G1MarkSweep::mark_sweep_phase2() { // Now all live objects are marked, compute the new object addresses. @@ -272,14 +202,10 @@ // phase2, phase3 and phase4, but the ValidateMarkSweep live oops // tracking expects us to do so. See comment under phase4. - G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCTraceTime tm("phase 2", G1Log::fine() && Verbose, true, gc_timer(), gc_tracer()->gc_id()); GenMarkSweep::trace("2"); - G1PrepareCompactClosure blk; - g1h->heap_region_iterate(&blk); - blk.update_sets(); + prepare_compaction(); } class G1AdjustPointersClosure: public HeapRegionClosure { @@ -374,3 +300,68 @@ g1h->heap_region_iterate(&blk); } + +void G1MarkSweep::prepare_compaction_work(G1PrepareCompactClosure* blk) { + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + g1h->heap_region_iterate(blk); + blk->update_sets(); +} + +void G1PrepareCompactClosure::free_humongous_region(HeapRegion* hr) { + HeapWord* end = hr->end(); + FreeRegionList dummy_free_list("Dummy Free List for G1MarkSweep"); + + assert(hr->startsHumongous(), + "Only the start of a humongous region should be freed."); + + hr->set_containing_set(NULL); + _humongous_regions_removed.increment(1u, hr->capacity()); + + _g1h->free_humongous_region(hr, &dummy_free_list, false /* par */); + prepare_for_compaction(hr, end); + dummy_free_list.remove_all(); +} + +void G1PrepareCompactClosure::prepare_for_compaction(HeapRegion* hr, HeapWord* end) { + // If this is the first live region that we came across which we can compact, + // initialize the CompactPoint. + if (!is_cp_initialized()) { + _cp.space = hr; + _cp.threshold = hr->initialize_threshold(); + } + prepare_for_compaction_work(&_cp, hr, end); +} + +void G1PrepareCompactClosure::prepare_for_compaction_work(CompactPoint* cp, + HeapRegion* hr, + HeapWord* end) { + hr->prepare_for_compaction(cp); + // Also clear the part of the card table that will be unused after + // compaction. + _mrbs->clear(MemRegion(hr->compaction_top(), end)); +} + +void G1PrepareCompactClosure::update_sets() { + // We'll recalculate total used bytes and recreate the free list + // at the end of the GC, so no point in updating those values here. + HeapRegionSetCount empty_set; + _g1h->remove_from_old_sets(empty_set, _humongous_regions_removed); +} + +bool G1PrepareCompactClosure::doHeapRegion(HeapRegion* hr) { + if (hr->isHumongous()) { + if (hr->startsHumongous()) { + oop obj = oop(hr->bottom()); + if (obj->is_gc_marked()) { + obj->forward_to(obj); + } else { + free_humongous_region(hr); + } + } else { + assert(hr->continuesHumongous(), "Invalid humongous."); + } + } else { + prepare_for_compaction(hr, hr->end()); + } + return false; +} diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1MarkSweep.hpp --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -43,7 +43,7 @@ // compaction. // // Class unloading will only occur when a full gc is invoked. - +class G1PrepareCompactClosure; class G1MarkSweep : AllStatic { friend class VM_G1MarkSweep; @@ -70,6 +70,30 @@ static void mark_sweep_phase4(); static void allocate_stacks(); + static void prepare_compaction(); + static void prepare_compaction_work(G1PrepareCompactClosure* blk); +}; + +class G1PrepareCompactClosure : public HeapRegionClosure { + protected: + G1CollectedHeap* _g1h; + ModRefBarrierSet* _mrbs; + CompactPoint _cp; + HeapRegionSetCount _humongous_regions_removed; + + virtual void prepare_for_compaction(HeapRegion* hr, HeapWord* end); + void prepare_for_compaction_work(CompactPoint* cp, HeapRegion* hr, HeapWord* end); + void free_humongous_region(HeapRegion* hr); + bool is_cp_initialized() const { return _cp.space != NULL; } + + public: + G1PrepareCompactClosure() : + _g1h(G1CollectedHeap::heap()), + _mrbs(_g1h->g1_barrier_set()), + _humongous_regions_removed() { } + + void update_sets(); + bool doHeapRegion(HeapRegion* hr); }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_G1MARKSWEEP_HPP diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/g1MarkSweep_ext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep_ext.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2001, 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. + * + */ + +#include "precompiled.hpp" +#include "gc_implementation/g1/g1MarkSweep.hpp" + +void G1MarkSweep::prepare_compaction() { + G1PrepareCompactClosure blk; + G1MarkSweep::prepare_compaction_work(&blk); +} diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/heapRegion.cpp --- a/src/share/vm/gc_implementation/g1/heapRegion.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/heapRegion.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -28,6 +28,7 @@ #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" #include "gc_implementation/g1/g1OopClosures.inline.hpp" #include "gc_implementation/g1/heapRegion.inline.hpp" +#include "gc_implementation/g1/heapRegionBounds.inline.hpp" #include "gc_implementation/g1/heapRegionRemSet.hpp" #include "gc_implementation/g1/heapRegionManager.inline.hpp" #include "gc_implementation/shared/liveRange.hpp" @@ -137,32 +138,16 @@ } } -// Minimum region size; we won't go lower than that. -// We might want to decrease this in the future, to deal with small -// heaps a bit more efficiently. -#define MIN_REGION_SIZE ( 1024 * 1024 ) - -// Maximum region size; we don't go higher than that. There's a good -// reason for having an upper bound. We don't want regions to get too -// large, otherwise cleanup's effectiveness would decrease as there -// will be fewer opportunities to find totally empty regions after -// marking. -#define MAX_REGION_SIZE ( 32 * 1024 * 1024 ) - -// The automatic region size calculation will try to have around this -// many regions in the heap (based on the min heap size). -#define TARGET_REGION_NUMBER 2048 - size_t HeapRegion::max_region_size() { - return (size_t)MAX_REGION_SIZE; + return HeapRegionBounds::max_size(); } void HeapRegion::setup_heap_region_size(size_t initial_heap_size, size_t max_heap_size) { uintx region_size = G1HeapRegionSize; if (FLAG_IS_DEFAULT(G1HeapRegionSize)) { size_t average_heap_size = (initial_heap_size + max_heap_size) / 2; - region_size = MAX2(average_heap_size / TARGET_REGION_NUMBER, - (uintx) MIN_REGION_SIZE); + region_size = MAX2(average_heap_size / HeapRegionBounds::target_number(), + (uintx) HeapRegionBounds::min_size()); } int region_size_log = log2_long((jlong) region_size); @@ -172,10 +157,10 @@ region_size = ((uintx)1 << region_size_log); // Now make sure that we don't go over or under our limits. - if (region_size < MIN_REGION_SIZE) { - region_size = MIN_REGION_SIZE; - } else if (region_size > MAX_REGION_SIZE) { - region_size = MAX_REGION_SIZE; + if (region_size < HeapRegionBounds::min_size()) { + region_size = HeapRegionBounds::min_size(); + } else if (region_size > HeapRegionBounds::max_size()) { + region_size = HeapRegionBounds::max_size(); } // And recalculate the log. @@ -347,9 +332,10 @@ HeapRegion::HeapRegion(uint hrm_index, G1BlockOffsetSharedArray* sharedOffsetArray, - MemRegion mr, AllocationContext_t context) : + MemRegion mr) : G1OffsetTableContigSpace(sharedOffsetArray, mr), - _hrm_index(hrm_index), _allocation_context(context), + _hrm_index(hrm_index), + _allocation_context(AllocationContext::system()), _humongous_type(NotHumongous), _humongous_start_region(NULL), _in_collection_set(false), _next_in_special_set(NULL), _orig_end(NULL), diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/heapRegion.hpp --- a/src/share/vm/gc_implementation/g1/heapRegion.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/heapRegion.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -335,8 +335,7 @@ public: HeapRegion(uint hrm_index, G1BlockOffsetSharedArray* sharedOffsetArray, - MemRegion mr, - AllocationContext_t context = AllocationContext::system()); + MemRegion mr); // Initializing the HeapRegion not only resets the data structure, but also // resets the BOT for that heap region. diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/heapRegionBounds.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/heapRegionBounds.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,52 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONBOUNDS_HPP +#define SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONBOUNDS_HPP + +class HeapRegionBounds : public AllStatic { +private: + // Minimum region size; we won't go lower than that. + // We might want to decrease this in the future, to deal with small + // heaps a bit more efficiently. + static const size_t MIN_REGION_SIZE = 1024 * 1024; + + // Maximum region size; we don't go higher than that. There's a good + // reason for having an upper bound. We don't want regions to get too + // large, otherwise cleanup's effectiveness would decrease as there + // will be fewer opportunities to find totally empty regions after + // marking. + static const size_t MAX_REGION_SIZE = 32 * 1024 * 1024; + + // The automatic region size calculation will try to have around this + // many regions in the heap (based on the min heap size). + static const size_t TARGET_REGION_NUMBER = 2048; + +public: + static inline size_t min_size(); + static inline size_t max_size(); + static inline size_t target_number(); +}; + +#endif // SHARE_VM_GC_IMPLEMENTATION_G1_HEAPREGIONBOUNDS_HPP diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/heapRegionBounds.inline.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/gc_implementation/g1/heapRegionBounds.inline.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,37 @@ +/* + * 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. + * + */ + +#include "gc_implementation/g1/heapRegionBounds.hpp" + +size_t HeapRegionBounds::min_size() { + return MIN_REGION_SIZE; +} + +size_t HeapRegionBounds::max_size() { + return MAX_REGION_SIZE; +} + +size_t HeapRegionBounds::target_number() { + return TARGET_REGION_NUMBER; +} diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_implementation/g1/heapRegionManager.cpp --- a/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_implementation/g1/heapRegionManager.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -66,10 +66,11 @@ #endif HeapRegion* HeapRegionManager::new_heap_region(uint hrm_index) { - HeapWord* bottom = G1CollectedHeap::heap()->bottom_addr_for_region(hrm_index); + G1CollectedHeap* g1h = G1CollectedHeap::heap(); + HeapWord* bottom = g1h->bottom_addr_for_region(hrm_index); MemRegion mr(bottom, bottom + HeapRegion::GrainWords); assert(reserved().contains(mr), "invariant"); - return new HeapRegion(hrm_index, G1CollectedHeap::heap()->bot_shared(), mr); + return g1h->allocator()->new_heap_region(hrm_index, g1h->bot_shared(), mr); } void HeapRegionManager::commit_regions(uint index, size_t num_regions) { diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_interface/collectedHeap.hpp --- a/src/share/vm/gc_interface/collectedHeap.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_interface/collectedHeap.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -637,6 +637,15 @@ // actual number may be germane. static bool use_parallel_gc_threads() { return ParallelGCThreads > 0; } + // Copy the current allocation context statistics for the specified contexts. + // For each context in contexts, set the corresponding entries in the totals + // and accuracy arrays to the current values held by the statistics. Each + // array should be of length len. + virtual void copy_allocation_context_stats(const jint* contexts, + jlong* totals, + jbyte* accuracy, + jint len) { } + /////////////// Unit tests /////////////// NOT_PRODUCT(static void test_is_in();) diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_interface/gcCause.cpp --- a/src/share/vm/gc_interface/gcCause.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_interface/gcCause.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -54,6 +54,9 @@ case _wb_young_gc: return "WhiteBox Initiated Young GC"; + case _update_allocation_context_stats: + return "Update Allocation Context Stats"; + case _no_gc: return "No GC"; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/gc_interface/gcCause.hpp --- a/src/share/vm/gc_interface/gcCause.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/gc_interface/gcCause.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -47,6 +47,7 @@ _heap_inspection, _heap_dump, _wb_young_gc, + _update_allocation_context_stats, /* implementation independent, but reserved for GC use */ _no_gc, diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/interpreter/interpreter.hpp --- a/src/share/vm/interpreter/interpreter.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/interpreter/interpreter.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -53,7 +53,9 @@ public: // Initialization/finalization void initialize(int size, - CodeStrings& strings) { _size = size; DEBUG_ONLY(_strings.assign(strings);) } + CodeStrings& strings) { _size = size; + DEBUG_ONLY(::new(&_strings) CodeStrings();) + DEBUG_ONLY(_strings.assign(strings);) } void finalize() { ShouldNotCallThis(); } // General info/converters diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -1269,8 +1269,10 @@ // This is a support of the JVMTI PopFrame interface. // Make sure it is an invokestatic of a polymorphic intrinsic that has a member_name argument // and return it as a vm_result so that it can be reloaded in the list of invokestatic parameters. -// The dmh argument is a reference to a DirectMethoHandle that has a member name field. -IRT_ENTRY(void, InterpreterRuntime::member_name_arg_or_null(JavaThread* thread, address dmh, +// The member_name argument is a saved reference (in local#0) to the member_name. +// For backward compatibility with some JDK versions (7, 8) it can also be a direct method handle. +// FIXME: remove DMH case after j.l.i.InvokerBytecodeGenerator code shape is updated. +IRT_ENTRY(void, InterpreterRuntime::member_name_arg_or_null(JavaThread* thread, address member_name, Method* method, address bcp)) Bytecodes::Code code = Bytecodes::code_at(method, bcp); if (code != Bytecodes::_invokestatic) { @@ -1282,8 +1284,12 @@ Symbol* mname = cpool->name_ref_at(cp_index); if (MethodHandles::has_member_arg(cname, mname)) { - oop member_name = java_lang_invoke_DirectMethodHandle::member((oop)dmh); - thread->set_vm_result(member_name); + oop member_name_oop = (oop) member_name; + if (java_lang_invoke_DirectMethodHandle::is_instance(member_name_oop)) { + // FIXME: remove after j.l.i.InvokerBytecodeGenerator code shape is updated. + member_name_oop = java_lang_invoke_DirectMethodHandle::member(member_name_oop); + } + thread->set_vm_result(member_name_oop); } IRT_END #endif // INCLUDE_JVMTI diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/memory/space.hpp --- a/src/share/vm/memory/space.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/memory/space.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -331,11 +331,10 @@ CompactibleSpace* space; HeapWord* threshold; - CompactPoint(Generation* _gen) : - gen(_gen), space(NULL), threshold(0) {} + CompactPoint(Generation* g = NULL) : + gen(g), space(NULL), threshold(0) {} }; - // A space that supports compaction operations. This is usually, but not // necessarily, a space that is normally contiguous. But, for example, a // free-list-based space whose normal collection is a mark-sweep without diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/memory/universe.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -126,6 +126,8 @@ oop Universe::_arithmetic_exception_instance = NULL; oop Universe::_virtual_machine_error_instance = NULL; oop Universe::_vm_exception = NULL; +oop Universe::_allocation_context_notification_obj = NULL; + Method* Universe::_throw_illegal_access_error = NULL; Array* Universe::_the_empty_int_array = NULL; Array* Universe::_the_empty_short_array = NULL; @@ -195,6 +197,7 @@ f->do_oop((oop*)&_main_thread_group); f->do_oop((oop*)&_system_thread_group); f->do_oop((oop*)&_vm_exception); + f->do_oop((oop*)&_allocation_context_notification_obj); debug_only(f->do_oop((oop*)&_fullgc_alot_dummy_array);) } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/memory/universe.hpp --- a/src/share/vm/memory/universe.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/memory/universe.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -178,6 +178,8 @@ // the vm thread. static oop _vm_exception; + static oop _allocation_context_notification_obj; + // The particular choice of collected heap. static CollectedHeap* _collectedHeap; @@ -307,6 +309,10 @@ static oop arithmetic_exception_instance() { return _arithmetic_exception_instance; } static oop virtual_machine_error_instance() { return _virtual_machine_error_instance; } static oop vm_exception() { return _vm_exception; } + + static inline oop allocation_context_notification_obj(); + static inline void set_allocation_context_notification_obj(oop obj); + static Method* throw_illegal_access_error() { return _throw_illegal_access_error; } static Array* the_empty_int_array() { return _the_empty_int_array; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/memory/universe.inline.hpp --- a/src/share/vm/memory/universe.inline.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/memory/universe.inline.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -41,4 +41,12 @@ return type == T_DOUBLE || type == T_LONG; } +inline oop Universe::allocation_context_notification_obj() { + return _allocation_context_notification_obj; +} + +inline void Universe::set_allocation_context_notification_obj(oop obj) { + _allocation_context_notification_obj = obj; +} + #endif // SHARE_VM_MEMORY_UNIVERSE_INLINE_HPP diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/arrayKlass.cpp --- a/src/share/vm/oops/arrayKlass.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/arrayKlass.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -100,7 +100,7 @@ ResourceMark rm(THREAD); k->initialize_supers(super_klass(), CHECK); k->vtable()->initialize_vtable(false, CHECK); - java_lang_Class::create_mirror(k, Handle(NULL), CHECK); + java_lang_Class::create_mirror(k, Handle(NULL), Handle(NULL), CHECK); } GrowableArray* ArrayKlass::compute_secondary_supers(int num_extra_slots) { diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/klass.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -536,7 +536,7 @@ // Only recreate it if not present. A previous attempt to restore may have // gotten an OOM later but keep the mirror if it was created. if (java_mirror() == NULL) { - java_lang_Class::create_mirror(this, protection_domain, CHECK); + java_lang_Class::create_mirror(this, class_loader(), protection_domain, CHECK); } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/method.cpp --- a/src/share/vm/oops/method.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/method.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -731,8 +731,8 @@ } if ((TraceDeoptimization || LogCompilation) && (xtty != NULL)) { ttyLocker ttyl; - xtty->begin_elem("make_not_%scompilable thread='" UINTX_FORMAT "'", - is_osr ? "osr_" : "", os::current_thread_id()); + xtty->begin_elem("make_not_compilable thread='" UINTX_FORMAT "' osr='%d' level='%d'", + os::current_thread_id(), is_osr, comp_level); if (reason != NULL) { xtty->print(" reason=\'%s\'", reason); } @@ -1636,34 +1636,34 @@ } int Method::highest_comp_level() const { - const MethodData* mdo = method_data(); - if (mdo != NULL) { - return mdo->highest_comp_level(); + const MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + return mcs->highest_comp_level(); } else { return CompLevel_none; } } int Method::highest_osr_comp_level() const { - const MethodData* mdo = method_data(); - if (mdo != NULL) { - return mdo->highest_osr_comp_level(); + const MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + return mcs->highest_osr_comp_level(); } else { return CompLevel_none; } } void Method::set_highest_comp_level(int level) { - MethodData* mdo = method_data(); - if (mdo != NULL) { - mdo->set_highest_comp_level(level); + MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + mcs->set_highest_comp_level(level); } } void Method::set_highest_osr_comp_level(int level) { - MethodData* mdo = method_data(); - if (mdo != NULL) { - mdo->set_highest_osr_comp_level(level); + MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + mcs->set_highest_osr_comp_level(level); } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/method.hpp --- a/src/share/vm/oops/method.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/method.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -233,10 +233,11 @@ // Tracking number of breakpoints, for fullspeed debugging. // Only mutated by VM thread. u2 number_of_breakpoints() const { - if (method_counters() == NULL) { + MethodCounters* mcs = method_counters(); + if (mcs == NULL) { return 0; } else { - return method_counters()->number_of_breakpoints(); + return mcs->number_of_breakpoints(); } } void incr_number_of_breakpoints(TRAPS) { @@ -253,8 +254,9 @@ } // Initialization only void clear_number_of_breakpoints() { - if (method_counters() != NULL) { - method_counters()->clear_number_of_breakpoints(); + MethodCounters* mcs = method_counters(); + if (mcs != NULL) { + mcs->clear_number_of_breakpoints(); } } @@ -301,10 +303,11 @@ } int interpreter_throwout_count() const { - if (method_counters() == NULL) { + MethodCounters* mcs = method_counters(); + if (mcs == NULL) { return 0; } else { - return method_counters()->interpreter_throwout_count(); + return mcs->interpreter_throwout_count(); } } @@ -379,26 +382,28 @@ return method_counters()->interpreter_invocation_count(); } } - void set_prev_event_count(int count, TRAPS) { - MethodCounters* mcs = get_method_counters(CHECK); + void set_prev_event_count(int count) { + MethodCounters* mcs = method_counters(); if (mcs != NULL) { mcs->set_interpreter_invocation_count(count); } } jlong prev_time() const { - return method_counters() == NULL ? 0 : method_counters()->prev_time(); + MethodCounters* mcs = method_counters(); + return mcs == NULL ? 0 : mcs->prev_time(); } - void set_prev_time(jlong time, TRAPS) { - MethodCounters* mcs = get_method_counters(CHECK); + void set_prev_time(jlong time) { + MethodCounters* mcs = method_counters(); if (mcs != NULL) { mcs->set_prev_time(time); } } float rate() const { - return method_counters() == NULL ? 0 : method_counters()->rate(); + MethodCounters* mcs = method_counters(); + return mcs == NULL ? 0 : mcs->rate(); } - void set_rate(float rate, TRAPS) { - MethodCounters* mcs = get_method_counters(CHECK); + void set_rate(float rate) { + MethodCounters* mcs = method_counters(); if (mcs != NULL) { mcs->set_rate(rate); } @@ -416,9 +421,12 @@ static MethodCounters* build_method_counters(Method* m, TRAPS); int interpreter_invocation_count() { - if (TieredCompilation) return invocation_count(); - else return (method_counters() == NULL) ? 0 : - method_counters()->interpreter_invocation_count(); + if (TieredCompilation) { + return invocation_count(); + } else { + MethodCounters* mcs = method_counters(); + return (mcs == NULL) ? 0 : mcs->interpreter_invocation_count(); + } } int increment_interpreter_invocation_count(TRAPS) { if (TieredCompilation) ShouldNotReachHere(); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/methodCounters.cpp --- a/src/share/vm/oops/methodCounters.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/methodCounters.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -34,4 +34,40 @@ backedge_counter()->reset(); set_interpreter_throwout_count(0); set_interpreter_invocation_count(0); +#ifdef TIERED + set_prev_time(0); + set_rate(0); + set_highest_comp_level(0); + set_highest_osr_comp_level(0); +#endif } + + +int MethodCounters::highest_comp_level() const { +#ifdef TIERED + return _highest_comp_level; +#else + return CompLevel_none; +#endif +} + +void MethodCounters::set_highest_comp_level(int level) { +#ifdef TIERED + _highest_comp_level = level; +#endif +} + +int MethodCounters::highest_osr_comp_level() const { +#ifdef TIERED + return _highest_osr_comp_level; +#else + return CompLevel_none; +#endif +} + +void MethodCounters::set_highest_osr_comp_level(int level) { +#ifdef TIERED + _highest_osr_comp_level = level; +#endif +} + diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/methodCounters.hpp --- a/src/share/vm/oops/methodCounters.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/methodCounters.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -39,6 +39,8 @@ #ifdef TIERED float _rate; // Events (invocation and backedge counter increments) per millisecond + u1 _highest_comp_level; // Highest compile level this method has ever seen. + u1 _highest_osr_comp_level; // Same for OSR level jlong _prev_time; // Previous time the rate was acquired #endif @@ -47,6 +49,8 @@ _number_of_breakpoints(0) #ifdef TIERED , _rate(0), + _highest_comp_level(0), + _highest_osr_comp_level(0), _prev_time(0) #endif { @@ -100,6 +104,11 @@ void set_rate(float rate) { _rate = rate; } #endif + int highest_comp_level() const; + void set_highest_comp_level(int level); + int highest_osr_comp_level() const; + void set_highest_osr_comp_level(int level); + // invocation counter InvocationCounter* invocation_counter() { return &_invocation_counter; } InvocationCounter* backedge_counter() { return &_backedge_counter; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/methodData.cpp --- a/src/share/vm/oops/methodData.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/methodData.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -1153,8 +1153,6 @@ _backedge_counter_start = 0; _num_loops = 0; _num_blocks = 0; - _highest_comp_level = 0; - _highest_osr_comp_level = 0; _would_profile = true; #if INCLUDE_RTM_OPT diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/oops/methodData.hpp --- a/src/share/vm/oops/methodData.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/oops/methodData.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -2057,7 +2057,7 @@ // Whole-method sticky bits and flags enum { - _trap_hist_limit = 19, // decoupled from Deoptimization::Reason_LIMIT + _trap_hist_limit = 20, // decoupled from Deoptimization::Reason_LIMIT _trap_hist_mask = max_jubyte, _extra_data_count = 4 // extra DataLayout headers, for trap history }; // Public flag values @@ -2098,10 +2098,6 @@ // time with C1. It is used to determine if method is trivial. short _num_loops; short _num_blocks; - // Highest compile level this method has ever seen. - u1 _highest_comp_level; - // Same for OSR level - u1 _highest_osr_comp_level; // Does this method contain anything worth profiling? bool _would_profile; @@ -2275,11 +2271,6 @@ void set_would_profile(bool p) { _would_profile = p; } bool would_profile() const { return _would_profile; } - int highest_comp_level() const { return _highest_comp_level; } - void set_highest_comp_level(int level) { _highest_comp_level = level; } - int highest_osr_comp_level() const { return _highest_osr_comp_level; } - void set_highest_osr_comp_level(int level) { _highest_osr_comp_level = level; } - int num_loops() const { return _num_loops; } void set_num_loops(int n) { _num_loops = n; } int num_blocks() const { return _num_blocks; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/bytecodeInfo.cpp --- a/src/share/vm/opto/bytecodeInfo.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/bytecodeInfo.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -107,7 +107,7 @@ int caller_bci, ciCallProfile& profile, WarmCallInfo* wci_result) { // Allows targeted inlining - if(callee_method->should_inline()) { + if (callee_method->should_inline()) { *wci_result = *(WarmCallInfo::always_hot()); if (C->print_inlining() && Verbose) { CompileTask::print_inline_indent(inline_level()); @@ -118,6 +118,12 @@ return true; } + if (callee_method->force_inline()) { + set_msg("force inline by annotation"); + _forced_inline = true; + return true; + } + #ifndef PRODUCT int inline_depth = inline_level()+1; if (ciReplay::should_inline(C->replay_inline_data(), callee_method, caller_bci, inline_depth)) { @@ -244,6 +250,11 @@ } #endif + if (callee_method->force_inline()) { + set_msg("force inline by annotation"); + return false; + } + // Now perform checks which are heuristic if (is_unboxing_method(callee_method, C)) { @@ -251,12 +262,10 @@ return false; } - if (!callee_method->force_inline()) { - if (callee_method->has_compiled_code() && - callee_method->instructions_size() > InlineSmallCode) { - set_msg("already compiled into a big method"); - return true; - } + if (callee_method->has_compiled_code() && + callee_method->instructions_size() > InlineSmallCode) { + set_msg("already compiled into a big method"); + return true; } // don't inline exception code unless the top method belongs to an @@ -349,7 +358,7 @@ // Escape Analysis stress testing when running Xcomp or CTW: // inline constructors even if they are not reached. } else if (forced_inline()) { - // Inlining was forced by CompilerOracle or ciReplay + // Inlining was forced by CompilerOracle, ciReplay or annotation } else if (profile.count() == 0) { // don't inline unreached call sites set_msg("call site not reached"); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/c2_globals.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -653,6 +653,9 @@ product(bool, UseMathExactIntrinsics, true, \ "Enables intrinsification of various java.lang.Math functions") \ \ + product(bool, UseMultiplyToLenIntrinsic, false, \ + "Enables intrinsification of BigInteger.multiplyToLen()") \ + \ product(bool, UseTypeSpeculation, true, \ "Speculatively propagate types from profiles") \ \ diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/callnode.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -777,7 +777,7 @@ } // Returns the unique CheckCastPP of a call -// or 'this' if there are several CheckCastPP +// or 'this' if there are several CheckCastPP or unexpected uses // or returns NULL if there is no one. Node *CallNode::result_cast() { Node *cast = NULL; @@ -793,6 +793,13 @@ return this; // more than 1 CheckCastPP } cast = use; + } else if (!use->is_Initialize() && + !use->is_AddP()) { + // Expected uses are restricted to a CheckCastPP, an Initialize + // node, and AddP nodes. If we encounter any other use (a Phi + // node can be seen in rare cases) return this to prevent + // incorrect optimizations. + return this; } } return cast; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/compile.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -598,6 +598,10 @@ bool method_has_option(const char * option) { return method() != NULL && method()->has_option(option); } + template + bool method_has_option_value(const char * option, T& value) { + return method() != NULL && method()->has_option_value(option, value); + } #ifndef PRODUCT bool trace_opto_output() const { return _trace_opto_output; } bool parsed_irreducible_loop() const { return _parsed_irreducible_loop; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/escape.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -944,7 +944,8 @@ strcmp(call->as_CallLeaf()->_name, "sha256_implCompress") == 0 || strcmp(call->as_CallLeaf()->_name, "sha256_implCompressMB") == 0 || strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 || - strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0) + strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 || + strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0) ))) { call->dump(); fatal(err_msg_res("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name)); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/library_call.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -322,6 +322,7 @@ bool inline_updateCRC32(); bool inline_updateBytesCRC32(); bool inline_updateByteBufferCRC32(); + bool inline_multiplyToLen(); }; @@ -330,8 +331,12 @@ vmIntrinsics::ID id = m->intrinsic_id(); assert(id != vmIntrinsics::_none, "must be a VM intrinsic"); - if (DisableIntrinsic[0] != '\0' - && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) { + ccstr disable_intr = NULL; + + if ((DisableIntrinsic[0] != '\0' + && strstr(DisableIntrinsic, vmIntrinsics::name_at(id)) != NULL) || + (method_has_option_value("DisableIntrinsic", disable_intr) + && strstr(disable_intr, vmIntrinsics::name_at(id)) != NULL)) { // disabled by a user request on the command line: // example: -XX:DisableIntrinsic=_hashCode,_getClass return NULL; @@ -515,6 +520,10 @@ if (!UseAESIntrinsics) return NULL; break; + case vmIntrinsics::_multiplyToLen: + if (!UseMultiplyToLenIntrinsic) return NULL; + break; + case vmIntrinsics::_cipherBlockChaining_encryptAESCrypt: case vmIntrinsics::_cipherBlockChaining_decryptAESCrypt: if (!UseAESIntrinsics) return NULL; @@ -912,6 +921,9 @@ case vmIntrinsics::_digestBase_implCompressMB: return inline_digestBase_implCompressMB(predicate); + case vmIntrinsics::_multiplyToLen: + return inline_multiplyToLen(); + case vmIntrinsics::_encodeISOArray: return inline_encodeISOArray(); @@ -2650,7 +2662,8 @@ if (need_mem_bar) insert_mem_bar(Op_MemBarCPUOrder); if (!is_store) { - Node* p = make_load(control(), adr, value_type, type, adr_type, MemNode::unordered, is_volatile); + MemNode::MemOrd mo = is_volatile ? MemNode::acquire : MemNode::unordered; + Node* p = make_load(control(), adr, value_type, type, adr_type, mo, is_volatile); // load value switch (type) { case T_BOOLEAN: @@ -5734,6 +5747,108 @@ return true; } +//-------------inline_multiplyToLen----------------------------------- +bool LibraryCallKit::inline_multiplyToLen() { + assert(UseMultiplyToLenIntrinsic, "not implementated on this platform"); + + address stubAddr = StubRoutines::multiplyToLen(); + if (stubAddr == NULL) { + return false; // Intrinsic's stub is not implemented on this platform + } + const char* stubName = "multiplyToLen"; + + assert(callee()->signature()->size() == 5, "multiplyToLen has 5 parameters"); + + Node* x = argument(1); + Node* xlen = argument(2); + Node* y = argument(3); + Node* ylen = argument(4); + Node* z = argument(5); + + const Type* x_type = x->Value(&_gvn); + const Type* y_type = y->Value(&_gvn); + const TypeAryPtr* top_x = x_type->isa_aryptr(); + const TypeAryPtr* top_y = y_type->isa_aryptr(); + if (top_x == NULL || top_x->klass() == NULL || + top_y == NULL || top_y->klass() == NULL) { + // failed array check + return false; + } + + BasicType x_elem = x_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type(); + BasicType y_elem = y_type->isa_aryptr()->klass()->as_array_klass()->element_type()->basic_type(); + if (x_elem != T_INT || y_elem != T_INT) { + return false; + } + + // Set the original stack and the reexecute bit for the interpreter to reexecute + // the bytecode that invokes BigInteger.multiplyToLen() if deoptimization happens + // on the return from z array allocation in runtime. + { PreserveReexecuteState preexecs(this); + jvms()->set_should_reexecute(true); + + Node* x_start = array_element_address(x, intcon(0), x_elem); + Node* y_start = array_element_address(y, intcon(0), y_elem); + // 'x_start' points to x array + scaled xlen + // 'y_start' points to y array + scaled ylen + + // Allocate the result array + Node* zlen = _gvn.transform(new(C) AddINode(xlen, ylen)); + ciKlass* klass = ciTypeArrayKlass::make(T_INT); + Node* klass_node = makecon(TypeKlassPtr::make(klass)); + + IdealKit ideal(this); + +#define __ ideal. + Node* one = __ ConI(1); + Node* zero = __ ConI(0); + IdealVariable need_alloc(ideal), z_alloc(ideal); __ declarations_done(); + __ set(need_alloc, zero); + __ set(z_alloc, z); + __ if_then(z, BoolTest::eq, null()); { + __ increment (need_alloc, one); + } __ else_(); { + // Update graphKit memory and control from IdealKit. + sync_kit(ideal); + Node* zlen_arg = load_array_length(z); + // Update IdealKit memory and control from graphKit. + __ sync_kit(this); + __ if_then(zlen_arg, BoolTest::lt, zlen); { + __ increment (need_alloc, one); + } __ end_if(); + } __ end_if(); + + __ if_then(__ value(need_alloc), BoolTest::ne, zero); { + // Update graphKit memory and control from IdealKit. + sync_kit(ideal); + Node * narr = new_array(klass_node, zlen, 1); + // Update IdealKit memory and control from graphKit. + __ sync_kit(this); + __ set(z_alloc, narr); + } __ end_if(); + + sync_kit(ideal); + z = __ value(z_alloc); + // Can't use TypeAryPtr::INTS which uses Bottom offset. + _gvn.set_type(z, TypeOopPtr::make_from_klass(klass)); + // Final sync IdealKit and GraphKit. + final_sync(ideal); +#undef __ + + Node* z_start = array_element_address(z, intcon(0), T_INT); + + Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, + OptoRuntime::multiplyToLen_Type(), + stubAddr, stubName, TypePtr::BOTTOM, + x_start, xlen, y_start, ylen, z_start, zlen); + } // original reexecute is set back here + + C->set_has_split_ifs(true); // Has chance for split-if optimization + set_result(z); + return true; +} + + /** * Calculate CRC32 for byte. * int java.util.zip.CRC32.update(int crc, int b) @@ -5912,8 +6027,19 @@ type = Type::get_const_basic_type(bt); } + if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_vol) { + insert_mem_bar(Op_MemBarVolatile); // StoreLoad barrier + } // Build the load. - Node* loadedField = make_load(NULL, adr, type, bt, adr_type, MemNode::unordered, is_vol); + MemNode::MemOrd mo = is_vol ? MemNode::acquire : MemNode::unordered; + Node* loadedField = make_load(NULL, adr, type, bt, adr_type, mo, is_vol); + // If reference is volatile, prevent following memory ops from + // floating up past the volatile read. Also prevents commoning + // another volatile read. + if (is_vol) { + // Memory barrier includes bogus read of value to force load BEFORE membar + insert_mem_bar(Op_MemBarAcquire, loadedField); + } return loadedField; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/machnode.cpp --- a/src/share/vm/opto/machnode.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/machnode.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -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 @@ -639,7 +639,6 @@ } #endif - bool MachCallNode::return_value_is_used() const { if (tf()->range()->cnt() == TypeFunc::Parms) { // void return @@ -657,6 +656,14 @@ return false; } +// Similar to cousin class CallNode::returns_pointer +// Because this is used in deoptimization, we want the type info, not the data +// flow info; the interpreter will "use" things that are dead to the optimizer. +bool MachCallNode::returns_pointer() const { + const TypeTuple *r = tf()->range(); + return (r->cnt() > TypeFunc::Parms && + r->field_at(TypeFunc::Parms)->isa_ptr()); +} //------------------------------Registers-------------------------------------- const RegMask &MachCallNode::in_RegMask(uint idx) const { diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/machnode.hpp --- a/src/share/vm/opto/machnode.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/machnode.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -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 @@ -784,6 +784,10 @@ bool returns_long() const { return tf()->return_type() == T_LONG; } bool return_value_is_used() const; + + // Similar to cousin class CallNode::returns_pointer + bool returns_pointer() const; + #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/macro.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -699,6 +699,7 @@ ciType* elem_type; Node* res = alloc->result_cast(); + assert(res == NULL || res->is_CheckCastPP(), "unexpected AllocateNode result"); const TypeOopPtr* res_type = NULL; if (res != NULL) { // Could be NULL when there are no users res_type = _igvn.type(res)->isa_oopptr(); @@ -1031,6 +1032,8 @@ return false; } + assert(boxing->result_cast() == NULL, "unexpected boxing node result"); + extract_call_projections(boxing); const TypeTuple* r = boxing->tf()->range(); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/node.cpp --- a/src/share/vm/opto/node.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/node.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -1093,6 +1093,9 @@ if( this->is_Store() ) { // Condition for back-to-back stores folding. return n->Opcode() == op && n->in(MemNode::Memory) == this; + } else if (this->is_Load()) { + // Condition for removing an unused LoadNode from the MemBarAcquire precedence input + return n->Opcode() == Op_MemBarAcquire; } else if( op == Op_AddL ) { // Condition for convL2I(addL(x,y)) ==> addI(convL2I(x),convL2I(y)) return n->Opcode() == Op_ConvL2I && n->in(1) == this; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/output.cpp --- a/src/share/vm/opto/output.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/output.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2013, 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 @@ -856,8 +856,7 @@ } // Check if a call returns an object. - if (mcall->return_value_is_used() && - mcall->tf()->range()->field_at(TypeFunc::Parms)->isa_ptr()) { + if (mcall->returns_pointer()) { return_oop = true; } safepoint_pc_offset += mcall->ret_addr_offset(); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/parse.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -142,7 +142,7 @@ void print_value_on(outputStream* st) const PRODUCT_RETURN; - bool _forced_inline; // Inlining was forced by CompilerOracle or ciReplay + bool _forced_inline; // Inlining was forced by CompilerOracle, ciReplay or annotation bool forced_inline() const { return _forced_inline; } // Count number of nodes in this subtree int count() const; @@ -551,8 +551,9 @@ float dynamic_branch_prediction(float &cnt); float branch_prediction(float &cnt, BoolTest::mask btest, int target_bci); - bool seems_never_taken(float prob); - bool seems_stable_comparison(BoolTest::mask btest, Node* c); + bool seems_never_taken(float prob) const; + bool path_is_suitable_for_uncommon_trap(float prob) const; + bool seems_stable_comparison() const; void do_ifnull(BoolTest::mask btest, Node* c); void do_if(BoolTest::mask btest, Node* c); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/parse2.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -884,7 +884,7 @@ // some branches (e.g., _213_javac.Assembler.eliminate) validly produce // very small but nonzero probabilities, which if confused with zero // counts would keep the program recompiling indefinitely. -bool Parse::seems_never_taken(float prob) { +bool Parse::seems_never_taken(float prob) const { return prob < PROB_MIN; } @@ -895,53 +895,12 @@ // if a path is never taken, its controlling comparison is // already acting in a stable fashion. If the comparison // seems stable, we will put an expensive uncommon trap -// on the untaken path. To be conservative, and to allow -// partially executed counted loops to be compiled fully, -// we will plant uncommon traps only after pointer comparisons. -bool Parse::seems_stable_comparison(BoolTest::mask btest, Node* cmp) { - for (int depth = 4; depth > 0; depth--) { - // The following switch can find CmpP here over half the time for - // dynamic language code rich with type tests. - // Code using counted loops or array manipulations (typical - // of benchmarks) will have many (>80%) CmpI instructions. - switch (cmp->Opcode()) { - case Op_CmpP: - // A never-taken null check looks like CmpP/BoolTest::eq. - // These certainly should be closed off as uncommon traps. - if (btest == BoolTest::eq) - return true; - // A never-failed type check looks like CmpP/BoolTest::ne. - // Let's put traps on those, too, so that we don't have to compile - // unused paths with indeterminate dynamic type information. - if (ProfileDynamicTypes) - return true; - return false; - - case Op_CmpI: - // A small minority (< 10%) of CmpP are masked as CmpI, - // as if by boolean conversion ((p == q? 1: 0) != 0). - // Detect that here, even if it hasn't optimized away yet. - // Specifically, this covers the 'instanceof' operator. - if (btest == BoolTest::ne || btest == BoolTest::eq) { - if (_gvn.type(cmp->in(2))->singleton() && - cmp->in(1)->is_Phi()) { - PhiNode* phi = cmp->in(1)->as_Phi(); - int true_path = phi->is_diamond_phi(); - if (true_path > 0 && - _gvn.type(phi->in(1))->singleton() && - _gvn.type(phi->in(2))->singleton()) { - // phi->region->if_proj->ifnode->bool->cmp - BoolNode* bol = phi->in(0)->in(1)->in(0)->in(1)->as_Bool(); - btest = bol->_test._test; - cmp = bol->in(1); - continue; - } - } - } - return false; - } +// on the untaken path. +bool Parse::seems_stable_comparison() const { + if (C->too_many_traps(method(), bci(), Deoptimization::Reason_unstable_if)) { + return false; } - return false; + return true; } //-------------------------------repush_if_args-------------------------------- @@ -1166,6 +1125,14 @@ } } +bool Parse::path_is_suitable_for_uncommon_trap(float prob) const { + // Don't want to speculate on uncommon traps when running with -Xcomp + if (!UseInterpreter) { + return false; + } + return (seems_never_taken(prob) && seems_stable_comparison()); +} + //----------------------------adjust_map_after_if------------------------------ // Adjust the JVM state to reflect the result of taking this path. // Basically, it means inspecting the CmpNode controlling this @@ -1179,33 +1146,9 @@ bool is_fallthrough = (path == successor_for_bci(iter().next_bci())); - if (seems_never_taken(prob) && seems_stable_comparison(btest, c)) { - // If this might possibly turn into an implicit null check, - // and the null has never yet been seen, we need to generate - // an uncommon trap, so as to recompile instead of suffering - // with very slow branches. (We'll get the slow branches if - // the program ever changes phase and starts seeing nulls here.) - // - // We do not inspect for a null constant, since a node may - // optimize to 'null' later on. - // - // Null checks, and other tests which expect inequality, - // show btest == BoolTest::eq along the non-taken branch. - // On the other hand, type tests, must-be-null tests, - // and other tests which expect pointer equality, - // show btest == BoolTest::ne along the non-taken branch. - // We prune both types of branches if they look unused. + if (path_is_suitable_for_uncommon_trap(prob)) { repush_if_args(); - // We need to mark this branch as taken so that if we recompile we will - // see that it is possible. In the tiered system the interpreter doesn't - // do profiling and by the time we get to the lower tier from the interpreter - // the path may be cold again. Make sure it doesn't look untaken - if (is_fallthrough) { - profile_not_taken_branch(!ProfileInterpreter); - } else { - profile_taken_branch(iter().get_dest(), !ProfileInterpreter); - } - uncommon_trap(Deoptimization::Reason_unreached, + uncommon_trap(Deoptimization::Reason_unstable_if, Deoptimization::Action_reinterpret, NULL, (is_fallthrough ? "taken always" : "taken never")); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/replacednodes.cpp --- a/src/share/vm/opto/replacednodes.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/replacednodes.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -185,11 +185,11 @@ void ReplacedNodes::dump(outputStream *st) const { if (!is_empty()) { - tty->print("replaced nodes: "); + st->print("replaced nodes: "); for (int i = 0; i < _replaced_nodes->length(); i++) { - tty->print("%d->%d", _replaced_nodes->at(i).initial()->_idx, _replaced_nodes->at(i).improved()->_idx); + st->print("%d->%d", _replaced_nodes->at(i).initial()->_idx, _replaced_nodes->at(i).improved()->_idx); if (i < _replaced_nodes->length()-1) { - tty->print(","); + st->print(","); } } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/runtime.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -942,6 +942,30 @@ return TypeFunc::make(domain, range); } +const TypeFunc* OptoRuntime::multiplyToLen_Type() { + // create input type (domain) + int num_args = 6; + int argcnt = num_args; + const Type** fields = TypeTuple::fields(argcnt); + int argp = TypeFunc::Parms; + fields[argp++] = TypePtr::NOTNULL; // x + fields[argp++] = TypeInt::INT; // xlen + fields[argp++] = TypePtr::NOTNULL; // y + fields[argp++] = TypeInt::INT; // ylen + fields[argp++] = TypePtr::NOTNULL; // z + fields[argp++] = TypeInt::INT; // zlen + assert(argp == TypeFunc::Parms+argcnt, "correct decoding"); + const TypeTuple* domain = TypeTuple::make(TypeFunc::Parms+argcnt, fields); + + // no result type needed + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms+0] = NULL; + const TypeTuple* range = TypeTuple::make(TypeFunc::Parms, fields); + return TypeFunc::make(domain, range); +} + + + //------------- Interpreter state access for on stack replacement const TypeFunc* OptoRuntime::osr_end_Type() { // create input type (domain) diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/opto/runtime.hpp --- a/src/share/vm/opto/runtime.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/opto/runtime.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -303,6 +303,8 @@ static const TypeFunc* sha_implCompress_Type(); static const TypeFunc* digestBase_implCompressMB_Type(); + static const TypeFunc* multiplyToLen_Type(); + static const TypeFunc* updateBytesCRC32_Type(); // leaf on stack replacement interpreter accessor types diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/prims/unsafe.cpp --- a/src/share/vm/prims/unsafe.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/prims/unsafe.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -953,6 +953,14 @@ } UNSAFE_END +static jobject get_class_loader(JNIEnv* env, jclass cls) { + if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(cls))) { + return NULL; + } + Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); + oop loader = k->class_loader(); + return JNIHandles::make_local(env, loader); +} UNSAFE_ENTRY(jclass, Unsafe_DefineClass0(JNIEnv *env, jobject unsafe, jstring name, jbyteArray data, int offset, int length)) UnsafeWrapper("Unsafe_DefineClass"); @@ -961,7 +969,7 @@ int depthFromDefineClass0 = 1; jclass caller = JVM_GetCallerClass(env, depthFromDefineClass0); - jobject loader = (caller == NULL) ? NULL : JVM_GetClassLoader(env, caller); + jobject loader = (caller == NULL) ? NULL : get_class_loader(env, caller); jobject pd = (caller == NULL) ? NULL : JVM_GetProtectionDomain(env, caller); return Unsafe_DefineClass_impl(env, name, data, offset, length, loader, pd); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/prims/whitebox.cpp --- a/src/share/vm/prims/whitebox.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/prims/whitebox.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -526,8 +526,8 @@ #ifdef TIERED mcs->set_rate(0.0F); - mh->set_prev_event_count(0, THREAD); - mh->set_prev_time(0, THREAD); + mh->set_prev_event_count(0); + mh->set_prev_time(0); #endif } WB_END @@ -695,6 +695,12 @@ WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true); Universe::heap()->collect(GCCause::_last_ditch_collection); +#if INCLUDE_ALL_GCS + if (UseG1GC) { + // Needs to be cleared explicitly for G1 + Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(false); + } +#endif // INCLUDE_ALL_GCS WB_END WB_ENTRY(void, WB_YoungGC(JNIEnv* env, jobject o)) @@ -838,6 +844,36 @@ return ret; } +void WhiteBox::register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread, JNINativeMethod* method_array, int method_count) { + ResourceMark rm; + ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI + + // one by one registration natives for exception catching + jclass no_such_method_error_klass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string()); + CHECK_JNI_EXCEPTION(env); + for (int i = 0, n = method_count; i < n; ++i) { + // Skip dummy entries + if (method_array[i].fnPtr == NULL) continue; + if (env->RegisterNatives(wbclass, &method_array[i], 1) != 0) { + jthrowable throwable_obj = env->ExceptionOccurred(); + if (throwable_obj != NULL) { + env->ExceptionClear(); + if (env->IsInstanceOf(throwable_obj, no_such_method_error_klass)) { + // NoSuchMethodError is thrown when a method can't be found or a method is not native. + // Ignoring the exception since it is not preventing use of other WhiteBox methods. + tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s", + method_array[i].name, method_array[i].signature); + } + } else { + // Registration failed unexpectedly. + tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered", + method_array[i].name, method_array[i].signature); + env->UnregisterNatives(wbclass); + break; + } + } + } +} #define CC (char*) @@ -940,35 +976,9 @@ instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass()); Handle loader(ikh->class_loader()); if (loader.is_null()) { - ResourceMark rm; - ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI - bool result = true; - // one by one registration natives for exception catching - jclass exceptionKlass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string()); - CHECK_JNI_EXCEPTION(env); - for (int i = 0, n = sizeof(methods) / sizeof(methods[0]); i < n; ++i) { - if (env->RegisterNatives(wbclass, methods + i, 1) != 0) { - result = false; - jthrowable throwable_obj = env->ExceptionOccurred(); - if (throwable_obj != NULL) { - env->ExceptionClear(); - if (env->IsInstanceOf(throwable_obj, exceptionKlass)) { - // j.l.NoSuchMethodError is thrown when a method can't be found or a method is not native - // ignoring the exception - tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s", methods[i].name, methods[i].signature); - } - } else { - // register is failed w/o exception or w/ unexpected exception - tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered", methods[i].name, methods[i].signature); - env->UnregisterNatives(wbclass); - break; - } - } - } - - if (result) { - WhiteBox::set_used(); - } + WhiteBox::register_methods(env, wbclass, thread, methods, sizeof(methods) / sizeof(methods[0])); + WhiteBox::register_extended(env, wbclass, thread); + WhiteBox::set_used(); } } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/prims/whitebox.hpp --- a/src/share/vm/prims/whitebox.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/prims/whitebox.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -29,6 +29,8 @@ #include "memory/allocation.hpp" #include "oops/oopsHierarchy.hpp" +#include "oops/symbol.hpp" +#include "runtime/interfaceSupport.hpp" // Entry macro to transition from JNI to VM state. @@ -64,6 +66,9 @@ static bool lookup_bool(const char* field_name, oop object); static int array_bytes_to_length(size_t bytes); + static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread, + JNINativeMethod* method_array, int method_count); + static void register_extended(JNIEnv* env, jclass wbclass, JavaThread* thread); }; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/prims/whitebox_ext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/prims/whitebox_ext.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2012, 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. + * + */ + +#include "precompiled.hpp" + +#include "prims/whitebox.hpp" + +void WhiteBox::register_extended(JNIEnv* env, jclass wbclass, JavaThread* thread) { } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/advancedThresholdPolicy.cpp --- a/src/share/vm/runtime/advancedThresholdPolicy.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/advancedThresholdPolicy.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -75,11 +75,14 @@ // update_rate() is called from select_task() while holding a compile queue lock. void AdvancedThresholdPolicy::update_rate(jlong t, Method* m) { - JavaThread* THREAD = JavaThread::current(); + // Skip update if counters are absent. + // Can't allocate them since we are holding compile queue lock. + if (m->method_counters() == NULL) return; + if (is_old(m)) { // We don't remove old methods from the queue, // so we can just zero the rate. - m->set_rate(0, THREAD); + m->set_rate(0); return; } @@ -95,14 +98,15 @@ if (delta_s >= TieredRateUpdateMinTime) { // And we must've taken the previous point at least 1ms before. if (delta_t >= TieredRateUpdateMinTime && delta_e > 0) { - m->set_prev_time(t, THREAD); - m->set_prev_event_count(event_count, THREAD); - m->set_rate((float)delta_e / (float)delta_t, THREAD); // Rate is events per millisecond - } else + m->set_prev_time(t); + m->set_prev_event_count(event_count); + m->set_rate((float)delta_e / (float)delta_t); // Rate is events per millisecond + } else { if (delta_t > TieredRateUpdateMaxTime && delta_e == 0) { // If nothing happened for 25ms, zero the rate. Don't modify prev values. - m->set_rate(0, THREAD); + m->set_rate(0); } + } } } @@ -164,7 +168,6 @@ for (CompileTask* task = compile_queue->first(); task != NULL;) { CompileTask* next_task = task->next(); Method* method = task->method(); - MethodData* mdo = method->method_data(); update_rate(t, method); if (max_task == NULL) { max_task = task; @@ -175,8 +178,7 @@ if (PrintTieredEvents) { print_event(REMOVE_FROM_QUEUE, method, method, task->osr_bci(), (CompLevel)task->comp_level()); } - CompileTaskWrapper ctw(task); // Frees the task - compile_queue->remove(task); + compile_queue->remove_and_mark_stale(task); method->clear_queued_for_compilation(); task = next_task; continue; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/arguments.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -601,7 +601,9 @@ static void fix_appclasspath(); // Operation modi - static Mode mode() { return _mode; } + static Mode mode() { return _mode; } + static bool is_interpreter_only() { return mode() == _int; } + // Utility: copies src into buf, replacing "%%" with "%" and "%p" with pid. static bool copy_expand_pid(const char* src, size_t srclen, char* buf, size_t buflen); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/deoptimization.cpp --- a/src/share/vm/runtime/deoptimization.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/deoptimization.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -228,7 +228,8 @@ // It is not guaranteed that we can get such information here only // by analyzing bytecode in deoptimized frames. This is why this flag // is set during method compilation (see Compile::Process_OopMap_Node()). - bool save_oop_result = chunk->at(0)->scope()->return_oop(); + // If the previous frame was popped, we don't have a result. + bool save_oop_result = chunk->at(0)->scope()->return_oop() && !thread->popframe_forcing_deopt_reexecution(); Handle return_value; if (save_oop_result) { // Reallocation may trigger GC. If deoptimization happened on return from @@ -1835,7 +1836,8 @@ "predicate", "loop_limit_check", "speculate_class_check", - "rtm_state_change" + "rtm_state_change", + "unstable_if" }; const char* Deoptimization::_trap_action_name[Action_LIMIT] = { // Note: Keep this in sync. with enum DeoptAction. diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/deoptimization.hpp --- a/src/share/vm/runtime/deoptimization.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/deoptimization.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -60,6 +60,7 @@ Reason_predicate, // compiler generated predicate failed Reason_loop_limit_check, // compiler generated loop limits check failed Reason_speculate_class_check, // saw unexpected object class from type speculation + Reason_unstable_if, // a branch predicted always false was taken Reason_rtm_state_change, // rtm state change detected Reason_LIMIT, // Note: Keep this enum in sync. with _trap_reason_name. @@ -315,6 +316,8 @@ return Reason_null_check; // recorded per BCI as a null check else if (reason == Reason_speculate_class_check) return Reason_class_check; + else if (reason == Reason_unstable_if) + return Reason_intrinsic; else return Reason_none; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/os.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -50,6 +50,7 @@ #include "runtime/thread.inline.hpp" #include "services/attachListener.hpp" #include "services/nmtCommon.hpp" +#include "services/mallocTracker.hpp" #include "services/memTracker.hpp" #include "services/threadService.hpp" #include "utilities/defaultStream.hpp" @@ -570,6 +571,17 @@ NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); +#if INCLUDE_NMT + // NMT can not track malloc allocation size > MAX_MALLOC_SIZE, which is + // (1GB - 1) on 32-bit system. It is not an issue on 64-bit system, where + // MAX_MALLOC_SIZE = ((1 << 62) - 1). + // VM code does not have such large malloc allocation. However, it can come + // Unsafe call. + if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) { + return NULL; + } +#endif + #ifdef ASSERT // checking for the WatcherThread and crash_protection first // since os::malloc can be called when the libjvm.{dll,so} is @@ -640,6 +652,13 @@ } void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCallStack& stack) { +#if INCLUDE_NMT + // See comments in os::malloc() above + if (MemTracker::tracking_level() >= NMT_summary && size > MAX_MALLOC_SIZE) { + return NULL; + } +#endif + #ifndef ASSERT NOT_PRODUCT(inc_stat_counter(&num_mallocs, 1)); NOT_PRODUCT(inc_stat_counter(&alloc_bytes, size)); diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/serviceThread.cpp --- a/src/share/vm/runtime/serviceThread.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/serviceThread.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -28,6 +28,7 @@ #include "runtime/serviceThread.hpp" #include "runtime/mutexLocker.hpp" #include "prims/jvmtiImpl.hpp" +#include "services/allocationContextService.hpp" #include "services/gcNotifier.hpp" #include "services/diagnosticArgument.hpp" #include "services/diagnosticFramework.hpp" @@ -86,6 +87,7 @@ bool has_jvmti_events = false; bool has_gc_notification_event = false; bool has_dcmd_notification_event = false; + bool acs_notify = false; JvmtiDeferredEvent jvmti_event; { // Need state transition ThreadBlockInVM so that this thread @@ -102,7 +104,8 @@ while (!(sensors_changed = LowMemoryDetector::has_pending_requests()) && !(has_jvmti_events = JvmtiDeferredEventQueue::has_events()) && !(has_gc_notification_event = GCNotifier::has_event()) && - !(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification())) { + !(has_dcmd_notification_event = DCmdFactory::has_pending_jmx_notification()) && + !(acs_notify = AllocationContextService::should_notify())) { // wait until one of the sensors has pending requests, or there is a // pending JVMTI event or JMX GC notification to post Service_lock->wait(Mutex::_no_safepoint_check_flag); @@ -128,6 +131,10 @@ if(has_dcmd_notification_event) { DCmdFactory::send_notification(CHECK); } + + if (acs_notify) { + AllocationContextService::notify(CHECK); + } } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/stubRoutines.cpp --- a/src/share/vm/runtime/stubRoutines.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/stubRoutines.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -135,6 +135,8 @@ address StubRoutines::_updateBytesCRC32 = NULL; address StubRoutines::_crc_table_adr = NULL; +address StubRoutines::_multiplyToLen = NULL; + double (* StubRoutines::_intrinsic_log )(double) = NULL; double (* StubRoutines::_intrinsic_log10 )(double) = NULL; double (* StubRoutines::_intrinsic_exp )(double) = NULL; diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/stubRoutines.hpp --- a/src/share/vm/runtime/stubRoutines.hpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/stubRoutines.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -217,6 +217,8 @@ static address _updateBytesCRC32; static address _crc_table_adr; + static address _multiplyToLen; + // These are versions of the java.lang.Math methods which perform // the same operations as the intrinsic version. They are used for // constant folding in the compiler to ensure equivalence. If the @@ -373,6 +375,8 @@ static address updateBytesCRC32() { return _updateBytesCRC32; } static address crc_table_addr() { return _crc_table_adr; } + static address multiplyToLen() {return _multiplyToLen; } + static address select_fill_function(BasicType t, bool aligned, const char* &name); static address zero_aligned_words() { return _zero_aligned_words; } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/thread.cpp --- a/src/share/vm/runtime/thread.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/thread.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -940,7 +940,7 @@ cur != VMOperationRequest_lock && cur != VMOperationQueue_lock) || cur->rank() == Mutex::special) { - warning("Thread holding lock at safepoint that vm can block on: %s", cur->name()); + fatal(err_msg("Thread holding lock at safepoint that vm can block on: %s", cur->name())); } } } diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/runtime/vmStructs.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -814,6 +814,7 @@ static_field(StubRoutines, _cipherBlockChaining_decryptAESCrypt, address) \ static_field(StubRoutines, _updateBytesCRC32, address) \ static_field(StubRoutines, _crc_table_adr, address) \ + static_field(StubRoutines, _multiplyToLen, address) \ \ /*****************/ \ /* SharedRuntime */ \ @@ -2495,6 +2496,7 @@ declare_constant(Deoptimization::Reason_age) \ declare_constant(Deoptimization::Reason_predicate) \ declare_constant(Deoptimization::Reason_loop_limit_check) \ + declare_constant(Deoptimization::Reason_unstable_if) \ declare_constant(Deoptimization::Reason_LIMIT) \ declare_constant(Deoptimization::Reason_RECORDED_LIMIT) \ \ diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/services/allocationContextService.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/allocationContextService.hpp Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,39 @@ +/* + * 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. + * + */ + +#ifndef SHARE_VM_SERVICES_ALLOCATION_CONTEXT_SERVICE_HPP +#define SHARE_VM_SERVICES_ALLOCATION_CONTEXT_SERVICE_HPP + +#include "utilities/exceptions.hpp" + +class AllocationContextService: public AllStatic { +public: + static inline bool should_notify(); + static inline void notify(TRAPS); +}; + +bool AllocationContextService::should_notify() { return false; } +void AllocationContextService::notify(TRAPS) { } + +#endif // SHARE_VM_SERVICES_ALLOCATION_CONTEXT_SERVICE_HPP diff -r 8cb56c8cb30d -r f0bedf980c65 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Mon Sep 15 16:39:00 2014 -0400 +++ b/src/share/vm/services/attachListener.cpp Tue Sep 16 13:55:38 2014 -0700 @@ -162,10 +162,7 @@ java_lang_Throwable::print(PENDING_EXCEPTION, out); out->cr(); CLEAR_PENDING_EXCEPTION; - // The exception has been printed on the output stream - // If the JVM returns JNI_ERR, the attachAPI throws a generic I/O - // exception and the content of the output stream is not processed. - // By returning JNI_OK, the exception will be displayed on the client side + return JNI_ERR; } return JNI_OK; } diff -r 8cb56c8cb30d -r f0bedf980c65 test/TEST.groups --- a/test/TEST.groups Mon Sep 15 16:39:00 2014 -0400 +++ b/test/TEST.groups Tue Sep 16 13:55:38 2014 -0700 @@ -82,6 +82,7 @@ runtime/NMT/MallocSiteHashOverflow.java \ runtime/NMT/MallocStressTest.java \ runtime/NMT/MallocTestType.java \ + runtime/NMT/MallocTrackingVerify.java \ runtime/NMT/ReleaseCommittedMemory.java \ runtime/NMT/ReleaseNoCommit.java \ runtime/NMT/ShutdownTwice.java \ @@ -89,6 +90,7 @@ runtime/NMT/SummarySanityCheck.java \ runtime/NMT/ThreadedMallocTestType.java \ runtime/NMT/ThreadedVirtualAllocTestType.java \ + runtime/NMT/UnsafeMallocLimit.java \ runtime/NMT/VirtualAllocCommitUncommitRecommit.java \ runtime/NMT/VirtualAllocTestType.java \ runtime/RedefineObject/TestRedefineObject.java \ diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/exceptions/TestRecursiveReplacedException.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/exceptions/TestRecursiveReplacedException.java Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,44 @@ +/* + * 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 8054224 + * @summary Recursive method compiled by C1 is unable to catch StackOverflowError + * @run main/othervm -Xcomp -XX:CompileOnly=Test.run -XX:+TieredCompilation -XX:TieredStopAtLevel=2 -Xss256K TestRecursiveReplacedException + * + */ + +public class TestRecursiveReplacedException { + + public static void main(String args[]) { + new TestRecursiveReplacedException().run(); + } + + public void run() { + try { + run(); + } catch (Throwable t) { + } + } +} diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java --- a/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/AddExactIntTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build AddExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class AddExactIntTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java --- a/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/AddExactLongTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build AddExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics AddExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class AddExactLongTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java --- a/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/DecrementExactIntTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build DecrementExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics DecrementExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class DecrementExactIntTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java --- a/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/DecrementExactLongTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build DecrementExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics DecrementExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class DecrementExactLongTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java --- a/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/IncrementExactIntTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build IncrementExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics IncrementExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class IncrementExactIntTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java --- a/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/IncrementExactLongTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build IncrementExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics IncrementExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class IncrementExactLongTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java --- a/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/IntrinsicBase.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -22,6 +22,7 @@ */ import com.oracle.java.testlibrary.Platform; +import intrinsics.Verifier; import java.io.FileOutputStream; import java.lang.reflect.Executable; @@ -79,10 +80,10 @@ System.out.println("Expected intrinsic count is " + expectedIntrinsicCount + " name " + getIntrinsicId()); - final FileOutputStream out = new FileOutputStream(getVMOption("LogFile") + ".verify.properties"); + final FileOutputStream out = new FileOutputStream(getVMOption("LogFile") + Verifier.PROPERTY_FILE_SUFFIX); Properties expectedProps = new Properties(); - expectedProps.setProperty("intrinsic.name", getIntrinsicId()); - expectedProps.setProperty("intrinsic.expectedCount", String.valueOf(expectedIntrinsicCount)); + expectedProps.setProperty(Verifier.INTRINSIC_NAME_PROPERTY, getIntrinsicId()); + expectedProps.setProperty(Verifier.INTRINSIC_EXPECTED_COUNT_PROPERTY, String.valueOf(expectedIntrinsicCount)); expectedProps.store(out, null); out.close(); diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java --- a/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/MultiplyExactIntTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build MultiplyExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics MultiplyExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class MultiplyExactIntTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java --- a/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/MultiplyExactLongTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build MultiplyExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics MultiplyExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class MultiplyExactLongTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java --- a/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/NegateExactIntTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build NegateExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics NegateExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class NegateExactIntTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java --- a/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/NegateExactLongTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build NegateExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics NegateExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class NegateExactLongTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java --- a/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/SubtractExactIntTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build SubtractExactIntTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics SubtractExactIntTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java --- a/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/compiler/intrinsics/mathexact/sanity/SubtractExactLongTest.java Tue Sep 16 13:55:38 2014 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -24,6 +24,7 @@ /* * @test * @library /testlibrary /testlibrary/whitebox /compiler/whitebox + * /compiler/testlibrary * @build SubtractExactLongTest * @run main ClassFileInstaller sun.hotspot.WhiteBox * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions @@ -34,7 +35,7 @@ * -XX:+IgnoreUnrecognizedVMOptions -XX:+WhiteBoxAPI -XX:+LogCompilation * -XX:CompileCommand=compileonly,MathIntrinsic*::execMathMethod * -XX:LogFile=hs.log -XX:+UseMathExactIntrinsics SubtractExactLongTest - * @run main Verifier hs_neg.log hs.log + * @run main intrinsics.Verifier hs_neg.log hs.log */ public class SubtractExactLongTest { diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/intrinsics/mathexact/sanity/Verifier.java --- a/test/compiler/intrinsics/mathexact/sanity/Verifier.java Mon Sep 15 16:39:00 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.io.BufferedReader; -import java.io.FileReader; -import java.util.Properties; - -public class Verifier { - - public static void main(String[] args) throws Exception { - if (args.length == 0) - throw new RuntimeException("Test bug, nothing to verify"); - for (String hsLogFile : args) { - verify(hsLogFile); - } - } - - private static void verify(String hsLogFile) throws Exception { - System.out.println("Verifying " + hsLogFile); - - final Properties expectedProperties = new Properties(); - final FileReader reader = new FileReader(hsLogFile + ".verify.properties"); - expectedProperties.load(reader); - reader.close(); - - int fullMatchCnt = 0; - int suspectCnt = 0; - final String intrinsicId = expectedProperties.getProperty("intrinsic.name"); - final String prefix = " is compiled + for (int i = 0; i < 100000; ++i) { + TestMemBarAcquire p = new TestMemBarAcquire(new Object()); + } + } +} + diff -r 8cb56c8cb30d -r f0bedf980c65 test/compiler/testlibrary/intrinsics/Verifier.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/testlibrary/intrinsics/Verifier.java Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2013, 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. + */ +package intrinsics; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.util.Properties; + +public class Verifier { + enum VerificationStrategy { + VERIFY_STRONG_EQUALITY { + @Override + void verify(Properties expectedProperties, int fullMatchCnt, + int suspectCnt) { + int expectedCount = Integer.parseInt( + expectedProperties.getProperty( + Verifier.INTRINSIC_EXPECTED_COUNT_PROPERTY)); + String intrinsicID = expectedProperties.getProperty( + Verifier.INTRINSIC_NAME_PROPERTY); + + System.out.println("Intrinsic " + intrinsicID + + " verification, expected: " + expectedCount + + ", matched: " + fullMatchCnt + + ", suspected: " + suspectCnt); + if (expectedCount != fullMatchCnt) { + throw new RuntimeException( + "Unexpected count of intrinsic " + + intrinsicID + + " expected:" + expectedCount + + ", matched: " + fullMatchCnt + + ", suspected: " + suspectCnt); + } + } + }, + + VERIFY_INTRINSIC_USAGE { + @Override + void verify(Properties expectedProperties, int fullMatchCnt, + int suspectCnt) { + boolean isExpected = Boolean.parseBoolean( + expectedProperties.getProperty( + Verifier.INTRINSIC_IS_EXPECTED_PROPERTY)); + String intrinsicID = expectedProperties.getProperty( + Verifier.INTRINSIC_NAME_PROPERTY); + + System.out.println("Intrinsic " + intrinsicID + + " verification, is expected: " + isExpected + + ", matched: " + fullMatchCnt + + ", suspected: " + suspectCnt); + if ((fullMatchCnt == 0 && isExpected) + || (fullMatchCnt > 0 && !isExpected)) { + throw new RuntimeException( + "Unexpected count of intrinsic " + + intrinsicID + + " is expected:" + isExpected + + ", matched: " + fullMatchCnt + + ", suspected: " + suspectCnt); + } + } + }; + + void verify(Properties expectedProperties, int fullMathCnt, + int suspectCnt) { + throw new RuntimeException("Default strategy is not implemented."); + } + } + + public static final String PROPERTY_FILE_SUFFIX = ".verify.properties"; + public static final String INTRINSIC_NAME_PROPERTY = "intrinsic.name"; + public static final String INTRINSIC_IS_EXPECTED_PROPERTY + = "intrinsic.expected"; + public static final String INTRINSIC_EXPECTED_COUNT_PROPERTY + = "intrinsic.expectedCount"; + private static final String DEFAULT_STRATEGY + = VerificationStrategy.VERIFY_STRONG_EQUALITY.name(); + + public static void main(String[] args) throws Exception { + if (args.length == 0) { + throw new RuntimeException("Test bug, nothing to verify"); + } + for (String hsLogFile : args) { + verify(hsLogFile); + } + } + + private static void verify(String hsLogFile) throws Exception { + System.out.println("Verifying " + hsLogFile); + + Properties expectedProperties = new Properties(); + FileReader reader = new FileReader(hsLogFile + + Verifier.PROPERTY_FILE_SUFFIX); + expectedProperties.load(reader); + reader.close(); + + int fullMatchCnt = 0; + int suspectCnt = 0; + String intrinsicId = expectedProperties.getProperty( + Verifier.INTRINSIC_NAME_PROPERTY); + String prefix = " { + boolean isTiered = IntrinsicPredicates.WHITE_BOX.getBooleanVMFlag( + "TieredCompilation"); + long tieredMaxLevel = IntrinsicPredicates.WHITE_BOX.getIntxVMFlag( + "TieredStopAtLevel"); + boolean maxLevelIsReachable = (tieredMaxLevel + == IntrinsicPredicates.TIERED_MAX_LEVEL); + return Platform.isServer() && (!isTiered || maxLevelIsReachable); + }; + + public static final BooleanSupplier SHA1_INSTRUCTION_AVAILABLE + = new CPUSpecificPredicate("sparc.*", new String[] { "sha1" }, + null); + + public static final BooleanSupplier SHA256_INSTRUCTION_AVAILABLE + = new CPUSpecificPredicate("sparc.*", new String[] { "sha256" }, + null); + + public static final BooleanSupplier SHA512_INSTRUCTION_AVAILABLE + = new CPUSpecificPredicate("sparc.*", new String[] { "sha512" }, + null); + + public static final BooleanSupplier ANY_SHA_INSTRUCTION_AVAILABLE + = new OrPredicate(IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE, + new OrPredicate( + IntrinsicPredicates.SHA256_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.SHA512_INSTRUCTION_AVAILABLE)); + + public static final BooleanSupplier SHA1_INTRINSICS_AVAILABLE + = new AndPredicate(new AndPredicate( + IntrinsicPredicates.SHA1_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.COMPILABLE_BY_C2), + IntrinsicPredicates.booleanOptionValue("UseSHA1Intrinsics")); + + public static final BooleanSupplier SHA256_INTRINSICS_AVAILABLE + = new AndPredicate(new AndPredicate( + IntrinsicPredicates.SHA256_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.COMPILABLE_BY_C2), + IntrinsicPredicates.booleanOptionValue("UseSHA256Intrinsics")); + + public static final BooleanSupplier SHA512_INTRINSICS_AVAILABLE + = new AndPredicate(new AndPredicate( + IntrinsicPredicates.SHA512_INSTRUCTION_AVAILABLE, + IntrinsicPredicates.COMPILABLE_BY_C2), + IntrinsicPredicates.booleanOptionValue("UseSHA512Intrinsics")); + + private static BooleanSupplier booleanOptionValue(String option) { + return () -> IntrinsicPredicates.WHITE_BOX.getBooleanVMFlag(option); + } + + private IntrinsicPredicates() { + } +} diff -r 8cb56c8cb30d -r f0bedf980c65 test/gc/g1/TestHumongousShrinkHeap.java --- a/test/gc/g1/TestHumongousShrinkHeap.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/gc/g1/TestHumongousShrinkHeap.java Tue Sep 16 13:55:38 2014 -0700 @@ -26,7 +26,7 @@ * @bug 8036025 8056043 * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects * @library /testlibrary - * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=50 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap + * @run main/othervm -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=12 -XX:+UseG1GC -XX:G1HeapRegionSize=1M -verbose:gc TestHumongousShrinkHeap */ import java.lang.management.ManagementFactory; @@ -41,12 +41,24 @@ public static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; public static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; - private static final ArrayList> garbage = new ArrayList<>(); - private static final int PAGE_SIZE = 1024 * 1024; // 1M - private static final int PAGES_NUM = 5; + private static final List> garbage = new ArrayList(); + private static final int REGION_SIZE = 1024 * 1024; // 1M + private static final int LISTS_COUNT = 10; + private static final int HUMON_SIZE = Math.round(.9f * REGION_SIZE); + private static final long AVAILABLE_MEMORY + = Runtime.getRuntime().freeMemory(); + private static final int HUMON_COUNT + = (int) ((AVAILABLE_MEMORY / HUMON_SIZE) + / LISTS_COUNT); public static void main(String[] args) { + System.out.format("Running with %s max heap size. " + + "Will allocate humongous object of %s size %d times.%n", + MemoryUsagePrinter.humanReadableByteCount(AVAILABLE_MEMORY, false), + MemoryUsagePrinter.humanReadableByteCount(HUMON_SIZE, false), + HUMON_COUNT + ); new TestHumongousShrinkHeap().test(); } @@ -54,8 +66,8 @@ System.gc(); MemoryUsagePrinter.printMemoryUsage("init"); - eat(); - MemoryUsagePrinter.printMemoryUsage("eaten"); + allocate(); + MemoryUsagePrinter.printMemoryUsage("allocated"); MemoryUsage muFull = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); free(); @@ -72,15 +84,12 @@ )); } - private void eat() { - int HumongousObjectSize = Math.round(.9f * PAGE_SIZE); - System.out.println("Will allocate objects of size=" + - MemoryUsagePrinter.humanReadableByteCount(HumongousObjectSize, true)); + private void allocate() { - for (int i = 0; i < PAGES_NUM; i++) { - ArrayList stuff = new ArrayList<>(); - eatList(stuff, 100, HumongousObjectSize); - MemoryUsagePrinter.printMemoryUsage("eat #" + i); + for (int i = 0; i < LISTS_COUNT; i++) { + List stuff = new ArrayList(); + allocateList(stuff, HUMON_COUNT, HUMON_SIZE); + MemoryUsagePrinter.printMemoryUsage("allocate #" + (i+1)); garbage.add(stuff); } } @@ -90,12 +99,12 @@ garbage.subList(0, garbage.size() - 1).clear(); // do not free last one element from last list - ArrayList stuff = garbage.get(garbage.size() - 1); + List stuff = garbage.get(garbage.size() - 1); stuff.subList(0, stuff.size() - 1).clear(); System.gc(); } - private static void eatList(List garbage, int count, int size) { + private static void allocateList(List garbage, int count, int size) { for (int i = 0; i < count; i++) { garbage.add(new byte[size]); } @@ -122,9 +131,9 @@ float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", label, - humanReadableByteCount(memusage.getInit(), true), - humanReadableByteCount(memusage.getUsed(), true), - humanReadableByteCount(memusage.getCommitted(), true), + humanReadableByteCount(memusage.getInit(), false), + humanReadableByteCount(memusage.getUsed(), false), + humanReadableByteCount(memusage.getCommitted(), false), freeratio * 100 ); } diff -r 8cb56c8cb30d -r f0bedf980c65 test/gc/g1/TestShrinkDefragmentedHeap.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gc/g1/TestShrinkDefragmentedHeap.java Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,188 @@ +/* + * 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 TestShrinkDefragmentedHeap + * @bug 8038423 + * @summary Verify that heap shrinks after GC in the presence of fragmentation due to humongous objects + * 1. allocate small objects mixed with humongous ones + * "ssssHssssHssssHssssHssssHssssHssssH" + * 2. release all allocated object except the last humongous one + * "..................................H" + * 3. invoke gc and check that memory returned to the system (amount of committed memory got down) + * + * @library /testlibrary + */ +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryUsage; +import java.util.ArrayList; +import java.util.List; +import sun.management.ManagementFactoryHelper; +import static com.oracle.java.testlibrary.Asserts.*; +import com.oracle.java.testlibrary.ProcessTools; +import com.oracle.java.testlibrary.OutputAnalyzer; + +public class TestShrinkDefragmentedHeap { + // Since we store all the small objects, they become old and old regions are also allocated at the bottom of the heap + // together with humongous regions. So if there are a lot of old regions in the lower part of the heap, + // the humongous regions will be allocated in the upper part of the heap anyway. + // To avoid this the Eden needs to be big enough to fit all the small objects. + private static final int INITIAL_HEAP_SIZE = 200 * 1024 * 1024; + private static final int MINIMAL_YOUNG_SIZE = 190 * 1024 * 1024; + private static final int REGION_SIZE = 1 * 1024 * 1024; + + public static void main(String[] args) throws Exception, Throwable { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder( + "-XX:InitialHeapSize=" + INITIAL_HEAP_SIZE, + "-Xmn" + MINIMAL_YOUNG_SIZE, + "-XX:MinHeapFreeRatio=10", + "-XX:MaxHeapFreeRatio=11", + "-XX:+UseG1GC", + "-XX:G1HeapRegionSize=" + REGION_SIZE, + "-verbose:gc", + GCTest.class.getName() + ); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + output.shouldHaveExitValue(0); + } + + static class GCTest { + + private static final String MIN_FREE_RATIO_FLAG_NAME = "MinHeapFreeRatio"; + private static final String MAX_FREE_RATIO_FLAG_NAME = "MaxHeapFreeRatio"; + private static final String NEW_SIZE_FLAG_NAME = "NewSize"; + + private static final ArrayList> garbage = new ArrayList<>(); + + private static final int SMALL_OBJS_SIZE = 10 * 1024; // 10kB + private static final int SMALL_OBJS_COUNT = MINIMAL_YOUNG_SIZE / (SMALL_OBJS_SIZE-1); + private static final int ALLOCATE_COUNT = 3; + // try to put all humongous object into gap between min young size and initial heap size + // to avoid implicit GCs + private static final int HUMONG_OBJS_SIZE = (int) Math.max( + (INITIAL_HEAP_SIZE - MINIMAL_YOUNG_SIZE) / ALLOCATE_COUNT / 4, + REGION_SIZE * 1.1 + ); + + private static final long initialHeapSize = getHeapMemoryUsage().getUsed(); + + public static void main(String[] args) throws InterruptedException { + new GCTest().test(); + } + + private void test() throws InterruptedException { + MemoryUsagePrinter.printMemoryUsage("init"); + + allocate(); + System.gc(); + MemoryUsage muFull = getHeapMemoryUsage(); + MemoryUsagePrinter.printMemoryUsage("allocated"); + + free(); + //Thread.sleep(1000); // sleep before measures due lags in JMX + MemoryUsage muFree = getHeapMemoryUsage(); + MemoryUsagePrinter.printMemoryUsage("free"); + + assertLessThan(muFree.getCommitted(), muFull.getCommitted(), prepareMessageCommittedIsNotLess() ); + } + + private void allocate() { + System.out.format("Will allocate objects of small size = %s and humongous size = %s", + MemoryUsagePrinter.humanReadableByteCount(SMALL_OBJS_SIZE, false), + MemoryUsagePrinter.humanReadableByteCount(HUMONG_OBJS_SIZE, false) + ); + + for (int i = 0; i < ALLOCATE_COUNT; i++) { + ArrayList stuff = new ArrayList<>(); + allocateList(stuff, SMALL_OBJS_COUNT / ALLOCATE_COUNT, SMALL_OBJS_SIZE); + garbage.add(stuff); + + ArrayList humongousStuff = new ArrayList<>(); + allocateList(humongousStuff, 4, HUMONG_OBJS_SIZE); + garbage.add(humongousStuff); + } + } + + private void free() { + // do not free last one list + garbage.subList(0, garbage.size() - 1).clear(); + + // do not free last one element from last list + ArrayList stuff = garbage.get(garbage.size() - 1); + if (stuff.size() > 1) { + stuff.subList(0, stuff.size() - 1).clear(); + } + System.gc(); + } + + private String prepareMessageCommittedIsNotLess() { + return String.format( + "committed free heap size is not less than committed full heap size, heap hasn't been shrunk?%n" + + "%s = %s%n%s = %s", + MIN_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MIN_FREE_RATIO_FLAG_NAME).getValue(), + MAX_FREE_RATIO_FLAG_NAME, + ManagementFactoryHelper.getDiagnosticMXBean().getVMOption(MAX_FREE_RATIO_FLAG_NAME).getValue() + ); + } + + private static void allocateList(List garbage, int count, int size) { + for (int i = 0; i < count; i++) { + garbage.add(new byte[size]); + } + } + } + + static MemoryUsage getHeapMemoryUsage() { + return ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + } + + /** + * Prints memory usage to standard output + */ + static class MemoryUsagePrinter { + + public static String humanReadableByteCount(long bytes, boolean si) { + int unit = si ? 1000 : 1024; + if (bytes < unit) { + return bytes + " B"; + } + int exp = (int) (Math.log(bytes) / Math.log(unit)); + String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp - 1) + (si ? "" : "i"); + return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); + } + + public static void printMemoryUsage(String label) { + MemoryUsage memusage = ManagementFactory.getMemoryMXBean().getHeapMemoryUsage(); + float freeratio = 1f - (float) memusage.getUsed() / memusage.getCommitted(); + System.out.format("[%-24s] init: %-7s, used: %-7s, comm: %-7s, freeRatio ~= %.1f%%%n", + label, + humanReadableByteCount(memusage.getInit(), false), + humanReadableByteCount(memusage.getUsed(), false), + humanReadableByteCount(memusage.getCommitted(), false), + freeratio * 100 + ); + } + } +} diff -r 8cb56c8cb30d -r f0bedf980c65 test/runtime/NMT/MallocTrackingVerify.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/MallocTrackingVerify.java Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,105 @@ +/* + * 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 8054836 + * @summary Test to verify correctness of malloc tracking + * @key nmt jcmd + * @library /testlibrary /testlibrary/whitebox + * @build MallocTrackingVerify + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:NativeMemoryTracking=detail MallocTrackingVerify + * + */ + +import java.util.ArrayList; +import java.util.Random; + +import com.oracle.java.testlibrary.*; + +import sun.hotspot.WhiteBox; + +public class MallocTrackingVerify { + private static int MAX_ALLOC = 4 * 1024; + + static ArrayList mallocd_memory = new ArrayList(); + static long mallocd_total = 0; + public static WhiteBox wb = WhiteBox.getWhiteBox(); + + public static void main(String args[]) throws Exception { + OutputAnalyzer output; + + // Grab my own PID + String pid = Integer.toString(ProcessTools.getProcessId()); + ProcessBuilder pb = new ProcessBuilder(); + + Random random = new Random(); + // Allocate small amounts of memory with random pseudo call stack + while (mallocd_total < MAX_ALLOC) { + int size = random.nextInt(31) + 1; + long addr = wb.NMTMallocWithPseudoStack(size, random.nextInt()); + if (addr != 0) { + MallocMemory mem = new MallocMemory(addr, size); + mallocd_memory.add(mem); + mallocd_total += size; + } else { + System.out.println("Out of malloc memory"); + break; + } + } + + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory", "summary" }); + output = new OutputAnalyzer(pb.start()); + output.shouldContain("Test (reserved=4KB, committed=4KB)"); + + // Free + for (MallocMemory mem : mallocd_memory) { + wb.NMTFree(mem.addr()); + } + + // Run 'jcmd VM.native_memory summary', check for expected output + pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, + "VM.native_memory", "summary" }); + output = new OutputAnalyzer(pb.start()); + output.shouldNotContain("Test (reserved="); + } + + static class MallocMemory { + private long addr; + private int size; + + MallocMemory(long addr, int size) { + this.addr = addr; + this.size = size; + } + + long addr() { + return this.addr; + } + + int size() { + return this.size; + } + } +} diff -r 8cb56c8cb30d -r f0bedf980c65 test/runtime/NMT/UnsafeMallocLimit.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtime/NMT/UnsafeMallocLimit.java Tue Sep 16 13:55:38 2014 -0700 @@ -0,0 +1,50 @@ +/* + * 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 8055289 + * @library /testlibrary + * @build UnsafeMallocLimit + * @run main/othervm -Xmx32m -XX:NativeMemoryTracking=summary UnsafeMallocLimit + */ + +import com.oracle.java.testlibrary.*; +import sun.misc.Unsafe; + +public class UnsafeMallocLimit { + + public static void main(String args[]) throws Exception { + if (Platform.is32bit()) { + Unsafe unsafe = Utils.getUnsafe(); + try { + unsafe.allocateMemory(1 << 30); + throw new RuntimeException("Did not get expected OOME"); + } catch (OutOfMemoryError e) { + // Expected exception + } + } else { + System.out.println("Test only valid on 32-bit platforms"); + } + } +} diff -r 8cb56c8cb30d -r f0bedf980c65 test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Mon Sep 15 16:39:00 2014 -0400 +++ b/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Sep 16 13:55:38 2014 -0700 @@ -30,6 +30,7 @@ import java.util.function.Function; import java.util.stream.Stream; import java.security.BasicPermission; + import sun.hotspot.parser.DiagnosticCommand; public class WhiteBox { @@ -168,6 +169,12 @@ // CPU features public native String getCPUFeatures(); + // Native extensions + public native long getHeapUsageForContext(int context); + public native long getHeapRegionCountForContext(int context); + public native int getContextForObject(Object obj); + public native void printRegionInfo(int context); + // VM flags public native void setBooleanVMFlag(String name, boolean value); public native void setIntxVMFlag(String name, long value);