6614597: Performance variability in jvm2008 xml.validation
Summary: Fix incorrect marking of methods as not compilable.
Reviewed-by: never
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -1681,11 +1681,8 @@
// If no method data exists, go to profile_continue.
test_method_data_pointer(profile_continue);
- // We are making a call. Increment the count.
- increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
-
// Record the receiver type.
- record_klass_in_profile(receiver, scratch);
+ record_klass_in_profile(receiver, scratch, true);
// The method data pointer needs to be updated to reflect the new target.
update_mdp_by_constant(in_bytes(VirtualCallData::virtual_call_data_size()));
@@ -1695,9 +1692,13 @@
void InterpreterMacroAssembler::record_klass_in_profile_helper(
Register receiver, Register scratch,
- int start_row, Label& done) {
- if (TypeProfileWidth == 0)
+ int start_row, Label& done, bool is_virtual_call) {
+ if (TypeProfileWidth == 0) {
+ if (is_virtual_call) {
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
+ }
return;
+ }
int last_row = VirtualCallData::row_limit() - 1;
assert(start_row <= last_row, "must be work left to do");
@@ -1714,6 +1715,7 @@
// See if the receiver is receiver[n].
int recvr_offset = in_bytes(VirtualCallData::receiver_offset(row));
test_mdp_data_at(recvr_offset, receiver, next_test, scratch);
+ // delayed()->tst(scratch);
// The receiver is receiver[n]. Increment count[n].
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(row));
@@ -1723,20 +1725,31 @@
bind(next_test);
if (test_for_null_also) {
+ Label found_null;
// Failed the equality check on receiver[n]... Test for null.
if (start_row == last_row) {
// The only thing left to do is handle the null case.
- brx(Assembler::notZero, false, Assembler::pt, done);
- delayed()->nop();
+ if (is_virtual_call) {
+ brx(Assembler::zero, false, Assembler::pn, found_null);
+ delayed()->nop();
+ // Receiver did not match any saved receiver and there is no empty row for it.
+ // Increment total counter to indicate polimorphic case.
+ increment_mdp_data_at(in_bytes(CounterData::count_offset()), scratch);
+ ba(false, done);
+ delayed()->nop();
+ bind(found_null);
+ } else {
+ brx(Assembler::notZero, false, Assembler::pt, done);
+ delayed()->nop();
+ }
break;
}
// Since null is rare, make it be the branch-taken case.
- Label found_null;
brx(Assembler::zero, false, Assembler::pn, found_null);
delayed()->nop();
// Put all the "Case 3" tests here.
- record_klass_in_profile_helper(receiver, scratch, start_row + 1, done);
+ record_klass_in_profile_helper(receiver, scratch, start_row + 1, done, is_virtual_call);
// Found a null. Keep searching for a matching receiver,
// but remember that this is an empty (unused) slot.
@@ -1753,16 +1766,18 @@
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
mov(DataLayout::counter_increment, scratch);
set_mdp_data_at(count_offset, scratch);
- ba(false, done);
- delayed()->nop();
+ if (start_row > 0) {
+ ba(false, done);
+ delayed()->nop();
+ }
}
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
- Register scratch) {
+ Register scratch, bool is_virtual_call) {
assert(ProfileInterpreter, "must be profiling");
Label done;
- record_klass_in_profile_helper(receiver, scratch, 0, done);
+ record_klass_in_profile_helper(receiver, scratch, 0, done, is_virtual_call);
bind (done);
}
@@ -1840,7 +1855,7 @@
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
// Record the object type.
- record_klass_in_profile(klass, scratch);
+ record_klass_in_profile(klass, scratch, false);
}
// The method data pointer needs to be updated.
--- a/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/cpu/sparc/vm/interp_masm_sparc.hpp Mon Feb 01 16:49:49 2010 -0800
@@ -290,9 +290,9 @@
void test_mdp_data_at(int offset, Register value, Label& not_equal_continue,
Register scratch);
- void record_klass_in_profile(Register receiver, Register scratch);
+ void record_klass_in_profile(Register receiver, Register scratch, bool is_virtual_call);
void record_klass_in_profile_helper(Register receiver, Register scratch,
- int start_row, Label& done);
+ int start_row, Label& done, bool is_virtual_call);
void update_mdp_by_offset(int offset_of_disp, Register scratch);
void update_mdp_by_offset(Register reg, int offset_of_disp,
--- a/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/cpu/x86/vm/c1_LIRAssembler_x86.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -3209,7 +3209,6 @@
Register mdo = op->mdo()->as_register();
__ movoop(mdo, md->constant_encoding());
Address counter_addr(mdo, md->byte_offset_of_slot(data, CounterData::count_offset()));
- __ addl(counter_addr, DataLayout::counter_increment);
Bytecodes::Code bc = method->java_code_at_bci(bci);
// Perform additional virtual call profiling for invokevirtual and
// invokeinterface bytecodes
@@ -3276,14 +3275,18 @@
__ jcc(Assembler::notEqual, next_test);
__ movptr(recv_addr, recv);
__ movl(Address(mdo, md->byte_offset_of_slot(data, VirtualCallData::receiver_count_offset(i))), DataLayout::counter_increment);
- if (i < (VirtualCallData::row_limit() - 1)) {
- __ jmp(update_done);
- }
+ __ jmp(update_done);
__ bind(next_test);
}
+ // Receiver did not match any saved receiver and there is no empty row for it.
+ // Increment total counter to indicate polimorphic case.
+ __ addl(counter_addr, DataLayout::counter_increment);
__ bind(update_done);
}
+ } else {
+ // Static call
+ __ addl(counter_addr, DataLayout::counter_increment);
}
}
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -1239,17 +1239,19 @@
// If no method data exists, go to profile_continue.
test_method_data_pointer(mdp, profile_continue);
- // We are making a call. Increment the count.
- increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
-
Label skip_receiver_profile;
if (receiver_can_be_null) {
+ Label not_null;
testptr(receiver, receiver);
- jcc(Assembler::zero, skip_receiver_profile);
+ jccb(Assembler::notZero, not_null);
+ // We are making a call. Increment the count for null receiver.
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+ jmp(skip_receiver_profile);
+ bind(not_null);
}
// Record the receiver type.
- record_klass_in_profile(receiver, mdp, reg2);
+ record_klass_in_profile(receiver, mdp, reg2, true);
bind(skip_receiver_profile);
// The method data pointer needs to be updated to reflect the new target.
@@ -1263,10 +1265,14 @@
void InterpreterMacroAssembler::record_klass_in_profile_helper(
Register receiver, Register mdp,
- Register reg2,
- int start_row, Label& done) {
- if (TypeProfileWidth == 0)
+ Register reg2, int start_row,
+ Label& done, bool is_virtual_call) {
+ if (TypeProfileWidth == 0) {
+ if (is_virtual_call) {
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+ }
return;
+ }
int last_row = VirtualCallData::row_limit() - 1;
assert(start_row <= last_row, "must be work left to do");
@@ -1294,19 +1300,28 @@
bind(next_test);
if (row == start_row) {
+ Label found_null;
// Failed the equality check on receiver[n]... Test for null.
testptr(reg2, reg2);
if (start_row == last_row) {
// The only thing left to do is handle the null case.
- jcc(Assembler::notZero, done);
+ if (is_virtual_call) {
+ jccb(Assembler::zero, found_null);
+ // Receiver did not match any saved receiver and there is no empty row for it.
+ // Increment total counter to indicate polimorphic case.
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+ jmp(done);
+ bind(found_null);
+ } else {
+ jcc(Assembler::notZero, done);
+ }
break;
}
// Since null is rare, make it be the branch-taken case.
- Label found_null;
jcc(Assembler::zero, found_null);
// Put all the "Case 3" tests here.
- record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done);
+ record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call);
// Found a null. Keep searching for a matching receiver,
// but remember that this is an empty (unused) slot.
@@ -1323,16 +1338,18 @@
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
movptr(reg2, (int32_t)DataLayout::counter_increment);
set_mdp_data_at(mdp, count_offset, reg2);
- jmp(done);
+ if (start_row > 0) {
+ jmp(done);
+ }
}
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
- Register mdp,
- Register reg2) {
+ Register mdp, Register reg2,
+ bool is_virtual_call) {
assert(ProfileInterpreter, "must be profiling");
Label done;
- record_klass_in_profile_helper(receiver, mdp, reg2, 0, done);
+ record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call);
bind (done);
}
@@ -1425,7 +1442,7 @@
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
// Record the object type.
- record_klass_in_profile(klass, mdp, reg2);
+ record_klass_in_profile(klass, mdp, reg2, false);
assert(reg2 == rdi, "we know how to fix this blown reg");
restore_locals(); // Restore EDI
}
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_32.hpp Mon Feb 01 16:49:49 2010 -0800
@@ -213,10 +213,10 @@
Label& not_equal_continue);
void record_klass_in_profile(Register receiver, Register mdp,
- Register reg2);
+ Register reg2, bool is_virtual_call);
void record_klass_in_profile_helper(Register receiver, Register mdp,
- Register reg2,
- int start_row, Label& done);
+ Register reg2, int start_row,
+ Label& done, bool is_virtual_call);
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -1262,17 +1262,19 @@
// If no method data exists, go to profile_continue.
test_method_data_pointer(mdp, profile_continue);
- // We are making a call. Increment the count.
- increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
-
Label skip_receiver_profile;
if (receiver_can_be_null) {
+ Label not_null;
testptr(receiver, receiver);
- jcc(Assembler::zero, skip_receiver_profile);
+ jccb(Assembler::notZero, not_null);
+ // We are making a call. Increment the count for null receiver.
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+ jmp(skip_receiver_profile);
+ bind(not_null);
}
// Record the receiver type.
- record_klass_in_profile(receiver, mdp, reg2);
+ record_klass_in_profile(receiver, mdp, reg2, true);
bind(skip_receiver_profile);
// The method data pointer needs to be updated to reflect the new target.
@@ -1296,10 +1298,14 @@
// See below for example code.
void InterpreterMacroAssembler::record_klass_in_profile_helper(
Register receiver, Register mdp,
- Register reg2,
- int start_row, Label& done) {
- if (TypeProfileWidth == 0)
+ Register reg2, int start_row,
+ Label& done, bool is_virtual_call) {
+ if (TypeProfileWidth == 0) {
+ if (is_virtual_call) {
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+ }
return;
+ }
int last_row = VirtualCallData::row_limit() - 1;
assert(start_row <= last_row, "must be work left to do");
@@ -1327,19 +1333,28 @@
bind(next_test);
if (test_for_null_also) {
+ Label found_null;
// Failed the equality check on receiver[n]... Test for null.
testptr(reg2, reg2);
if (start_row == last_row) {
// The only thing left to do is handle the null case.
- jcc(Assembler::notZero, done);
+ if (is_virtual_call) {
+ jccb(Assembler::zero, found_null);
+ // Receiver did not match any saved receiver and there is no empty row for it.
+ // Increment total counter to indicate polimorphic case.
+ increment_mdp_data_at(mdp, in_bytes(CounterData::count_offset()));
+ jmp(done);
+ bind(found_null);
+ } else {
+ jcc(Assembler::notZero, done);
+ }
break;
}
// Since null is rare, make it be the branch-taken case.
- Label found_null;
jcc(Assembler::zero, found_null);
// Put all the "Case 3" tests here.
- record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done);
+ record_klass_in_profile_helper(receiver, mdp, reg2, start_row + 1, done, is_virtual_call);
// Found a null. Keep searching for a matching receiver,
// but remember that this is an empty (unused) slot.
@@ -1356,7 +1371,9 @@
int count_offset = in_bytes(VirtualCallData::receiver_count_offset(start_row));
movl(reg2, DataLayout::counter_increment);
set_mdp_data_at(mdp, count_offset, reg2);
- jmp(done);
+ if (start_row > 0) {
+ jmp(done);
+ }
}
// Example state machine code for three profile rows:
@@ -1368,7 +1385,7 @@
// if (row[1].rec != NULL) {
// // degenerate decision tree, rooted at row[2]
// if (row[2].rec == rec) { row[2].incr(); goto done; }
-// if (row[2].rec != NULL) { goto done; } // overflow
+// if (row[2].rec != NULL) { count.incr(); goto done; } // overflow
// row[2].init(rec); goto done;
// } else {
// // remember row[1] is empty
@@ -1381,14 +1398,15 @@
// if (row[2].rec == rec) { row[2].incr(); goto done; }
// row[0].init(rec); goto done;
// }
+// done:
void InterpreterMacroAssembler::record_klass_in_profile(Register receiver,
- Register mdp,
- Register reg2) {
+ Register mdp, Register reg2,
+ bool is_virtual_call) {
assert(ProfileInterpreter, "must be profiling");
Label done;
- record_klass_in_profile_helper(receiver, mdp, reg2, 0, done);
+ record_klass_in_profile_helper(receiver, mdp, reg2, 0, done, is_virtual_call);
bind (done);
}
@@ -1484,7 +1502,7 @@
mdp_delta = in_bytes(VirtualCallData::virtual_call_data_size());
// Record the object type.
- record_klass_in_profile(klass, mdp, reg2);
+ record_klass_in_profile(klass, mdp, reg2, false);
}
update_mdp_by_constant(mdp, mdp_delta);
--- a/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/cpu/x86/vm/interp_masm_x86_64.hpp Mon Feb 01 16:49:49 2010 -0800
@@ -222,10 +222,10 @@
Label& not_equal_continue);
void record_klass_in_profile(Register receiver, Register mdp,
- Register reg2);
+ Register reg2, bool is_virtual_call);
void record_klass_in_profile_helper(Register receiver, Register mdp,
- Register reg2,
- int start_row, Label& done);
+ Register reg2, int start_row,
+ Label& done, bool is_virtual_call);
void update_mdp_by_offset(Register mdp_in, int offset_of_offset);
void update_mdp_by_offset(Register mdp_in, Register reg, int offset_of_disp);
--- a/hotspot/src/share/vm/ci/ciMethod.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/ci/ciMethod.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -436,15 +436,20 @@
// we will set result._method also.
}
// Determine call site's morphism.
- // The call site count could be == (receivers_count_total + 1)
- // not only in the case of a polymorphic call but also in the case
- // when a method data snapshot is taken after the site count was updated
- // but before receivers counters were updated.
- if (morphism == result._limit) {
- // There were no array klasses and morphism <= MorphismLimit.
- if (morphism < ciCallProfile::MorphismLimit ||
- morphism == ciCallProfile::MorphismLimit &&
- (receivers_count_total+1) >= count) {
+ // The call site count is 0 with known morphism (onlt 1 or 2 receivers)
+ // or < 0 in the case of a type check failured for checkcast, aastore, instanceof.
+ // The call site count is > 0 in the case of a polymorphic virtual call.
+ if (morphism > 0 && morphism == result._limit) {
+ // The morphism <= MorphismLimit.
+ if ((morphism < ciCallProfile::MorphismLimit) ||
+ (morphism == ciCallProfile::MorphismLimit && count == 0)) {
+#ifdef ASSERT
+ if (count > 0) {
+ tty->print_cr("bci: %d", bci);
+ this->print_codes();
+ assert(false, "this call site should not be polymorphic");
+ }
+#endif
result._morphism = morphism;
}
}
@@ -452,10 +457,8 @@
// zero or less, presume that this is a typecheck profile and
// do nothing. Otherwise, increase count to be the sum of all
// receiver's counts.
- if (count > 0) {
- if (count < receivers_count_total) {
- count = receivers_count_total;
- }
+ if (count >= 0) {
+ count += receivers_count_total;
}
}
result._count = count;
--- a/hotspot/src/share/vm/code/dependencies.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/code/dependencies.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -843,13 +843,15 @@
if (occasional_print || final_stats) {
// Every now and then dump a little info about dependency searching.
if (xtty != NULL) {
- xtty->elem("deps_find_witness calls='%d' steps='%d' recursions='%d' singles='%d'",
+ ttyLocker ttyl;
+ xtty->elem("deps_find_witness calls='%d' steps='%d' recursions='%d' singles='%d'",
deps_find_witness_calls,
deps_find_witness_steps,
deps_find_witness_recursions,
deps_find_witness_singles);
}
if (final_stats || (TraceDependencies && WizardMode)) {
+ ttyLocker ttyl;
tty->print_cr("Dependency check (find_witness) "
"calls=%d, steps=%d (avg=%.1f), recursions=%d, singles=%d",
deps_find_witness_calls,
--- a/hotspot/src/share/vm/code/nmethod.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/code/nmethod.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -1117,7 +1117,6 @@
if (_method->code() == this) {
_method->clear_code(); // Break a cycle
}
- inc_decompile_count(); // Last chance to make a mark on the MDO
_method = NULL; // Clear the method of this dead nmethod
}
// Make the class unloaded - i.e., change state and notify sweeper
@@ -1177,15 +1176,17 @@
bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
- // If the method is already zombie there is nothing to do
- if (is_zombie()) {
- return false;
- }
+ bool was_alive = false;
// Make sure the nmethod is not flushed in case of a safepoint in code below.
nmethodLocker nml(this);
{
+ // If the method is already zombie there is nothing to do
+ if (is_zombie()) {
+ return false;
+ }
+
// invalidate osr nmethod before acquiring the patching lock since
// they both acquire leaf locks and we don't want a deadlock.
// This logic is equivalent to the logic below for patching the
@@ -1223,6 +1224,8 @@
assert(state == not_entrant, "other cases may need to be handled differently");
}
+ was_alive = is_in_use(); // Read state under lock
+
// Change state
flags.state = state;
@@ -1249,8 +1252,11 @@
mark_as_seen_on_stack();
}
- // It's a true state change, so mark the method as decompiled.
- inc_decompile_count();
+ if (was_alive) {
+ // It's a true state change, so mark the method as decompiled.
+ // Do it only for transition from alive.
+ inc_decompile_count();
+ }
// zombie only - if a JVMTI agent has enabled the CompiledMethodUnload event
// and it hasn't already been reported for this nmethod then report it now.
--- a/hotspot/src/share/vm/oops/methodDataOop.hpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/oops/methodDataOop.hpp Mon Feb 01 16:49:49 2010 -0800
@@ -1391,6 +1391,9 @@
}
void inc_decompile_count() {
_nof_decompiles += 1;
+ if (decompile_count() > (uint)PerMethodRecompilationCutoff) {
+ method()->set_not_compilable();
+ }
}
// Support for code generation
--- a/hotspot/src/share/vm/oops/methodOop.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/oops/methodOop.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -575,12 +575,6 @@
return true;
}
- methodDataOop mdo = method_data();
- if (mdo != NULL
- && (uint)mdo->decompile_count() > (uint)PerMethodRecompilationCutoff) {
- // Since (uint)-1 is large, -1 really means 'no cutoff'.
- return true;
- }
#ifdef COMPILER2
if (is_tier1_compile(comp_level)) {
if (is_not_tier1_compilable()) {
@@ -594,6 +588,15 @@
// call this when compiler finds that this method is not compilable
void methodOopDesc::set_not_compilable(int comp_level) {
+ if (PrintCompilation) {
+ ttyLocker ttyl;
+ tty->print("made not compilable ");
+ this->print_short_name(tty);
+ int size = this->code_size();
+ if (size > 0)
+ tty->print(" (%d bytes)", size);
+ tty->cr();
+ }
if ((TraceDeoptimization || LogCompilation) && (xtty != NULL)) {
ttyLocker ttyl;
xtty->begin_elem("make_not_compilable thread='%d'", (int) os::current_thread_id());
--- a/hotspot/src/share/vm/opto/doCall.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/opto/doCall.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -182,26 +182,16 @@
}
}
CallGenerator* miss_cg;
+ Deoptimization::DeoptReason reason = (profile.morphism() == 2) ?
+ Deoptimization::Reason_bimorphic :
+ Deoptimization::Reason_class_check;
if (( profile.morphism() == 1 ||
(profile.morphism() == 2 && next_hit_cg != NULL) ) &&
-
- !too_many_traps(Deoptimization::Reason_class_check)
-
- // Check only total number of traps per method to allow
- // the transition from monomorphic to bimorphic case between
- // compilations without falling into virtual call.
- // A monomorphic case may have the class_check trap flag is set
- // due to the time gap between the uncommon trap processing
- // when flags are set in MDO and the call site bytecode execution
- // in Interpreter when MDO counters are updated.
- // There was also class_check trap in monomorphic case due to
- // the bug 6225440.
-
+ !too_many_traps(jvms->method(), jvms->bci(), reason)
) {
// Generate uncommon trap for class check failure path
// in case of monomorphic or bimorphic virtual call site.
- miss_cg = CallGenerator::for_uncommon_trap(call_method,
- Deoptimization::Reason_class_check,
+ miss_cg = CallGenerator::for_uncommon_trap(call_method, reason,
Deoptimization::Action_maybe_recompile);
} else {
// Generate virtual call for class check failure path
--- a/hotspot/src/share/vm/opto/parseHelper.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/opto/parseHelper.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -414,8 +414,6 @@
void Parse::profile_call(Node* receiver) {
if (!method_data_update()) return;
- profile_generic_call();
-
switch (bc()) {
case Bytecodes::_invokevirtual:
case Bytecodes::_invokeinterface:
@@ -424,6 +422,7 @@
case Bytecodes::_invokestatic:
case Bytecodes::_invokedynamic:
case Bytecodes::_invokespecial:
+ profile_generic_call();
break;
default: fatal("unexpected call bytecode");
}
@@ -444,13 +443,16 @@
void Parse::profile_receiver_type(Node* receiver) {
assert(method_data_update(), "must be generating profile code");
- // Skip if we aren't tracking receivers
- if (TypeProfileWidth < 1) return;
-
ciMethodData* md = method()->method_data();
assert(md != NULL, "expected valid ciMethodData");
ciProfileData* data = md->bci_to_data(bci());
assert(data->is_ReceiverTypeData(), "need ReceiverTypeData here");
+
+ // Skip if we aren't tracking receivers
+ if (TypeProfileWidth < 1) {
+ increment_md_counter_at(md, data, CounterData::count_offset());
+ return;
+ }
ciReceiverTypeData* rdata = (ciReceiverTypeData*)data->as_ReceiverTypeData();
Node* method_data = method_data_addressing(md, rdata, in_ByteSize(0));
--- a/hotspot/src/share/vm/opto/runtime.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/opto/runtime.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -706,6 +706,11 @@
// vc->set_receiver_count(empty_row, DataLayout::counter_increment);
int count_off = ReceiverTypeData::receiver_count_cell_index(empty_row);
*(mdp + count_off) = DataLayout::counter_increment;
+ } else {
+ // Receiver did not match any saved receiver and there is no empty row for it.
+ // Increment total counter to indicate polimorphic case.
+ intptr_t* count_p = (intptr_t*)(((byte*)(data)) + in_bytes(CounterData::count_offset()));
+ *count_p += DataLayout::counter_increment;
}
JRT_END
--- a/hotspot/src/share/vm/runtime/deoptimization.cpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/runtime/deoptimization.cpp Mon Feb 01 16:49:49 2010 -0800
@@ -1338,13 +1338,14 @@
// Whether the interpreter is producing MDO data or not, we also need
// to use the MDO to detect hot deoptimization points and control
// aggressive optimization.
+ bool inc_recompile_count = false;
+ ProfileData* pdata = NULL;
if (ProfileTraps && update_trap_state && trap_mdo.not_null()) {
assert(trap_mdo() == get_method_data(thread, trap_method, false), "sanity");
uint this_trap_count = 0;
bool maybe_prior_trap = false;
bool maybe_prior_recompile = false;
- ProfileData* pdata
- = query_update_method_data(trap_mdo, trap_bci, reason,
+ pdata = query_update_method_data(trap_mdo, trap_bci, reason,
//outputs:
this_trap_count,
maybe_prior_trap,
@@ -1380,18 +1381,7 @@
// Detect repeated recompilation at the same BCI, and enforce a limit.
if (make_not_entrant && maybe_prior_recompile) {
// More than one recompile at this point.
- trap_mdo->inc_overflow_recompile_count();
- if (maybe_prior_trap
- && ((uint)trap_mdo->overflow_recompile_count()
- > (uint)PerBytecodeRecompilationCutoff)) {
- // Give up on the method containing the bad BCI.
- if (trap_method() == nm->method()) {
- make_not_compilable = true;
- } else {
- trap_method->set_not_compilable();
- // But give grace to the enclosing nm->method().
- }
- }
+ inc_recompile_count = maybe_prior_trap;
}
} else {
// For reasons which are not recorded per-bytecode, we simply
@@ -1418,7 +1408,17 @@
reset_counters = true;
}
- if (make_not_entrant && pdata != NULL) {
+ }
+
+ // Take requested actions on the method:
+
+ // Recompile
+ if (make_not_entrant) {
+ if (!nm->make_not_entrant()) {
+ return; // the call did not change nmethod's state
+ }
+
+ if (pdata != NULL) {
// Record the recompilation event, if any.
int tstate0 = pdata->trap_state();
int tstate1 = trap_state_set_recompiled(tstate0, true);
@@ -1427,7 +1427,19 @@
}
}
- // Take requested actions on the method:
+ if (inc_recompile_count) {
+ trap_mdo->inc_overflow_recompile_count();
+ if ((uint)trap_mdo->overflow_recompile_count() >
+ (uint)PerBytecodeRecompilationCutoff) {
+ // Give up on the method containing the bad BCI.
+ if (trap_method() == nm->method()) {
+ make_not_compilable = true;
+ } else {
+ trap_method->set_not_compilable();
+ // But give grace to the enclosing nm->method().
+ }
+ }
+ }
// Reset invocation counters
if (reset_counters) {
@@ -1437,13 +1449,8 @@
reset_invocation_counter(trap_scope);
}
- // Recompile
- if (make_not_entrant) {
- nm->make_not_entrant();
- }
-
// Give up compiling
- if (make_not_compilable) {
+ if (make_not_compilable && !nm->method()->is_not_compilable()) {
assert(make_not_entrant, "consistent");
nm->method()->set_not_compilable();
}
@@ -1516,9 +1523,11 @@
if (tstate1 != tstate0)
pdata->set_trap_state(tstate1);
} else {
- if (LogCompilation && xtty != NULL)
+ if (LogCompilation && xtty != NULL) {
+ ttyLocker ttyl;
// Missing MDP? Leave a small complaint in the log.
xtty->elem("missing_mdp bci='%d'", trap_bci);
+ }
}
}
@@ -1672,6 +1681,7 @@
"class_check",
"array_check",
"intrinsic",
+ "bimorphic",
"unloaded",
"uninitialized",
"unreached",
--- a/hotspot/src/share/vm/runtime/deoptimization.hpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/runtime/deoptimization.hpp Mon Feb 01 16:49:49 2010 -0800
@@ -33,12 +33,15 @@
enum DeoptReason {
Reason_many = -1, // indicates presence of several reasons
Reason_none = 0, // indicates absence of a relevant deopt.
+ // Next 7 reasons are recorded per bytecode in DataLayout::trap_bits
Reason_null_check, // saw unexpected null or zero divisor (@bci)
Reason_null_assert, // saw unexpected non-null or non-zero (@bci)
Reason_range_check, // saw unexpected array index (@bci)
Reason_class_check, // saw unexpected object class (@bci)
Reason_array_check, // saw unexpected array class (aastore @bci)
Reason_intrinsic, // saw unexpected operand to intrinsic (@bci)
+ Reason_bimorphic, // saw unexpected object class in bimorphic inlining (@bci)
+
Reason_unloaded, // unloaded class or constant pool entry
Reason_uninitialized, // bad class state (uninitialized)
Reason_unreached, // code is not reached, compiler
@@ -49,7 +52,7 @@
Reason_predicate, // compiler generated predicate failed
Reason_LIMIT,
// Note: Keep this enum in sync. with _trap_reason_name.
- Reason_RECORDED_LIMIT = Reason_unloaded // some are not recorded per bc
+ Reason_RECORDED_LIMIT = Reason_bimorphic // some are not recorded per bc
// Note: Reason_RECORDED_LIMIT should be < 8 to fit into 3 bits of
// DataLayout::trap_bits. This dependency is enforced indirectly
// via asserts, to avoid excessive direct header-to-header dependencies.
@@ -279,7 +282,7 @@
int trap_state);
static bool reason_is_recorded_per_bytecode(DeoptReason reason) {
- return reason > Reason_none && reason < Reason_RECORDED_LIMIT;
+ return reason > Reason_none && reason <= Reason_RECORDED_LIMIT;
}
static DeoptReason reason_recorded_per_bytecode_if_any(DeoptReason reason) {
--- a/hotspot/src/share/vm/runtime/globals.hpp Mon Feb 01 23:18:47 2010 +0100
+++ b/hotspot/src/share/vm/runtime/globals.hpp Mon Feb 01 16:49:49 2010 -0800
@@ -2864,7 +2864,7 @@
product(intx, PerMethodRecompilationCutoff, 400, \
"After recompiling N times, stay in the interpreter (-1=>'Inf')") \
\
- product(intx, PerBytecodeRecompilationCutoff, 100, \
+ product(intx, PerBytecodeRecompilationCutoff, 200, \
"Per-BCI limit on repeated recompilation (-1=>'Inf')") \
\
product(intx, PerMethodTrapLimit, 100, \