8173338: C2: continuous CallSite relinkage eventually disables compilation for a method

Reviewed-by: jrose, dlong, kvn
This commit is contained in:
Vladimir Ivanov 2017-01-31 01:11:40 +03:00
parent 81e25c58fb
commit 95ff3ccdb4
4 changed files with 19 additions and 3 deletions

View file

@ -101,6 +101,7 @@ ciEnv::ciEnv(CompileTask* task, int system_dictionary_modification_counter)
_debug_info = NULL;
_dependencies = NULL;
_failure_reason = NULL;
_inc_decompile_count_on_failure = true;
_compilable = MethodCompilable;
_break_at_compile = false;
_compiler_data = NULL;
@ -161,6 +162,7 @@ ciEnv::ciEnv(Arena* arena) : _ciEnv_arena(mtCompiler) {
_debug_info = NULL;
_dependencies = NULL;
_failure_reason = NULL;
_inc_decompile_count_on_failure = true;
_compilable = MethodCompilable_never;
_break_at_compile = false;
_compiler_data = NULL;
@ -902,7 +904,12 @@ void ciEnv::validate_compile_task_dependencies(ciMethod* target) {
if (deps.is_klass_type()) continue; // skip klass dependencies
Klass* witness = deps.check_dependency();
if (witness != NULL) {
if (deps.type() == Dependencies::call_site_target_value) {
_inc_decompile_count_on_failure = false;
record_failure("call site target change");
} else {
record_failure("invalid non-klass dependency");
}
return;
}
}
@ -1017,7 +1024,7 @@ void ciEnv::register_method(ciMethod* target,
if (failing()) {
// While not a true deoptimization, it is a preemptive decompile.
MethodData* mdo = method()->method_data();
if (mdo != NULL) {
if (mdo != NULL && _inc_decompile_count_on_failure) {
mdo->inc_decompile_count();
}

View file

@ -55,6 +55,7 @@ private:
DebugInformationRecorder* _debug_info;
Dependencies* _dependencies;
const char* _failure_reason;
bool _inc_decompile_count_on_failure;
int _compilable;
bool _break_at_compile;
int _num_inlined_bytecodes;

View file

@ -1211,7 +1211,7 @@ void CodeCache::make_marked_nmethods_not_entrant() {
CompiledMethodIterator iter;
while(iter.next_alive()) {
CompiledMethod* nm = iter.method();
if (nm->is_marked_for_deoptimization()) {
if (nm->is_marked_for_deoptimization() && !nm->is_not_entrant()) {
nm->make_not_entrant();
}
}

View file

@ -1146,6 +1146,14 @@ bool nmethod::make_not_entrant_or_zombie(unsigned int state) {
assert(state == zombie || state == not_entrant, "must be zombie or not_entrant");
assert(!is_zombie(), "should not already be a zombie");
if (_state == state) {
// Avoid taking the lock if already in required state.
// This is safe from races because the state is an end-state,
// which the nmethod cannot back out of once entered.
// No need for fencing either.
return false;
}
// Make sure neither the nmethod nor the method is flushed in case of a safepoint in code below.
nmethodLocker nml(this);
methodHandle the_method(method());