# HG changeset patch # User kevinw # Date 1313071109 -3600 # Node ID e9db47a083cc02c9ad9fbf3199a786a3f71131be # Parent 41e6ee74f8792e3c0c64cf038afd97956e5e63a0# Parent 7c2653aefc46a1a3b6683055a72f86313b28c923 Merge diff -r 41e6ee74f879 -r e9db47a083cc .hgtags --- a/.hgtags Tue Aug 02 14:37:35 2011 +0100 +++ b/.hgtags Thu Aug 11 14:58:29 2011 +0100 @@ -172,3 +172,5 @@ 3aea9e9feb073f5500e031be6186666bcae89aa2 hs21-b11 9ad1548c6b63d596c411afc35147ffd5254426d9 jdk7-b142 9ad1548c6b63d596c411afc35147ffd5254426d9 hs21-b12 +c149193c768b8b7233da4c3a3fdc0756b975848e hs21-b13 +c149193c768b8b7233da4c3a3fdc0756b975848e jdk7-b143 diff -r 41e6ee74f879 -r e9db47a083cc .jcheck/conf --- a/.jcheck/conf Tue Aug 02 14:37:35 2011 +0100 +++ b/.jcheck/conf Thu Aug 11 14:58:29 2011 +0100 @@ -1,1 +1,1 @@ -project=jdk7 +project=jdk8 diff -r 41e6ee74f879 -r e9db47a083cc make/hotspot_version --- a/make/hotspot_version Tue Aug 02 14:37:35 2011 +0100 +++ b/make/hotspot_version Thu Aug 11 14:58:29 2011 +0100 @@ -38,8 +38,8 @@ HS_BUILD_NUMBER=01 JDK_MAJOR_VER=1 -JDK_MINOR_VER=7 +JDK_MINOR_VER=8 JDK_MICRO_VER=0 # Previous (bootdir) JDK version -JDK_PREVIOUS_VERSION=1.6.0 +JDK_PREVIOUS_VERSION=1.7.0 diff -r 41e6ee74f879 -r e9db47a083cc make/jprt.gmk --- a/make/jprt.gmk Tue Aug 02 14:37:35 2011 +0100 +++ b/make/jprt.gmk Thu Aug 11 14:58:29 2011 +0100 @@ -34,13 +34,13 @@ endif jprt_build_productEmb: - $(MAKE) JAVASE_EMBEDDED=true jprt_build_product + $(MAKE) JAVASE_EMBEDDED=true MINIMIZE_RAM_USAGE=true jprt_build_product jprt_build_debugEmb: - $(MAKE) JAVASE_EMBEDDED=true jprt_build_debug + $(MAKE) JAVASE_EMBEDDED=true MINIMIZE_RAM_USAGE=true jprt_build_debug jprt_build_fastdebugEmb: - $(MAKE) JAVASE_EMBEDDED=true jprt_build_fastdebug + $(MAKE) JAVASE_EMBEDDED=true MINIMIZE_RAM_USAGE=true jprt_build_fastdebug jprt_build_productOpen: $(MAKE) OPENJDK=true jprt_build_product diff -r 41e6ee74f879 -r e9db47a083cc make/jprt.properties --- a/make/jprt.properties Tue Aug 02 14:37:35 2011 +0100 +++ b/make/jprt.properties Thu Aug 11 14:58:29 2011 +0100 @@ -50,7 +50,7 @@ # sparc etc. # Define the Solaris platforms we want for the various releases - +jprt.my.solaris.sparc.jdk8=solaris_sparc_5.10 jprt.my.solaris.sparc.jdk7=solaris_sparc_5.10 jprt.my.solaris.sparc.jdk7b107=solaris_sparc_5.10 jprt.my.solaris.sparc.jdk7temp=solaris_sparc_5.10 @@ -64,6 +64,7 @@ jprt.my.solaris.sparc.ejdk6=${jprt.my.solaris.sparc.jdk6} jprt.my.solaris.sparc=${jprt.my.solaris.sparc.${jprt.tools.default.release}} +jprt.my.solaris.sparcv9.jdk8=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk7=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk7b107=solaris_sparcv9_5.10 jprt.my.solaris.sparcv9.jdk7temp=solaris_sparcv9_5.10 @@ -77,6 +78,7 @@ jprt.my.solaris.sparcv9.ejdk6=${jprt.my.solaris.sparcv9.jdk6} jprt.my.solaris.sparcv9=${jprt.my.solaris.sparcv9.${jprt.tools.default.release}} +jprt.my.solaris.i586.jdk8=solaris_i586_5.10 jprt.my.solaris.i586.jdk7=solaris_i586_5.10 jprt.my.solaris.i586.jdk7b107=solaris_i586_5.10 jprt.my.solaris.i586.jdk7temp=solaris_i586_5.10 @@ -90,6 +92,7 @@ jprt.my.solaris.i586.ejdk6=${jprt.my.solaris.i586.jdk6} jprt.my.solaris.i586=${jprt.my.solaris.i586.${jprt.tools.default.release}} +jprt.my.solaris.x64.jdk8=solaris_x64_5.10 jprt.my.solaris.x64.jdk7=solaris_x64_5.10 jprt.my.solaris.x64.jdk7b107=solaris_x64_5.10 jprt.my.solaris.x64.jdk7temp=solaris_x64_5.10 @@ -103,6 +106,7 @@ jprt.my.solaris.x64.ejdk6=${jprt.my.solaris.x64.jdk6} jprt.my.solaris.x64=${jprt.my.solaris.x64.${jprt.tools.default.release}} +jprt.my.linux.i586.jdk8=linux_i586_2.6 jprt.my.linux.i586.jdk7=linux_i586_2.6 jprt.my.linux.i586.jdk7b107=linux_i586_2.6 jprt.my.linux.i586.jdk7temp=linux_i586_2.6 @@ -116,6 +120,7 @@ jprt.my.linux.i586.ejdk6=linux_i586_2.6 jprt.my.linux.i586=${jprt.my.linux.i586.${jprt.tools.default.release}} +jprt.my.linux.x64.jdk8=linux_x64_2.6 jprt.my.linux.x64.jdk7=linux_x64_2.6 jprt.my.linux.x64.jdk7b107=linux_x64_2.6 jprt.my.linux.x64.jdk7temp=linux_x64_2.6 @@ -129,6 +134,7 @@ jprt.my.linux.x64.ejdk6=${jprt.my.linux.x64.jdk6} jprt.my.linux.x64=${jprt.my.linux.x64.${jprt.tools.default.release}} +jprt.my.linux.ppc.jdk8=linux_ppc_2.6 jprt.my.linux.ppc.jdk7=linux_ppc_2.6 jprt.my.linux.ppc.jdk7b107=linux_ppc_2.6 jprt.my.linux.ppc.jdk7temp=linux_ppc_2.6 @@ -136,6 +142,7 @@ jprt.my.linux.ppc.ejdk7=linux_ppc_2.6 jprt.my.linux.ppc=${jprt.my.linux.ppc.${jprt.tools.default.release}} +jprt.my.linux.ppcv2.jdk8=linux_ppcv2_2.6 jprt.my.linux.ppcv2.jdk7=linux_ppcv2_2.6 jprt.my.linux.ppcv2.jdk7b107=linux_ppcv2_2.6 jprt.my.linux.ppcv2.jdk7temp=linux_ppcv2_2.6 @@ -143,6 +150,7 @@ jprt.my.linux.ppcv2.ejdk7=linux_ppcv2_2.6 jprt.my.linux.ppcv2=${jprt.my.linux.ppcv2.${jprt.tools.default.release}} +jprt.my.linux.ppcsflt.jdk8=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt.jdk7=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt.jdk7b107=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt.jdk7temp=linux_ppcsflt_2.6 @@ -150,6 +158,7 @@ jprt.my.linux.ppcsflt.ejdk7=linux_ppcsflt_2.6 jprt.my.linux.ppcsflt=${jprt.my.linux.ppcsflt.${jprt.tools.default.release}} +jprt.my.linux.armvfp.jdk8=linux_armvfp_2.6 jprt.my.linux.armvfp.jdk7=linux_armvfp_2.6 jprt.my.linux.armvfp.jdk7b107=linux_armvfp_2.6 jprt.my.linux.armvfp.jdk7temp=linux_armvfp_2.6 @@ -157,6 +166,7 @@ jprt.my.linux.armvfp.ejdk7=linux_armvfp_2.6 jprt.my.linux.armvfp=${jprt.my.linux.armvfp.${jprt.tools.default.release}} +jprt.my.linux.armsflt.jdk8=linux_armsflt_2.6 jprt.my.linux.armsflt.jdk7=linux_armsflt_2.6 jprt.my.linux.armsflt.jdk7b107=linux_armsflt_2.6 jprt.my.linux.armsflt.jdk7temp=linux_armsflt_2.6 @@ -164,6 +174,7 @@ jprt.my.linux.armsflt.ejdk7=linux_armsflt_2.6 jprt.my.linux.armsflt=${jprt.my.linux.armsflt.${jprt.tools.default.release}} +jprt.my.windows.i586.jdk8=windows_i586_5.1 jprt.my.windows.i586.jdk7=windows_i586_5.1 jprt.my.windows.i586.jdk7b107=windows_i586_5.0 jprt.my.windows.i586.jdk7temp=windows_i586_5.0 @@ -177,6 +188,7 @@ jprt.my.windows.i586.ejdk6=${jprt.my.windows.i586.jdk6} jprt.my.windows.i586=${jprt.my.windows.i586.${jprt.tools.default.release}} +jprt.my.windows.x64.jdk8=windows_x64_5.2 jprt.my.windows.x64.jdk7=windows_x64_5.2 jprt.my.windows.x64.jdk7b107=windows_x64_5.2 jprt.my.windows.x64.jdk7temp=windows_x64_5.2 @@ -218,6 +230,7 @@ jprt.build.targets.all=${jprt.build.targets.standard}, \ ${jprt.build.targets.embedded}, ${jprt.build.targets.open} +jprt.build.targets.jdk8=${jprt.build.targets.all} jprt.build.targets.jdk7=${jprt.build.targets.all} jprt.build.targets.jdk7temp=${jprt.build.targets.all} jprt.build.targets.jdk7b107=${jprt.build.targets.all} @@ -494,6 +507,7 @@ ${jprt.my.windows.x64.test.targets} +jprt.test.targets.jdk8=${jprt.test.targets.standard} jprt.test.targets.jdk7=${jprt.test.targets.standard} jprt.test.targets.jdk7temp=${jprt.test.targets.standard} jprt.test.targets.jdk7b105=${jprt.test.targets.standard} @@ -534,6 +548,7 @@ jprt.make.rule.test.targets.embedded = \ ${jprt.make.rule.test.targets.standard.client} +jprt.make.rule.test.targets.jdk8=${jprt.make.rule.test.targets.standard} jprt.make.rule.test.targets.jdk7=${jprt.make.rule.test.targets.standard} jprt.make.rule.test.targets.jdk7temp=${jprt.make.rule.test.targets.standard} jprt.make.rule.test.targets.jdk7b107=${jprt.make.rule.test.targets.standard} diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -716,6 +716,8 @@ casa_op3 = 0x3c, casxa_op3 = 0x3e, + mftoi_op3 = 0x36, + alt_bit_op3 = 0x10, cc_bit_op3 = 0x10 }; @@ -750,7 +752,13 @@ fitod_opf = 0xc8, fstod_opf = 0xc9, fstoi_opf = 0xd1, - fdtoi_opf = 0xd2 + fdtoi_opf = 0xd2, + + mdtox_opf = 0x110, + mstouw_opf = 0x111, + mstosw_opf = 0x113, + mxtod_opf = 0x118, + mwtos_opf = 0x119 }; enum RCondition { rc_z = 1, rc_lez = 2, rc_lz = 3, rc_nz = 5, rc_gz = 6, rc_gez = 7 }; @@ -1061,6 +1069,9 @@ return x & ((1 << 10) - 1); } + // instruction only in VIS3 + static void vis3_only() { assert( VM_Version::has_vis3(), "This instruction only works on SPARC with VIS3"); } + // instruction only in v9 static void v9_only() { assert( VM_Version::v9_instructions_work(), "This instruction only works on SPARC V9"); } @@ -1247,8 +1258,8 @@ // pp 159 - void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); } - void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); } + void ftox( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(fpop1_op3) | opf(0x80 + w) | fs2(s, w)); } + void ftoi( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(fpop1_op3) | opf(0xd0 + w) | fs2(s, w)); } // pp 160 @@ -1256,8 +1267,8 @@ // pp 161 - void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, w)); } - void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, w)); } + void fxtof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { v9_only(); emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0x80 + w*4) | fs2(s, FloatRegisterImpl::D)); } + void fitof( FloatRegisterImpl::Width w, FloatRegister s, FloatRegister d ) { emit_long( op(arith_op) | fd(d, w) | op3(fpop1_op3) | opf(0xc0 + w*4) | fs2(s, FloatRegisterImpl::S)); } // pp 162 @@ -1709,6 +1720,19 @@ inline void wrasi( Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(3, 29, 25)); } inline void wrfprs( Register d) { v9_only(); emit_long( op(arith_op) | rs1(d) | op3(wrreg_op3) | u_field(6, 29, 25)); } + + // VIS3 instructions + + void movstosw( FloatRegister s, Register d ) { vis3_only(); emit_long( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstosw_opf) | fs2(s, FloatRegisterImpl::S)); } + void movstouw( FloatRegister s, Register d ) { vis3_only(); emit_long( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mstouw_opf) | fs2(s, FloatRegisterImpl::S)); } + void movdtox( FloatRegister s, Register d ) { vis3_only(); emit_long( op(arith_op) | rd(d) | op3(mftoi_op3) | opf(mdtox_opf) | fs2(s, FloatRegisterImpl::D)); } + + void movwtos( Register s, FloatRegister d ) { vis3_only(); emit_long( op(arith_op) | fd(d, FloatRegisterImpl::S) | op3(mftoi_op3) | opf(mwtos_opf) | rs2(s)); } + void movxtod( Register s, FloatRegister d ) { vis3_only(); emit_long( op(arith_op) | fd(d, FloatRegisterImpl::D) | op3(mftoi_op3) | opf(mxtod_opf) | rs2(s)); } + + + + // For a given register condition, return the appropriate condition code // Condition (the one you would use to get the same effect after "tst" on // the target register.) diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -524,6 +524,30 @@ } #endif // ASSERT + +void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register target, Register temp) { + assert(method == G5_method, "interpreter calling convention"); + __ verify_oop(method); + __ ld_ptr(G5_method, in_bytes(methodOopDesc::from_interpreted_offset()), target); + if (JvmtiExport::can_post_interpreter_events()) { + // JVMTI events, such as single-stepping, are implemented partly by avoiding running + // compiled code in threads for which the event is enabled. Check here for + // interp_only_mode if these events CAN be enabled. + __ verify_thread(); + Label skip_compiled_code; + + const Address interp_only(G2_thread, JavaThread::interp_only_mode_offset()); + __ ld(interp_only, temp); + __ tst(temp); + __ br(Assembler::notZero, true, Assembler::pn, skip_compiled_code); + __ delayed()->ld_ptr(G5_method, in_bytes(methodOopDesc::interpreter_entry_offset()), target); + __ bind(skip_compiled_code); + } + __ jmp(target, 0); + __ delayed()->nop(); +} + + // Code generation address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { // I5_savedSP/O5_savedSP: sender SP (must preserve) @@ -1105,9 +1129,6 @@ guarantee(java_lang_invoke_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); // Some handy addresses: - Address G5_method_fie( G5_method, in_bytes(methodOopDesc::from_interpreted_offset())); - Address G5_method_fce( G5_method, in_bytes(methodOopDesc::from_compiled_offset())); - Address G3_mh_vmtarget( G3_method_handle, java_lang_invoke_MethodHandle::vmtarget_offset_in_bytes()); Address G3_dmh_vmindex( G3_method_handle, java_lang_invoke_DirectMethodHandle::vmindex_offset_in_bytes()); @@ -1136,24 +1157,23 @@ case _raise_exception: { // Not a real MH entry, but rather shared code for raising an - // exception. Since we use the compiled entry, arguments are - // expected in compiler argument registers. + // exception. For sharing purposes the arguments are passed into registers + // and then placed in the intepreter calling convention here. assert(raise_exception_method(), "must be set"); assert(raise_exception_method()->from_compiled_entry(), "method must be linked"); - __ mov(O5_savedSP, SP); // Cut the stack back to where the caller started. - - Label L_no_method; - // FIXME: fill in _raise_exception_method with a suitable java.lang.invoke method __ set(AddressLiteral((address) &_raise_exception_method), G5_method); __ ld_ptr(Address(G5_method, 0), G5_method); const int jobject_oop_offset = 0; __ ld_ptr(Address(G5_method, jobject_oop_offset), G5_method); - __ verify_oop(G5_method); - __ jump_indirect_to(G5_method_fce, O3_scratch); // jump to compiled entry - __ delayed()->nop(); + adjust_SP_and_Gargs_down_by_slots(_masm, 3, noreg, noreg); + + __ st_ptr(O0_code, __ argument_address(constant(2), noreg, 0)); + __ st_ptr(O1_actual, __ argument_address(constant(1), noreg, 0)); + __ st_ptr(O2_required, __ argument_address(constant(0), noreg, 0)); + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); } break; @@ -1161,7 +1181,6 @@ case _invokespecial_mh: { __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop - __ verify_oop(G5_method); // Same as TemplateTable::invokestatic or invokespecial, // minus the CP setup and profiling: if (ek == _invokespecial_mh) { @@ -1171,8 +1190,7 @@ __ null_check(G3_method_handle); __ verify_oop(G3_method_handle); } - __ jump_indirect_to(G5_method_fie, O1_scratch); - __ delayed()->nop(); + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); } break; @@ -1204,9 +1222,7 @@ Address vtable_entry_addr(O0_klass, base + vtableEntry::method_offset_in_bytes()); __ ld_ptr(vtable_entry_addr, G5_method); - __ verify_oop(G5_method); - __ jump_indirect_to(G5_method_fie, O1_scratch); - __ delayed()->nop(); + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); } break; @@ -1237,9 +1253,7 @@ O3_scratch, no_such_interface); - __ verify_oop(G5_method); - __ jump_indirect_to(G5_method_fie, O1_scratch); - __ delayed()->nop(); + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); __ bind(no_such_interface); // Throw an exception. @@ -1283,9 +1297,7 @@ if (direct_to_method) { __ load_heap_oop(G3_mh_vmtarget, G5_method); // target is a methodOop - __ verify_oop(G5_method); - __ jump_indirect_to(G5_method_fie, O1_scratch); - __ delayed()->nop(); + jump_from_method_handle(_masm, G5_method, O1_scratch, O2_scratch); } else { __ load_heap_oop(G3_mh_vmtarget, G3_method_handle); // target is a methodOop __ verify_oop(G3_method_handle); diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/sparc/vm/methodHandles_sparc.hpp --- a/src/cpu/sparc/vm/methodHandles_sparc.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/sparc/vm/methodHandles_sparc.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -221,4 +221,8 @@ "reference is a MH"); } + // Similar to InterpreterMacroAssembler::jump_from_interpreted. + // Takes care of special dispatch from single stepping too. + static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp, Register temp2); + static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN; diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/sparc/vm/sparc.ad Thu Aug 11 14:58:29 2011 +0100 @@ -425,7 +425,7 @@ // but they are used with the "Op_RegD" type, and always occur in even/odd pairs. // This class is usable for mis-aligned loads as happen in I2C adapters. reg_class dflt_low_reg(R_F0, R_F1, R_F2, R_F3, R_F4, R_F5, R_F6, R_F7, R_F8, R_F9, R_F10,R_F11,R_F12,R_F13,R_F14,R_F15, - R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29,R_F30,R_F31 ); + R_F16,R_F17,R_F18,R_F19,R_F20,R_F21,R_F22,R_F23,R_F24,R_F25,R_F26,R_F27,R_F28,R_F29); %} //----------DEFINITION BLOCK--------------------------------------------------- @@ -1326,17 +1326,17 @@ // -------------------------------------- // Check for float->int copy; requires a trip through memory - if( src_first_rc == rc_float && dst_first_rc == rc_int ) { + if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS < 3) { int offset = frame::register_save_words*wordSize; - if( cbuf ) { + if (cbuf) { emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::sub_op3, R_SP_enc, 16 ); impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); emit3_simm13( *cbuf, Assembler::arith_op, R_SP_enc, Assembler::add_op3, R_SP_enc, 16 ); } #ifndef PRODUCT - else if( !do_size ) { - if( size != 0 ) st->print("\n\t"); + else if (!do_size) { + if (size != 0) st->print("\n\t"); st->print( "SUB R_SP,16,R_SP\n"); impl_helper(this,cbuf,ra_,do_size,false,offset,src_first,Assembler::stf_op3 ,"STF ",size, st); impl_helper(this,cbuf,ra_,do_size,true ,offset,dst_first,Assembler::lduw_op3,"LDUW",size, st); @@ -1346,6 +1346,21 @@ size += 16; } + // Check for float->int copy on T4 + if (src_first_rc == rc_float && dst_first_rc == rc_int && UseVIS >= 3) { + // Further check for aligned-adjacent pair, so we can use a double move + if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) + return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mdtox_opf,"MOVDTOX",size, st); + size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mstouw_opf,"MOVSTOUW",size, st); + } + // Check for int->float copy on T4 + if (src_first_rc == rc_int && dst_first_rc == rc_float && UseVIS >= 3) { + // Further check for aligned-adjacent pair, so we can use a double move + if ((src_first&1)==0 && src_first+1 == src_second && (dst_first&1)==0 && dst_first+1 == dst_second) + return impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mxtod_opf,"MOVXTOD",size, st); + size = impl_mov_helper(cbuf,do_size,src_first,dst_first,Assembler::mftoi_op3,Assembler::mwtos_opf,"MOVWTOS",size, st); + } + // -------------------------------------- // In the 32-bit 1-reg-longs build ONLY, I see mis-aligned long destinations. // In such cases, I have to do the big-endian swap. For aligned targets, the @@ -8164,215 +8179,58 @@ ins_pipe( cadd_cmpltmask ); %} -//----------Arithmetic Conversion Instructions--------------------------------- -// The conversions operations are all Alpha sorted. Please keep it that way! - -instruct convD2F_reg(regF dst, regD src) %{ - match(Set dst (ConvD2F src)); - size(4); - format %{ "FDTOS $src,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdtos_opf); - ins_encode(form3_opf_rs2D_rdF(src, dst)); - ins_pipe(fcvtD2F); -%} - - -// Convert a double to an int in a float register. -// If the double is a NAN, stuff a zero in instead. -instruct convD2I_helper(regF dst, regD src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FDTOI $src,$dst\t! convert in delay slot\n\t" - "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t" - "FSUBs $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_d2i_helper(src,dst)); - ins_pipe(fcvtD2I); -%} - -instruct convD2I_reg(stackSlotI dst, regD src) %{ - match(Set dst (ConvD2I src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regF tmp; - convD2I_helper(tmp, src); - regF_to_stkI(dst, tmp); - %} -%} - -// Convert a double to a long in a double register. -// If the double is a NAN, stuff a zero in instead. -instruct convD2L_helper(regD dst, regD src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FDTOX $src,$dst\t! convert in delay slot\n\t" - "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t" - "FSUBd $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_d2l_helper(src,dst)); - ins_pipe(fcvtD2L); -%} - - -// Double to Long conversion -instruct convD2L_reg(stackSlotL dst, regD src) %{ - match(Set dst (ConvD2L src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regD tmp; - convD2L_helper(tmp, src); - regD_to_stkL(dst, tmp); - %} -%} - - -instruct convF2D_reg(regD dst, regF src) %{ - match(Set dst (ConvF2D src)); - format %{ "FSTOD $src,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fstod_opf); - ins_encode(form3_opf_rs2F_rdD(src, dst)); - ins_pipe(fcvtF2D); -%} - - -instruct convF2I_helper(regF dst, regF src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FSTOI $src,$dst\t! convert in delay slot\n\t" - "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t" - "FSUBs $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_f2i_helper(src,dst)); - ins_pipe(fcvtF2I); -%} - -instruct convF2I_reg(stackSlotI dst, regF src) %{ - match(Set dst (ConvF2I src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regF tmp; - convF2I_helper(tmp, src); - regF_to_stkI(dst, tmp); - %} -%} - - -instruct convF2L_helper(regD dst, regF src, flagsRegF0 fcc0) %{ - effect(DEF dst, USE src, KILL fcc0); - format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t" - "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" - "FSTOX $src,$dst\t! convert in delay slot\n\t" - "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t" - "FSUBd $dst,$dst,$dst\t! cleared only if nan\n" - "skip:" %} - ins_encode(form_f2l_helper(src,dst)); - ins_pipe(fcvtF2L); -%} - -// Float to Long conversion -instruct convF2L_reg(stackSlotL dst, regF src) %{ - match(Set dst (ConvF2L src)); - ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); - expand %{ - regD tmp; - convF2L_helper(tmp, src); - regD_to_stkL(dst, tmp); - %} -%} - - -instruct convI2D_helper(regD dst, regF tmp) %{ - effect(USE tmp, DEF dst); - format %{ "FITOD $tmp,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf); - ins_encode(form3_opf_rs2F_rdD(tmp, dst)); - ins_pipe(fcvtI2D); -%} - -instruct convI2D_reg(stackSlotI src, regD dst) %{ - match(Set dst (ConvI2D src)); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - expand %{ - regF tmp; - stkI_to_regF( tmp, src); - convI2D_helper( dst, tmp); - %} -%} - -instruct convI2D_mem( regD_low dst, memory mem ) %{ - match(Set dst (ConvI2D (LoadI mem))); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); - format %{ "LDF $mem,$dst\n\t" - "FITOD $dst,$dst" %} - opcode(Assembler::ldf_op3, Assembler::fitod_opf); - ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); - ins_pipe(floadF_mem); -%} - - -instruct convI2F_helper(regF dst, regF tmp) %{ - effect(DEF dst, USE tmp); - format %{ "FITOS $tmp,$dst" %} - opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitos_opf); - ins_encode(form3_opf_rs2F_rdF(tmp, dst)); - ins_pipe(fcvtI2F); -%} - -instruct convI2F_reg( regF dst, stackSlotI src ) %{ - match(Set dst (ConvI2F src)); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - expand %{ - regF tmp; - stkI_to_regF(tmp,src); - convI2F_helper(dst, tmp); - %} -%} - -instruct convI2F_mem( regF dst, memory mem ) %{ - match(Set dst (ConvI2F (LoadI mem))); - ins_cost(DEFAULT_COST + MEMORY_REF_COST); - size(8); - format %{ "LDF $mem,$dst\n\t" - "FITOS $dst,$dst" %} - opcode(Assembler::ldf_op3, Assembler::fitos_opf); - ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); - ins_pipe(floadF_mem); -%} - - -instruct convI2L_reg(iRegL dst, iRegI src) %{ - match(Set dst (ConvI2L src)); - size(4); - format %{ "SRA $src,0,$dst\t! int->long" %} - opcode(Assembler::sra_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); + +//----------------------------------------------------------------- +// Direct raw moves between float and general registers using VIS3. + +// ins_pipe(faddF_reg); +instruct MoveF2I_reg_reg(iRegI dst, regF src) %{ + predicate(UseVIS >= 3); + match(Set dst (MoveF2I src)); + + format %{ "MOVSTOUW $src,$dst\t! MoveF2I" %} + ins_encode %{ + __ movstouw($src$$FloatRegister, $dst$$Register); + %} + ins_pipe(ialu_reg_reg); +%} + +instruct MoveI2F_reg_reg(regF dst, iRegI src) %{ + predicate(UseVIS >= 3); + match(Set dst (MoveI2F src)); + + format %{ "MOVWTOS $src,$dst\t! MoveI2F" %} + ins_encode %{ + __ movwtos($src$$Register, $dst$$FloatRegister); + %} ins_pipe(ialu_reg_reg); %} -// Zero-extend convert int to long -instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{ - match(Set dst (AndL (ConvI2L src) mask) ); - size(4); - format %{ "SRL $src,0,$dst\t! zero-extend int to long" %} - opcode(Assembler::srl_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); +instruct MoveD2L_reg_reg(iRegL dst, regD src) %{ + predicate(UseVIS >= 3); + match(Set dst (MoveD2L src)); + + format %{ "MOVDTOX $src,$dst\t! MoveD2L" %} + ins_encode %{ + __ movdtox(as_DoubleFloatRegister($src$$reg), $dst$$Register); + %} ins_pipe(ialu_reg_reg); %} -// Zero-extend long -instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{ - match(Set dst (AndL src mask) ); - size(4); - format %{ "SRL $src,0,$dst\t! zero-extend long" %} - opcode(Assembler::srl_op3, Assembler::arith_op); - ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); +instruct MoveL2D_reg_reg(regD dst, iRegL src) %{ + predicate(UseVIS >= 3); + match(Set dst (MoveL2D src)); + + format %{ "MOVXTOD $src,$dst\t! MoveL2D" %} + ins_encode %{ + __ movxtod($src$$Register, as_DoubleFloatRegister($dst$$reg)); + %} ins_pipe(ialu_reg_reg); %} + +// Raw moves between float and general registers using stack. + instruct MoveF2I_stack_reg(iRegI dst, stackSlotF src) %{ match(Set dst (MoveF2I src)); effect(DEF dst, USE src); @@ -8427,7 +8285,7 @@ ins_cost(MEMORY_REF_COST); size(4); - format %{ "STF $src,$dst\t!MoveF2I" %} + format %{ "STF $src,$dst\t! MoveF2I" %} opcode(Assembler::stf_op3); ins_encode(simple_form3_mem_reg(dst, src)); ins_pipe(fstoreF_stk_reg); @@ -8439,7 +8297,7 @@ ins_cost(MEMORY_REF_COST); size(4); - format %{ "STW $src,$dst\t!MoveI2F" %} + format %{ "STW $src,$dst\t! MoveI2F" %} opcode(Assembler::stw_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); @@ -8451,7 +8309,7 @@ ins_cost(MEMORY_REF_COST); size(4); - format %{ "STDF $src,$dst\t!MoveD2L" %} + format %{ "STDF $src,$dst\t! MoveD2L" %} opcode(Assembler::stdf_op3); ins_encode(simple_form3_mem_reg(dst, src)); ins_pipe(fstoreD_stk_reg); @@ -8463,13 +8321,290 @@ ins_cost(MEMORY_REF_COST); size(4); - format %{ "STX $src,$dst\t!MoveL2D" %} + format %{ "STX $src,$dst\t! MoveL2D" %} opcode(Assembler::stx_op3); ins_encode(simple_form3_mem_reg( dst, src ) ); ins_pipe(istore_mem_reg); %} +//----------Arithmetic Conversion Instructions--------------------------------- +// The conversions operations are all Alpha sorted. Please keep it that way! + +instruct convD2F_reg(regF dst, regD src) %{ + match(Set dst (ConvD2F src)); + size(4); + format %{ "FDTOS $src,$dst" %} + opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fdtos_opf); + ins_encode(form3_opf_rs2D_rdF(src, dst)); + ins_pipe(fcvtD2F); +%} + + +// Convert a double to an int in a float register. +// If the double is a NAN, stuff a zero in instead. +instruct convD2I_helper(regF dst, regD src, flagsRegF0 fcc0) %{ + effect(DEF dst, USE src, KILL fcc0); + format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t" + "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" + "FDTOI $src,$dst\t! convert in delay slot\n\t" + "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t" + "FSUBs $dst,$dst,$dst\t! cleared only if nan\n" + "skip:" %} + ins_encode(form_d2i_helper(src,dst)); + ins_pipe(fcvtD2I); +%} + +instruct convD2I_stk(stackSlotI dst, regD src) %{ + match(Set dst (ConvD2I src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); + expand %{ + regF tmp; + convD2I_helper(tmp, src); + regF_to_stkI(dst, tmp); + %} +%} + +instruct convD2I_reg(iRegI dst, regD src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvD2I src)); + ins_cost(DEFAULT_COST*2 + BRANCH_COST); + expand %{ + regF tmp; + convD2I_helper(tmp, src); + MoveF2I_reg_reg(dst, tmp); + %} +%} + + +// Convert a double to a long in a double register. +// If the double is a NAN, stuff a zero in instead. +instruct convD2L_helper(regD dst, regD src, flagsRegF0 fcc0) %{ + effect(DEF dst, USE src, KILL fcc0); + format %{ "FCMPd fcc0,$src,$src\t! check for NAN\n\t" + "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" + "FDTOX $src,$dst\t! convert in delay slot\n\t" + "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t" + "FSUBd $dst,$dst,$dst\t! cleared only if nan\n" + "skip:" %} + ins_encode(form_d2l_helper(src,dst)); + ins_pipe(fcvtD2L); +%} + +instruct convD2L_stk(stackSlotL dst, regD src) %{ + match(Set dst (ConvD2L src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); + expand %{ + regD tmp; + convD2L_helper(tmp, src); + regD_to_stkL(dst, tmp); + %} +%} + +instruct convD2L_reg(iRegL dst, regD src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvD2L src)); + ins_cost(DEFAULT_COST*2 + BRANCH_COST); + expand %{ + regD tmp; + convD2L_helper(tmp, src); + MoveD2L_reg_reg(dst, tmp); + %} +%} + + +instruct convF2D_reg(regD dst, regF src) %{ + match(Set dst (ConvF2D src)); + format %{ "FSTOD $src,$dst" %} + opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fstod_opf); + ins_encode(form3_opf_rs2F_rdD(src, dst)); + ins_pipe(fcvtF2D); +%} + + +// Convert a float to an int in a float register. +// If the float is a NAN, stuff a zero in instead. +instruct convF2I_helper(regF dst, regF src, flagsRegF0 fcc0) %{ + effect(DEF dst, USE src, KILL fcc0); + format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t" + "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" + "FSTOI $src,$dst\t! convert in delay slot\n\t" + "FITOS $dst,$dst\t! change NaN/max-int to valid float\n\t" + "FSUBs $dst,$dst,$dst\t! cleared only if nan\n" + "skip:" %} + ins_encode(form_f2i_helper(src,dst)); + ins_pipe(fcvtF2I); +%} + +instruct convF2I_stk(stackSlotI dst, regF src) %{ + match(Set dst (ConvF2I src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); + expand %{ + regF tmp; + convF2I_helper(tmp, src); + regF_to_stkI(dst, tmp); + %} +%} + +instruct convF2I_reg(iRegI dst, regF src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvF2I src)); + ins_cost(DEFAULT_COST*2 + BRANCH_COST); + expand %{ + regF tmp; + convF2I_helper(tmp, src); + MoveF2I_reg_reg(dst, tmp); + %} +%} + + +// Convert a float to a long in a float register. +// If the float is a NAN, stuff a zero in instead. +instruct convF2L_helper(regD dst, regF src, flagsRegF0 fcc0) %{ + effect(DEF dst, USE src, KILL fcc0); + format %{ "FCMPs fcc0,$src,$src\t! check for NAN\n\t" + "FBO,pt fcc0,skip\t! branch on ordered, predict taken\n\t" + "FSTOX $src,$dst\t! convert in delay slot\n\t" + "FXTOD $dst,$dst\t! change NaN/max-long to valid double\n\t" + "FSUBd $dst,$dst,$dst\t! cleared only if nan\n" + "skip:" %} + ins_encode(form_f2l_helper(src,dst)); + ins_pipe(fcvtF2L); +%} + +instruct convF2L_stk(stackSlotL dst, regF src) %{ + match(Set dst (ConvF2L src)); + ins_cost(DEFAULT_COST*2 + MEMORY_REF_COST*2 + BRANCH_COST); + expand %{ + regD tmp; + convF2L_helper(tmp, src); + regD_to_stkL(dst, tmp); + %} +%} + +instruct convF2L_reg(iRegL dst, regF src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvF2L src)); + ins_cost(DEFAULT_COST*2 + BRANCH_COST); + expand %{ + regD tmp; + convF2L_helper(tmp, src); + MoveD2L_reg_reg(dst, tmp); + %} +%} + + +instruct convI2D_helper(regD dst, regF tmp) %{ + effect(USE tmp, DEF dst); + format %{ "FITOD $tmp,$dst" %} + opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitod_opf); + ins_encode(form3_opf_rs2F_rdD(tmp, dst)); + ins_pipe(fcvtI2D); +%} + +instruct convI2D_stk(stackSlotI src, regD dst) %{ + match(Set dst (ConvI2D src)); + ins_cost(DEFAULT_COST + MEMORY_REF_COST); + expand %{ + regF tmp; + stkI_to_regF(tmp, src); + convI2D_helper(dst, tmp); + %} +%} + +instruct convI2D_reg(regD_low dst, iRegI src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvI2D src)); + expand %{ + regF tmp; + MoveI2F_reg_reg(tmp, src); + convI2D_helper(dst, tmp); + %} +%} + +instruct convI2D_mem(regD_low dst, memory mem) %{ + match(Set dst (ConvI2D (LoadI mem))); + ins_cost(DEFAULT_COST + MEMORY_REF_COST); + size(8); + format %{ "LDF $mem,$dst\n\t" + "FITOD $dst,$dst" %} + opcode(Assembler::ldf_op3, Assembler::fitod_opf); + ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); + ins_pipe(floadF_mem); +%} + + +instruct convI2F_helper(regF dst, regF tmp) %{ + effect(DEF dst, USE tmp); + format %{ "FITOS $tmp,$dst" %} + opcode(Assembler::fpop1_op3, Assembler::arith_op, Assembler::fitos_opf); + ins_encode(form3_opf_rs2F_rdF(tmp, dst)); + ins_pipe(fcvtI2F); +%} + +instruct convI2F_stk(regF dst, stackSlotI src) %{ + match(Set dst (ConvI2F src)); + ins_cost(DEFAULT_COST + MEMORY_REF_COST); + expand %{ + regF tmp; + stkI_to_regF(tmp,src); + convI2F_helper(dst, tmp); + %} +%} + +instruct convI2F_reg(regF dst, iRegI src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvI2F src)); + ins_cost(DEFAULT_COST); + expand %{ + regF tmp; + MoveI2F_reg_reg(tmp, src); + convI2F_helper(dst, tmp); + %} +%} + +instruct convI2F_mem( regF dst, memory mem ) %{ + match(Set dst (ConvI2F (LoadI mem))); + ins_cost(DEFAULT_COST + MEMORY_REF_COST); + size(8); + format %{ "LDF $mem,$dst\n\t" + "FITOS $dst,$dst" %} + opcode(Assembler::ldf_op3, Assembler::fitos_opf); + ins_encode(simple_form3_mem_reg( mem, dst ), form3_convI2F(dst, dst)); + ins_pipe(floadF_mem); +%} + + +instruct convI2L_reg(iRegL dst, iRegI src) %{ + match(Set dst (ConvI2L src)); + size(4); + format %{ "SRA $src,0,$dst\t! int->long" %} + opcode(Assembler::sra_op3, Assembler::arith_op); + ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); + ins_pipe(ialu_reg_reg); +%} + +// Zero-extend convert int to long +instruct convI2L_reg_zex(iRegL dst, iRegI src, immL_32bits mask ) %{ + match(Set dst (AndL (ConvI2L src) mask) ); + size(4); + format %{ "SRL $src,0,$dst\t! zero-extend int to long" %} + opcode(Assembler::srl_op3, Assembler::arith_op); + ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); + ins_pipe(ialu_reg_reg); +%} + +// Zero-extend long +instruct zerox_long(iRegL dst, iRegL src, immL_32bits mask ) %{ + match(Set dst (AndL src mask) ); + size(4); + format %{ "SRL $src,0,$dst\t! zero-extend long" %} + opcode(Assembler::srl_op3, Assembler::arith_op); + ins_encode( form3_rs1_rs2_rd( src, R_G0, dst ) ); + ins_pipe(ialu_reg_reg); +%} + + //----------- // Long to Double conversion using V8 opcodes. // Still useful because cheetah traps and becomes @@ -8589,7 +8724,7 @@ ins_pipe(fcvtL2D); %} -instruct convL2D_reg_fast_fxtof(regD dst, stackSlotL src) %{ +instruct convL2D_stk_fast_fxtof(regD dst, stackSlotL src) %{ predicate(VM_Version::has_fast_fxtof()); match(Set dst (ConvL2D src)); ins_cost(DEFAULT_COST + 3 * MEMORY_REF_COST); @@ -8600,10 +8735,15 @@ %} %} -//----------- -// Long to Float conversion using V8 opcodes. -// Still useful because cheetah traps and becomes -// amazingly slow for some common numbers. +instruct convL2D_reg(regD dst, iRegL src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvL2D src)); + expand %{ + regD tmp; + MoveL2D_reg_reg(tmp, src); + convL2D_helper(dst, tmp); + %} +%} // Long to Float conversion using fast fxtof instruct convL2F_helper(regF dst, regD tmp) %{ @@ -8615,7 +8755,7 @@ ins_pipe(fcvtL2F); %} -instruct convL2F_reg_fast_fxtof(regF dst, stackSlotL src) %{ +instruct convL2F_stk_fast_fxtof(regF dst, stackSlotL src) %{ match(Set dst (ConvL2F src)); ins_cost(DEFAULT_COST + MEMORY_REF_COST); expand %{ @@ -8624,6 +8764,18 @@ convL2F_helper(dst, tmp); %} %} + +instruct convL2F_reg(regF dst, iRegL src) %{ + predicate(UseVIS >= 3); + match(Set dst (ConvL2F src)); + ins_cost(DEFAULT_COST); + expand %{ + regD tmp; + MoveL2D_reg_reg(tmp, src); + convL2F_helper(dst, tmp); + %} +%} + //----------- instruct convL2I_reg(iRegI dst, iRegL src) %{ diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/sparc/vm/vm_version_sparc.cpp --- a/src/cpu/sparc/vm/vm_version_sparc.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/sparc/vm/vm_version_sparc.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -144,6 +144,18 @@ // buf is started with ", " or is empty _features_str = strdup(strlen(buf) > 2 ? buf + 2 : buf); + // UseVIS is set to the smallest of what hardware supports and what + // the command line requires. I.e., you cannot set UseVIS to 3 on + // older UltraSparc which do not support it. + if (UseVIS > 3) UseVIS=3; + if (UseVIS < 0) UseVIS=0; + if (!has_vis3()) // Drop to 2 if no VIS3 support + UseVIS = MIN2((intx)2,UseVIS); + if (!has_vis2()) // Drop to 1 if no VIS2 support + UseVIS = MIN2((intx)1,UseVIS); + if (!has_vis1()) // Drop to 0 if no VIS1 support + UseVIS = 0; + #ifndef PRODUCT if (PrintMiscellaneous && Verbose) { tty->print("Allocation: "); diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/x86/vm/interp_masm_x86_32.cpp --- a/src/cpu/x86/vm/interp_masm_x86_32.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_32.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -403,9 +403,9 @@ // interp_only_mode if these events CAN be enabled. get_thread(temp); // interp_only is an int, on little endian it is sufficient to test the byte only - // Is a cmpl faster (ce + // Is a cmpl faster? cmpb(Address(temp, JavaThread::interp_only_mode_offset()), 0); - jcc(Assembler::zero, run_compiled_code); + jccb(Assembler::zero, run_compiled_code); jmp(Address(method, methodOopDesc::interpreter_entry_offset())); bind(run_compiled_code); } diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/x86/vm/interp_masm_x86_64.cpp --- a/src/cpu/x86/vm/interp_masm_x86_64.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/x86/vm/interp_masm_x86_64.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -402,7 +402,7 @@ // interp_only is an int, on little endian it is sufficient to test the byte only // Is a cmpl faster? cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0); - jcc(Assembler::zero, run_compiled_code); + jccb(Assembler::zero, run_compiled_code); jmp(Address(method, methodOopDesc::interpreter_entry_offset())); bind(run_compiled_code); } diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/x86/vm/methodHandles_x86.cpp --- a/src/cpu/x86/vm/methodHandles_x86.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/x86/vm/methodHandles_x86.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -546,6 +546,28 @@ } #endif //ASSERT +void MethodHandles::jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp) { + if (JvmtiExport::can_post_interpreter_events()) { + Label run_compiled_code; + // JVMTI events, such as single-stepping, are implemented partly by avoiding running + // compiled code in threads for which the event is enabled. Check here for + // interp_only_mode if these events CAN be enabled. +#ifdef _LP64 + Register rthread = r15_thread; +#else + Register rthread = temp; + __ get_thread(rthread); +#endif + // interp_only is an int, on little endian it is sufficient to test the byte only + // Is a cmpl faster? + __ cmpb(Address(rthread, JavaThread::interp_only_mode_offset()), 0); + __ jccb(Assembler::zero, run_compiled_code); + __ jmp(Address(method, methodOopDesc::interpreter_entry_offset())); + __ bind(run_compiled_code); + } + __ jmp(Address(method, methodOopDesc::from_interpreted_offset())); +} + // Code generation address MethodHandles::generate_method_handle_interpreter_entry(MacroAssembler* _masm) { // rbx: methodOop @@ -1120,9 +1142,6 @@ guarantee(java_lang_invoke_MethodHandle::vmentry_offset_in_bytes() != 0, "must have offsets"); // some handy addresses - Address rbx_method_fie( rbx, methodOopDesc::from_interpreted_offset() ); - Address rbx_method_fce( rbx, methodOopDesc::from_compiled_offset() ); - Address rcx_mh_vmtarget( rcx_recv, java_lang_invoke_MethodHandle::vmtarget_offset_in_bytes() ); Address rcx_dmh_vmindex( rcx_recv, java_lang_invoke_DirectMethodHandle::vmindex_offset_in_bytes() ); @@ -1163,8 +1182,8 @@ assert(raise_exception_method(), "must be set"); assert(raise_exception_method()->from_compiled_entry(), "method must be linked"); - const Register rdi_pc = rax; - __ pop(rdi_pc); // caller PC + const Register rax_pc = rax; + __ pop(rax_pc); // caller PC __ mov(rsp, saved_last_sp); // cut the stack back to where the caller started Register rbx_method = rbx_temp; @@ -1172,11 +1191,15 @@ const int jobject_oop_offset = 0; __ movptr(rbx_method, Address(rbx_method, jobject_oop_offset)); // dereference the jobject - __ verify_oop(rbx_method); + + __ movptr(rsi, rsp); + __ subptr(rsp, 3 * wordSize); + __ push(rax_pc); // restore caller PC - NOT_LP64(__ push(rarg2_required)); - __ push(rdi_pc); // restore caller PC - __ jmp(rbx_method_fce); // jump to compiled entry + __ movptr(__ argument_address(constant(2)), rarg0_code); + __ movptr(__ argument_address(constant(1)), rarg1_actual); + __ movptr(__ argument_address(constant(0)), rarg2_required); + jump_from_method_handle(_masm, rbx_method, rax); } break; @@ -1195,7 +1218,7 @@ __ null_check(rcx_recv); __ verify_oop(rcx_recv); } - __ jmp(rbx_method_fie); + jump_from_method_handle(_masm, rbx_method, rax); } break; @@ -1228,7 +1251,7 @@ __ movptr(rbx_method, vtable_entry_addr); __ verify_oop(rbx_method); - __ jmp(rbx_method_fie); + jump_from_method_handle(_masm, rbx_method, rax); } break; @@ -1263,7 +1286,7 @@ no_such_interface); __ verify_oop(rbx_method); - __ jmp(rbx_method_fie); + jump_from_method_handle(_masm, rbx_method, rax); __ hlt(); __ bind(no_such_interface); @@ -1311,7 +1334,7 @@ Register rbx_method = rbx_temp; __ load_heap_oop(rbx_method, rcx_mh_vmtarget); __ verify_oop(rbx_method); - __ jmp(rbx_method_fie); + jump_from_method_handle(_masm, rbx_method, rax); } else { __ load_heap_oop(rcx_recv, rcx_mh_vmtarget); __ verify_oop(rcx_recv); diff -r 41e6ee74f879 -r e9db47a083cc src/cpu/x86/vm/methodHandles_x86.hpp --- a/src/cpu/x86/vm/methodHandles_x86.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/cpu/x86/vm/methodHandles_x86.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -291,6 +291,10 @@ "reference is a MH"); } + // Similar to InterpreterMacroAssembler::jump_from_interpreted. + // Takes care of special dispatch from single stepping too. + static void jump_from_method_handle(MacroAssembler* _masm, Register method, Register temp); + static void trace_method_handle(MacroAssembler* _masm, const char* adaptername) PRODUCT_RETURN; static Register saved_last_sp_register() { diff -r 41e6ee74f879 -r e9db47a083cc src/os/linux/vm/os_linux.cpp --- a/src/os/linux/vm/os_linux.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/os/linux/vm/os_linux.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -125,6 +125,10 @@ # include # include +#ifdef AMD64 +#include +#endif + #define MAX_PATH (2 * K) // for timer info max values which include all bits @@ -2534,7 +2538,7 @@ } void os::free_memory(char *addr, size_t bytes) { - ::madvise(addr, bytes, MADV_DONTNEED); + commit_memory(addr, bytes, false); } void os::numa_make_global(char *addr, size_t bytes) { @@ -2578,6 +2582,22 @@ return end; } + +int os::Linux::sched_getcpu_syscall(void) { + unsigned int cpu; + int retval = -1; + +#if defined(IA32) + retval = syscall(SYS_getcpu, &cpu, NULL, NULL); +#elif defined(AMD64) + typedef long (*vgetcpu_t)(unsigned int *cpu, unsigned int *node, unsigned long *tcache); + vgetcpu_t vgetcpu = (vgetcpu_t)VSYSCALL_ADDR(__NR_vgetcpu); + retval = vgetcpu(&cpu, NULL, NULL); +#endif + + return (retval == -1) ? retval : cpu; +} + // Something to do with the numa-aware allocator needs these symbols extern "C" JNIEXPORT void numa_warn(int number, char *where, ...) { } extern "C" JNIEXPORT void numa_error(char *where) { } @@ -2601,6 +2621,10 @@ set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t, dlsym(RTLD_DEFAULT, "sched_getcpu"))); + // If it's not, try a direct syscall. + if (sched_getcpu() == -1) + set_sched_getcpu(CAST_TO_FN_PTR(sched_getcpu_func_t, (void*)&sched_getcpu_syscall)); + if (sched_getcpu() != -1) { // Does it work? void *handle = dlopen("libnuma.so.1", RTLD_LAZY); if (handle != NULL) { diff -r 41e6ee74f879 -r e9db47a083cc src/os/linux/vm/os_linux.hpp --- a/src/os/linux/vm/os_linux.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/os/linux/vm/os_linux.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -263,6 +263,7 @@ static void set_numa_tonode_memory(numa_tonode_memory_func_t func) { _numa_tonode_memory = func; } static void set_numa_interleave_memory(numa_interleave_memory_func_t func) { _numa_interleave_memory = func; } static void set_numa_all_nodes(unsigned long* ptr) { _numa_all_nodes = ptr; } + static int sched_getcpu_syscall(void); public: static int sched_getcpu() { return _sched_getcpu != NULL ? _sched_getcpu() : -1; } static int numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) { diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/classfile/javaClasses.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -1019,6 +1019,16 @@ compute_offset(_ngroups_offset, k, vmSymbols::ngroups_name(), vmSymbols::int_signature()); } +oop java_lang_Throwable::unassigned_stacktrace() { + instanceKlass* ik = instanceKlass::cast(SystemDictionary::Throwable_klass()); + address addr = ik->static_field_addr(static_unassigned_stacktrace_offset); + if (UseCompressedOops) { + return oopDesc::load_decode_heap_oop((narrowOop *)addr); + } else { + return oopDesc::load_decode_heap_oop((oop*)addr); + } +} + oop java_lang_Throwable::backtrace(oop throwable) { return throwable->obj_field_acquire(backtrace_offset); } @@ -1044,9 +1054,13 @@ } +void java_lang_Throwable::set_stacktrace(oop throwable, oop st_element_array) { + throwable->obj_field_put(stackTrace_offset, st_element_array); +} + void java_lang_Throwable::clear_stacktrace(oop throwable) { assert(JDK_Version::is_gte_jdk14x_version(), "should only be called in >= 1.4"); - throwable->obj_field_put(stackTrace_offset, NULL); + set_stacktrace(throwable, NULL); } @@ -1340,6 +1354,7 @@ if (JDK_Version::is_gte_jdk14x_version()) { // New since 1.4, clear lazily constructed Java level stacktrace if // refilling occurs + // This is unnecessary in 1.7+ but harmless clear_stacktrace(throwable()); } @@ -1541,6 +1556,15 @@ // Bail-out for deep stacks if (chunk_count >= max_chunks) break; } + + // For Java 7+ we support the Throwable immutability protocol defined for Java 7. This support + // was missing in 7u0 so in 7u0 there is a workaround in the Throwable class. That workaround + // can be removed in a JDK using this JVM version + if (JDK_Version::is_gte_jdk17x_version()) { + java_lang_Throwable::set_stacktrace(throwable(), java_lang_Throwable::unassigned_stacktrace()); + assert(java_lang_Throwable::unassigned_stacktrace() != NULL, "not initialized"); + } + } @@ -2770,6 +2794,7 @@ int java_lang_Throwable::detailMessage_offset; int java_lang_Throwable::cause_offset; int java_lang_Throwable::stackTrace_offset; +int java_lang_Throwable::static_unassigned_stacktrace_offset; int java_lang_reflect_AccessibleObject::override_offset; int java_lang_reflect_Method::clazz_offset; int java_lang_reflect_Method::name_offset; @@ -2947,6 +2972,7 @@ java_lang_Throwable::detailMessage_offset = java_lang_Throwable::hc_detailMessage_offset * x + header; java_lang_Throwable::cause_offset = java_lang_Throwable::hc_cause_offset * x + header; java_lang_Throwable::stackTrace_offset = java_lang_Throwable::hc_stackTrace_offset * x + header; + java_lang_Throwable::static_unassigned_stacktrace_offset = java_lang_Throwable::hc_static_unassigned_stacktrace_offset * x; // java_lang_boxing_object java_lang_boxing_object::value_offset = java_lang_boxing_object::hc_value_offset + header; diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/classfile/javaClasses.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -393,6 +393,9 @@ hc_cause_offset = 2, // New since 1.4 hc_stackTrace_offset = 3 // New since 1.4 }; + enum { + hc_static_unassigned_stacktrace_offset = 0 // New since 1.7 + }; // Trace constants enum { trace_methods_offset = 0, @@ -406,6 +409,7 @@ static int detailMessage_offset; static int cause_offset; static int stackTrace_offset; + static int static_unassigned_stacktrace_offset; // Printing static char* print_stack_element_to_buffer(methodOop method, int bci); @@ -414,6 +418,9 @@ static void clear_stacktrace(oop throwable); // No stack trace available static const char* no_stack_trace_message(); + // Stacktrace (post JDK 1.7.0 to allow immutability protocol to be followed) + static void set_stacktrace(oop throwable, oop st_element_array); + static oop unassigned_stacktrace(); public: // Backtrace @@ -438,7 +445,6 @@ static void allocate_backtrace(Handle throwable, TRAPS); // Fill in current stack trace for throwable with preallocated backtrace (no GC) static void fill_in_stack_trace_of_preallocated_backtrace(Handle throwable); - // Fill in current stack trace, can cause GC static void fill_in_stack_trace(Handle throwable, methodHandle method, TRAPS); static void fill_in_stack_trace(Handle throwable, methodHandle method = methodHandle()); diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -1901,12 +1901,27 @@ PermanentGenerationSpec* pgs = collector_policy()->permanent_generation(); // Includes the perm-gen. - const size_t total_reserved = max_byte_size + pgs->max_size(); + // When compressed oops are enabled, the preferred heap base + // is calculated by subtracting the requested size from the + // 32Gb boundary and using the result as the base address for + // heap reservation. If the requested size is not aligned to + // HeapRegion::GrainBytes (i.e. the alignment that is passed + // into the ReservedHeapSpace constructor) then the actual + // base of the reserved heap may end up differing from the + // address that was requested (i.e. the preferred heap base). + // If this happens then we could end up using a non-optimal + // compressed oops mode. + + // Since max_byte_size is aligned to the size of a heap region (checked + // above), we also need to align the perm gen size as it might not be. + const size_t total_reserved = max_byte_size + + align_size_up(pgs->max_size(), HeapRegion::GrainBytes); + Universe::check_alignment(total_reserved, HeapRegion::GrainBytes, "g1 heap and perm"); + char* addr = Universe::preferred_heap_base(total_reserved, Universe::UnscaledNarrowOop); - ReservedSpace heap_rs(max_byte_size + pgs->max_size(), - HeapRegion::GrainBytes, - UseLargePages, addr); + ReservedHeapSpace heap_rs(total_reserved, HeapRegion::GrainBytes, + UseLargePages, addr); if (UseCompressedOops) { if (addr != NULL && !heap_rs.is_reserved()) { @@ -1914,14 +1929,17 @@ // region is taken already, for example, by 'java' launcher. // Try again to reserver heap higher. addr = Universe::preferred_heap_base(total_reserved, Universe::ZeroBasedNarrowOop); - ReservedSpace heap_rs0(total_reserved, HeapRegion::GrainBytes, - UseLargePages, addr); + + ReservedHeapSpace heap_rs0(total_reserved, HeapRegion::GrainBytes, + UseLargePages, addr); + if (addr != NULL && !heap_rs0.is_reserved()) { // Failed to reserve at specified address again - give up. addr = Universe::preferred_heap_base(total_reserved, Universe::HeapBasedNarrowOop); assert(addr == NULL, ""); - ReservedSpace heap_rs1(total_reserved, HeapRegion::GrainBytes, - UseLargePages, addr); + + ReservedHeapSpace heap_rs1(total_reserved, HeapRegion::GrainBytes, + UseLargePages, addr); heap_rs = heap_rs1; } else { heap_rs = heap_rs0; @@ -4834,6 +4852,7 @@ scan_perm_cl, i); pss.end_strong_roots(); + { double start = os::elapsedTime(); G1ParEvacuateFollowersClosure evac(_g1h, &pss, _queues, &_terminator); @@ -4890,17 +4909,29 @@ &eager_scan_code_roots, &buf_scan_perm); - // Finish up any enqueued closure apps. + // Now the ref_processor roots. + if (!_process_strong_tasks->is_task_claimed(G1H_PS_refProcessor_oops_do)) { + // We need to treat the discovered reference lists as roots and + // keep entries (which are added by the marking threads) on them + // live until they can be processed at the end of marking. + ref_processor()->weak_oops_do(&buf_scan_non_heap_roots); + ref_processor()->oops_do(&buf_scan_non_heap_roots); + } + + // Finish up any enqueued closure apps (attributed as object copy time). buf_scan_non_heap_roots.done(); buf_scan_perm.done(); + double ext_roots_end = os::elapsedTime(); + g1_policy()->reset_obj_copy_time(worker_i); - double obj_copy_time_sec = - buf_scan_non_heap_roots.closure_app_seconds() + - buf_scan_perm.closure_app_seconds(); + double obj_copy_time_sec = buf_scan_perm.closure_app_seconds() + + buf_scan_non_heap_roots.closure_app_seconds(); g1_policy()->record_obj_copy_time(worker_i, obj_copy_time_sec * 1000.0); + double ext_root_time_ms = ((ext_roots_end - ext_roots_start) - obj_copy_time_sec) * 1000.0; + g1_policy()->record_ext_root_scan_time(worker_i, ext_root_time_ms); // Scan strong roots in mark stack. @@ -4910,21 +4941,11 @@ double mark_stack_scan_ms = (os::elapsedTime() - ext_roots_end) * 1000.0; g1_policy()->record_mark_stack_scan_time(worker_i, mark_stack_scan_ms); - // XXX What should this be doing in the parallel case? - g1_policy()->record_collection_pause_end_CH_strong_roots(); // Now scan the complement of the collection set. if (scan_rs != NULL) { g1_rem_set()->oops_into_collection_set_do(scan_rs, worker_i); } - // Finish with the ref_processor roots. - if (!_process_strong_tasks->is_task_claimed(G1H_PS_refProcessor_oops_do)) { - // We need to treat the discovered reference lists as roots and - // keep entries (which are added by the marking threads) on them - // live until they can be processed at the end of marking. - ref_processor()->weak_oops_do(scan_non_heap_roots); - ref_processor()->oops_do(scan_non_heap_roots); - } - g1_policy()->record_collection_pause_end_G1_strong_roots(); + _process_strong_tasks->all_tasks_completed(); } diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -393,8 +393,7 @@ // Perform finalization stuff on all allocation regions. void retire_all_alloc_regions(); - // The number of regions allocated to hold humongous objects. - int _num_humongous_regions; + // The young region list. YoungList* _young_list; // The current policy object for the collector. diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -134,13 +134,10 @@ G1CollectorPolicy::G1CollectorPolicy() : _parallel_gc_threads(G1CollectedHeap::use_parallel_gc_threads() - ? ParallelGCThreads : 1), - + ? ParallelGCThreads : 1), _n_pauses(0), - _recent_CH_strong_roots_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), - _recent_G1_strong_roots_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), - _recent_evac_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), + _recent_rs_scan_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), _recent_pause_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), _recent_rs_sizes(new TruncatedSeq(NumPrevPausesForHeuristics)), _recent_gc_times_ms(new TruncatedSeq(NumPrevPausesForHeuristics)), @@ -1050,18 +1047,6 @@ void G1CollectorPolicy::record_concurrent_pause_end() { } -void G1CollectorPolicy::record_collection_pause_end_CH_strong_roots() { - _cur_CH_strong_roots_end_sec = os::elapsedTime(); - _cur_CH_strong_roots_dur_ms = - (_cur_CH_strong_roots_end_sec - _cur_collection_start_sec) * 1000.0; -} - -void G1CollectorPolicy::record_collection_pause_end_G1_strong_roots() { - _cur_G1_strong_roots_end_sec = os::elapsedTime(); - _cur_G1_strong_roots_dur_ms = - (_cur_G1_strong_roots_end_sec - _cur_CH_strong_roots_end_sec) * 1000.0; -} - template T sum_of(T* sum_arr, int start, int n, int N) { T sum = (T)0; @@ -1183,7 +1168,6 @@ double end_time_sec = os::elapsedTime(); double elapsed_ms = _last_pause_time_ms; bool parallel = G1CollectedHeap::use_parallel_gc_threads(); - double evac_ms = (end_time_sec - _cur_G1_strong_roots_end_sec) * 1000.0; size_t rs_size = _cur_collection_pause_used_regions_at_start - collection_set_size(); size_t cur_used_bytes = _g1->used(); @@ -1256,14 +1240,52 @@ _n_pauses++; + double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms); + double mark_stack_scan_time = avg_value(_par_last_mark_stack_scan_times_ms); + double update_rs_time = avg_value(_par_last_update_rs_times_ms); + double update_rs_processed_buffers = + sum_of_values(_par_last_update_rs_processed_buffers); + double scan_rs_time = avg_value(_par_last_scan_rs_times_ms); + double obj_copy_time = avg_value(_par_last_obj_copy_times_ms); + double termination_time = avg_value(_par_last_termination_times_ms); + + double parallel_known_time = update_rs_time + + ext_root_scan_time + + mark_stack_scan_time + + scan_rs_time + + obj_copy_time + + termination_time; + + double parallel_other_time = _cur_collection_par_time_ms - parallel_known_time; + + PauseSummary* summary = _summary; + if (update_stats) { - _recent_CH_strong_roots_times_ms->add(_cur_CH_strong_roots_dur_ms); - _recent_G1_strong_roots_times_ms->add(_cur_G1_strong_roots_dur_ms); - _recent_evac_times_ms->add(evac_ms); + _recent_rs_scan_times_ms->add(scan_rs_time); _recent_pause_times_ms->add(elapsed_ms); - _recent_rs_sizes->add(rs_size); + MainBodySummary* body_summary = summary->main_body_summary(); + guarantee(body_summary != NULL, "should not be null!"); + + if (_satb_drain_time_set) + body_summary->record_satb_drain_time_ms(_cur_satb_drain_time_ms); + else + body_summary->record_satb_drain_time_ms(0.0); + + body_summary->record_ext_root_scan_time_ms(ext_root_scan_time); + body_summary->record_mark_stack_scan_time_ms(mark_stack_scan_time); + body_summary->record_update_rs_time_ms(update_rs_time); + body_summary->record_scan_rs_time_ms(scan_rs_time); + body_summary->record_obj_copy_time_ms(obj_copy_time); + if (parallel) { + body_summary->record_parallel_time_ms(_cur_collection_par_time_ms); + body_summary->record_clear_ct_time_ms(_cur_clear_ct_time_ms); + body_summary->record_termination_time_ms(termination_time); + body_summary->record_parallel_other_time_ms(parallel_other_time); + } + body_summary->record_mark_closure_time_ms(_mark_closure_time_ms); + // We exempt parallel collection from this check because Alloc Buffer // fragmentation can produce negative collections. Same with evac // failure. @@ -1328,56 +1350,12 @@ gclog_or_tty->print_cr(" Recording collection pause(%d)", _n_pauses); } - PauseSummary* summary = _summary; - - double ext_root_scan_time = avg_value(_par_last_ext_root_scan_times_ms); - double mark_stack_scan_time = avg_value(_par_last_mark_stack_scan_times_ms); - double update_rs_time = avg_value(_par_last_update_rs_times_ms); - double update_rs_processed_buffers = - sum_of_values(_par_last_update_rs_processed_buffers); - double scan_rs_time = avg_value(_par_last_scan_rs_times_ms); - double obj_copy_time = avg_value(_par_last_obj_copy_times_ms); - double termination_time = avg_value(_par_last_termination_times_ms); - - double parallel_other_time = _cur_collection_par_time_ms - - (update_rs_time + ext_root_scan_time + mark_stack_scan_time + - scan_rs_time + obj_copy_time + termination_time); - if (update_stats) { - MainBodySummary* body_summary = summary->main_body_summary(); - guarantee(body_summary != NULL, "should not be null!"); - - if (_satb_drain_time_set) - body_summary->record_satb_drain_time_ms(_cur_satb_drain_time_ms); - else - body_summary->record_satb_drain_time_ms(0.0); - body_summary->record_ext_root_scan_time_ms(ext_root_scan_time); - body_summary->record_mark_stack_scan_time_ms(mark_stack_scan_time); - body_summary->record_update_rs_time_ms(update_rs_time); - body_summary->record_scan_rs_time_ms(scan_rs_time); - body_summary->record_obj_copy_time_ms(obj_copy_time); - if (parallel) { - body_summary->record_parallel_time_ms(_cur_collection_par_time_ms); - body_summary->record_clear_ct_time_ms(_cur_clear_ct_time_ms); - body_summary->record_termination_time_ms(termination_time); - body_summary->record_parallel_other_time_ms(parallel_other_time); - } - body_summary->record_mark_closure_time_ms(_mark_closure_time_ms); - } - if (G1PolicyVerbose > 1) { gclog_or_tty->print_cr(" ET: %10.6f ms (avg: %10.6f ms)\n" - " CH Strong: %10.6f ms (avg: %10.6f ms)\n" - " G1 Strong: %10.6f ms (avg: %10.6f ms)\n" - " Evac: %10.6f ms (avg: %10.6f ms)\n" " ET-RS: %10.6f ms (avg: %10.6f ms)\n" " |RS|: " SIZE_FORMAT, elapsed_ms, recent_avg_time_for_pauses_ms(), - _cur_CH_strong_roots_dur_ms, recent_avg_time_for_CH_strong_ms(), - _cur_G1_strong_roots_dur_ms, recent_avg_time_for_G1_strong_ms(), - evac_ms, recent_avg_time_for_evac_ms(), - scan_rs_time, - recent_avg_time_for_pauses_ms() - - recent_avg_time_for_G1_strong_ms(), + scan_rs_time, recent_avg_time_for_rs_scan_ms(), rs_size); gclog_or_tty->print_cr(" Used at start: " SIZE_FORMAT"K" @@ -1438,7 +1416,7 @@ } print_par_stats(2, "GC Worker Times", _par_last_gc_worker_times_ms); - print_stats(2, "Other", parallel_other_time); + print_stats(2, "Parallel Other", parallel_other_time); print_stats(1, "Clear CT", _cur_clear_ct_time_ms); } else { print_stats(1, "Update RS", update_rs_time); @@ -1967,38 +1945,27 @@ } double G1CollectorPolicy::recent_avg_time_for_pauses_ms() { - if (_recent_pause_times_ms->num() == 0) return (double) MaxGCPauseMillis; - else return _recent_pause_times_ms->avg(); -} - -double G1CollectorPolicy::recent_avg_time_for_CH_strong_ms() { - if (_recent_CH_strong_roots_times_ms->num() == 0) - return (double)MaxGCPauseMillis/3.0; - else return _recent_CH_strong_roots_times_ms->avg(); + if (_recent_pause_times_ms->num() == 0) { + return (double) MaxGCPauseMillis; + } + return _recent_pause_times_ms->avg(); } -double G1CollectorPolicy::recent_avg_time_for_G1_strong_ms() { - if (_recent_G1_strong_roots_times_ms->num() == 0) +double G1CollectorPolicy::recent_avg_time_for_rs_scan_ms() { + if (_recent_rs_scan_times_ms->num() == 0) { return (double)MaxGCPauseMillis/3.0; - else return _recent_G1_strong_roots_times_ms->avg(); -} - -double G1CollectorPolicy::recent_avg_time_for_evac_ms() { - if (_recent_evac_times_ms->num() == 0) return (double)MaxGCPauseMillis/3.0; - else return _recent_evac_times_ms->avg(); + } + return _recent_rs_scan_times_ms->avg(); } int G1CollectorPolicy::number_of_recent_gcs() { - assert(_recent_CH_strong_roots_times_ms->num() == - _recent_G1_strong_roots_times_ms->num(), "Sequence out of sync"); - assert(_recent_G1_strong_roots_times_ms->num() == - _recent_evac_times_ms->num(), "Sequence out of sync"); - assert(_recent_evac_times_ms->num() == + assert(_recent_rs_scan_times_ms->num() == _recent_pause_times_ms->num(), "Sequence out of sync"); assert(_recent_pause_times_ms->num() == _recent_CS_bytes_used_before->num(), "Sequence out of sync"); assert(_recent_CS_bytes_used_before->num() == _recent_CS_bytes_surviving->num(), "Sequence out of sync"); + return _recent_pause_times_ms->num(); } diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -129,15 +129,9 @@ jlong _num_cc_clears; // number of times the card count cache has been cleared #endif - double _cur_CH_strong_roots_end_sec; - double _cur_CH_strong_roots_dur_ms; - double _cur_G1_strong_roots_end_sec; - double _cur_G1_strong_roots_dur_ms; + // Statistics for recent GC pauses. See below for how indexed. + TruncatedSeq* _recent_rs_scan_times_ms; - // Statistics for recent GC pauses. See below for how indexed. - TruncatedSeq* _recent_CH_strong_roots_times_ms; - TruncatedSeq* _recent_G1_strong_roots_times_ms; - TruncatedSeq* _recent_evac_times_ms; // These exclude marking times. TruncatedSeq* _recent_pause_times_ms; TruncatedSeq* _recent_gc_times_ms; @@ -692,17 +686,11 @@ // The average time in ms per collection pause, averaged over recent pauses. double recent_avg_time_for_pauses_ms(); - // The average time in ms for processing CollectedHeap strong roots, per - // collection pause, averaged over recent pauses. - double recent_avg_time_for_CH_strong_ms(); - - // The average time in ms for processing the G1 remembered set, per - // pause, averaged over recent pauses. - double recent_avg_time_for_G1_strong_ms(); - - // The average time in ms for "evacuating followers", per pause, averaged - // over recent pauses. - double recent_avg_time_for_evac_ms(); + // The average time in ms for RS scanning, per pause, averaged + // over recent pauses. (Note the RS scanning time for a pause + // is itself an average of the RS scanning time for each worker + // thread.) + double recent_avg_time_for_rs_scan_ms(); // The number of "recent" GCs recorded in the number sequences int number_of_recent_gcs(); @@ -887,9 +875,6 @@ virtual void record_concurrent_pause(); virtual void record_concurrent_pause_end(); - virtual void record_collection_pause_end_CH_strong_roots(); - virtual void record_collection_pause_end_G1_strong_roots(); - virtual void record_collection_pause_end(); void print_heap_transition(); diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/opto/parse3.cpp --- a/src/share/vm/opto/parse3.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/opto/parse3.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -417,17 +417,10 @@ // Note: Array classes are always initialized; no is_initialized check. - enum { MAX_DIMENSION = 5 }; - if (ndimensions > MAX_DIMENSION || ndimensions <= 0) { - uncommon_trap(Deoptimization::Reason_unhandled, - Deoptimization::Action_none); - return; - } - kill_dead_locals(); // get the lengths from the stack (first dimension is on top) - Node* length[MAX_DIMENSION+1]; + Node** length = NEW_RESOURCE_ARRAY(Node*, ndimensions + 1); length[ndimensions] = NULL; // terminating null for make_runtime_call int j; for (j = ndimensions-1; j >= 0 ; j--) length[j] = pop(); @@ -470,20 +463,43 @@ address fun = NULL; switch (ndimensions) { - //case 1: Actually, there is no case 1. It's handled by new_array. + case 1: ShouldNotReachHere(); break; case 2: fun = OptoRuntime::multianewarray2_Java(); break; case 3: fun = OptoRuntime::multianewarray3_Java(); break; case 4: fun = OptoRuntime::multianewarray4_Java(); break; case 5: fun = OptoRuntime::multianewarray5_Java(); break; - default: ShouldNotReachHere(); }; + Node* c = NULL; - Node* c = make_runtime_call(RC_NO_LEAF | RC_NO_IO, - OptoRuntime::multianewarray_Type(ndimensions), - fun, NULL, TypeRawPtr::BOTTOM, - makecon(TypeKlassPtr::make(array_klass)), - length[0], length[1], length[2], - length[3], length[4]); + if (fun != NULL) { + c = make_runtime_call(RC_NO_LEAF | RC_NO_IO, + OptoRuntime::multianewarray_Type(ndimensions), + fun, NULL, TypeRawPtr::BOTTOM, + makecon(TypeKlassPtr::make(array_klass)), + length[0], length[1], length[2], + length[3], length[4]); + } else { + // Create a java array for dimension sizes + Node* dims = NULL; + { PreserveReexecuteState preexecs(this); + _sp += ndimensions; + Node* dims_array_klass = makecon(TypeKlassPtr::make(ciArrayKlass::make(ciType::make(T_INT)))); + dims = new_array(dims_array_klass, intcon(ndimensions), 0); + + // Fill-in it with values + for (j = 0; j < ndimensions; j++) { + Node *dims_elem = array_element_address(dims, intcon(j), T_INT); + store_to_memory(control(), dims_elem, length[j], T_INT, TypeAryPtr::INTS); + } + } + + c = make_runtime_call(RC_NO_LEAF | RC_NO_IO, + OptoRuntime::multianewarrayN_Type(), + OptoRuntime::multianewarrayN_Java(), NULL, TypeRawPtr::BOTTOM, + makecon(TypeKlassPtr::make(array_klass)), + dims); + } + Node* res = _gvn.transform(new (C, 1) ProjNode(c, TypeFunc::Parms)); const Type* type = TypeOopPtr::make_from_klass_raw(array_klass); @@ -496,7 +512,7 @@ if (ltype != NULL) type = type->is_aryptr()->cast_to_size(ltype); - // We cannot sharpen the nested sub-arrays, since the top level is mutable. + // We cannot sharpen the nested sub-arrays, since the top level is mutable. Node* cast = _gvn.transform( new (C, 2) CheckCastPPNode(control(), res, type) ); push(cast); diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/opto/runtime.cpp --- a/src/share/vm/opto/runtime.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/opto/runtime.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -106,6 +106,7 @@ address OptoRuntime::_multianewarray3_Java = NULL; address OptoRuntime::_multianewarray4_Java = NULL; address OptoRuntime::_multianewarray5_Java = NULL; +address OptoRuntime::_multianewarrayN_Java = NULL; address OptoRuntime::_g1_wb_pre_Java = NULL; address OptoRuntime::_g1_wb_post_Java = NULL; address OptoRuntime::_vtable_must_compile_Java = NULL; @@ -154,6 +155,7 @@ gen(env, _multianewarray3_Java , multianewarray3_Type , multianewarray3_C , 0 , true , false, false); gen(env, _multianewarray4_Java , multianewarray4_Type , multianewarray4_C , 0 , true , false, false); gen(env, _multianewarray5_Java , multianewarray5_Type , multianewarray5_C , 0 , true , false, false); + gen(env, _multianewarrayN_Java , multianewarrayN_Type , multianewarrayN_C , 0 , true , false, false); gen(env, _g1_wb_pre_Java , g1_wb_pre_Type , SharedRuntime::g1_wb_pre , 0 , false, false, false); gen(env, _g1_wb_post_Java , g1_wb_post_Type , SharedRuntime::g1_wb_post , 0 , false, false, false); gen(env, _complete_monitor_locking_Java , complete_monitor_enter_Type , SharedRuntime::complete_monitor_locking_C , 0 , false, false, false); @@ -374,6 +376,24 @@ thread->set_vm_result(obj); JRT_END +JRT_ENTRY(void, OptoRuntime::multianewarrayN_C(klassOopDesc* elem_type, arrayOopDesc* dims, JavaThread *thread)) + assert(check_compiled_frame(thread), "incorrect caller"); + assert(oop(elem_type)->is_klass(), "not a class"); + assert(oop(dims)->is_typeArray(), "not an array"); + + ResourceMark rm; + jint len = dims->length(); + assert(len > 0, "Dimensions array should contain data"); + jint *j_dims = typeArrayOop(dims)->int_at_addr(0); + jint *c_dims = NEW_RESOURCE_ARRAY(jint, len); + Copy::conjoint_jints_atomic(j_dims, c_dims, len); + + oop obj = arrayKlass::cast(elem_type)->multi_allocate(len, c_dims, THREAD); + deoptimize_caller_frame(thread, HAS_PENDING_EXCEPTION); + thread->set_vm_result(obj); +JRT_END + + const TypeFunc *OptoRuntime::new_instance_Type() { // create input type (domain) const Type **fields = TypeTuple::fields(1); @@ -454,6 +474,21 @@ return multianewarray_Type(5); } +const TypeFunc *OptoRuntime::multianewarrayN_Type() { + // create input type (domain) + const Type **fields = TypeTuple::fields(2); + fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // element klass + fields[TypeFunc::Parms+1] = TypeInstPtr::NOTNULL; // array of dim sizes + const TypeTuple *domain = TypeTuple::make(TypeFunc::Parms+2, fields); + + // create result type (range) + fields = TypeTuple::fields(1); + fields[TypeFunc::Parms+0] = TypeRawPtr::NOTNULL; // Returned oop + const TypeTuple *range = TypeTuple::make(TypeFunc::Parms+1, fields); + + return TypeFunc::make(domain, range); +} + const TypeFunc *OptoRuntime::g1_wb_pre_Type() { const Type **fields = TypeTuple::fields(2); fields[TypeFunc::Parms+0] = TypeInstPtr::NOTNULL; // original field value diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/opto/runtime.hpp --- a/src/share/vm/opto/runtime.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/opto/runtime.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -118,6 +118,7 @@ static address _multianewarray3_Java; static address _multianewarray4_Java; static address _multianewarray5_Java; + static address _multianewarrayN_Java; static address _g1_wb_pre_Java; static address _g1_wb_post_Java; static address _vtable_must_compile_Java; @@ -153,6 +154,7 @@ static void multianewarray3_C(klassOopDesc* klass, int len1, int len2, int len3, JavaThread *thread); static void multianewarray4_C(klassOopDesc* klass, int len1, int len2, int len3, int len4, JavaThread *thread); static void multianewarray5_C(klassOopDesc* klass, int len1, int len2, int len3, int len4, int len5, JavaThread *thread); + static void multianewarrayN_C(klassOopDesc* klass, arrayOopDesc* dims, JavaThread *thread); static void g1_wb_pre_C(oopDesc* orig, JavaThread* thread); static void g1_wb_post_C(void* card_addr, JavaThread* thread); @@ -210,6 +212,7 @@ static address multianewarray3_Java() { return _multianewarray3_Java; } static address multianewarray4_Java() { return _multianewarray4_Java; } static address multianewarray5_Java() { return _multianewarray5_Java; } + static address multianewarrayN_Java() { return _multianewarrayN_Java; } static address g1_wb_pre_Java() { return _g1_wb_pre_Java; } static address g1_wb_post_Java() { return _g1_wb_post_Java; } static address vtable_must_compile_stub() { return _vtable_must_compile_Java; } @@ -249,6 +252,7 @@ static const TypeFunc* multianewarray3_Type(); // multianewarray static const TypeFunc* multianewarray4_Type(); // multianewarray static const TypeFunc* multianewarray5_Type(); // multianewarray + static const TypeFunc* multianewarrayN_Type(); // multianewarray static const TypeFunc* g1_wb_pre_Type(); static const TypeFunc* g1_wb_post_Type(); static const TypeFunc* complete_monitor_enter_Type(); diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/prims/jvmtiTagMap.cpp --- a/src/share/vm/prims/jvmtiTagMap.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/prims/jvmtiTagMap.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -1647,6 +1647,7 @@ // saved headers static GrowableArray* _saved_oop_stack; static GrowableArray* _saved_mark_stack; + static bool _needs_reset; // do we need to reset mark bits? public: static void init(); // initialize @@ -1654,10 +1655,14 @@ static inline void mark(oop o); // mark an object static inline bool visited(oop o); // check if object has been visited + + static inline bool needs_reset() { return _needs_reset; } + static inline void set_needs_reset(bool v) { _needs_reset = v; } }; GrowableArray* ObjectMarker::_saved_oop_stack = NULL; GrowableArray* ObjectMarker::_saved_mark_stack = NULL; +bool ObjectMarker::_needs_reset = true; // need to reset mark bits by default // initialize ObjectMarker - prepares for object marking void ObjectMarker::init() { @@ -1680,7 +1685,13 @@ // iterate over all objects and restore the mark bits to // their initial value RestoreMarksClosure blk; - Universe::heap()->object_iterate(&blk); + if (needs_reset()) { + Universe::heap()->object_iterate(&blk); + } else { + // We don't need to reset mark bits on this call, but reset the + // flag to the default for the next call. + set_needs_reset(true); + } // When sharing is enabled we need to restore the headers of the objects // in the readwrite space too. @@ -3023,7 +3034,8 @@ } -// collects all simple (non-stack) roots. +// Collects all simple (non-stack) roots except for threads; +// threads are handled in collect_stack_roots() as an optimization. // if there's a heap root callback provided then the callback is // invoked for each simple root. // if an object reference callback is provided then all simple @@ -3054,16 +3066,7 @@ return false; } - // Threads - for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) { - oop threadObj = thread->threadObj(); - if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) { - bool cont = CallbackInvoker::report_simple_root(JVMTI_HEAP_REFERENCE_THREAD, threadObj); - if (!cont) { - return false; - } - } - } + // threads are now handled in collect_stack_roots() // Other kinds of roots maintained by HotSpot // Many of these won't be visible but others (such as instances of important @@ -3175,13 +3178,20 @@ } -// collects all stack roots - for each thread it walks the execution +// Collects the simple roots for all threads and collects all +// stack roots - for each thread it walks the execution // stack to find all references and local JNI refs. inline bool VM_HeapWalkOperation::collect_stack_roots() { JNILocalRootsClosure blk; for (JavaThread* thread = Threads::first(); thread != NULL ; thread = thread->next()) { oop threadObj = thread->threadObj(); if (threadObj != NULL && !thread->is_exiting() && !thread->is_hidden_from_external_view()) { + // Collect the simple root for this thread before we + // collect its stack roots + if (!CallbackInvoker::report_simple_root(JVMTI_HEAP_REFERENCE_THREAD, + threadObj)) { + return false; + } if (!collect_stack_roots(thread, &blk)) { return false; } @@ -3235,8 +3245,20 @@ // the heap walk starts with an initial object or the heap roots if (initial_object().is_null()) { + // If either collect_stack_roots() or collect_simple_roots() + // returns false at this point, then there are no mark bits + // to reset. + ObjectMarker::set_needs_reset(false); + + // Calling collect_stack_roots() before collect_simple_roots() + // can result in a big performance boost for an agent that is + // focused on analyzing references in the thread stacks. + if (!collect_stack_roots()) return; + if (!collect_simple_roots()) return; - if (!collect_stack_roots()) return; + + // no early return so enable heap traversal to reset the mark bits + ObjectMarker::set_needs_reset(true); } else { visit_stack()->push(initial_object()()); } diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/runtime/globals.hpp Thu Aug 11 14:58:29 2011 +0100 @@ -501,6 +501,9 @@ product(intx, UseSSE, 99, \ "Highest supported SSE instructions set on x86/x64") \ \ + product(intx, UseVIS, 99, \ + "Highest supported VIS instructions set on Sparc") \ + \ product(uintx, LargePageSizeInBytes, 0, \ "Large page size (0 to let VM choose the page size") \ \ diff -r 41e6ee74f879 -r e9db47a083cc src/share/vm/runtime/virtualspace.cpp --- a/src/share/vm/runtime/virtualspace.cpp Tue Aug 02 14:37:35 2011 +0100 +++ b/src/share/vm/runtime/virtualspace.cpp Thu Aug 11 14:58:29 2011 +0100 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -68,7 +68,7 @@ assert(len >= required_size, "len too small"); const size_t s = size_t(addr); - const size_t beg_ofs = s + prefix_size & suffix_align - 1; + const size_t beg_ofs = (s + prefix_size) & (suffix_align - 1); const size_t beg_delta = beg_ofs == 0 ? 0 : suffix_align - beg_ofs; if (len < beg_delta + required_size) { @@ -113,8 +113,8 @@ assert(res >= raw, "alignment decreased start addr"); assert(res + prefix_size + suffix_size <= raw + reserve_size, "alignment increased end addr"); - assert((res & prefix_align - 1) == 0, "bad alignment of prefix"); - assert((res + prefix_size & suffix_align - 1) == 0, + assert((res & (prefix_align - 1)) == 0, "bad alignment of prefix"); + assert(((res + prefix_size) & (suffix_align - 1)) == 0, "bad alignment of suffix"); } #endif @@ -135,7 +135,7 @@ assert(UseCompressedOops, "currently requested address used only for compressed oops"); if (PrintCompressedOopsMode) { tty->cr(); - tty->print_cr("Reserved memory at not requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); + tty->print_cr("Reserved memory not at requested address: " PTR_FORMAT " vs " PTR_FORMAT, base, requested_address); } // OS ignored requested address. Try different address. if (special) { @@ -162,11 +162,11 @@ assert(prefix_align != 0, "sanity"); assert(suffix_size != 0, "sanity"); assert(suffix_align != 0, "sanity"); - assert((prefix_size & prefix_align - 1) == 0, + assert((prefix_size & (prefix_align - 1)) == 0, "prefix_size not divisible by prefix_align"); - assert((suffix_size & suffix_align - 1) == 0, + assert((suffix_size & (suffix_align - 1)) == 0, "suffix_size not divisible by suffix_align"); - assert((suffix_align & prefix_align - 1) == 0, + assert((suffix_align & (prefix_align - 1)) == 0, "suffix_align not divisible by prefix_align"); // Assert that if noaccess_prefix is used, it is the same as prefix_align. @@ -210,8 +210,8 @@ if (addr == NULL) return; // Check whether the result has the needed alignment (unlikely unless - // prefix_align == suffix_align). - const size_t ofs = size_t(addr) + adjusted_prefix_size & suffix_align - 1; + // prefix_align < suffix_align). + const size_t ofs = (size_t(addr) + adjusted_prefix_size) & (suffix_align - 1); if (ofs != 0) { // Wrong alignment. Release, allocate more space and do manual alignment. // @@ -232,6 +232,15 @@ addr = reserve_and_align(size + suffix_align, adjusted_prefix_size, prefix_align, suffix_size, suffix_align); } + + if (requested_address != 0 && + failed_to_reserve_as_requested(addr, requested_address, size, false)) { + // As a result of the alignment constraints, the allocated addr differs + // from the requested address. Return back to the caller who can + // take remedial action (like try again without a requested address). + assert(_base == NULL, "should be"); + return; + } } _base = addr; @@ -245,13 +254,19 @@ const size_t noaccess_prefix, bool executable) { const size_t granularity = os::vm_allocation_granularity(); - assert((size & granularity - 1) == 0, + assert((size & (granularity - 1)) == 0, "size not aligned to os::vm_allocation_granularity()"); - assert((alignment & granularity - 1) == 0, + assert((alignment & (granularity - 1)) == 0, "alignment not aligned to os::vm_allocation_granularity()"); assert(alignment == 0 || is_power_of_2((intptr_t)alignment), "not a power of 2"); + alignment = MAX2(alignment, (size_t)os::vm_page_size()); + + // Assert that if noaccess_prefix is used, it is the same as alignment. + assert(noaccess_prefix == 0 || + noaccess_prefix == alignment, "noaccess prefix wrong"); + _base = NULL; _size = 0; _special = false; @@ -282,10 +297,8 @@ return; } // Check alignment constraints - if (alignment > 0) { - assert((uintptr_t) base % alignment == 0, - "Large pages returned a non-aligned address"); - } + assert((uintptr_t) base % alignment == 0, + "Large pages returned a non-aligned address"); _special = true; } else { // failed; try to reserve regular memory below @@ -321,7 +334,7 @@ if (base == NULL) return; // Check alignment constraints - if (alignment > 0 && ((size_t)base & alignment - 1) != 0) { + if ((((size_t)base + noaccess_prefix) & (alignment - 1)) != 0) { // Base not aligned, retry if (!os::release_memory(base, size)) fatal("os::release_memory failed"); // Reserve size large enough to do manual alignment and @@ -338,12 +351,21 @@ os::release_memory(extra_base, extra_size); base = os::reserve_memory(size, base); } while (base == NULL); + + if (requested_address != 0 && + failed_to_reserve_as_requested(base, requested_address, size, false)) { + // As a result of the alignment constraints, the allocated base differs + // from the requested address. Return back to the caller who can + // take remedial action (like try again without a requested address). + assert(_base == NULL, "should be"); + return; + } } } // Done _base = base; _size = size; - _alignment = MAX2(alignment, (size_t) os::vm_page_size()); + _alignment = alignment; _noaccess_prefix = noaccess_prefix; // Assert that if noaccess_prefix is used, it is the same as alignment. diff -r 41e6ee74f879 -r e9db47a083cc test/compiler/6990212/Test6990212.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6990212/Test6990212.java Thu Aug 11 14:58:29 2011 +0100 @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +/** + * @test + * @bug 6990212 + * @summary JSR 292 JVMTI MethodEnter hook is not called for JSR 292 bootstrap and target methods + * + * @run main Test6990212 + */ + +import java.lang.invoke.*; + +interface intf { + public Object target(); +} + +public class Test6990212 implements intf { + public Object target() { + return null; + } + + public static void main(String[] args) throws Throwable { + // Build an interface invoke and then invoke it on something + // that doesn't implement the interface to test the + // raiseException path. + MethodHandle target = MethodHandles.lookup().findVirtual(intf.class, "target", MethodType.methodType(Object.class)); + try { + target.invoke(new Object()); + } catch (ClassCastException cce) { + // everything is ok + System.out.println("got expected ClassCastException"); + } + } +} diff -r 41e6ee74f879 -r e9db47a083cc test/compiler/7052494/Test7052494.java --- a/test/compiler/7052494/Test7052494.java Tue Aug 02 14:37:35 2011 +0100 +++ b/test/compiler/7052494/Test7052494.java Thu Aug 11 14:58:29 2011 +0100 @@ -70,18 +70,24 @@ } // Empty loop rolls through MAXINT if i > 0 + + static final int limit5 = Integer.MIN_VALUE + 10000; + static int test5(int i) { int result = 0; - while (i++ != 0) { + while (i++ != limit5) { result = i*2; } return result; } // Empty loop rolls through MININT if i < 0 + + static final int limit6 = Integer.MAX_VALUE - 10000; + static int test6(int i) { int result = 0; - while (i-- != 0) { + while (i-- != limit6) { result = i*2; } return result; @@ -92,6 +98,7 @@ int[] arr = new int[8]; int[] ar3 = { 0, 0, 4, 6, 8, 10, 0, 0 }; int[] ar4 = { 0, 0, 0, -10, -8, -6, -4, 0 }; + System.out.println("test1"); for (int i = 0; i < 11000; i++) { int k = test1(1, 10); if (k != 10) { @@ -100,6 +107,7 @@ break; } } + System.out.println("test2"); for (int i = 0; i < 11000; i++) { int k = test2(-1, -10); if (k != -10) { @@ -108,6 +116,7 @@ break; } } + System.out.println("test3"); for (int i = 0; i < 11000; i++) { java.util.Arrays.fill(arr, 0); test3(1, 10, arr); @@ -124,6 +133,7 @@ break; } } + System.out.println("test4"); for (int i = 0; i < 11000; i++) { java.util.Arrays.fill(arr, 0); test4(-1, -10, arr); @@ -140,22 +150,25 @@ break; } } + System.out.println("test5"); for (int i = 0; i < 11000; i++) { - int k = test5(1); - if (k != 0) { - System.out.println("FAILED: " + k + " != 0"); + int k = test5(limit6); + if (k != limit5*2) { + System.out.println("FAILED: " + k + " != " + limit5*2); failed = true; break; } } + System.out.println("test6"); for (int i = 0; i < 11000; i++) { - int k = test6(-1); - if (k != 0) { - System.out.println("FAILED: " + k + " != 0"); + int k = test6(limit5); + if (k != limit6*2) { + System.out.println("FAILED: " + k + " != " + limit6*2); failed = true; break; } } + System.out.println("finish"); if (failed) System.exit(97); }