--- a/hotspot/src/cpu/sparc/vm/c1_LIRAssembler_sparc.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 {
--- a/hotspot/src/cpu/sparc/vm/c1_LIRGenerator_sparc.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
}
--- a/hotspot/src/cpu/sparc/vm/c1_globals_sparc.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 );
--- a/hotspot/src/cpu/sparc/vm/c2_globals_sparc.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/cpu/sparc/vm/globals_sparc.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/cpu/sparc/vm/templateInterpreter_sparc.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/cpu/x86/vm/assembler_x86.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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));
+ }
}
--- a/hotspot/src/cpu/x86/vm/assembler_x86.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/cpu/x86/vm/c1_LIRGenerator_x86.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.
--- a/hotspot/src/cpu/x86/vm/c1_globals_x86.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 );
--- a/hotspot/src/cpu/x86/vm/c2_globals_x86.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/cpu/x86/vm/globals_x86.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_32.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/cpu/x86/vm/templateInterpreter_x86_64.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/cpu/x86/vm/templateTable_x86_32.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
}
//----------------------------------------------------------------------------------------------------
--- a/hotspot/src/cpu/x86/vm/vm_version_x86.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/cpu/zero/vm/cppInterpreter_zero.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/cpu/zero/vm/frame_zero.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/cpu/zero/vm/frame_zero.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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,
--- a/hotspot/src/cpu/zero/vm/globals_zero.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/cpu/zero/vm/sharedRuntime_zero.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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,
--- a/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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() {
--- a/hotspot/src/os_cpu/linux_x86/vm/globals_linux_x86.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/os_cpu/solaris_x86/vm/globals_solaris_x86.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/os_cpu/windows_x86/vm/globals_windows_x86.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/c1/c1_GraphBuilder.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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");
}
}
--- a/hotspot/src/share/vm/c1/c1_LIRGenerator.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/c1/c1_LinearScan.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/ci/ciEnv.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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();
--- a/hotspot/src/share/vm/ci/ciEnv.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
}
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 {
--- a/hotspot/src/share/vm/ci/ciInstanceKlass.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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<ciField*>* non_static_fields();
--- a/hotspot/src/share/vm/ci/ciObjectFactory.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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();
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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:
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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();
}
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/classfile/verifier.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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(
--- a/hotspot/src/share/vm/classfile/vmSymbols.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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:
--- a/hotspot/src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/gc_implementation/g1/dirtyCardQueue.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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();
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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:");
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectorPolicy.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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: ***
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1MMUTracker.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/gc_implementation/g1/g1_globals.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.") \
\
--- a/hotspot/src/share/vm/gc_implementation/g1/ptrQueue.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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--;
}
}
--- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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();
}
--- a/hotspot/src/share/vm/gc_implementation/g1/vm_operations_g1.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 {
--- a/hotspot/src/share/vm/gc_implementation/includeDB_gc_g1 Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/gc_implementation/parallelScavenge/psGCAdaptivePolicyCounters.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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,
--- a/hotspot/src/share/vm/includeDB_compiler2 Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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_<arch_model>.cpp runtime.hpp
stubRoutines.cpp runtime.hpp
--- a/hotspot/src/share/vm/includeDB_core Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/interpreter/bytecodeInterpreter.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/interpreter/bytecodeTracer.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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());
}
--- a/hotspot/src/share/vm/interpreter/interpreter.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/interpreter/interpreterRuntime.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/interpreter/linkResolver.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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();
--- a/hotspot/src/share/vm/interpreter/rewriter.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.
}
--- a/hotspot/src/share/vm/interpreter/rewriter.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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)
+ };
};
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/interpreter/templateInterpreter.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/interpreter/templateInterpreterGenerator.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/memory/barrierSet.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
}
--- a/hotspot/src/share/vm/memory/barrierSet.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/memory/barrierSet.inline.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/memory/cardTableModRefBS.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/memory/collectorPolicy.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
}
--- a/hotspot/src/share/vm/memory/sharedHeap.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/memory/universe.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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() {
--- a/hotspot/src/share/vm/memory/universe.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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; }
--- a/hotspot/src/share/vm/oops/constantPoolOop.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
}
--- a/hotspot/src/share/vm/oops/constantPoolOop.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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) {
--- a/hotspot/src/share/vm/oops/cpCacheOop.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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:
--- a/hotspot/src/share/vm/oops/cpCacheOop.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/oops/generateOopMap.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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];
--- a/hotspot/src/share/vm/oops/instanceKlassKlass.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
}
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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,
--- a/hotspot/src/share/vm/oops/objArrayOop.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/c2_globals.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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)
--- a/hotspot/src/share/vm/opto/c2_globals.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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)
--- a/hotspot/src/share/vm/opto/callGenerator.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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() {
--- a/hotspot/src/share/vm/opto/callGenerator.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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,
--- a/hotspot/src/share/vm/opto/callnode.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 {
--- a/hotspot/src/share/vm/opto/callnode.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/compile.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/compile.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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<CallGenerator*> _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; }
--- a/hotspot/src/share/vm/opto/doCall.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.<init>(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) {
--- a/hotspot/src/share/vm/opto/escape.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/opto/graphKit.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 __
-
--- a/hotspot/src/share/vm/opto/graphKit.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/loopnode.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/macro.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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()) {
--- a/hotspot/src/share/vm/opto/matcher.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/opto/memnode.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/node.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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); }
--- a/hotspot/src/share/vm/opto/parse1.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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));
}
--- a/hotspot/src/share/vm/opto/parseHelper.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/phase.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/opto/phaseX.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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.<init>(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<int> _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<StringConcat*> 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();
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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);
+};
--- a/hotspot/src/share/vm/opto/superword.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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");
--- a/hotspot/src/share/vm/opto/type.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/prims/jni.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/prims/jvm.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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");
}
--- a/hotspot/src/share/vm/prims/jvmtiManageCapabilities.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/prims/methodHandles.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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)}
};
--- a/hotspot/src/share/vm/runtime/arguments.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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
--- a/hotspot/src/share/vm/runtime/arguments.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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; }
--- a/hotspot/src/share/vm/runtime/globals.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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;
--- a/hotspot/src/share/vm/runtime/globals.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.<init> 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)") \
--- a/hotspot/src/share/vm/runtime/globals_extension.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/runtime/os.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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();
--- a/hotspot/src/share/vm/services/attachListener.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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 {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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();
+};
--- a/hotspot/src/share/vm/services/management.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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) {
--- a/hotspot/src/share/vm/services/memoryManager.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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.
--- a/hotspot/src/share/vm/services/memoryManager.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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"; }
+};
--- a/hotspot/src/share/vm/services/memoryService.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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) {
--- a/hotspot/src/share/vm/services/memoryService.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
--- a/hotspot/src/share/vm/utilities/growableArray.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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<E>* l) {
for (int i = 0; i < l->_len; i++) {
raw_at_put_grow(_len, l->_data[i], 0);
--- a/hotspot/src/share/vm/utilities/numberSeq.cpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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("");
+}
--- a/hotspot/src/share/vm/utilities/numberSeq.hpp Thu Dec 03 12:52:49 2009 -0800
+++ b/hotspot/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);
};
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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);
+ }
+
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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);
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/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;
+ }
+}