mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-17 17:44:40 +02:00
8139551: Scalability problem with redefinition - multiple code cache walks
Walk code cache and deoptimize once per redefinition. Reviewed-by: sspitsyn, dlong
This commit is contained in:
parent
fc31592f6e
commit
8f5e561d19
14 changed files with 244 additions and 74 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, Oracle and/or its affiliates. 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
|
||||
|
@ -1200,9 +1200,9 @@ bool CodeCache::is_far_target(address target) {
|
|||
#endif
|
||||
}
|
||||
|
||||
int CodeCache::mark_for_evol_deoptimization(InstanceKlass* dependee) {
|
||||
// Just marks the methods in this class as needing deoptimization
|
||||
void CodeCache::mark_for_evol_deoptimization(InstanceKlass* dependee) {
|
||||
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
|
||||
int number_of_marked_CodeBlobs = 0;
|
||||
|
||||
// Deoptimize all methods of the evolving class itself
|
||||
Array<Method*>* old_methods = dependee->methods();
|
||||
|
@ -1212,16 +1212,24 @@ int CodeCache::mark_for_evol_deoptimization(InstanceKlass* dependee) {
|
|||
CompiledMethod* nm = old_method->code();
|
||||
if (nm != NULL) {
|
||||
nm->mark_for_deoptimization();
|
||||
number_of_marked_CodeBlobs++;
|
||||
}
|
||||
}
|
||||
|
||||
// Mark dependent AOT nmethods, which are only found via the class redefined.
|
||||
AOTLoader::mark_evol_dependent_methods(dependee);
|
||||
}
|
||||
|
||||
// Walk compiled methods and mark dependent methods for deoptimization.
|
||||
int CodeCache::mark_dependents_for_evol_deoptimization() {
|
||||
int number_of_marked_CodeBlobs = 0;
|
||||
CompiledMethodIterator iter(CompiledMethodIterator::only_alive_and_not_unloading);
|
||||
while(iter.next()) {
|
||||
CompiledMethod* nm = iter.method();
|
||||
if (nm->is_marked_for_deoptimization()) {
|
||||
// ...Already marked in the previous pass; don't count it again.
|
||||
} else if (nm->is_evol_dependent_on(dependee)) {
|
||||
// ...Already marked in the previous pass; count it here.
|
||||
// Also counts AOT compiled methods, already marked.
|
||||
number_of_marked_CodeBlobs++;
|
||||
} else if (nm->is_evol_dependent()) {
|
||||
ResourceMark rm;
|
||||
nm->mark_for_deoptimization();
|
||||
number_of_marked_CodeBlobs++;
|
||||
|
@ -1231,6 +1239,8 @@ int CodeCache::mark_for_evol_deoptimization(InstanceKlass* dependee) {
|
|||
}
|
||||
}
|
||||
|
||||
// return total count of nmethods marked for deoptimization, if zero the caller
|
||||
// can skip deoptimization
|
||||
return number_of_marked_CodeBlobs;
|
||||
}
|
||||
|
||||
|
@ -1294,34 +1304,30 @@ void CodeCache::flush_dependents_on(InstanceKlass* dependee) {
|
|||
}
|
||||
}
|
||||
|
||||
// Flushes compiled methods dependent on dependee when the dependee is redefined
|
||||
// via RedefineClasses
|
||||
void CodeCache::flush_evol_dependents_on(InstanceKlass* ev_k) {
|
||||
// Flushes compiled methods dependent on redefined classes, that have already been
|
||||
// marked for deoptimization.
|
||||
void CodeCache::flush_evol_dependents() {
|
||||
// --- Compile_lock is not held. However we are at a safepoint.
|
||||
assert_locked_or_safepoint(Compile_lock);
|
||||
if (number_of_nmethods_with_dependencies() == 0 && !UseAOT) return;
|
||||
|
||||
// CodeCache can only be updated by a thread_in_VM and they will all be
|
||||
// stopped during the safepoint so CodeCache will be safe to update without
|
||||
// holding the CodeCache_lock.
|
||||
|
||||
// Compute the dependent nmethods
|
||||
if (mark_for_evol_deoptimization(ev_k) > 0) {
|
||||
// At least one nmethod has been marked for deoptimization
|
||||
// At least one nmethod has been marked for deoptimization
|
||||
|
||||
// All this already happens inside a VM_Operation, so we'll do all the work here.
|
||||
// Stuff copied from VM_Deoptimize and modified slightly.
|
||||
// All this already happens inside a VM_Operation, so we'll do all the work here.
|
||||
// Stuff copied from VM_Deoptimize and modified slightly.
|
||||
|
||||
// We do not want any GCs to happen while we are in the middle of this VM operation
|
||||
ResourceMark rm;
|
||||
DeoptimizationMarker dm;
|
||||
// We do not want any GCs to happen while we are in the middle of this VM operation
|
||||
ResourceMark rm;
|
||||
DeoptimizationMarker dm;
|
||||
|
||||
// Deoptimize all activations depending on marked nmethods
|
||||
Deoptimization::deoptimize_dependents();
|
||||
// Deoptimize all activations depending on marked nmethods
|
||||
Deoptimization::deoptimize_dependents();
|
||||
|
||||
// Make the dependent methods not entrant
|
||||
make_marked_nmethods_not_entrant();
|
||||
}
|
||||
// Make the dependent methods not entrant
|
||||
make_marked_nmethods_not_entrant();
|
||||
}
|
||||
|
||||
// Flushes compiled methods dependent on dependee
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue