# HG changeset patch # User trims # Date 1260578317 28800 # Node ID 74e00f62c72632605b033601d9caab48142f1612 # Parent 7589c1b729075d4cb39c47b03555a890821748e5# Parent 84a2da7f454c3b393673681a19ac51829001b045 Merge diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -189,14 +189,17 @@ Register OSR_buf = osrBufferPointer()->as_register(); { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); int monitor_offset = BytesPerWord * method()->max_locals() + - (BasicObjectLock::size() * BytesPerWord) * (number_of_locks - 1); + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. for (int i = 0; i < number_of_locks; i++) { - int slot_offset = monitor_offset - ((i * BasicObjectLock::size()) * BytesPerWord); + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); #ifdef ASSERT // verify the interpreter's monitor has a non-null object { Label L; - __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes(), O7); + __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7); __ cmp(G0, O7); __ br(Assembler::notEqual, false, Assembler::pt, L); __ delayed()->nop(); @@ -205,9 +208,9 @@ } #endif // ASSERT // Copy the lock field into the compiled activation. - __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::lock_offset_in_bytes(), O7); + __ ld_ptr(OSR_buf, slot_offset + 0, O7); __ st_ptr(O7, frame_map()->address_for_monitor_lock(i)); - __ ld_ptr(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes(), O7); + __ ld_ptr(OSR_buf, slot_offset + 1*BytesPerWord, O7); __ st_ptr(O7, frame_map()->address_for_monitor_object(i)); } } @@ -953,9 +956,11 @@ } else { #ifdef _LP64 assert(base != to_reg->as_register_lo(), "can't handle this"); + assert(O7 != to_reg->as_register_lo(), "can't handle this"); __ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_lo()); + __ lduw(base, offset + lo_word_offset_in_bytes, O7); // in case O7 is base or offset, use it last __ sllx(to_reg->as_register_lo(), 32, to_reg->as_register_lo()); - __ ld(base, offset + lo_word_offset_in_bytes, to_reg->as_register_lo()); + __ or3(to_reg->as_register_lo(), O7, to_reg->as_register_lo()); #else if (base == to_reg->as_register_lo()) { __ ld(base, offset + hi_word_offset_in_bytes, to_reg->as_register_hi()); @@ -976,8 +981,8 @@ FloatRegister reg = to_reg->as_double_reg(); // split unaligned loads if (unaligned || PatchALot) { - __ ldf(FloatRegisterImpl::S, base, offset + BytesPerWord, reg->successor()); - __ ldf(FloatRegisterImpl::S, base, offset, reg); + __ ldf(FloatRegisterImpl::S, base, offset + 4, reg->successor()); + __ ldf(FloatRegisterImpl::S, base, offset, reg); } else { __ ldf(FloatRegisterImpl::D, base, offset, to_reg->as_double_reg()); } @@ -2200,6 +2205,7 @@ Register len = O2; __ add(src, arrayOopDesc::base_offset_in_bytes(basic_type), src_ptr); + LP64_ONLY(__ sra(src_pos, 0, src_pos);) //higher 32bits must be null if (shift == 0) { __ add(src_ptr, src_pos, src_ptr); } else { @@ -2208,6 +2214,7 @@ } __ add(dst, arrayOopDesc::base_offset_in_bytes(basic_type), dst_ptr); + LP64_ONLY(__ sra(dst_pos, 0, dst_pos);) //higher 32bits must be null if (shift == 0) { __ add(dst_ptr, dst_pos, dst_ptr); } else { diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp --- a/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -144,17 +144,17 @@ if (index->is_register()) { // apply the shift and accumulate the displacement if (shift > 0) { - LIR_Opr tmp = new_register(T_INT); + LIR_Opr tmp = new_pointer_register(); __ shift_left(index, shift, tmp); index = tmp; } if (disp != 0) { - LIR_Opr tmp = new_register(T_INT); + LIR_Opr tmp = new_pointer_register(); if (Assembler::is_simm13(disp)) { - __ add(tmp, LIR_OprFact::intConst(disp), tmp); + __ add(tmp, LIR_OprFact::intptrConst(disp), tmp); index = tmp; } else { - __ move(LIR_OprFact::intConst(disp), tmp); + __ move(LIR_OprFact::intptrConst(disp), tmp); __ add(tmp, index, tmp); index = tmp; } @@ -162,8 +162,8 @@ } } else if (disp != 0 && !Assembler::is_simm13(disp)) { // index is illegal so replace it with the displacement loaded into a register - index = new_register(T_INT); - __ move(LIR_OprFact::intConst(disp), index); + index = new_pointer_register(); + __ move(LIR_OprFact::intptrConst(disp), index); disp = 0; } diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/sparc/vm/c1_globals_sparc.hpp --- a/src/cpu/sparc/vm/c1_globals_sparc.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/sparc/vm/c1_globals_sparc.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,10 +22,9 @@ * */ -// // Sets the default values for platform dependent flags used by the client compiler. // (see c1_globals.hpp) -// + #ifndef TIERED define_pd_global(bool, BackgroundCompilation, true ); define_pd_global(bool, CICompileOSR, true ); @@ -48,27 +47,24 @@ define_pd_global(bool, UseTLAB, true ); define_pd_global(bool, ProfileInterpreter, false); define_pd_global(intx, FreqInlineSize, 325 ); -define_pd_global(intx, NewRatio, 8 ); // Design center runs on 1.3.1 define_pd_global(bool, ResizeTLAB, true ); define_pd_global(intx, ReservedCodeCacheSize, 32*M ); define_pd_global(intx, CodeCacheExpansionSize, 32*K ); define_pd_global(uintx,CodeCacheMinBlockLength, 1); -define_pd_global(uintx, PermSize, 12*M ); -define_pd_global(uintx, MaxPermSize, 64*M ); -define_pd_global(bool, NeverActAsServerClassMachine, true); +define_pd_global(uintx,PermSize, 12*M ); +define_pd_global(uintx,MaxPermSize, 64*M ); +define_pd_global(bool, NeverActAsServerClassMachine, true ); define_pd_global(intx, NewSizeThreadIncrease, 16*K ); -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uint64_t,MaxRAM, 1ULL*G); define_pd_global(intx, InitialCodeCacheSize, 160*K); -#endif // TIERED +#endif // !TIERED define_pd_global(bool, UseTypeProfile, false); define_pd_global(bool, RoundFPResults, false); - -define_pd_global(bool, LIRFillDelaySlots, true); +define_pd_global(bool, LIRFillDelaySlots, true ); define_pd_global(bool, OptimizeSinglePrecision, false); -define_pd_global(bool, CSEArrayLength, true); +define_pd_global(bool, CSEArrayLength, true ); define_pd_global(bool, TwoOperandLIRForm, false); - -define_pd_global(intx, SafepointPollOffset, 0); +define_pd_global(intx, SafepointPollOffset, 0 ); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/sparc/vm/c2_globals_sparc.hpp --- a/src/cpu/sparc/vm/c2_globals_sparc.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/sparc/vm/c2_globals_sparc.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -59,7 +59,6 @@ define_pd_global(intx, FreqInlineSize, 175); define_pd_global(intx, INTPRESSURE, 48); // large register set define_pd_global(intx, InteriorEntryAlignment, 16); // = CodeEntryAlignment -define_pd_global(intx, NewRatio, 2); define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); // The default setting 16/16 seems to work best. // (For _228_jack 16/16 is 2% better than 4/4, 16/4, 32/32, 32/16, or 16/32.) @@ -83,25 +82,25 @@ // sequence of instructions to load a 64 bit pointer. // // InitialCodeCacheSize derived from specjbb2000 run. -define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize -define_pd_global(intx, ReservedCodeCacheSize, 48*M); -define_pd_global(intx, CodeCacheExpansionSize, 64*K); +define_pd_global(intx, InitialCodeCacheSize, 2048*K); // Integral multiple of CodeCacheExpansionSize +define_pd_global(intx, ReservedCodeCacheSize, 48*M); +define_pd_global(intx, CodeCacheExpansionSize, 64*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 32*G); +define_pd_global(uint64_t,MaxRAM, 128ULL*G); #else // InitialCodeCacheSize derived from specjbb2000 run. -define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize -define_pd_global(intx, ReservedCodeCacheSize, 32*M); -define_pd_global(intx, CodeCacheExpansionSize, 32*K); +define_pd_global(intx, InitialCodeCacheSize, 1536*K); // Integral multiple of CodeCacheExpansionSize +define_pd_global(intx, ReservedCodeCacheSize, 32*M); +define_pd_global(intx, CodeCacheExpansionSize, 32*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uint64_t,MaxRAM, 4ULL*G); #endif -define_pd_global(uintx,CodeCacheMinBlockLength, 4); +define_pd_global(uintx,CodeCacheMinBlockLength, 4); // Heap related flags -define_pd_global(uintx, PermSize, ScaleForWordSize(16*M)); -define_pd_global(uintx, MaxPermSize, ScaleForWordSize(64*M)); +define_pd_global(uintx,PermSize, ScaleForWordSize(16*M)); +define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M)); // Ergonomics related flags define_pd_global(bool, NeverActAsServerClassMachine, false); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/sparc/vm/globals_sparc.hpp --- a/src/cpu/sparc/vm/globals_sparc.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/sparc/vm/globals_sparc.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,10 +22,8 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// // For sparc we do not do call backs when a thread is in the interpreter, because the // interpreter dispatch needs at least two instructions - first to load the dispatch address @@ -41,26 +39,23 @@ define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast -define_pd_global(intx, CodeEntryAlignment, 32); -define_pd_global(uintx, TLABSize, 0); -define_pd_global(uintx, NewSize, ScaleForWordSize((2048 * K) + (2 * (64 * K)))); -define_pd_global(intx, SurvivorRatio, 8); -define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC -define_pd_global(intx, InlineSmallCode, 1500); +define_pd_global(intx, CodeEntryAlignment, 32); +define_pd_global(intx, InlineFrequencyCount, 50); // we can use more inlining on the SPARC +define_pd_global(intx, InlineSmallCode, 1500); #ifdef _LP64 // Stack slots are 2X larger in LP64 than in the 32 bit VM. -define_pd_global(intx, ThreadStackSize, 1024); -define_pd_global(intx, VMThreadStackSize, 1024); +define_pd_global(intx, ThreadStackSize, 1024); +define_pd_global(intx, VMThreadStackSize, 1024); #else -define_pd_global(intx, ThreadStackSize, 512); -define_pd_global(intx, VMThreadStackSize, 512); +define_pd_global(intx, ThreadStackSize, 512); +define_pd_global(intx, VMThreadStackSize, 512); #endif define_pd_global(intx, StackYellowPages, 2); define_pd_global(intx, StackRedPages, 1); define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1)); -define_pd_global(intx, PreInflateSpin, 40); // Determined by running design center +define_pd_global(intx, PreInflateSpin, 40); // Determined by running design center define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/sparc/vm/templateInterpreter_sparc.cpp --- a/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -150,8 +150,7 @@ } -address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) { - assert(!unbox, "NYI");//6815692// +address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) { address compiled_entry = __ pc(); Label cont; diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/assembler_x86.cpp --- a/src/cpu/x86/vm/assembler_x86.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/assembler_x86.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -2251,6 +2251,7 @@ emit_byte(0x9D); } +#ifndef _LP64 // no 32bit push/pop on amd64 void Assembler::popl(Address dst) { // NOTE: this will adjust stack by 8byte on 64bits InstructionMark im(this); @@ -2258,6 +2259,7 @@ emit_byte(0x8F); emit_operand(rax, dst); } +#endif void Assembler::prefetch_prefix(Address src) { prefix(src); @@ -2428,6 +2430,7 @@ emit_byte(0x9C); } +#ifndef _LP64 // no 32bit push/pop on amd64 void Assembler::pushl(Address src) { // Note this will push 64bit on 64bit InstructionMark im(this); @@ -2435,6 +2438,7 @@ emit_byte(0xFF); emit_operand(rsi, src); } +#endif void Assembler::pxor(XMMRegister dst, Address src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); @@ -5591,7 +5595,12 @@ } void MacroAssembler::andpd(XMMRegister dst, AddressLiteral src) { - andpd(dst, as_Address(src)); + if (reachable(src)) { + andpd(dst, as_Address(src)); + } else { + lea(rscratch1, src); + andpd(dst, Address(rscratch1, 0)); + } } void MacroAssembler::andptr(Register dst, int32_t imm32) { @@ -6078,11 +6087,21 @@ } void MacroAssembler::comisd(XMMRegister dst, AddressLiteral src) { - comisd(dst, as_Address(src)); + if (reachable(src)) { + comisd(dst, as_Address(src)); + } else { + lea(rscratch1, src); + comisd(dst, Address(rscratch1, 0)); + } } void MacroAssembler::comiss(XMMRegister dst, AddressLiteral src) { - comiss(dst, as_Address(src)); + if (reachable(src)) { + comiss(dst, as_Address(src)); + } else { + lea(rscratch1, src); + comiss(dst, Address(rscratch1, 0)); + } } diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/assembler_x86.hpp --- a/src/cpu/x86/vm/assembler_x86.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/assembler_x86.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -1244,7 +1244,9 @@ void pcmpestri(XMMRegister xmm1, XMMRegister xmm2, int imm8); void pcmpestri(XMMRegister xmm1, Address src, int imm8); +#ifndef _LP64 // no 32bit push/pop on amd64 void popl(Address dst); +#endif #ifdef _LP64 void popq(Address dst); @@ -1285,7 +1287,9 @@ // Interleave Low Bytes void punpcklbw(XMMRegister dst, XMMRegister src); +#ifndef _LP64 // no 32bit push/pop on amd64 void pushl(Address src); +#endif void pushq(Address src); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/c1_LIRAssembler_x86.cpp --- a/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -301,22 +301,25 @@ Register OSR_buf = osrBufferPointer()->as_pointer_register(); { assert(frame::interpreter_frame_monitor_size() == BasicObjectLock::size(), "adjust code below"); int monitor_offset = BytesPerWord * method()->max_locals() + - (BasicObjectLock::size() * BytesPerWord) * (number_of_locks - 1); + (2 * BytesPerWord) * (number_of_locks - 1); + // SharedRuntime::OSR_migration_begin() packs BasicObjectLocks in + // the OSR buffer using 2 word entries: first the lock and then + // the oop. for (int i = 0; i < number_of_locks; i++) { - int slot_offset = monitor_offset - ((i * BasicObjectLock::size()) * BytesPerWord); + int slot_offset = monitor_offset - ((i * 2) * BytesPerWord); #ifdef ASSERT // verify the interpreter's monitor has a non-null object { Label L; - __ cmpptr(Address(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes()), (int32_t)NULL_WORD); + __ cmpptr(Address(OSR_buf, slot_offset + 1*BytesPerWord), (int32_t)NULL_WORD); __ jcc(Assembler::notZero, L); __ stop("locked object is NULL"); __ bind(L); } #endif - __ movptr(rbx, Address(OSR_buf, slot_offset + BasicObjectLock::lock_offset_in_bytes())); + __ movptr(rbx, Address(OSR_buf, slot_offset + 0)); __ movptr(frame_map()->address_for_monitor_lock(i), rbx); - __ movptr(rbx, Address(OSR_buf, slot_offset + BasicObjectLock::obj_offset_in_bytes())); + __ movptr(rbx, Address(OSR_buf, slot_offset + 1*BytesPerWord)); __ movptr(frame_map()->address_for_monitor_object(i), rbx); } } @@ -785,7 +788,13 @@ ShouldNotReachHere(); __ movoop(as_Address(addr, noreg), c->as_jobject()); } else { +#ifdef _LP64 + __ movoop(rscratch1, c->as_jobject()); + null_check_here = code_offset(); + __ movptr(as_Address_lo(addr), rscratch1); +#else __ movoop(as_Address(addr), c->as_jobject()); +#endif } } break; @@ -1118,8 +1127,14 @@ __ pushptr(frame_map()->address_for_slot(src ->single_stack_ix())); __ popptr (frame_map()->address_for_slot(dest->single_stack_ix())); } else { +#ifndef _LP64 __ pushl(frame_map()->address_for_slot(src ->single_stack_ix())); __ popl (frame_map()->address_for_slot(dest->single_stack_ix())); +#else + //no pushl on 64bits + __ movl(rscratch1, frame_map()->address_for_slot(src ->single_stack_ix())); + __ movl(frame_map()->address_for_slot(dest->single_stack_ix()), rscratch1); +#endif } } else if (src->is_double_stack()) { @@ -3136,8 +3151,10 @@ #ifdef _LP64 assert_different_registers(c_rarg0, dst, dst_pos, length); + __ movl2ptr(src_pos, src_pos); //higher 32bits must be null __ lea(c_rarg0, Address(src, src_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); assert_different_registers(c_rarg1, length); + __ movl2ptr(dst_pos, dst_pos); //higher 32bits must be null __ lea(c_rarg1, Address(dst, dst_pos, scale, arrayOopDesc::base_offset_in_bytes(basic_type))); __ mov(c_rarg2, length); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/c1_LIRGenerator_x86.cpp --- a/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -755,8 +755,19 @@ } LIR_Opr addr = new_pointer_register(); - __ move(obj.result(), addr); - __ add(addr, offset.result(), addr); + LIR_Address* a; + if(offset.result()->is_constant()) { + a = new LIR_Address(obj.result(), + NOT_LP64(offset.result()->as_constant_ptr()->as_jint()) LP64_ONLY((int)offset.result()->as_constant_ptr()->as_jlong()), + as_BasicType(type)); + } else { + a = new LIR_Address(obj.result(), + offset.result(), + LIR_Address::times_1, + 0, + as_BasicType(type)); + } + __ leal(LIR_OprFact::address(a), addr); if (type == objectType) { // Write-barrier needed for Object fields. // Do the pre-write barrier, if any. diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/c1_globals_x86.hpp --- a/src/cpu/x86/vm/c1_globals_x86.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/c1_globals_x86.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,10 +22,8 @@ * */ -// // Sets the default values for platform dependent flags used by the client compiler. // (see c1_globals.hpp) -// #ifndef TIERED define_pd_global(bool, BackgroundCompilation, true ); @@ -48,27 +46,24 @@ define_pd_global(intx, OnStackReplacePercentage, 933 ); define_pd_global(intx, FreqInlineSize, 325 ); -define_pd_global(intx, NewRatio, 12 ); define_pd_global(intx, NewSizeThreadIncrease, 4*K ); define_pd_global(intx, InitialCodeCacheSize, 160*K); define_pd_global(intx, ReservedCodeCacheSize, 32*M ); define_pd_global(bool, ProfileInterpreter, false); define_pd_global(intx, CodeCacheExpansionSize, 32*K ); define_pd_global(uintx,CodeCacheMinBlockLength, 1); -define_pd_global(uintx, PermSize, 12*M ); -define_pd_global(uintx, MaxPermSize, 64*M ); -define_pd_global(bool, NeverActAsServerClassMachine, true); -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uintx,PermSize, 12*M ); +define_pd_global(uintx,MaxPermSize, 64*M ); +define_pd_global(bool, NeverActAsServerClassMachine, true ); +define_pd_global(uint64_t,MaxRAM, 1ULL*G); define_pd_global(bool, CICompileOSR, true ); -#endif // TIERED +#endif // !TIERED define_pd_global(bool, UseTypeProfile, false); define_pd_global(bool, RoundFPResults, true ); - define_pd_global(bool, LIRFillDelaySlots, false); -define_pd_global(bool, OptimizeSinglePrecision, true); +define_pd_global(bool, OptimizeSinglePrecision, true ); define_pd_global(bool, CSEArrayLength, false); -define_pd_global(bool, TwoOperandLIRForm, true); +define_pd_global(bool, TwoOperandLIRForm, true ); - -define_pd_global(intx, SafepointPollOffset, 256); +define_pd_global(intx, SafepointPollOffset, 256 ); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/c2_globals_x86.hpp --- a/src/cpu/x86/vm/c2_globals_x86.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/c2_globals_x86.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,7 +22,6 @@ * */ -// // Sets the default values for platform dependent flags used by the server compiler. // (see c2_globals.hpp). Alpha-sorted. @@ -46,8 +45,8 @@ define_pd_global(intx, CompileThreshold, 10000); #endif // TIERED define_pd_global(intx, Tier2CompileThreshold, 10000); -define_pd_global(intx, Tier3CompileThreshold, 20000 ); -define_pd_global(intx, Tier4CompileThreshold, 40000 ); +define_pd_global(intx, Tier3CompileThreshold, 20000); +define_pd_global(intx, Tier4CompileThreshold, 40000); define_pd_global(intx, BackEdgeThreshold, 100000); define_pd_global(intx, Tier2BackEdgeThreshold, 100000); @@ -61,7 +60,6 @@ #ifdef AMD64 define_pd_global(intx, INTPRESSURE, 13); define_pd_global(intx, InteriorEntryAlignment, 16); -define_pd_global(intx, NewRatio, 2); define_pd_global(intx, NewSizeThreadIncrease, ScaleForWordSize(4*K)); define_pd_global(intx, LoopUnrollLimit, 60); // InitialCodeCacheSize derived from specjbb2000 run. @@ -69,19 +67,18 @@ define_pd_global(intx, CodeCacheExpansionSize, 64*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 32*G); +define_pd_global(uint64_t,MaxRAM, 128ULL*G); #else define_pd_global(intx, INTPRESSURE, 6); define_pd_global(intx, InteriorEntryAlignment, 4); -define_pd_global(intx, NewRatio, 8); // Design center runs on 1.3.1 define_pd_global(intx, NewSizeThreadIncrease, 4*K); -define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1 +define_pd_global(intx, LoopUnrollLimit, 50); // Design center runs on 1.3.1 // InitialCodeCacheSize derived from specjbb2000 run. define_pd_global(intx, InitialCodeCacheSize, 2304*K); // Integral multiple of CodeCacheExpansionSize define_pd_global(intx, CodeCacheExpansionSize, 32*K); // Ergonomics related flags -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uint64_t,MaxRAM, 4ULL*G); #endif // AMD64 define_pd_global(intx, OptoLoopAlignment, 16); define_pd_global(intx, RegisterCostAreaRatio, 16000); @@ -97,8 +94,8 @@ define_pd_global(uintx,CodeCacheMinBlockLength, 4); // Heap related flags -define_pd_global(uintx, PermSize, ScaleForWordSize(16*M)); -define_pd_global(uintx, MaxPermSize, ScaleForWordSize(64*M)); +define_pd_global(uintx,PermSize, ScaleForWordSize(16*M)); +define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M)); // Ergonomics related flags define_pd_global(bool, NeverActAsServerClassMachine, false); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/globals_x86.hpp --- a/src/cpu/x86/vm/globals_x86.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/globals_x86.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,17 +22,16 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// -define_pd_global(bool, ConvertSleepToYield, true); -define_pd_global(bool, ShareVtableStubs, true); -define_pd_global(bool, CountInterpCalls, true); +define_pd_global(bool, ConvertSleepToYield, true); +define_pd_global(bool, ShareVtableStubs, true); +define_pd_global(bool, CountInterpCalls, true); +define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this -define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks -define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast +define_pd_global(bool, ImplicitNullChecks, true); // Generate code for implicit null checks +define_pd_global(bool, UncommonNullCast, true); // Uncommon-trap NULLs past to check cast // See 4827828 for this change. There is no globals_core_i486.hpp. I can't // assign a different value for C2 without touching a number of files. Use @@ -42,29 +41,24 @@ // the uep and the vep doesn't get real alignment but just slops on by // only assured that the entry instruction meets the 5 byte size requirement. #ifdef COMPILER2 -define_pd_global(intx, CodeEntryAlignment, 32); +define_pd_global(intx, CodeEntryAlignment, 32); #else -define_pd_global(intx, CodeEntryAlignment, 16); +define_pd_global(intx, CodeEntryAlignment, 16); #endif // COMPILER2 +define_pd_global(intx, InlineFrequencyCount, 100); +define_pd_global(intx, InlineSmallCode, 1000); -define_pd_global(bool, NeedsDeoptSuspend, false); // only register window machines need this - -define_pd_global(uintx, TLABSize, 0); +define_pd_global(intx, StackYellowPages, 2); +define_pd_global(intx, StackRedPages, 1); #ifdef AMD64 -define_pd_global(uintx, NewSize, ScaleForWordSize(2048 * K)); // Very large C++ stack frames using solaris-amd64 optimized builds // due to lack of optimization caused by C++ compiler bugs define_pd_global(intx, StackShadowPages, SOLARIS_ONLY(20) NOT_SOLARIS(6) DEBUG_ONLY(+2)); #else -define_pd_global(uintx, NewSize, 1024 * K); define_pd_global(intx, StackShadowPages, 3 DEBUG_ONLY(+1)); #endif // AMD64 -define_pd_global(intx, InlineFrequencyCount, 100); -define_pd_global(intx, InlineSmallCode, 1000); -define_pd_global(intx, PreInflateSpin, 10); -define_pd_global(intx, StackYellowPages, 2); -define_pd_global(intx, StackRedPages, 1); +define_pd_global(intx, PreInflateSpin, 10); define_pd_global(bool, RewriteBytecodes, true); define_pd_global(bool, RewriteFrequentPairs, true); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/templateInterpreter_x86_32.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -155,15 +155,8 @@ } -address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step, bool unbox) { +address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, int step) { TosState incoming_state = state; - if (EnableInvokeDynamic) { - if (unbox) { - incoming_state = atos; - } - } else { - assert(!unbox, "old behavior"); - } Label interpreter_entry; address compiled_entry = __ pc(); @@ -216,46 +209,6 @@ __ restore_bcp(); __ restore_locals(); - Label L_fail; - - if (unbox && state != atos) { - // cast and unbox - BasicType type = as_BasicType(state); - if (type == T_BYTE) type = T_BOOLEAN; // FIXME - KlassHandle boxk = SystemDictionaryHandles::box_klass(type); - __ mov32(rbx, ExternalAddress((address) boxk.raw_value())); - __ testl(rax, rax); - Label L_got_value, L_get_value; - // convert nulls to zeroes (avoid NPEs here) - if (!(type == T_FLOAT || type == T_DOUBLE)) { - // if rax already contains zero bits, forge ahead - __ jcc(Assembler::zero, L_got_value); - } else { - __ jcc(Assembler::notZero, L_get_value); - __ fldz(); - __ jmp(L_got_value); - } - __ bind(L_get_value); - __ cmp32(rbx, Address(rax, oopDesc::klass_offset_in_bytes())); - __ jcc(Assembler::notEqual, L_fail); - int offset = java_lang_boxing_object::value_offset_in_bytes(type); - // Cf. TemplateTable::getfield_or_static - switch (type) { - case T_BYTE: // fall through: - case T_BOOLEAN: __ load_signed_byte(rax, Address(rax, offset)); break; - case T_CHAR: __ load_unsigned_short(rax, Address(rax, offset)); break; - case T_SHORT: __ load_signed_short(rax, Address(rax, offset)); break; - case T_INT: __ movl(rax, Address(rax, offset)); break; - case T_FLOAT: __ fld_s(Address(rax, offset)); break; - case T_DOUBLE: __ fld_d(Address(rax, offset)); break; - // Access to java.lang.Double.value does not need to be atomic: - case T_LONG: { __ movl(rdx, Address(rax, offset + 4)); - __ movl(rax, Address(rax, offset + 0)); } break; - default: ShouldNotReachHere(); - } - __ bind(L_got_value); - } - Label L_got_cache, L_giant_index; if (EnableInvokeDynamic) { __ cmpb(Address(rsi, 0), Bytecodes::_invokedynamic); @@ -263,32 +216,6 @@ } __ get_cache_and_index_at_bcp(rbx, rcx, 1, false); __ bind(L_got_cache); - if (unbox && state == atos) { - // insert a casting conversion, to keep verifier sane - Label L_ok, L_ok_pops; - __ testl(rax, rax); - __ jcc(Assembler::zero, L_ok); - __ push(rax); // save the object to check - __ push(rbx); // save CP cache reference - __ movl(rdx, Address(rax, oopDesc::klass_offset_in_bytes())); - __ movl(rbx, Address(rbx, rcx, - Address::times_4, constantPoolCacheOopDesc::base_offset() + - ConstantPoolCacheEntry::f1_offset())); - __ movl(rbx, Address(rbx, __ delayed_value(sun_dyn_CallSiteImpl::type_offset_in_bytes, rcx))); - __ movl(rbx, Address(rbx, __ delayed_value(java_dyn_MethodType::rtype_offset_in_bytes, rcx))); - __ movl(rax, Address(rbx, __ delayed_value(java_lang_Class::klass_offset_in_bytes, rcx))); - __ check_klass_subtype(rdx, rax, rbx, L_ok_pops); - __ pop(rcx); // pop and discard CP cache - __ mov(rbx, rax); // target supertype into rbx for L_fail - __ pop(rax); // failed object into rax for L_fail - __ jmp(L_fail); - - __ bind(L_ok_pops); - // restore pushed temp regs: - __ pop(rbx); - __ pop(rax); - __ bind(L_ok); - } __ movl(rbx, Address(rbx, rcx, Address::times_ptr, constantPoolCacheOopDesc::base_offset() + ConstantPoolCacheEntry::flags_offset())); @@ -301,14 +228,6 @@ __ bind(L_giant_index); __ get_cache_and_index_at_bcp(rbx, rcx, 1, true); __ jmp(L_got_cache); - - if (unbox) { - __ bind(L_fail); - __ push(rbx); // missed klass (required) - __ push(rax); // bad object (actual) - __ movptr(rdx, ExternalAddress((address) &Interpreter::_throw_WrongMethodType_entry)); - __ call(rdx); - } } return entry; diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/templateInterpreter_x86_64.cpp --- a/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -166,8 +166,7 @@ address TemplateInterpreterGenerator::generate_return_entry_for(TosState state, - int step, bool unbox) { - assert(!unbox, "NYI");//6815692// + int step) { // amd64 doesn't need to do anything special about compiled returns // to the interpreter so the code that exists on x86 to place a sentinel diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/templateTable_x86_32.cpp --- a/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/templateTable_x86_32.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -2890,9 +2890,6 @@ void TemplateTable::prepare_invoke(Register method, Register index, int byte_no) { - bool is_invdyn_bootstrap = (byte_no < 0); - if (is_invdyn_bootstrap) byte_no = -byte_no; - // determine flags Bytecodes::Code code = bytecode(); const bool is_invokeinterface = code == Bytecodes::_invokeinterface; @@ -2907,8 +2904,6 @@ const Register flags = rdx; assert_different_registers(method, index, recv, flags); - assert(!is_invdyn_bootstrap || is_invokedynamic, "byte_no<0 hack only for invdyn"); - // save 'interpreter return address' __ save_bcp(); @@ -2944,9 +2939,7 @@ // load return address { address table_addr; - if (is_invdyn_bootstrap) - table_addr = (address)Interpreter::return_5_unbox_addrs_by_index_table(); - else if (is_invokeinterface || is_invokedynamic) + if (is_invokeinterface || is_invokedynamic) table_addr = (address)Interpreter::return_5_addrs_by_index_table(); else table_addr = (address)Interpreter::return_3_addrs_by_index_table(); @@ -3154,53 +3147,10 @@ } Label handle_unlinked_site; - __ movptr(rcx, Address(rax, __ delayed_value(sun_dyn_CallSiteImpl::target_offset_in_bytes, rcx))); - __ testptr(rcx, rcx); - __ jcc(Assembler::zero, handle_unlinked_site); - + __ movptr(rcx, Address(rax, __ delayed_value(java_dyn_CallSite::target_offset_in_bytes, rcx))); + __ null_check(rcx); __ prepare_to_jump_from_interpreted(); __ jump_to_method_handle_entry(rcx, rdx); - - // Initial calls come here... - __ bind(handle_unlinked_site); - __ pop(rcx); // remove return address pushed by prepare_invoke - - // box stacked arguments into an array for the bootstrap method - address entry = CAST_FROM_FN_PTR(address, InterpreterRuntime::bootstrap_invokedynamic); - __ restore_bcp(); // rsi must be correct for call_VM - __ call_VM(rax, entry, rax); - __ movl(rdi, rax); // protect bootstrap MH from prepare_invoke - - // recompute return address - __ restore_bcp(); // rsi must be correct for prepare_invoke - prepare_invoke(rax, rbx, -byte_no); // smashes rcx, rdx - // rax: CallSite object (f1) - // rbx: unused (f2) - // rdi: bootstrap MH - // rdx: flags - - // now load up the arglist, which has been neatly boxed - __ get_thread(rcx); - __ movptr(rdx, Address(rcx, JavaThread::vm_result_2_offset())); - __ movptr(Address(rcx, JavaThread::vm_result_2_offset()), NULL_WORD); - __ verify_oop(rdx); - // rdx = arglist - - // save SP now, before we add the bootstrap call to the stack - // We must preserve a fiction that the original arguments are outgoing, - // because the return sequence will reset the stack to this point - // and then pop all those arguments. It seems error-prone to use - // a different argument list size just for bootstrapping. - __ prepare_to_jump_from_interpreted(); - - // Now let's play adapter, pushing the real arguments on the stack. - __ pop(rbx); // return PC - __ push(rdi); // boot MH - __ push(rax); // call site - __ push(rdx); // arglist - __ push(rbx); // return PC, again - __ mov(rcx, rdi); - __ jump_to_method_handle_entry(rcx, rdx); } //---------------------------------------------------------------------------------------------------- diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/x86/vm/vm_version_x86.cpp --- a/src/cpu/x86/vm/vm_version_x86.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/x86/vm/vm_version_x86.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -255,6 +255,8 @@ if (!VM_Version::supports_sse2()) { vm_exit_during_initialization("Unknown x64 processor: SSE2 not supported"); } + // in 64 bit the use of SSE2 is the minimum + if (UseSSE < 2) UseSSE = 2; #endif // If the OS doesn't support SSE, we can't use this feature even if the HW does diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/zero/vm/cppInterpreter_zero.cpp --- a/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/zero/vm/cppInterpreter_zero.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -204,6 +204,20 @@ goto unwind_and_return; } + // Update the invocation counter + if ((UseCompiler || CountCompiledCalls) && !method->is_synchronized()) { + thread->set_do_not_unlock(); + InvocationCounter *counter = method->invocation_counter(); + counter->increment(); + if (counter->reached_InvocationLimit()) { + CALL_VM_NOCHECK( + InterpreterRuntime::frequency_counter_overflow(thread, NULL)); + if (HAS_PENDING_EXCEPTION) + goto unwind_and_return; + } + thread->clr_do_not_unlock(); + } + // Lock if necessary BasicObjectLock *monitor; monitor = NULL; diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/zero/vm/frame_zero.cpp --- a/src/cpu/zero/vm/frame_zero.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/zero/vm/frame_zero.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -36,11 +36,8 @@ return zeroframe()->is_interpreter_frame(); } -bool frame::is_fake_stub_frame() const { - return zeroframe()->is_fake_stub_frame(); -} - frame frame::sender_for_entry_frame(RegisterMap *map) const { + assert(zeroframe()->is_entry_frame(), "wrong type of frame"); assert(map != NULL, "map must be set"); assert(!entry_frame_is_first(), "next Java fp must be non zero"); assert(entry_frame_call_wrapper()->anchor()->last_Java_sp() == sender_sp(), @@ -50,15 +47,10 @@ return frame(sender_sp(), sp() + 1); } -frame frame::sender_for_interpreter_frame(RegisterMap *map) const { - return frame(sender_sp(), sp() + 1); -} - -frame frame::sender_for_compiled_frame(RegisterMap *map) const { - return frame(sender_sp(), sp() + 1); -} - -frame frame::sender_for_fake_stub_frame(RegisterMap *map) const { +frame frame::sender_for_nonentry_frame(RegisterMap *map) const { + assert(zeroframe()->is_interpreter_frame() || + zeroframe()->is_shark_frame() || + zeroframe()->is_fake_stub_frame(), "wrong type of frame"); return frame(sender_sp(), sp() + 1); } @@ -69,17 +61,8 @@ if (is_entry_frame()) return sender_for_entry_frame(map); - - if (is_interpreted_frame()) - return sender_for_interpreter_frame(map); - - if (is_compiled_frame()) - return sender_for_compiled_frame(map); - - if (is_fake_stub_frame()) - return sender_for_fake_stub_frame(map); - - ShouldNotReachHere(); + else + return sender_for_nonentry_frame(map); } #ifdef CC_INTERP diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/zero/vm/frame_zero.hpp --- a/src/cpu/zero/vm/frame_zero.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/zero/vm/frame_zero.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -65,10 +65,7 @@ } public: - bool is_fake_stub_frame() const; - - public: - frame sender_for_fake_stub_frame(RegisterMap* map) const; + frame sender_for_nonentry_frame(RegisterMap* map) const; public: void zero_print_on_error(int index, diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/zero/vm/globals_zero.hpp --- a/src/cpu/zero/vm/globals_zero.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/zero/vm/globals_zero.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -23,10 +23,8 @@ * */ -// // Set the default values for platform dependent flags used by the // runtime system. See globals.hpp for details of what they do. -// define_pd_global(bool, ConvertSleepToYield, true); define_pd_global(bool, ShareVtableStubs, true); @@ -37,14 +35,7 @@ define_pd_global(bool, UncommonNullCast, true); define_pd_global(intx, CodeEntryAlignment, 32); -define_pd_global(uintx, TLABSize, 0); -#ifdef _LP64 -define_pd_global(uintx, NewSize, ScaleForWordSize(2048 * K)); -#else -define_pd_global(uintx, NewSize, ScaleForWordSize(1024 * K)); -#endif // _LP64 define_pd_global(intx, InlineFrequencyCount, 100); -define_pd_global(intx, InlineSmallCode, 1000); define_pd_global(intx, PreInflateSpin, 10); define_pd_global(intx, StackYellowPages, 2); diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/zero/vm/sharedRuntime_zero.cpp --- a/src/cpu/zero/vm/sharedRuntime_zero.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/zero/vm/sharedRuntime_zero.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1,6 +1,6 @@ /* * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2007, 2008 Red Hat, Inc. + * Copyright 2007, 2008, 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -61,7 +61,14 @@ BasicType *in_sig_bt, VMRegPair *in_regs, BasicType ret_type) { +#ifdef SHARK + return SharkCompiler::compiler()->generate_native_wrapper(masm, + method, + in_sig_bt, + ret_type); +#else ShouldNotCallThis(); +#endif // SHARK } int Deoptimization::last_frame_adjust(int callee_parameters, diff -r 7589c1b72907 -r 74e00f62c726 src/cpu/zero/vm/sharkFrame_zero.hpp --- a/src/cpu/zero/vm/sharkFrame_zero.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/cpu/zero/vm/sharkFrame_zero.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -1,6 +1,6 @@ /* * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved. - * Copyright 2008 Red Hat, Inc. + * Copyright 2008, 2009 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,7 +41,7 @@ // | ... | class SharkFrame : public ZeroFrame { - friend class SharkFunction; + friend class SharkStack; private: SharkFrame() : ZeroFrame() { diff -r 7589c1b72907 -r 74e00f62c726 src/os_cpu/linux_x86/vm/globals_linux_x86.hpp --- a/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,10 +22,9 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// + define_pd_global(bool, DontYieldALot, false); #ifdef AMD64 define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default @@ -39,11 +38,10 @@ #endif // AMD64 define_pd_global(intx, CompilerThreadStackSize, 0); -define_pd_global(intx, SurvivorRatio, 8); -define_pd_global(uintx, JVMInvokeMethodSlack, 8192); +define_pd_global(uintx,JVMInvokeMethodSlack, 8192); // Only used on 64 bit platforms -define_pd_global(uintx, HeapBaseMinAddress, 2*G); +define_pd_global(uintx,HeapBaseMinAddress, 2*G); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff -r 7589c1b72907 -r 74e00f62c726 src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp --- a/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,31 +22,25 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// + define_pd_global(bool, DontYieldALot, true); // Determined in the design center #ifdef AMD64 define_pd_global(intx, ThreadStackSize, 1024); // 0 => use system default define_pd_global(intx, VMThreadStackSize, 1024); -define_pd_global(intx, SurvivorRatio, 6); -define_pd_global(uintx, JVMInvokeMethodSlack, 8*K); +define_pd_global(uintx,JVMInvokeMethodSlack, 8*K); #else -// UseStackBanging is not pd -// define_pd_global(bool, UseStackBanging, true); - // ThreadStackSize 320 allows TaggedStackInterpreter and a couple of test cases // to run while keeping the number of threads that can be created high. define_pd_global(intx, ThreadStackSize, 320); define_pd_global(intx, VMThreadStackSize, 512); -define_pd_global(intx, SurvivorRatio, 8); -define_pd_global(uintx, JVMInvokeMethodSlack, 10*K); +define_pd_global(uintx,JVMInvokeMethodSlack, 10*K); #endif // AMD64 define_pd_global(intx, CompilerThreadStackSize, 0); // Only used on 64 bit platforms -define_pd_global(uintx, HeapBaseMinAddress, 256*M); +define_pd_global(uintx,HeapBaseMinAddress, 256*M); // Only used on 64 bit Windows platforms define_pd_global(bool, UseVectoredExceptions, false); diff -r 7589c1b72907 -r 74e00f62c726 src/os_cpu/windows_x86/vm/globals_windows_x86.hpp --- a/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -22,10 +22,9 @@ * */ -// // Sets the default values for platform dependent flags used by the runtime system. // (see globals.hpp) -// + define_pd_global(bool, DontYieldALot, false); // Default stack size on Windows is determined by the executable (java.exe @@ -35,8 +34,6 @@ define_pd_global(intx, ThreadStackSize, 0); // 0 => use system default define_pd_global(intx, VMThreadStackSize, 0); // 0 => use system default -define_pd_global(intx, SurvivorRatio, 8); - #ifdef ASSERT define_pd_global(intx, CompilerThreadStackSize, 1024); #else diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/c1/c1_GraphBuilder.cpp --- a/src/share/vm/c1/c1_GraphBuilder.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/c1/c1_GraphBuilder.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -365,7 +365,7 @@ if (_next_loop_index < 31) _next_loop_index++; } else { // block already marked as loop header - assert(is_power_of_2(_loop_map.at(block->block_id())), "exactly one bit must be set"); + assert(is_power_of_2((unsigned int)_loop_map.at(block->block_id())), "exactly one bit must be set"); } } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/c1/c1_LIRGenerator.cpp --- a/src/share/vm/c1/c1_LIRGenerator.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/c1/c1_LIRGenerator.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1855,12 +1855,26 @@ addr = new LIR_Address(base_op, index_op->as_jint(), dst_type); } else { #ifdef X86 +#ifdef _LP64 + if (!index_op->is_illegal() && index_op->type() == T_INT) { + LIR_Opr tmp = new_pointer_register(); + __ convert(Bytecodes::_i2l, index_op, tmp); + index_op = tmp; + } +#endif addr = new LIR_Address(base_op, index_op, LIR_Address::Scale(log2_scale), 0, dst_type); #else if (index_op->is_illegal() || log2_scale == 0) { +#ifdef _LP64 + if (!index_op->is_illegal() && index_op->type() == T_INT) { + LIR_Opr tmp = new_pointer_register(); + __ convert(Bytecodes::_i2l, index_op, tmp); + index_op = tmp; + } +#endif addr = new LIR_Address(base_op, index_op, dst_type); } else { - LIR_Opr tmp = new_register(T_INT); + LIR_Opr tmp = new_pointer_register(); __ shift_left(index_op, log2_scale, tmp); addr = new LIR_Address(base_op, tmp, dst_type); } @@ -1915,10 +1929,25 @@ LIR_Opr index_op = idx.result(); if (log2_scale != 0) { // temporary fix (platform dependent code without shift on Intel would be better) - index_op = new_register(T_INT); - __ move(idx.result(), index_op); + index_op = new_pointer_register(); +#ifdef _LP64 + if(idx.result()->type() == T_INT) { + __ convert(Bytecodes::_i2l, idx.result(), index_op); + } else { +#endif + __ move(idx.result(), index_op); +#ifdef _LP64 + } +#endif __ shift_left(index_op, log2_scale, index_op); } +#ifdef _LP64 + else if(!index_op->is_illegal() && index_op->type() == T_INT) { + LIR_Opr tmp = new_pointer_register(); + __ convert(Bytecodes::_i2l, index_op, tmp); + index_op = tmp; + } +#endif LIR_Address* addr = new LIR_Address(base_op, index_op, x->basic_type()); __ move(value.result(), addr); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/c1/c1_LinearScan.cpp --- a/src/share/vm/c1/c1_LinearScan.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/c1/c1_LinearScan.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -2464,6 +2464,10 @@ case T_LONG: // fall through case T_DOUBLE: { +#ifdef _LP64 + scope_values->append(&_int_0_scope_value); + scope_values->append(new ConstantLongValue(c->as_jlong_bits())); +#else if (hi_word_offset_in_bytes > lo_word_offset_in_bytes) { scope_values->append(new ConstantIntValue(c->as_jint_hi_bits())); scope_values->append(new ConstantIntValue(c->as_jint_lo_bits())); @@ -2471,7 +2475,7 @@ scope_values->append(new ConstantIntValue(c->as_jint_lo_bits())); scope_values->append(new ConstantIntValue(c->as_jint_hi_bits())); } - +#endif return 2; } @@ -2503,17 +2507,18 @@ } else if (opr->is_single_cpu()) { bool is_oop = opr->is_oop_register(); int cache_idx = opr->cpu_regnr() * 2 + (is_oop ? 1 : 0); + Location::Type int_loc_type = NOT_LP64(Location::normal) LP64_ONLY(Location::int_in_long); ScopeValue* sv = _scope_value_cache.at(cache_idx); if (sv == NULL) { - Location::Type loc_type = is_oop ? Location::oop : Location::normal; + Location::Type loc_type = is_oop ? Location::oop : int_loc_type; VMReg rname = frame_map()->regname(opr); sv = new LocationValue(Location::new_reg_loc(loc_type, rname)); _scope_value_cache.at_put(cache_idx, sv); } // check if cached value is correct - DEBUG_ONLY(assert_equal(sv, new LocationValue(Location::new_reg_loc(is_oop ? Location::oop : Location::normal, frame_map()->regname(opr))))); + DEBUG_ONLY(assert_equal(sv, new LocationValue(Location::new_reg_loc(is_oop ? Location::oop : int_loc_type, frame_map()->regname(opr))))); scope_values->append(sv); return 1; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/ci/ciEnv.cpp --- a/src/share/vm/ci/ciEnv.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/ci/ciEnv.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -46,6 +46,9 @@ ciInstanceKlass* ciEnv::_Thread; ciInstanceKlass* ciEnv::_OutOfMemoryError; ciInstanceKlass* ciEnv::_String; +ciInstanceKlass* ciEnv::_StringBuffer; +ciInstanceKlass* ciEnv::_StringBuilder; +ciInstanceKlass* ciEnv::_Integer; ciSymbol* ciEnv::_unloaded_cisymbol = NULL; ciInstanceKlass* ciEnv::_unloaded_ciinstance_klass = NULL; @@ -110,6 +113,8 @@ _ArrayIndexOutOfBoundsException_instance = NULL; _ArrayStoreException_instance = NULL; _ClassCastException_instance = NULL; + _the_null_string = NULL; + _the_min_jint_string = NULL; } ciEnv::ciEnv(Arena* arena) { @@ -163,6 +168,8 @@ _ArrayIndexOutOfBoundsException_instance = NULL; _ArrayStoreException_instance = NULL; _ClassCastException_instance = NULL; + _the_null_string = NULL; + _the_min_jint_string = NULL; } ciEnv::~ciEnv() { @@ -248,6 +255,22 @@ return _ClassCastException_instance; } +ciInstance* ciEnv::the_null_string() { + if (_the_null_string == NULL) { + VM_ENTRY_MARK; + _the_null_string = get_object(Universe::the_null_string())->as_instance(); + } + return _the_null_string; +} + +ciInstance* ciEnv::the_min_jint_string() { + if (_the_min_jint_string == NULL) { + VM_ENTRY_MARK; + _the_min_jint_string = get_object(Universe::the_min_jint_string())->as_instance(); + } + return _the_min_jint_string; +} + // ------------------------------------------------------------------ // ciEnv::get_method_from_handle ciMethod* ciEnv::get_method_from_handle(jobject method) { @@ -690,10 +713,8 @@ ciInstanceKlass* declared_holder = get_instance_klass_for_declared_method_holder(holder); // Get the method's name and signature. - int nt_index = cpool->name_and_type_ref_index_at(index); - int sig_index = cpool->signature_ref_index_at(nt_index); symbolOop name_sym = cpool->name_ref_at(index); - symbolOop sig_sym = cpool->symbol_at(sig_index); + symbolOop sig_sym = cpool->signature_ref_at(index); if (holder_is_accessible) { // Our declared holder is loaded. instanceKlass* lookup = declared_holder->get_instanceKlass(); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/ci/ciEnv.hpp --- a/src/share/vm/ci/ciEnv.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/ci/ciEnv.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -82,6 +82,9 @@ static ciInstanceKlass* _Thread; static ciInstanceKlass* _OutOfMemoryError; static ciInstanceKlass* _String; + static ciInstanceKlass* _StringBuffer; + static ciInstanceKlass* _StringBuilder; + static ciInstanceKlass* _Integer; static ciSymbol* _unloaded_cisymbol; static ciInstanceKlass* _unloaded_ciinstance_klass; @@ -97,6 +100,9 @@ ciInstance* _ArrayStoreException_instance; ciInstance* _ClassCastException_instance; + ciInstance* _the_null_string; // The Java string "null" + ciInstance* _the_min_jint_string; // The Java string "-2147483648" + // Look up a klass by name from a particular class loader (the accessor's). // If require_local, result must be defined in that class loader, or NULL. // If !require_local, a result from remote class loader may be reported, @@ -310,6 +316,15 @@ ciInstanceKlass* String_klass() { return _String; } + ciInstanceKlass* StringBuilder_klass() { + return _StringBuilder; + } + ciInstanceKlass* StringBuffer_klass() { + return _StringBuffer; + } + ciInstanceKlass* Integer_klass() { + return _Integer; + } ciInstance* NullPointerException_instance() { assert(_NullPointerException_instance != NULL, "initialization problem"); return _NullPointerException_instance; @@ -324,6 +339,9 @@ ciInstance* ArrayStoreException_instance(); ciInstance* ClassCastException_instance(); + ciInstance* the_null_string(); + ciInstance* the_min_jint_string(); + static ciSymbol* unloaded_cisymbol() { return _unloaded_cisymbol; } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/ci/ciInstanceKlass.cpp --- a/src/share/vm/ci/ciInstanceKlass.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/ci/ciInstanceKlass.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -341,6 +341,20 @@ } // ------------------------------------------------------------------ +// ciInstanceKlass::get_field_by_name +ciField* ciInstanceKlass::get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static) { + VM_ENTRY_MARK; + instanceKlass* k = get_instanceKlass(); + fieldDescriptor fd; + klassOop def = k->find_field(name->get_symbolOop(), signature->get_symbolOop(), is_static, &fd); + if (def == NULL) { + return NULL; + } + ciField* field = new (CURRENT_THREAD_ENV->arena()) ciField(&fd); + return field; +} + +// ------------------------------------------------------------------ // ciInstanceKlass::non_static_fields. class NonStaticFieldFiller: public FieldClosure { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/ci/ciInstanceKlass.hpp --- a/src/share/vm/ci/ciInstanceKlass.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/ci/ciInstanceKlass.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -148,6 +148,7 @@ ciInstanceKlass* get_canonical_holder(int offset); ciField* get_field_by_offset(int field_offset, bool is_static); + ciField* get_field_by_name(ciSymbol* name, ciSymbol* signature, bool is_static); GrowableArray* non_static_fields(); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/ci/ciObjectFactory.cpp --- a/src/share/vm/ci/ciObjectFactory.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/ci/ciObjectFactory.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -168,6 +168,15 @@ ciEnv::_String = get(SystemDictionary::string_klass()) ->as_instance_klass(); + ciEnv::_StringBuffer = + get(SystemDictionary::stringBuffer_klass()) + ->as_instance_klass(); + ciEnv::_StringBuilder = + get(SystemDictionary::StringBuilder_klass()) + ->as_instance_klass(); + ciEnv::_Integer = + get(SystemDictionary::int_klass()) + ->as_instance_klass(); for (int len = -1; len != _ci_objects->length(); ) { len = _ci_objects->length(); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/classfile/javaClasses.cpp --- a/src/share/vm/classfile/javaClasses.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/classfile/javaClasses.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1124,8 +1124,7 @@ if (_dirty && _methods != NULL) { BarrierSet* bs = Universe::heap()->barrier_set(); assert(bs->has_write_ref_array_opt(), "Barrier set must have ref array opt"); - bs->write_ref_array(MemRegion((HeapWord*)_methods->base(), - _methods->array_size())); + bs->write_ref_array((HeapWord*)_methods->base(), _methods->length()); _dirty = false; } } @@ -2430,15 +2429,15 @@ } -// Support for sun_dyn_CallSiteImpl - -int sun_dyn_CallSiteImpl::_type_offset; -int sun_dyn_CallSiteImpl::_target_offset; -int sun_dyn_CallSiteImpl::_vmmethod_offset; - -void sun_dyn_CallSiteImpl::compute_offsets() { +// Support for java_dyn_CallSite + +int java_dyn_CallSite::_type_offset; +int java_dyn_CallSite::_target_offset; +int java_dyn_CallSite::_vmmethod_offset; + +void java_dyn_CallSite::compute_offsets() { if (!EnableInvokeDynamic) return; - klassOop k = SystemDictionary::CallSiteImpl_klass(); + klassOop k = SystemDictionary::CallSite_klass(); if (k != NULL) { compute_offset(_type_offset, k, vmSymbols::type_name(), vmSymbols::java_dyn_MethodType_signature(), true); compute_offset(_target_offset, k, vmSymbols::target_name(), vmSymbols::java_dyn_MethodHandle_signature(), true); @@ -2446,23 +2445,23 @@ } } -oop sun_dyn_CallSiteImpl::type(oop site) { +oop java_dyn_CallSite::type(oop site) { return site->obj_field(_type_offset); } -oop sun_dyn_CallSiteImpl::target(oop site) { +oop java_dyn_CallSite::target(oop site) { return site->obj_field(_target_offset); } -void sun_dyn_CallSiteImpl::set_target(oop site, oop target) { +void java_dyn_CallSite::set_target(oop site, oop target) { site->obj_field_put(_target_offset, target); } -oop sun_dyn_CallSiteImpl::vmmethod(oop site) { +oop java_dyn_CallSite::vmmethod(oop site) { return site->obj_field(_vmmethod_offset); } -void sun_dyn_CallSiteImpl::set_vmmethod(oop site, oop ref) { +void java_dyn_CallSite::set_vmmethod(oop site, oop ref) { site->obj_field_put(_vmmethod_offset, ref); } @@ -2811,7 +2810,7 @@ java_dyn_MethodTypeForm::compute_offsets(); } if (EnableInvokeDynamic) { - sun_dyn_CallSiteImpl::compute_offsets(); + java_dyn_CallSite::compute_offsets(); } java_security_AccessControlContext::compute_offsets(); // Initialize reflection classes. The layouts of these classes diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/classfile/javaClasses.hpp --- a/src/share/vm/classfile/javaClasses.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/classfile/javaClasses.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -1061,9 +1061,9 @@ }; -// Interface to sun.dyn.CallSiteImpl objects +// Interface to java.dyn.CallSite objects -class sun_dyn_CallSiteImpl: AllStatic { +class java_dyn_CallSite: AllStatic { friend class JavaClasses; private: diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/classfile/systemDictionary.cpp --- a/src/share/vm/classfile/systemDictionary.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/classfile/systemDictionary.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -99,6 +99,15 @@ return java_lang_Class::parallelCapable(class_loader()); } // ---------------------------------------------------------------------------- +// ParallelDefineClass flag does not apply to bootclass loader +bool SystemDictionary::is_parallelDefine(Handle class_loader) { + if (class_loader.is_null()) return false; + if (AllowParallelDefineClass && java_lang_Class::parallelCapable(class_loader())) { + return true; + } + return false; +} +// ---------------------------------------------------------------------------- // Resolving of classes // Forwards to resolve_or_null @@ -724,13 +733,13 @@ // Do actual loading k = load_instance_class(name, class_loader, THREAD); - // For UnsyncloadClass and AllowParallelDefineClass only: + // For UnsyncloadClass only // If they got a linkageError, check if a parallel class load succeeded. // If it did, then for bytecode resolution the specification requires // that we return the same result we did for the other thread, i.e. the // successfully loaded instanceKlass // Should not get here for classloaders that support parallelism - // with the new cleaner mechanism + // with the new cleaner mechanism, even with AllowParallelDefineClass // Bootstrap goes through here to allow for an extra guarantee check if (UnsyncloadClass || (class_loader.is_null())) { if (k.is_null() && HAS_PENDING_EXCEPTION @@ -1483,14 +1492,17 @@ } // Support parallel classloading -// Initial implementation for bootstrap classloader -// For custom class loaders that support parallel classloading, +// All parallel class loaders, including bootstrap classloader +// lock a placeholder entry for this class/class_loader pair +// to allow parallel defines of different classes for this class loader // With AllowParallelDefine flag==true, in case they do not synchronize around // FindLoadedClass/DefineClass, calls, we check for parallel // loading for them, wait if a defineClass is in progress // and return the initial requestor's results +// This flag does not apply to the bootstrap classloader. // With AllowParallelDefine flag==false, call through to define_instance_class // which will throw LinkageError: duplicate class definition. +// False is the requested default. // For better performance, the class loaders should synchronize // findClass(), i.e. FindLoadedClass/DefineClassIfAbsent or they // potentially waste time reading and parsing the bytestream. @@ -1511,9 +1523,11 @@ { MutexLocker mu(SystemDictionary_lock, THREAD); // First check if class already defined - klassOop check = find_class(d_index, d_hash, name_h, class_loader); - if (check != NULL) { - return(instanceKlassHandle(THREAD, check)); + if (UnsyncloadClass || (is_parallelDefine(class_loader))) { + klassOop check = find_class(d_index, d_hash, name_h, class_loader); + if (check != NULL) { + return(instanceKlassHandle(THREAD, check)); + } } // Acquire define token for this class/classloader @@ -1529,7 +1543,7 @@ // Only special cases allow parallel defines and can use other thread's results // Other cases fall through, and may run into duplicate defines // caught by finding an entry in the SystemDictionary - if ((UnsyncloadClass || AllowParallelDefineClass) && (probe->instanceKlass() != NULL)) { + if ((UnsyncloadClass || is_parallelDefine(class_loader)) && (probe->instanceKlass() != NULL)) { probe->remove_seen_thread(THREAD, PlaceholderTable::DEFINE_CLASS); placeholders()->find_and_remove(p_index, p_hash, name_h, class_loader, THREAD); SystemDictionary_lock->notify_all(); @@ -1973,7 +1987,7 @@ WKID indy_group_end = WK_KLASS_ENUM_NAME(Dynamic_klass); initialize_wk_klasses_until(indy_group_start, scan, CHECK); if (EnableInvokeDynamic) { - initialize_wk_klasses_through(indy_group_start, scan, CHECK); + initialize_wk_klasses_through(indy_group_end, scan, CHECK); } if (_well_known_klasses[indy_group_start] == NULL) { // Skip the rest of the dynamic typing classes, if Linkage is not loaded. @@ -2404,7 +2418,7 @@ methodHandle mh_invdyn, TRAPS) { Handle empty; - // call sun.dyn.CallSiteImpl::makeSite(caller, name, mtype, cmid, cbci) + // call java.dyn.CallSite::makeSite(caller, name, mtype, cmid, cbci) oop name_str_oop = StringTable::intern(name(), CHECK_(empty)); // not a handle! JavaCallArguments args(Handle(THREAD, caller->java_mirror())); args.push_oop(name_str_oop); @@ -2413,17 +2427,19 @@ args.push_int(caller_bci); JavaValue result(T_OBJECT); JavaCalls::call_static(&result, - SystemDictionary::CallSiteImpl_klass(), + SystemDictionary::CallSite_klass(), vmSymbols::makeSite_name(), vmSymbols::makeSite_signature(), &args, CHECK_(empty)); oop call_site_oop = (oop) result.get_jobject(); assert(call_site_oop->is_oop() - /*&& sun_dyn_CallSiteImpl::is_instance(call_site_oop)*/, "must be sane"); - sun_dyn_CallSiteImpl::set_vmmethod(call_site_oop, mh_invdyn()); + /*&& java_dyn_CallSite::is_instance(call_site_oop)*/, "must be sane"); + java_dyn_CallSite::set_vmmethod(call_site_oop, mh_invdyn()); if (TraceMethodHandles) { +#ifndef PRODUCT tty->print_cr("Linked invokedynamic bci=%d site="INTPTR_FORMAT":", caller_bci, call_site_oop); call_site_oop->print(); tty->cr(); +#endif //PRODUCT } return call_site_oop; } @@ -2436,9 +2452,17 @@ instanceKlassHandle ik(THREAD, caller()); - if (ik->bootstrap_method() != NULL) { - return Handle(THREAD, ik->bootstrap_method()); + oop boot_method_oop = ik->bootstrap_method(); + if (boot_method_oop != NULL) { + if (TraceMethodHandles) { + tty->print_cr("bootstrap method for "PTR_FORMAT" cached as "PTR_FORMAT":", ik(), boot_method_oop); + } + NOT_PRODUCT(if (!boot_method_oop->is_oop()) { tty->print_cr("*** boot MH of "PTR_FORMAT" = "PTR_FORMAT, ik(), boot_method_oop); ik()->print(); }); + assert(boot_method_oop->is_oop() + && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane"); + return Handle(THREAD, boot_method_oop); } + boot_method_oop = NULL; // GC safety // call java.dyn.Linkage::findBootstrapMethod(caller, sbk) JavaCallArguments args(Handle(THREAD, ik->java_mirror())); @@ -2452,9 +2476,18 @@ vmSymbols::findBootstrapMethod_name(), vmSymbols::findBootstrapMethod_signature(), &args, CHECK_(empty)); - oop boot_method_oop = (oop) result.get_jobject(); + boot_method_oop = (oop) result.get_jobject(); if (boot_method_oop != NULL) { + if (TraceMethodHandles) { +#ifndef PRODUCT + tty->print_cr("--------"); + tty->print_cr("bootstrap method for "PTR_FORMAT" computed as "PTR_FORMAT":", ik(), boot_method_oop); + ik()->print(); + boot_method_oop->print(); + tty->print_cr("========"); +#endif //PRODUCT + } assert(boot_method_oop->is_oop() && java_dyn_MethodHandle::is_instance(boot_method_oop), "must be sane"); // probably no race conditions, but let's be careful: @@ -2463,6 +2496,14 @@ else boot_method_oop = ik->bootstrap_method(); } else { + if (TraceMethodHandles) { +#ifndef PRODUCT + tty->print_cr("--------"); + tty->print_cr("bootstrap method for "PTR_FORMAT" computed as NULL:", ik()); + ik()->print(); + tty->print_cr("========"); +#endif //PRODUCT + } boot_method_oop = ik->bootstrap_method(); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/classfile/systemDictionary.hpp --- a/src/share/vm/classfile/systemDictionary.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/classfile/systemDictionary.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -144,13 +144,13 @@ template(WrongMethodTypeException_klass, java_dyn_WrongMethodTypeException, Opt) \ template(Linkage_klass, java_dyn_Linkage, Opt) \ template(CallSite_klass, java_dyn_CallSite, Opt) \ - template(CallSiteImpl_klass, sun_dyn_CallSiteImpl, Opt) \ template(Dynamic_klass, java_dyn_Dynamic, Opt) \ /* Note: MethodHandle must be first, and Dynamic last in group */ \ \ template(vector_klass, java_util_Vector, Pre) \ template(hashtable_klass, java_util_Hashtable, Pre) \ template(stringBuffer_klass, java_lang_StringBuffer, Pre) \ + template(StringBuilder_klass, java_lang_StringBuilder, Pre) \ \ /* It's NULL in non-1.4 JDKs. */ \ template(stackTraceElement_klass, java_lang_StackTraceElement, Opt) \ @@ -578,6 +578,7 @@ static Handle compute_loader_lock_object(Handle class_loader, TRAPS); static void check_loader_lock_contention(Handle loader_lock, TRAPS); static bool is_parallelCapable(Handle class_loader); + static bool is_parallelDefine(Handle class_loader); static klassOop find_shared_class(symbolHandle class_name); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/classfile/verifier.cpp --- a/src/share/vm/classfile/verifier.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/classfile/verifier.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1903,17 +1903,8 @@ verify_cp_type(index, cp, types, CHECK_VERIFY(this)); // Get method name and signature - symbolHandle method_name; - symbolHandle method_sig; - if (opcode == Bytecodes::_invokedynamic) { - int name_index = cp->name_ref_index_at(index); - int sig_index = cp->signature_ref_index_at(index); - method_name = symbolHandle(THREAD, cp->symbol_at(name_index)); - method_sig = symbolHandle(THREAD, cp->symbol_at(sig_index)); - } else { - method_name = symbolHandle(THREAD, cp->name_ref_at(index)); - method_sig = symbolHandle(THREAD, cp->signature_ref_at(index)); - } + symbolHandle method_name(THREAD, cp->name_ref_at(index)); + symbolHandle method_sig(THREAD, cp->signature_ref_at(index)); if (!SignatureVerifier::is_valid_method_signature(method_sig)) { class_format_error( diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/classfile/vmSymbols.cpp --- a/src/share/vm/classfile/vmSymbols.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/classfile/vmSymbols.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -303,6 +303,11 @@ const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; return (flags & (req | neg)) == req; } +inline bool match_F_Y(jshort flags) { + const int req = JVM_ACC_SYNCHRONIZED; + const int neg = JVM_ACC_STATIC; + return (flags & (req | neg)) == req; +} inline bool match_F_RN(jshort flags) { const int req = JVM_ACC_NATIVE; const int neg = JVM_ACC_STATIC | JVM_ACC_SYNCHRONIZED; @@ -361,6 +366,7 @@ const char* sname = vmSymbols::name_for(signature_for(id)); const char* fname = ""; switch (flags_for(id)) { + case F_Y: fname = "synchronized "; break; case F_RN: fname = "native "; break; case F_SN: fname = "native static "; break; case F_S: fname = "static "; break; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/classfile/vmSymbols.hpp --- a/src/share/vm/classfile/vmSymbols.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/classfile/vmSymbols.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -84,6 +84,7 @@ template(java_lang_reflect_Field, "java/lang/reflect/Field") \ template(java_lang_reflect_Array, "java/lang/reflect/Array") \ template(java_lang_StringBuffer, "java/lang/StringBuffer") \ + template(java_lang_StringBuilder, "java/lang/StringBuilder") \ template(java_lang_CharSequence, "java/lang/CharSequence") \ template(java_security_AccessControlContext, "java/security/AccessControlContext") \ template(java_security_ProtectionDomain, "java/security/ProtectionDomain") \ @@ -233,10 +234,9 @@ template(sun_dyn_AdapterMethodHandle, "sun/dyn/AdapterMethodHandle") \ template(sun_dyn_BoundMethodHandle, "sun/dyn/BoundMethodHandle") \ template(sun_dyn_DirectMethodHandle, "sun/dyn/DirectMethodHandle") \ - template(sun_dyn_CallSiteImpl, "sun/dyn/CallSiteImpl") \ template(makeImpl_name, "makeImpl") /*MethodType::makeImpl*/ \ template(makeImpl_signature, "(Ljava/lang/Class;[Ljava/lang/Class;ZZ)Ljava/dyn/MethodType;") \ - template(makeSite_name, "makeSite") /*CallSiteImpl::makeImpl*/ \ + template(makeSite_name, "makeSite") /*CallSite::makeSite*/ \ template(makeSite_signature, "(Ljava/lang/Class;Ljava/lang/String;Ljava/dyn/MethodType;II)Ljava/dyn/CallSite;") \ template(findBootstrapMethod_name, "findBootstrapMethod") \ template(findBootstrapMethod_signature, "(Ljava/lang/Class;Ljava/lang/Class;)Ljava/dyn/MethodHandle;") \ @@ -335,6 +335,7 @@ template(ptypes_name, "ptypes") \ template(form_name, "form") \ template(erasedType_name, "erasedType") \ + template(append_name, "append") \ \ /* non-intrinsic name/signature pairs: */ \ template(register_method_name, "register") \ @@ -416,6 +417,13 @@ template(string_signature, "Ljava/lang/String;") \ template(reference_signature, "Ljava/lang/ref/Reference;") \ template(concurrenthashmap_signature, "Ljava/util/concurrent/ConcurrentHashMap;") \ + template(String_StringBuilder_signature, "(Ljava/lang/String;)Ljava/lang/StringBuilder;") \ + template(int_StringBuilder_signature, "(I)Ljava/lang/StringBuilder;") \ + template(char_StringBuilder_signature, "(C)Ljava/lang/StringBuilder;") \ + template(String_StringBuffer_signature, "(Ljava/lang/String;)Ljava/lang/StringBuffer;") \ + template(int_StringBuffer_signature, "(I)Ljava/lang/StringBuffer;") \ + template(char_StringBuffer_signature, "(C)Ljava/lang/StringBuffer;") \ + template(int_String_signature, "(I)Ljava/lang/String;") \ /* signature symbols needed by intrinsics */ \ VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, VM_SYMBOL_IGNORE, template, VM_ALIAS_IGNORE) \ \ @@ -815,10 +823,34 @@ /*the compiler does have special inlining code for these; bytecode inline is just fine */ \ \ do_intrinsic(_fillInStackTrace, java_lang_Throwable, fillInStackTrace_name, void_throwable_signature, F_RNY) \ - \ - do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \ - /* (symbol object_initializer_name defined above) */ \ - \ + \ + do_intrinsic(_StringBuilder_void, java_lang_StringBuilder, object_initializer_name, void_method_signature, F_R) \ + do_intrinsic(_StringBuilder_int, java_lang_StringBuilder, object_initializer_name, int_void_signature, F_R) \ + do_intrinsic(_StringBuilder_String, java_lang_StringBuilder, object_initializer_name, string_void_signature, F_R) \ + \ + do_intrinsic(_StringBuilder_append_char, java_lang_StringBuilder, append_name, char_StringBuilder_signature, F_R) \ + do_intrinsic(_StringBuilder_append_int, java_lang_StringBuilder, append_name, int_StringBuilder_signature, F_R) \ + do_intrinsic(_StringBuilder_append_String, java_lang_StringBuilder, append_name, String_StringBuilder_signature, F_R) \ + \ + do_intrinsic(_StringBuilder_toString, java_lang_StringBuilder, toString_name, void_string_signature, F_R) \ + \ + do_intrinsic(_StringBuffer_void, java_lang_StringBuffer, object_initializer_name, void_method_signature, F_R) \ + do_intrinsic(_StringBuffer_int, java_lang_StringBuffer, object_initializer_name, int_void_signature, F_R) \ + do_intrinsic(_StringBuffer_String, java_lang_StringBuffer, object_initializer_name, string_void_signature, F_R) \ + \ + do_intrinsic(_StringBuffer_append_char, java_lang_StringBuffer, append_name, char_StringBuffer_signature, F_Y) \ + do_intrinsic(_StringBuffer_append_int, java_lang_StringBuffer, append_name, int_StringBuffer_signature, F_Y) \ + do_intrinsic(_StringBuffer_append_String, java_lang_StringBuffer, append_name, String_StringBuffer_signature, F_Y) \ + \ + do_intrinsic(_StringBuffer_toString, java_lang_StringBuffer, toString_name, void_string_signature, F_Y) \ + \ + do_intrinsic(_Integer_toString, java_lang_Integer, toString_name, int_String_signature, F_S) \ + \ + do_intrinsic(_String_String, java_lang_String, object_initializer_name, string_void_signature, F_R) \ + \ + do_intrinsic(_Object_init, java_lang_Object, object_initializer_name, void_method_signature, F_R) \ + /* (symbol object_initializer_name defined above) */ \ + \ do_intrinsic(_invoke, java_lang_reflect_Method, invoke_name, object_array_object_object_signature, F_R) \ /* (symbols invoke_name and invoke_signature defined above) */ \ \ @@ -946,11 +978,12 @@ enum Flags { // AccessFlags syndromes relevant to intrinsics. F_none = 0, - F_R, // !static !synchronized (R="regular") - F_S, // static !synchronized - F_RN, // !static native !synchronized - F_SN, // static native !synchronized - F_RNY // !static native synchronized + F_R, // !static ?native !synchronized (R="regular") + F_S, // static ?native !synchronized + F_Y, // !static ?native synchronized + F_RN, // !static native !synchronized + F_SN, // static native !synchronized + F_RNY // !static native synchronized }; public: diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp --- a/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -709,7 +709,8 @@ // Support for parallelizing survivor space rescan if (CMSParallelRemarkEnabled && CMSParallelSurvivorRemarkEnabled) { - size_t max_plab_samples = MaxNewSize/((SurvivorRatio+2)*MinTLABSize); + size_t max_plab_samples = cp->max_gen0_size()/ + ((SurvivorRatio+2)*MinTLABSize); _survivor_plab_array = NEW_C_HEAP_ARRAY(ChunkArray, ParallelGCThreads); _survivor_chunk_array = NEW_C_HEAP_ARRAY(HeapWord*, 2*max_plab_samples); _cursor = NEW_C_HEAP_ARRAY(size_t, ParallelGCThreads); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -155,7 +155,7 @@ } DirtyCardQueueSet::CompletedBufferNode* -DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) { +DirtyCardQueueSet::get_completed_buffer(int stop_at) { CompletedBufferNode* nd = NULL; MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); @@ -175,28 +175,6 @@ return nd; } -// We only do this in contexts where there is no concurrent enqueueing. -DirtyCardQueueSet::CompletedBufferNode* -DirtyCardQueueSet::get_completed_buffer_CAS() { - CompletedBufferNode* nd = _completed_buffers_head; - - while (nd != NULL) { - CompletedBufferNode* next = nd->next; - CompletedBufferNode* result = - (CompletedBufferNode*)Atomic::cmpxchg_ptr(next, - &_completed_buffers_head, - nd); - if (result == nd) { - return result; - } else { - nd = _completed_buffers_head; - } - } - assert(_completed_buffers_head == NULL, "Loop post"); - _completed_buffers_tail = NULL; - return NULL; -} - bool DirtyCardQueueSet:: apply_closure_to_completed_buffer_helper(int worker_i, CompletedBufferNode* nd) { @@ -222,15 +200,10 @@ bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, int stop_at, - bool with_CAS) + bool during_pause) { - CompletedBufferNode* nd = NULL; - if (with_CAS) { - guarantee(stop_at == 0, "Precondition"); - nd = get_completed_buffer_CAS(); - } else { - nd = get_completed_buffer_lock(stop_at); - } + assert(!during_pause || stop_at == 0, "Should not leave any completed buffers during a pause"); + CompletedBufferNode* nd = get_completed_buffer(stop_at); bool res = apply_closure_to_completed_buffer_helper(worker_i, nd); if (res) Atomic::inc(&_processed_buffers_rs_thread); return res; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp --- a/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 2001-2009 Sun Microsystems, Inc. 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 @@ -120,12 +120,13 @@ // is returned to the completed buffer set, and this call returns false. bool apply_closure_to_completed_buffer(int worker_i = 0, int stop_at = 0, - bool with_CAS = false); + bool during_pause = false); + bool apply_closure_to_completed_buffer_helper(int worker_i, CompletedBufferNode* nd); - CompletedBufferNode* get_completed_buffer_CAS(); - CompletedBufferNode* get_completed_buffer_lock(int stop_at); + CompletedBufferNode* get_completed_buffer(int stop_at); + // Applies the current closure to all completed buffers, // non-consumptively. void apply_closure_to_all_completed_buffers(); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -928,6 +928,8 @@ TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); TraceTime t(full ? "Full GC (System.gc())" : "Full GC", PrintGC, true, gclog_or_tty); + TraceMemoryManagerStats tms(true /* fullGC */); + double start = os::elapsedTime(); g1_policy()->record_full_collection_start(); @@ -1001,6 +1003,8 @@ COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); + MemoryService::track_memory_usage(); + if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); @@ -1732,13 +1736,6 @@ return car->free(); } -void G1CollectedHeap::collect(GCCause::Cause cause) { - // The caller doesn't have the Heap_lock - assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); - MutexLocker ml(Heap_lock); - collect_locked(cause); -} - void G1CollectedHeap::collect_as_vm_thread(GCCause::Cause cause) { assert(Thread::current()->is_VM_thread(), "Precondition#1"); assert(Heap_lock->is_locked(), "Precondition#2"); @@ -1755,17 +1752,31 @@ } } - -void G1CollectedHeap::collect_locked(GCCause::Cause cause) { - // Don't want to do a GC until cleanup is completed. - wait_for_cleanup_complete(); - - // Read the GC count while holding the Heap_lock - int gc_count_before = SharedHeap::heap()->total_collections(); +void G1CollectedHeap::collect(GCCause::Cause cause) { + // The caller doesn't have the Heap_lock + assert(!Heap_lock->owned_by_self(), "this thread should not own the Heap_lock"); + + int gc_count_before; { - MutexUnlocker mu(Heap_lock); // give up heap lock, execute gets it back - VM_G1CollectFull op(gc_count_before, cause); - VMThread::execute(&op); + MutexLocker ml(Heap_lock); + // Read the GC count while holding the Heap_lock + gc_count_before = SharedHeap::heap()->total_collections(); + + // Don't want to do a GC until cleanup is completed. + wait_for_cleanup_complete(); + } // We give up heap lock; VMThread::execute gets it back below + switch (cause) { + case GCCause::_scavenge_alot: { + // Do an incremental pause, which might sometimes be abandoned. + VM_G1IncCollectionPause op(gc_count_before, cause); + VMThread::execute(&op); + break; + } + default: { + // In all other cases, we currently do a full gc. + VM_G1CollectFull op(gc_count_before, cause); + VMThread::execute(&op); + } } } @@ -2119,7 +2130,7 @@ } size_t G1CollectedHeap::max_capacity() const { - return _g1_committed.byte_size(); + return g1_reserved_obj_bytes(); } jlong G1CollectedHeap::millis_since_last_gc() { @@ -2638,6 +2649,8 @@ } { + ResourceMark rm; + char verbose_str[128]; sprintf(verbose_str, "GC pause "); if (g1_policy()->in_young_gc_mode()) { @@ -2649,8 +2662,6 @@ if (g1_policy()->should_initiate_conc_mark()) strcat(verbose_str, " (initial-mark)"); - GCCauseSetter x(this, GCCause::_g1_inc_collection_pause); - // if PrintGCDetails is on, we'll print long statistics information // in the collector policy code, so let's not print this as the output // is messy if we do. @@ -2658,7 +2669,8 @@ TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty); TraceTime t(verbose_str, PrintGC && !PrintGCDetails, true, gclog_or_tty); - ResourceMark rm; + TraceMemoryManagerStats tms(false /* fullGC */); + assert(SafepointSynchronize::is_at_safepoint(), "should be at safepoint"); assert(Thread::current() == VMThread::vm_thread(), "should be in vm thread"); guarantee(!is_gc_active(), "collection is not reentrant"); @@ -2802,6 +2814,22 @@ _young_list->reset_auxilary_lists(); } } else { + if (_in_cset_fast_test != NULL) { + assert(_in_cset_fast_test_base != NULL, "Since _in_cset_fast_test isn't"); + FREE_C_HEAP_ARRAY(bool, _in_cset_fast_test_base); + // this is more for peace of mind; we're nulling them here and + // we're expecting them to be null at the beginning of the next GC + _in_cset_fast_test = NULL; + _in_cset_fast_test_base = NULL; + } + // This looks confusing, because the DPT should really be empty + // at this point -- since we have not done any collection work, + // there should not be any derived pointers in the table to update; + // however, there is some additional state in the DPT which is + // reset at the end of the (null) "gc" here via the following call. + // A better approach might be to split off that state resetting work + // into a separate method that asserts that the DPT is empty and call + // that here. That is deferred for now. COMPILER2_PRESENT(DerivedPointerTable::update_pointers()); } @@ -2838,6 +2866,8 @@ assert(regions_accounted_for(), "Region leakage."); + MemoryService::track_memory_usage(); + if (VerifyAfterGC && total_collections() >= VerifyGCStartAt) { HandleMark hm; // Discard invalid handles created during verification gclog_or_tty->print(" VerifyAfterGC:"); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp --- a/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -692,7 +692,7 @@ // Reserved (g1 only; super method includes perm), capacity and the used // portion in bytes. - size_t g1_reserved_obj_bytes() { return _g1_reserved.byte_size(); } + size_t g1_reserved_obj_bytes() const { return _g1_reserved.byte_size(); } virtual size_t capacity() const; virtual size_t used() const; // This should be called when we're not holding the heap lock. The diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp --- a/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1516,8 +1516,30 @@ (end_time_sec - _recent_prev_end_times_for_all_gcs_sec->oldest()) * 1000.0; update_recent_gc_times(end_time_sec, elapsed_ms); _recent_avg_pause_time_ratio = _recent_gc_times_ms->sum()/interval_ms; - // using 1.01 to account for floating point inaccuracies - assert(recent_avg_pause_time_ratio() < 1.01, "All GC?"); + if (recent_avg_pause_time_ratio() < 0.0 || + (recent_avg_pause_time_ratio() - 1.0 > 0.0)) { +#ifndef PRODUCT + // Dump info to allow post-facto debugging + gclog_or_tty->print_cr("recent_avg_pause_time_ratio() out of bounds"); + gclog_or_tty->print_cr("-------------------------------------------"); + gclog_or_tty->print_cr("Recent GC Times (ms):"); + _recent_gc_times_ms->dump(); + gclog_or_tty->print_cr("(End Time=%3.3f) Recent GC End Times (s):", end_time_sec); + _recent_prev_end_times_for_all_gcs_sec->dump(); + gclog_or_tty->print_cr("GC = %3.3f, Interval = %3.3f, Ratio = %3.3f", + _recent_gc_times_ms->sum(), interval_ms, recent_avg_pause_time_ratio()); + // In debug mode, terminate the JVM if the user wants to debug at this point. + assert(!G1FailOnFPError, "Debugging data for CR 6898948 has been dumped above"); +#endif // !PRODUCT + // Clip ratio between 0.0 and 1.0, and continue. This will be fixed in + // CR 6902692 by redoing the manner in which the ratio is incrementally computed. + if (_recent_avg_pause_time_ratio < 0.0) { + _recent_avg_pause_time_ratio = 0.0; + } else { + assert(_recent_avg_pause_time_ratio - 1.0 > 0.0, "Ctl-point invariant"); + _recent_avg_pause_time_ratio = 1.0; + } + } } if (G1PolicyVerbose > 1) { @@ -2825,8 +2847,15 @@ double non_young_start_time_sec; start_recording_regions(); - guarantee(_target_pause_time_ms > -1.0, + guarantee(_target_pause_time_ms > -1.0 + NOT_PRODUCT(|| Universe::heap()->gc_cause() == GCCause::_scavenge_alot), "_target_pause_time_ms should have been set!"); +#ifndef PRODUCT + if (_target_pause_time_ms <= -1.0) { + assert(ScavengeALot && Universe::heap()->gc_cause() == GCCause::_scavenge_alot, "Error"); + _target_pause_time_ms = _mmu_tracker->max_gc_time() * 1000.0; + } +#endif assert(_collection_set == NULL, "Precondition"); double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); @@ -2972,7 +3001,3 @@ G1CollectorPolicy::record_collection_pause_end(abandoned); assert(assertMarkedBytesDataOK(), "Marked regions not OK at pause end."); } - -// Local Variables: *** -// c-indentation-style: gnu *** -// End: *** diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/g1MMUTracker.cpp --- a/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -86,12 +86,22 @@ // increase the array size (:-) // remove the oldest entry (this might allow more GC time for // the time slice than what's allowed) - // concolidate the two entries with the minimum gap between them - // (this mighte allow less GC time than what's allowed) - guarantee(0, "array full, currently we can't recover"); + // consolidate the two entries with the minimum gap between them + // (this might allow less GC time than what's allowed) + guarantee(NOT_PRODUCT(ScavengeALot ||) G1ForgetfulMMUTracker, + "array full, currently we can't recover unless +G1ForgetfulMMUTracker"); + // In the case where ScavengeALot is true, such overflow is not + // uncommon; in such cases, we can, without much loss of precision + // or performance (we are GC'ing most of the time anyway!), + // simply overwrite the oldest entry in the tracker: this + // is also the behaviour when G1ForgetfulMMUTracker is enabled. + _head_index = trim_index(_head_index + 1); + assert(_head_index == _tail_index, "Because we have a full circular buffer"); + _tail_index = trim_index(_tail_index + 1); + } else { + _head_index = trim_index(_head_index + 1); + ++_no_entries; } - _head_index = trim_index(_head_index + 1); - ++_no_entries; _array[_head_index] = G1MMUTrackerQueueElem(start, end); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/g1MMUTracker.hpp --- a/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -99,7 +99,10 @@ // The array is of fixed size and I don't think we'll need more than // two or three entries with the current behaviour of G1 pauses. // If the array is full, an easy fix is to look for the pauses with - // the shortest gap between them and concolidate them. + // the shortest gap between them and consolidate them. + // For now, we have taken the expedient alternative of forgetting + // the oldest entry in the event that +G1ForgetfulMMUTracker, thus + // potentially violating MMU specs for some time thereafter. G1MMUTrackerQueueElem _array[QueueLength]; int _head_index; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/g1_globals.hpp --- a/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/g1_globals.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -242,6 +242,10 @@ product(bool, G1UseSurvivorSpaces, true, \ "When true, use survivor space.") \ \ + develop(bool, G1FailOnFPError, false, \ + "When set, G1 will fail when it encounters an FP 'error', " \ + "so as to allow debugging") \ + \ develop(bool, G1FixedTenuringThreshold, false, \ "When set, G1 will not adjust the tenuring threshold") \ \ @@ -252,6 +256,9 @@ "If non-0 is the size of the G1 survivor space, " \ "otherwise SurvivorRatio is used to determine the size") \ \ + product(bool, G1ForgetfulMMUTracker, false, \ + "If the MMU tracker's memory is full, forget the oldest entry") \ + \ product(uintx, G1HeapRegionSize, 0, \ "Size of the G1 regions.") \ \ diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/ptrQueue.cpp --- a/src/share/vm/gc_implementation/g1/ptrQueue.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/ptrQueue.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -107,7 +107,7 @@ res[0] = NULL; return res; } else { - return NEW_C_HEAP_ARRAY(void*, _sz); + return (void**) NEW_C_HEAP_ARRAY(char, _sz); } } @@ -127,7 +127,8 @@ assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong."); void** head = _buf_free_list; _buf_free_list = (void**)_buf_free_list[0]; - FREE_C_HEAP_ARRAY(void*,head); + FREE_C_HEAP_ARRAY(char, head); + _buf_free_list_sz --; n--; } } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/vm_operations_g1.cpp --- a/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -42,7 +42,7 @@ void VM_G1IncCollectionPause::doit() { JvmtiGCForAllocationMarker jgcm; G1CollectedHeap* g1h = G1CollectedHeap::heap(); - GCCauseSetter x(g1h, GCCause::_g1_inc_collection_pause); + GCCauseSetter x(g1h, _gc_cause); g1h->do_collection_pause_at_safepoint(); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/g1/vm_operations_g1.hpp --- a/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -68,8 +68,9 @@ class VM_G1IncCollectionPause: public VM_GC_Operation { public: - VM_G1IncCollectionPause(int gc_count_before) : - VM_GC_Operation(gc_count_before) {} + VM_G1IncCollectionPause(int gc_count_before, + GCCause::Cause gc_cause = GCCause::_g1_inc_collection_pause) : + VM_GC_Operation(gc_count_before) { _gc_cause = gc_cause; } virtual VMOp_Type type() const { return VMOp_G1IncCollectionPause; } virtual void doit(); virtual const char* name() const { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/includeDB_gc_g1 --- a/src/share/vm/gc_implementation/includeDB_gc_g1 Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/includeDB_gc_g1 Fri Dec 11 16:38:37 2009 -0800 @@ -222,6 +222,15 @@ g1MarkSweep.hpp timer.hpp g1MarkSweep.hpp universe.hpp +g1MemoryPool.cpp heapRegion.hpp +g1MemoryPool.cpp g1CollectedHeap.inline.hpp +g1MemoryPool.cpp g1CollectedHeap.hpp +g1MemoryPool.cpp g1CollectorPolicy.hpp +g1MemoryPool.cpp g1MemoryPool.hpp + +g1MemoryPool.hpp memoryUsage.hpp +g1MemoryPool.hpp memoryPool.hpp + g1OopClosures.inline.hpp concurrentMark.hpp g1OopClosures.inline.hpp g1OopClosures.hpp g1OopClosures.inline.hpp g1CollectedHeap.hpp @@ -303,6 +312,8 @@ klass.hpp g1OopClosures.hpp +memoryService.cpp g1MemoryPool.hpp + ptrQueue.cpp allocation.hpp ptrQueue.cpp allocation.inline.hpp ptrQueue.cpp mutex.hpp diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp --- a/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -51,7 +51,7 @@ cname = PerfDataManager::counter_name(name_space(), "oldCapacity"); _old_capacity = PerfDataManager::create_variable(SUN_GC, cname, - PerfData::U_Bytes, (jlong) Arguments::initial_heap_size(), CHECK); + PerfData::U_Bytes, (jlong) InitialHeapSize, CHECK); cname = PerfDataManager::counter_name(name_space(), "boundaryMoved"); _boundary_moved = PerfDataManager::create_variable(SUN_GC, cname, diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/includeDB_compiler2 --- a/src/share/vm/includeDB_compiler2 Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/includeDB_compiler2 Fri Dec 11 16:38:37 2009 -0800 @@ -149,6 +149,7 @@ c2compiler.hpp abstractCompiler.hpp callGenerator.cpp addnode.hpp +callGenerator.cpp bcEscapeAnalyzer.hpp callGenerator.cpp callGenerator.hpp callGenerator.cpp callnode.hpp callGenerator.cpp cfgnode.hpp @@ -321,6 +322,7 @@ compile.cpp rootnode.hpp compile.cpp runtime.hpp compile.cpp signature.hpp +compile.cpp stringopts.hpp compile.cpp stubRoutines.hpp compile.cpp systemDictionary.hpp compile.cpp timer.hpp @@ -476,12 +478,16 @@ graphKit.cpp runtime.hpp graphKit.cpp sharedRuntime.hpp +graphKit.hpp addnode.hpp graphKit.hpp callnode.hpp graphKit.hpp cfgnode.hpp graphKit.hpp ciEnv.hpp +graphKit.hpp divnode.hpp graphKit.hpp compile.hpp graphKit.hpp deoptimization.hpp graphKit.hpp phaseX.hpp +graphKit.hpp mulnode.hpp +graphKit.hpp subnode.hpp graphKit.hpp type.hpp idealKit.cpp addnode.hpp @@ -490,7 +496,10 @@ idealKit.cpp idealKit.hpp idealKit.cpp runtime.hpp +idealKit.hpp addnode.hpp +idealKit.hpp cfgnode.hpp idealKit.hpp connode.hpp +idealKit.hpp divnode.hpp idealKit.hpp mulnode.hpp idealKit.hpp phaseX.hpp idealKit.hpp subnode.hpp @@ -641,6 +650,7 @@ macro.cpp callnode.hpp macro.cpp cfgnode.hpp macro.cpp compile.hpp +macro.cpp compileLog.hpp macro.cpp connode.hpp macro.cpp locknode.hpp macro.cpp loopnode.hpp @@ -993,6 +1003,21 @@ split_if.cpp connode.hpp split_if.cpp loopnode.hpp +stringopts.hpp phaseX.hpp +stringopts.hpp node.hpp + +stringopts.cpp addnode.hpp +stringopts.cpp callnode.hpp +stringopts.cpp callGenerator.hpp +stringopts.cpp compileLog.hpp +stringopts.cpp divnode.hpp +stringopts.cpp idealKit.hpp +stringopts.cpp graphKit.hpp +stringopts.cpp rootnode.hpp +stringopts.cpp runtime.hpp +stringopts.cpp subnode.hpp +stringopts.cpp stringopts.hpp + stubGenerator_.cpp runtime.hpp stubRoutines.cpp runtime.hpp diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/includeDB_core --- a/src/share/vm/includeDB_core Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/includeDB_core Fri Dec 11 16:38:37 2009 -0800 @@ -289,7 +289,7 @@ attachListener.hpp debug.hpp attachListener.hpp ostream.hpp -barrierSet.cpp barrierSet.hpp +barrierSet.cpp barrierSet.inline.hpp barrierSet.cpp collectedHeap.hpp barrierSet.cpp universe.hpp @@ -570,6 +570,7 @@ ciEnv.hpp dependencies.hpp ciEnv.hpp exceptionHandlerTable.hpp ciEnv.hpp oopMap.hpp +ciEnv.hpp systemDictionary.hpp ciEnv.hpp thread.hpp ciExceptionHandler.cpp ciExceptionHandler.hpp @@ -1291,6 +1292,7 @@ cpCacheOop.cpp markSweep.inline.hpp cpCacheOop.cpp objArrayOop.hpp cpCacheOop.cpp oop.inline.hpp +cpCacheOop.cpp rewriter.hpp cpCacheOop.cpp universe.inline.hpp cpCacheOop.hpp allocation.hpp diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/bytecodeInterpreter.cpp --- a/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/bytecodeInterpreter.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -281,7 +281,7 @@ #define DO_BACKEDGE_CHECKS(skip, branch_pc) \ if ((skip) <= 0) { \ - if (UseCompiler && UseLoopCounter) { \ + if (UseLoopCounter) { \ bool do_OSR = UseOnStackReplacement; \ BACKEDGE_COUNT->increment(); \ if (do_OSR) do_OSR = BACKEDGE_COUNT->reached_InvocationLimit(); \ @@ -289,16 +289,12 @@ nmethod* osr_nmethod; \ OSR_REQUEST(osr_nmethod, branch_pc); \ if (osr_nmethod != NULL && osr_nmethod->osr_entry_bci() != InvalidOSREntryBci) { \ - intptr_t* buf; \ - CALL_VM(buf=SharedRuntime::OSR_migration_begin(THREAD), handle_exception); \ + intptr_t* buf = SharedRuntime::OSR_migration_begin(THREAD); \ istate->set_msg(do_osr); \ istate->set_osr_buf((address)buf); \ istate->set_osr_entry(osr_nmethod->osr_entry()); \ return; \ } \ - } else { \ - INCR_INVOCATION_COUNT; \ - SAFEPOINT; \ } \ } /* UseCompiler ... */ \ INCR_INVOCATION_COUNT; \ @@ -1281,12 +1277,7 @@ jfloat f; jdouble r; f = STACK_FLOAT(-1); -#ifdef IA64 - // IA64 gcc bug - r = ( f == 0.0f ) ? (jdouble) f : (jdouble) f + ia64_double_zero; -#else r = (jdouble) f; -#endif MORE_STACK(-1); // POP SET_STACK_DOUBLE(r, 1); UPDATE_PC_AND_TOS_AND_CONTINUE(1, 2); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/bytecodeTracer.cpp --- a/src/share/vm/interpreter/bytecodeTracer.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/bytecodeTracer.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -282,18 +282,21 @@ constantPoolOop constants = method()->constants(); constantTag tag = constants->tag_at(i); + int nt_index = -1; + switch (tag.value()) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Methodref: case JVM_CONSTANT_Fieldref: + case JVM_CONSTANT_NameAndType: break; default: st->print_cr(" bad tag=%d at %d", tag.value(), i); return; } - symbolOop name = constants->name_ref_at(orig_i); - symbolOop signature = constants->signature_ref_at(orig_i); + symbolOop name = constants->uncached_name_ref_at(i); + symbolOop signature = constants->uncached_signature_ref_at(i); st->print_cr(" %d <%s> <%s> ", i, name->as_C_string(), signature->as_C_string()); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/interpreter.cpp --- a/src/share/vm/interpreter/interpreter.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/interpreter.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -314,6 +314,20 @@ break; } + case Bytecodes::_invokedynamic: { + Thread *thread = Thread::current(); + ResourceMark rm(thread); + methodHandle mh(thread, method); + type = Bytecode_invoke_at(mh, bci)->result_type(thread); + // since the cache entry might not be initialized: + // (NOT needed for the old calling convension) + if (!is_top_frame) { + int index = Bytes::get_native_u4(bcp+1); + method->constants()->cache()->entry_at(index)->set_parameter_size(callee_parameters); + } + break; + } + case Bytecodes::_ldc : type = constant_pool_type( method, *(bcp+1) ); break; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/interpreterRuntime.cpp --- a/src/share/vm/interpreter/interpreterRuntime.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/interpreterRuntime.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -681,7 +681,7 @@ IRT_END -// First time execution: Resolve symbols, create a permanent CallSiteImpl object. +// First time execution: Resolve symbols, create a permanent CallSite object. IRT_ENTRY(void, InterpreterRuntime::resolve_invokedynamic(JavaThread* thread)) { ResourceMark rm(thread); @@ -708,21 +708,16 @@ constantPoolHandle pool(thread, caller_method->constants()); pool->set_invokedynamic(); // mark header to flag active call sites - int raw_index = four_byte_index(thread); - assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "invokedynamic indexes marked specially"); - - // there are two CPC entries that are of interest: - int site_index = constantPoolCacheOopDesc::decode_secondary_index(raw_index); - int main_index = pool->cache()->entry_at(site_index)->main_entry_index(); - // and there is one CP entry, a NameAndType: - int nt_index = pool->map_instruction_operand_to_index(raw_index); + int site_index = four_byte_index(thread); + // there is a second CPC entries that is of interest; it caches signature info: + int main_index = pool->cache()->secondary_entry_at(site_index)->main_entry_index(); // first resolve the signature to a MH.invoke methodOop if (!pool->cache()->entry_at(main_index)->is_resolved(bytecode)) { JvmtiHideSingleStepping jhss(thread); CallInfo info; LinkResolver::resolve_invoke(info, Handle(), pool, - raw_index, bytecode, CHECK); + site_index, bytecode, CHECK); // The main entry corresponds to a JVM_CONSTANT_NameAndType, and serves // as a common reference point for all invokedynamic call sites with // that exact call descriptor. We will link it in the CP cache exactly @@ -741,7 +736,7 @@ assert(mh_invdyn.not_null() && mh_invdyn->is_method() && mh_invdyn->is_method_handle_invoke(), "correct result from LinkResolver::resolve_invokedynamic"); - symbolHandle call_site_name(THREAD, pool->nt_name_ref_at(nt_index)); + symbolHandle call_site_name(THREAD, pool->name_ref_at(site_index)); Handle call_site = SystemDictionary::make_dynamic_call_site(caller_method->method_holder(), caller_method->method_idnum(), @@ -753,61 +748,11 @@ // In the secondary entry, the f1 field is the call site, and the f2 (index) // field is some data about the invoke site. int extra_data = 0; - pool->cache()->entry_at(site_index)->set_dynamic_call(call_site(), extra_data); + pool->cache()->secondary_entry_at(site_index)->set_dynamic_call(call_site(), extra_data); } IRT_END -// Called on first time execution, and also whenever the CallSite.target is null. -// FIXME: Do more of this in Java code. -IRT_ENTRY(void, InterpreterRuntime::bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site)) { - methodHandle mh_invdyn(thread, (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site)); - Handle mh_type(thread, mh_invdyn->method_handle_type()); - objArrayHandle mh_ptypes(thread, java_dyn_MethodType::ptypes(mh_type())); - - // squish the arguments down to a single array - int nargs = mh_ptypes->length(); - objArrayHandle arg_array; - { - objArrayOop aaoop = oopFactory::new_objArray(SystemDictionary::object_klass(), nargs, CHECK); - arg_array = objArrayHandle(thread, aaoop); - } - frame fr = thread->last_frame(); - assert(fr.interpreter_frame_bcp() != NULL, "sanity"); - int tos_offset = 0; - for (int i = nargs; --i >= 0; ) { - intptr_t* slot_addr = fr.interpreter_frame_tos_at(tos_offset++); - oop ptype = mh_ptypes->obj_at(i); - oop arg = NULL; - if (!java_lang_Class::is_primitive(ptype)) { - arg = *(oop*) slot_addr; - } else { - BasicType bt = java_lang_Class::primitive_type(ptype); - assert(frame::interpreter_frame_expression_stack_direction() < 0, "else reconsider this code"); - jvalue value; - Interpreter::get_jvalue_in_slot(slot_addr, bt, &value); - tos_offset += type2size[bt]-1; - arg = java_lang_boxing_object::create(bt, &value, CHECK); - // FIXME: These boxing objects are not canonicalized under - // the Java autoboxing rules. They should be... - // The best approach would be to push the arglist creation into Java. - // The JVM should use a lower-level interface to communicate argument lists. - } - arg_array->obj_at_put(i, arg); - } - - // now find the bootstrap method - oop bootstrap_mh_oop = instanceKlass::cast(fr.interpreter_frame_method()->method_holder())->bootstrap_method(); - assert(bootstrap_mh_oop != NULL, "resolve_invokedynamic ensures a BSM"); - - // return the bootstrap method and argument array via vm_result/_2 - thread->set_vm_result(bootstrap_mh_oop); - thread->set_vm_result_2(arg_array()); -} -IRT_END - - - //------------------------------------------------------------------------------------------------------------------------ // Miscellaneous diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/interpreterRuntime.hpp --- a/src/share/vm/interpreter/interpreterRuntime.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/interpreterRuntime.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -91,7 +91,6 @@ // Calls static void resolve_invoke (JavaThread* thread, Bytecodes::Code bytecode); static void resolve_invokedynamic(JavaThread* thread); - static void bootstrap_invokedynamic(JavaThread* thread, oopDesc* call_site); // Breakpoints static void _breakpoint(JavaThread* thread, methodOopDesc* method, address bcp); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/linkResolver.cpp --- a/src/share/vm/interpreter/linkResolver.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/linkResolver.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1015,11 +1015,8 @@ // This guy is reached from InterpreterRuntime::resolve_invokedynamic. - assert(constantPoolCacheOopDesc::is_secondary_index(raw_index), "must be secondary index"); - int nt_index = pool->map_instruction_operand_to_index(raw_index); - // At this point, we only need the signature, and can ignore the name. - symbolHandle method_signature(THREAD, pool->nt_signature_ref_at(nt_index)); + symbolHandle method_signature(THREAD, pool->signature_ref_at(raw_index)); // raw_index works directly symbolHandle method_name = vmSymbolHandles::invoke_name(); KlassHandle resolved_klass = SystemDictionaryHandles::MethodHandle_klass(); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/rewriter.cpp --- a/src/share/vm/interpreter/rewriter.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/rewriter.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -48,16 +48,6 @@ } -int Rewriter::add_extra_cp_cache_entry(int main_entry) { - // Hack: We put it on the map as an encoded value. - // The only place that consumes this is ConstantPoolCacheEntry::set_initial_state - int encoded = constantPoolCacheOopDesc::encode_secondary_index(main_entry); - int plain_secondary_index = _cp_cache_map.append(encoded); - return constantPoolCacheOopDesc::encode_secondary_index(plain_secondary_index); -} - - - // Creates a constant pool cache given a CPC map // This creates the constant pool cache initially in a state // that is unsafe for concurrent GC processing but sets it to @@ -127,7 +117,7 @@ assert(p[-1] == Bytecodes::_invokedynamic, ""); int cp_index = Bytes::get_Java_u2(p); int cpc = maybe_add_cp_cache_entry(cp_index); // add lazily - int cpc2 = add_extra_cp_cache_entry(cpc); + int cpc2 = add_secondary_cp_cache_entry(cpc); // Replace the trailing four bytes with a CPC index for the dynamic // call site. Unlike other CPC entries, there is one per bytecode, @@ -137,7 +127,7 @@ // all these entries. That is the main reason invokedynamic // must have a five-byte instruction format. (Of course, other JVM // implementations can use the bytes for other purposes.) - Bytes::put_native_u4(p, cpc2); + Bytes::put_native_u4(p, constantPoolCacheOopDesc::encode_secondary_index(cpc2)); // Note: We use native_u4 format exclusively for 4-byte indexes. } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/rewriter.hpp --- a/src/share/vm/interpreter/rewriter.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/rewriter.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -43,13 +43,18 @@ bool has_cp_cache(int i) { return (uint)i < (uint)_cp_map.length() && _cp_map[i] >= 0; } int maybe_add_cp_cache_entry(int i) { return has_cp_cache(i) ? _cp_map[i] : add_cp_cache_entry(i); } int add_cp_cache_entry(int cp_index) { + assert((cp_index & _secondary_entry_tag) == 0, "bad tag"); assert(_cp_map[cp_index] == -1, "not twice on same cp_index"); int cache_index = _cp_cache_map.append(cp_index); _cp_map.at_put(cp_index, cache_index); assert(cp_entry_to_cp_cache(cp_index) == cache_index, ""); return cache_index; } - int add_extra_cp_cache_entry(int main_entry); + int add_secondary_cp_cache_entry(int main_cpc_entry) { + assert(main_cpc_entry < _cp_cache_map.length(), "must be earlier CP cache entry"); + int cache_index = _cp_cache_map.append(main_cpc_entry | _secondary_entry_tag); + return cache_index; + } // All the work goes in here: Rewriter(instanceKlassHandle klass, TRAPS); @@ -65,4 +70,8 @@ public: // Driver routine: static void rewrite(instanceKlassHandle klass, TRAPS); + + enum { + _secondary_entry_tag = nth_bit(30) + }; }; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/templateInterpreter.cpp --- a/src/share/vm/interpreter/templateInterpreter.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/templateInterpreter.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -178,14 +178,12 @@ #endif // !PRODUCT EntryPoint TemplateInterpreter::_return_entry[TemplateInterpreter::number_of_return_entries]; EntryPoint TemplateInterpreter::_earlyret_entry; -EntryPoint TemplateInterpreter::_return_unbox_entry; EntryPoint TemplateInterpreter::_deopt_entry [TemplateInterpreter::number_of_deopt_entries ]; EntryPoint TemplateInterpreter::_continuation_entry; EntryPoint TemplateInterpreter::_safept_entry; address TemplateInterpreter::_return_3_addrs_by_index[TemplateInterpreter::number_of_return_addrs]; address TemplateInterpreter::_return_5_addrs_by_index[TemplateInterpreter::number_of_return_addrs]; -address TemplateInterpreter::_return_5_unbox_addrs_by_index[TemplateInterpreter::number_of_return_addrs]; DispatchTable TemplateInterpreter::_active_table; DispatchTable TemplateInterpreter::_normal_table; @@ -253,22 +251,6 @@ } } - if (EnableInvokeDynamic) { - CodeletMark cm(_masm, "unboxing return entry points"); - Interpreter::_return_unbox_entry = - EntryPoint( - generate_return_unbox_entry_for(btos, 5), - generate_return_unbox_entry_for(ctos, 5), - generate_return_unbox_entry_for(stos, 5), - generate_return_unbox_entry_for(atos, 5), // cast conversion - generate_return_unbox_entry_for(itos, 5), - generate_return_unbox_entry_for(ltos, 5), - generate_return_unbox_entry_for(ftos, 5), - generate_return_unbox_entry_for(dtos, 5), - Interpreter::_return_entry[5].entry(vtos) // no unboxing for void - ); - } - { CodeletMark cm(_masm, "earlyret entry points"); Interpreter::_earlyret_entry = EntryPoint( @@ -319,8 +301,6 @@ int index = Interpreter::TosState_as_index(states[j]); Interpreter::_return_3_addrs_by_index[index] = Interpreter::return_entry(states[j], 3); Interpreter::_return_5_addrs_by_index[index] = Interpreter::return_entry(states[j], 5); - if (EnableInvokeDynamic) - Interpreter::_return_5_unbox_addrs_by_index[index] = Interpreter::return_unbox_entry(states[j], 5); } { CodeletMark cm(_masm, "continuation entry points"); @@ -485,9 +465,11 @@ void TemplateInterpreterGenerator::set_short_entry_points(Template* t, address& bep, address& cep, address& sep, address& aep, address& iep, address& lep, address& fep, address& dep, address& vep) { assert(t->is_valid(), "template must exist"); switch (t->tos_in()) { - case btos: vep = __ pc(); __ pop(btos); bep = __ pc(); generate_and_dispatch(t); break; - case ctos: vep = __ pc(); __ pop(ctos); sep = __ pc(); generate_and_dispatch(t); break; - case stos: vep = __ pc(); __ pop(stos); sep = __ pc(); generate_and_dispatch(t); break; + case btos: + case ctos: + case stos: + ShouldNotReachHere(); // btos/ctos/stos should use itos. + break; case atos: vep = __ pc(); __ pop(atos); aep = __ pc(); generate_and_dispatch(t); break; case itos: vep = __ pc(); __ pop(itos); iep = __ pc(); generate_and_dispatch(t); break; case ltos: vep = __ pc(); __ pop(ltos); lep = __ pc(); generate_and_dispatch(t); break; @@ -547,18 +529,6 @@ } -address TemplateInterpreter::return_unbox_entry(TosState state, int length) { - assert(EnableInvokeDynamic, ""); - if (state == vtos) { - // no unboxing to do, actually - return return_entry(state, length); - } else { - assert(length == 5, "unboxing entries generated for invokedynamic only"); - return _return_unbox_entry.entry(state); - } -} - - address TemplateInterpreter::deopt_entry(TosState state, int length) { guarantee(0 <= length && length < Interpreter::number_of_deopt_entries, "illegal length"); return _deopt_entry[length].entry(state); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/templateInterpreter.hpp --- a/src/share/vm/interpreter/templateInterpreter.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/templateInterpreter.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -110,14 +110,12 @@ #endif // !PRODUCT static EntryPoint _return_entry[number_of_return_entries]; // entry points to return to from a call static EntryPoint _earlyret_entry; // entry point to return early from a call - static EntryPoint _return_unbox_entry; // entry point to unbox a return value from a call static EntryPoint _deopt_entry[number_of_deopt_entries]; // entry points to return to from a deoptimization static EntryPoint _continuation_entry; static EntryPoint _safept_entry; static address _return_3_addrs_by_index[number_of_return_addrs]; // for invokevirtual return entries static address _return_5_addrs_by_index[number_of_return_addrs]; // for invokeinterface return entries - static address _return_5_unbox_addrs_by_index[number_of_return_addrs]; // for invokedynamic bootstrap methods static DispatchTable _active_table; // the active dispatch table (used by the interpreter for dispatch) static DispatchTable _normal_table; // the normal dispatch table (used to set the active table in normal mode) @@ -159,12 +157,10 @@ // Support for invokes static address* return_3_addrs_by_index_table() { return _return_3_addrs_by_index; } static address* return_5_addrs_by_index_table() { return _return_5_addrs_by_index; } - static address* return_5_unbox_addrs_by_index_table() { return _return_5_unbox_addrs_by_index; } static int TosState_as_index(TosState state); // computes index into return_3_entry_by_index table static address return_entry (TosState state, int length); static address deopt_entry (TosState state, int length); - static address return_unbox_entry(TosState state, int length); // Safepoint support static void notice_safepoints(); // stops the thread when reaching a safepoint diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/interpreter/templateInterpreterGenerator.hpp --- a/src/share/vm/interpreter/templateInterpreterGenerator.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/interpreter/templateInterpreterGenerator.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -51,10 +51,7 @@ address generate_WrongMethodType_handler(); address generate_ArrayIndexOutOfBounds_handler(const char* name); address generate_continuation_for(TosState state); - address generate_return_entry_for(TosState state, int step, bool unbox = false); - address generate_return_unbox_entry_for(TosState state, int step) { - return generate_return_entry_for(state, step, true); - } + address generate_return_entry_for(TosState state, int step); address generate_earlyret_entry_for(TosState state); address generate_deopt_entry_for(TosState state, int step); address generate_safept_entry_for(TosState state, address runtime_entry); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/barrierSet.cpp --- a/src/share/vm/memory/barrierSet.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/barrierSet.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -41,11 +41,6 @@ // count is number of array elements being written void BarrierSet::static_write_ref_array_post(HeapWord* start, size_t count) { - assert(count <= (size_t)max_intx, "count too large"); - HeapWord* end = start + objArrayOopDesc::array_size((int)count); -#if 0 - warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT","INTPTR_FORMAT")\t", - start, count, start, end); -#endif - Universe::heap()->barrier_set()->write_ref_array_work(MemRegion(start, end)); + // simply delegate to instance method + Universe::heap()->barrier_set()->write_ref_array(start, count); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/barrierSet.hpp --- a/src/share/vm/memory/barrierSet.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/barrierSet.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -121,17 +121,20 @@ virtual void read_ref_array(MemRegion mr) = 0; virtual void read_prim_array(MemRegion mr) = 0; + // Below length is the # array elements being written virtual void write_ref_array_pre( oop* dst, int length) {} virtual void write_ref_array_pre(narrowOop* dst, int length) {} + // Below MemRegion mr is expected to be HeapWord-aligned inline void write_ref_array(MemRegion mr); + // Below count is the # array elements being written, starting + // at the address "start", which may not necessarily be HeapWord-aligned + inline void write_ref_array(HeapWord* start, size_t count); - // Static versions, suitable for calling from generated code. + // Static versions, suitable for calling from generated code; + // count is # array elements being written, starting with "start", + // which may not necessarily be HeapWord-aligned. static void static_write_ref_array_pre(HeapWord* start, size_t count); static void static_write_ref_array_post(HeapWord* start, size_t count); - // Narrow oop versions of the above; count is # of array elements being written, - // starting with "start", which is HeapWord-aligned. - static void static_write_ref_array_pre_narrow(HeapWord* start, size_t count); - static void static_write_ref_array_post_narrow(HeapWord* start, size_t count); protected: virtual void write_ref_array_work(MemRegion mr) = 0; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/barrierSet.inline.hpp --- a/src/share/vm/memory/barrierSet.inline.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/barrierSet.inline.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -43,6 +43,8 @@ } void BarrierSet::write_ref_array(MemRegion mr) { + assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start() , "Unaligned start"); + assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); if (kind() == CardTableModRef) { ((CardTableModRefBS*)this)->inline_write_ref_array(mr); } else { @@ -50,6 +52,34 @@ } } +// count is number of array elements being written +void BarrierSet::write_ref_array(HeapWord* start, size_t count) { + assert(count <= (size_t)max_intx, "count too large"); + HeapWord* end = (HeapWord*)((char*)start + (count*heapOopSize)); + // In the case of compressed oops, start and end may potentially be misaligned; + // so we need to conservatively align the first downward (this is not + // strictly necessary for current uses, but a case of good hygiene and, + // if you will, aesthetics) and the second upward (this is essential for + // current uses) to a HeapWord boundary, so we mark all cards overlapping + // this write. In the event that this evolves in the future to calling a + // logging barrier of narrow oop granularity, like the pre-barrier for G1 + // (mentioned here merely by way of example), we will need to change this + // interface, much like the pre-barrier one above, so it is "exactly precise" + // (if i may be allowed the adverbial redundancy for emphasis) and does not + // include narrow oop slots not included in the original write interval. + HeapWord* aligned_start = (HeapWord*)align_size_down((uintptr_t)start, HeapWordSize); + HeapWord* aligned_end = (HeapWord*)align_size_up ((uintptr_t)end, HeapWordSize); + // If compressed oops were not being used, these should already be aligned + assert(UseCompressedOops || (aligned_start == start && aligned_end == end), + "Expected heap word alignment of start and end"); +#if 0 + warning("Post:\t" INTPTR_FORMAT "[" SIZE_FORMAT "] : [" INTPTR_FORMAT","INTPTR_FORMAT")\t", + start, count, aligned_start, aligned_end); +#endif + write_ref_array_work(MemRegion(aligned_start, aligned_end)); +} + + void BarrierSet::write_region(MemRegion mr) { if (kind() == CardTableModRef) { ((CardTableModRefBS*)this)->inline_write_region(mr); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/cardTableModRefBS.cpp --- a/src/share/vm/memory/cardTableModRefBS.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/cardTableModRefBS.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -511,6 +511,8 @@ } void CardTableModRefBS::dirty_MemRegion(MemRegion mr) { + assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start"); + assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); jbyte* cur = byte_for(mr.start()); jbyte* last = byte_after(mr.last()); while (cur < last) { @@ -520,6 +522,8 @@ } void CardTableModRefBS::invalidate(MemRegion mr, bool whole_heap) { + assert((HeapWord*)align_size_down((uintptr_t)mr.start(), HeapWordSize) == mr.start(), "Unaligned start"); + assert((HeapWord*)align_size_up ((uintptr_t)mr.end(), HeapWordSize) == mr.end(), "Unaligned end" ); for (int i = 0; i < _cur_covered_regions; i++) { MemRegion mri = mr.intersection(_covered[i]); if (!mri.is_empty()) dirty_MemRegion(mri); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/collectorPolicy.cpp --- a/src/share/vm/memory/collectorPolicy.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/collectorPolicy.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -55,7 +55,7 @@ void CollectorPolicy::initialize_size_info() { // User inputs from -mx and ms are aligned - set_initial_heap_byte_size(Arguments::initial_heap_size()); + set_initial_heap_byte_size(InitialHeapSize); if (initial_heap_byte_size() == 0) { set_initial_heap_byte_size(NewSize + OldSize); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/sharedHeap.hpp --- a/src/share/vm/memory/sharedHeap.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/sharedHeap.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -224,10 +224,6 @@ CodeBlobClosure* code_roots, OopClosure* non_root_closure); - - // Like CollectedHeap::collect, but assume that the caller holds the Heap_lock. - virtual void collect_locked(GCCause::Cause cause) = 0; - // The functions below are helper functions that a subclass of // "SharedHeap" can use in the implementation of its virtual // functions. diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/universe.cpp --- a/src/share/vm/memory/universe.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/universe.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -67,6 +67,8 @@ objArrayOop Universe::_the_empty_system_obj_array = NULL; objArrayOop Universe::_the_empty_class_klass_array = NULL; objArrayOop Universe::_the_array_interfaces_array = NULL; +oop Universe::_the_null_string = NULL; +oop Universe::_the_min_jint_string = NULL; LatestMethodOopCache* Universe::_finalizer_register_cache = NULL; LatestMethodOopCache* Universe::_loader_addClass_cache = NULL; ActiveMethodOopsCache* Universe::_reflect_invoke_cache = NULL; @@ -187,6 +189,8 @@ f->do_oop((oop*)&_the_empty_system_obj_array); f->do_oop((oop*)&_the_empty_class_klass_array); f->do_oop((oop*)&_the_array_interfaces_array); + f->do_oop((oop*)&_the_null_string); + f->do_oop((oop*)&_the_min_jint_string); _finalizer_register_cache->oops_do(f); _loader_addClass_cache->oops_do(f); _reflect_invoke_cache->oops_do(f); @@ -289,6 +293,9 @@ klassOop ok = SystemDictionary::object_klass(); + _the_null_string = StringTable::intern("null", CHECK); + _the_min_jint_string = StringTable::intern("-2147483648", CHECK); + if (UseSharedSpaces) { // Verify shared interfaces array. assert(_the_array_interfaces_array->obj_at(0) == @@ -744,22 +751,22 @@ static const uint64_t OopEncodingHeapMax = NarrowOopHeapMax << LogMinObjAlignmentInBytes; char* Universe::preferred_heap_base(size_t heap_size, NARROW_OOP_MODE mode) { + size_t base = 0; #ifdef _LP64 if (UseCompressedOops) { assert(mode == UnscaledNarrowOop || mode == ZeroBasedNarrowOop || mode == HeapBasedNarrowOop, "mode is invalid"); + const size_t total_size = heap_size + HeapBaseMinAddress; // Return specified base for the first request. if (!FLAG_IS_DEFAULT(HeapBaseMinAddress) && (mode == UnscaledNarrowOop)) { - return (char*)HeapBaseMinAddress; - } - const size_t total_size = heap_size + HeapBaseMinAddress; - if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) { + base = HeapBaseMinAddress; + } else if (total_size <= OopEncodingHeapMax && (mode != HeapBasedNarrowOop)) { if (total_size <= NarrowOopHeapMax && (mode == UnscaledNarrowOop) && (Universe::narrow_oop_shift() == 0)) { // Use 32-bits oops without encoding and // place heap's top on the 4Gb boundary - return (char*)(NarrowOopHeapMax - heap_size); + base = (NarrowOopHeapMax - heap_size); } else { // Can't reserve with NarrowOopShift == 0 Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); @@ -768,16 +775,38 @@ // Use zero based compressed oops with encoding and // place heap's top on the 32Gb boundary in case // total_size > 4Gb or failed to reserve below 4Gb. - return (char*)(OopEncodingHeapMax - heap_size); + base = (OopEncodingHeapMax - heap_size); } } } else { // Can't reserve below 32Gb. Universe::set_narrow_oop_shift(LogMinObjAlignmentInBytes); } + // Set narrow_oop_base and narrow_oop_use_implicit_null_checks + // used in ReservedHeapSpace() constructors. + // The final values will be set in initialize_heap() below. + if (base != 0 && (base + heap_size) <= OopEncodingHeapMax) { + // Use zero based compressed oops + Universe::set_narrow_oop_base(NULL); + // Don't need guard page for implicit checks in indexed + // addressing mode with zero based Compressed Oops. + Universe::set_narrow_oop_use_implicit_null_checks(true); + } else { + // Set to a non-NULL value so the ReservedSpace ctor computes + // the correct no-access prefix. + // The final value will be set in initialize_heap() below. + Universe::set_narrow_oop_base((address)NarrowOopHeapMax); +#ifdef _WIN64 + if (UseLargePages) { + // Cannot allocate guard pages for implicit checks in indexed + // addressing mode when large pages are specified on windows. + Universe::set_narrow_oop_use_implicit_null_checks(false); + } +#endif // _WIN64 + } } #endif - return NULL; // also return NULL (don't care) for 32-bit VM + return (char*)base; // also return NULL (don't care) for 32-bit VM } jint Universe::initialize_heap() { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/memory/universe.hpp --- a/src/share/vm/memory/universe.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/memory/universe.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -169,6 +169,8 @@ static objArrayOop _the_empty_system_obj_array; // Canonicalized system obj array static objArrayOop _the_empty_class_klass_array; // Canonicalized obj array of type java.lang.Class static objArrayOop _the_array_interfaces_array; // Canonicalized 2-array of cloneable & serializable klasses + static oop _the_null_string; // A cache of "null" as a Java string + static oop _the_min_jint_string; // A cache of "-2147483648" as a Java string static LatestMethodOopCache* _finalizer_register_cache; // static method for registering finalizable objects static LatestMethodOopCache* _loader_addClass_cache; // method for registering loaded classes in class loader vector static ActiveMethodOopsCache* _reflect_invoke_cache; // method for security checks @@ -310,6 +312,8 @@ static objArrayOop the_empty_system_obj_array () { return _the_empty_system_obj_array; } static objArrayOop the_empty_class_klass_array () { return _the_empty_class_klass_array; } static objArrayOop the_array_interfaces_array() { return _the_array_interfaces_array; } + static oop the_null_string() { return _the_null_string; } + static oop the_min_jint_string() { return _the_min_jint_string; } static methodOop finalizer_register_method() { return _finalizer_register_cache->get_methodOop(); } static methodOop loader_addClass_method() { return _loader_addClass_cache->get_methodOop(); } static ActiveMethodOopsCache* reflect_invoke_cache() { return _reflect_invoke_cache; } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/constantPoolOop.cpp --- a/src/share/vm/oops/constantPoolOop.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/constantPoolOop.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -262,25 +262,48 @@ int constantPoolOopDesc::impl_name_and_type_ref_index_at(int which, bool uncached) { - jint ref_index = field_or_method_at(which, uncached); + int i = which; + if (!uncached && cache() != NULL) { + if (constantPoolCacheOopDesc::is_secondary_index(which)) + // Invokedynamic indexes are always processed in native order + // so there is no question of reading a native u2 in Java order here. + return cache()->main_entry_at(which)->constant_pool_index(); + // change byte-ordering and go via cache + i = remap_instruction_operand_from_cache(which); + } else { + if (tag_at(which).is_name_and_type()) + // invokedynamic index is a simple name-and-type + return which; + } + assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); + jint ref_index = *int_at_addr(i); return extract_high_short_from_int(ref_index); } int constantPoolOopDesc::impl_klass_ref_index_at(int which, bool uncached) { - jint ref_index = field_or_method_at(which, uncached); + guarantee(!constantPoolCacheOopDesc::is_secondary_index(which), + "an invokedynamic instruction does not have a klass"); + int i = which; + if (!uncached && cache() != NULL) { + // change byte-ordering and go via cache + i = remap_instruction_operand_from_cache(which); + } + assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); + jint ref_index = *int_at_addr(i); return extract_low_short_from_int(ref_index); } -int constantPoolOopDesc::map_instruction_operand_to_index(int operand) { - if (constantPoolCacheOopDesc::is_secondary_index(operand)) { - return cache()->main_entry_at(operand)->constant_pool_index(); - } +int constantPoolOopDesc::remap_instruction_operand_from_cache(int operand) { + // Operand was fetched by a stream using get_Java_u2, yet was stored + // by Rewriter::rewrite_member_reference in native order. + // So now we have to fix the damage by swapping back to native order. assert((int)(u2)operand == operand, "clean u2"); - int index = Bytes::swap_u2(operand); - return cache()->entry_at(index)->constant_pool_index(); + int cpc_index = Bytes::swap_u2(operand); + int member_index = cache()->entry_at(cpc_index)->constant_pool_index(); + return member_index; } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/constantPoolOop.hpp --- a/src/share/vm/oops/constantPoolOop.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/constantPoolOop.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -342,12 +342,14 @@ } // The following methods (name/signature/klass_ref_at, klass_ref_at_noresolve, - // name_and_type_ref_index_at) all expect constant pool indices - // from the bytecodes to be passed in, which are actually potentially byte-swapped - // or rewritten constant pool cache indices. They all call map_instruction_operand_to_index. - int map_instruction_operand_to_index(int operand); + // name_and_type_ref_index_at) all expect to be passed indices obtained + // directly from the bytecode, and extracted according to java byte order. + // If the indices are meant to refer to fields or methods, they are + // actually potentially byte-swapped, rewritten constant pool cache indices. + // The routine remap_instruction_operand_from_cache manages the adjustment + // of these values back to constant pool indices. - // There are also "uncached" versions which do not map the operand index; see below. + // There are also "uncached" versions which do not adjust the operand index; see below. // Lookup for entries consisting of (klass_index, name_and_type index) klassOop klass_ref_at(int which, TRAPS); @@ -361,8 +363,6 @@ // Lookup for entries consisting of (name_index, signature_index) int name_ref_index_at(int which_nt); // == low-order jshort of name_and_type_at(which_nt) int signature_ref_index_at(int which_nt); // == high-order jshort of name_and_type_at(which_nt) - symbolOop nt_name_ref_at(int which_nt) { return symbol_at(name_ref_index_at(which_nt)); } - symbolOop nt_signature_ref_at(int which_nt) { return symbol_at(signature_ref_index_at(which_nt)); } BasicType basic_type_for_signature_at(int which); @@ -425,18 +425,7 @@ int impl_klass_ref_index_at(int which, bool uncached); int impl_name_and_type_ref_index_at(int which, bool uncached); - // Takes either a constant pool cache index in possibly byte-swapped - // byte order (which comes from the bytecodes after rewriting) or, - // if "uncached" is true, a vanilla constant pool index - jint field_or_method_at(int which, bool uncached) { - int i = which; - if (!uncached && cache() != NULL) { - // change byte-ordering and go via cache - i = map_instruction_operand_to_index(which); - } - assert(tag_at(i).is_field_or_method(), "Corrupted constant pool"); - return *int_at_addr(i); - } + int remap_instruction_operand_from_cache(int operand); // Used while constructing constant pool (only by ClassFileParser) jint klass_index_at(int which) { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/cpCacheOop.cpp --- a/src/share/vm/oops/cpCacheOop.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/cpCacheOop.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -28,21 +28,17 @@ // Implememtation of ConstantPoolCacheEntry -void ConstantPoolCacheEntry::set_initial_state(int index) { - if (constantPoolCacheOopDesc::is_secondary_index(index)) { - // Hack: The rewriter is trying to say that this entry itself - // will be a secondary entry. - int main_index = constantPoolCacheOopDesc::decode_secondary_index(index); - assert(0 <= main_index && main_index < 0x10000, "sanity check"); - _indices = (main_index << 16); - assert(main_entry_index() == main_index, ""); - return; - } +void ConstantPoolCacheEntry::initialize_entry(int index) { assert(0 < index && index < 0x10000, "sanity check"); _indices = index; assert(constant_pool_index() == index, ""); } +void ConstantPoolCacheEntry::initialize_secondary_entry(int main_index) { + assert(0 <= main_index && main_index < 0x10000, "sanity check"); + _indices = (main_index << 16); + assert(main_entry_index() == main_index, ""); +} int ConstantPoolCacheEntry::as_flags(TosState state, bool is_final, bool is_vfinal, bool is_volatile, @@ -223,10 +219,10 @@ void ConstantPoolCacheEntry::set_dynamic_call(Handle call_site, int extra_data) { - methodOop method = (methodOop) sun_dyn_CallSiteImpl::vmmethod(call_site()); + methodOop method = (methodOop) java_dyn_CallSite::vmmethod(call_site()); assert(method->is_method(), "must be initialized properly"); int param_size = method->size_of_parameters(); - assert(param_size > 1, "method argument size must include MH.this & initial dynamic receiver"); + assert(param_size >= 1, "method argument size must include MH.this"); param_size -= 1; // do not count MH.this; it is not stacked for invokedynamic if (Atomic::cmpxchg_ptr(call_site(), &_f1, NULL) == NULL) { // racing threads might be trying to install their own favorites @@ -439,7 +435,18 @@ void constantPoolCacheOopDesc::initialize(intArray& inverse_index_map) { assert(inverse_index_map.length() == length(), "inverse index map must have same length as cache"); - for (int i = 0; i < length(); i++) entry_at(i)->set_initial_state(inverse_index_map[i]); + for (int i = 0; i < length(); i++) { + ConstantPoolCacheEntry* e = entry_at(i); + int original_index = inverse_index_map[i]; + if ((original_index & Rewriter::_secondary_entry_tag) != 0) { + int main_index = (original_index - Rewriter::_secondary_entry_tag); + assert(!entry_at(main_index)->is_secondary_entry(), "valid main index"); + e->initialize_secondary_entry(main_index); + } else { + e->initialize_entry(original_index); + } + assert(entry_at(i) == e, "sanity"); + } } // RedefineClasses() API support: diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/cpCacheOop.hpp --- a/src/share/vm/oops/cpCacheOop.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/cpCacheOop.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -154,7 +154,8 @@ }; // Initialization - void set_initial_state(int index); // sets entry to initial state + void initialize_entry(int original_index); // initialize primary entry + void initialize_secondary_entry(int main_index); // initialize secondary entry void set_field( // sets entry to resolved field state Bytecodes::Code get_code, // the bytecode used for reading the field @@ -251,6 +252,7 @@ // Code generation support static WordSize size() { return in_WordSize(sizeof(ConstantPoolCacheEntry) / HeapWordSize); } + static ByteSize size_in_bytes() { return in_ByteSize(sizeof(ConstantPoolCacheEntry)); } static ByteSize indices_offset() { return byte_offset_of(ConstantPoolCacheEntry, _indices); } static ByteSize f1_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f1); } static ByteSize f2_offset() { return byte_offset_of(ConstantPoolCacheEntry, _f2); } @@ -321,6 +323,7 @@ ConstantPoolCacheEntry* base() const { return (ConstantPoolCacheEntry*)((address)this + in_bytes(base_offset())); } friend class constantPoolCacheKlass; + friend class ConstantPoolCacheEntry; public: // Initialization @@ -329,7 +332,8 @@ // Secondary indexes. // They must look completely different from normal indexes. // The main reason is that byte swapping is sometimes done on normal indexes. - // Also, it is helpful for debugging to tell the two apart. + // Also, some of the CP accessors do different things for secondary indexes. + // Finally, it is helpful for debugging to tell the two apart. static bool is_secondary_index(int i) { return (i < 0); } static int decode_secondary_index(int i) { assert(is_secondary_index(i), ""); return ~i; } static int encode_secondary_index(int i) { assert(!is_secondary_index(i), ""); return ~i; } @@ -337,18 +341,35 @@ // Accessors void set_constant_pool(constantPoolOop pool) { oop_store_without_check((oop*)&_constant_pool, (oop)pool); } constantPoolOop constant_pool() const { return _constant_pool; } - ConstantPoolCacheEntry* entry_at(int i) const { assert(0 <= i && i < length(), "index out of bounds"); return base() + i; } + // Fetches the entry at the given index. + // The entry may be either primary or secondary. + // In either case the index must not be encoded or byte-swapped in any way. + ConstantPoolCacheEntry* entry_at(int i) const { + assert(0 <= i && i < length(), "index out of bounds"); + return base() + i; + } + // Fetches the secondary entry referred to by index. + // The index may be a secondary index, and must not be byte-swapped. + ConstantPoolCacheEntry* secondary_entry_at(int i) const { + int raw_index = i; + if (is_secondary_index(i)) { // correct these on the fly + raw_index = decode_secondary_index(i); + } + assert(entry_at(raw_index)->is_secondary_entry(), "not a secondary entry"); + return entry_at(raw_index); + } + // Given a primary or secondary index, fetch the corresponding primary entry. + // Indirect through the secondary entry, if the index is encoded as a secondary index. + // The index must not be byte-swapped. ConstantPoolCacheEntry* main_entry_at(int i) const { - ConstantPoolCacheEntry* e; + int primary_index = i; if (is_secondary_index(i)) { // run through an extra level of indirection: - i = decode_secondary_index(i); - e = entry_at(i); - i = e->main_entry_index(); + int raw_index = decode_secondary_index(i); + primary_index = entry_at(raw_index)->main_entry_index(); } - e = entry_at(i); - assert(!e->is_secondary_entry(), "only one level of indirection"); - return e; + assert(!entry_at(primary_index)->is_secondary_entry(), "only one level of indirection"); + return entry_at(primary_index); } // GC support @@ -359,6 +380,12 @@ // Code generation static ByteSize base_offset() { return in_ByteSize(sizeof(constantPoolCacheOopDesc)); } + static ByteSize entry_offset(int raw_index) { + int index = raw_index; + if (is_secondary_index(raw_index)) + index = decode_secondary_index(raw_index); + return (base_offset() + ConstantPoolCacheEntry::size_in_bytes() * index); + } // RedefineClasses() API support: // If any entry of this constantPoolCache points to any of diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/generateOopMap.cpp --- a/src/share/vm/oops/generateOopMap.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/generateOopMap.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1556,13 +1556,13 @@ case Bytecodes::_getfield: do_field(true, false, itr->get_index_big(), itr->bci()); break; case Bytecodes::_putfield: do_field(false, false, itr->get_index_big(), itr->bci()); break; - case Bytecodes::_invokevirtual: - case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break; - case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break; - case Bytecodes::_invokedynamic: do_method(false, true, itr->get_index_int(), itr->bci()); break; - case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break; - case Bytecodes::_newarray: - case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break; + case Bytecodes::_invokevirtual: + case Bytecodes::_invokespecial: do_method(false, false, itr->get_index_big(), itr->bci()); break; + case Bytecodes::_invokestatic: do_method(true, false, itr->get_index_big(), itr->bci()); break; + case Bytecodes::_invokedynamic: do_method(true, false, itr->get_index_int(), itr->bci()); break; + case Bytecodes::_invokeinterface: do_method(false, true, itr->get_index_big(), itr->bci()); break; + case Bytecodes::_newarray: + case Bytecodes::_anewarray: pp_new_ref(vCTS, itr->bci()); break; case Bytecodes::_checkcast: do_checkcast(); break; case Bytecodes::_arraylength: case Bytecodes::_instanceof: pp(rCTS, vCTS); break; @@ -1900,11 +1900,9 @@ } void GenerateOopMap::do_method(int is_static, int is_interface, int idx, int bci) { - // Dig up signature for field in constant pool - constantPoolOop cp = _method->constants(); - int nameAndTypeIdx = cp->name_and_type_ref_index_at(idx); - int signatureIdx = cp->signature_ref_index_at(nameAndTypeIdx); // @@@@@ - symbolOop signature = cp->symbol_at(signatureIdx); + // Dig up signature for field in constant pool + constantPoolOop cp = _method->constants(); + symbolOop signature = cp->signature_ref_at(idx); // Parse method signature CellTypeState out[4]; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/instanceKlassKlass.cpp --- a/src/share/vm/oops/instanceKlassKlass.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/instanceKlassKlass.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -317,6 +317,11 @@ pm->claim_or_forward_breadth(sg_addr); } + oop* bsm_addr = ik->adr_bootstrap_method(); + if (PSScavenge::should_scavenge(bsm_addr)) { + pm->claim_or_forward_breadth(bsm_addr); + } + klassKlass::oop_copy_contents(pm, obj); } @@ -345,6 +350,11 @@ pm->claim_or_forward_depth(sg_addr); } + oop* bsm_addr = ik->adr_bootstrap_method(); + if (PSScavenge::should_scavenge(bsm_addr)) { + pm->claim_or_forward_depth(bsm_addr); + } + klassKlass::oop_copy_contents(pm, obj); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/objArrayKlass.cpp --- a/src/share/vm/oops/objArrayKlass.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/objArrayKlass.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -127,16 +127,14 @@ // pointer delta is scaled to number of elements (length field in // objArrayOop) which we assume is 32 bit. assert(pd == (size_t)(int)pd, "length field overflow"); - const size_t done_word_len = objArrayOopDesc::array_size((int)pd); - bs->write_ref_array(MemRegion((HeapWord*)dst, done_word_len)); + bs->write_ref_array((HeapWord*)dst, pd); THROW(vmSymbols::java_lang_ArrayStoreException()); return; } } } } - const size_t word_len = objArrayOopDesc::array_size(length); - bs->write_ref_array(MemRegion((HeapWord*)dst, word_len)); + bs->write_ref_array((HeapWord*)dst, length); } void objArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/oops/objArrayOop.hpp --- a/src/share/vm/oops/objArrayOop.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/oops/objArrayOop.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -37,6 +37,32 @@ return &((T*)base())[index]; } +private: + // Give size of objArrayOop in HeapWords minus the header + static int array_size(int length) { + const int OopsPerHeapWord = HeapWordSize/heapOopSize; + assert(OopsPerHeapWord >= 1 && (HeapWordSize % heapOopSize == 0), + "Else the following (new) computation would be in error"); +#ifdef ASSERT + // The old code is left in for sanity-checking; it'll + // go away pretty soon. XXX + // Without UseCompressedOops, this is simply: + // oop->length() * HeapWordsPerOop; + // With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer. + // The oop elements are aligned up to wordSize + const int HeapWordsPerOop = heapOopSize/HeapWordSize; + int old_res; + if (HeapWordsPerOop > 0) { + old_res = length * HeapWordsPerOop; + } else { + old_res = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord; + } +#endif // ASSERT + int res = ((uint)length + OopsPerHeapWord - 1)/OopsPerHeapWord; + assert(res == old_res, "Inconsistency between old and new."); + return res; + } + public: // Returns the offset of the first element. static int base_offset_in_bytes() { @@ -67,27 +93,14 @@ // Sizing static int header_size() { return arrayOopDesc::header_size(T_OBJECT); } int object_size() { return object_size(length()); } - int array_size() { return array_size(length()); } static int object_size(int length) { // This returns the object size in HeapWords. - return align_object_size(header_size() + array_size(length)); - } - - // Give size of objArrayOop in HeapWords minus the header - static int array_size(int length) { - // Without UseCompressedOops, this is simply: - // oop->length() * HeapWordsPerOop; - // With narrowOops, HeapWordsPerOop is 1/2 or equal 0 as an integer. - // The oop elements are aligned up to wordSize - const int HeapWordsPerOop = heapOopSize/HeapWordSize; - if (HeapWordsPerOop > 0) { - return length * HeapWordsPerOop; - } else { - const int OopsPerHeapWord = HeapWordSize/heapOopSize; - int word_len = align_size_up(length, OopsPerHeapWord)/OopsPerHeapWord; - return word_len; - } + uint asz = array_size(length); + uint osz = align_object_size(header_size() + asz); + assert(osz >= asz, "no overflow"); + assert((int)osz > 0, "no overflow"); + return (int)osz; } // special iterators for index ranges, returns size of object diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/c2_globals.cpp --- a/src/share/vm/opto/c2_globals.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/c2_globals.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -25,4 +25,4 @@ # include "incls/_precompiled.incl" # include "incls/_c2_globals.cpp.incl" -C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) +C2_FLAGS(MATERIALIZE_DEVELOPER_FLAG, MATERIALIZE_PD_DEVELOPER_FLAG, MATERIALIZE_PRODUCT_FLAG, MATERIALIZE_PD_PRODUCT_FLAG, MATERIALIZE_DIAGNOSTIC_FLAG, MATERIALIZE_EXPERIMENTAL_FLAG, MATERIALIZE_NOTPRODUCT_FLAG) diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/c2_globals.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -26,7 +26,7 @@ // Defines all globals flags used by the server compiler. // -#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, notproduct) \ +#define C2_FLAGS(develop, develop_pd, product, product_pd, diagnostic, experimental, notproduct) \ \ notproduct(intx, CompileZapFirst, 0, \ "If +ZapDeadCompiledLocals, " \ @@ -394,6 +394,12 @@ product(bool, UseOptoBiasInlining, true, \ "Generate biased locking code in C2 ideal graph") \ \ + product(bool, OptimizeStringConcat, false, \ + "Optimize the construction of Strings by StringBuilder") \ + \ + notproduct(bool, PrintOptimizeStringConcat, false, \ + "Print information about transformations performed on Strings") \ + \ product(intx, ValueSearchLimit, 1000, \ "Recursion limit in PhaseMacroExpand::value_from_mem_phi") \ \ @@ -413,4 +419,4 @@ product(bool, BlockLayoutRotateLoops, true, \ "Allow back branches to be fall throughs in the block layour") \ -C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_NOTPRODUCT_FLAG) +C2_FLAGS(DECLARE_DEVELOPER_FLAG, DECLARE_PD_DEVELOPER_FLAG, DECLARE_PRODUCT_FLAG, DECLARE_PD_PRODUCT_FLAG, DECLARE_DIAGNOSTIC_FLAG, DECLARE_EXPERIMENTAL_FLAG, DECLARE_NOTPRODUCT_FLAG) diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/callGenerator.cpp --- a/src/share/vm/opto/callGenerator.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/callGenerator.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -98,12 +98,21 @@ //---------------------------DirectCallGenerator------------------------------ // Internal class which handles all out-of-line calls w/o receiver type checks. class DirectCallGenerator : public CallGenerator { -public: - DirectCallGenerator(ciMethod* method) - : CallGenerator(method) + private: + CallStaticJavaNode* _call_node; + // Force separate memory and I/O projections for the exceptional + // paths to facilitate late inlinig. + bool _separate_io_proj; + + public: + DirectCallGenerator(ciMethod* method, bool separate_io_proj) + : CallGenerator(method), + _separate_io_proj(separate_io_proj) { } virtual JVMState* generate(JVMState* jvms); + + CallStaticJavaNode* call_node() const { return _call_node; } }; JVMState* DirectCallGenerator::generate(JVMState* jvms) { @@ -129,9 +138,10 @@ call->set_optimized_virtual(true); } kit.set_arguments_for_java_call(call); - kit.set_edges_for_java_call(call); - Node* ret = kit.set_results_for_java_call(call); + kit.set_edges_for_java_call(call, false, _separate_io_proj); + Node* ret = kit.set_results_for_java_call(call, _separate_io_proj); kit.push_node(method()->return_type()->basic_type(), ret); + _call_node = call; // Save the call node in case we need it later return kit.transfer_exceptions_into_jvms(); } @@ -238,9 +248,9 @@ return new ParseGenerator(m, expected_uses, true); } -CallGenerator* CallGenerator::for_direct_call(ciMethod* m) { +CallGenerator* CallGenerator::for_direct_call(ciMethod* m, bool separate_io_proj) { assert(!m->is_abstract(), "for_direct_call mismatch"); - return new DirectCallGenerator(m); + return new DirectCallGenerator(m, separate_io_proj); } CallGenerator* CallGenerator::for_virtual_call(ciMethod* m, int vtable_index) { @@ -248,6 +258,108 @@ return new VirtualCallGenerator(m, vtable_index); } +// Allow inlining decisions to be delayed +class LateInlineCallGenerator : public DirectCallGenerator { + CallGenerator* _inline_cg; + + public: + LateInlineCallGenerator(ciMethod* method, CallGenerator* inline_cg) : + DirectCallGenerator(method, true), _inline_cg(inline_cg) {} + + virtual bool is_late_inline() const { return true; } + + // Convert the CallStaticJava into an inline + virtual void do_late_inline(); + + JVMState* generate(JVMState* jvms) { + // Record that this call site should be revisited once the main + // parse is finished. + Compile::current()->add_late_inline(this); + + // Emit the CallStaticJava and request separate projections so + // that the late inlining logic can distinguish between fall + // through and exceptional uses of the memory and io projections + // as is done for allocations and macro expansion. + return DirectCallGenerator::generate(jvms); + } + +}; + + +void LateInlineCallGenerator::do_late_inline() { + // Can't inline it + if (call_node() == NULL || call_node()->outcnt() == 0 || + call_node()->in(0) == NULL || call_node()->in(0)->is_top()) + return; + + CallStaticJavaNode* call = call_node(); + + // Make a clone of the JVMState that appropriate to use for driving a parse + Compile* C = Compile::current(); + JVMState* jvms = call->jvms()->clone_shallow(C); + uint size = call->req(); + SafePointNode* map = new (C, size) SafePointNode(size, jvms); + for (uint i1 = 0; i1 < size; i1++) { + map->init_req(i1, call->in(i1)); + } + + // Make sure the state is a MergeMem for parsing. + if (!map->in(TypeFunc::Memory)->is_MergeMem()) { + map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory))); + } + + // Make enough space for the expression stack and transfer the incoming arguments + int nargs = method()->arg_size(); + jvms->set_map(map); + map->ensure_stack(jvms, jvms->method()->max_stack()); + if (nargs > 0) { + for (int i1 = 0; i1 < nargs; i1++) { + map->set_req(i1 + jvms->argoff(), call->in(TypeFunc::Parms + i1)); + } + } + + CompileLog* log = C->log(); + if (log != NULL) { + log->head("late_inline method='%d'", log->identify(method())); + JVMState* p = jvms; + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("late_inline"); + } + + // Setup default node notes to be picked up by the inlining + Node_Notes* old_nn = C->default_node_notes(); + if (old_nn != NULL) { + Node_Notes* entry_nn = old_nn->clone(C); + entry_nn->set_jvms(jvms); + C->set_default_node_notes(entry_nn); + } + + // Now perform the inling using the synthesized JVMState + JVMState* new_jvms = _inline_cg->generate(jvms); + if (new_jvms == NULL) return; // no change + if (C->failing()) return; + + // Capture any exceptional control flow + GraphKit kit(new_jvms); + + // Find the result object + Node* result = C->top(); + int result_size = method()->return_type()->size(); + if (result_size != 0 && !kit.stopped()) { + result = (result_size == 1) ? kit.pop() : kit.pop_pair(); + } + + kit.replace_call(call, result); +} + + +CallGenerator* CallGenerator::for_late_inline(ciMethod* method, CallGenerator* inline_cg) { + return new LateInlineCallGenerator(method, inline_cg); +} + //---------------------------WarmCallGenerator-------------------------------- // Internal class which handles initial deferral of inlining decisions. @@ -315,70 +427,7 @@ } void WarmCallInfo::make_hot() { - Compile* C = Compile::current(); - // Replace the callnode with something better. - CallJavaNode* call = this->call()->as_CallJava(); - ciMethod* method = call->method(); - int nargs = method->arg_size(); - JVMState* jvms = call->jvms()->clone_shallow(C); - uint size = TypeFunc::Parms + MAX2(2, nargs); - SafePointNode* map = new (C, size) SafePointNode(size, jvms); - for (uint i1 = 0; i1 < (uint)(TypeFunc::Parms + nargs); i1++) { - map->init_req(i1, call->in(i1)); - } - jvms->set_map(map); - jvms->set_offsets(map->req()); - jvms->set_locoff(TypeFunc::Parms); - jvms->set_stkoff(TypeFunc::Parms); - GraphKit kit(jvms); - - JVMState* new_jvms = _hot_cg->generate(kit.jvms()); - if (new_jvms == NULL) return; // no change - if (C->failing()) return; - - kit.set_jvms(new_jvms); - Node* res = C->top(); - int res_size = method->return_type()->size(); - if (res_size != 0) { - kit.inc_sp(-res_size); - res = kit.argument(0); - } - GraphKit ekit(kit.combine_and_pop_all_exception_states()->jvms()); - - // Replace the call: - for (DUIterator i = call->outs(); call->has_out(i); i++) { - Node* n = call->out(i); - Node* nn = NULL; // replacement - if (n->is_Proj()) { - ProjNode* nproj = n->as_Proj(); - assert(nproj->_con < (uint)(TypeFunc::Parms + (res_size ? 1 : 0)), "sane proj"); - if (nproj->_con == TypeFunc::Parms) { - nn = res; - } else { - nn = kit.map()->in(nproj->_con); - } - if (nproj->_con == TypeFunc::I_O) { - for (DUIterator j = nproj->outs(); nproj->has_out(j); j++) { - Node* e = nproj->out(j); - if (e->Opcode() == Op_CreateEx) { - e->replace_by(ekit.argument(0)); - } else if (e->Opcode() == Op_Catch) { - for (DUIterator k = e->outs(); e->has_out(k); k++) { - CatchProjNode* p = e->out(j)->as_CatchProj(); - if (p->is_handler_proj()) { - p->replace_by(ekit.control()); - } else { - p->replace_by(kit.control()); - } - } - } - } - } - } - NOT_PRODUCT(if (!nn) n->dump(2)); - assert(nn != NULL, "don't know what to do with this user"); - n->replace_by(nn); - } + Unimplemented(); } void WarmCallInfo::make_cold() { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/callGenerator.hpp --- a/src/share/vm/opto/callGenerator.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/callGenerator.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -57,6 +57,13 @@ // is_trap: Does not return to the caller. (E.g., uncommon trap.) virtual bool is_trap() const { return false; } + // is_late_inline: supports conversion of call into an inline + virtual bool is_late_inline() const { return false; } + // Replace the call with an inline version of the code + virtual void do_late_inline() { ShouldNotReachHere(); } + + virtual CallStaticJavaNode* call_node() const { ShouldNotReachHere(); return NULL; } + // Note: It is possible for a CG to be both inline and virtual. // (The hashCode intrinsic does a vtable check and an inlined fast path.) @@ -92,9 +99,12 @@ static CallGenerator* for_osr(ciMethod* m, int osr_bci); // How to generate vanilla out-of-line call sites: - static CallGenerator* for_direct_call(ciMethod* m); // static, special + 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 + // How to generate a replace a direct call with an inline version + static CallGenerator* for_late_inline(ciMethod* m, CallGenerator* inline_cg); + // How to make a call but defer the decision whether to inline or not. static CallGenerator* for_warm_call(WarmCallInfo* ci, CallGenerator* if_cold, diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/callnode.cpp --- a/src/share/vm/opto/callnode.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/callnode.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -693,6 +693,84 @@ } +void CallNode::extract_projections(CallProjections* projs, bool separate_io_proj) { + projs->fallthrough_proj = NULL; + projs->fallthrough_catchproj = NULL; + projs->fallthrough_ioproj = NULL; + projs->catchall_ioproj = NULL; + projs->catchall_catchproj = NULL; + projs->fallthrough_memproj = NULL; + projs->catchall_memproj = NULL; + projs->resproj = NULL; + projs->exobj = NULL; + + for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) { + ProjNode *pn = fast_out(i)->as_Proj(); + if (pn->outcnt() == 0) continue; + switch (pn->_con) { + case TypeFunc::Control: + { + // For Control (fallthrough) and I_O (catch_all_index) we have CatchProj -> Catch -> Proj + projs->fallthrough_proj = pn; + DUIterator_Fast jmax, j = pn->fast_outs(jmax); + const Node *cn = pn->fast_out(j); + if (cn->is_Catch()) { + ProjNode *cpn = NULL; + for (DUIterator_Fast kmax, k = cn->fast_outs(kmax); k < kmax; k++) { + cpn = cn->fast_out(k)->as_Proj(); + assert(cpn->is_CatchProj(), "must be a CatchProjNode"); + if (cpn->_con == CatchProjNode::fall_through_index) + projs->fallthrough_catchproj = cpn; + else { + assert(cpn->_con == CatchProjNode::catch_all_index, "must be correct index."); + projs->catchall_catchproj = cpn; + } + } + } + break; + } + case TypeFunc::I_O: + if (pn->_is_io_use) + projs->catchall_ioproj = pn; + else + projs->fallthrough_ioproj = pn; + for (DUIterator j = pn->outs(); pn->has_out(j); j++) { + Node* e = pn->out(j); + if (e->Opcode() == Op_CreateEx && e->in(0)->is_CatchProj()) { + assert(projs->exobj == NULL, "only one"); + projs->exobj = e; + } + } + break; + case TypeFunc::Memory: + if (pn->_is_io_use) + projs->catchall_memproj = pn; + else + projs->fallthrough_memproj = pn; + break; + case TypeFunc::Parms: + projs->resproj = pn; + break; + default: + assert(false, "unexpected projection from allocation node."); + } + } + + // The resproj may not exist because the result couuld be ignored + // and the exception object may not exist if an exception handler + // swallows the exception but all the other must exist and be found. + assert(projs->fallthrough_proj != NULL, "must be found"); + assert(projs->fallthrough_catchproj != NULL, "must be found"); + assert(projs->fallthrough_memproj != NULL, "must be found"); + assert(projs->fallthrough_ioproj != NULL, "must be found"); + assert(projs->catchall_catchproj != NULL, "must be found"); + if (separate_io_proj) { + assert(projs->catchall_memproj != NULL, "must be found"); + assert(projs->catchall_ioproj != NULL, "must be found"); + } +} + + //============================================================================= uint CallJavaNode::size_of() const { return sizeof(*this); } uint CallJavaNode::cmp( const Node &n ) const { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/callnode.hpp --- a/src/share/vm/opto/callnode.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/callnode.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -470,6 +470,23 @@ #endif }; + +// Simple container for the outgoing projections of a call. Useful +// for serious surgery on calls. +class CallProjections : public StackObj { +public: + Node* fallthrough_proj; + Node* fallthrough_catchproj; + Node* fallthrough_memproj; + Node* fallthrough_ioproj; + Node* catchall_catchproj; + Node* catchall_memproj; + Node* catchall_ioproj; + Node* resproj; + Node* exobj; +}; + + //------------------------------CallNode--------------------------------------- // Call nodes now subsume the function of debug nodes at callsites, so they // contain the functionality of a full scope chain of debug nodes. @@ -521,6 +538,11 @@ // or returns NULL if there is no one. Node *result_cast(); + // Collect all the interesting edges from a call for use in + // replacing the call by something else. Used by macro expansion + // and the late inlining support. + void extract_projections(CallProjections* projs, bool separate_io_proj); + virtual uint match_edge(uint idx) const; #ifndef PRODUCT @@ -529,6 +551,7 @@ #endif }; + //------------------------------CallJavaNode----------------------------------- // Make a static or dynamic subroutine call node using Java calling // convention. (The "Java" calling convention is the compiler's calling diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/compile.cpp --- a/src/share/vm/opto/compile.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/compile.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -224,6 +224,32 @@ } +void Compile::gvn_replace_by(Node* n, Node* nn) { + for (DUIterator_Last imin, i = n->last_outs(imin); i >= imin; ) { + Node* use = n->last_out(i); + bool is_in_table = initial_gvn()->hash_delete(use); + uint uses_found = 0; + for (uint j = 0; j < use->len(); j++) { + if (use->in(j) == n) { + if (j < use->req()) + use->set_req(j, nn); + else + use->set_prec(j, nn); + uses_found++; + } + } + if (is_in_table) { + // reinsert into table + initial_gvn()->hash_find_insert(use); + } + record_for_igvn(use); + i -= uses_found; // we deleted 1 or more copies of this edge + } +} + + + + // Identify all nodes that are reachable from below, useful. // Use breadth-first pass that records state in a Unique_Node_List, // recursive traversal is slower. @@ -554,6 +580,28 @@ rethrow_exceptions(kit.transfer_exceptions_into_jvms()); } + if (!failing() && has_stringbuilder()) { + { + // remove useless nodes to make the usage analysis simpler + ResourceMark rm; + PhaseRemoveUseless pru(initial_gvn(), &for_igvn); + } + + { + ResourceMark rm; + print_method("Before StringOpts", 3); + PhaseStringOpts pso(initial_gvn(), &for_igvn); + print_method("After StringOpts", 3); + } + + // now inline anything that we skipped the first time around + while (_late_inlines.length() > 0) { + CallGenerator* cg = _late_inlines.pop(); + cg->do_late_inline(); + } + } + assert(_late_inlines.length() == 0, "should have been processed"); + print_method("Before RemoveUseless", 3); // Remove clutter produced by parsing. @@ -820,6 +868,7 @@ _fixed_slots = 0; set_has_split_ifs(false); set_has_loops(has_method() && method()->has_loops()); // first approximation + set_has_stringbuilder(false); _deopt_happens = true; // start out assuming the worst _trap_can_recompile = false; // no traps emitted yet _major_progress = true; // start out assuming good things will happen @@ -2240,6 +2289,30 @@ break; } + case Op_Proj: { + if (OptimizeStringConcat) { + ProjNode* p = n->as_Proj(); + if (p->_is_io_use) { + // Separate projections were used for the exception path which + // are normally removed by a late inline. If it wasn't inlined + // then they will hang around and should just be replaced with + // the original one. + Node* proj = NULL; + // Replace with just one + for (SimpleDUIterator i(p->in(0)); i.has_next(); i.next()) { + Node *use = i.get(); + if (use->is_Proj() && p != use && use->as_Proj()->_con == p->_con) { + proj = use; + break; + } + } + assert(p != NULL, "must be found"); + p->subsume_by(proj); + } + } + break; + } + case Op_Phi: if (n->as_Phi()->bottom_type()->isa_narrowoop()) { // The EncodeP optimization may create Phi with the same edges diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/compile.hpp --- a/src/share/vm/opto/compile.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/compile.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -149,6 +149,7 @@ bool _has_loops; // True if the method _may_ have some loops bool _has_split_ifs; // True if the method _may_ have some split-if bool _has_unsafe_access; // True if the method _may_ produce faults in unsafe loads or stores. + bool _has_stringbuilder; // True StringBuffers or StringBuilders are allocated uint _trap_hist[trapHistLength]; // Cumulative traps bool _trap_can_recompile; // Have we emitted a recompiling trap? uint _decompile_count; // Cumulative decompilation counts. @@ -219,6 +220,9 @@ Unique_Node_List* _for_igvn; // Initial work-list for next round of Iterative GVN WarmCallInfo* _warm_calls; // Sorted work-list for heat-based inlining. + GrowableArray _late_inlines; // List of CallGenerators to be revisited after + // main parsing has finished. + // Matching, CFG layout, allocation, code generation PhaseCFG* _cfg; // Results of CFG finding bool _select_24_bit_instr; // We selected an instruction with a 24-bit result @@ -298,6 +302,8 @@ void set_has_split_ifs(bool z) { _has_split_ifs = z; } bool has_unsafe_access() const { return _has_unsafe_access; } void set_has_unsafe_access(bool z) { _has_unsafe_access = z; } + bool has_stringbuilder() const { return _has_stringbuilder; } + void set_has_stringbuilder(bool z) { _has_stringbuilder = z; } void set_trap_count(uint r, uint c) { assert(r < trapHistLength, "oob"); _trap_hist[r] = c; } uint trap_count(uint r) const { assert(r < trapHistLength, "oob"); return _trap_hist[r]; } bool trap_can_recompile() const { return _trap_can_recompile; } @@ -475,6 +481,7 @@ // Decide how to build a call. // The profile factor is a discount to apply to this site's interp. profile. CallGenerator* call_generator(ciMethod* call_method, int vtable_index, bool call_is_virtual, JVMState* jvms, bool allow_inline, float profile_factor); + bool should_delay_inlining(ciMethod* call_method, JVMState* jvms); // Report if there were too many traps at a current method and bci. // Report if a trap was recorded, and/or PerMethodTrapLimit was exceeded. @@ -495,6 +502,11 @@ void set_initial_gvn(PhaseGVN *gvn) { _initial_gvn = gvn; } void set_for_igvn(Unique_Node_List *for_igvn) { _for_igvn = for_igvn; } + // Replace n by nn using initial_gvn, calling hash_delete and + // record_for_igvn as needed. + void gvn_replace_by(Node* n, Node* nn); + + void identify_useful_nodes(Unique_Node_List &useful); void remove_useless_nodes (Unique_Node_List &useful); @@ -502,6 +514,9 @@ void set_warm_calls(WarmCallInfo* l) { _warm_calls = l; } WarmCallInfo* pop_warm_call(); + // Record this CallGenerator for inlining at the end of parsing. + void add_late_inline(CallGenerator* cg) { _late_inlines.push(cg); } + // Matching, CFG layout, allocation, code generation PhaseCFG* cfg() { return _cfg; } bool select_24_bit_instr() const { return _select_24_bit_instr; } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/doCall.cpp --- a/src/share/vm/opto/doCall.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/doCall.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -128,6 +128,12 @@ if (allow_inline) { CallGenerator* cg = CallGenerator::for_inline(call_method, expected_uses); + if (require_inline && cg != NULL && should_delay_inlining(call_method, jvms)) { + // Delay the inlining of this method to give us the + // opportunity to perform some high level optimizations + // first. + return CallGenerator::for_late_inline(call_method, cg); + } if (cg == NULL) { // Fall through. } else if (require_inline || !InlineWarmCalls) { @@ -225,10 +231,63 @@ } else { // Class Hierarchy Analysis or Type Profile reveals a unique target, // or it is a static or special call. - return CallGenerator::for_direct_call(call_method); + return CallGenerator::for_direct_call(call_method, should_delay_inlining(call_method, jvms)); } } +// Return true for methods that shouldn't be inlined early so that +// they are easier to analyze and optimize as intrinsics. +bool Compile::should_delay_inlining(ciMethod* call_method, JVMState* jvms) { + if (has_stringbuilder()) { + + if ((call_method->holder() == C->env()->StringBuilder_klass() || + call_method->holder() == C->env()->StringBuffer_klass()) && + (jvms->method()->holder() == C->env()->StringBuilder_klass() || + jvms->method()->holder() == C->env()->StringBuffer_klass())) { + // Delay SB calls only when called from non-SB code + return false; + } + + switch (call_method->intrinsic_id()) { + case vmIntrinsics::_StringBuilder_void: + case vmIntrinsics::_StringBuilder_int: + case vmIntrinsics::_StringBuilder_String: + case vmIntrinsics::_StringBuilder_append_char: + case vmIntrinsics::_StringBuilder_append_int: + case vmIntrinsics::_StringBuilder_append_String: + case vmIntrinsics::_StringBuilder_toString: + case vmIntrinsics::_StringBuffer_void: + case vmIntrinsics::_StringBuffer_int: + case vmIntrinsics::_StringBuffer_String: + case vmIntrinsics::_StringBuffer_append_char: + case vmIntrinsics::_StringBuffer_append_int: + case vmIntrinsics::_StringBuffer_append_String: + case vmIntrinsics::_StringBuffer_toString: + case vmIntrinsics::_Integer_toString: + return true; + + case vmIntrinsics::_String_String: + { + Node* receiver = jvms->map()->in(jvms->argoff() + 1); + if (receiver->is_Proj() && receiver->in(0)->is_CallStaticJava()) { + CallStaticJavaNode* csj = receiver->in(0)->as_CallStaticJava(); + ciMethod* m = csj->method(); + if (m != NULL && + (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString || + m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) + // Delay String.(new SB()) + return true; + } + return false; + } + + default: + return false; + } + } + return false; +} + // uncommon-trap call-sites where callee is unloaded, uninitialized or will not link bool Parse::can_not_compile_call_site(ciMethod *dest_method, ciInstanceKlass* klass) { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/escape.cpp --- a/src/share/vm/opto/escape.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/escape.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -537,8 +537,9 @@ } const TypeOopPtr *tinst = base_t->add_offset(t->offset())->is_oopptr(); - // Do NOT remove the next call: ensure an new alias index is allocated - // for the instance type + // Do NOT remove the next line: ensure a new alias index is allocated + // for the instance type. Note: C++ will not remove it since the call + // has side effect. int alias_idx = _compile->get_alias_index(tinst); igvn->set_type(addp, tinst); // record the allocation in the node map @@ -1149,7 +1150,6 @@ } else { assert(n->is_Mem(), "memory node required."); Node *addr = n->in(MemNode::Address); - assert(addr->is_AddP(), "AddP required"); const Type *addr_t = igvn->type(addr); if (addr_t == Type::TOP) continue; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/graphKit.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1351,8 +1351,8 @@ } //------------------------------set_all_memory_call---------------------------- -void GraphKit::set_all_memory_call(Node* call) { - Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) ); +void GraphKit::set_all_memory_call(Node* call, bool separate_io_proj) { + Node* newmem = _gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory, separate_io_proj) ); set_all_memory(newmem); } @@ -1573,7 +1573,7 @@ //---------------------------set_edges_for_java_call--------------------------- // Connect a newly created call into the current JVMS. // A return value node (if any) is returned from set_edges_for_java_call. -void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw) { +void GraphKit::set_edges_for_java_call(CallJavaNode* call, bool must_throw, bool separate_io_proj) { // Add the predefined inputs: call->init_req( TypeFunc::Control, control() ); @@ -1595,13 +1595,13 @@ // Re-use the current map to produce the result. set_control(_gvn.transform(new (C, 1) ProjNode(call, TypeFunc::Control))); - set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O ))); - set_all_memory_call(xcall); + set_i_o( _gvn.transform(new (C, 1) ProjNode(call, TypeFunc::I_O , separate_io_proj))); + set_all_memory_call(xcall, separate_io_proj); //return xcall; // no need, caller already has it } -Node* GraphKit::set_results_for_java_call(CallJavaNode* call) { +Node* GraphKit::set_results_for_java_call(CallJavaNode* call, bool separate_io_proj) { if (stopped()) return top(); // maybe the call folded up? // Capture the return value, if any. @@ -1614,8 +1614,15 @@ // Note: Since any out-of-line call can produce an exception, // we always insert an I_O projection from the call into the result. - make_slow_call_ex(call, env()->Throwable_klass(), false); - + make_slow_call_ex(call, env()->Throwable_klass(), separate_io_proj); + + if (separate_io_proj) { + // The caller requested separate projections be used by the fall + // through and exceptional paths, so replace the projections for + // the fall through path. + set_i_o(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::I_O) )); + set_all_memory(_gvn.transform( new (C, 1) ProjNode(call, TypeFunc::Memory) )); + } return ret; } @@ -1678,6 +1685,59 @@ } } + +// Replace the call with the current state of the kit. +void GraphKit::replace_call(CallNode* call, Node* result) { + JVMState* ejvms = NULL; + if (has_exceptions()) { + ejvms = transfer_exceptions_into_jvms(); + } + + SafePointNode* final_state = stop(); + + // Find all the needed outputs of this call + CallProjections callprojs; + call->extract_projections(&callprojs, true); + + // Replace all the old call edges with the edges from the inlining result + C->gvn_replace_by(callprojs.fallthrough_catchproj, final_state->in(TypeFunc::Control)); + C->gvn_replace_by(callprojs.fallthrough_memproj, final_state->in(TypeFunc::Memory)); + C->gvn_replace_by(callprojs.fallthrough_ioproj, final_state->in(TypeFunc::I_O)); + + // Replace the result with the new result if it exists and is used + if (callprojs.resproj != NULL && result != NULL) { + C->gvn_replace_by(callprojs.resproj, result); + } + + if (ejvms == NULL) { + // No exception edges to simply kill off those paths + C->gvn_replace_by(callprojs.catchall_catchproj, C->top()); + C->gvn_replace_by(callprojs.catchall_memproj, C->top()); + C->gvn_replace_by(callprojs.catchall_ioproj, C->top()); + } else { + GraphKit ekit(ejvms); + + // Load my combined exception state into the kit, with all phis transformed: + SafePointNode* ex_map = ekit.combine_and_pop_all_exception_states(); + + Node* ex_oop = ekit.use_exception_state(ex_map); + + C->gvn_replace_by(callprojs.catchall_catchproj, ekit.control()); + C->gvn_replace_by(callprojs.catchall_memproj, ekit.reset_memory()); + C->gvn_replace_by(callprojs.catchall_ioproj, ekit.i_o()); + + // Replace the old exception object with the newly created one + if (callprojs.exobj != NULL) { + C->gvn_replace_by(callprojs.exobj, ex_oop); + } + } + + // Disconnect the call from the graph + call->disconnect_inputs(NULL); + C->gvn_replace_by(call, C->top()); +} + + //------------------------------increment_counter------------------------------ // for statistics: increment a VM counter by 1 @@ -3459,4 +3519,3 @@ sync_kit(ideal); } #undef __ - diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/graphKit.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -279,6 +279,34 @@ } Node* basic_plus_adr(Node* base, Node* ptr, Node* offset); + + // Some convenient shortcuts for common nodes + Node* IfTrue(IfNode* iff) { return _gvn.transform(new (C,1) IfTrueNode(iff)); } + Node* IfFalse(IfNode* iff) { return _gvn.transform(new (C,1) IfFalseNode(iff)); } + + Node* AddI(Node* l, Node* r) { return _gvn.transform(new (C,3) AddINode(l, r)); } + Node* SubI(Node* l, Node* r) { return _gvn.transform(new (C,3) SubINode(l, r)); } + Node* MulI(Node* l, Node* r) { return _gvn.transform(new (C,3) MulINode(l, r)); } + Node* DivI(Node* ctl, Node* l, Node* r) { return _gvn.transform(new (C,3) DivINode(ctl, l, r)); } + + Node* AndI(Node* l, Node* r) { return _gvn.transform(new (C,3) AndINode(l, r)); } + Node* OrI(Node* l, Node* r) { return _gvn.transform(new (C,3) OrINode(l, r)); } + Node* XorI(Node* l, Node* r) { return _gvn.transform(new (C,3) XorINode(l, r)); } + + Node* MaxI(Node* l, Node* r) { return _gvn.transform(new (C,3) MaxINode(l, r)); } + Node* MinI(Node* l, Node* r) { return _gvn.transform(new (C,3) MinINode(l, r)); } + + Node* LShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) LShiftINode(l, r)); } + Node* RShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) RShiftINode(l, r)); } + Node* URShiftI(Node* l, Node* r) { return _gvn.transform(new (C,3) URShiftINode(l, r)); } + + Node* CmpI(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpINode(l, r)); } + Node* CmpL(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpLNode(l, r)); } + Node* CmpP(Node* l, Node* r) { return _gvn.transform(new (C,3) CmpPNode(l, r)); } + Node* Bool(Node* cmp, BoolTest::mask relop) { return _gvn.transform(new (C,2) BoolNode(cmp, relop)); } + + Node* AddP(Node* b, Node* a, Node* o) { return _gvn.transform(new (C,4) AddPNode(b, a, o)); } + // Convert between int and long, and size_t. // (See macros ConvI2X, etc., in type.hpp for ConvI2X, etc.) Node* ConvI2L(Node* offset); @@ -400,7 +428,7 @@ void set_all_memory(Node* newmem); // Create a memory projection from the call, then set_all_memory. - void set_all_memory_call(Node* call); + void set_all_memory_call(Node* call, bool separate_io_proj = false); // Create a LoadNode, reading from the parser's memory state. // (Note: require_atomic_access is useful only with T_LONG.) @@ -543,12 +571,12 @@ // Transform the call, and update the basics: control, i_o, memory. // (The next step is usually to call set_results_for_java_call.) void set_edges_for_java_call(CallJavaNode* call, - bool must_throw = false); + bool must_throw = false, bool separate_io_proj = false); // Finish up a java call that was started by set_edges_for_java_call. // Call add_exception on any throw arising from the call. // Return the call result (transformed). - Node* set_results_for_java_call(CallJavaNode* call); + Node* set_results_for_java_call(CallJavaNode* call, bool separate_io_proj = false); // Similar to set_edges_for_java_call, but simplified for runtime calls. void set_predefined_output_for_runtime_call(Node* call) { @@ -559,6 +587,11 @@ const TypePtr* hook_mem); Node* set_predefined_input_for_runtime_call(SafePointNode* call); + // Replace the call with the current state of the kit. Requires + // that the call was generated with separate io_projs so that + // exceptional control flow can be handled properly. + void replace_call(CallNode* call, Node* result); + // helper functions for statistics void increment_counter(address counter_addr); // increment a debug counter void increment_counter(Node* counter_addr); // increment a debug counter diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/loopnode.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1279,7 +1279,8 @@ // Visit all children, looking for Phis for (DUIterator i = cl->outs(); cl->has_out(i); i++) { Node *out = cl->out(i); - if (!out->is_Phi() || out == phi) continue; // Looking for other phis + // Look for other phis (secondary IVs). Skip dead ones + if (!out->is_Phi() || out == phi || !phase->has_node(out)) continue; PhiNode* phi2 = out->as_Phi(); Node *incr2 = phi2->in( LoopNode::LoopBackControl ); // Look for induction variables of the form: X += constant diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/macro.cpp --- a/src/share/vm/opto/macro.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/macro.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -912,15 +912,29 @@ return false; } + CompileLog* log = C->log(); + if (log != NULL) { + Node* klass = alloc->in(AllocateNode::KlassNode); + const TypeKlassPtr* tklass = _igvn.type(klass)->is_klassptr(); + log->head("eliminate_allocation type='%d'", + log->identify(tklass->klass())); + JVMState* p = alloc->jvms(); + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("eliminate_allocation"); + } + process_users_of_allocation(alloc); #ifndef PRODUCT -if (PrintEliminateAllocations) { - if (alloc->is_AllocateArray()) - tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx); - else - tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx); -} + if (PrintEliminateAllocations) { + if (alloc->is_AllocateArray()) + tty->print_cr("++++ Eliminated: %d AllocateArray", alloc->_idx); + else + tty->print_cr("++++ Eliminated: %d Allocate", alloc->_idx); + } #endif return true; @@ -1639,6 +1653,18 @@ } // if (!oldbox->is_eliminated()) } // if (alock->is_Lock() && !lock->is_coarsened()) + CompileLog* log = C->log(); + if (log != NULL) { + log->head("eliminate_lock lock='%d'", + alock->is_Lock()); + JVMState* p = alock->jvms(); + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("eliminate_lock"); + } + #ifndef PRODUCT if (PrintEliminateLocks) { if (alock->is_Lock()) { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/matcher.cpp --- a/src/share/vm/opto/matcher.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/matcher.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1832,67 +1832,23 @@ case Op_Binary: // These are introduced in the Post_Visit state. ShouldNotReachHere(); break; - case Op_StoreB: // Do match these, despite no ideal reg - case Op_StoreC: - case Op_StoreCM: - case Op_StoreD: - case Op_StoreF: - case Op_StoreI: - case Op_StoreL: - case Op_StoreP: - case Op_StoreN: - case Op_Store16B: - case Op_Store8B: - case Op_Store4B: - case Op_Store8C: - case Op_Store4C: - case Op_Store2C: - case Op_Store4I: - case Op_Store2I: - case Op_Store2L: - case Op_Store4F: - case Op_Store2F: - case Op_Store2D: case Op_ClearArray: case Op_SafePoint: mem_op = true; break; - case Op_LoadB: - case Op_LoadUS: - case Op_LoadD: - case Op_LoadF: - case Op_LoadI: - case Op_LoadKlass: - case Op_LoadNKlass: - case Op_LoadL: - case Op_LoadS: - case Op_LoadP: - case Op_LoadN: - case Op_LoadRange: - case Op_LoadD_unaligned: - case Op_LoadL_unaligned: - case Op_Load16B: - case Op_Load8B: - case Op_Load4B: - case Op_Load4C: - case Op_Load2C: - case Op_Load8C: - case Op_Load8S: - case Op_Load4S: - case Op_Load2S: - case Op_Load4I: - case Op_Load2I: - case Op_Load2L: - case Op_Load4F: - case Op_Load2F: - case Op_Load2D: - mem_op = true; - // Must be root of match tree due to prior load conflict - if( C->subsume_loads() == false ) { - set_shared(n); + default: + if( n->is_Store() ) { + // Do match stores, despite no ideal reg + mem_op = true; + break; + } + if( n->is_Mem() ) { // Loads and LoadStores + mem_op = true; + // Loads must be root of match tree due to prior load conflict + if( C->subsume_loads() == false ) + set_shared(n); } // Fall into default case - default: if( !n->ideal_reg() ) set_dontcare(n); // Unmatchable Nodes } // end_switch @@ -1913,15 +1869,15 @@ continue; // for(int i = ...) } - // Clone addressing expressions as they are "free" in most instructions + if( mop == Op_AddP && m->in(AddPNode::Base)->Opcode() == Op_DecodeN ) { + // Bases used in addresses must be shared but since + // they are shared through a DecodeN they may appear + // to have a single use so force sharing here. + set_shared(m->in(AddPNode::Base)->in(1)); + } + + // Clone addressing expressions as they are "free" in memory access instructions if( mem_op && i == MemNode::Address && mop == Op_AddP ) { - if (m->in(AddPNode::Base)->Opcode() == Op_DecodeN) { - // Bases used in addresses must be shared but since - // they are shared through a DecodeN they may appear - // to have a single use so force sharing here. - set_shared(m->in(AddPNode::Base)->in(1)); - } - // Some inputs for address expression are not put on stack // to avoid marking them as shared and forcing them into register // if they are used only in address expressions. diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/memnode.cpp --- a/src/share/vm/opto/memnode.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/memnode.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -255,6 +255,13 @@ return NodeSentinel; // caller will return NULL } + // Do NOT remove or optimize the next lines: ensure a new alias index + // is allocated for an oop pointer type before Escape Analysis. + // Note: C++ will not remove it since the call has side effect. + if ( t_adr->isa_oopptr() ) { + int alias_idx = phase->C->get_alias_index(t_adr->is_ptr()); + } + #ifdef ASSERT Node* base = NULL; if (address->is_AddP()) @@ -1496,6 +1503,8 @@ } } } else if (tp->base() == Type::InstPtr) { + const TypeInstPtr* tinst = tp->is_instptr(); + ciKlass* klass = tinst->klass(); assert( off != Type::OffsetBot || // arrays can be cast to Objects tp->is_oopptr()->klass()->is_java_lang_Object() || @@ -1503,6 +1512,25 @@ phase->C->has_unsafe_access(), "Field accesses must be precise" ); // For oop loads, we expect the _type to be precise + if (OptimizeStringConcat && klass == phase->C->env()->String_klass() && + adr->is_AddP() && off != Type::OffsetBot) { + // For constant Strings treat the fields as compile time constants. + Node* base = adr->in(AddPNode::Base); + if (base->Opcode() == Op_ConP) { + const TypeOopPtr* t = phase->type(base)->isa_oopptr(); + ciObject* string = t->const_oop(); + ciConstant constant = string->as_instance()->field_value_by_offset(off); + if (constant.basic_type() == T_INT) { + return TypeInt::make(constant.as_int()); + } else if (constant.basic_type() == T_ARRAY) { + if (adr->bottom_type()->is_ptr_to_narrowoop()) { + return TypeNarrowOop::make_from_constant(constant.as_object()); + } else { + return TypeOopPtr::make_from_constant(constant.as_object()); + } + } + } + } } else if (tp->base() == Type::KlassPtr) { assert( off != Type::OffsetBot || // arrays can be cast to Objects diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/node.hpp --- a/src/share/vm/opto/node.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/node.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -661,18 +661,25 @@ return (_flags & Flag_is_Call) != 0; } + CallNode* isa_Call() const { + return is_Call() ? as_Call() : NULL; + } + CallNode *as_Call() const { // Only for CallNode (not for MachCallNode) assert((_class_id & ClassMask_Call) == Class_Call, "invalid node class"); return (CallNode*)this; } - #define DEFINE_CLASS_QUERY(type) \ - bool is_##type() const { \ + #define DEFINE_CLASS_QUERY(type) \ + bool is_##type() const { \ return ((_class_id & ClassMask_##type) == Class_##type); \ - } \ - type##Node *as_##type() const { \ - assert(is_##type(), "invalid node class"); \ - return (type##Node*)this; \ + } \ + type##Node *as_##type() const { \ + assert(is_##type(), "invalid node class"); \ + return (type##Node*)this; \ + } \ + type##Node* isa_##type() const { \ + return (is_##type()) ? as_##type() : NULL; \ } DEFINE_CLASS_QUERY(AbstractLock) @@ -1249,6 +1256,24 @@ #undef I_VDUI_ONLY #undef VDUI_ONLY +// An Iterator that truly follows the iterator pattern. Doesn't +// support deletion but could be made to. +// +// for (SimpleDUIterator i(n); i.has_next(); i.next()) { +// Node* m = i.get(); +// +class SimpleDUIterator : public StackObj { + private: + Node* node; + DUIterator_Fast i; + DUIterator_Fast imax; + public: + SimpleDUIterator(Node* n): node(n), i(n->fast_outs(imax)) {} + bool has_next() { return i < imax; } + void next() { i++; } + Node* get() { return node->fast_out(i); } +}; + //----------------------------------------------------------------------------- // Map dense integer indices to Nodes. Uses classic doubling-array trick. @@ -1290,6 +1315,12 @@ public: Node_List() : Node_Array(Thread::current()->resource_area()), _cnt(0) {} Node_List(Arena *a) : Node_Array(a), _cnt(0) {} + bool contains(Node* n) { + for (uint e = 0; e < size(); e++) { + if (at(e) == n) return true; + } + return false; + } void insert( uint i, Node *n ) { Node_Array::insert(i,n); _cnt++; } void remove( uint i ) { Node_Array::remove(i); _cnt--; } void push( Node *b ) { map(_cnt++,b); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/parse1.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -231,12 +231,13 @@ // Use the raw liveness computation to make sure that unexpected // values don't propagate into the OSR frame. - MethodLivenessResult live_locals = method()->raw_liveness_at_bci(osr_bci()); + MethodLivenessResult live_locals = method()->liveness_at_bci(osr_bci()); if (!live_locals.is_valid()) { // Degenerate or breakpointed method. C->record_method_not_compilable("OSR in empty or breakpointed method"); return; } + MethodLivenessResult raw_live_locals = method()->raw_liveness_at_bci(osr_bci()); // Extract the needed locals from the interpreter frame. Node *locals_addr = basic_plus_adr(osr_buf, osr_buf, (max_locals-1)*wordSize); @@ -316,6 +317,10 @@ continue; } } + if (type->basic_type() == T_ADDRESS && !raw_live_locals.at(index)) { + // Skip type check for dead address locals + continue; + } set_local(index, check_interpreter_type(l, type, bad_type_exit)); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/parseHelper.cpp --- a/src/share/vm/opto/parseHelper.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/parseHelper.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -221,6 +221,14 @@ // Push resultant oop onto stack push(obj); + + // Keep track of whether opportunities exist for StringBuilder + // optimizations. + if (OptimizeStringConcat && + (klass == C->env()->StringBuilder_klass() || + klass == C->env()->StringBuffer_klass())) { + C->set_has_stringbuilder(true); + } } #ifndef PRODUCT diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/phase.hpp --- a/src/share/vm/opto/phase.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/phase.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -44,6 +44,7 @@ BlockLayout, // Linear ordering of blocks Register_Allocation, // Register allocation, duh LIVE, // Dragon-book LIVE range problem + StringOpts, // StringBuilder related optimizations Interference_Graph, // Building the IFG Coalesce, // Coalescing copies Ideal_Loop, // Find idealized trip-counted loops diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/phaseX.hpp --- a/src/share/vm/opto/phaseX.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/phaseX.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -345,7 +345,11 @@ Node *hash_find(const Node *n) { return _table.hash_find(n); } // Used after parsing to eliminate values that are no longer in program - void remove_useless_nodes(VectorSet &useful) { _table.remove_useless_nodes(useful); } + void remove_useless_nodes(VectorSet &useful) { + _table.remove_useless_nodes(useful); + // this may invalidate cached cons so reset the cache + init_con_caches(); + } virtual ConNode* uncached_makecon(const Type* t); // override from PhaseTransform diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/stringopts.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/stringopts.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,1395 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +#include "incls/_precompiled.incl" +#include "incls/_stringopts.cpp.incl" + +#define __ kit. + +class StringConcat : public ResourceObj { + private: + PhaseStringOpts* _stringopts; + Node* _string_alloc; + AllocateNode* _begin; // The allocation the begins the pattern + CallStaticJavaNode* _end; // The final call of the pattern. Will either be + // SB.toString or or String.(SB.toString) + bool _multiple; // indicates this is a fusion of two or more + // separate StringBuilders + + Node* _arguments; // The list of arguments to be concatenated + GrowableArray _mode; // into a String along with a mode flag + // indicating how to treat the value. + + Node_List _control; // List of control nodes that will be deleted + Node_List _uncommon_traps; // Uncommon traps that needs to be rewritten + // to restart at the initial JVMState. + public: + // Mode for converting arguments to Strings + enum { + StringMode, + IntMode, + CharMode + }; + + StringConcat(PhaseStringOpts* stringopts, CallStaticJavaNode* end): + _end(end), + _begin(NULL), + _multiple(false), + _string_alloc(NULL), + _stringopts(stringopts) { + _arguments = new (_stringopts->C, 1) Node(1); + _arguments->del_req(0); + } + + bool validate_control_flow(); + + void merge_add() { +#if 0 + // XXX This is place holder code for reusing an existing String + // allocation but the logic for checking the state safety is + // probably inadequate at the moment. + CallProjections endprojs; + sc->end()->extract_projections(&endprojs, false); + if (endprojs.resproj != NULL) { + for (SimpleDUIterator i(endprojs.resproj); i.has_next(); i.next()) { + CallStaticJavaNode *use = i.get()->isa_CallStaticJava(); + if (use != NULL && use->method() != NULL && + use->method()->holder() == C->env()->String_klass() && + use->method()->name() == ciSymbol::object_initializer_name() && + use->in(TypeFunc::Parms + 1) == endprojs.resproj) { + // Found useless new String(sb.toString()) so reuse the newly allocated String + // when creating the result instead of allocating a new one. + sc->set_string_alloc(use->in(TypeFunc::Parms)); + sc->set_end(use); + } + } + } +#endif + } + + StringConcat* merge(StringConcat* other, Node* arg); + + void set_allocation(AllocateNode* alloc) { + _begin = alloc; + } + + void append(Node* value, int mode) { + _arguments->add_req(value); + _mode.append(mode); + } + void push(Node* value, int mode) { + _arguments->ins_req(0, value); + _mode.insert_before(0, mode); + } + void push_string(Node* value) { + push(value, StringMode); + } + void push_int(Node* value) { + push(value, IntMode); + } + void push_char(Node* value) { + push(value, CharMode); + } + + Node* argument(int i) { + return _arguments->in(i); + } + void set_argument(int i, Node* value) { + _arguments->set_req(i, value); + } + int num_arguments() { + return _mode.length(); + } + int mode(int i) { + return _mode.at(i); + } + void add_control(Node* ctrl) { + assert(!_control.contains(ctrl), "only push once"); + _control.push(ctrl); + } + CallStaticJavaNode* end() { return _end; } + AllocateNode* begin() { return _begin; } + Node* string_alloc() { return _string_alloc; } + + void eliminate_unneeded_control(); + void eliminate_initialize(InitializeNode* init); + void eliminate_call(CallNode* call); + + void maybe_log_transform() { + CompileLog* log = _stringopts->C->log(); + if (log != NULL) { + log->head("replace_string_concat arguments='%d' string_alloc='%d' multiple='%d'", + num_arguments(), + _string_alloc != NULL, + _multiple); + JVMState* p = _begin->jvms(); + while (p != NULL) { + log->elem("jvms bci='%d' method='%d'", p->bci(), log->identify(p->method())); + p = p->caller(); + } + log->tail("replace_string_concat"); + } + } + + void convert_uncommon_traps(GraphKit& kit, const JVMState* jvms) { + for (uint u = 0; u < _uncommon_traps.size(); u++) { + Node* uct = _uncommon_traps.at(u); + + // Build a new call using the jvms state of the allocate + address call_addr = SharedRuntime::uncommon_trap_blob()->instructions_begin(); + const TypeFunc* call_type = OptoRuntime::uncommon_trap_Type(); + int size = call_type->domain()->cnt(); + const TypePtr* no_memory_effects = NULL; + Compile* C = _stringopts->C; + CallStaticJavaNode* call = new (C, size) CallStaticJavaNode(call_type, call_addr, "uncommon_trap", + jvms->bci(), no_memory_effects); + for (int e = 0; e < TypeFunc::Parms; e++) { + call->init_req(e, uct->in(e)); + } + // Set the trap request to record intrinsic failure if this trap + // is taken too many times. Ideally we would handle then traps by + // doing the original bookkeeping in the MDO so that if it caused + // the code to be thrown out we could still recompile and use the + // optimization. Failing the uncommon traps doesn't really mean + // that the optimization is a bad idea but there's no other way to + // do the MDO updates currently. + int trap_request = Deoptimization::make_trap_request(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + call->init_req(TypeFunc::Parms, __ intcon(trap_request)); + kit.add_safepoint_edges(call); + + _stringopts->gvn()->transform(call); + C->gvn_replace_by(uct, call); + uct->disconnect_inputs(NULL); + } + } + + void cleanup() { + // disconnect the hook node + _arguments->disconnect_inputs(NULL); + } +}; + + +void StringConcat::eliminate_unneeded_control() { + eliminate_initialize(begin()->initialization()); + for (uint i = 0; i < _control.size(); i++) { + Node* n = _control.at(i); + if (n->is_Call()) { + if (n != _end) { + eliminate_call(n->as_Call()); + } + } else if (n->is_IfTrue()) { + Compile* C = _stringopts->C; + C->gvn_replace_by(n, n->in(0)->in(0)); + C->gvn_replace_by(n->in(0), C->top()); + } + } +} + + +StringConcat* StringConcat::merge(StringConcat* other, Node* arg) { + StringConcat* result = new StringConcat(_stringopts, _end); + for (uint x = 0; x < _control.size(); x++) { + Node* n = _control.at(x); + if (n->is_Call()) { + result->_control.push(n); + } + } + for (uint x = 0; x < other->_control.size(); x++) { + Node* n = other->_control.at(x); + if (n->is_Call()) { + result->_control.push(n); + } + } + assert(result->_control.contains(other->_end), "what?"); + assert(result->_control.contains(_begin), "what?"); + for (int x = 0; x < num_arguments(); x++) { + if (argument(x) == arg) { + // replace the toString result with the all the arguments that + // made up the other StringConcat + for (int y = 0; y < other->num_arguments(); y++) { + result->append(other->argument(y), other->mode(y)); + } + } else { + result->append(argument(x), mode(x)); + } + } + result->set_allocation(other->_begin); + result->_multiple = true; + return result; +} + + +void StringConcat::eliminate_call(CallNode* call) { + Compile* C = _stringopts->C; + CallProjections projs; + call->extract_projections(&projs, false); + if (projs.fallthrough_catchproj != NULL) { + C->gvn_replace_by(projs.fallthrough_catchproj, call->in(TypeFunc::Control)); + } + if (projs.fallthrough_memproj != NULL) { + C->gvn_replace_by(projs.fallthrough_memproj, call->in(TypeFunc::Memory)); + } + if (projs.catchall_memproj != NULL) { + C->gvn_replace_by(projs.catchall_memproj, C->top()); + } + if (projs.fallthrough_ioproj != NULL) { + C->gvn_replace_by(projs.fallthrough_ioproj, call->in(TypeFunc::I_O)); + } + if (projs.catchall_ioproj != NULL) { + C->gvn_replace_by(projs.catchall_ioproj, C->top()); + } + if (projs.catchall_catchproj != NULL) { + // EA can't cope with the partially collapsed graph this + // creates so put it on the worklist to be collapsed later. + for (SimpleDUIterator i(projs.catchall_catchproj); i.has_next(); i.next()) { + Node *use = i.get(); + int opc = use->Opcode(); + if (opc == Op_CreateEx || opc == Op_Region) { + _stringopts->record_dead_node(use); + } + } + C->gvn_replace_by(projs.catchall_catchproj, C->top()); + } + if (projs.resproj != NULL) { + C->gvn_replace_by(projs.resproj, C->top()); + } + C->gvn_replace_by(call, C->top()); +} + +void StringConcat::eliminate_initialize(InitializeNode* init) { + Compile* C = _stringopts->C; + + // Eliminate Initialize node. + assert(init->outcnt() <= 2, "only a control and memory projection expected"); + assert(init->req() <= InitializeNode::RawStores, "no pending inits"); + Node *ctrl_proj = init->proj_out(TypeFunc::Control); + if (ctrl_proj != NULL) { + C->gvn_replace_by(ctrl_proj, init->in(TypeFunc::Control)); + } + Node *mem_proj = init->proj_out(TypeFunc::Memory); + if (mem_proj != NULL) { + Node *mem = init->in(TypeFunc::Memory); + C->gvn_replace_by(mem_proj, mem); + } + C->gvn_replace_by(init, C->top()); + init->disconnect_inputs(NULL); +} + +Node_List PhaseStringOpts::collect_toString_calls() { + Node_List string_calls; + Node_List worklist; + + _visited.Clear(); + + // Prime the worklist + for (uint i = 1; i < C->root()->len(); i++) { + Node* n = C->root()->in(i); + if (n != NULL && !_visited.test_set(n->_idx)) { + worklist.push(n); + } + } + + while (worklist.size() > 0) { + Node* ctrl = worklist.pop(); + if (ctrl->is_CallStaticJava()) { + CallStaticJavaNode* csj = ctrl->as_CallStaticJava(); + ciMethod* m = csj->method(); + if (m != NULL && + (m->intrinsic_id() == vmIntrinsics::_StringBuffer_toString || + m->intrinsic_id() == vmIntrinsics::_StringBuilder_toString)) { + string_calls.push(csj); + } + } + if (ctrl->in(0) != NULL && !_visited.test_set(ctrl->in(0)->_idx)) { + worklist.push(ctrl->in(0)); + } + if (ctrl->is_Region()) { + for (uint i = 1; i < ctrl->len(); i++) { + if (ctrl->in(i) != NULL && !_visited.test_set(ctrl->in(i)->_idx)) { + worklist.push(ctrl->in(i)); + } + } + } + } + return string_calls; +} + + +StringConcat* PhaseStringOpts::build_candidate(CallStaticJavaNode* call) { + ciMethod* m = call->method(); + ciSymbol* string_sig; + ciSymbol* int_sig; + ciSymbol* char_sig; + if (m->holder() == C->env()->StringBuilder_klass()) { + string_sig = ciSymbol::String_StringBuilder_signature(); + int_sig = ciSymbol::int_StringBuilder_signature(); + char_sig = ciSymbol::char_StringBuilder_signature(); + } else if (m->holder() == C->env()->StringBuffer_klass()) { + string_sig = ciSymbol::String_StringBuffer_signature(); + int_sig = ciSymbol::int_StringBuffer_signature(); + char_sig = ciSymbol::char_StringBuffer_signature(); + } else { + return NULL; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("considering toString call in "); + call->jvms()->dump_spec(tty); tty->cr(); + } +#endif + + StringConcat* sc = new StringConcat(this, call); + + AllocateNode* alloc = NULL; + InitializeNode* init = NULL; + + // possible opportunity for StringBuilder fusion + CallStaticJavaNode* cnode = call; + while (cnode) { + Node* recv = cnode->in(TypeFunc::Parms)->uncast(); + if (recv->is_Proj()) { + recv = recv->in(0); + } + cnode = recv->isa_CallStaticJava(); + if (cnode == NULL) { + alloc = recv->isa_Allocate(); + if (alloc == NULL) { + break; + } + // Find the constructor call + Node* result = alloc->result_cast(); + if (result == NULL || !result->is_CheckCastPP()) { + // strange looking allocation +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because allocation looks strange "); + alloc->jvms()->dump_spec(tty); tty->cr(); + } +#endif + break; + } + Node* constructor = NULL; + for (SimpleDUIterator i(result); i.has_next(); i.next()) { + CallStaticJavaNode *use = i.get()->isa_CallStaticJava(); + if (use != NULL && use->method() != NULL && + use->method()->name() == ciSymbol::object_initializer_name() && + use->method()->holder() == m->holder()) { + // Matched the constructor. + ciSymbol* sig = use->method()->signature()->as_symbol(); + if (sig == ciSymbol::void_method_signature() || + sig == ciSymbol::int_void_signature() || + sig == ciSymbol::string_void_signature()) { + if (sig == ciSymbol::string_void_signature()) { + // StringBuilder(String) so pick this up as the first argument + assert(use->in(TypeFunc::Parms + 1) != NULL, "what?"); + sc->push_string(use->in(TypeFunc::Parms + 1)); + } + // The int variant takes an initial size for the backing + // array so just treat it like the void version. + constructor = use; + } else { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("unexpected constructor signature: %s", sig->as_utf8()); + } +#endif + } + break; + } + } + if (constructor == NULL) { + // couldn't find constructor +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because couldn't find constructor "); + alloc->jvms()->dump_spec(tty); + } +#endif + break; + } + + // Walked all the way back and found the constructor call so see + // if this call converted into a direct string concatenation. + sc->add_control(call); + sc->add_control(constructor); + sc->add_control(alloc); + sc->set_allocation(alloc); + if (sc->validate_control_flow()) { + return sc; + } else { + return NULL; + } + } else if (cnode->method() == NULL) { + break; + } else if (cnode->method()->holder() == m->holder() && + cnode->method()->name() == ciSymbol::append_name() && + (cnode->method()->signature()->as_symbol() == string_sig || + cnode->method()->signature()->as_symbol() == char_sig || + cnode->method()->signature()->as_symbol() == int_sig)) { + sc->add_control(cnode); + Node* arg = cnode->in(TypeFunc::Parms + 1); + if (cnode->method()->signature()->as_symbol() == int_sig) { + sc->push_int(arg); + } else if (cnode->method()->signature()->as_symbol() == char_sig) { + sc->push_char(arg); + } else { + if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { + CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); + if (csj->method() != NULL && + csj->method()->holder() == C->env()->Integer_klass() && + csj->method()->name() == ciSymbol::toString_name()) { + sc->add_control(csj); + sc->push_int(csj->in(TypeFunc::Parms)); + continue; + } + } + sc->push_string(arg); + } + continue; + } else { + // some unhandled signature +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print("giving up because encountered unexpected signature "); + cnode->tf()->dump(); tty->cr(); + cnode->in(TypeFunc::Parms + 1)->dump(); + } +#endif + break; + } + } + return NULL; +} + + +PhaseStringOpts::PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List*): + Phase(StringOpts), + _gvn(gvn), + _visited(Thread::current()->resource_area()) { + + assert(OptimizeStringConcat, "shouldn't be here"); + + size_table_field = C->env()->Integer_klass()->get_field_by_name(ciSymbol::make("sizeTable"), + ciSymbol::make("[I"), true); + if (size_table_field == NULL) { + // Something wrong so give up. + assert(false, "why can't we find Integer.sizeTable?"); + return; + } + + // Collect the types needed to talk about the various slices of memory + const TypeInstPtr* string_type = TypeInstPtr::make(TypePtr::NotNull, C->env()->String_klass(), + false, NULL, 0); + + const TypePtr* value_field_type = string_type->add_offset(java_lang_String::value_offset_in_bytes()); + const TypePtr* offset_field_type = string_type->add_offset(java_lang_String::offset_offset_in_bytes()); + const TypePtr* count_field_type = string_type->add_offset(java_lang_String::count_offset_in_bytes()); + + value_field_idx = C->get_alias_index(value_field_type); + count_field_idx = C->get_alias_index(count_field_type); + offset_field_idx = C->get_alias_index(offset_field_type); + char_adr_idx = C->get_alias_index(TypeAryPtr::CHARS); + + // For each locally allocated StringBuffer see if the usages can be + // collapsed into a single String construction. + + // Run through the list of allocation looking for SB.toString to see + // if it's possible to fuse the usage of the SB into a single String + // construction. + GrowableArray concats; + Node_List toStrings = collect_toString_calls(); + while (toStrings.size() > 0) { + StringConcat* sc = build_candidate(toStrings.pop()->as_CallStaticJava()); + if (sc != NULL) { + concats.push(sc); + } + } + + // try to coalesce separate concats + restart: + for (int c = 0; c < concats.length(); c++) { + StringConcat* sc = concats.at(c); + for (int i = 0; i < sc->num_arguments(); i++) { + Node* arg = sc->argument(i); + if (arg->is_Proj() && arg->in(0)->is_CallStaticJava()) { + CallStaticJavaNode* csj = arg->in(0)->as_CallStaticJava(); + if (csj->method() != NULL && + (csj->method()->holder() == C->env()->StringBuffer_klass() || + csj->method()->holder() == C->env()->StringBuilder_klass()) && + csj->method()->name() == ciSymbol::toString_name()) { + for (int o = 0; o < concats.length(); o++) { + if (c == o) continue; + StringConcat* other = concats.at(o); + if (other->end() == csj) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("considering stacked concats"); + } +#endif + + StringConcat* merged = sc->merge(other, arg); + if (merged->validate_control_flow()) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("stacking would succeed"); + } +#endif + if (c < o) { + concats.remove_at(o); + concats.at_put(c, merged); + } else { + concats.remove_at(c); + concats.at_put(o, merged); + } + goto restart; + } else { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("stacking would fail"); + } +#endif + } + } + } + } + } + } + } + + + for (int c = 0; c < concats.length(); c++) { + StringConcat* sc = concats.at(c); + replace_string_concat(sc); + } + + remove_dead_nodes(); +} + +void PhaseStringOpts::record_dead_node(Node* dead) { + dead_worklist.push(dead); +} + +void PhaseStringOpts::remove_dead_nodes() { + // Delete any dead nodes to make things clean enough that escape + // analysis doesn't get unhappy. + while (dead_worklist.size() > 0) { + Node* use = dead_worklist.pop(); + int opc = use->Opcode(); + switch (opc) { + case Op_Region: { + uint i = 1; + for (i = 1; i < use->req(); i++) { + if (use->in(i) != C->top()) { + break; + } + } + if (i >= use->req()) { + for (SimpleDUIterator i(use); i.has_next(); i.next()) { + Node* m = i.get(); + if (m->is_Phi()) { + dead_worklist.push(m); + } + } + C->gvn_replace_by(use, C->top()); + } + break; + } + case Op_AddP: + case Op_CreateEx: { + // Recurisvely clean up references to CreateEx so EA doesn't + // get unhappy about the partially collapsed graph. + for (SimpleDUIterator i(use); i.has_next(); i.next()) { + Node* m = i.get(); + if (m->is_AddP()) { + dead_worklist.push(m); + } + } + C->gvn_replace_by(use, C->top()); + break; + } + case Op_Phi: + if (use->in(0) == C->top()) { + C->gvn_replace_by(use, C->top()); + } + break; + } + } +} + + +bool StringConcat::validate_control_flow() { + // We found all the calls and arguments now lets see if it's + // safe to transform the graph as we would expect. + + // Check to see if this resulted in too many uncommon traps previously + if (Compile::current()->too_many_traps(_begin->jvms()->method(), _begin->jvms()->bci(), + Deoptimization::Reason_intrinsic)) { + return false; + } + + // Walk backwards over the control flow from toString to the + // allocation and make sure all the control flow is ok. This + // means it's either going to be eliminated once the calls are + // removed or it can safely be transformed into an uncommon + // trap. + + int null_check_count = 0; + Unique_Node_List ctrl_path; + + assert(_control.contains(_begin), "missing"); + assert(_control.contains(_end), "missing"); + + // Collect the nodes that we know about and will eliminate into ctrl_path + for (uint i = 0; i < _control.size(); i++) { + // Push the call and it's control projection + Node* n = _control.at(i); + if (n->is_Allocate()) { + AllocateNode* an = n->as_Allocate(); + InitializeNode* init = an->initialization(); + ctrl_path.push(init); + ctrl_path.push(init->as_Multi()->proj_out(0)); + } + if (n->is_Call()) { + CallNode* cn = n->as_Call(); + ctrl_path.push(cn); + ctrl_path.push(cn->proj_out(0)); + ctrl_path.push(cn->proj_out(0)->unique_out()); + ctrl_path.push(cn->proj_out(0)->unique_out()->as_Catch()->proj_out(0)); + } else { + ShouldNotReachHere(); + } + } + + // Skip backwards through the control checking for unexpected contro flow + Node* ptr = _end; + bool fail = false; + while (ptr != _begin) { + if (ptr->is_Call() && ctrl_path.member(ptr)) { + ptr = ptr->in(0); + } else if (ptr->is_CatchProj() && ctrl_path.member(ptr)) { + ptr = ptr->in(0)->in(0)->in(0); + assert(ctrl_path.member(ptr), "should be a known piece of control"); + } else if (ptr->is_IfTrue()) { + IfNode* iff = ptr->in(0)->as_If(); + BoolNode* b = iff->in(1)->isa_Bool(); + Node* cmp = b->in(1); + Node* v1 = cmp->in(1); + Node* v2 = cmp->in(2); + Node* otherproj = iff->proj_out(1 - ptr->as_Proj()->_con); + + // Null check of the return of append which can simply be eliminated + if (b->_test._test == BoolTest::ne && + v2->bottom_type() == TypePtr::NULL_PTR && + v1->is_Proj() && ctrl_path.member(v1->in(0))) { + // NULL check of the return value of the append + null_check_count++; + if (otherproj->outcnt() == 1) { + CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); + if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) { + ctrl_path.push(call); + } + } + _control.push(ptr); + ptr = ptr->in(0)->in(0); + continue; + } + + // A test which leads to an uncommon trap which should be safe. + // Later this trap will be converted into a trap that restarts + // at the beginning. + if (otherproj->outcnt() == 1) { + CallStaticJavaNode* call = otherproj->unique_out()->isa_CallStaticJava(); + if (call != NULL && call->_name != NULL && strcmp(call->_name, "uncommon_trap") == 0) { + // control flow leads to uct so should be ok + _uncommon_traps.push(call); + ctrl_path.push(call); + ptr = ptr->in(0)->in(0); + continue; + } + } + +#ifndef PRODUCT + // Some unexpected control flow we don't know how to handle. + if (PrintOptimizeStringConcat) { + tty->print_cr("failing with unknown test"); + b->dump(); + cmp->dump(); + v1->dump(); + v2->dump(); + tty->cr(); + } +#endif + break; + } else if (ptr->is_Proj() && ptr->in(0)->is_Initialize()) { + ptr = ptr->in(0)->in(0); + } else if (ptr->is_Region()) { + Node* copy = ptr->as_Region()->is_copy(); + if (copy != NULL) { + ptr = copy; + continue; + } + if (ptr->req() == 3 && + ptr->in(1) != NULL && ptr->in(1)->is_Proj() && + ptr->in(2) != NULL && ptr->in(2)->is_Proj() && + ptr->in(1)->in(0) == ptr->in(2)->in(0) && + ptr->in(1)->in(0) != NULL && ptr->in(1)->in(0)->is_If()) { + // Simple diamond. + // XXX should check for possibly merging stores. simple data merges are ok. + ptr = ptr->in(1)->in(0)->in(0); + continue; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("fusion would fail for region"); + _begin->dump(); + ptr->dump(2); + } +#endif + fail = true; + break; + } else { + // other unknown control + if (!fail) { +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + tty->print_cr("fusion would fail for"); + _begin->dump(); + } +#endif + fail = true; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + ptr->dump(); + } +#endif + ptr = ptr->in(0); + } + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat && fail) { + tty->cr(); + } +#endif + if (fail) return !fail; + + // Validate that all these results produced are contained within + // this cluster of objects. First collect all the results produced + // by calls in the region. + _stringopts->_visited.Clear(); + Node_List worklist; + Node* final_result = _end->proj_out(TypeFunc::Parms); + for (uint i = 0; i < _control.size(); i++) { + CallNode* cnode = _control.at(i)->isa_Call(); + if (cnode != NULL) { + _stringopts->_visited.test_set(cnode->_idx); + } + Node* result = cnode != NULL ? cnode->proj_out(TypeFunc::Parms) : NULL; + if (result != NULL && result != final_result) { + worklist.push(result); + } + } + + Node* last_result = NULL; + while (worklist.size() > 0) { + Node* result = worklist.pop(); + if (_stringopts->_visited.test_set(result->_idx)) + continue; + for (SimpleDUIterator i(result); i.has_next(); i.next()) { + Node *use = i.get(); + if (ctrl_path.member(use)) { + // already checked this + continue; + } + int opc = use->Opcode(); + if (opc == Op_CmpP || opc == Op_Node) { + ctrl_path.push(use); + continue; + } + if (opc == Op_CastPP || opc == Op_CheckCastPP) { + for (SimpleDUIterator j(use); j.has_next(); j.next()) { + worklist.push(j.get()); + } + worklist.push(use->in(1)); + ctrl_path.push(use); + continue; + } +#ifndef PRODUCT + if (PrintOptimizeStringConcat) { + if (result != last_result) { + last_result = result; + tty->print_cr("extra uses for result:"); + last_result->dump(); + } + use->dump(); + } +#endif + fail = true; + break; + } + } + +#ifndef PRODUCT + if (PrintOptimizeStringConcat && !fail) { + ttyLocker ttyl; + tty->cr(); + tty->print("fusion would succeed (%d %d) for ", null_check_count, _uncommon_traps.size()); + _begin->jvms()->dump_spec(tty); tty->cr(); + for (int i = 0; i < num_arguments(); i++) { + argument(i)->dump(); + } + _control.dump(); + tty->cr(); + } +#endif + + return !fail; +} + +Node* PhaseStringOpts::fetch_static_field(GraphKit& kit, ciField* field) { + const TypeKlassPtr* klass_type = TypeKlassPtr::make(field->holder()); + Node* klass_node = __ makecon(klass_type); + BasicType bt = field->layout_type(); + ciType* field_klass = field->type(); + + const Type *type; + if( bt == T_OBJECT ) { + if (!field->type()->is_loaded()) { + type = TypeInstPtr::BOTTOM; + } else if (field->is_constant()) { + // This can happen if the constant oop is non-perm. + ciObject* con = field->constant_value().as_object(); + // Do not "join" in the previous type; it doesn't add value, + // and may yield a vacuous result if the field is of interface type. + type = TypeOopPtr::make_from_constant(con)->isa_oopptr(); + assert(type != NULL, "field singleton type must be consistent"); + } else { + type = TypeOopPtr::make_from_klass(field_klass->as_klass()); + } + } else { + type = Type::get_const_basic_type(bt); + } + + return kit.make_load(NULL, kit.basic_plus_adr(klass_node, field->offset_in_bytes()), + type, T_OBJECT, + C->get_alias_index(klass_type->add_offset(field->offset_in_bytes()))); +} + +Node* PhaseStringOpts::int_stringSize(GraphKit& kit, Node* arg) { + RegionNode *final_merge = new (C, 3) RegionNode(3); + kit.gvn().set_type(final_merge, Type::CONTROL); + Node* final_size = new (C, 3) PhiNode(final_merge, TypeInt::INT); + kit.gvn().set_type(final_size, TypeInt::INT); + + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + Node* is_min = __ IfFalse(iff); + final_merge->init_req(1, is_min); + final_size->init_req(1, __ intcon(11)); + + kit.set_control(__ IfTrue(iff)); + if (kit.stopped()) { + final_merge->init_req(2, C->top()); + final_size->init_req(2, C->top()); + } else { + + // int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i); + RegionNode *r = new (C, 3) RegionNode(3); + kit.gvn().set_type(r, Type::CONTROL); + Node *phi = new (C, 3) PhiNode(r, TypeInt::INT); + kit.gvn().set_type(phi, TypeInt::INT); + Node *size = new (C, 3) PhiNode(r, TypeInt::INT); + kit.gvn().set_type(size, TypeInt::INT); + Node* chk = __ CmpI(arg, __ intcon(0)); + Node* p = __ Bool(chk, BoolTest::lt); + IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_FAIR, COUNT_UNKNOWN); + Node* lessthan = __ IfTrue(iff); + Node* greaterequal = __ IfFalse(iff); + r->init_req(1, lessthan); + phi->init_req(1, __ SubI(__ intcon(0), arg)); + size->init_req(1, __ intcon(1)); + r->init_req(2, greaterequal); + phi->init_req(2, arg); + size->init_req(2, __ intcon(0)); + kit.set_control(r); + C->record_for_igvn(r); + C->record_for_igvn(phi); + C->record_for_igvn(size); + + // for (int i=0; ; i++) + // if (x <= sizeTable[i]) + // return i+1; + RegionNode *loop = new (C, 3) RegionNode(3); + loop->init_req(1, kit.control()); + kit.gvn().set_type(loop, Type::CONTROL); + + Node *index = new (C, 3) PhiNode(loop, TypeInt::INT); + index->init_req(1, __ intcon(0)); + kit.gvn().set_type(index, TypeInt::INT); + kit.set_control(loop); + Node* sizeTable = fetch_static_field(kit, size_table_field); + + Node* value = kit.load_array_element(NULL, sizeTable, index, TypeAryPtr::INTS); + C->record_for_igvn(value); + Node* limit = __ CmpI(phi, value); + Node* limitb = __ Bool(limit, BoolTest::le); + IfNode* iff2 = kit.create_and_map_if(kit.control(), limitb, PROB_MIN, COUNT_UNKNOWN); + Node* lessEqual = __ IfTrue(iff2); + Node* greater = __ IfFalse(iff2); + + loop->init_req(2, greater); + index->init_req(2, __ AddI(index, __ intcon(1))); + + kit.set_control(lessEqual); + C->record_for_igvn(loop); + C->record_for_igvn(index); + + final_merge->init_req(2, kit.control()); + final_size->init_req(2, __ AddI(__ AddI(index, size), __ intcon(1))); + } + + kit.set_control(final_merge); + C->record_for_igvn(final_merge); + C->record_for_igvn(final_size); + + return final_size; +} + +void PhaseStringOpts::int_getChars(GraphKit& kit, Node* arg, Node* char_array, Node* start, Node* end) { + RegionNode *final_merge = new (C, 4) RegionNode(4); + kit.gvn().set_type(final_merge, Type::CONTROL); + Node *final_mem = PhiNode::make(final_merge, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS); + kit.gvn().set_type(final_mem, Type::MEMORY); + + // need to handle Integer.MIN_VALUE specially because negating doesn't make it positive + { + // i == MIN_VALUE + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(arg, __ intcon(0x80000000)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + + Node* old_mem = kit.memory(char_adr_idx); + + kit.set_control(__ IfFalse(iff)); + if (kit.stopped()) { + // Statically not equal to MIN_VALUE so this path is dead + final_merge->init_req(3, kit.control()); + } else { + copy_string(kit, __ makecon(TypeInstPtr::make(C->env()->the_min_jint_string())), + char_array, start); + final_merge->init_req(3, kit.control()); + final_mem->init_req(3, kit.memory(char_adr_idx)); + } + + kit.set_control(__ IfTrue(iff)); + kit.set_memory(old_mem, char_adr_idx); + } + + + // Simplified version of Integer.getChars + + // int q, r; + // int charPos = index; + Node* charPos = end; + + // char sign = 0; + + Node* i = arg; + Node* sign = __ intcon(0); + + // if (i < 0) { + // sign = '-'; + // i = -i; + // } + { + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(arg, __ intcon(0)), BoolTest::lt), + PROB_FAIR, COUNT_UNKNOWN); + + RegionNode *merge = new (C, 3) RegionNode(3); + kit.gvn().set_type(merge, Type::CONTROL); + i = new (C, 3) PhiNode(merge, TypeInt::INT); + kit.gvn().set_type(i, TypeInt::INT); + sign = new (C, 3) PhiNode(merge, TypeInt::INT); + kit.gvn().set_type(sign, TypeInt::INT); + + merge->init_req(1, __ IfTrue(iff)); + i->init_req(1, __ SubI(__ intcon(0), arg)); + sign->init_req(1, __ intcon('-')); + merge->init_req(2, __ IfFalse(iff)); + i->init_req(2, arg); + sign->init_req(2, __ intcon(0)); + + kit.set_control(merge); + + C->record_for_igvn(merge); + C->record_for_igvn(i); + C->record_for_igvn(sign); + } + + // for (;;) { + // q = i / 10; + // r = i - ((q << 3) + (q << 1)); // r = i-(q*10) ... + // buf [--charPos] = digits [r]; + // i = q; + // if (i == 0) break; + // } + + { + RegionNode *head = new (C, 3) RegionNode(3); + head->init_req(1, kit.control()); + kit.gvn().set_type(head, Type::CONTROL); + Node *i_phi = new (C, 3) PhiNode(head, TypeInt::INT); + i_phi->init_req(1, i); + kit.gvn().set_type(i_phi, TypeInt::INT); + charPos = PhiNode::make(head, charPos); + kit.gvn().set_type(charPos, TypeInt::INT); + Node *mem = PhiNode::make(head, kit.memory(char_adr_idx), Type::MEMORY, TypeAryPtr::CHARS); + kit.gvn().set_type(mem, Type::MEMORY); + kit.set_control(head); + kit.set_memory(mem, char_adr_idx); + + Node* q = __ DivI(kit.null(), i_phi, __ intcon(10)); + Node* r = __ SubI(i_phi, __ AddI(__ LShiftI(q, __ intcon(3)), + __ LShiftI(q, __ intcon(1)))); + Node* m1 = __ SubI(charPos, __ intcon(1)); + Node* ch = __ AddI(r, __ intcon('0')); + + Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR), + ch, T_CHAR, char_adr_idx); + + + IfNode* iff = kit.create_and_map_if(head, __ Bool(__ CmpI(q, __ intcon(0)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + Node* ne = __ IfTrue(iff); + Node* eq = __ IfFalse(iff); + + head->init_req(2, ne); + mem->init_req(2, st); + i_phi->init_req(2, q); + charPos->init_req(2, m1); + + charPos = m1; + + kit.set_control(eq); + kit.set_memory(st, char_adr_idx); + + C->record_for_igvn(head); + C->record_for_igvn(mem); + C->record_for_igvn(i_phi); + C->record_for_igvn(charPos); + } + + { + // if (sign != 0) { + // buf [--charPos] = sign; + // } + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(sign, __ intcon(0)), BoolTest::ne), + PROB_FAIR, COUNT_UNKNOWN); + + final_merge->init_req(2, __ IfFalse(iff)); + final_mem->init_req(2, kit.memory(char_adr_idx)); + + kit.set_control(__ IfTrue(iff)); + if (kit.stopped()) { + final_merge->init_req(1, C->top()); + final_mem->init_req(1, C->top()); + } else { + Node* m1 = __ SubI(charPos, __ intcon(1)); + Node* st = __ store_to_memory(kit.control(), kit.array_element_address(char_array, m1, T_CHAR), + sign, T_CHAR, char_adr_idx); + + final_merge->init_req(1, kit.control()); + final_mem->init_req(1, st); + } + + kit.set_control(final_merge); + kit.set_memory(final_mem, char_adr_idx); + + C->record_for_igvn(final_merge); + C->record_for_igvn(final_mem); + } +} + + +Node* PhaseStringOpts::copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start) { + Node* string = str; + Node* offset = kit.make_load(NULL, + kit.basic_plus_adr(string, string, java_lang_String::offset_offset_in_bytes()), + TypeInt::INT, T_INT, offset_field_idx); + Node* count = kit.make_load(NULL, + kit.basic_plus_adr(string, string, java_lang_String::count_offset_in_bytes()), + TypeInt::INT, T_INT, count_field_idx); + const TypeAryPtr* value_type = TypeAryPtr::make(TypePtr::NotNull, + TypeAry::make(TypeInt::CHAR,TypeInt::POS), + ciTypeArrayKlass::make(T_CHAR), true, 0); + Node* value = kit.make_load(NULL, + kit.basic_plus_adr(string, string, java_lang_String::value_offset_in_bytes()), + value_type, T_OBJECT, value_field_idx); + + // copy the contents + if (offset->is_Con() && count->is_Con() && value->is_Con() && count->get_int() < unroll_string_copy_length) { + // For small constant strings just emit individual stores. + // A length of 6 seems like a good space/speed tradeof. + int c = count->get_int(); + int o = offset->get_int(); + const TypeOopPtr* t = kit.gvn().type(value)->isa_oopptr(); + ciTypeArray* value_array = t->const_oop()->as_type_array(); + for (int e = 0; e < c; e++) { + __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR), + __ intcon(value_array->char_at(o + e)), T_CHAR, char_adr_idx); + start = __ AddI(start, __ intcon(1)); + } + } else { + Node* src_ptr = kit.array_element_address(value, offset, T_CHAR); + Node* dst_ptr = kit.array_element_address(char_array, start, T_CHAR); + Node* c = count; + Node* extra = NULL; +#ifdef _LP64 + c = __ ConvI2L(c); + extra = C->top(); +#endif + Node* call = kit.make_runtime_call(GraphKit::RC_LEAF|GraphKit::RC_NO_FP, + OptoRuntime::fast_arraycopy_Type(), + CAST_FROM_FN_PTR(address, StubRoutines::jshort_disjoint_arraycopy()), + "jshort_disjoint_arraycopy", TypeAryPtr::CHARS, + src_ptr, dst_ptr, c, extra); + start = __ AddI(start, count); + } + return start; +} + + +void PhaseStringOpts::replace_string_concat(StringConcat* sc) { + // Log a little info about the transformation + sc->maybe_log_transform(); + + // pull the JVMState of the allocation into a SafePointNode to serve as + // as a shim for the insertion of the new code. + JVMState* jvms = sc->begin()->jvms()->clone_shallow(C); + uint size = sc->begin()->req(); + SafePointNode* map = new (C, size) SafePointNode(size, jvms); + + // copy the control and memory state from the final call into our + // new starting state. This allows any preceeding tests to feed + // into the new section of code. + for (uint i1 = 0; i1 < TypeFunc::Parms; i1++) { + map->init_req(i1, sc->end()->in(i1)); + } + // blow away old allocation arguments + for (uint i1 = TypeFunc::Parms; i1 < jvms->debug_start(); i1++) { + map->init_req(i1, C->top()); + } + // Copy the rest of the inputs for the JVMState + for (uint i1 = jvms->debug_start(); i1 < sc->begin()->req(); i1++) { + map->init_req(i1, sc->begin()->in(i1)); + } + // Make sure the memory state is a MergeMem for parsing. + if (!map->in(TypeFunc::Memory)->is_MergeMem()) { + map->set_req(TypeFunc::Memory, MergeMemNode::make(C, map->in(TypeFunc::Memory))); + } + + jvms->set_map(map); + map->ensure_stack(jvms, jvms->method()->max_stack()); + + + // disconnect all the old StringBuilder calls from the graph + sc->eliminate_unneeded_control(); + + // At this point all the old work has been completely removed from + // the graph and the saved JVMState exists at the point where the + // final toString call used to be. + GraphKit kit(jvms); + + // There may be uncommon traps which are still using the + // intermediate states and these need to be rewritten to point at + // the JVMState at the beginning of the transformation. + sc->convert_uncommon_traps(kit, jvms); + + // Now insert the logic to compute the size of the string followed + // by all the logic to construct array and resulting string. + + Node* null_string = __ makecon(TypeInstPtr::make(C->env()->the_null_string())); + + // Create a region for the overflow checks to merge into. + int args = MAX2(sc->num_arguments(), 1); + RegionNode* overflow = new (C, args) RegionNode(args); + kit.gvn().set_type(overflow, Type::CONTROL); + + // Create a hook node to hold onto the individual sizes since they + // are need for the copying phase. + Node* string_sizes = new (C, args) Node(args); + + Node* length = __ intcon(0); + for (int argi = 0; argi < sc->num_arguments(); argi++) { + Node* arg = sc->argument(argi); + switch (sc->mode(argi)) { + case StringConcat::IntMode: { + Node* string_size = int_stringSize(kit, arg); + + // accumulate total + length = __ AddI(length, string_size); + + // Cache this value for the use by int_toString + string_sizes->init_req(argi, string_size); + break; + } + case StringConcat::StringMode: { + const Type* type = kit.gvn().type(arg); + if (type == TypePtr::NULL_PTR) { + // replace the argument with the null checked version + arg = null_string; + sc->set_argument(argi, arg); + } else if (!type->higher_equal(TypeInstPtr::NOTNULL)) { + // s = s != null ? s : "null"; + // length = length + (s.count - s.offset); + RegionNode *r = new (C, 3) RegionNode(3); + kit.gvn().set_type(r, Type::CONTROL); + Node *phi = new (C, 3) PhiNode(r, type->join(TypeInstPtr::NOTNULL)); + kit.gvn().set_type(phi, phi->bottom_type()); + Node* p = __ Bool(__ CmpP(arg, kit.null()), BoolTest::ne); + IfNode* iff = kit.create_and_map_if(kit.control(), p, PROB_MIN, COUNT_UNKNOWN); + Node* notnull = __ IfTrue(iff); + Node* isnull = __ IfFalse(iff); + r->init_req(1, notnull); + phi->init_req(1, arg); + r->init_req(2, isnull); + phi->init_req(2, null_string); + kit.set_control(r); + C->record_for_igvn(r); + C->record_for_igvn(phi); + // replace the argument with the null checked version + arg = phi; + sc->set_argument(argi, arg); + } + // Node* offset = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, offset_offset), + // TypeInt::INT, T_INT, offset_field_idx); + Node* count = kit.make_load(NULL, kit.basic_plus_adr(arg, arg, java_lang_String::count_offset_in_bytes()), + TypeInt::INT, T_INT, count_field_idx); + length = __ AddI(length, count); + string_sizes->init_req(argi, NULL); + break; + } + case StringConcat::CharMode: { + // one character only + length = __ AddI(length, __ intcon(1)); + break; + } + default: + ShouldNotReachHere(); + } + if (argi > 0) { + // Check that the sum hasn't overflowed + IfNode* iff = kit.create_and_map_if(kit.control(), + __ Bool(__ CmpI(length, __ intcon(0)), BoolTest::lt), + PROB_MIN, COUNT_UNKNOWN); + kit.set_control(__ IfFalse(iff)); + overflow->set_req(argi, __ IfTrue(iff)); + } + } + + { + // Hook + PreserveJVMState pjvms(&kit); + kit.set_control(overflow); + kit.uncommon_trap(Deoptimization::Reason_intrinsic, + Deoptimization::Action_make_not_entrant); + } + + // length now contains the number of characters needed for the + // char[] so create a new AllocateArray for the char[] + Node* char_array = NULL; + { + PreserveReexecuteState preexecs(&kit); + // The original jvms is for an allocation of either a String or + // StringBuffer so no stack adjustment is necessary for proper + // reexecution. If we deoptimize in the slow path the bytecode + // will be reexecuted and the char[] allocation will be thrown away. + kit.jvms()->set_should_reexecute(true); + char_array = kit.new_array(__ makecon(TypeKlassPtr::make(ciTypeArrayKlass::make(T_CHAR))), + length, 1); + } + + // Mark the allocation so that zeroing is skipped since the code + // below will overwrite the entire array + AllocateArrayNode* char_alloc = AllocateArrayNode::Ideal_array_allocation(char_array, _gvn); + char_alloc->maybe_set_complete(_gvn); + + // Now copy the string representations into the final char[] + Node* start = __ intcon(0); + for (int argi = 0; argi < sc->num_arguments(); argi++) { + Node* arg = sc->argument(argi); + switch (sc->mode(argi)) { + case StringConcat::IntMode: { + Node* end = __ AddI(start, string_sizes->in(argi)); + // getChars words backwards so pass the ending point as well as the start + int_getChars(kit, arg, char_array, start, end); + start = end; + break; + } + case StringConcat::StringMode: { + start = copy_string(kit, arg, char_array, start); + break; + } + case StringConcat::CharMode: { + __ store_to_memory(kit.control(), kit.array_element_address(char_array, start, T_CHAR), + arg, T_CHAR, char_adr_idx); + start = __ AddI(start, __ intcon(1)); + break; + } + default: + ShouldNotReachHere(); + } + } + + // If we're not reusing an existing String allocation then allocate one here. + Node* result = sc->string_alloc(); + if (result == NULL) { + PreserveReexecuteState preexecs(&kit); + // The original jvms is for an allocation of either a String or + // StringBuffer so no stack adjustment is necessary for proper + // reexecution. + kit.jvms()->set_should_reexecute(true); + result = kit.new_instance(__ makecon(TypeKlassPtr::make(C->env()->String_klass()))); + } + + // Intialize the string + kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::offset_offset_in_bytes()), + __ intcon(0), T_INT, offset_field_idx); + kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::count_offset_in_bytes()), + length, T_INT, count_field_idx); + kit.store_to_memory(kit.control(), kit.basic_plus_adr(result, java_lang_String::value_offset_in_bytes()), + char_array, T_OBJECT, value_field_idx); + + // hook up the outgoing control and result + kit.replace_call(sc->end(), result); + + // Unhook any hook nodes + string_sizes->disconnect_inputs(NULL); + sc->cleanup(); +} diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/stringopts.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/opto/stringopts.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,83 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class StringConcat; + +class PhaseStringOpts : public Phase { + friend class StringConcat; + + private: + PhaseGVN* _gvn; + + // List of dead nodes to clean up aggressively at the end + Unique_Node_List dead_worklist; + + // Memory slices needed for code gen + int char_adr_idx; + int value_field_idx; + int count_field_idx; + int offset_field_idx; + + // Integer.sizeTable - used for int to String conversion + ciField* size_table_field; + + // A set for use by various stages + VectorSet _visited; + + // Collect a list of all SB.toString calls + Node_List collect_toString_calls(); + + // Examine the use of the SB alloc to see if it can be replace with + // a single string construction. + StringConcat* build_candidate(CallStaticJavaNode* call); + + // Replace all the SB calls in concat with an optimization String allocation + void replace_string_concat(StringConcat* concat); + + // Load the value of a static field, performing any constant folding. + Node* fetch_static_field(GraphKit& kit, ciField* field); + + // Compute the number of characters required to represent the int value + Node* int_stringSize(GraphKit& kit, Node* value); + + // Copy the characters representing value into char_array starting at start + void int_getChars(GraphKit& kit, Node* value, Node* char_array, Node* start, Node* end); + + // Copy of the contents of the String str into char_array starting at index start. + Node* copy_string(GraphKit& kit, Node* str, Node* char_array, Node* start); + + // Clean up any leftover nodes + void record_dead_node(Node* node); + void remove_dead_nodes(); + + PhaseGVN* gvn() { return _gvn; } + + enum { + // max length of constant string copy unrolling in copy_string + unroll_string_copy_length = 6 + }; + + public: + PhaseStringOpts(PhaseGVN* gvn, Unique_Node_List* worklist); +}; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/superword.cpp --- a/src/share/vm/opto/superword.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/superword.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -1921,6 +1921,11 @@ } // Match AddP(base, AddP(ptr, k*iv [+ invariant]), constant) Node* base = adr->in(AddPNode::Base); + //unsafe reference could not be aligned appropriately without runtime checking + if (base == NULL || base->bottom_type() == Type::TOP) { + assert(!valid(), "unsafe access"); + return; + } for (int i = 0; i < 3; i++) { if (!scaled_iv_plus_offset(adr->in(AddPNode::Offset))) { assert(!valid(), "too complex"); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/opto/type.hpp --- a/src/share/vm/opto/type.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/opto/type.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -847,9 +847,6 @@ // Constant pointer to array static const TypeAryPtr *make( PTR ptr, ciObject* o, const TypeAry *ary, ciKlass* k, bool xk, int offset, int instance_id = InstanceBot); - // Convenience - static const TypeAryPtr *make(ciObject* o); - // Return a 'ptr' version of this type virtual const Type *cast_to_ptr_type(PTR ptr) const; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/prims/jni.cpp --- a/src/share/vm/prims/jni.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/prims/jni.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -3231,6 +3231,21 @@ jint result = JNI_ERR; DT_RETURN_MARK(CreateJavaVM, jint, (const jint&)result); + // We're about to use Atomic::xchg for synchronization. Some Zero + // platforms use the GCC builtin __sync_lock_test_and_set for this, + // but __sync_lock_test_and_set is not guaranteed to do what we want + // on all architectures. So we check it works before relying on it. +#if defined(ZERO) && defined(ASSERT) + { + jint a = 0xcafebabe; + jint b = Atomic::xchg(0xdeadbeef, &a); + void *c = &a; + void *d = Atomic::xchg_ptr(&b, &c); + assert(a == 0xdeadbeef && b == (jint) 0xcafebabe, "Atomic::xchg() works"); + assert(c == &b && d == &a, "Atomic::xchg_ptr() works"); + } +#endif // ZERO && ASSERT + // At the moment it's only possible to have one Java VM, // since some of the runtime state is in global variables. diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/prims/jvm.cpp --- a/src/share/vm/prims/jvm.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/prims/jvm.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -2257,10 +2257,8 @@ switch (cp->tag_at(cp_index).value()) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Methodref: + case JVM_CONSTANT_NameAndType: // for invokedynamic return cp->uncached_name_ref_at(cp_index)->as_utf8(); - case JVM_CONSTANT_NameAndType: - // for invokedynamic - return cp->nt_name_ref_at(cp_index)->as_utf8(); default: fatal("JVM_GetCPMethodNameUTF: illegal constant"); } @@ -2277,10 +2275,8 @@ switch (cp->tag_at(cp_index).value()) { case JVM_CONSTANT_InterfaceMethodref: case JVM_CONSTANT_Methodref: + case JVM_CONSTANT_NameAndType: // for invokedynamic return cp->uncached_signature_ref_at(cp_index)->as_utf8(); - case JVM_CONSTANT_NameAndType: - // for invokedynamic - return cp->nt_signature_ref_at(cp_index)->as_utf8(); default: fatal("JVM_GetCPMethodSignatureUTF: illegal constant"); } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/prims/jvmtiManageCapabilities.cpp --- a/src/share/vm/prims/jvmtiManageCapabilities.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/prims/jvmtiManageCapabilities.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -115,8 +115,10 @@ jvmtiCapabilities jc; memset(&jc, 0, sizeof(jc)); +#ifndef CC_INTERP jc.can_pop_frame = 1; jc.can_force_early_return = 1; +#endif // !CC_INTERP jc.can_get_source_debug_extension = 1; jc.can_access_local_variables = 1; jc.can_maintain_original_method_order = 1; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/prims/methodHandles.cpp --- a/src/share/vm/prims/methodHandles.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/prims/methodHandles.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -2347,9 +2347,9 @@ JVM_ENTRY(void, MH_linkCallSite(JNIEnv *env, jobject igcls, jobject site_jh, jobject target_jh)) { // No special action required, yet. oop site_oop = JNIHandles::resolve(site_jh); - if (site_oop == NULL || site_oop->klass() != SystemDictionary::CallSiteImpl_klass()) + if (site_oop == NULL || site_oop->klass() != SystemDictionary::CallSite_klass()) THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "call site"); - sun_dyn_CallSiteImpl::set_target(site_oop, JNIHandles::resolve(target_jh)); + java_dyn_CallSite::set_target(site_oop, JNIHandles::resolve(target_jh)); } JVM_END @@ -2365,6 +2365,7 @@ #define OBJ LANG"Object;" #define CLS LANG"Class;" #define STRG LANG"String;" +#define CST JDYN"CallSite;" #define MT JDYN"MethodType;" #define MH JDYN"MethodHandle;" #define MHI IDYN"MethodHandleImpl;" @@ -2372,7 +2373,6 @@ #define AMH IDYN"AdapterMethodHandle;" #define BMH IDYN"BoundMethodHandle;" #define DMH IDYN"DirectMethodHandle;" -#define CSTI IDYN"CallSiteImpl;" #define CC (char*) /*cast a literal from (const char*)*/ #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) @@ -2398,7 +2398,7 @@ // More entry points specifically for EnableInvokeDynamic. static JNINativeMethod methods2[] = { - {CC"linkCallSite", CC"("CSTI MH")V", FN_PTR(MH_linkCallSite)} + {CC"linkCallSite", CC"("CST MH")V", FN_PTR(MH_linkCallSite)} }; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/runtime/arguments.cpp --- a/src/share/vm/runtime/arguments.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/runtime/arguments.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -37,7 +37,6 @@ const char* Arguments::_gc_log_filename = NULL; bool Arguments::_has_profile = false; bool Arguments::_has_alloc_profile = false; -uintx Arguments::_initial_heap_size = 0; uintx Arguments::_min_heap_size = 0; Arguments::Mode Arguments::_mode = _mixed; bool Arguments::_java_compiler = false; @@ -182,6 +181,9 @@ { "ProcessingToTenuringRatio", JDK_Version::jdk(5), JDK_Version::jdk(7) }, { "MinTrainLength", JDK_Version::jdk(5), JDK_Version::jdk(7) }, { "AppendRatio", JDK_Version::jdk_update(6,10), JDK_Version::jdk(7) }, + { "DefaultMaxRAM", JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, + { "DefaultInitialRAMFraction", + JDK_Version::jdk_update(6,18), JDK_Version::jdk(7) }, { NULL, JDK_Version(0), JDK_Version(0) } }; @@ -555,6 +557,10 @@ if (!is_neg && CommandLineFlags::uintxAtPut(name, &uintx_v, origin)) { return true; } + uint64_t uint64_t_v = (uint64_t) v; + if (!is_neg && CommandLineFlags::uint64_tAtPut(name, &uint64_t_v, origin)) { + return true; + } return false; } @@ -947,7 +953,7 @@ // UseParNewGC and not explicitly set ParallelGCThreads we // set it, unless this is a single cpu machine. void Arguments::set_parnew_gc_flags() { - assert(!UseSerialGC && !UseParallelGC && !UseG1GC, + assert(!UseSerialGC && !UseParallelOldGC && !UseParallelGC && !UseG1GC, "control point invariant"); assert(UseParNewGC, "Error"); @@ -960,13 +966,13 @@ if (ParallelGCThreads == 0) { FLAG_SET_DEFAULT(ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads()); - if (FLAG_IS_DEFAULT(ParallelGCThreads) && ParallelGCThreads == 1) { + if (ParallelGCThreads == 1) { FLAG_SET_DEFAULT(UseParNewGC, false); + FLAG_SET_DEFAULT(ParallelGCThreads, 0); } } - if (!UseParNewGC) { - FLAG_SET_DEFAULT(ParallelGCThreads, 0); - } else { + if (UseParNewGC) { + // CDS doesn't work with ParNew yet no_shared_spaces(); // By default YoungPLABSize and OldPLABSize are set to 4096 and 1024 respectively, @@ -980,7 +986,7 @@ FLAG_SET_DEFAULT(OldPLABSize, (intx)1024); } - // AlwaysTenure flag should make ParNew to promote all at first collection. + // AlwaysTenure flag should make ParNew promote all at first collection. // See CR 6362902. if (AlwaysTenure) { FLAG_SET_CMDLINE(intx, MaxTenuringThreshold, 0); @@ -1003,7 +1009,7 @@ // further optimization and tuning efforts, and would almost // certainly gain from analysis of platform and environment. void Arguments::set_cms_and_parnew_gc_flags() { - assert(!UseSerialGC && !UseParallelGC, "Error"); + assert(!UseSerialGC && !UseParallelOldGC && !UseParallelGC, "Error"); assert(UseConcMarkSweepGC, "CMS is expected to be on here"); // If we are using CMS, we prefer to UseParNewGC, @@ -1068,7 +1074,7 @@ } else { FLAG_SET_ERGO(uintx, MaxNewSize, preferred_max_new_size); } - if(PrintGCDetails && Verbose) { + if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty tty->print_cr("Ergo set MaxNewSize: " SIZE_FORMAT, MaxNewSize); } @@ -1097,15 +1103,15 @@ } else { min_new = NewSize; } - size_t prev_initial_size = initial_heap_size(); - if (prev_initial_size != 0 && prev_initial_size < min_new+OldSize) { - set_initial_heap_size(min_new+OldSize); + size_t prev_initial_size = InitialHeapSize; + if (prev_initial_size != 0 && prev_initial_size < min_new + OldSize) { + FLAG_SET_ERGO(uintx, InitialHeapSize, min_new + OldSize); // Currently minimum size and the initial heap sizes are the same. - set_min_heap_size(initial_heap_size()); + set_min_heap_size(InitialHeapSize); if (PrintGCDetails && Verbose) { warning("Initial heap size increased to " SIZE_FORMAT " M from " SIZE_FORMAT " M; use -XX:NewSize=... for finer control.", - initial_heap_size()/M, prev_initial_size/M); + InitialHeapSize/M, prev_initial_size/M); } } @@ -1114,12 +1120,12 @@ align_size_down(MaxHeapSize, CardTableRS::ct_max_alignment_constraint()); - if(PrintGCDetails && Verbose) { + if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty tty->print_cr("CMS set min_heap_size: " SIZE_FORMAT " initial_heap_size: " SIZE_FORMAT " max_heap: " SIZE_FORMAT, - min_heap_size(), initial_heap_size(), max_heap); + min_heap_size(), InitialHeapSize, max_heap); } if (max_heap > min_new) { // Unless explicitly requested otherwise, make young gen @@ -1127,7 +1133,7 @@ if (FLAG_IS_DEFAULT(NewSize)) { FLAG_SET_ERGO(uintx, NewSize, MAX2(NewSize, min_new)); FLAG_SET_ERGO(uintx, NewSize, MIN2(preferred_max_new_size, NewSize)); - if(PrintGCDetails && Verbose) { + if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty tty->print_cr("Ergo set NewSize: " SIZE_FORMAT, NewSize); } @@ -1137,8 +1143,8 @@ // later NewRatio will decide how it grows; see above. if (FLAG_IS_DEFAULT(OldSize)) { if (max_heap > NewSize) { - FLAG_SET_ERGO(uintx, OldSize, MIN2(3*NewSize, max_heap - NewSize)); - if(PrintGCDetails && Verbose) { + FLAG_SET_ERGO(uintx, OldSize, MIN2(3*NewSize, max_heap - NewSize)); + if (PrintGCDetails && Verbose) { // Too early to use gclog_or_tty tty->print_cr("Ergo set OldSize: " SIZE_FORMAT, OldSize); } @@ -1186,7 +1192,7 @@ inline uintx max_heap_for_compressed_oops() { LP64_ONLY(return oopDesc::OopEncodingHeapMax - MaxPermSize - os::vm_page_size()); - NOT_LP64(return DefaultMaxRAM); + NOT_LP64(ShouldNotReachHere(); return 0); } bool Arguments::should_auto_select_low_pause_collector() { @@ -1205,7 +1211,7 @@ void Arguments::set_ergonomics_flags() { // Parallel GC is not compatible with sharing. If one specifies - // that they want sharing explicitly, do not set ergonmics flags. + // that they want sharing explicitly, do not set ergonomics flags. if (DumpSharedSpaces || ForceSharedSpaces) { return; } @@ -1234,9 +1240,11 @@ // Check that UseCompressedOops can be set with the max heap size allocated // by ergonomics. if (MaxHeapSize <= max_heap_for_compressed_oops()) { +#ifndef COMPILER1 if (FLAG_IS_DEFAULT(UseCompressedOops) && !UseG1GC) { FLAG_SET_ERGO(bool, UseCompressedOops, true); } +#endif #ifdef _WIN64 if (UseLargePages && UseCompressedOops) { // Cannot allocate guard pages for implicit checks in indexed addressing @@ -1271,8 +1279,6 @@ FLAG_SET_ERGO(uintx, ParallelGCThreads, Abstract_VM_Version::parallel_worker_threads()); - // PS is a server collector, setup the heap sizes accordingly. - set_server_heap_size(); // If InitialSurvivorRatio or MinSurvivorRatio were not specified, but the // SurvivorRatio has been set, reset their default values to SurvivorRatio + // 2. By doing this we make SurvivorRatio also work for Parallel Scavenger. @@ -1302,8 +1308,6 @@ void Arguments::set_g1_gc_flags() { assert(UseG1GC, "Error"); - // G1 is a server collector, setup the heap sizes accordingly. - set_server_heap_size(); #ifdef COMPILER1 FastTLABRefill = false; #endif @@ -1321,50 +1325,79 @@ } } -void Arguments::set_server_heap_size() { +void Arguments::set_heap_size() { + if (!FLAG_IS_DEFAULT(DefaultMaxRAMFraction)) { + // Deprecated flag + FLAG_SET_CMDLINE(uintx, MaxRAMFraction, DefaultMaxRAMFraction); + } + + const julong phys_mem = + FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM) + : (julong)MaxRAM; + + // If the maximum heap size has not been set with -Xmx, + // then set it as fraction of the size of physical memory, + // respecting the maximum and minimum sizes of the heap. if (FLAG_IS_DEFAULT(MaxHeapSize)) { - const uint64_t reasonable_fraction = - os::physical_memory() / DefaultMaxRAMFraction; - const uint64_t maximum_size = (uint64_t) - (FLAG_IS_DEFAULT(DefaultMaxRAM) && UseCompressedOops ? - MIN2(max_heap_for_compressed_oops(), DefaultMaxRAM) : - DefaultMaxRAM); - size_t reasonable_max = - (size_t) os::allocatable_physical_memory(reasonable_fraction); - if (reasonable_max > maximum_size) { - reasonable_max = maximum_size; + julong reasonable_max = phys_mem / MaxRAMFraction; + + if (phys_mem <= MaxHeapSize * MinRAMFraction) { + // Small physical memory, so use a minimum fraction of it for the heap + reasonable_max = phys_mem / MinRAMFraction; + } else { + // Not-small physical memory, so require a heap at least + // as large as MaxHeapSize + reasonable_max = MAX2(reasonable_max, (julong)MaxHeapSize); + } + if (!FLAG_IS_DEFAULT(ErgoHeapSizeLimit) && ErgoHeapSizeLimit != 0) { + // Limit the heap size to ErgoHeapSizeLimit + reasonable_max = MIN2(reasonable_max, (julong)ErgoHeapSizeLimit); } + if (UseCompressedOops) { + // Limit the heap size to the maximum possible when using compressed oops + reasonable_max = MIN2(reasonable_max, (julong)max_heap_for_compressed_oops()); + } + reasonable_max = os::allocatable_physical_memory(reasonable_max); + + if (!FLAG_IS_DEFAULT(InitialHeapSize)) { + // An initial heap size was specified on the command line, + // so be sure that the maximum size is consistent. Done + // after call to allocatable_physical_memory because that + // method might reduce the allocation size. + reasonable_max = MAX2(reasonable_max, (julong)InitialHeapSize); + } + if (PrintGCDetails && Verbose) { // Cannot use gclog_or_tty yet. - tty->print_cr(" Max heap size for server class platform " - SIZE_FORMAT, reasonable_max); + tty->print_cr(" Maximum heap size " SIZE_FORMAT, reasonable_max); } - // If the initial_heap_size has not been set with -Xms, - // then set it as fraction of size of physical memory - // respecting the maximum and minimum sizes of the heap. - if (initial_heap_size() == 0) { - const uint64_t reasonable_initial_fraction = - os::physical_memory() / DefaultInitialRAMFraction; - const size_t reasonable_initial = - (size_t) os::allocatable_physical_memory(reasonable_initial_fraction); - const size_t minimum_size = NewSize + OldSize; - set_initial_heap_size(MAX2(MIN2(reasonable_initial, reasonable_max), - minimum_size)); - // Currently the minimum size and the initial heap sizes are the same. - set_min_heap_size(initial_heap_size()); - if (PrintGCDetails && Verbose) { - // Cannot use gclog_or_tty yet. - tty->print_cr(" Initial heap size for server class platform " - SIZE_FORMAT, initial_heap_size()); - } - } else { - // A minimum size was specified on the command line. Be sure - // that the maximum size is consistent. - if (initial_heap_size() > reasonable_max) { - reasonable_max = initial_heap_size(); - } + FLAG_SET_ERGO(uintx, MaxHeapSize, (uintx)reasonable_max); + } + + // If the initial_heap_size has not been set with InitialHeapSize + // or -Xms, then set it as fraction of the size of physical memory, + // respecting the maximum and minimum sizes of the heap. + if (FLAG_IS_DEFAULT(InitialHeapSize)) { + julong reasonable_minimum = (julong)(OldSize + NewSize); + + reasonable_minimum = MIN2(reasonable_minimum, (julong)MaxHeapSize); + + reasonable_minimum = os::allocatable_physical_memory(reasonable_minimum); + + julong reasonable_initial = phys_mem / InitialRAMFraction; + + reasonable_initial = MAX2(reasonable_initial, reasonable_minimum); + reasonable_initial = MIN2(reasonable_initial, (julong)MaxHeapSize); + + reasonable_initial = os::allocatable_physical_memory(reasonable_initial); + + if (PrintGCDetails && Verbose) { + // Cannot use gclog_or_tty yet. + tty->print_cr(" Initial heap size " SIZE_FORMAT, (uintx)reasonable_initial); + tty->print_cr(" Minimum heap size " SIZE_FORMAT, (uintx)reasonable_minimum); } - FLAG_SET_ERGO(uintx, MaxHeapSize, (uintx) reasonable_max); + FLAG_SET_ERGO(uintx, InitialHeapSize, (uintx)reasonable_initial); + set_min_heap_size((uintx)reasonable_minimum); } } @@ -1448,7 +1481,7 @@ return false; } -static void set_serial_gc_flags() { +static void force_serial_gc() { FLAG_SET_DEFAULT(UseSerialGC, true); FLAG_SET_DEFAULT(UseParNewGC, false); FLAG_SET_DEFAULT(UseConcMarkSweepGC, false); @@ -1584,15 +1617,15 @@ // force sharing off. if (DumpSharedSpaces || ForceSharedSpaces) { jio_fprintf(defaultStream::error_stream(), - "Reverting to Serial GC because of %s \n", + "Reverting to Serial GC because of %s\n", ForceSharedSpaces ? " -Xshare:on" : "-Xshare:dump"); - set_serial_gc_flags(); + force_serial_gc(); FLAG_SET_DEFAULT(SOLARIS_ONLY(UseISM) NOT_SOLARIS(UseLargePages), false); } else { - if (UseSharedSpaces) { + if (UseSharedSpaces && Verbose) { jio_fprintf(defaultStream::error_stream(), "Turning off use of shared archive because of " - "choice of garbage collector or large pages \n"); + "choice of garbage collector or large pages\n"); } no_shared_spaces(); } @@ -1925,8 +1958,8 @@ describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, MaxNewSize, (size_t) long_initial_eden_size); - FLAG_SET_CMDLINE(uintx, NewSize, (size_t) long_initial_eden_size); + FLAG_SET_CMDLINE(uintx, MaxNewSize, (uintx)long_initial_eden_size); + FLAG_SET_CMDLINE(uintx, NewSize, (uintx)long_initial_eden_size); // -Xms } else if (match_option(option, "-Xms", &tail)) { julong long_initial_heap_size = 0; @@ -1937,9 +1970,9 @@ describe_range_error(errcode); return JNI_EINVAL; } - set_initial_heap_size((size_t) long_initial_heap_size); + FLAG_SET_CMDLINE(uintx, InitialHeapSize, (uintx)long_initial_heap_size); // Currently the minimum size and the initial heap sizes are the same. - set_min_heap_size(initial_heap_size()); + set_min_heap_size(InitialHeapSize); // -Xmx } else if (match_option(option, "-Xmx", &tail)) { julong long_max_heap_size = 0; @@ -1950,7 +1983,7 @@ describe_range_error(errcode); return JNI_EINVAL; } - FLAG_SET_CMDLINE(uintx, MaxHeapSize, (size_t) long_max_heap_size); + FLAG_SET_CMDLINE(uintx, MaxHeapSize, (uintx)long_max_heap_size); // Xmaxf } else if (match_option(option, "-Xmaxf", &tail)) { int maxf = (int)(atof(tail) * 100); @@ -2196,9 +2229,9 @@ if (FLAG_IS_DEFAULT(MaxHeapSize)) { FLAG_SET_CMDLINE(uintx, MaxHeapSize, initHeapSize); - set_initial_heap_size(MaxHeapSize); + FLAG_SET_CMDLINE(uintx, InitialHeapSize, initHeapSize); // Currently the minimum size and the initial heap sizes are the same. - set_min_heap_size(initial_heap_size()); + set_min_heap_size(initHeapSize); } if (FLAG_IS_DEFAULT(NewSize)) { // Make the young generation 3/8ths of the total heap. @@ -2675,8 +2708,12 @@ } } +#if defined(_LP64) && defined(COMPILER1) + UseCompressedOops = false; +#endif + #ifdef SERIALGC - set_serial_gc_flags(); + force_serial_gc(); #endif // SERIALGC #ifdef KERNEL no_shared_spaces(); @@ -2690,18 +2727,22 @@ return JNI_EINVAL; } - if (UseParallelGC || UseParallelOldGC) { - // Set some flags for ParallelGC if needed. - set_parallel_gc_flags(); - } else if (UseConcMarkSweepGC) { - // Set some flags for CMS + if (UseConcMarkSweepGC) { + // Set flags for CMS and ParNew. Check UseConcMarkSweep first + // to ensure that when both UseConcMarkSweepGC and UseParNewGC + // are true, we don't call set_parnew_gc_flags() as well. set_cms_and_parnew_gc_flags(); - } else if (UseParNewGC) { - // Set some flags for ParNew - set_parnew_gc_flags(); - } else if (UseG1GC) { - // Set some flags for garbage-first, if needed. - set_g1_gc_flags(); + } else { + // Set heap size based on available physical memory + set_heap_size(); + // Set per-collector flags + if (UseParallelGC || UseParallelOldGC) { + set_parallel_gc_flags(); + } else if (UseParNewGC) { + set_parnew_gc_flags(); + } else if (UseG1GC) { + set_g1_gc_flags(); + } } #ifdef SERIALGC diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/runtime/arguments.hpp --- a/src/share/vm/runtime/arguments.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/runtime/arguments.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -254,7 +254,6 @@ static bool _has_profile; static bool _has_alloc_profile; static const char* _gc_log_filename; - static uintx _initial_heap_size; static uintx _min_heap_size; // -Xrun arguments @@ -300,8 +299,8 @@ static void set_g1_gc_flags(); // GC ergonomics static void set_ergonomics_flags(); - // Setup heap size for a server platform - static void set_server_heap_size(); + // Setup heap size + static void set_heap_size(); // Based on automatic selection criteria, should the // low pause collector be used. static bool should_auto_select_low_pause_collector(); @@ -434,9 +433,7 @@ static bool has_profile() { return _has_profile; } static bool has_alloc_profile() { return _has_alloc_profile; } - // -Xms , -Xmx - static uintx initial_heap_size() { return _initial_heap_size; } - static void set_initial_heap_size(uintx v) { _initial_heap_size = v; } + // -Xms, -Xmx static uintx min_heap_size() { return _min_heap_size; } static void set_min_heap_size(uintx v) { _min_heap_size = v; } diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/runtime/globals.cpp --- a/src/share/vm/runtime/globals.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/runtime/globals.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -46,7 +46,8 @@ bool Flag::is_unlocked() const { if (strcmp(kind, "{diagnostic}") == 0) { return UnlockDiagnosticVMOptions; - } else if (strcmp(kind, "{experimental}") == 0) { + } else if (strcmp(kind, "{experimental}") == 0 || + strcmp(kind, "{C2 experimental}") == 0) { return UnlockExperimentalVMOptions; } else { return true; @@ -69,9 +70,10 @@ void Flag::print_on(outputStream* st) { st->print("%5s %-35s %c= ", type, name, (origin != DEFAULT ? ':' : ' ')); - if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false"); - if (is_intx()) st->print("%-16ld", get_intx()); - if (is_uintx()) st->print("%-16lu", get_uintx()); + if (is_bool()) st->print("%-16s", get_bool() ? "true" : "false"); + if (is_intx()) st->print("%-16ld", get_intx()); + if (is_uintx()) st->print("%-16lu", get_uintx()); + if (is_uint64_t()) st->print("%-16lu", get_uint64_t()); if (is_ccstr()) { const char* cp = get_ccstr(); if (cp != NULL) { @@ -100,6 +102,8 @@ st->print("-XX:%s=" INTX_FORMAT, name, get_intx()); } else if (is_uintx()) { st->print("-XX:%s=" UINTX_FORMAT, name, get_uintx()); + } else if (is_uint64_t()) { + st->print("-XX:%s=" UINT64_FORMAT, name, get_uint64_t()); } else if (is_ccstr()) { st->print("-XX:%s=", name); const char* cp = get_ccstr(); @@ -166,6 +170,7 @@ #define C2_PRODUCT_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 product}", DEFAULT }, #define C2_PD_PRODUCT_FLAG_STRUCT(type, name, doc) { #type, XSTR(name), &name, "{C2 pd product}", DEFAULT }, #define C2_DIAGNOSTIC_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 diagnostic}", DEFAULT }, +#define C2_EXPERIMENTAL_FLAG_STRUCT(type, name, value, doc) { #type, XSTR(name), &name, "{C2 experimental}", DEFAULT }, #ifdef PRODUCT #define C2_DEVELOP_FLAG_STRUCT(type, name, value, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_STRUCT(type, name, doc) /* flag is constant */ @@ -187,7 +192,7 @@ C1_FLAGS(C1_DEVELOP_FLAG_STRUCT, C1_PD_DEVELOP_FLAG_STRUCT, C1_PRODUCT_FLAG_STRUCT, C1_PD_PRODUCT_FLAG_STRUCT, C1_NOTPRODUCT_FLAG_STRUCT) #endif #ifdef COMPILER2 - C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT) + C2_FLAGS(C2_DEVELOP_FLAG_STRUCT, C2_PD_DEVELOP_FLAG_STRUCT, C2_PRODUCT_FLAG_STRUCT, C2_PD_PRODUCT_FLAG_STRUCT, C2_DIAGNOSTIC_FLAG_STRUCT, C2_EXPERIMENTAL_FLAG_STRUCT, C2_NOTPRODUCT_FLAG_STRUCT) #endif {0, NULL, NULL} }; @@ -324,6 +329,32 @@ faddr->origin = origin; } +bool CommandLineFlags::uint64_tAt(char* name, size_t len, uint64_t* value) { + Flag* result = Flag::find_flag(name, len); + if (result == NULL) return false; + if (!result->is_uint64_t()) return false; + *value = result->get_uint64_t(); + return true; +} + +bool CommandLineFlags::uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin) { + Flag* result = Flag::find_flag(name, len); + if (result == NULL) return false; + if (!result->is_uint64_t()) return false; + uint64_t old_value = result->get_uint64_t(); + result->set_uint64_t(*value); + *value = old_value; + result->origin = origin; + return true; +} + +void CommandLineFlagsEx::uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin) { + Flag* faddr = address_of_flag(flag); + guarantee(faddr != NULL && faddr->is_uint64_t(), "wrong flag type"); + faddr->set_uint64_t(value); + faddr->origin = origin; +} + bool CommandLineFlags::doubleAt(char* name, size_t len, double* value) { Flag* result = Flag::find_flag(name, len); if (result == NULL) return false; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/runtime/globals.hpp --- a/src/share/vm/runtime/globals.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/runtime/globals.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -47,8 +47,8 @@ define_pd_global(intx, OnStackReplacePercentage, 0); define_pd_global(bool, ResizeTLAB, false); define_pd_global(intx, FreqInlineSize, 0); +define_pd_global(intx, InlineSmallCode, 0); define_pd_global(intx, NewSizeThreadIncrease, 4*K); -define_pd_global(intx, NewRatio, 4); define_pd_global(intx, InlineClassNatives, true); define_pd_global(intx, InlineUnsafeOps, true); define_pd_global(intx, InitialCodeCacheSize, 160*K); @@ -58,7 +58,7 @@ define_pd_global(uintx,PermSize, ScaleForWordSize(4*M)); define_pd_global(uintx,MaxPermSize, ScaleForWordSize(64*M)); define_pd_global(bool, NeverActAsServerClassMachine, true); -define_pd_global(uintx, DefaultMaxRAM, 1*G); +define_pd_global(uint64_t,MaxRAM, 1ULL*G); #define CI_COMPILER_COUNT 0 #else @@ -113,6 +113,10 @@ uintx get_uintx() const { return *((uintx*) addr); } void set_uintx(uintx value) { *((uintx*) addr) = value; } + bool is_uint64_t() const { return strcmp(type, "uint64_t") == 0; } + uint64_t get_uint64_t() const { return *((uint64_t*) addr); } + void set_uint64_t(uint64_t value) { *((uint64_t*) addr) = value; } + bool is_double() const { return strcmp(type, "double") == 0; } double get_double() const { return *((double*) addr); } void set_double(double value) { *((double*) addr) = value; } @@ -188,6 +192,11 @@ static bool uintxAtPut(char* name, size_t len, uintx* value, FlagValueOrigin origin); static bool uintxAtPut(char* name, uintx* value, FlagValueOrigin origin) { return uintxAtPut(name, strlen(name), value, origin); } + static bool uint64_tAt(char* name, size_t len, uint64_t* value); + static bool uint64_tAt(char* name, uint64_t* value) { return uint64_tAt(name, strlen(name), value); } + static bool uint64_tAtPut(char* name, size_t len, uint64_t* value, FlagValueOrigin origin); + static bool uint64_tAtPut(char* name, uint64_t* value, FlagValueOrigin origin) { return uint64_tAtPut(name, strlen(name), value, origin); } + static bool doubleAt(char* name, size_t len, double* value); static bool doubleAt(char* name, double* value) { return doubleAt(name, strlen(name), value); } static bool doubleAtPut(char* name, size_t len, double* value, FlagValueOrigin origin); @@ -785,7 +794,7 @@ product(bool, ProfilerRecordPC, false, \ "Collects tick for each 16 byte interval of compiled code") \ \ - product(bool, ProfileVM, false, \ + product(bool, ProfileVM, false, \ "Profiles ticks that fall within VM (either in the VM Thread " \ "or VM code called through stubs)") \ \ @@ -815,7 +824,7 @@ \ product(bool, RegisterFinalizersAtInit, true, \ "Register finalizable objects at end of Object. or " \ - "after allocation.") \ + "after allocation") \ \ develop(bool, RegisterReferences, true, \ "Tells whether the VM should register soft/weak/final/phantom " \ @@ -862,14 +871,14 @@ product(bool, AlwaysLockClassLoader, false, \ "Require the VM to acquire the class loader lock before calling " \ "loadClass() even for class loaders registering " \ - "as parallel capable. Default false. ") \ + "as parallel capable") \ \ product(bool, AllowParallelDefineClass, false, \ "Allow parallel defineClass requests for class loaders " \ - "registering as parallel capable. Default false") \ + "registering as parallel capable") \ \ product(bool, MustCallLoadClassInternal, false, \ - "Call loadClassInternal() rather than loadClass().Default false") \ + "Call loadClassInternal() rather than loadClass()") \ \ product_pd(bool, DontYieldALot, \ "Throw away obvious excess yield calls (for SOLARIS only)") \ @@ -921,9 +930,9 @@ "(Unstable, Linux-specific)" \ " avoid NPTL-FUTEX hang pthread_cond_timedwait" ) \ \ - product(bool, FilterSpuriousWakeups , true, \ - "Prevent spurious or premature wakeups from object.wait" \ - "(Solaris only)") \ + product(bool, FilterSpuriousWakeups, true, \ + "Prevent spurious or premature wakeups from object.wait " \ + "(Solaris only)") \ \ product(intx, NativeMonitorTimeout, -1, "(Unstable)" ) \ product(intx, NativeMonitorFlags, 0, "(Unstable)" ) \ @@ -973,7 +982,7 @@ \ product(bool, UseAltSigs, false, \ "Use alternate signals instead of SIGUSR1 & SIGUSR2 for VM " \ - "internal signals. (Solaris only)") \ + "internal signals (Solaris only)") \ \ product(bool, UseSpinning, false, \ "Use spinning in monitor inflation and before entry") \ @@ -1265,12 +1274,12 @@ "Always tenure objects in eden. (ParallelGC only)") \ \ product(bool, NeverTenure, false, \ - "Never tenure objects in eden, May tenure on overflow" \ - " (ParallelGC only)") \ + "Never tenure objects in eden, May tenure on overflow " \ + "(ParallelGC only)") \ \ product(bool, ScavengeBeforeFullGC, true, \ - "Scavenge youngest generation before each full GC," \ - " used with UseParallelGC") \ + "Scavenge youngest generation before each full GC, " \ + "used with UseParallelGC") \ \ develop(bool, ScavengeWithObjectsInToSpace, false, \ "Allow scavenges to occur when to_space contains objects.") \ @@ -1283,9 +1292,9 @@ " (effective only when UseConcMarkSweepGC)") \ \ product(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false, \ - "A System.gc() request invokes a concurrent collection and" \ - " also unloads classes during such a concurrent gc cycle " \ - " (effective only when UseConcMarkSweepGC)") \ + "A System.gc() request invokes a concurrent collection and " \ + "also unloads classes during such a concurrent gc cycle " \ + "(effective only when UseConcMarkSweepGC)") \ \ develop(bool, UseCMSAdaptiveFreeLists, true, \ "Use Adaptive Free Lists in the CMS generation") \ @@ -1340,8 +1349,8 @@ "Whether we should simulate work queue overflow in ParNew") \ \ notproduct(uintx, ParGCWorkQueueOverflowInterval, 1000, \ - "An `interval' counter that determines how frequently" \ - " we simulate overflow; a smaller number increases frequency") \ + "An `interval' counter that determines how frequently " \ + "we simulate overflow; a smaller number increases frequency") \ \ product(uintx, ParGCDesiredObjsFromOverflowList, 20, \ "The desired number of objects to claim from the overflow list") \ @@ -1354,12 +1363,12 @@ "It forces all freshly committed pages to be pre-touched.") \ \ product(bool, CMSUseOldDefaults, false, \ - "A flag temporarily introduced to allow reverting to some older" \ - "default settings; older as of 6.0 ") \ + "A flag temporarily introduced to allow reverting to some " \ + "older default settings; older as of 6.0") \ \ product(intx, CMSYoungGenPerWorker, 16*M, \ "The amount of young gen chosen by default per GC worker " \ - "thread available ") \ + "thread available") \ \ product(bool, GCOverheadReporting, false, \ "Enables the GC overhead reporting facility") \ @@ -1380,43 +1389,44 @@ "automatically adjusted") \ \ product(uintx, CMSIncrementalDutyCycleMin, 0, \ - "Lower bound on the duty cycle when CMSIncrementalPacing is" \ - "enabled (a percentage, 0-100).") \ + "Lower bound on the duty cycle when CMSIncrementalPacing is " \ + "enabled (a percentage, 0-100)") \ \ product(uintx, CMSIncrementalSafetyFactor, 10, \ - "Percentage (0-100) used to add conservatism when computing the" \ - "duty cycle.") \ + "Percentage (0-100) used to add conservatism when computing the " \ + "duty cycle") \ \ product(uintx, CMSIncrementalOffset, 0, \ "Percentage (0-100) by which the CMS incremental mode duty cycle" \ - "is shifted to the right within the period between young GCs") \ + " is shifted to the right within the period between young GCs") \ \ product(uintx, CMSExpAvgFactor, 25, \ - "Percentage (0-100) used to weight the current sample when" \ - "computing exponential averages for CMS statistics.") \ + "Percentage (0-100) used to weight the current sample when " \ + "computing exponential averages for CMS statistics") \ \ product(uintx, CMS_FLSWeight, 50, \ - "Percentage (0-100) used to weight the current sample when" \ - "computing exponentially decating averages for CMS FLS statistics.") \ + "Percentage (0-100) used to weight the current sample when " \ + "computing exponentially decating averages for CMS FLS statistics") \ \ product(uintx, CMS_FLSPadding, 2, \ - "The multiple of deviation from mean to use for buffering" \ + "The multiple of deviation from mean to use for buffering " \ "against volatility in free list demand.") \ \ product(uintx, FLSCoalescePolicy, 2, \ "CMS: Aggression level for coalescing, increasing from 0 to 4") \ \ product(uintx, CMS_SweepWeight, 50, \ - "Percentage (0-100) used to weight the current sample when" \ - "computing exponentially decaying average for inter-sweep duration.") \ + "Percentage (0-100) used to weight the current sample when " \ + "computing exponentially decaying average for inter-sweep " \ + "duration") \ \ product(uintx, CMS_SweepPadding, 2, \ - "The multiple of deviation from mean to use for buffering" \ + "The multiple of deviation from mean to use for buffering " \ "against volatility in inter-sweep duration.") \ \ product(uintx, CMS_SweepTimerThresholdMillis, 10, \ "Skip block flux-rate sampling for an epoch unless inter-sweep " \ - " duration exceeds this threhold in milliseconds") \ + "duration exceeds this threhold in milliseconds") \ \ develop(bool, CMSTraceIncrementalMode, false, \ "Trace CMS incremental mode") \ @@ -1617,35 +1627,36 @@ \ product(intx, CMSTriggerRatio, 80, \ "Percentage of MinHeapFreeRatio in CMS generation that is " \ - " allocated before a CMS collection cycle commences") \ + "allocated before a CMS collection cycle commences") \ \ product(intx, CMSTriggerPermRatio, 80, \ - "Percentage of MinHeapFreeRatio in the CMS perm generation that" \ - " is allocated before a CMS collection cycle commences, that " \ - " also collects the perm generation") \ + "Percentage of MinHeapFreeRatio in the CMS perm generation that " \ + "is allocated before a CMS collection cycle commences, that " \ + "also collects the perm generation") \ \ product(uintx, CMSBootstrapOccupancy, 50, \ "Percentage CMS generation occupancy at which to " \ - " initiate CMS collection for bootstrapping collection stats") \ + "initiate CMS collection for bootstrapping collection stats") \ \ product(intx, CMSInitiatingOccupancyFraction, -1, \ "Percentage CMS generation occupancy to start a CMS collection " \ - " cycle (A negative value means that CMSTriggerRatio is used)") \ + "cycle. A negative value means that CMSTriggerRatio is used") \ \ product(intx, CMSInitiatingPermOccupancyFraction, -1, \ - "Percentage CMS perm generation occupancy to start a CMScollection"\ - " cycle (A negative value means that CMSTriggerPermRatio is used)")\ + "Percentage CMS perm generation occupancy to start a " \ + "CMScollection cycle. A negative value means that " \ + "CMSTriggerPermRatio is used") \ \ product(bool, UseCMSInitiatingOccupancyOnly, false, \ "Only use occupancy as a crierion for starting a CMS collection") \ \ product(intx, CMSIsTooFullPercentage, 98, \ - "An absolute ceiling above which CMS will always consider the" \ - " perm gen ripe for collection") \ + "An absolute ceiling above which CMS will always consider the " \ + "perm gen ripe for collection") \ \ develop(bool, CMSTestInFreeList, false, \ "Check if the coalesced range is already in the " \ - "free lists as claimed.") \ + "free lists as claimed") \ \ notproduct(bool, CMSVerifyReturnedBytes, false, \ "Check that all the garbage collected was returned to the " \ @@ -1663,8 +1674,8 @@ "Enforce ScavengeALot/GCALot at all potential safepoints") \ \ product(bool, HandlePromotionFailure, true, \ - "The youngest generation collection does not require" \ - " a guarantee of full promotion of all live objects.") \ + "The youngest generation collection does not require " \ + "a guarantee of full promotion of all live objects.") \ \ notproduct(bool, PromotionFailureALot, false, \ "Use promotion failure handling on every youngest generation " \ @@ -1692,7 +1703,7 @@ "Ratio of hard spins to calls to yield") \ \ product(uintx, PreserveMarkStackSize, 1024, \ - "Size for stack used in promotion failure handling") \ + "Size for stack used in promotion failure handling") \ \ product_pd(bool, UseTLAB, "Use thread-local object allocation") \ \ @@ -1720,14 +1731,27 @@ product(bool, AlwaysActAsServerClassMachine, false, \ "Always act like a server-class machine") \ \ - product_pd(uintx, DefaultMaxRAM, \ - "Maximum real memory size for setting server class heap size") \ + product_pd(uint64_t, MaxRAM, \ + "Real memory size (in bytes) used to set maximum heap size") \ + \ + product(uintx, ErgoHeapSizeLimit, 0, \ + "Maximum ergonomically set heap size (in bytes); zero means use " \ + "MaxRAM / MaxRAMFraction") \ + \ + product(uintx, MaxRAMFraction, 4, \ + "Maximum fraction (1/n) of real memory used for maximum heap " \ + "size") \ \ product(uintx, DefaultMaxRAMFraction, 4, \ - "Fraction (1/n) of real memory used for server class max heap") \ - \ - product(uintx, DefaultInitialRAMFraction, 64, \ - "Fraction (1/n) of real memory used for server class initial heap") \ + "Maximum fraction (1/n) of real memory used for maximum heap " \ + "size; deprecated: to be renamed to MaxRAMFraction") \ + \ + product(uintx, MinRAMFraction, 2, \ + "Minimum fraction (1/n) of real memory used for maxmimum heap " \ + "size on systems with small physical memory size") \ + \ + product(uintx, InitialRAMFraction, 64, \ + "Fraction (1/n) of real memory used for initial heap size") \ \ product(bool, UseAutoGCSelectPolicy, false, \ "Use automatic collection selection policy") \ @@ -1778,7 +1802,7 @@ "Number of collections before the adaptive sizing is started") \ \ product(uintx, AdaptiveSizePolicyOutputInterval, 0, \ - "Collecton interval for printing information, zero => never") \ + "Collecton interval for printing information; zero => never") \ \ product(bool, UseAdaptiveSizePolicyFootprintGoal, true, \ "Use adaptive minimum footprint as a goal") \ @@ -1808,7 +1832,8 @@ "Allowed collection cost difference between generations") \ \ product(uintx, AdaptiveSizePolicyCollectionCostMargin, 50, \ - "If collection costs are within margin, reduce both by full delta") \ + "If collection costs are within margin, reduce both by full " \ + "delta") \ \ product(uintx, YoungGenerationSizeIncrement, 20, \ "Adaptive size percentage change in young generation") \ @@ -2527,7 +2552,7 @@ \ develop(bool, VerifyCompiledCode, false, \ "Include miscellaneous runtime verifications in nmethod code; " \ - "off by default because it disturbs nmethod size heuristics.") \ + "default off because it disturbs nmethod size heuristics") \ \ \ /* compilation */ \ @@ -2789,20 +2814,28 @@ "an OS lock") \ \ /* gc parameters */ \ - product(uintx, MaxHeapSize, ScaleForWordSize(64*M), \ - "Default maximum size for object heap (in bytes)") \ - \ - product_pd(uintx, NewSize, \ - "Default size of new generation (in bytes)") \ + product(uintx, InitialHeapSize, 0, \ + "Initial heap size (in bytes); zero means OldSize + NewSize") \ + \ + product(uintx, MaxHeapSize, ScaleForWordSize(96*M), \ + "Maximum heap size (in bytes)") \ + \ + product(uintx, OldSize, ScaleForWordSize(4*M), \ + "Initial tenured generation size (in bytes)") \ + \ + product(uintx, NewSize, ScaleForWordSize(4*M), \ + "Initial new generation size (in bytes)") \ \ product(uintx, MaxNewSize, max_uintx, \ - "Maximum size of new generation (in bytes)") \ + "Maximum new generation size (in bytes), max_uintx means set " \ + "ergonomically") \ \ product(uintx, PretenureSizeThreshold, 0, \ - "Max size in bytes of objects allocated in DefNew generation") \ - \ - product_pd(uintx, TLABSize, \ - "Default (or starting) size of TLAB (in bytes)") \ + "Maximum size in bytes of objects allocated in DefNew " \ + "generation; zero means no maximum") \ + \ + product(uintx, TLABSize, 0, \ + "Starting TLAB size (in bytes); zero means set ergonomically") \ \ product(uintx, MinTLABSize, 2*K, \ "Minimum allowed TLAB size (in bytes)") \ @@ -2819,10 +2852,10 @@ product(uintx, TLABWasteIncrement, 4, \ "Increment allowed waste at slow allocation") \ \ - product_pd(intx, SurvivorRatio, \ + product(intx, SurvivorRatio, 8, \ "Ratio of eden/survivor space size") \ \ - product_pd(intx, NewRatio, \ + product(intx, NewRatio, 2, \ "Ratio of new/old generation sizes") \ \ product(uintx, MaxLiveObjectEvacuationRatio, 100, \ @@ -2832,11 +2865,8 @@ "Additional size added to desired new generation size per " \ "non-daemon thread (in bytes)") \ \ - product(uintx, OldSize, ScaleForWordSize(4096*K), \ - "Default size of tenured generation (in bytes)") \ - \ product_pd(uintx, PermSize, \ - "Default size of permanent generation (in bytes)") \ + "Initial size of permanent generation (in bytes)") \ \ product_pd(uintx, MaxPermSize, \ "Maximum size of permanent generation (in bytes)") \ diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/runtime/globals_extension.hpp --- a/src/share/vm/runtime/globals_extension.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/runtime/globals_extension.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -64,6 +64,7 @@ #define C2_PRODUCT_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #define C2_PD_PRODUCT_FLAG_MEMBER(type, name, doc) FLAG_MEMBER(name), #define C2_DIAGNOSTIC_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), +#define C2_EXPERIMENTAL_FLAG_MEMBER(type, name, value, doc) FLAG_MEMBER(name), #ifdef PRODUCT #define C2_DEVELOP_FLAG_MEMBER(type, name, value, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_MEMBER(type, name, doc) /* flag is constant */ @@ -84,7 +85,7 @@ C1_FLAGS(C1_DEVELOP_FLAG_MEMBER, C1_PD_DEVELOP_FLAG_MEMBER, C1_PRODUCT_FLAG_MEMBER, C1_PD_PRODUCT_FLAG_MEMBER, C1_NOTPRODUCT_FLAG_MEMBER) #endif #ifdef COMPILER2 - C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER) + C2_FLAGS(C2_DEVELOP_FLAG_MEMBER, C2_PD_DEVELOP_FLAG_MEMBER, C2_PRODUCT_FLAG_MEMBER, C2_PD_PRODUCT_FLAG_MEMBER, C2_DIAGNOSTIC_FLAG_MEMBER, C2_EXPERIMENTAL_FLAG_MEMBER, C2_NOTPRODUCT_FLAG_MEMBER) #endif NUM_CommandLineFlag } CommandLineFlag; @@ -130,6 +131,7 @@ #define C2_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE(type, name, doc) FLAG_MEMBER_WITH_TYPE(name,type), #define C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), +#define C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) FLAG_MEMBER_WITH_TYPE(name,type), #ifdef PRODUCT #define C2_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, value, doc) /* flag is constant */ #define C2_PD_DEVELOP_FLAG_MEMBER_WITH_TYPE(type, name, doc) /* flag is constant */ @@ -181,6 +183,7 @@ C2_PRODUCT_FLAG_MEMBER_WITH_TYPE, C2_PD_PRODUCT_FLAG_MEMBER_WITH_TYPE, C2_DIAGNOSTIC_FLAG_MEMBER_WITH_TYPE, + C2_EXPERIMENTAL_FLAG_MEMBER_WITH_TYPE, C2_NOTPRODUCT_FLAG_MEMBER_WITH_TYPE) #endif NUM_CommandLineFlagWithType @@ -202,6 +205,7 @@ static void boolAtPut(CommandLineFlagWithType flag, bool value, FlagValueOrigin origin); static void intxAtPut(CommandLineFlagWithType flag, intx value, FlagValueOrigin origin); static void uintxAtPut(CommandLineFlagWithType flag, uintx value, FlagValueOrigin origin); + static void uint64_tAtPut(CommandLineFlagWithType flag, uint64_t value, FlagValueOrigin origin); static void doubleAtPut(CommandLineFlagWithType flag, double value, FlagValueOrigin origin); static void ccstrAtPut(CommandLineFlagWithType flag, ccstr value, FlagValueOrigin origin); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/runtime/os.hpp --- a/src/share/vm/runtime/os.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/runtime/os.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -294,19 +294,16 @@ } static bool is_memory_serialize_page(JavaThread *thread, address addr) { - address thr_addr; if (UseMembar) return false; - // Calculate thread specific address + // Previously this function calculated the exact address of this + // thread's serialize page, and checked if the faulting address + // was equal. However, some platforms mask off faulting addresses + // to the page size, so now we just check that the address is + // within the page. This makes the thread argument unnecessary, + // but we retain the NULL check to preserve existing behaviour. if (thread == NULL) return false; - // TODO-FIXME: some platforms mask off faulting addresses to the base pagesize. - // Instead of using a test for equality we should probably use something - // of the form: - // return ((_mem_serialize_page ^ addr) & -pagesize) == 0 - // - thr_addr = (address)(((uintptr_t)thread >> - get_serialize_page_shift_count()) & - get_serialize_page_mask()) + (uintptr_t)_mem_serialize_page; - return (thr_addr == addr); + address page = (address) _mem_serialize_page; + return addr >= page && addr < (page + os::vm_page_size()); } static void block_on_serialize_page_trap(); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/attachListener.cpp --- a/src/share/vm/services/attachListener.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/services/attachListener.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -207,7 +207,7 @@ int tmp; int n = sscanf(arg1, "%d", &tmp); if (n != 1) { - out->print_cr("flag value has to be boolean (1 or 0)"); + out->print_cr("flag value must be a boolean (1 or 0)"); return JNI_ERR; } value = (tmp != 0); @@ -226,11 +226,11 @@ if ((arg1 = op->arg(1)) != NULL) { int n = sscanf(arg1, INTX_FORMAT, &value); if (n != 1) { - out->print_cr("flag value has to be integer"); + out->print_cr("flag value must be an integer"); return JNI_ERR; } } - bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::intxAtPut((char*)name, &value, ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -245,11 +245,30 @@ if ((arg1 = op->arg(1)) != NULL) { int n = sscanf(arg1, UINTX_FORMAT, &value); if (n != 1) { - out->print_cr("flag value has to be integer"); + out->print_cr("flag value must be an unsigned integer"); return JNI_ERR; } } - bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::uintxAtPut((char*)name, &value, ATTACH_ON_DEMAND); + if (! res) { + out->print_cr("setting flag %s failed", name); + } + + return res? JNI_OK : JNI_ERR; +} + +// set a uint64_t global flag using value from AttachOperation +static jint set_uint64_t_flag(const char* name, AttachOperation* op, outputStream* out) { + uint64_t value; + const char* arg1; + if ((arg1 = op->arg(1)) != NULL) { + int n = sscanf(arg1, UINT64_FORMAT, &value); + if (n != 1) { + out->print_cr("flag value must be an unsigned 64-bit integer"); + return JNI_ERR; + } + } + bool res = CommandLineFlags::uint64_tAtPut((char*)name, &value, ATTACH_ON_DEMAND); if (! res) { out->print_cr("setting flag %s failed", name); } @@ -261,10 +280,10 @@ static jint set_ccstr_flag(const char* name, AttachOperation* op, outputStream* out) { const char* value; if ((value = op->arg(1)) == NULL) { - out->print_cr("flag value has to be a string"); + out->print_cr("flag value must be a string"); return JNI_ERR; } - bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND); + bool res = CommandLineFlags::ccstrAtPut((char*)name, &value, ATTACH_ON_DEMAND); if (res) { FREE_C_HEAP_ARRAY(char, value); } else { @@ -291,6 +310,8 @@ return set_intx_flag(name, op, out); } else if (f->is_uintx()) { return set_uintx_flag(name, op, out); + } else if (f->is_uint64_t()) { + return set_uint64_t_flag(name, op, out); } else if (f->is_ccstr()) { return set_ccstr_flag(name, op, out); } else { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/g1MemoryPool.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/g1MemoryPool.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +# include "incls/_precompiled.incl" +# include "incls/_g1MemoryPool.cpp.incl" + +G1MemoryPoolSuper::G1MemoryPoolSuper(G1CollectedHeap* g1h, + const char* name, + size_t init_size, + size_t max_size, + bool support_usage_threshold) : + _g1h(g1h), CollectedMemoryPool(name, + MemoryPool::Heap, + init_size, + max_size, + support_usage_threshold) { + assert(UseG1GC, "sanity"); +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::eden_space_committed(G1CollectedHeap* g1h) { + return MAX2(eden_space_used(g1h), (size_t) HeapRegion::GrainBytes); +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::eden_space_used(G1CollectedHeap* g1h) { + size_t young_list_length = g1h->young_list_length(); + size_t eden_used = young_list_length * HeapRegion::GrainBytes; + size_t survivor_used = survivor_space_used(g1h); + eden_used = subtract_up_to_zero(eden_used, survivor_used); + return eden_used; +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::eden_space_max(G1CollectedHeap* g1h) { + // This should ensure that it returns a value no smaller than the + // region size. Currently, eden_space_committed() guarantees that. + return eden_space_committed(g1h); +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::survivor_space_committed(G1CollectedHeap* g1h) { + return MAX2(survivor_space_used(g1h), (size_t) HeapRegion::GrainBytes); +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::survivor_space_used(G1CollectedHeap* g1h) { + size_t survivor_num = g1h->g1_policy()->recorded_survivor_regions(); + size_t survivor_used = survivor_num * HeapRegion::GrainBytes; + return survivor_used; +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::survivor_space_max(G1CollectedHeap* g1h) { + // This should ensure that it returns a value no smaller than the + // region size. Currently, survivor_space_committed() guarantees that. + return survivor_space_committed(g1h); +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::old_space_committed(G1CollectedHeap* g1h) { + size_t committed = overall_committed(g1h); + size_t eden_committed = eden_space_committed(g1h); + size_t survivor_committed = survivor_space_committed(g1h); + committed = subtract_up_to_zero(committed, eden_committed); + committed = subtract_up_to_zero(committed, survivor_committed); + committed = MAX2(committed, (size_t) HeapRegion::GrainBytes); + return committed; +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::old_space_used(G1CollectedHeap* g1h) { + size_t used = overall_used(g1h); + size_t eden_used = eden_space_used(g1h); + size_t survivor_used = survivor_space_used(g1h); + used = subtract_up_to_zero(used, eden_used); + used = subtract_up_to_zero(used, survivor_used); + return used; +} + +// See the comment at the top of g1MemoryPool.hpp +size_t G1MemoryPoolSuper::old_space_max(G1CollectedHeap* g1h) { + size_t max = overall_max(g1h); + size_t eden_max = eden_space_max(g1h); + size_t survivor_max = survivor_space_max(g1h); + max = subtract_up_to_zero(max, eden_max); + max = subtract_up_to_zero(max, survivor_max); + max = MAX2(max, (size_t) HeapRegion::GrainBytes); + return max; +} + +G1EdenPool::G1EdenPool(G1CollectedHeap* g1h) : + G1MemoryPoolSuper(g1h, + "G1 Eden", + eden_space_committed(g1h), /* init_size */ + eden_space_max(g1h), /* max_size */ + false /* support_usage_threshold */) { +} + +MemoryUsage G1EdenPool::get_memory_usage() { + size_t initial_sz = initial_size(); + size_t max_sz = max_size(); + size_t used = used_in_bytes(); + size_t committed = eden_space_committed(_g1h); + + return MemoryUsage(initial_sz, used, committed, max_sz); +} + +G1SurvivorPool::G1SurvivorPool(G1CollectedHeap* g1h) : + G1MemoryPoolSuper(g1h, + "G1 Survivor", + survivor_space_committed(g1h), /* init_size */ + survivor_space_max(g1h), /* max_size */ + false /* support_usage_threshold */) { +} + +MemoryUsage G1SurvivorPool::get_memory_usage() { + size_t initial_sz = initial_size(); + size_t max_sz = max_size(); + size_t used = used_in_bytes(); + size_t committed = survivor_space_committed(_g1h); + + return MemoryUsage(initial_sz, used, committed, max_sz); +} + +G1OldGenPool::G1OldGenPool(G1CollectedHeap* g1h) : + G1MemoryPoolSuper(g1h, + "G1 Old Gen", + old_space_committed(g1h), /* init_size */ + old_space_max(g1h), /* max_size */ + true /* support_usage_threshold */) { +} + +MemoryUsage G1OldGenPool::get_memory_usage() { + size_t initial_sz = initial_size(); + size_t max_sz = max_size(); + size_t used = used_in_bytes(); + size_t committed = old_space_committed(_g1h); + + return MemoryUsage(initial_sz, used, committed, max_sz); +} diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/g1MemoryPool.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/vm/services/g1MemoryPool.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +class G1CollectedHeap; + +// This file contains the three classes that represent the memory +// pools of the G1 spaces: G1EdenPool, G1SurvivorPool, and +// G1OldGenPool. In G1, unlike our other GCs, we do not have a +// physical space for each of those spaces. Instead, we allocate +// regions for all three spaces out of a single pool of regions (that +// pool basically covers the entire heap). As a result, the eden, +// survivor, and old gen are considered logical spaces in G1, as each +// is a set of non-contiguous regions. This is also reflected in the +// way we map them to memory pools here. The easiest way to have done +// this would have been to map the entire G1 heap to a single memory +// pool. However, it's helpful to show how large the eden and survivor +// get, as this does affect the performance and behavior of G1. Which +// is why we introduce the three memory pools implemented here. +// +// The above approach inroduces a couple of challenging issues in the +// implementation of the three memory pools: +// +// 1) The used space calculation for a pool is not necessarily +// independent of the others. We can easily get from G1 the overall +// used space in the entire heap, the number of regions in the young +// generation (includes both eden and survivors), and the number of +// survivor regions. So, from that we calculate: +// +// survivor_used = survivor_num * region_size +// eden_used = young_region_num * region_size - survivor_used +// old_gen_used = overall_used - eden_used - survivor_used +// +// Note that survivor_used and eden_used are upper bounds. To get the +// actual value we would have to iterate over the regions and add up +// ->used(). But that'd be expensive. So, we'll accept some lack of +// accuracy for those two. But, we have to be careful when calculating +// old_gen_used, in case we subtract from overall_used more then the +// actual number and our result goes negative. +// +// 2) Calculating the used space is straightforward, as described +// above. However, how do we calculate the committed space, given that +// we allocate space for the eden, survivor, and old gen out of the +// same pool of regions? One way to do this is to use the used value +// as also the committed value for the eden and survivor spaces and +// then calculate the old gen committed space as follows: +// +// old_gen_committed = overall_committed - eden_committed - survivor_committed +// +// Maybe a better way to do that would be to calculate used for eden +// and survivor as a sum of ->used() over their regions and then +// calculate committed as region_num * region_size (i.e., what we use +// to calculate the used space now). This is something to consider +// in the future. +// +// 3) Another decision that is again not straightforward is what is +// the max size that each memory pool can grow to. Right now, we set +// that the committed size for the eden and the survivors and +// calculate the old gen max as follows (basically, it's a similar +// pattern to what we use for the committed space, as described +// above): +// +// old_gen_max = overall_max - eden_max - survivor_max +// +// 4) Now, there is a very subtle issue with all the above. The +// framework will call get_memory_usage() on the three pools +// asynchronously. As a result, each call might get a different value +// for, say, survivor_num which will yield inconsistent values for +// eden_used, survivor_used, and old_gen_used (as survivor_num is used +// in the calculation of all three). This would normally be +// ok. However, it's possible that this might cause the sum of +// eden_used, survivor_used, and old_gen_used to go over the max heap +// size and this seems to sometimes cause JConsole (and maybe other +// clients) to get confused. There's not a really an easy / clean +// solution to this problem, due to the asynchrounous nature of the +// framework. + + +// This class is shared by the three G1 memory pool classes +// (G1EdenPool, G1SurvivorPool, G1OldGenPool). Given that the way we +// calculate used / committed bytes for these three pools is related +// (see comment above), we put the calculations in this class so that +// we can easily share them among the subclasses. +class G1MemoryPoolSuper : public CollectedMemoryPool { +private: + // It returns x - y if x > y, 0 otherwise. + // As described in the comment above, some of the inputs to the + // calculations we have to do are obtained concurrently and hence + // may be inconsistent with each other. So, this provides a + // defensive way of performing the subtraction and avoids the value + // going negative (which would mean a very large result, given that + // the parameter are size_t). + static size_t subtract_up_to_zero(size_t x, size_t y) { + if (x > y) { + return x - y; + } else { + return 0; + } + } + +protected: + G1CollectedHeap* _g1h; + + // Would only be called from subclasses. + G1MemoryPoolSuper(G1CollectedHeap* g1h, + const char* name, + size_t init_size, + size_t max_size, + bool support_usage_threshold); + + // The reason why all the code is in static methods is so that it + // can be safely called from the constructors of the subclasses. + + static size_t overall_committed(G1CollectedHeap* g1h) { + return g1h->capacity(); + } + static size_t overall_used(G1CollectedHeap* g1h) { + return g1h->used_unlocked(); + } + static size_t overall_max(G1CollectedHeap* g1h) { + return g1h->g1_reserved_obj_bytes(); + } + + static size_t eden_space_committed(G1CollectedHeap* g1h); + static size_t eden_space_used(G1CollectedHeap* g1h); + static size_t eden_space_max(G1CollectedHeap* g1h); + + static size_t survivor_space_committed(G1CollectedHeap* g1h); + static size_t survivor_space_used(G1CollectedHeap* g1h); + static size_t survivor_space_max(G1CollectedHeap* g1h); + + static size_t old_space_committed(G1CollectedHeap* g1h); + static size_t old_space_used(G1CollectedHeap* g1h); + static size_t old_space_max(G1CollectedHeap* g1h); +}; + +// Memory pool that represents the G1 eden. +class G1EdenPool : public G1MemoryPoolSuper { +public: + G1EdenPool(G1CollectedHeap* g1h); + + size_t used_in_bytes() { + return eden_space_used(_g1h); + } + size_t max_size() const { + return eden_space_max(_g1h); + } + MemoryUsage get_memory_usage(); +}; + +// Memory pool that represents the G1 survivor. +class G1SurvivorPool : public G1MemoryPoolSuper { +public: + G1SurvivorPool(G1CollectedHeap* g1h); + + size_t used_in_bytes() { + return survivor_space_used(_g1h); + } + size_t max_size() const { + return survivor_space_max(_g1h); + } + MemoryUsage get_memory_usage(); +}; + +// Memory pool that represents the G1 old gen. +class G1OldGenPool : public G1MemoryPoolSuper { +public: + G1OldGenPool(G1CollectedHeap* g1h); + + size_t used_in_bytes() { + return old_space_used(_g1h); + } + size_t max_size() const { + return old_space_max(_g1h); + } + MemoryUsage get_memory_usage(); +}; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/management.cpp --- a/src/share/vm/services/management.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/services/management.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -790,7 +790,7 @@ assert(!has_undefined_init_size, "Undefined init size"); assert(!has_undefined_max_size, "Undefined max size"); - MemoryUsage usage((heap ? Arguments::initial_heap_size() : total_init), + MemoryUsage usage((heap ? InitialHeapSize : total_init), total_used, total_committed, (heap ? Universe::heap()->max_capacity() : total_max)); @@ -1507,16 +1507,17 @@ return (jobjectArray)JNIHandles::make_local(env, flags_ah()); JVM_END -// utility function used by jmm_GetVMGlobals -void add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) { +// Utility function used by jmm_GetVMGlobals. Returns false if flag type +// can't be determined, true otherwise. If false is returned, then *global +// will be incomplete and invalid. +bool add_global_entry(JNIEnv* env, Handle name, jmmVMGlobal *global, Flag *flag, TRAPS) { Handle flag_name; if (name() == NULL) { - flag_name = java_lang_String::create_from_str(flag->name, CHECK); + flag_name = java_lang_String::create_from_str(flag->name, CHECK_false); } else { flag_name = name; } global->name = (jstring)JNIHandles::make_local(env, flag_name()); - global->type = JMM_VMGLOBAL_TYPE_UNKNOWN; if (flag->is_bool()) { global->value.z = flag->get_bool() ? JNI_TRUE : JNI_FALSE; @@ -1527,10 +1528,17 @@ } else if (flag->is_uintx()) { global->value.j = (jlong)flag->get_uintx(); global->type = JMM_VMGLOBAL_TYPE_JLONG; + } else if (flag->is_uint64_t()) { + global->value.j = (jlong)flag->get_uint64_t(); + global->type = JMM_VMGLOBAL_TYPE_JLONG; } else if (flag->is_ccstr()) { - Handle str = java_lang_String::create_from_str(flag->get_ccstr(), CHECK); + Handle str = java_lang_String::create_from_str(flag->get_ccstr(), CHECK_false); global->value.l = (jobject)JNIHandles::make_local(env, str()); global->type = JMM_VMGLOBAL_TYPE_JSTRING; + } else { + global->type = JMM_VMGLOBAL_TYPE_UNKNOWN; + assert(false, "Unsupported VMGlobal Type"); + return false; } global->writeable = flag->is_writeable(); @@ -1557,6 +1565,8 @@ default: global->origin = JMM_VMGLOBAL_ORIGIN_OTHER; } + + return true; } // Fill globals array of count length with jmmVMGlobal entries @@ -1599,8 +1609,8 @@ Handle sh(THREAD, s); char* str = java_lang_String::as_utf8_string(s); Flag* flag = Flag::find_flag(str, strlen(str)); - if (flag != NULL) { - add_global_entry(env, sh, &globals[i], flag, THREAD); + if (flag != NULL && + add_global_entry(env, sh, &globals[i], flag, THREAD)) { num_entries++; } else { globals[i].name = NULL; @@ -1617,8 +1627,8 @@ for (int i = 0; i < nFlags && num_entries < count; i++) { Flag* flag = &Flag::flags[i]; // Exclude the locked (diagnostic, experimental) flags - if (flag->is_unlocked() || flag->is_unlocker()) { - add_global_entry(env, null_h, &globals[num_entries], flag, THREAD); + if ((flag->is_unlocked() || flag->is_unlocker()) && + add_global_entry(env, null_h, &globals[num_entries], flag, THREAD)) { num_entries++; } } @@ -1650,11 +1660,14 @@ bool bvalue = (new_value.z == JNI_TRUE ? true : false); succeed = CommandLineFlags::boolAtPut(name, &bvalue, MANAGEMENT); } else if (flag->is_intx()) { - intx ivalue = new_value.j; + intx ivalue = (intx)new_value.j; succeed = CommandLineFlags::intxAtPut(name, &ivalue, MANAGEMENT); } else if (flag->is_uintx()) { - uintx uvalue = new_value.j; + uintx uvalue = (uintx)new_value.j; succeed = CommandLineFlags::uintxAtPut(name, &uvalue, MANAGEMENT); + } else if (flag->is_uint64_t()) { + uint64_t uvalue = (uint64_t)new_value.j; + succeed = CommandLineFlags::uint64_tAtPut(name, &uvalue, MANAGEMENT); } else if (flag->is_ccstr()) { oop str = JNIHandles::resolve_external_guard(new_value.l); if (str == NULL) { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/memoryManager.cpp --- a/src/share/vm/services/memoryManager.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/services/memoryManager.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -72,6 +72,14 @@ return (GCMemoryManager*) new PSMarkSweepMemoryManager(); } +GCMemoryManager* MemoryManager::get_g1YoungGen_memory_manager() { + return (GCMemoryManager*) new G1YoungGenMemoryManager(); +} + +GCMemoryManager* MemoryManager::get_g1OldGen_memory_manager() { + return (GCMemoryManager*) new G1OldGenMemoryManager(); +} + instanceOop MemoryManager::get_memory_manager_instance(TRAPS) { // Must do an acquire so as to force ordering of subsequent // loads from anything _memory_mgr_obj points to or implies. diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/memoryManager.hpp --- a/src/share/vm/services/memoryManager.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/services/memoryManager.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -54,7 +54,9 @@ ParNew, ConcurrentMarkSweep, PSScavenge, - PSMarkSweep + PSMarkSweep, + G1YoungGen, + G1OldGen }; MemoryManager(); @@ -85,6 +87,8 @@ static GCMemoryManager* get_cms_memory_manager(); static GCMemoryManager* get_psScavenge_memory_manager(); static GCMemoryManager* get_psMarkSweep_memory_manager(); + static GCMemoryManager* get_g1YoungGen_memory_manager(); + static GCMemoryManager* get_g1OldGen_memory_manager(); }; @@ -231,3 +235,21 @@ MemoryManager::Name kind() { return MemoryManager::PSMarkSweep; } const char* name() { return "PS MarkSweep"; } }; + +class G1YoungGenMemoryManager : public GCMemoryManager { +private: +public: + G1YoungGenMemoryManager() : GCMemoryManager() {} + + MemoryManager::Name kind() { return MemoryManager::G1YoungGen; } + const char* name() { return "G1 Young Generation"; } +}; + +class G1OldGenMemoryManager : public GCMemoryManager { +private: +public: + G1OldGenMemoryManager() : GCMemoryManager() {} + + MemoryManager::Name kind() { return MemoryManager::G1OldGen; } + const char* name() { return "G1 Old Generation"; } +}; diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/memoryService.cpp --- a/src/share/vm/services/memoryService.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/services/memoryService.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -60,8 +60,8 @@ break; } case CollectedHeap::G1CollectedHeap : { - G1CollectedHeap::g1_unimplemented(); - return; + add_g1_heap_info(G1CollectedHeap::heap()); + break; } #endif // SERIALGC default: { @@ -164,6 +164,19 @@ add_psOld_memory_pool(heap->old_gen(), _major_gc_manager); add_psPerm_memory_pool(heap->perm_gen(), _major_gc_manager); } + +void MemoryService::add_g1_heap_info(G1CollectedHeap* g1h) { + assert(UseG1GC, "sanity"); + + _minor_gc_manager = MemoryManager::get_g1YoungGen_memory_manager(); + _major_gc_manager = MemoryManager::get_g1OldGen_memory_manager(); + _managers_list->append(_minor_gc_manager); + _managers_list->append(_major_gc_manager); + + add_g1YoungGen_memory_pool(g1h, _major_gc_manager, _minor_gc_manager); + add_g1OldGen_memory_pool(g1h, _major_gc_manager); + add_g1PermGen_memory_pool(g1h, _major_gc_manager); +} #endif // SERIALGC MemoryPool* MemoryService::add_gen(Generation* gen, @@ -384,6 +397,64 @@ mgr->add_pool(perm_gen); _pools_list->append(perm_gen); } + +void MemoryService::add_g1YoungGen_memory_pool(G1CollectedHeap* g1h, + MemoryManager* major_mgr, + MemoryManager* minor_mgr) { + assert(major_mgr != NULL && minor_mgr != NULL, "should have two managers"); + + G1EdenPool* eden = new G1EdenPool(g1h); + G1SurvivorPool* survivor = new G1SurvivorPool(g1h); + + major_mgr->add_pool(eden); + major_mgr->add_pool(survivor); + minor_mgr->add_pool(eden); + minor_mgr->add_pool(survivor); + _pools_list->append(eden); + _pools_list->append(survivor); +} + +void MemoryService::add_g1OldGen_memory_pool(G1CollectedHeap* g1h, + MemoryManager* mgr) { + assert(mgr != NULL, "should have one manager"); + + G1OldGenPool* old_gen = new G1OldGenPool(g1h); + mgr->add_pool(old_gen); + _pools_list->append(old_gen); +} + +void MemoryService::add_g1PermGen_memory_pool(G1CollectedHeap* g1h, + MemoryManager* mgr) { + assert(mgr != NULL, "should have one manager"); + + CompactingPermGenGen* perm_gen = (CompactingPermGenGen*) g1h->perm_gen(); + PermanentGenerationSpec* spec = perm_gen->spec(); + size_t max_size = spec->max_size() - spec->read_only_size() + - spec->read_write_size(); + MemoryPool* pool = add_space(perm_gen->unshared_space(), + "G1 Perm Gen", + false, /* is_heap */ + max_size, + true /* support_usage_threshold */); + mgr->add_pool(pool); + + // in case we support CDS in G1 + if (UseSharedSpaces) { + pool = add_space(perm_gen->ro_space(), + "G1 Perm Gen [shared-ro]", + false, /* is_heap */ + spec->read_only_size(), + true /* support_usage_threshold */); + mgr->add_pool(pool); + + pool = add_space(perm_gen->rw_space(), + "G1 Perm Gen [shared-rw]", + false, /* is_heap */ + spec->read_write_size(), + true /* support_usage_threshold */); + mgr->add_pool(pool); + } +} #endif // SERIALGC void MemoryService::add_code_heap_memory_pool(CodeHeap* heap) { diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/services/memoryService.hpp --- a/src/share/vm/services/memoryService.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/services/memoryService.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -40,6 +40,7 @@ class ParallelScavengeHeap; class CompactingPermGenGen; class CMSPermGenGen; +class G1CollectedHeap; // VM Monitoring and Management Support @@ -88,6 +89,13 @@ static void add_psPerm_memory_pool(PSPermGen* perm, MemoryManager* mgr); + static void add_g1YoungGen_memory_pool(G1CollectedHeap* g1h, + MemoryManager* major_mgr, + MemoryManager* minor_mgr); + static void add_g1OldGen_memory_pool(G1CollectedHeap* g1h, + MemoryManager* mgr); + static void add_g1PermGen_memory_pool(G1CollectedHeap* g1h, + MemoryManager* mgr); static MemoryPool* add_space(ContiguousSpace* space, const char* name, @@ -111,6 +119,7 @@ static void add_gen_collected_heap_info(GenCollectedHeap* heap); static void add_parallel_scavenge_heap_info(ParallelScavengeHeap* heap); + static void add_g1_heap_info(G1CollectedHeap* g1h); public: static void set_universe_heap(CollectedHeap* heap); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/utilities/growableArray.hpp --- a/src/share/vm/utilities/growableArray.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/utilities/growableArray.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -278,6 +278,17 @@ _len--; } + // inserts the given element before the element at index i + void insert_before(const int idx, const E& elem) { + check_nesting(); + if (_len == _max) grow(_len); + for (int j = _len - 1; j >= idx; j--) { + _data[j + 1] = _data[j]; + } + _len++; + _data[idx] = elem; + } + void appendAll(const GrowableArray* l) { for (int i = 0; i < l->_len; i++) { raw_at_put_grow(_len, l->_data[i], 0); diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/utilities/numberSeq.cpp --- a/src/share/vm/utilities/numberSeq.cpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/utilities/numberSeq.cpp Fri Dec 11 16:38:37 2009 -0800 @@ -241,3 +241,33 @@ return b0 + b1 * num; } + + +// Printing/Debugging Support + +void AbsSeq::dump() { dump_on(gclog_or_tty); } + +void AbsSeq::dump_on(outputStream* s) { + s->print_cr("\t _num = %d, _sum = %7.3f, _sum_of_squares = %7.3f", + _num, _sum, _sum_of_squares); + s->print_cr("\t _davg = %7.3f, _dvariance = %7.3f, _alpha = %7.3f", + _davg, _dvariance, _alpha); +} + +void NumberSeq::dump_on(outputStream* s) { + AbsSeq::dump_on(s); + s->print_cr("\t\t _last = %7.3f, _maximum = %7.3f"); +} + +void TruncatedSeq::dump_on(outputStream* s) { + AbsSeq::dump_on(s); + s->print_cr("\t\t _length = %d, _next = %d", _length, _next); + for (int i = 0; i < _length; i++) { + if (i%5 == 0) { + s->cr(); + s->print("\t"); + } + s->print("\t[%d]=%7.3f", i, _sequence[i]); + } + s->print_cr(""); +} diff -r 7589c1b72907 -r 74e00f62c726 src/share/vm/utilities/numberSeq.hpp --- a/src/share/vm/utilities/numberSeq.hpp Thu Dec 03 12:52:49 2009 -0800 +++ b/src/share/vm/utilities/numberSeq.hpp Fri Dec 11 16:38:37 2009 -0800 @@ -74,6 +74,10 @@ double davg() const; // decaying average double dvariance() const; // decaying variance double dsd() const; // decaying "standard deviation" + + // Debugging/Printing + virtual void dump(); + virtual void dump_on(outputStream* s); }; class NumberSeq: public AbsSeq { @@ -91,6 +95,9 @@ virtual void add(double val); virtual double maximum() const { return _maximum; } virtual double last() const { return _last; } + + // Debugging/Printing + virtual void dump_on(outputStream* s); }; class TruncatedSeq: public AbsSeq { @@ -114,4 +121,7 @@ double oldest() const; // the oldest valid value in the sequence double predict_next() const; // prediction based on linear regression + + // Debugging/Printing + virtual void dump_on(outputStream* s); }; diff -r 7589c1b72907 -r 74e00f62c726 test/compiler/6769124/TestArrayCopy6769124.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6769124/TestArrayCopy6769124.java Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,53 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6769124 + * @summary arraycopy may crash the VM with c1 on 64 bit + */ + +public class TestArrayCopy6769124 { + + public static void main(String[] args) { + + int k = 1 << 31; + + + for(int j = 0; j <1000000; j++) { + int i = -1; + while(i < 10) { + i++; + } + + int m = k * i; + + int[] O1 = new int[20]; + int[] O2 = new int[20]; + + System.arraycopy(O1, i, O2, i, 1); //will crash on amd64 + System.arraycopy(O1, m, O2, m, 1); //will crash on sparcv9 + } + } +} diff -r 7589c1b72907 -r 74e00f62c726 test/compiler/6769124/TestDeoptInt6769124.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6769124/TestDeoptInt6769124.java Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,56 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6769124 + * @summary int value might not be correctly decoded on deopt with c1 on 64 bit + * + * @run main/othervm -Xcomp -XX:CompileOnly=TestDeoptInt6769124.m TestDeoptInt6769124 + */ + +public class TestDeoptInt6769124 { + + static class A { + volatile int vl; + A(int v) { + vl = v; + } + } + + static void m(int b) { + A a = new A(10); + int c; + c = b + a.vl; //accessing volatile field of class not loaded at compile time forces a deopt + if(c != 20) { + System.out.println("a (= " + a.vl + ") + b (= " + b + ") = c (= " + c + ") != 20"); + throw new InternalError(); + } + } + + public static void main(String[] args) { + m(10); + } + +} diff -r 7589c1b72907 -r 74e00f62c726 test/compiler/6769124/TestUnalignedLoad6769124.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6769124/TestUnalignedLoad6769124.java Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,69 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6769124 + * @summary unaligned load may fail with c1 on 64 bit + */ + +public class TestUnalignedLoad6769124 { + + static long l1v = 0x200000003L; + static long l2v = 0x400000005L; + static double d1v = Double.MAX_VALUE; + static double d2v = Double.MIN_VALUE; + + public static void main(String[] args) { + long l1 = l1v; + double d1 = d1v; + long l2 = l2v; + double d2 = d2v; + + // Run long enough to induce an OSR + for (int i = 0; i < 10000000; i++) { + } + boolean error = false; + + if (l1 != l1v) { + System.out.println(l1 + " != " + l1v); + error = true; + } + if (l2 != l2v) { + System.out.println(l2 + " != " + l2v); + error = true; + } + if (d1 != d1v) { + System.out.println(d1 + " != " + d1v); + error = true; + } + if (d2 != d2v) { + System.out.println(d2 + " != " + d2v); + error = true; + } + if (error) { + throw new InternalError(); + } + } +} diff -r 7589c1b72907 -r 74e00f62c726 test/compiler/6852078/Test6852078.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6852078/Test6852078.java Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,57 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + * + */ + +/** + * @test + * @bug 6852078 + * @summary Disable SuperWord optimization for unsafe read/write + * + * @run main/othervm Test6852078 + */ + +import java.util.*; +import java.nio.ByteBuffer; +import com.sun.corba.se.impl.encoding.ByteBufferWithInfo; +import com.sun.jndi.toolkit.corba.CorbaUtils; + +public class Test6852078 { + + public Test6852078(String [] args) { + + int capacity = 128; + ByteBuffer bb = ByteBuffer.allocateDirect(capacity); + ByteBufferWithInfo bbwi = new ByteBufferWithInfo( CorbaUtils.getOrb(null, -1, new Hashtable()), bb); + byte[] tmpBuf; + tmpBuf = new byte[bbwi.buflen]; + + for (int i = 0; i < capacity; i++) + tmpBuf[i] = bbwi.byteBuffer.get(i); + } + + public static void main(String [] args) { + for (int i=0; i<2000; i++) { + Test6852078 t = new Test6852078(args); + } + } +} diff -r 7589c1b72907 -r 74e00f62c726 test/compiler/6901572/Test.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/compiler/6901572/Test.java Fri Dec 11 16:38:37 2009 -0800 @@ -0,0 +1,55 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6901572 + * @summary JVM 1.6.16 crash on loops: assert(has_node(i),"") + * + * @run main/othervm Test + */ + + +public class Test { + + public static void main(String[] args) { + for (int i = 0; i < 2; i++) + NestedLoop(); + } + + public static long NestedLoop() { + final int n = 50; + long startTime = System.currentTimeMillis(); + int x = 0; + for(int a = 0; a < n; a++) + for(int b = 0; b < n; b++) + for(int c = 0; c < n; c++) + for(int d = 0; d < n; d++) + for(int e = 0; e < n; e++) + for(int f = 0; f < n; f++) + x++; + long stopTime = System.currentTimeMillis(); + + return stopTime - startTime; + } +}