提交 f299daf0 编写于 作者: K kvn

6614597: Performance variability in jvm2008 xml.validation

Summary: Fix incorrect marking of methods as not compilable.
Reviewed-by: never
上级 7ecf2ea5
......@@ -1681,11 +1681,8 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
// 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::profile_virtual_call(Register receiver,
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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
// 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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
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 @@ void InterpreterMacroAssembler::profile_typecheck(Register klass,
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.
......
......@@ -290,9 +290,9 @@ class InterpreterMacroAssembler: public MacroAssembler {
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,
......
......@@ -3209,7 +3209,6 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
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 @@ void LIR_Assembler::emit_profile_call(LIR_OpProfileCall* op) {
__ 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);
}
}
......
......@@ -1239,17 +1239,19 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver, Register
// 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::profile_virtual_call(Register receiver, Register
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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
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 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass,
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
}
......
......@@ -213,10 +213,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
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);
......
......@@ -1262,17 +1262,19 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
// 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 @@ void InterpreterMacroAssembler::profile_virtual_call(Register receiver,
// 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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
// 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 @@ void InterpreterMacroAssembler::record_klass_in_profile_helper(
// 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 @@ void InterpreterMacroAssembler::profile_typecheck(Register mdp, Register klass,
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);
......
......@@ -222,10 +222,10 @@ class InterpreterMacroAssembler: public MacroAssembler {
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);
......
......@@ -436,15 +436,20 @@ ciCallProfile ciMethod::call_profile_at_bci(int bci) {
// 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 @@ ciCallProfile ciMethod::call_profile_at_bci(int bci) {
// 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;
......
......@@ -843,13 +843,15 @@ static bool count_find_witness_calls() {
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,
......
......@@ -1117,7 +1117,6 @@ void nmethod::make_unloaded(BoolObjectClosure* is_alive, oop cause) {
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 @@ void nmethod::log_state_change() const {
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 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
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 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
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.
......
......@@ -1391,6 +1391,9 @@ public:
}
void inc_decompile_count() {
_nof_decompiles += 1;
if (decompile_count() > (uint)PerMethodRecompilationCutoff) {
method()->set_not_compilable();
}
}
// Support for code generation
......
......@@ -575,12 +575,6 @@ bool methodOopDesc::is_not_compilable(int comp_level) const {
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 @@ bool methodOopDesc::is_not_compilable(int comp_level) const {
// 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());
......
......@@ -182,26 +182,16 @@ CallGenerator* Compile::call_generator(ciMethod* call_method, int vtable_index,
}
}
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
......
......@@ -414,8 +414,6 @@ void Parse::profile_not_taken_branch(bool force_update) {
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 @@ void Parse::profile_call(Node* receiver) {
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_generic_call() {
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));
......
......@@ -706,6 +706,11 @@ JRT_LEAF(void, OptoRuntime::profile_receiver_type_C(DataLayout* data, oopDesc* r
// 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
......
......@@ -1338,13 +1338,14 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
// 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 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
// 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 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
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 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
}
}
// 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 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* thread, jint tra
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 @@ Deoptimization::query_update_method_data(methodDataHandle trap_mdo,
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 @@ const char* Deoptimization::_trap_reason_name[Reason_LIMIT] = {
"class_check",
"array_check",
"intrinsic",
"bimorphic",
"unloaded",
"uninitialized",
"unreached",
......
......@@ -33,12 +33,15 @@ class Deoptimization : AllStatic {
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 @@ class Deoptimization : AllStatic {
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 @@ class Deoptimization : AllStatic {
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) {
......
......@@ -2864,7 +2864,7 @@ class CommandLineFlags {
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, \
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册