# HG changeset patch # User kvn # Date 1323368853 28800 # Node ID 81f7362f7bed0bddc23a6e6e5620866f6f012fd3 # Parent 55d777c0860a83a522f561ab0e4b05f7289330b0# Parent f745b2be37375f5c54d5b6c1b95fbfcf24e21aa3 Merge diff -r 55d777c0860a -r 81f7362f7bed make/jprt.properties --- a/make/jprt.properties Wed Dec 07 07:27:09 2011 -0800 +++ b/make/jprt.properties Thu Dec 08 10:27:33 2011 -0800 @@ -248,7 +248,7 @@ jprt.my.solaris.sparc.test.targets= \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.sparc}-product-{c1|c2}-runThese, \ ${jprt.my.solaris.sparc}-fastdebug-c1-runThese_Xshare, \ @@ -267,7 +267,7 @@ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_G1, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_default, \ - ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jbb_default_tiered, \ + ${jprt.my.solaris.sparc}-{product|fastdebug}-c2-jbb_default_nontiered, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_SerialGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.solaris.sparc}-{product|fastdebug}-{c1|c2}-jbb_CMS, \ @@ -276,7 +276,7 @@ jprt.my.solaris.sparcv9.test.targets= \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-scimark, \ ${jprt.my.solaris.sparcv9}-product-c2-runThese, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCBasher_default, \ @@ -294,7 +294,7 @@ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default, \ - ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default_tiered, \ + ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_default_nontiered, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.solaris.sparcv9}-{product|fastdebug}-c2-jbb_CMS, \ @@ -303,7 +303,7 @@ jprt.my.solaris.x64.test.targets= \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-scimark, \ ${jprt.my.solaris.x64}-product-c2-runThese, \ ${jprt.my.solaris.x64}-product-c2-runThese_Xcomp, \ @@ -322,7 +322,7 @@ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default, \ - ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default_tiered, \ + ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_SerialGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.solaris.x64}-{product|fastdebug}-c2-GCOld_CMS, \ @@ -331,7 +331,7 @@ jprt.my.solaris.i586.test.targets= \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.solaris.i586}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.solaris.i586}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.solaris.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.solaris.i586}-product-{c1|c2}-runThese_Xcomp, \ ${jprt.my.solaris.i586}-fastdebug-c1-runThese_Xcomp, \ @@ -358,7 +358,7 @@ ${jprt.my.solaris.i586}-product-c1-GCOld_G1, \ ${jprt.my.solaris.i586}-product-c1-GCOld_ParOldGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default, \ - ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default_tiered, \ + ${jprt.my.solaris.i586}-fastdebug-c2-jbb_default_nontiered, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_ParallelGC, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_CMS, \ ${jprt.my.solaris.i586}-fastdebug-c2-jbb_G1, \ @@ -366,7 +366,7 @@ jprt.my.linux.i586.test.targets = \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.linux.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.linux.i586}-product-c1-runThese_Xcomp, \ ${jprt.my.linux.i586}-fastdebug-c1-runThese_Xshare, \ @@ -386,7 +386,7 @@ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_G1, \ ${jprt.my.linux.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_default, \ - ${jprt.my.linux.i586}-{product|fastdebug}-c2-jbb_default_tiered, \ + ${jprt.my.linux.i586}-{product|fastdebug}-c2-jbb_default_nontiered, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_ParallelGC, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_CMS, \ ${jprt.my.linux.i586}-{product|fastdebug}-c1-jbb_G1, \ @@ -394,7 +394,7 @@ jprt.my.linux.x64.test.targets = \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-scimark, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_default, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCBasher_SerialGC, \ @@ -411,14 +411,14 @@ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default, \ - ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default_tiered, \ + ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParallelGC, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_G1, \ ${jprt.my.linux.x64}-{product|fastdebug}-c2-jbb_ParOldGC jprt.my.windows.i586.test.targets = \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jvm98, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.windows.i586}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-scimark, \ ${jprt.my.windows.i586}-product-{c1|c2}-runThese, \ ${jprt.my.windows.i586}-product-{c1|c2}-runThese_Xcomp, \ @@ -438,7 +438,7 @@ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_G1, \ ${jprt.my.windows.i586}-product-{c1|c2}-GCOld_ParOldGC, \ ${jprt.my.windows.i586}-{product|fastdebug}-{c1|c2}-jbb_default, \ - ${jprt.my.windows.i586}-{product|fastdebug}-c2-jbb_default_tiered, \ + ${jprt.my.windows.i586}-{product|fastdebug}-c2-jbb_default_nontiered, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_ParallelGC, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_CMS, \ ${jprt.my.windows.i586}-product-{c1|c2}-jbb_G1, \ @@ -446,7 +446,7 @@ jprt.my.windows.x64.test.targets = \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98_tiered, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-jvm98_nontiered, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-scimark, \ ${jprt.my.windows.x64}-product-c2-runThese, \ ${jprt.my.windows.x64}-product-c2-runThese_Xcomp, \ @@ -465,7 +465,7 @@ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_G1, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-GCOld_ParOldGC, \ ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default, \ - ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default_tiered, \ + ${jprt.my.windows.x64}-{product|fastdebug}-c2-jbb_default_nontiered, \ ${jprt.my.windows.x64}-product-c2-jbb_CMS, \ ${jprt.my.windows.x64}-product-c2-jbb_ParallelGC, \ ${jprt.my.windows.x64}-product-c2-jbb_G1, \ @@ -473,9 +473,9 @@ # Some basic "smoke" tests for OpenJDK builds jprt.test.targets.open = \ - ${jprt.my.solaris.x64}-{productOpen|debugOpen|fastdebugOpen}-c2-jvm98_tiered, \ - ${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98_tiered, \ - ${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98_tiered + ${jprt.my.solaris.x64}-{productOpen|debugOpen|fastdebugOpen}-c2-jvm98, \ + ${jprt.my.solaris.i586}-{productOpen|fastdebugOpen}-c2-jvm98, \ + ${jprt.my.linux.x64}-{productOpen|fastdebugOpen}-c2-jvm98 # Testing for actual embedded builds is different to standard jprt.my.linux.i586.test.targets.embedded = \ diff -r 55d777c0860a -r 81f7362f7bed src/cpu/sparc/vm/assembler_sparc.hpp --- a/src/cpu/sparc/vm/assembler_sparc.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/sparc/vm/assembler_sparc.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -855,12 +855,6 @@ Lookaside = 1 << 4 }; - // test if x is within signed immediate range for nbits - static bool is_simm(intptr_t x, int nbits) { return -( intptr_t(1) << nbits-1 ) <= x && x < ( intptr_t(1) << nbits-1 ); } - - // test if -4096 <= x <= 4095 - static bool is_simm13(intptr_t x) { return is_simm(x, 13); } - static bool is_in_wdisp_range(address a, address b, int nbits) { intptr_t d = intptr_t(b) - intptr_t(a); return is_simm(d, nbits + 2); @@ -1203,7 +1197,7 @@ if (!UseCBCond || cbcond_before()) return false; intptr_t x = intptr_t(target_distance(L)) - intptr_t(pc()); assert( (x & 3) == 0, "not word aligned"); - return is_simm(x, 12); + return is_simm12(x); } // Tells assembler you know that next instruction is delayed diff -r 55d777c0860a -r 81f7362f7bed src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -765,7 +765,7 @@ void LIR_Assembler::vtable_call(LIR_OpJavaCall* op) { add_debug_info_for_null_check_here(op->info()); __ load_klass(O0, G3_scratch); - if (__ is_simm13(op->vtable_offset())) { + if (Assembler::is_simm13(op->vtable_offset())) { __ ld_ptr(G3_scratch, op->vtable_offset(), G5_method); } else { // This will generate 2 instructions diff -r 55d777c0860a -r 81f7362f7bed src/cpu/sparc/vm/c2_globals_sparc.hpp --- a/src/cpu/sparc/vm/c2_globals_sparc.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -42,7 +42,7 @@ #else define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP -define_pd_global(bool, TieredCompilation, false); +define_pd_global(bool, TieredCompilation, true); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 140000); diff -r 55d777c0860a -r 81f7362f7bed src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -315,7 +315,7 @@ __ cmp_and_br_short(O7_temp, T_VOID, Assembler::equal, Assembler::pt, L_ok_4); extract_conversion_vminfo(_masm, L5_conversion, O5_temp); __ ld_ptr(L4_saved_args_base, __ argument_offset(O5_temp, O5_temp), O7_temp); - assert(__ is_simm13(RETURN_VALUE_PLACEHOLDER), "must be simm13"); + assert(Assembler::is_simm13(RETURN_VALUE_PLACEHOLDER), "must be simm13"); __ cmp_and_brx_short(O7_temp, (int32_t) RETURN_VALUE_PLACEHOLDER, Assembler::equal, Assembler::pt, L_ok_4); __ stop("damaged ricochet frame: RETURN_VALUE_PLACEHOLDER not found"); __ BIND(L_ok_4); diff -r 55d777c0860a -r 81f7362f7bed src/cpu/sparc/vm/sharedRuntime_sparc.cpp --- a/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/sparc/vm/sharedRuntime_sparc.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -767,7 +767,7 @@ // In the 64bit build because of wider slots and STACKBIAS we can run // out of bits in the displacement to do loads and stores. Use g3 as // temporary displacement. - if (! __ is_simm13(extraspace)) { + if (!Assembler::is_simm13(extraspace)) { __ set(extraspace, G3_scratch); __ sub(SP, G3_scratch, SP); } else { diff -r 55d777c0860a -r 81f7362f7bed src/cpu/sparc/vm/sparc.ad --- a/src/cpu/sparc/vm/sparc.ad Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/sparc/vm/sparc.ad Thu Dec 08 10:27:33 2011 -0800 @@ -566,7 +566,7 @@ } else { klass_load_size = 1*BytesPerInstWord; } - if( Assembler::is_simm13(v_off) ) { + if (Assembler::is_simm13(v_off)) { return klass_load_size + (2*BytesPerInstWord + // ld_ptr, ld_ptr NativeCall::instruction_size); // call; delay slot @@ -1019,8 +1019,21 @@ //============================================================================= -const bool Matcher::constant_table_absolute_addressing = false; -const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask; +const RegMask& MachConstantBaseNode::_out_RegMask = PTR_REG_mask(); + +int Compile::ConstantTable::calculate_table_base_offset() const { + if (UseRDPCForConstantTableBase) { + // The table base offset might be less but then it fits into + // simm13 anyway and we are good (cf. MachConstantBaseNode::emit). + return Assembler::min_simm13(); + } else { + int offset = -(size() / 2); + if (!Assembler::is_simm13(offset)) { + offset = Assembler::min_simm13(); + } + return offset; + } +} void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { Compile* C = ra_->C; @@ -1028,8 +1041,9 @@ MacroAssembler _masm(&cbuf); Register r = as_Register(ra_->get_encode(this)); - CodeSection* cs = __ code()->consts(); - int consts_size = cs->align_at_start(cs->size()); + CodeSection* consts_section = __ code()->consts(); + int consts_size = consts_section->align_at_start(consts_section->size()); + assert(constant_table.size() == consts_size, err_msg("must be: %d == %d", constant_table.size(), consts_size)); if (UseRDPCForConstantTableBase) { // For the following RDPC logic to work correctly the consts @@ -1037,30 +1051,37 @@ // assert checks for that. The layout and the SECT_* constants // are defined in src/share/vm/asm/codeBuffer.hpp. assert(CodeBuffer::SECT_CONSTS + 1 == CodeBuffer::SECT_INSTS, "must be"); - int offset = __ offset(); + int insts_offset = __ offset(); + + // Layout: + // + // |----------- consts section ------------|----------- insts section -----------... + // |------ constant table -----|- padding -|------------------x---- + // \ current PC (RDPC instruction) + // |<------------- consts_size ----------->|<- insts_offset ->| + // \ table base + // The table base offset is later added to the load displacement + // so it has to be negative. + int table_base_offset = -(consts_size + insts_offset); int disp; // If the displacement from the current PC to the constant table // base fits into simm13 we set the constant table base to the // current PC. - if (__ is_simm13(-(consts_size + offset))) { - constant_table.set_table_base_offset(-(consts_size + offset)); + if (Assembler::is_simm13(table_base_offset)) { + constant_table.set_table_base_offset(table_base_offset); disp = 0; } else { - // If the offset of the top constant (last entry in the table) - // fits into simm13 we set the constant table base to the actual - // table base. - if (__ is_simm13(constant_table.top_offset())) { - constant_table.set_table_base_offset(0); - disp = consts_size + offset; - } else { - // Otherwise we set the constant table base in the middle of the - // constant table. - int half_consts_size = consts_size / 2; - assert(half_consts_size * 2 == consts_size, "sanity"); - constant_table.set_table_base_offset(-half_consts_size); // table base offset gets added to the load displacement. - disp = half_consts_size + offset; - } + // Otherwise we set the constant table base offset to the + // maximum negative displacement of load instructions to keep + // the disp as small as possible: + // + // |<------------- consts_size ----------->|<- insts_offset ->| + // |<--------- min_simm13 --------->|<-------- disp --------->| + // \ table base + table_base_offset = Assembler::min_simm13(); + constant_table.set_table_base_offset(table_base_offset); + disp = (consts_size + insts_offset) + table_base_offset; } __ rdpc(r); @@ -1072,8 +1093,7 @@ } else { // Materialize the constant table base. - assert(constant_table.size() == consts_size, err_msg("must be: %d == %d", constant_table.size(), consts_size)); - address baseaddr = cs->start() + -(constant_table.table_base_offset()); + address baseaddr = consts_section->start() + -(constant_table.table_base_offset()); RelocationHolder rspec = internal_word_Relocation::spec(baseaddr); AddressLiteral base(baseaddr, rspec); __ set(base, r); @@ -1169,6 +1189,13 @@ __ save(SP, G3, SP); } C->set_frame_complete( __ offset() ); + + if (!UseRDPCForConstantTableBase && C->has_mach_constant_base_node()) { + // NOTE: We set the table base offset here because users might be + // emitted before MachConstantBaseNode. + Compile::ConstantTable& constant_table = C->constant_table(); + constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); + } } uint MachPrologNode::size(PhaseRegAlloc *ra_) const { @@ -1843,7 +1870,7 @@ bool Matcher::is_short_branch_offset(int rule, int br_size, int offset) { // The passed offset is relative to address of the branch. // Don't need to adjust the offset. - return UseCBCond && Assembler::is_simm(offset, 12); + return UseCBCond && Assembler::is_simm12(offset); } const bool Matcher::isSimpleConstant64(jlong value) { @@ -1997,7 +2024,7 @@ } const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return L7_REGP_mask; + return L7_REGP_mask(); } %} @@ -2072,8 +2099,8 @@ %} enc_class form3_mem_reg_long_unaligned_marshal( memory mem, iRegL reg ) %{ - assert( Assembler::is_simm13($mem$$disp ), "need disp and disp+4" ); - assert( Assembler::is_simm13($mem$$disp+4), "need disp and disp+4" ); + assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4"); + assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4"); guarantee($mem$$index == R_G0_enc, "double index?"); emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp+4, R_G0_enc, R_O7_enc ); emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg ); @@ -2082,8 +2109,8 @@ %} enc_class form3_mem_reg_double_unaligned( memory mem, RegD_low reg ) %{ - assert( Assembler::is_simm13($mem$$disp ), "need disp and disp+4" ); - assert( Assembler::is_simm13($mem$$disp+4), "need disp and disp+4" ); + assert(Assembler::is_simm13($mem$$disp ), "need disp and disp+4"); + assert(Assembler::is_simm13($mem$$disp+4), "need disp and disp+4"); guarantee($mem$$index == R_G0_enc, "double index?"); // Load long with 2 instructions emit_form3_mem_reg(cbuf, this, $primary, -1, $mem$$base, $mem$$disp, R_G0_enc, $reg$$reg+0 ); @@ -2563,7 +2590,7 @@ } int entry_offset = instanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); - if( __ is_simm13(v_off) ) { + if (Assembler::is_simm13(v_off)) { __ ld_ptr(G3, v_off, G5_method); } else { // Generate 2 instructions @@ -3336,7 +3363,7 @@ // Integer Immediate: 8-bit operand immI8() %{ - predicate(Assembler::is_simm(n->get_int(), 8)); + predicate(Assembler::is_simm8(n->get_int())); match(ConI); op_cost(0); format %{ %} @@ -3365,7 +3392,7 @@ // Integer Immediate: 16-bit operand immI16() %{ - predicate(Assembler::is_simm(n->get_int(), 16)); + predicate(Assembler::is_simm16(n->get_int())); match(ConI); op_cost(0); format %{ %} @@ -3393,7 +3420,7 @@ // Integer Immediate: 11-bit operand immI11() %{ - predicate(Assembler::is_simm(n->get_int(),11)); + predicate(Assembler::is_simm11(n->get_int())); match(ConI); op_cost(0); format %{ %} @@ -3402,7 +3429,7 @@ // Integer Immediate: 5-bit operand immI5() %{ - predicate(Assembler::is_simm(n->get_int(), 5)); + predicate(Assembler::is_simm5(n->get_int())); match(ConI); op_cost(0); format %{ %} @@ -3634,7 +3661,7 @@ // Integer Immediate: 5-bit operand immL5() %{ - predicate(n->get_long() == (int)n->get_long() && Assembler::is_simm((int)n->get_long(), 5)); + predicate(n->get_long() == (int)n->get_long() && Assembler::is_simm5((int)n->get_long())); match(ConL); op_cost(0); format %{ %} @@ -9251,13 +9278,16 @@ format %{ "ADD $constanttablebase, $constantoffset, O7\n\t" "LD [O7 + $switch_val], O7\n\t" - "JUMP O7" - %} + "JUMP O7" %} ins_encode %{ // Calculate table address into a register. Register table_reg; Register label_reg = O7; - if (constant_offset() == 0) { + // If we are calculating the size of this instruction don't trust + // zero offsets because they might change when + // MachConstantBaseNode decides to optimize the constant table + // base. + if ((constant_offset() == 0) && !Compile::current()->in_scratch_emit_size()) { table_reg = $constanttablebase; } else { table_reg = O7; diff -r 55d777c0860a -r 81f7362f7bed src/cpu/sparc/vm/vtableStubs_sparc.cpp --- a/src/cpu/sparc/vm/vtableStubs_sparc.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/sparc/vm/vtableStubs_sparc.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -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 @@ -83,7 +83,7 @@ } #endif int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); - if( __ is_simm13(v_off) ) { + if (Assembler::is_simm13(v_off)) { __ ld_ptr(G3, v_off, G5_method); } else { __ set(v_off,G5); diff -r 55d777c0860a -r 81f7362f7bed src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/x86/vm/assembler_x86.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -3535,7 +3535,8 @@ // addressing. bool Assembler::is_polling_page_far() { intptr_t addr = (intptr_t)os::get_polling_page(); - return !is_simm32(addr - (intptr_t)CodeCache::low_bound()) || + return ForceUnreachable || + !is_simm32(addr - (intptr_t)CodeCache::low_bound()) || !is_simm32(addr - (intptr_t)CodeCache::high_bound()); } diff -r 55d777c0860a -r 81f7362f7bed src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/x86/vm/assembler_x86.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -693,17 +693,6 @@ static address locate_next_instruction(address inst); // Utilities - -#ifdef _LP64 - static bool is_simm(int64_t x, int nbits) { return -(CONST64(1) << (nbits-1)) <= x && - x < (CONST64(1) << (nbits-1)); } - static bool is_simm32(int64_t x) { return x == (int64_t)(int32_t)x; } -#else - static bool is_simm(int32_t x, int nbits) { return -(1 << (nbits-1)) <= x && - x < (1 << (nbits-1)); } - static bool is_simm32(int32_t x) { return true; } -#endif // _LP64 - static bool is_polling_page_far() NOT_LP64({ return false;}); // Generic instructions diff -r 55d777c0860a -r 81f7362f7bed src/cpu/x86/vm/c2_globals_x86.hpp --- a/src/cpu/x86/vm/c2_globals_x86.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/x86/vm/c2_globals_x86.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -44,7 +44,7 @@ #else define_pd_global(bool, ProfileInterpreter, true); #endif // CC_INTERP -define_pd_global(bool, TieredCompilation, false); +define_pd_global(bool, TieredCompilation, true); define_pd_global(intx, CompileThreshold, 10000); define_pd_global(intx, BackEdgeThreshold, 100000); diff -r 55d777c0860a -r 81f7362f7bed src/cpu/x86/vm/methodHandles_x86.hpp --- a/src/cpu/x86/vm/methodHandles_x86.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/x86/vm/methodHandles_x86.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -27,7 +27,7 @@ // Adapters enum /* platform_dependent_constants */ { - adapter_code_size = NOT_LP64(16000 DEBUG_ONLY(+ 15000)) LP64_ONLY(32000 DEBUG_ONLY(+ 80000)) + adapter_code_size = NOT_LP64(16000 DEBUG_ONLY(+ 15000)) LP64_ONLY(32000 DEBUG_ONLY(+ 120000)) }; public: diff -r 55d777c0860a -r 81f7362f7bed src/cpu/x86/vm/stubGenerator_x86_64.cpp --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -95,6 +95,7 @@ #define inc_counter_np(counter) (0) #else void inc_counter_np_(int& counter) { + // This can destroy rscratch1 if counter is far from the code cache __ incrementl(ExternalAddress((address)&counter)); } #define inc_counter_np(counter) \ @@ -1268,7 +1269,7 @@ __ subptr(end, start); // number of bytes to copy intptr_t disp = (intptr_t) ct->byte_map_base; - if (__ is_simm32(disp)) { + if (Assembler::is_simm32(disp)) { Address cardtable(noreg, noreg, Address::no_scale, disp); __ lea(scratch, cardtable); } else { @@ -1466,8 +1467,8 @@ __ movb(Address(end_to, 8), rax); __ BIND(L_exit); - inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1555,8 +1556,8 @@ __ decrement(qword_count); __ jcc(Assembler::notZero, L_copy_8_bytes); - inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1564,8 +1565,8 @@ // Copy in 32-bytes chunks copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes); - inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jbyte_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1658,8 +1659,8 @@ __ movw(Address(end_to, 8), rax); __ BIND(L_exit); - inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1759,8 +1760,8 @@ __ decrement(qword_count); __ jcc(Assembler::notZero, L_copy_8_bytes); - inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1768,8 +1769,8 @@ // Copy in 32-bytes chunks copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes); - inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jshort_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1859,8 +1860,8 @@ __ leaq(end_to, Address(saved_to, dword_count, Address::times_4, -4)); gen_write_ref_array_post_barrier(saved_to, end_to, rax); } - inc_counter_np(SharedRuntime::_jint_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1940,11 +1941,11 @@ __ decrement(qword_count); __ jcc(Assembler::notZero, L_copy_8_bytes); - inc_counter_np(SharedRuntime::_jint_array_copy_ctr); if (is_oop) { __ jmp(L_exit); } restore_arg_regs(); + inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -1952,7 +1953,6 @@ // Copy in 32-bytes chunks copy_32_bytes_backward(from, to, qword_count, rax, L_copy_32_bytes, L_copy_8_bytes); - inc_counter_np(SharedRuntime::_jint_array_copy_ctr); __ bind(L_exit); if (is_oop) { Register end_to = rdx; @@ -1960,6 +1960,7 @@ gen_write_ref_array_post_barrier(to, end_to, rax); } restore_arg_regs(); + inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -2032,8 +2033,8 @@ if (is_oop) { __ jmp(L_exit); } else { - inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -2045,11 +2046,13 @@ if (is_oop) { __ BIND(L_exit); gen_write_ref_array_post_barrier(saved_to, end_to, rax); - inc_counter_np(SharedRuntime::_oop_array_copy_ctr); - } else { - inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); } restore_arg_regs(); + if (is_oop) { + inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free + } else { + inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free + } __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -2113,8 +2116,8 @@ if (is_oop) { __ jmp(L_exit); } else { - inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -2127,11 +2130,13 @@ __ BIND(L_exit); __ lea(rcx, Address(to, saved_count, Address::times_8, -8)); gen_write_ref_array_post_barrier(to, rcx, rax); - inc_counter_np(SharedRuntime::_oop_array_copy_ctr); - } else { - inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); } restore_arg_regs(); + if (is_oop) { + inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free + } else { + inc_counter_np(SharedRuntime::_jlong_array_copy_ctr); // Update counter after rscratch1 is free + } __ xorptr(rax, rax); // return 0 __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); @@ -2331,8 +2336,8 @@ __ BIND(L_done); __ movptr(r13, Address(rsp, saved_r13_offset * wordSize)); __ movptr(r14, Address(rsp, saved_r14_offset * wordSize)); - inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr); restore_arg_regs(); + inc_counter_np(SharedRuntime::_checkcast_array_copy_ctr); // Update counter after rscratch1 is free __ leave(); // required for proper stackwalking of RuntimeStub frame __ ret(0); diff -r 55d777c0860a -r 81f7362f7bed src/cpu/x86/vm/x86_32.ad --- a/src/cpu/x86/vm/x86_32.ad Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/x86/vm/x86_32.ad Thu Dec 08 10:27:33 2011 -0800 @@ -507,9 +507,12 @@ //============================================================================= -const bool Matcher::constant_table_absolute_addressing = true; const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty; +int Compile::ConstantTable::calculate_table_base_offset() const { + return 0; // absolute addressing, no offset +} + void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { // Empty encoding } @@ -639,6 +642,12 @@ } #endif + if (C->has_mach_constant_base_node()) { + // NOTE: We set the table base offset here because users might be + // emitted before MachConstantBaseNode. + Compile::ConstantTable& constant_table = C->constant_table(); + constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); + } } uint MachPrologNode::size(PhaseRegAlloc *ra_) const { @@ -1515,12 +1524,12 @@ // Register for DIVI projection of divmodI RegMask Matcher::divI_proj_mask() { - return EAX_REG_mask; + return EAX_REG_mask(); } // Register for MODI projection of divmodI RegMask Matcher::modI_proj_mask() { - return EDX_REG_mask; + return EDX_REG_mask(); } // Register for DIVL projection of divmodL @@ -1536,7 +1545,7 @@ } const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return EBP_REG_mask; + return EBP_REG_mask(); } // Returns true if the high 32 bits of the value is known to be zero. diff -r 55d777c0860a -r 81f7362f7bed src/cpu/x86/vm/x86_64.ad --- a/src/cpu/x86/vm/x86_64.ad Wed Dec 07 07:27:09 2011 -0800 +++ b/src/cpu/x86/vm/x86_64.ad Thu Dec 08 10:27:33 2011 -0800 @@ -843,9 +843,12 @@ //============================================================================= -const bool Matcher::constant_table_absolute_addressing = true; const RegMask& MachConstantBaseNode::_out_RegMask = RegMask::Empty; +int Compile::ConstantTable::calculate_table_base_offset() const { + return 0; // absolute addressing, no offset +} + void MachConstantBaseNode::emit(CodeBuffer& cbuf, PhaseRegAlloc* ra_) const { // Empty encoding } @@ -977,6 +980,13 @@ masm.bind(L); } #endif + + if (C->has_mach_constant_base_node()) { + // NOTE: We set the table base offset here because users might be + // emitted before MachConstantBaseNode. + Compile::ConstantTable& constant_table = C->constant_table(); + constant_table.set_table_base_offset(constant_table.calculate_table_base_offset()); + } } uint MachPrologNode::size(PhaseRegAlloc* ra_) const @@ -2079,26 +2089,26 @@ // Register for DIVI projection of divmodI RegMask Matcher::divI_proj_mask() { - return INT_RAX_REG_mask; + return INT_RAX_REG_mask(); } // Register for MODI projection of divmodI RegMask Matcher::modI_proj_mask() { - return INT_RDX_REG_mask; + return INT_RDX_REG_mask(); } // Register for DIVL projection of divmodL RegMask Matcher::divL_proj_mask() { - return LONG_RAX_REG_mask; + return LONG_RAX_REG_mask(); } // Register for MODL projection of divmodL RegMask Matcher::modL_proj_mask() { - return LONG_RDX_REG_mask; + return LONG_RDX_REG_mask(); } const RegMask Matcher::method_handle_invoke_SP_save_mask() { - return PTR_RBP_REG_mask; + return PTR_RBP_REG_mask(); } static Address build_address(int b, int i, int s, int d) { diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/adlparse.cpp --- a/src/share/vm/adlc/adlparse.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/adlparse.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -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 @@ -982,27 +982,9 @@ } if (strcmp(token,"interpreter_frame_pointer")==0) { interpreter_frame_pointer_parse(frame, false); - // Add reg_class interpreter_frame_pointer_reg - if( _AD._register != NULL ) { - RegClass *reg_class = _AD._register->addRegClass("interpreter_frame_pointer_reg"); - char *interpreter_frame_pointer_reg = frame->_interpreter_frame_pointer_reg; - if( interpreter_frame_pointer_reg != NULL ) { - RegDef *regDef = _AD._register->getRegDef(interpreter_frame_pointer_reg); - reg_class->addReg(regDef); // add regDef to regClass - } - } } if (strcmp(token,"inline_cache_reg")==0) { inline_cache_parse(frame, false); - // Add reg_class inline_cache_reg - if( _AD._register != NULL ) { - RegClass *reg_class = _AD._register->addRegClass("inline_cache_reg"); - char *inline_cache_reg = frame->_inline_cache_reg; - if( inline_cache_reg != NULL ) { - RegDef *regDef = _AD._register->getRegDef(inline_cache_reg); - reg_class->addReg(regDef); // add regDef to regClass - } - } } if (strcmp(token,"compiler_method_oop_reg")==0) { parse_err(WARN, "Using obsolete Token, compiler_method_oop_reg"); @@ -1010,15 +992,6 @@ } if (strcmp(token,"interpreter_method_oop_reg")==0) { interpreter_method_oop_parse(frame, false); - // Add reg_class interpreter_method_oop_reg - if( _AD._register != NULL ) { - RegClass *reg_class = _AD._register->addRegClass("interpreter_method_oop_reg"); - char *method_oop_reg = frame->_interpreter_method_oop_reg; - if( method_oop_reg != NULL ) { - RegDef *regDef = _AD._register->getRegDef(method_oop_reg); - reg_class->addReg(regDef); // add regDef to regClass - } - } } if (strcmp(token,"cisc_spilling_operand_name")==0) { cisc_spilling_operand_name_parse(frame, false); @@ -2363,6 +2336,14 @@ } } next_char(); // Skip closing ')' + } else if (_curchar == '%') { + char *code = find_cpp_block("reg class"); + if (code == NULL) { + parse_err(SYNERR, "missing code declaration for reg class.\n"); + return; + } + reg_class->_user_defined = code; + return; } // Check for terminating ';' @@ -3115,7 +3096,7 @@ encoding->add_code(" _constant = C->constant_table().add"); // Parse everything in ( ) expression. - encoding->add_code("("); + encoding->add_code("(this, "); next_char(); // Skip '(' int parens_depth = 1; @@ -3130,7 +3111,8 @@ } else if (_curchar == ')') { parens_depth--; - encoding->add_code(")"); + if (parens_depth > 0) + encoding->add_code(")"); next_char(); } else { @@ -3157,7 +3139,7 @@ } // Finish code line. - encoding->add_code(";"); + encoding->add_code(");"); if (_AD._adlocation_debug) { encoding->add_code(end_line_marker()); @@ -3817,7 +3799,7 @@ return; } // Get list of effect-operand pairs and insert into dictionary - else get_effectlist(instr->_effects, instr->_localNames); + else get_effectlist(instr->_effects, instr->_localNames, instr->_has_call); // Debug Stuff if (_AD._adl_debug > 1) fprintf(stderr,"Effect description: %s\n", desc); @@ -4595,7 +4577,7 @@ // effect, and the second must be the name of an operand defined in the // operand list of this instruction. Stores the names with a pointer to the // effect form in a local effects table. -void ADLParser::get_effectlist(FormDict &effects, FormDict &operands) { +void ADLParser::get_effectlist(FormDict &effects, FormDict &operands, bool& has_call) { OperandForm *opForm; Effect *eForm; char *ident; @@ -4628,26 +4610,31 @@ // Debugging Stuff if (_AD._adl_debug > 1) fprintf(stderr, "\tEffect Type: %s\t", ident); skipws(); - // Get name of operand and check that it is in the local name table - if( (ident = get_unique_ident(effects, "effect")) == NULL) { - parse_err(SYNERR, "missing operand identifier in effect list\n"); - return; + if (eForm->is(Component::CALL)) { + if (_AD._adl_debug > 1) fprintf(stderr, "\n"); + has_call = true; + } else { + // Get name of operand and check that it is in the local name table + if( (ident = get_unique_ident(effects, "effect")) == NULL) { + parse_err(SYNERR, "missing operand identifier in effect list\n"); + return; + } + const Form *form = operands[ident]; + opForm = form ? form->is_operand() : NULL; + if( opForm == NULL ) { + if( form && form->is_opclass() ) { + const char* cname = form->is_opclass()->_ident; + parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident); + } else { + parse_err(SYNERR, "undefined operand %s in effect list\n", ident); + } + return; + } + // Add the pair to the effects table + effects.Insert(ident, eForm); + // Debugging Stuff + if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident); } - const Form *form = operands[ident]; - opForm = form ? form->is_operand() : NULL; - if( opForm == NULL ) { - if( form && form->is_opclass() ) { - const char* cname = form->is_opclass()->_ident; - parse_err(SYNERR, "operand classes are illegal in effect lists (found %s %s)\n", cname, ident); - } else { - parse_err(SYNERR, "undefined operand %s in effect list\n", ident); - } - return; - } - // Add the pair to the effects table - effects.Insert(ident, eForm); - // Debugging Stuff - if (_AD._adl_debug > 1) fprintf(stderr, "\tOperand Name: %s\n", ident); skipws(); } while(_curchar == ','); diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/adlparse.hpp --- a/src/share/vm/adlc/adlparse.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/adlparse.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -232,7 +232,7 @@ char *get_relation_dup(void); void get_oplist(NameList ¶meters, FormDict &operands);// Parse type-operand pairs - void get_effectlist(FormDict &effects, FormDict &operands); // Parse effect-operand pairs + void get_effectlist(FormDict &effects, FormDict &operands, bool& has_call); // Parse effect-operand pairs // Return the contents of a parenthesized expression. // Requires initial '(' and consumes final ')', which is replaced by '\0'. char *get_paren_expr(const char *description, bool include_location = false); diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/archDesc.cpp --- a/src/share/vm/adlc/archDesc.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/archDesc.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -823,9 +823,9 @@ } else { char *rc_name = toUpper(reg_class_name); const char *mask = "_mask"; - int length = (int)strlen(rc_name) + (int)strlen(mask) + 3; + int length = (int)strlen(rc_name) + (int)strlen(mask) + 5; char *regMask = new char[length]; - sprintf(regMask,"%s%s", rc_name, mask); + sprintf(regMask,"%s%s()", rc_name, mask); return regMask; } } @@ -1018,6 +1018,9 @@ ident = "TEMP"; eForm = new Effect(ident); _globalNames.Insert(ident, eForm); + ident = "CALL"; + eForm = new Effect(ident); + _globalNames.Insert(ident, eForm); } // diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/formsopt.cpp --- a/src/share/vm/adlc/formsopt.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/formsopt.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -219,7 +219,9 @@ //------------------------------RegClass--------------------------------------- // Construct a register class into which registers will be inserted -RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena) { +RegClass::RegClass(const char *classid) : _stack_or_reg(false), _classid(classid), _regDef(cmpstr,hashstr, Form::arena), + _user_defined(NULL) +{ } // record a register in this class diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/formsopt.hpp --- a/src/share/vm/adlc/formsopt.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/formsopt.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -161,6 +161,7 @@ NameList _regDefs; // List of registers in class Dict _regDef; // Dictionary of registers in class bool _stack_or_reg; // Allowed on any stack slot + char* _user_defined; // Public Methods RegClass(const char *classid);// Constructor diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/formssel.cpp --- a/src/share/vm/adlc/formssel.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/formssel.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -31,7 +31,8 @@ : _ident(id), _ideal_only(ideal_only), _localNames(cmpstr, hashstr, Form::arena), _effects(cmpstr, hashstr, Form::arena), - _is_mach_constant(false) + _is_mach_constant(false), + _has_call(false) { _ftype = Form::INS; @@ -62,7 +63,8 @@ : _ident(id), _ideal_only(false), _localNames(instr->_localNames), _effects(instr->_effects), - _is_mach_constant(false) + _is_mach_constant(false), + _has_call(false) { _ftype = Form::INS; @@ -1754,6 +1756,7 @@ if(!strcmp(name, "USE_KILL")) return Component::USE_KILL; if(!strcmp(name, "TEMP")) return Component::TEMP; if(!strcmp(name, "INVALID")) return Component::INVALID; + if(!strcmp(name, "CALL")) return Component::CALL; assert( false,"Invalid effect name specified\n"); return Component::INVALID; } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/formssel.hpp --- a/src/share/vm/adlc/formssel.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/formssel.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -111,6 +111,8 @@ ComponentList _components; // List of Components matches MachNode's // operand structure + bool _has_call; // contain a call and caller save registers should be saved? + // Public Methods InstructForm(const char *id, bool ideal_only = false); InstructForm(const char *id, InstructForm *instr, MatchRule *rule); @@ -895,7 +897,8 @@ DEF = 0x2, USE_DEF = 0x3, KILL = 0x4, USE_KILL = 0x5, SYNTHETIC = 0x8, - TEMP = USE | SYNTHETIC + TEMP = USE | SYNTHETIC, + CALL = 0x10 }; }; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/output_c.cpp --- a/src/share/vm/adlc/output_c.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/output_c.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -162,11 +162,17 @@ RegClass *reg_class = _register->getRegClass(rc_name); assert( reg_class, "Using an undefined register class"); - int len = RegisterForm::RegMask_Size(); - fprintf(fp_hpp, "extern const RegMask %s%s_mask;\n", prefix, toUpper( rc_name ) ); + if (reg_class->_user_defined == NULL) { + fprintf(fp_hpp, "extern const RegMask _%s%s_mask;\n", prefix, toUpper( rc_name ) ); + fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { return _%s%s_mask; }\n", prefix, toUpper( rc_name ), prefix, toUpper( rc_name )); + } else { + fprintf(fp_hpp, "inline const RegMask &%s%s_mask() { %s }\n", prefix, toUpper( rc_name ), reg_class->_user_defined); + } if( reg_class->_stack_or_reg ) { - fprintf(fp_hpp, "extern const RegMask %sSTACK_OR_%s_mask;\n", prefix, toUpper( rc_name ) ); + assert(reg_class->_user_defined == NULL, "no user defined reg class here"); + fprintf(fp_hpp, "extern const RegMask _%sSTACK_OR_%s_mask;\n", prefix, toUpper( rc_name ) ); + fprintf(fp_hpp, "inline const RegMask &%sSTACK_OR_%s_mask() { return _%sSTACK_OR_%s_mask; }\n", prefix, toUpper( rc_name ), prefix, toUpper( rc_name ) ); } } } @@ -188,8 +194,10 @@ RegClass *reg_class = _register->getRegClass(rc_name); assert( reg_class, "Using an undefined register class"); + if (reg_class->_user_defined != NULL) continue; + int len = RegisterForm::RegMask_Size(); - fprintf(fp_cpp, "const RegMask %s%s_mask(", prefix, toUpper( rc_name ) ); + fprintf(fp_cpp, "const RegMask _%s%s_mask(", prefix, toUpper( rc_name ) ); { int i; for( i = 0; i < len-1; i++ ) fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i,false)); @@ -198,7 +206,7 @@ if( reg_class->_stack_or_reg ) { int i; - fprintf(fp_cpp, "const RegMask %sSTACK_OR_%s_mask(", prefix, toUpper( rc_name ) ); + fprintf(fp_cpp, "const RegMask _%sSTACK_OR_%s_mask(", prefix, toUpper( rc_name ) ); for( i = 0; i < len-1; i++ ) fprintf(fp_cpp," 0x%x,",reg_class->regs_in_word(i,true)); fprintf(fp_cpp," 0x%x );\n",reg_class->regs_in_word(i,true)); @@ -2585,9 +2593,9 @@ // Output instruction's emit prototype fprintf(fp, "void %sNode::eval_constant(Compile* C) {\n", inst._ident); - // For ideal jump nodes, allocate a jump table. + // For ideal jump nodes, add a jump-table entry. if (inst.is_ideal_jump()) { - fprintf(fp, " _constant = C->constant_table().allocate_jump_table(this);\n"); + fprintf(fp, " _constant = C->constant_table().add_jump_table(this);\n"); } // If user did not define an encode section, @@ -2690,7 +2698,7 @@ if (strcmp(first_reg_class, "stack_slots") == 0) { fprintf(fp," return &(Compile::current()->FIRST_STACK_mask());\n"); } else { - fprintf(fp," return &%s_mask;\n", toUpper(first_reg_class)); + fprintf(fp," return &%s_mask();\n", toUpper(first_reg_class)); } } else { // Build a switch statement to return the desired mask. @@ -2702,7 +2710,7 @@ if( !strcmp(reg_class, "stack_slots") ) { fprintf(fp, " case %d: return &(Compile::current()->FIRST_STACK_mask());\n", index); } else { - fprintf(fp, " case %d: return &%s_mask;\n", index, toUpper(reg_class)); + fprintf(fp, " case %d: return &%s_mask();\n", index, toUpper(reg_class)); } } fprintf(fp," }\n"); @@ -4080,8 +4088,6 @@ fprintf(fp_cpp,"OptoReg::Name Matcher::inline_cache_reg() {"); fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n", _frame->_inline_cache_reg); - fprintf(fp_cpp,"const RegMask &Matcher::inline_cache_reg_mask() {"); - fprintf(fp_cpp," return INLINE_CACHE_REG_mask; }\n\n"); fprintf(fp_cpp,"int Matcher::inline_cache_reg_encode() {"); fprintf(fp_cpp," return _regEncode[inline_cache_reg()]; }\n\n"); @@ -4089,8 +4095,6 @@ fprintf(fp_cpp,"OptoReg::Name Matcher::interpreter_method_oop_reg() {"); fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n", _frame->_interpreter_method_oop_reg); - fprintf(fp_cpp,"const RegMask &Matcher::interpreter_method_oop_reg_mask() {"); - fprintf(fp_cpp," return INTERPRETER_METHOD_OOP_REG_mask; }\n\n"); fprintf(fp_cpp,"int Matcher::interpreter_method_oop_reg_encode() {"); fprintf(fp_cpp," return _regEncode[interpreter_method_oop_reg()]; }\n\n"); @@ -4101,11 +4105,6 @@ else fprintf(fp_cpp," return OptoReg::Name(%s_num); }\n\n", _frame->_interpreter_frame_pointer_reg); - fprintf(fp_cpp,"const RegMask &Matcher::interpreter_frame_pointer_reg_mask() {"); - if (_frame->_interpreter_frame_pointer_reg == NULL) - fprintf(fp_cpp," static RegMask dummy; return dummy; }\n\n"); - else - fprintf(fp_cpp," return INTERPRETER_FRAME_POINTER_REG_mask; }\n\n"); // Frame Pointer definition /* CNC - I can not contemplate having a different frame pointer between diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/adlc/output_h.cpp --- a/src/share/vm/adlc/output_h.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/adlc/output_h.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -1720,6 +1720,16 @@ } } + // flag: if this instruction is implemented with a call + if ( instr->_has_call ) { + if ( node_flags_set ) { + fprintf(fp," | Flag_has_call"); + } else { + fprintf(fp,"init_flags(Flag_has_call"); + node_flags_set = true; + } + } + if ( node_flags_set ) { fprintf(fp,"); "); } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/asm/assembler.hpp --- a/src/share/vm/asm/assembler.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/asm/assembler.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -257,6 +257,29 @@ // ensure buf contains all code (call this before using/copying the code) void flush(); + // min and max values for signed immediate ranges + static int min_simm(int nbits) { return -(intptr_t(1) << (nbits - 1)) ; } + static int max_simm(int nbits) { return (intptr_t(1) << (nbits - 1)) - 1; } + + // Define some: + static int min_simm10() { return min_simm(10); } + static int min_simm13() { return min_simm(13); } + static int min_simm16() { return min_simm(16); } + + // Test if x is within signed immediate range for nbits + static bool is_simm(intptr_t x, int nbits) { return min_simm(nbits) <= x && x <= max_simm(nbits); } + + // Define some: + static bool is_simm5( intptr_t x) { return is_simm(x, 5 ); } + static bool is_simm8( intptr_t x) { return is_simm(x, 8 ); } + static bool is_simm10(intptr_t x) { return is_simm(x, 10); } + static bool is_simm11(intptr_t x) { return is_simm(x, 11); } + static bool is_simm12(intptr_t x) { return is_simm(x, 12); } + static bool is_simm13(intptr_t x) { return is_simm(x, 13); } + static bool is_simm16(intptr_t x) { return is_simm(x, 16); } + static bool is_simm26(intptr_t x) { return is_simm(x, 26); } + static bool is_simm32(intptr_t x) { return is_simm(x, 32); } + // Accessors CodeBuffer* code() const; // _code_section->outer() CodeSection* code_section() const { return _code_section; } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -3495,9 +3495,6 @@ if (profile_calls()) { profile_call(recv, holder_known ? callee->holder() : NULL); } - if (profile_inlined_calls()) { - profile_invocation(callee, copy_state_before()); - } } // Introduce a new callee continuation point - if the callee has @@ -3571,6 +3568,10 @@ append(new RuntimeCall(voidType, "dtrace_method_entry", CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry), args)); } + if (profile_inlined_calls()) { + profile_invocation(callee, copy_state_before_with_bci(SynchronizationEntryBCI)); + } + BlockBegin* callee_start_block = block_at(0); if (callee_start_block != NULL) { assert(callee_start_block->is_set(BlockBegin::parser_loop_header_flag), "must be loop header"); diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/c1/c1_Instruction.hpp --- a/src/share/vm/c1/c1_Instruction.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/c1/c1_Instruction.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -501,6 +501,7 @@ virtual RoundFP* as_RoundFP() { return NULL; } virtual ExceptionObject* as_ExceptionObject() { return NULL; } virtual UnsafeOp* as_UnsafeOp() { return NULL; } + virtual ProfileInvoke* as_ProfileInvoke() { return NULL; } virtual void visit(InstructionVisitor* v) = 0; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -429,7 +429,7 @@ // all locals are dead on exit from the synthetic unlocker liveness.clear(); } else { - assert(x->as_MonitorEnter(), "only other case is MonitorEnter"); + assert(x->as_MonitorEnter() || x->as_ProfileInvoke(), "only other cases are MonitorEnter and ProfileInvoke"); } } if (!liveness.is_valid()) { diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/ci/bcEscapeAnalyzer.cpp --- a/src/share/vm/ci/bcEscapeAnalyzer.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/ci/bcEscapeAnalyzer.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -150,11 +150,23 @@ clear_bits(vars, _arg_local); } -void BCEscapeAnalyzer::set_global_escape(ArgumentMap vars) { +void BCEscapeAnalyzer::set_global_escape(ArgumentMap vars, bool merge) { clear_bits(vars, _arg_local); clear_bits(vars, _arg_stack); if (vars.contains_allocated()) _allocated_escapes = true; + + if (merge && !vars.is_empty()) { + // Merge new state into already processed block. + // New state is not taken into account and + // it may invalidate set_returned() result. + if (vars.contains_unknown() || vars.contains_allocated()) { + _return_local = false; + } + if (vars.contains_unknown() || vars.contains_vars()) { + _return_allocated = false; + } + } } void BCEscapeAnalyzer::set_dirty(ArgumentMap vars) { @@ -999,7 +1011,7 @@ t.set_difference(d_state->_stack[i]); extra_vars.set_union(t); } - set_global_escape(extra_vars); + set_global_escape(extra_vars, true); } } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/ci/bcEscapeAnalyzer.hpp --- a/src/share/vm/ci/bcEscapeAnalyzer.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/ci/bcEscapeAnalyzer.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -81,7 +81,7 @@ bool is_arg_stack(ArgumentMap vars); void clear_bits(ArgumentMap vars, VectorSet &bs); void set_method_escape(ArgumentMap vars); - void set_global_escape(ArgumentMap vars); + void set_global_escape(ArgumentMap vars, bool merge = false); void set_dirty(ArgumentMap vars); void set_modified(ArgumentMap vars, int offs, int size); diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/ci/ciMethod.hpp --- a/src/share/vm/ci/ciMethod.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/ci/ciMethod.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -295,12 +295,6 @@ // Print the name of this method in various incarnations. void print_name(outputStream* st = tty); void print_short_name(outputStream* st = tty); - - methodOop get_method_handle_target() { - KlassHandle receiver_limit; int flags = 0; - methodHandle m = MethodHandles::decode_method(get_oop(), receiver_limit, flags); - return m(); - } }; #endif // SHARE_VM_CI_CIMETHOD_HPP diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/compiler/compileBroker.cpp --- a/src/share/vm/compiler/compileBroker.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/compiler/compileBroker.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -1748,7 +1748,7 @@ tty->print("%4d ", compile_id); // print compilation number tty->print("%s ", (is_osr ? "%" : " ")); int code_size = (task->code() == NULL) ? 0 : task->code()->total_size(); - tty->print_cr("size: %d time: %d inlined: %d bytes", code_size, time.milliseconds(), task->num_inlined_bytecodes()); + tty->print_cr("size: %d time: %d inlined: %d bytes", code_size, (int)time.milliseconds(), task->num_inlined_bytecodes()); } if (compilable == ciEnv::MethodCompilable_never) { diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/block.cpp --- a/src/share/vm/opto/block.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/block.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -898,45 +898,41 @@ void PhaseCFG::verify( ) const { #ifdef ASSERT // Verify sane CFG - for( uint i = 0; i < _num_blocks; i++ ) { + for (uint i = 0; i < _num_blocks; i++) { Block *b = _blocks[i]; uint cnt = b->_nodes.size(); uint j; - for( j = 0; j < cnt; j++ ) { + for (j = 0; j < cnt; j++) { Node *n = b->_nodes[j]; assert( _bbs[n->_idx] == b, "" ); - if( j >= 1 && n->is_Mach() && - n->as_Mach()->ideal_Opcode() == Op_CreateEx ) { - assert( j == 1 || b->_nodes[j-1]->is_Phi(), - "CreateEx must be first instruction in block" ); + if (j >= 1 && n->is_Mach() && + n->as_Mach()->ideal_Opcode() == Op_CreateEx) { + assert(j == 1 || b->_nodes[j-1]->is_Phi(), + "CreateEx must be first instruction in block"); } - for( uint k = 0; k < n->req(); k++ ) { + for (uint k = 0; k < n->req(); k++) { Node *def = n->in(k); - if( def && def != n ) { - assert( _bbs[def->_idx] || def->is_Con(), - "must have block; constants for debug info ok" ); + if (def && def != n) { + assert(_bbs[def->_idx] || def->is_Con(), + "must have block; constants for debug info ok"); // Verify that instructions in the block is in correct order. // Uses must follow their definition if they are at the same block. // Mostly done to check that MachSpillCopy nodes are placed correctly // when CreateEx node is moved in build_ifg_physical(). - if( _bbs[def->_idx] == b && + if (_bbs[def->_idx] == b && !(b->head()->is_Loop() && n->is_Phi()) && // See (+++) comment in reg_split.cpp - !(n->jvms() != NULL && n->jvms()->is_monitor_use(k)) ) { + !(n->jvms() != NULL && n->jvms()->is_monitor_use(k))) { bool is_loop = false; if (n->is_Phi()) { - for( uint l = 1; l < def->req(); l++ ) { + for (uint l = 1; l < def->req(); l++) { if (n == def->in(l)) { is_loop = true; break; // Some kind of loop } } } - assert( is_loop || b->find_node(def) < j, "uses must follow definitions" ); - } - if( def->is_SafePointScalarObject() ) { - assert(_bbs[def->_idx] == b, "SafePointScalarObject Node should be at the same block as its SafePoint node"); - assert(_bbs[def->_idx] == _bbs[def->in(0)->_idx], "SafePointScalarObject Node should be at the same block as its control edge"); + assert(is_loop || b->find_node(def) < j, "uses must follow definitions"); } } } @@ -946,12 +942,11 @@ Node *bp = (Node*)b->_nodes[b->_nodes.size()-1]->is_block_proj(); assert( bp, "last instruction must be a block proj" ); assert( bp == b->_nodes[j], "wrong number of successors for this block" ); - if( bp->is_Catch() ) { - while( b->_nodes[--j]->is_MachProj() ) ; - assert( b->_nodes[j]->is_MachCall(), "CatchProj must follow call" ); - } - else if( bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If ) { - assert( b->_num_succs == 2, "Conditional branch must have two targets"); + if (bp->is_Catch()) { + while (b->_nodes[--j]->is_MachProj()) ; + assert(b->_nodes[j]->is_MachCall(), "CatchProj must follow call"); + } else if (bp->is_Mach() && bp->as_Mach()->ideal_Opcode() == Op_If) { + assert(b->_num_succs == 2, "Conditional branch must have two targets"); } } #endif diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/block.hpp --- a/src/share/vm/opto/block.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/block.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -281,6 +281,8 @@ // Find and remove n from block list void find_remove( const Node *n ); + // helper function that adds caller save registers to MachProjNode + void add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe); // Schedule a call next in the block uint sched_call(Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call); diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/c2_globals.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -456,6 +456,12 @@ product(intx, EliminateAllocationArraySizeLimit, 64, \ "Array size (number of elements) limit for scalar replacement") \ \ + product(bool, OptimizePtrCompare, true, \ + "Use escape analysis to optimize pointers compare") \ + \ + notproduct(bool, PrintOptimizePtrCompare, false, \ + "Print information about optimized pointers compare") \ + \ product(bool, UseOptoBiasInlining, true, \ "Generate biased locking code in C2 ideal graph") \ \ diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/callGenerator.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -318,17 +318,17 @@ return new DirectCallGenerator(m, separate_io_proj); } -CallGenerator* CallGenerator::for_dynamic_call(ciMethod* m) { - assert(m->is_method_handle_invoke() || m->is_method_handle_adapter(), "for_dynamic_call mismatch"); - return new DynamicCallGenerator(m); -} - CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) { assert(!m->is_static(), "for_virtual_call mismatch"); assert(!m->is_method_handle_invoke(), "should be a direct call"); return new VirtualCallGenerator(m, vtable_index); } +CallGenerator* CallGenerator::for_dynamic_call(ciMethod* m) { + assert(m->is_method_handle_invoke() || m->is_method_handle_adapter(), "for_dynamic_call mismatch"); + return new DynamicCallGenerator(m); +} + // Allow inlining decisions to be delayed class LateInlineCallGenerator : public DirectCallGenerator { CallGenerator* _inline_cg; @@ -576,7 +576,9 @@ kit.set_control(slow_ctl); if (!kit.stopped()) { slow_jvms = _if_missed->generate(kit.sync_jvms()); - assert(slow_jvms != NULL, "miss path must not fail to generate"); + if (kit.failing()) + return NULL; // might happen because of NodeCountInliningCutoff + assert(slow_jvms != NULL, "must be"); kit.add_exception_states_from(slow_jvms); kit.set_map(slow_jvms->map()); if (!kit.stopped()) @@ -682,6 +684,15 @@ } +CallGenerator* CallGenerator::for_method_handle_call(Node* method_handle, JVMState* jvms, + ciMethod* caller, ciMethod* callee, ciCallProfile profile) { + assert(callee->is_method_handle_invoke() || callee->is_method_handle_adapter(), "for_method_handle_call mismatch"); + CallGenerator* cg = CallGenerator::for_method_handle_inline(method_handle, jvms, caller, callee, profile); + if (cg != NULL) + return cg; + return CallGenerator::for_direct_call(callee); +} + CallGenerator* CallGenerator::for_method_handle_inline(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile) { if (method_handle->Opcode() == Op_ConP) { @@ -721,8 +732,8 @@ // Generate a guard so that each can be inlined. We might want to // do more inputs at later point but this gets the most common // case. - CallGenerator* cg1 = for_method_handle_inline(method_handle->in(1), jvms, caller, callee, profile.rescale(1.0 - prob)); - CallGenerator* cg2 = for_method_handle_inline(method_handle->in(2), jvms, caller, callee, profile.rescale(prob)); + CallGenerator* cg1 = for_method_handle_call(method_handle->in(1), jvms, caller, callee, profile.rescale(1.0 - prob)); + CallGenerator* cg2 = for_method_handle_call(method_handle->in(2), jvms, caller, callee, profile.rescale(prob)); if (cg1 != NULL && cg2 != NULL) { const TypeOopPtr* oop_ptr = method_handle->in(1)->bottom_type()->is_oopptr(); ciObject* const_oop = oop_ptr->const_oop(); @@ -733,6 +744,17 @@ return NULL; } +CallGenerator* CallGenerator::for_invokedynamic_call(JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile) { + assert(callee->is_method_handle_invoke() || callee->is_method_handle_adapter(), "for_invokedynamic_call mismatch"); + // Get the CallSite object. + ciBytecodeStream str(caller); + str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. + ciCallSite* call_site = str.get_call_site(); + CallGenerator* cg = CallGenerator::for_invokedynamic_inline(call_site, jvms, caller, callee, profile); + if (cg != NULL) + return cg; + return CallGenerator::for_dynamic_call(callee); +} CallGenerator* CallGenerator::for_invokedynamic_inline(ciCallSite* call_site, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile) { @@ -819,7 +841,9 @@ kit.set_control(slow_ctl); if (!kit.stopped()) { slow_jvms = _if_missed->generate(kit.sync_jvms()); - assert(slow_jvms != NULL, "miss path must not fail to generate"); + if (kit.failing()) + return NULL; // might happen because of NodeCountInliningCutoff + assert(slow_jvms != NULL, "must be"); kit.add_exception_states_from(slow_jvms); kit.set_map(slow_jvms->map()); if (!kit.stopped()) diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/callGenerator.hpp --- a/src/share/vm/opto/callGenerator.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/callGenerator.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -108,8 +108,11 @@ // How to generate vanilla out-of-line call sites: static CallGenerator* for_direct_call(ciMethod* m, bool separate_io_projs = false); // static, special + static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface static CallGenerator* for_dynamic_call(ciMethod* m); // invokedynamic - static CallGenerator* for_virtual_call(ciMethod* m, int vtable_index); // virtual, interface + + static CallGenerator* for_method_handle_call(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile); + static CallGenerator* for_invokedynamic_call( JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile); static CallGenerator* for_method_handle_inline(Node* method_handle, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile); static CallGenerator* for_invokedynamic_inline(ciCallSite* call_site, JVMState* jvms, ciMethod* caller, ciMethod* callee, ciCallProfile profile); diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/callnode.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -1071,8 +1071,11 @@ init_class_id(Class_SafePointScalarObject); } -bool SafePointScalarObjectNode::pinned() const { return true; } -bool SafePointScalarObjectNode::depends_only_on_test() const { return false; } +// Do not allow value-numbering for SafePointScalarObject node. +uint SafePointScalarObjectNode::hash() const { return NO_HASH; } +uint SafePointScalarObjectNode::cmp( const Node &n ) const { + return (&n == this); // Always fail except on self +} uint SafePointScalarObjectNode::ideal_reg() const { return 0; // No matching to machine instruction @@ -1096,7 +1099,6 @@ if (cached != NULL) { return (SafePointScalarObjectNode*)cached; } - Compile* C = Compile::current(); SafePointScalarObjectNode* res = (SafePointScalarObjectNode*)Node::clone(); res->_first_index += jvms_adj; sosn_map->Insert((void*)this, (void*)res); @@ -1142,6 +1144,8 @@ Node* AllocateArrayNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (remove_dead_region(phase, can_reshape)) return this; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; const Type* type = phase->type(Ideal_length()); if (type->isa_int() && type->is_int()->_hi < 0) { @@ -1522,13 +1526,16 @@ // perform any generic optimizations first (returns 'this' or NULL) Node *result = SafePointNode::Ideal(phase, can_reshape); + if (result != NULL) return result; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; // Now see if we can optimize away this lock. We don't actually // remove the locking here, we simply set the _eliminate flag which // prevents macro expansion from expanding the lock. Since we don't // modify the graph, the value returned from this function is the // one computed above. - if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) { + if (can_reshape && EliminateLocks && (!is_eliminated() || is_coarsened())) { // // If we are locking an unescaped object, the lock/unlock is unnecessary // @@ -1537,8 +1544,16 @@ if (cgr != NULL) es = cgr->escape_state(obj_node()); if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { - // Mark it eliminated to update any counters - this->set_eliminated(); + if (!is_eliminated()) { + // Mark it eliminated to update any counters + this->set_eliminated(); + } else { + assert(is_coarsened(), "sanity"); + // The lock could be marked eliminated by lock coarsening + // code during first IGVN before EA. Clear coarsened flag + // to eliminate all associated locks/unlocks. + this->clear_coarsened(); + } return result; } @@ -1546,7 +1561,7 @@ // Try lock coarsening // PhaseIterGVN* iter = phase->is_IterGVN(); - if (iter != NULL) { + if (iter != NULL && !is_eliminated()) { GrowableArray lock_ops; @@ -1602,7 +1617,7 @@ lock->set_eliminated(); lock->set_coarsened(); } - } else if (result != NULL && ctrl->is_Region() && + } else if (ctrl->is_Region() && iter->_worklist.member(ctrl)) { // We weren't able to find any opportunities but the region this // lock is control dependent on hasn't been processed yet so put @@ -1623,7 +1638,10 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) { // perform any generic optimizations first (returns 'this' or NULL) - Node * result = SafePointNode::Ideal(phase, can_reshape); + Node *result = SafePointNode::Ideal(phase, can_reshape); + if (result != NULL) return result; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; // Now see if we can optimize away this unlock. We don't actually // remove the unlocking here, we simply set the _eliminate flag which @@ -1631,7 +1649,7 @@ // modify the graph, the value returned from this function is the // one computed above. // Escape state is defined after Parse phase. - if (result == NULL && can_reshape && EliminateLocks && !is_eliminated()) { + if (can_reshape && EliminateLocks && (!is_eliminated() || is_coarsened())) { // // If we are unlocking an unescaped object, the lock/unlock is unnecessary. // @@ -1640,8 +1658,16 @@ if (cgr != NULL) es = cgr->escape_state(obj_node()); if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { - // Mark it eliminated to update any counters - this->set_eliminated(); + if (!is_eliminated()) { + // Mark it eliminated to update any counters + this->set_eliminated(); + } else { + assert(is_coarsened(), "sanity"); + // The lock could be marked eliminated by lock coarsening + // code during first IGVN before EA. Clear coarsened flag + // to eliminate all associated locks/unlocks. + this->clear_coarsened(); + } } } return result; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/callnode.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -440,6 +440,10 @@ // states of the scalarized object fields are collected. uint _n_fields; // Number of non-static fields of the scalarized object. DEBUG_ONLY(AllocateNode* _alloc;) + + virtual uint hash() const ; // { return NO_HASH; } + virtual uint cmp( const Node &n ) const; + public: SafePointScalarObjectNode(const TypeOopPtr* tp, #ifdef ASSERT @@ -454,15 +458,10 @@ uint first_index() const { return _first_index; } uint n_fields() const { return _n_fields; } - DEBUG_ONLY(AllocateNode* alloc() const { return _alloc; }) - // SafePointScalarObject should be always pinned to the control edge - // of the SafePoint node for which it was generated. - virtual bool pinned() const; // { return true; } - - // SafePointScalarObject depends on the SafePoint node - // for which it was generated. - virtual bool depends_only_on_test() const; // { return false; } +#ifdef ASSERT + AllocateNode* alloc() const { return _alloc; } +#endif virtual uint size_of() const { return sizeof(*this); } @@ -880,6 +879,7 @@ bool is_coarsened() { return _coarsened; } void set_coarsened() { _coarsened = true; } + void clear_coarsened() { _coarsened = false; } // locking does not modify its arguments virtual bool may_modify(const TypePtr *addr_t, PhaseTransform *phase){ return false;} diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/cfgnode.cpp --- a/src/share/vm/opto/cfgnode.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/cfgnode.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -460,8 +460,11 @@ // Is it dead loop? // If it is LoopNopde it had 2 (+1 itself) inputs and // one of them was cut. The loop is dead if it was EntryContol. - assert(!this->is_Loop() || cnt_orig == 3, "Loop node should have 3 inputs"); - if (this->is_Loop() && del_it == LoopNode::EntryControl || + // Loop node may have only one input because entry path + // is removed in PhaseIdealLoop::Dominators(). + assert(!this->is_Loop() || cnt_orig <= 3, "Loop node should have 3 or less inputs"); + if (this->is_Loop() && (del_it == LoopNode::EntryControl || + del_it == 0 && is_unreachable_region(phase)) || !this->is_Loop() && has_phis && is_unreachable_region(phase)) { // Yes, the region will be removed during the next step below. // Cut the backedge input and remove phis since no data paths left. @@ -1585,14 +1588,17 @@ // Only one not-NULL unique input path is left. // Determine if this input is backedge of a loop. // (Skip new phis which have no uses and dead regions). - if( outcnt() > 0 && r->in(0) != NULL ) { + if (outcnt() > 0 && r->in(0) != NULL) { // First, take the short cut when we know it is a loop and // the EntryControl data path is dead. - assert(!r->is_Loop() || r->req() == 3, "Loop node should have 3 inputs"); + // Loop node may have only one input because entry path + // is removed in PhaseIdealLoop::Dominators(). + assert(!r->is_Loop() || r->req() <= 3, "Loop node should have 3 or less inputs"); + bool is_loop = (r->is_Loop() && r->req() == 3); // Then, check if there is a data loop when phi references itself directly // or through other data nodes. - if( r->is_Loop() && !phase->eqv_uncast(uin, in(LoopNode::EntryControl)) || - !r->is_Loop() && is_unsafe_data_reference(uin) ) { + if (is_loop && !phase->eqv_uncast(uin, in(LoopNode::EntryControl)) || + !is_loop && is_unsafe_data_reference(uin)) { // Break this data loop to avoid creation of a dead loop. if (can_reshape) { return top; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/compile.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -1711,11 +1711,22 @@ if (failing()) return; + // Optimize out fields loads from scalar replaceable allocations. igvn.optimize(); print_method("Iter GVN after EA", 2); if (failing()) return; + if (congraph() != NULL && macro_count() > 0) { + PhaseMacroExpand mexp(igvn); + mexp.eliminate_macro_nodes(); + igvn.set_delay_transform(false); + + igvn.optimize(); + print_method("Iter GVN after eliminating allocations and locks", 2); + + if (failing()) return; + } } // Loop transforms on the ideal graph. Range Check Elimination, @@ -3052,24 +3063,13 @@ return false; } -// Emit constants grouped in the following order: -static BasicType type_order[] = { - T_FLOAT, // 32-bit - T_OBJECT, // 32 or 64-bit - T_ADDRESS, // 32 or 64-bit - T_DOUBLE, // 64-bit - T_LONG, // 64-bit - T_VOID, // 32 or 64-bit (jump-tables are at the end of the constant table for code emission reasons) - T_ILLEGAL -}; - static int type_to_size_in_bytes(BasicType t) { switch (t) { case T_LONG: return sizeof(jlong ); case T_FLOAT: return sizeof(jfloat ); case T_DOUBLE: return sizeof(jdouble); // We use T_VOID as marker for jump-table entries (labels) which - // need an interal word relocation. + // need an internal word relocation. case T_VOID: case T_ADDRESS: case T_OBJECT: return sizeof(jobject); @@ -3079,87 +3079,92 @@ return -1; } +int Compile::ConstantTable::qsort_comparator(Constant* a, Constant* b) { + // sort descending + if (a->freq() > b->freq()) return -1; + if (a->freq() < b->freq()) return 1; + return 0; +} + void Compile::ConstantTable::calculate_offsets_and_size() { - int size = 0; - for (int t = 0; type_order[t] != T_ILLEGAL; t++) { - BasicType type = type_order[t]; - - for (int i = 0; i < _constants.length(); i++) { - Constant con = _constants.at(i); - if (con.type() != type) continue; // Skip other types. - - // Align size for type. - int typesize = type_to_size_in_bytes(con.type()); - size = align_size_up(size, typesize); - - // Set offset. - con.set_offset(size); - _constants.at_put(i, con); - - // Add type size. - size = size + typesize; + // First, sort the array by frequencies. + _constants.sort(qsort_comparator); + +#ifdef ASSERT + // Make sure all jump-table entries were sorted to the end of the + // array (they have a negative frequency). + bool found_void = false; + for (int i = 0; i < _constants.length(); i++) { + Constant con = _constants.at(i); + if (con.type() == T_VOID) + found_void = true; // jump-tables + else + assert(!found_void, "wrong sorting"); + } +#endif + + int offset = 0; + for (int i = 0; i < _constants.length(); i++) { + Constant* con = _constants.adr_at(i); + + // Align offset for type. + int typesize = type_to_size_in_bytes(con->type()); + offset = align_size_up(offset, typesize); + con->set_offset(offset); // set constant's offset + + if (con->type() == T_VOID) { + MachConstantNode* n = (MachConstantNode*) con->get_jobject(); + offset = offset + typesize * n->outcnt(); // expand jump-table + } else { + offset = offset + typesize; } } // Align size up to the next section start (which is insts; see // CodeBuffer::align_at_start). assert(_size == -1, "already set?"); - _size = align_size_up(size, CodeEntryAlignment); - - if (Matcher::constant_table_absolute_addressing) { - set_table_base_offset(0); // No table base offset required - } else { - if (UseRDPCForConstantTableBase) { - // table base offset is set in MachConstantBaseNode::emit - } else { - // When RDPC is not used, the table base is set into the middle of - // the constant table. - int half_size = _size / 2; - assert(half_size * 2 == _size, "sanity"); - set_table_base_offset(-half_size); - } - } + _size = align_size_up(offset, CodeEntryAlignment); } void Compile::ConstantTable::emit(CodeBuffer& cb) { MacroAssembler _masm(&cb); - for (int t = 0; type_order[t] != T_ILLEGAL; t++) { - BasicType type = type_order[t]; - - for (int i = 0; i < _constants.length(); i++) { - Constant con = _constants.at(i); - if (con.type() != type) continue; // Skip other types. - - address constant_addr; - switch (con.type()) { - case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break; - case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break; - case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break; - case T_OBJECT: { - jobject obj = con.get_jobject(); - int oop_index = _masm.oop_recorder()->find_index(obj); - constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index)); - break; + for (int i = 0; i < _constants.length(); i++) { + Constant con = _constants.at(i); + address constant_addr; + switch (con.type()) { + case T_LONG: constant_addr = _masm.long_constant( con.get_jlong() ); break; + case T_FLOAT: constant_addr = _masm.float_constant( con.get_jfloat() ); break; + case T_DOUBLE: constant_addr = _masm.double_constant(con.get_jdouble()); break; + case T_OBJECT: { + jobject obj = con.get_jobject(); + int oop_index = _masm.oop_recorder()->find_index(obj); + constant_addr = _masm.address_constant((address) obj, oop_Relocation::spec(oop_index)); + break; + } + case T_ADDRESS: { + address addr = (address) con.get_jobject(); + constant_addr = _masm.address_constant(addr); + break; + } + // We use T_VOID as marker for jump-table entries (labels) which + // need an internal word relocation. + case T_VOID: { + MachConstantNode* n = (MachConstantNode*) con.get_jobject(); + // Fill the jump-table with a dummy word. The real value is + // filled in later in fill_jump_table. + address dummy = (address) n; + constant_addr = _masm.address_constant(dummy); + // Expand jump-table + for (uint i = 1; i < n->outcnt(); i++) { + address temp_addr = _masm.address_constant(dummy + i); + assert(temp_addr, "consts section too small"); } - case T_ADDRESS: { - address addr = (address) con.get_jobject(); - constant_addr = _masm.address_constant(addr); - break; - } - // We use T_VOID as marker for jump-table entries (labels) which - // need an interal word relocation. - case T_VOID: { - // Write a dummy word. The real value is filled in later - // in fill_jump_table_in_constant_table. - address addr = (address) con.get_jobject(); - constant_addr = _masm.address_constant(addr); - break; - } - default: ShouldNotReachHere(); - } - assert(constant_addr != NULL, "consts section too small"); - assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), err_msg("must be: %d == %d", constant_addr - _masm.code()->consts()->start(), con.offset())); + break; } + default: ShouldNotReachHere(); + } + assert(constant_addr, "consts section too small"); + assert((constant_addr - _masm.code()->consts()->start()) == con.offset(), err_msg("must be: %d == %d", constant_addr - _masm.code()->consts()->start(), con.offset())); } } @@ -3175,19 +3180,21 @@ if (con.can_be_reused()) { int idx = _constants.find(con); if (idx != -1 && _constants.at(idx).can_be_reused()) { + _constants.adr_at(idx)->inc_freq(con.freq()); // increase the frequency by the current value return; } } (void) _constants.append(con); } -Compile::Constant Compile::ConstantTable::add(BasicType type, jvalue value) { - Constant con(type, value); +Compile::Constant Compile::ConstantTable::add(MachConstantNode* n, BasicType type, jvalue value) { + Block* b = Compile::current()->cfg()->_bbs[n->_idx]; + Constant con(type, value, b->_freq); add(con); return con; } -Compile::Constant Compile::ConstantTable::add(MachOper* oper) { +Compile::Constant Compile::ConstantTable::add(MachConstantNode* n, MachOper* oper) { jvalue value; BasicType type = oper->type()->basic_type(); switch (type) { @@ -3198,20 +3205,18 @@ case T_ADDRESS: value.l = (jobject) oper->constant(); break; default: ShouldNotReachHere(); } - return add(type, value); + return add(n, type, value); } -Compile::Constant Compile::ConstantTable::allocate_jump_table(MachConstantNode* n) { +Compile::Constant Compile::ConstantTable::add_jump_table(MachConstantNode* n) { jvalue value; // We can use the node pointer here to identify the right jump-table // as this method is called from Compile::Fill_buffer right before // the MachNodes are emitted and the jump-table is filled (means the // MachNode pointers do not change anymore). value.l = (jobject) n; - Constant con(T_VOID, value, false); // Labels of a jump-table cannot be reused. - for (uint i = 0; i < n->outcnt(); i++) { - add(con); - } + Constant con(T_VOID, value, next_jump_table_freq(), false); // Labels of a jump-table cannot be reused. + add(con); return con; } @@ -3230,9 +3235,9 @@ MacroAssembler _masm(&cb); address* jump_table_base = (address*) (_masm.code()->consts()->start() + offset); - for (int i = 0; i < labels.length(); i++) { + for (uint i = 0; i < n->outcnt(); i++) { address* constant_addr = &jump_table_base[i]; - assert(*constant_addr == (address) n, "all jump-table entries must contain node pointer"); + assert(*constant_addr == (((address) n) + i), err_msg("all jump-table entries must contain adjusted node pointer: " INTPTR_FORMAT " == " INTPTR_FORMAT, *constant_addr, (((address) n) + i))); *constant_addr = cb.consts()->target(*labels.at(i), (address) constant_addr); cb.consts()->relocate((address) constant_addr, relocInfo::internal_word_type); } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/compile.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -150,14 +150,16 @@ BasicType _type; jvalue _value; int _offset; // offset of this constant (in bytes) relative to the constant table base. + float _freq; bool _can_be_reused; // true (default) if the value can be shared with other users. public: - Constant() : _type(T_ILLEGAL), _offset(-1), _can_be_reused(true) { _value.l = 0; } - Constant(BasicType type, jvalue value, bool can_be_reused = true) : + Constant() : _type(T_ILLEGAL), _offset(-1), _freq(0.0f), _can_be_reused(true) { _value.l = 0; } + Constant(BasicType type, jvalue value, float freq = 0.0f, bool can_be_reused = true) : _type(type), _value(value), _offset(-1), + _freq(freq), _can_be_reused(can_be_reused) {} @@ -173,6 +175,9 @@ int offset() const { return _offset; } void set_offset(int offset) { _offset = offset; } + float freq() const { return _freq; } + void inc_freq(float freq) { _freq += freq; } + bool can_be_reused() const { return _can_be_reused; } }; @@ -182,41 +187,51 @@ GrowableArray _constants; // Constants of this table. int _size; // Size in bytes the emitted constant table takes (including padding). int _table_base_offset; // Offset of the table base that gets added to the constant offsets. + int _nof_jump_tables; // Number of jump-tables in this constant table. + + static int qsort_comparator(Constant* a, Constant* b); + + // We use negative frequencies to keep the order of the + // jump-tables in which they were added. Otherwise we get into + // trouble with relocation. + float next_jump_table_freq() { return -1.0f * (++_nof_jump_tables); } public: ConstantTable() : _size(-1), - _table_base_offset(-1) // We can use -1 here since the constant table is always bigger than 2 bytes (-(size / 2), see MachConstantBaseNode::emit). + _table_base_offset(-1), // We can use -1 here since the constant table is always bigger than 2 bytes (-(size / 2), see MachConstantBaseNode::emit). + _nof_jump_tables(0) {} - int size() const { assert(_size != -1, "size not yet calculated"); return _size; } + int size() const { assert(_size != -1, "not calculated yet"); return _size; } - void set_table_base_offset(int x) { assert(_table_base_offset == -1, "set only once"); _table_base_offset = x; } - int table_base_offset() const { assert(_table_base_offset != -1, "table base offset not yet set"); return _table_base_offset; } + int calculate_table_base_offset() const; // AD specific + void set_table_base_offset(int x) { assert(_table_base_offset == -1 || x == _table_base_offset, "can't change"); _table_base_offset = x; } + int table_base_offset() const { assert(_table_base_offset != -1, "not set yet"); return _table_base_offset; } void emit(CodeBuffer& cb); // Returns the offset of the last entry (the top) of the constant table. - int top_offset() const { assert(_constants.top().offset() != -1, "constant not yet bound"); return _constants.top().offset(); } + int top_offset() const { assert(_constants.top().offset() != -1, "not bound yet"); return _constants.top().offset(); } void calculate_offsets_and_size(); int find_offset(Constant& con) const; void add(Constant& con); - Constant add(BasicType type, jvalue value); - Constant add(MachOper* oper); - Constant add(jfloat f) { + Constant add(MachConstantNode* n, BasicType type, jvalue value); + Constant add(MachConstantNode* n, MachOper* oper); + Constant add(MachConstantNode* n, jfloat f) { jvalue value; value.f = f; - return add(T_FLOAT, value); + return add(n, T_FLOAT, value); } - Constant add(jdouble d) { + Constant add(MachConstantNode* n, jdouble d) { jvalue value; value.d = d; - return add(T_DOUBLE, value); + return add(n, T_DOUBLE, value); } - // Jump table - Constant allocate_jump_table(MachConstantNode* n); - void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray labels) const; + // Jump-table + Constant add_jump_table(MachConstantNode* n); + void fill_jump_table(CodeBuffer& cb, MachConstantNode* n, GrowableArray labels) const; }; private: diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/doCall.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -62,7 +62,6 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float prof_factor) { - CallGenerator* cg; ciMethod* caller = jvms->method(); int bci = jvms->bci(); Bytecodes::Code bytecode = caller->java_code_at_bci(bci); @@ -110,7 +109,7 @@ // We do this before the strict f.p. check below because the // intrinsics handle strict f.p. correctly. if (allow_inline) { - cg = find_intrinsic(call_method, call_is_virtual); + CallGenerator* cg = find_intrinsic(call_method, call_is_virtual); if (cg != NULL) return cg; } @@ -121,33 +120,16 @@ if (call_method->is_method_handle_invoke()) { if (bytecode != Bytecodes::_invokedynamic) { GraphKit kit(jvms); - Node* n = kit.argument(0); - - CallGenerator* cg = CallGenerator::for_method_handle_inline(n, jvms, caller, call_method, profile); - if (cg != NULL) { - return cg; - } - return CallGenerator::for_direct_call(call_method); + Node* method_handle = kit.argument(0); + return CallGenerator::for_method_handle_call(method_handle, jvms, caller, call_method, profile); } else { - // Get the CallSite object. - ciMethod* caller_method = jvms->method(); - ciBytecodeStream str(caller_method); - str.force_bci(jvms->bci()); // Set the stream to the invokedynamic bci. - ciCallSite* call_site = str.get_call_site(); - - CallGenerator* cg = CallGenerator::for_invokedynamic_inline(call_site, jvms, caller, call_method, profile); - if (cg != NULL) { - return cg; - } - // If something failed, generate a normal dynamic call. - return CallGenerator::for_dynamic_call(call_method); + return CallGenerator::for_invokedynamic_call(jvms, caller, call_method, profile); } } // Do not inline strict fp into non-strict code, or the reverse - bool caller_method_is_strict = jvms->method()->is_strict(); - if( caller_method_is_strict ^ call_method->is_strict() ) { + if (caller->is_strict() ^ call_method->is_strict()) { allow_inline = false; } @@ -258,7 +240,7 @@ } if (miss_cg != NULL) { NOT_PRODUCT(trace_type_profile(jvms->method(), jvms->depth() - 1, jvms->bci(), receiver_method, profile.receiver(0), site_count, receiver_count)); - cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0)); + CallGenerator* cg = CallGenerator::for_predicted_call(profile.receiver(0), miss_cg, hit_cg, profile.receiver_prob(0)); if (cg != NULL) return cg; } } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/escape.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -119,6 +119,8 @@ } else { _noop_null = _oop_null; // Should be initialized } + _pcmp_neq = NULL; // Should be initialized + _pcmp_eq = NULL; } void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) { @@ -128,6 +130,13 @@ assert(f->node_type() != PointsToNode::UnknownType && t->node_type() != PointsToNode::UnknownType, "node types must be set"); assert(f->node_type() == PointsToNode::LocalVar || f->node_type() == PointsToNode::Field, "invalid source of PointsTo edge"); assert(t->node_type() == PointsToNode::JavaObject, "invalid destination of PointsTo edge"); + if (to_i == _phantom_object) { // Quick test for most common object + if (f->has_unknown_ptr()) { + return; + } else { + f->set_has_unknown_ptr(); + } + } add_edge(f, to_i, PointsToNode::PointsToEdge); } @@ -163,6 +172,9 @@ } void ConnectionGraph::add_field_edge(uint from_i, uint to_i, int offset) { + // Don't add fields to NULL pointer. + if (is_null_ptr(from_i)) + return; PointsToNode *f = ptnode_adr(from_i); PointsToNode *t = ptnode_adr(to_i); @@ -177,7 +189,7 @@ void ConnectionGraph::set_escape_state(uint ni, PointsToNode::EscapeState es) { // Don't change non-escaping state of NULL pointer. - if (ni == _noop_null || ni == _oop_null) + if (is_null_ptr(ni)) return; PointsToNode *npt = ptnode_adr(ni); PointsToNode::EscapeState old_es = npt->escape_state(); @@ -309,6 +321,9 @@ visited->set(ni); PointsToNode *ptn = ptnode_adr(ni); + assert(ptn->node_type() == PointsToNode::LocalVar || + ptn->node_type() == PointsToNode::Field, "sanity"); + assert(ptn->edge_count() != 0, "should have at least phantom_object"); // Mark current edges as visited and move deferred edges to separate array. for (uint i = 0; i < ptn->edge_count(); ) { @@ -329,6 +344,7 @@ uint t = deferred_edges->at(next); PointsToNode *ptt = ptnode_adr(t); uint e_cnt = ptt->edge_count(); + assert(e_cnt != 0, "should have at least phantom_object"); for (uint e = 0; e < e_cnt; e++) { uint etgt = ptt->edge_target(e); if (visited->test_set(etgt)) @@ -337,10 +353,6 @@ PointsToNode::EdgeType et = ptt->edge_type(e); if (et == PointsToNode::PointsToEdge) { add_pointsto_edge(ni, etgt); - if(etgt == _phantom_object) { - // Special case - field set outside (globally escaping). - set_escape_state(ni, PointsToNode::GlobalEscape); - } } else if (et == PointsToNode::DeferredEdge) { deferred_edges->append(etgt); } else { @@ -348,6 +360,20 @@ } } } + if (ptn->edge_count() == 0) { + // No pointsto edges found after deferred edges are removed. + // For example, in the next case where call is replaced + // with uncommon trap and as result array's load references + // itself through deferred edges: + // + // A a = b[i]; + // if (c!=null) a = c.foo(); + // b[i] = a; + // + // Assume the value was set outside this method and + // add edge to phantom object. + add_pointsto_edge(ni, _phantom_object); + } } @@ -356,13 +382,25 @@ // a pointsto edge is added if it is a JavaObject void ConnectionGraph::add_edge_from_fields(uint adr_i, uint to_i, int offs) { + // No fields for NULL pointer. + if (is_null_ptr(adr_i)) { + return; + } PointsToNode* an = ptnode_adr(adr_i); PointsToNode* to = ptnode_adr(to_i); bool deferred = (to->node_type() == PointsToNode::LocalVar); - + bool escaped = (to_i == _phantom_object) && (offs == Type::OffsetTop); + if (escaped) { + // Values in fields escaped during call. + assert(an->escape_state() >= PointsToNode::ArgEscape, "sanity"); + offs = Type::OffsetBot; + } for (uint fe = 0; fe < an->edge_count(); fe++) { assert(an->edge_type(fe) == PointsToNode::FieldEdge, "expecting a field edge"); int fi = an->edge_target(fe); + if (escaped) { + set_escape_state(fi, PointsToNode::GlobalEscape); + } PointsToNode* pf = ptnode_adr(fi); int po = pf->offset(); if (po == offs || po == Type::OffsetBot || offs == Type::OffsetBot) { @@ -377,6 +415,15 @@ // Add a deferred edge from node given by "from_i" to any field of adr_i // whose offset matches "offset". void ConnectionGraph::add_deferred_edge_to_fields(uint from_i, uint adr_i, int offs) { + // No fields for NULL pointer. + if (is_null_ptr(adr_i)) { + return; + } + if (adr_i == _phantom_object) { + // Add only one edge for unknown object. + add_pointsto_edge(from_i, _phantom_object); + return; + } PointsToNode* an = ptnode_adr(adr_i); bool is_alloc = an->_node->is_Allocate(); for (uint fe = 0; fe < an->edge_count(); fe++) { @@ -392,6 +439,13 @@ add_deferred_edge(from_i, fi); } } + // Some fields references (AddP) may still be missing + // until Connection Graph construction is complete. + // For example, loads from RAW pointers with offset 0 + // which don't have AddP. + // A reference to phantom_object will be added if + // a field reference is still missing after completing + // Connection Graph (see remove_deferred()). } // Helper functions @@ -1540,8 +1594,8 @@ GrowableArray alloc_worklist; GrowableArray addp_worklist; + GrowableArray ptr_cmp_worklist; PhaseGVN* igvn = _igvn; - bool has_allocations = false; // Push all useful nodes onto CG list and set their type. for( uint next = 0; next < worklist_init.size(); ++next ) { @@ -1551,11 +1605,8 @@ // for an escape status. See process_call_result() below. if (n->is_Allocate() || n->is_CallStaticJava() && ptnode_adr(n->_idx)->node_type() == PointsToNode::JavaObject) { - has_allocations = true; - if (n->is_Allocate()) - alloc_worklist.append(n); - } - if(n->is_AddP()) { + alloc_worklist.append(n); + } else if(n->is_AddP()) { // Collect address nodes. Use them during stage 3 below // to build initial connection graph field edges. addp_worklist.append(n); @@ -1563,6 +1614,10 @@ // Collect all MergeMem nodes to add memory slices for // scalar replaceable objects in split_unique_types(). _mergemem_worklist.append(n->as_MergeMem()); + } else if (OptimizePtrCompare && n->is_Cmp() && + (n->Opcode() == Op_CmpP || n->Opcode() == Op_CmpN)) { + // Compare pointers nodes + ptr_cmp_worklist.append(n); } for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* m = n->fast_out(i); // Get user @@ -1570,7 +1625,7 @@ } } - if (!has_allocations) { + if (alloc_worklist.length() == 0) { _collecting = false; return false; // Nothing to do. } @@ -1588,7 +1643,7 @@ for( uint next = 0; next < addp_length; ++next ) { Node* n = addp_worklist.at(next); Node* base = get_addp_base(n); - if (base->is_Proj()) + if (base->is_Proj() && base->in(0)->is_Call()) base = base->in(0); PointsToNode::NodeType nt = ptnode_adr(base->_idx)->node_type(); if (nt == PointsToNode::JavaObject) { @@ -1653,39 +1708,7 @@ } #undef CG_BUILD_ITER_LIMIT - Arena* arena = Thread::current()->resource_area(); - VectorSet visited(arena); - - // 5. Find fields initializing values for not escaped allocations - uint alloc_length = alloc_worklist.length(); - for (uint next = 0; next < alloc_length; ++next) { - Node* n = alloc_worklist.at(next); - if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { - find_init_values(n, &visited, igvn); - } - } - - worklist.clear(); - - // 6. Remove deferred edges from the graph. - uint cg_length = cg_worklist.length(); - for (uint next = 0; next < cg_length; ++next) { - int ni = cg_worklist.at(next); - PointsToNode* ptn = ptnode_adr(ni); - PointsToNode::NodeType nt = ptn->node_type(); - if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { - remove_deferred(ni, &worklist, &visited); - Node *n = ptn->_node; - } - } - - // 7. Adjust escape state of nonescaping objects. - for (uint next = 0; next < addp_length; ++next) { - Node* n = addp_worklist.at(next); - adjust_escape_state(n); - } - - // 8. Propagate escape states. + // 5. Propagate escaped states. worklist.clear(); // mark all nodes reachable from GlobalEscape nodes @@ -1694,20 +1717,72 @@ // mark all nodes reachable from ArgEscape nodes bool has_non_escaping_obj = propagate_escape_state(&cg_worklist, &worklist, PointsToNode::ArgEscape); + Arena* arena = Thread::current()->resource_area(); + VectorSet visited(arena); + + // 6. Find fields initializing values for not escaped allocations + uint alloc_length = alloc_worklist.length(); + for (uint next = 0; next < alloc_length; ++next) { + Node* n = alloc_worklist.at(next); + if (ptnode_adr(n->_idx)->escape_state() == PointsToNode::NoEscape) { + has_non_escaping_obj = true; + if (n->is_Allocate()) { + find_init_values(n, &visited, igvn); + } + } + } + + uint cg_length = cg_worklist.length(); + + // Skip the rest of code if all objects escaped. + if (!has_non_escaping_obj) { + cg_length = 0; + addp_length = 0; + } + + for (uint next = 0; next < cg_length; ++next) { + int ni = cg_worklist.at(next); + PointsToNode* ptn = ptnode_adr(ni); + PointsToNode::NodeType nt = ptn->node_type(); + if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { + if (ptn->edge_count() == 0) { + // No values were found. Assume the value was set + // outside this method - add edge to phantom object. + add_pointsto_edge(ni, _phantom_object); + } + } + } + + // 7. Remove deferred edges from the graph. + for (uint next = 0; next < cg_length; ++next) { + int ni = cg_worklist.at(next); + PointsToNode* ptn = ptnode_adr(ni); + PointsToNode::NodeType nt = ptn->node_type(); + if (nt == PointsToNode::LocalVar || nt == PointsToNode::Field) { + remove_deferred(ni, &worklist, &visited); + } + } + + // 8. Adjust escape state of nonescaping objects. + for (uint next = 0; next < addp_length; ++next) { + Node* n = addp_worklist.at(next); + adjust_escape_state(n); + } + // push all NoEscape nodes on the worklist + worklist.clear(); for( uint next = 0; next < cg_length; ++next ) { int nk = cg_worklist.at(next); - if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape) + if (ptnode_adr(nk)->escape_state() == PointsToNode::NoEscape && + !is_null_ptr(nk)) worklist.push(nk); } + alloc_worklist.clear(); - // mark all nodes reachable from NoEscape nodes + // Propagate scalar_replaceable value. while(worklist.length() > 0) { uint nk = worklist.pop(); PointsToNode* ptn = ptnode_adr(nk); - if (ptn->node_type() == PointsToNode::JavaObject && - !(nk == _noop_null || nk == _oop_null)) - has_non_escaping_obj = true; // Non Escape Node* n = ptn->_node; bool scalar_replaceable = ptn->scalar_replaceable(); if (n->is_Allocate() && scalar_replaceable) { @@ -1719,6 +1794,8 @@ uint e_cnt = ptn->edge_count(); for (uint ei = 0; ei < e_cnt; ei++) { uint npi = ptn->edge_target(ei); + if (is_null_ptr(npi)) + continue; PointsToNode *np = ptnode_adr(npi); if (np->escape_state() < PointsToNode::NoEscape) { set_escape_state(npi, PointsToNode::NoEscape); @@ -1727,7 +1804,6 @@ } worklist.push(npi); } else if (np->scalar_replaceable() && !scalar_replaceable) { - // Propagate scalar_replaceable value. np->set_scalar_replaceable(false); worklist.push(npi); } @@ -1737,9 +1813,11 @@ _collecting = false; assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); - assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); + assert(ptnode_adr(_oop_null)->escape_state() == PointsToNode::NoEscape && + ptnode_adr(_oop_null)->edge_count() == 0, "sanity"); if (UseCompressedOops) { - assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape, "sanity"); + assert(ptnode_adr(_noop_null)->escape_state() == PointsToNode::NoEscape && + ptnode_adr(_noop_null)->edge_count() == 0, "sanity"); } if (EliminateLocks && has_non_escaping_obj) { @@ -1749,18 +1827,53 @@ Node *n = C->macro_node(i); if (n->is_AbstractLock()) { // Lock and Unlock nodes AbstractLockNode* alock = n->as_AbstractLock(); - if (!alock->is_eliminated()) { + if (!alock->is_eliminated() || alock->is_coarsened()) { PointsToNode::EscapeState es = escape_state(alock->obj_node()); assert(es != PointsToNode::UnknownEscape, "should know"); if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { - // Mark it eliminated - alock->set_eliminated(); + if (!alock->is_eliminated()) { + // Mark it eliminated to update any counters + alock->set_eliminated(); + } else { + // The lock could be marked eliminated by lock coarsening + // code during first IGVN before EA. Clear coarsened flag + // to eliminate all associated locks/unlocks and relock + // during deoptimization. + alock->clear_coarsened(); + } } } } } } + if (OptimizePtrCompare && has_non_escaping_obj) { + // Add ConI(#CC_GT) and ConI(#CC_EQ). + _pcmp_neq = igvn->makecon(TypeInt::CC_GT); + _pcmp_eq = igvn->makecon(TypeInt::CC_EQ); + // Optimize objects compare. + while (ptr_cmp_worklist.length() != 0) { + Node *n = ptr_cmp_worklist.pop(); + Node *res = optimize_ptr_compare(n); + if (res != NULL) { +#ifndef PRODUCT + if (PrintOptimizePtrCompare) { + tty->print_cr("++++ Replaced: %d %s(%d,%d) --> %s", n->_idx, (n->Opcode() == Op_CmpP ? "CmpP" : "CmpN"), n->in(1)->_idx, n->in(2)->_idx, (res == _pcmp_eq ? "EQ" : "NotEQ")); + if (Verbose) { + n->dump(1); + } + } +#endif + _igvn->replace_node(n, res); + } + } + // cleanup + if (_pcmp_neq->outcnt() == 0) + igvn->hash_delete(_pcmp_neq); + if (_pcmp_eq->outcnt() == 0) + igvn->hash_delete(_pcmp_eq); + } + #ifndef PRODUCT if (PrintEscapeAnalysis) { dump(); // Dump ConnectionGraph @@ -1821,15 +1934,30 @@ // Connection Graph does not record a default initialization by NULL // captured by Initialize node. // + uint null_idx = UseCompressedOops ? _noop_null : _oop_null; uint ae_cnt = pta->edge_count(); + bool visited_bottom_offset = false; for (uint ei = 0; ei < ae_cnt; ei++) { uint nidx = pta->edge_target(ei); // Field (AddP) PointsToNode* ptn = ptnode_adr(nidx); assert(ptn->_node->is_AddP(), "Should be AddP nodes only"); int offset = ptn->offset(); - if (offset != Type::OffsetBot && - offset != oopDesc::klass_offset_in_bytes() && - !visited->test_set(offset)) { + if (offset == Type::OffsetBot) { + if (!visited_bottom_offset) { + visited_bottom_offset = true; + // Check only oop fields. + const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); + if (!adr_type->isa_aryptr() || + (adr_type->isa_aryptr()->klass() == NULL) || + adr_type->isa_aryptr()->klass()->is_obj_array_klass()) { + // OffsetBot is used to reference array's element, + // always add reference to NULL since we don't + // known which element is referenced. + add_edge_from_fields(alloc->_idx, null_idx, offset); + } + } + } else if (offset != oopDesc::klass_offset_in_bytes() && + !visited->test_set(offset)) { // Check only oop fields. const Type* adr_type = ptn->_node->as_AddP()->bottom_type(); @@ -1904,7 +2032,6 @@ } if (value == NULL || value != ptnode_adr(value->_idx)->_node) { // A field's initializing value was not recorded. Add NULL. - uint null_idx = UseCompressedOops ? _noop_null : _oop_null; add_edge_from_fields(alloc->_idx, null_idx, offset); } } @@ -1990,13 +2117,21 @@ } // mark all reachable nodes while (worklist->length() > 0) { - PointsToNode* ptn = ptnode_adr(worklist->pop()); - if (ptn->node_type() == PointsToNode::JavaObject) { + int pt = worklist->pop(); + PointsToNode* ptn = ptnode_adr(pt); + if (ptn->node_type() == PointsToNode::JavaObject && + !is_null_ptr(pt)) { has_java_obj = true; + if (esc_state > PointsToNode::NoEscape) { + // fields values are unknown if object escapes + add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); + } } uint e_cnt = ptn->edge_count(); for (uint ei = 0; ei < e_cnt; ei++) { uint npi = ptn->edge_target(ei); + if (is_null_ptr(npi)) + continue; PointsToNode *np = ptnode_adr(npi); if (np->escape_state() < esc_state) { set_escape_state(npi, esc_state); @@ -2008,8 +2143,100 @@ return has_java_obj && (esc_state < PointsToNode::GlobalEscape); } +// Optimize objects compare. +Node* ConnectionGraph::optimize_ptr_compare(Node* n) { + assert(OptimizePtrCompare, "sanity"); + // Clone returned Set since PointsTo() returns pointer + // to the same structure ConnectionGraph.pt_ptset. + VectorSet ptset1 = *PointsTo(n->in(1)); + VectorSet ptset2 = *PointsTo(n->in(2)); + + // Check simple cases first. + if (ptset1.Size() == 1) { + uint pt1 = ptset1.getelem(); + PointsToNode* ptn1 = ptnode_adr(pt1); + if (ptn1->escape_state() == PointsToNode::NoEscape) { + if (ptset2.Size() == 1 && ptset2.getelem() == pt1) { + // Comparing the same not escaping object. + return _pcmp_eq; + } + Node* obj = ptn1->_node; + // Comparing not escaping allocation. + if ((obj->is_Allocate() || obj->is_CallStaticJava()) && + !ptset2.test(pt1)) { + return _pcmp_neq; // This includes nullness check. + } + } + } else if (ptset2.Size() == 1) { + uint pt2 = ptset2.getelem(); + PointsToNode* ptn2 = ptnode_adr(pt2); + if (ptn2->escape_state() == PointsToNode::NoEscape) { + Node* obj = ptn2->_node; + // Comparing not escaping allocation. + if ((obj->is_Allocate() || obj->is_CallStaticJava()) && + !ptset1.test(pt2)) { + return _pcmp_neq; // This includes nullness check. + } + } + } + + if (!ptset1.disjoint(ptset2)) { + return NULL; // Sets are not disjoint + } + + // Sets are disjoint. + bool set1_has_unknown_ptr = ptset1.test(_phantom_object) != 0; + bool set2_has_unknown_ptr = ptset2.test(_phantom_object) != 0; + bool set1_has_null_ptr = (ptset1.test(_oop_null) | ptset1.test(_noop_null)) != 0; + bool set2_has_null_ptr = (ptset2.test(_oop_null) | ptset2.test(_noop_null)) != 0; + + if (set1_has_unknown_ptr && set2_has_null_ptr || + set2_has_unknown_ptr && set1_has_null_ptr) { + // Check nullness of unknown object. + return NULL; + } + + // Disjointness by itself is not sufficient since + // alias analysis is not complete for escaped objects. + // Disjoint sets are definitely unrelated only when + // at least one set has only not escaping objects. + if (!set1_has_unknown_ptr && !set1_has_null_ptr) { + bool has_only_non_escaping_alloc = true; + for (VectorSetI i(&ptset1); i.test(); ++i) { + uint pt = i.elem; + PointsToNode* ptn = ptnode_adr(pt); + Node* obj = ptn->_node; + if (ptn->escape_state() != PointsToNode::NoEscape || + !(obj->is_Allocate() || obj->is_CallStaticJava())) { + has_only_non_escaping_alloc = false; + break; + } + } + if (has_only_non_escaping_alloc) { + return _pcmp_neq; + } + } + if (!set2_has_unknown_ptr && !set2_has_null_ptr) { + bool has_only_non_escaping_alloc = true; + for (VectorSetI i(&ptset2); i.test(); ++i) { + uint pt = i.elem; + PointsToNode* ptn = ptnode_adr(pt); + Node* obj = ptn->_node; + if (ptn->escape_state() != PointsToNode::NoEscape || + !(obj->is_Allocate() || obj->is_CallStaticJava())) { + has_only_non_escaping_alloc = false; + break; + } + } + if (has_only_non_escaping_alloc) { + return _pcmp_neq; + } + } + return NULL; +} + void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *phase) { - + bool is_arraycopy = false; switch (call->Opcode()) { #ifdef ASSERT case Op_Allocate: @@ -2019,25 +2246,44 @@ assert(false, "should be done already"); break; #endif + case Op_CallLeafNoFP: + is_arraycopy = (call->as_CallLeaf()->_name != NULL && + strstr(call->as_CallLeaf()->_name, "arraycopy") != 0); + // fall through case Op_CallLeaf: - case Op_CallLeafNoFP: { // Stub calls, objects do not escape but they are not scale replaceable. // Adjust escape state for outgoing arguments. const TypeTuple * d = call->tf()->domain(); + bool src_has_oops = false; for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { const Type* at = d->field_at(i); Node *arg = call->in(i)->uncast(); const Type *aat = phase->type(arg); + PointsToNode::EscapeState arg_esc = ptnode_adr(arg->_idx)->escape_state(); if (!arg->is_top() && at->isa_ptr() && aat->isa_ptr() && - ptnode_adr(arg->_idx)->escape_state() < PointsToNode::ArgEscape) { + (is_arraycopy || arg_esc < PointsToNode::ArgEscape)) { assert(aat == Type::TOP || aat == TypePtr::NULL_PTR || aat->isa_ptr() != NULL, "expecting an Ptr"); + bool arg_has_oops = aat->isa_oopptr() && + (aat->isa_oopptr()->klass() == NULL || aat->isa_instptr() || + (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); + if (i == TypeFunc::Parms) { + src_has_oops = arg_has_oops; + } + // + // src or dst could be j.l.Object when other is basic type array: + // + // arraycopy(char[],0,Object*,0,size); + // arraycopy(Object*,0,char[],0,size); + // + // Don't add edges from dst's fields in such cases. + // + bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && + arg_has_oops && (i > TypeFunc::Parms); #ifdef ASSERT - if (!(call->Opcode() == Op_CallLeafNoFP && - call->as_CallLeaf()->_name != NULL && - (strstr(call->as_CallLeaf()->_name, "arraycopy") != 0) || + if (!(is_arraycopy || call->as_CallLeaf()->_name != NULL && (strcmp(call->as_CallLeaf()->_name, "g1_wb_pre") == 0 || strcmp(call->as_CallLeaf()->_name, "g1_wb_post") == 0 )) @@ -2046,20 +2292,72 @@ assert(false, "EA: unexpected CallLeaf"); } #endif + // Always process arraycopy's destination object since + // we need to add all possible edges to references in + // source object. + if (arg_esc >= PointsToNode::ArgEscape && + !arg_is_arraycopy_dest) { + continue; + } set_escape_state(arg->_idx, PointsToNode::ArgEscape); + Node* arg_base = arg; if (arg->is_AddP()) { // // The inline_native_clone() case when the arraycopy stub is called // after the allocation before Initialize and CheckCastPP nodes. + // Or normal arraycopy for object arrays case. // // Set AddP's base (Allocate) as not scalar replaceable since // pointer to the base (with offset) is passed as argument. // - arg = get_addp_base(arg); + arg_base = get_addp_base(arg); } - for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { - uint pt = j.elem; - set_escape_state(pt, PointsToNode::ArgEscape); + VectorSet argset = *PointsTo(arg_base); // Clone set + for( VectorSetI j(&argset); j.test(); ++j ) { + uint pd = j.elem; // Destination object + set_escape_state(pd, PointsToNode::ArgEscape); + + if (arg_is_arraycopy_dest) { + PointsToNode* ptd = ptnode_adr(pd); + // Conservatively reference an unknown object since + // not all source's fields/elements may be known. + add_edge_from_fields(pd, _phantom_object, Type::OffsetBot); + + Node *src = call->in(TypeFunc::Parms)->uncast(); + Node* src_base = src; + if (src->is_AddP()) { + src_base = get_addp_base(src); + } + // Create edges from destination's fields to + // everything known source's fields could point to. + for( VectorSetI s(PointsTo(src_base)); s.test(); ++s ) { + uint ps = s.elem; + bool has_bottom_offset = false; + for (uint fd = 0; fd < ptd->edge_count(); fd++) { + assert(ptd->edge_type(fd) == PointsToNode::FieldEdge, "expecting a field edge"); + int fdi = ptd->edge_target(fd); + PointsToNode* pfd = ptnode_adr(fdi); + int offset = pfd->offset(); + if (offset == Type::OffsetBot) + has_bottom_offset = true; + assert(offset != -1, "offset should be set"); + add_deferred_edge_to_fields(fdi, ps, offset); + } + // Destination object may not have access (no field edge) + // to fields which are accessed in source object. + // As result no edges will be created to those source's + // fields and escape state of destination object will + // not be propagated to those fields. + // + // Mark source object as global escape except in + // the case with Type::OffsetBot field (which is + // common case for array elements access) when + // edges are created to all source's fields. + if (!has_bottom_offset) { + set_escape_state(ps, PointsToNode::GlobalEscape); + } + } + } } } } @@ -2102,14 +2400,16 @@ for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { uint pt = j.elem; if (global_escapes) { - //The argument global escapes, mark everything it could point to + // The argument global escapes, mark everything it could point to set_escape_state(pt, PointsToNode::GlobalEscape); + add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); } else { + set_escape_state(pt, PointsToNode::ArgEscape); if (fields_escapes) { - // The argument itself doesn't escape, but any fields might - add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); + // The argument itself doesn't escape, but any fields might. + // Use OffsetTop to indicate such case. + add_edge_from_fields(pt, _phantom_object, Type::OffsetTop); } - set_escape_state(pt, PointsToNode::ArgEscape); } } } @@ -2135,6 +2435,7 @@ for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) { uint pt = j.elem; set_escape_state(pt, PointsToNode::GlobalEscape); + add_edge_from_fields(pt, _phantom_object, Type::OffsetBot); } } } @@ -2235,15 +2536,16 @@ // it's fields will be marked as NoEscape at least. set_escape_state(call_idx, PointsToNode::NoEscape); ptnode_adr(call_idx)->set_scalar_replaceable(false); + // Fields values are unknown + add_edge_from_fields(call_idx, _phantom_object, Type::OffsetBot); add_pointsto_edge(resproj_idx, call_idx); copy_dependencies = true; - } else if (call_analyzer->is_return_local()) { + } else { // determine whether any arguments are returned set_escape_state(call_idx, PointsToNode::ArgEscape); bool ret_arg = false; for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { const Type* at = d->field_at(i); - if (at->isa_oopptr() != NULL) { Node *arg = call->in(i)->uncast(); @@ -2259,17 +2561,14 @@ } } } - if (done && !ret_arg) { - // Returns unknown object. - set_escape_state(call_idx, PointsToNode::GlobalEscape); - add_pointsto_edge(resproj_idx, _phantom_object); - } if (done) { copy_dependencies = true; + // is_return_local() is true when only arguments are returned. + if (!ret_arg || !call_analyzer->is_return_local()) { + // Returns unknown object. + add_pointsto_edge(resproj_idx, _phantom_object); + } } - } else { - set_escape_state(call_idx, PointsToNode::GlobalEscape); - add_pointsto_edge(resproj_idx, _phantom_object); } if (copy_dependencies) call_analyzer->copy_dependencies(_compile->dependencies()); @@ -2431,6 +2730,11 @@ add_node(n, PointsToNode::JavaObject, PointsToNode::GlobalEscape, false); break; } + case Op_PartialSubtypeCheck: + { // Produces Null or notNull and is used in CmpP. + add_node(n, PointsToNode::JavaObject, PointsToNode::ArgEscape, true); + break; + } case Op_Phi: { const Type *t = n->as_Phi()->type(); @@ -2589,10 +2893,11 @@ case Op_AddP: { Node *base = get_addp_base(n); + int offset = address_offset(n, phase); // Create a field edge to this node from everything base could point to. for( VectorSetI i(PointsTo(base)); i.test(); ++i ) { uint pt = i.elem; - add_field_edge(pt, n_idx, address_offset(n, phase)); + add_field_edge(pt, n_idx, offset); } break; } @@ -2659,6 +2964,10 @@ int offset = address_offset(adr, phase); for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) { uint pt = i.elem; + if (adr->is_AddP()) { + // Add field edge if it is missing. + add_field_edge(pt, adr->_idx, offset); + } add_deferred_edge_to_fields(n_idx, pt, offset); } break; @@ -2668,6 +2977,11 @@ assert(false, "Op_Parm"); break; } + case Op_PartialSubtypeCheck: + { + assert(false, "Op_PartialSubtypeCheck"); + break; + } case Op_Phi: { #ifdef ASSERT @@ -2745,11 +3059,14 @@ assert(adr->is_AddP(), "expecting an AddP"); Node *adr_base = get_addp_base(adr); Node *val = n->in(MemNode::ValueIn)->uncast(); + int offset = address_offset(adr, phase); // For everything "adr_base" could point to, create a deferred edge // to "val" from each field with the same offset. for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) { uint pt = i.elem; - add_edge_from_fields(pt, val->_idx, address_offset(adr, phase)); + // Add field edge if it is missing. + add_field_edge(pt, adr->_idx, offset); + add_edge_from_fields(pt, val->_idx, offset); } break; } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/escape.hpp --- a/src/share/vm/opto/escape.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/escape.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -160,6 +160,7 @@ Node* _node; // Ideal node corresponding to this PointsTo node. int _offset; // Object fields offsets. bool _scalar_replaceable; // Not escaped object could be replaced with scalar + bool _has_unknown_ptr; // Has edge to phantom_object public: PointsToNode(): @@ -168,6 +169,7 @@ _edges(NULL), _node(NULL), _offset(-1), + _has_unknown_ptr(false), _scalar_replaceable(true) {} @@ -175,6 +177,7 @@ NodeType node_type() const { return _type;} int offset() { return _offset;} bool scalar_replaceable() { return _scalar_replaceable;} + bool has_unknown_ptr() { return _has_unknown_ptr;} void set_offset(int offs) { _offset = offs;} void set_escape_state(EscapeState state) { _escape = state; } @@ -183,6 +186,7 @@ _type = ntype; } void set_scalar_replaceable(bool v) { _scalar_replaceable = v; } + void set_has_unknown_ptr() { _has_unknown_ptr = true; } // count of outgoing edges uint edge_count() const { return (_edges == NULL) ? 0 : _edges->length(); } @@ -236,6 +240,8 @@ // are assumed to point to. uint _oop_null; // ConP(#NULL)->_idx uint _noop_null; // ConN(#NULL)->_idx + Node* _pcmp_neq; // ConI(#CC_GT) + Node* _pcmp_eq; // ConI(#CC_EQ) Compile * _compile; // Compile object for current compilation PhaseIterGVN * _igvn; // Value numbering @@ -248,6 +254,8 @@ } uint nodes_size() const { return _nodes.length(); } + bool is_null_ptr(uint idx) const { return (idx == _noop_null || idx == _oop_null); } + // Add node to ConnectionGraph. void add_node(Node *n, PointsToNode::NodeType nt, PointsToNode::EscapeState es, bool done); @@ -331,10 +339,9 @@ } // Notify optimizer that a node has been modified - // Node: This assumes that escape analysis is run before - // PhaseIterGVN creation void record_for_optimizer(Node *n) { _igvn->_worklist.push(n); + _igvn->add_users_to_worklist(n); } // Set the escape state of a node @@ -351,6 +358,9 @@ GrowableArray* worklist, PointsToNode::EscapeState esc_state); + // Optimize objects compare. + Node* optimize_ptr_compare(Node* n); + // Compute the escape information bool compute_escape(); diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/gcm.cpp --- a/src/share/vm/opto/gcm.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/gcm.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -95,7 +95,7 @@ assert(in0 != NULL, "Only control-dependent"); const Node *p = in0->is_block_proj(); if (p != NULL && p != n) { // Control from a block projection? - assert(!n->pinned() || n->is_MachConstantBase() || n->is_SafePointScalarObject(), "only pinned MachConstantBase or SafePointScalarObject node is expected here"); + assert(!n->pinned() || n->is_MachConstantBase(), "only pinned MachConstantBase node is expected here"); // Find trailing Region Block *pb = _bbs[in0->_idx]; // Block-projection already has basic block uint j = 0; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/idealGraphPrinter.cpp --- a/src/share/vm/opto/idealGraphPrinter.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/idealGraphPrinter.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -447,6 +447,9 @@ if (flags & Node::Flag_may_be_short_branch) { print_prop("may_be_short_branch", "true"); } + if (flags & Node::Flag_has_call) { + print_prop("has_call", "true"); + } if (C->matcher() != NULL) { if (C->matcher()->is_shared(node)) { diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/lcm.cpp --- a/src/share/vm/opto/lcm.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/lcm.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -548,6 +548,22 @@ set_next_call(call, next_call, bbs); } +//------------------------------add_call_kills------------------------------------- +void Block::add_call_kills(MachProjNode *proj, RegMask& regs, const char* save_policy, bool exclude_soe) { + // Fill in the kill mask for the call + for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) { + if( !regs.Member(r) ) { // Not already defined by the call + // Save-on-call register? + if ((save_policy[r] == 'C') || + (save_policy[r] == 'A') || + ((save_policy[r] == 'E') && exclude_soe)) { + proj->_rout.Insert(r); + } + } + } +} + + //------------------------------sched_call------------------------------------- uint Block::sched_call( Matcher &matcher, Block_Array &bbs, uint node_cnt, Node_List &worklist, int *ready_cnt, MachCallNode *mcall, VectorSet &next_call ) { RegMask regs; @@ -631,17 +647,7 @@ proj->_rout.OR(Matcher::method_handle_invoke_SP_save_mask()); } - // Fill in the kill mask for the call - for( OptoReg::Name r = OptoReg::Name(0); r < _last_Mach_Reg; r=OptoReg::add(r,1) ) { - if( !regs.Member(r) ) { // Not already defined by the call - // Save-on-call register? - if ((save_policy[r] == 'C') || - (save_policy[r] == 'A') || - ((save_policy[r] == 'E') && exclude_soe)) { - proj->_rout.Insert(r); - } - } - } + add_call_kills(proj, regs, save_policy, exclude_soe); return node_cnt; } @@ -776,6 +782,7 @@ } #endif + uint max_idx = matcher.C->unique(); // Pull from worklist and schedule while( worklist.size() ) { // Worklist is not ready @@ -815,11 +822,28 @@ phi_cnt = sched_call(matcher, cfg->_bbs, phi_cnt, worklist, ready_cnt, mcall, next_call); continue; } + + if (n->is_Mach() && n->as_Mach()->has_call()) { + RegMask regs; + regs.Insert(matcher.c_frame_pointer()); + regs.OR(n->out_RegMask()); + + MachProjNode *proj = new (matcher.C, 1) MachProjNode( n, 1, RegMask::Empty, MachProjNode::fat_proj ); + cfg->_bbs.map(proj->_idx,this); + _nodes.insert(phi_cnt++, proj); + + add_call_kills(proj, regs, matcher._c_reg_save_policy, false); + } + // Children are now all ready for (DUIterator_Fast i5max, i5 = n->fast_outs(i5max); i5 < i5max; i5++) { Node* m = n->fast_out(i5); // Get user if( cfg->_bbs[m->_idx] != this ) continue; if( m->is_Phi() ) continue; + if (m->_idx > max_idx) { // new node, skip it + assert(m->is_MachProj() && n->is_Mach() && n->as_Mach()->has_call(), "unexpected node types"); + continue; + } if( !--ready_cnt[m->_idx] ) worklist.push(m); } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/loopnode.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -715,7 +715,6 @@ long limit_con = cl->limit()->get_int(); julong trip_cnt = cl->trip_count(); long final_con = init_con + trip_cnt*stride_con; - final_con -= stride_con; int final_int = (int)final_con; // The final value should be in integer range since the loop // is counted and the limit was checked for overflow. @@ -1947,7 +1946,7 @@ } // Nothing to do, so get out - if( !C->has_loops() && !do_split_ifs && !_verify_me && !_verify_only ) { + if( !C->has_loops() && !skip_loop_opts && !do_split_ifs && !_verify_me && !_verify_only ) { _igvn.optimize(); // Cleanup NeverBranches return; } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/machnode.cpp --- a/src/share/vm/opto/machnode.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/machnode.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -480,21 +480,20 @@ //============================================================================= int MachConstantNode::constant_offset() { - int offset = _constant.offset(); // Bind the offset lazily. - if (offset == -1) { + if (_constant.offset() == -1) { Compile::ConstantTable& constant_table = Compile::current()->constant_table(); - // If called from Compile::scratch_emit_size assume the worst-case - // for load offsets: half the constant table size. - // NOTE: Don't return or calculate the actual offset (which might - // be zero) because that leads to problems with e.g. jumpXtnd on - // some architectures (cf. add-optimization in SPARC jumpXtnd). - if (Compile::current()->in_scratch_emit_size()) - return constant_table.size() / 2; - offset = constant_table.table_base_offset() + constant_table.find_offset(_constant); - _constant.set_offset(offset); + int offset = constant_table.find_offset(_constant); + // If called from Compile::scratch_emit_size return the + // pre-calculated offset. + // NOTE: If the AD file does some table base offset optimizations + // later the AD file needs to take care of this fact. + if (Compile::current()->in_scratch_emit_size()) { + return constant_table.calculate_table_base_offset() + offset; + } + _constant.set_offset(constant_table.table_base_offset() + offset); } - return offset; + return _constant.offset(); } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/machnode.hpp --- a/src/share/vm/opto/machnode.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/machnode.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -190,6 +190,9 @@ // Avoid back to back some instructions on some CPUs. bool avoid_back_to_back() const { return (flags() & Flag_avoid_back_to_back) != 0; } + // instruction implemented with a call + bool has_call() const { return (flags() & Flag_has_call) != 0; } + // First index in _in[] corresponding to operand, or -1 if there is none int operand_index(uint operand) const; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/macro.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -81,7 +81,7 @@ uint old_unique = C->unique(); Node* new_in = old_sosn->clone(jvms_adj, sosn_map); if (old_unique != C->unique()) { - new_in->set_req(0, newcall->in(0)); // reset control edge + new_in->set_req(0, C->root()); // reset control edge new_in = transform_later(new_in); // Register new node. } old_in = new_in; @@ -565,7 +565,6 @@ if (res == NULL) { // All users were eliminated. } else if (!res->is_CheckCastPP()) { - alloc->_is_scalar_replaceable = false; // don't try again NOT_PRODUCT(fail_eliminate = "Allocation does not have unique CheckCastPP";) can_eliminate = false; } else { @@ -719,7 +718,7 @@ alloc, #endif first_ind, nfields); - sobj->init_req(0, sfpt->in(TypeFunc::Control)); + sobj->init_req(0, C->root()); transform_later(sobj); // Scan object's fields adding an input to the safepoint for each field. @@ -762,10 +761,10 @@ Node *field_val = value_from_mem(mem, basic_elem_type, field_type, field_addr_type, alloc); if (field_val == NULL) { - // we weren't able to find a value for this field, - // give up on eliminating this allocation - alloc->_is_scalar_replaceable = false; // don't try again - // remove any extra entries we added to the safepoint + // We weren't able to find a value for this field, + // give up on eliminating this allocation. + + // Remove any extra entries we added to the safepoint. uint last = sfpt->req() - 1; for (int k = 0; k < j; k++) { sfpt->del_req(last--); @@ -1804,9 +1803,9 @@ #ifndef PRODUCT if (PrintEliminateLocks) { if (alock->is_Lock()) { - tty->print_cr("++++ Eliminating: %d Lock", alock->_idx); + tty->print_cr("++++ Eliminated: %d Lock", alock->_idx); } else { - tty->print_cr("++++ Eliminating: %d Unlock", alock->_idx); + tty->print_cr("++++ Eliminated: %d Unlock", alock->_idx); } } #endif @@ -2165,11 +2164,12 @@ _igvn.replace_node(_memproj_fallthrough, mem_phi); } -//------------------------------expand_macro_nodes---------------------- -// Returns true if a failure occurred. -bool PhaseMacroExpand::expand_macro_nodes() { +//---------------------------eliminate_macro_nodes---------------------- +// Eliminate scalar replaced allocations and associated locks. +void PhaseMacroExpand::eliminate_macro_nodes() { if (C->macro_count() == 0) - return false; + return; + // First, attempt to eliminate locks int cnt = C->macro_count(); for (int i=0; i < cnt; i++) { @@ -2189,14 +2189,6 @@ debug_only(int old_macro_count = C->macro_count();); if (n->is_AbstractLock()) { success = eliminate_locking_node(n->as_AbstractLock()); - } else if (n->Opcode() == Op_LoopLimit) { - // Remove it from macro list and put on IGVN worklist to optimize. - C->remove_macro_node(n); - _igvn._worklist.push(n); - success = true; - } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { - _igvn.replace_node(n, n->in(1)); - success = true; } assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); progress = progress || success; @@ -2220,18 +2212,50 @@ assert(!n->as_AbstractLock()->is_eliminated(), "sanity"); break; default: - assert(false, "unknown node type in macro list"); + assert(n->Opcode() == Op_LoopLimit || + n->Opcode() == Op_Opaque1 || + n->Opcode() == Op_Opaque2, "unknown node type in macro list"); } assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); progress = progress || success; } } +} + +//------------------------------expand_macro_nodes---------------------- +// Returns true if a failure occurred. +bool PhaseMacroExpand::expand_macro_nodes() { + // Last attempt to eliminate macro nodes. + eliminate_macro_nodes(); + // Make sure expansion will not cause node limit to be exceeded. // Worst case is a macro node gets expanded into about 50 nodes. // Allow 50% more for optimization. if (C->check_node_count(C->macro_count() * 75, "out of nodes before macro expansion" ) ) return true; + // Eliminate Opaque and LoopLimit nodes. Do it after all loop optimizations. + bool progress = true; + while (progress) { + progress = false; + for (int i = C->macro_count(); i > 0; i--) { + Node * n = C->macro_node(i-1); + bool success = false; + debug_only(int old_macro_count = C->macro_count();); + if (n->Opcode() == Op_LoopLimit) { + // Remove it from macro list and put on IGVN worklist to optimize. + C->remove_macro_node(n); + _igvn._worklist.push(n); + success = true; + } else if (n->Opcode() == Op_Opaque1 || n->Opcode() == Op_Opaque2) { + _igvn.replace_node(n, n->in(1)); + success = true; + } + assert(success == (C->macro_count() < old_macro_count), "elimination reduces macro count"); + progress = progress || success; + } + } + // expand "macro" nodes // nodes are removed from the macro list as they are processed while (C->macro_count() > 0) { @@ -2265,5 +2289,6 @@ _igvn.set_delay_transform(false); _igvn.optimize(); + if (C->failing()) return true; return false; } diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/macro.hpp --- a/src/share/vm/opto/macro.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/macro.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -119,6 +119,7 @@ PhaseMacroExpand(PhaseIterGVN &igvn) : Phase(Macro_Expand), _igvn(igvn) { _igvn.set_delay_transform(true); } + void eliminate_macro_nodes(); bool expand_macro_nodes(); }; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/matcher.hpp --- a/src/share/vm/opto/matcher.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/matcher.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -294,7 +294,6 @@ RegMask _return_value_mask; // Inline Cache Register static OptoReg::Name inline_cache_reg(); - static const RegMask &inline_cache_reg_mask(); static int inline_cache_reg_encode(); // Register for DIVI projection of divmodI @@ -324,7 +323,6 @@ // and then expanded into the inline_cache_reg and a method_oop register static OptoReg::Name interpreter_method_oop_reg(); - static const RegMask &interpreter_method_oop_reg_mask(); static int interpreter_method_oop_reg_encode(); static OptoReg::Name compiler_method_oop_reg(); @@ -333,7 +331,6 @@ // Interpreter's Frame Pointer Register static OptoReg::Name interpreter_frame_pointer_reg(); - static const RegMask &interpreter_frame_pointer_reg_mask(); // Java-Native calling convention // (what you use when intercalling between Java and C++ code) @@ -371,10 +368,6 @@ // registers? True for Intel but false for most RISCs static const bool clone_shift_expressions; - // Should constant table entries be accessed with loads using - // absolute addressing? True for x86 but false for most RISCs. - static const bool constant_table_absolute_addressing; - static bool narrow_oop_use_complex_address(); // Generate implicit null check for narrow oops if it can fold diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/memnode.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -265,6 +265,13 @@ if( phase->type( mem ) == Type::TOP ) return NodeSentinel; // caller will return NULL assert( mem != this, "dead loop in MemNode::Ideal" ); + if (can_reshape && igvn != NULL && igvn->_worklist.member(mem)) { + // This memory slice may be dead. + // Delay this mem node transformation until the memory is processed. + phase->is_IterGVN()->_worklist.push(this); + return NodeSentinel; // caller will return NULL + } + Node *address = in(MemNode::Address); const Type *t_adr = phase->type( address ); if( t_adr == Type::TOP ) return NodeSentinel; // caller will return NULL @@ -2661,6 +2668,8 @@ // control copies Node *StrIntrinsicNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (remove_dead_region(phase, can_reshape)) return this; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; if (can_reshape) { Node* mem = phase->transform(in(MemNode::Memory)); @@ -2675,6 +2684,12 @@ return NULL; } +//------------------------------Value------------------------------------------ +const Type *StrIntrinsicNode::Value( PhaseTransform *phase ) const { + if (in(0) && phase->type(in(0)) == Type::TOP) return Type::TOP; + return bottom_type(); +} + //============================================================================= MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent) : MultiNode(TypeFunc::Parms + (precedent == NULL? 0: 1)), @@ -2715,6 +2730,8 @@ // control copies Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (remove_dead_region(phase, can_reshape)) return this; + // Don't bother trying to transform a dead node + if (in(0) && in(0)->is_top()) return NULL; // Eliminate volatile MemBars for scalar replaced objects. if (can_reshape && req() == (Precedent+1) && diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/memnode.hpp --- a/src/share/vm/opto/memnode.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/memnode.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -800,6 +800,7 @@ virtual uint match_edge(uint idx) const; virtual uint ideal_reg() const { return Op_RegI; } virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type *Value(PhaseTransform *phase) const; }; //------------------------------StrComp------------------------------------- diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/opto/node.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -641,7 +641,8 @@ Flag_is_dead_loop_safe = Flag_is_cisc_alternate << 1, Flag_may_be_short_branch = Flag_is_dead_loop_safe << 1, Flag_avoid_back_to_back = Flag_may_be_short_branch << 1, - _max_flags = (Flag_avoid_back_to_back << 1) - 1 // allow flags combination + Flag_has_call = Flag_avoid_back_to_back << 1, + _max_flags = (Flag_has_call << 1) - 1 // allow flags combination }; private: diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/runtime/globals.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -890,7 +890,7 @@ diagnostic(bool, TraceNMethodInstalls, false, \ "Trace nmethod intallation") \ \ - diagnostic(intx, ScavengeRootsInCode, 1, \ + diagnostic(intx, ScavengeRootsInCode, 2, \ "0: do not allow scavengable oops in the code cache; " \ "1: allow scavenging from the code cache; " \ "2: emit as many constants as the compiler can see") \ diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/runtime/simpleThresholdPolicy.cpp --- a/src/share/vm/runtime/simpleThresholdPolicy.cpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/runtime/simpleThresholdPolicy.cpp Thu Dec 08 10:27:33 2011 -0800 @@ -30,6 +30,27 @@ #include "runtime/simpleThresholdPolicy.inline.hpp" #include "code/scopeDesc.hpp" + +void SimpleThresholdPolicy::print_counters(const char* prefix, methodHandle mh) { + int invocation_count = mh->invocation_count(); + int backedge_count = mh->backedge_count(); + methodDataHandle mdh = mh->method_data(); + int mdo_invocations = 0, mdo_backedges = 0; + int mdo_invocations_start = 0, mdo_backedges_start = 0; + if (mdh() != NULL) { + mdo_invocations = mdh->invocation_count(); + mdo_backedges = mdh->backedge_count(); + mdo_invocations_start = mdh->invocation_count_start(); + mdo_backedges_start = mdh->backedge_count_start(); + } + tty->print(" %stotal: %d,%d %smdo: %d(%d),%d(%d)", prefix, + invocation_count, backedge_count, prefix, + mdo_invocations, mdo_invocations_start, + mdo_backedges, mdo_backedges_start); + tty->print(" %smax levels: %d,%d", prefix, + mh->highest_comp_level(), mh->highest_osr_comp_level()); +} + // Print an event. void SimpleThresholdPolicy::print_event(EventType type, methodHandle mh, methodHandle imh, int bci, CompLevel level) { @@ -38,8 +59,6 @@ ttyLocker tty_lock; tty->print("%lf: [", os::elapsedTime()); - int invocation_count = mh->invocation_count(); - int backedge_count = mh->backedge_count(); switch(type) { case CALL: tty->print("call"); @@ -82,23 +101,9 @@ print_specific(type, mh, imh, bci, level); if (type != COMPILE) { - methodDataHandle mdh = mh->method_data(); - int mdo_invocations = 0, mdo_backedges = 0; - int mdo_invocations_start = 0, mdo_backedges_start = 0; - if (mdh() != NULL) { - mdo_invocations = mdh->invocation_count(); - mdo_backedges = mdh->backedge_count(); - mdo_invocations_start = mdh->invocation_count_start(); - mdo_backedges_start = mdh->backedge_count_start(); - } - tty->print(" total: %d,%d mdo: %d(%d),%d(%d)", - invocation_count, backedge_count, - mdo_invocations, mdo_invocations_start, - mdo_backedges, mdo_backedges_start); - tty->print(" max levels: %d,%d", - mh->highest_comp_level(), mh->highest_osr_comp_level()); + print_counters("", mh); if (inlinee_event) { - tty->print(" inlinee max levels: %d,%d", imh->highest_comp_level(), imh->highest_osr_comp_level()); + print_counters("inlinee ", imh); } tty->print(" compilable: "); bool need_comma = false; diff -r 55d777c0860a -r 81f7362f7bed src/share/vm/runtime/simpleThresholdPolicy.hpp --- a/src/share/vm/runtime/simpleThresholdPolicy.hpp Wed Dec 07 07:27:09 2011 -0800 +++ b/src/share/vm/runtime/simpleThresholdPolicy.hpp Thu Dec 08 10:27:33 2011 -0800 @@ -55,7 +55,7 @@ // loop_event checks if a method should be OSR compiled at a different // level. CompLevel loop_event(methodOop method, CompLevel cur_level); - + void print_counters(const char* prefix, methodHandle mh); protected: int c1_count() const { return _c1_count; } int c2_count() const { return _c2_count; } diff -r 55d777c0860a -r 81f7362f7bed test/compiler/6792161/Test6792161.java --- a/test/compiler/6792161/Test6792161.java Wed Dec 07 07:27:09 2011 -0800 +++ b/test/compiler/6792161/Test6792161.java Thu Dec 08 10:27:33 2011 -0800 @@ -27,7 +27,7 @@ * @bug 6792161 * @summary assert("No dead instructions after post-alloc") * - * @run main/othervm -Xcomp -XX:MaxInlineSize=120 Test6792161 + * @run main/othervm/timeout=300 -Xcomp -XX:MaxInlineSize=120 Test6792161 */ import java.lang.reflect.Constructor; diff -r 55d777c0860a -r 81f7362f7bed test/compiler/7110586/Test7110586.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/7110586/Test7110586.java Thu Dec 08 10:27:33 2011 -0800 @@ -0,0 +1,132 @@ +/* + * 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 7110586 + * @summary C2 generates icorrect results + * + * @run main/othervm -Xbatch Test7110586 + */ + +public class Test7110586 { + static int test1() { + int i = 0; + for ( ; i < 11; i+=1) {} + return i; + } + static int test2() { + int i = 0; + for ( ; i < 11; i+=2) {} + return i; + } + static int test3() { + int i = 0; + for ( ; i < 11; i+=3) {} + return i; + } + static int test11() { + int i = 0; + for ( ; i < 11; i+=11) {} + return i; + } + + static int testm1() { + int i = 0; + for ( ; i > -11; i-=1) {} + return i; + } + static int testm2() { + int i = 0; + for ( ; i > -11; i-=2) {} + return i; + } + static int testm3() { + int i = 0; + for ( ; i > -11; i-=3) {} + return i; + } + static int testm11() { + int i = 0; + for ( ; i > -11; i-=11) {} + return i; + } + + public static void main(String args[]) { + int x1 = 0; + int x2 = 0; + int x3 = 0; + int x11 = 0; + int m1 = 0; + int m2 = 0; + int m3 = 0; + int m11 = 0; + for (int i=0; i<10000; i++) { + x1 = test1(); + x2 = test2(); + x3 = test3(); + x11 = test11(); + m1 = testm1(); + m2 = testm2(); + m3 = testm3(); + m11 = testm11(); + } + boolean failed = false; + if (x1 != 11) { + System.out.println("ERROR (incr = +1): " + x1 + " != 11"); + failed = true; + } + if (x2 != 12) { + System.out.println("ERROR (incr = +2): " + x2 + " != 12"); + failed = true; + } + if (x3 != 12) { + System.out.println("ERROR (incr = +3): " + x3 + " != 12"); + failed = true; + } + if (x11 != 11) { + System.out.println("ERROR (incr = +11): " + x11 + " != 11"); + failed = true; + } + if (m1 != -11) { + System.out.println("ERROR (incr = -1): " + m1 + " != -11"); + failed = true; + } + if (m2 != -12) { + System.out.println("ERROR (incr = -2): " + m2 + " != -12"); + failed = true; + } + if (m3 != -12) { + System.out.println("ERROR (incr = -3): " + m3 + " != -12"); + failed = true; + } + if (m11 != -11) { + System.out.println("ERROR (incr = -11): " + m11 + " != -11"); + failed = true; + } + if (failed) { + System.exit(97); + } + } +}