8256425: Obsolete Biased Locking in JDK 18

Reviewed-by: kvn, dholmes, dcubed, rrich
This commit is contained in:
Patricio Chilano Mateo 2021-06-24 18:54:41 +00:00
parent 595446bff4
commit 2fd7943ec1
165 changed files with 293 additions and 5261 deletions

View file

@ -56,7 +56,6 @@
#include "prims/vectorSupport.hpp"
#include "prims/methodHandles.hpp"
#include "runtime/atomic.hpp"
#include "runtime/biasedLocking.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/escapeBarrier.hpp"
#include "runtime/fieldDescriptor.hpp"
@ -311,9 +310,6 @@ bool Deoptimization::deoptimize_objects_internal(JavaThread* thread, GrowableArr
realloc_failures = rematerialize_objects(thread, Unpack_none, cm, deoptee, map, chunk, deoptimized_objects);
}
// Revoke biases of objects with eliminated locks in the given frame.
Deoptimization::revoke_for_object_deoptimization(deoptee_thread, deoptee, &map, thread);
// MonitorInfo structures used in eliminate_locks are not GC safe.
NoSafepointVerifier no_safepoint;
@ -383,10 +379,6 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread
}
#endif // COMPILER2_OR_JVMCI
// Revoke biases, done with in java state.
// No safepoints allowed after this
revoke_from_deopt_handler(current, deoptee, &map);
// Ensure that no safepoint is taken after pointers have been stored
// in fields of rematerialized objects. If a safepoint occurs from here on
// out the java state residing in the vframeArray will be missed.
@ -1442,20 +1434,10 @@ bool Deoptimization::relock_objects(JavaThread* thread, GrowableArray<MonitorInf
if (!mon_info->owner_is_scalar_replaced()) {
Handle obj(thread, mon_info->owner());
markWord mark = obj->mark();
if (UseBiasedLocking && mark.has_bias_pattern()) {
// New allocated objects may have the mark set to anonymously biased.
// Also the deoptimized method may called methods with synchronization
// where the thread-local object is bias locked to the current thread.
assert(mark.is_biased_anonymously() ||
mark.biased_locker() == deoptee_thread, "should be locked to current thread");
// Reset mark word to unbiased prototype.
markWord unbiased_prototype = markWord::prototype().set_age(mark.age());
obj->set_mark(unbiased_prototype);
} else if (exec_mode == Unpack_none) {
if (exec_mode == Unpack_none) {
if (mark.has_locker() && fr.sp() > (intptr_t*)mark.locker()) {
// With exec_mode == Unpack_none obj may be thread local and locked in
// a callee frame. In this case the bias was revoked before in revoke_for_object_deoptimization().
// Make the lock in the callee a recursive lock and restore the displaced header.
// a callee frame. Make the lock in the callee a recursive lock and restore the displaced header.
markWord dmw = mark.displaced_mark_helper();
mark.locker()->set_displaced_header(markWord::encode((BasicLock*) NULL));
obj->set_mark(dmw);
@ -1595,98 +1577,6 @@ void Deoptimization::pop_frames_failed_reallocs(JavaThread* thread, vframeArray*
}
#endif
static void collect_monitors(compiledVFrame* cvf, GrowableArray<Handle>* objects_to_revoke,
bool only_eliminated) {
GrowableArray<MonitorInfo*>* monitors = cvf->monitors();
Thread* thread = Thread::current();
for (int i = 0; i < monitors->length(); i++) {
MonitorInfo* mon_info = monitors->at(i);
if (mon_info->eliminated() == only_eliminated &&
!mon_info->owner_is_scalar_replaced() &&
mon_info->owner() != NULL) {
objects_to_revoke->append(Handle(thread, mon_info->owner()));
}
}
}
static void get_monitors_from_stack(GrowableArray<Handle>* objects_to_revoke, JavaThread* thread,
frame fr, RegisterMap* map, bool only_eliminated) {
// Unfortunately we don't have a RegisterMap available in most of
// the places we want to call this routine so we need to walk the
// stack again to update the register map.
if (map == NULL || !map->update_map()) {
StackFrameStream sfs(thread, true /* update */, true /* process_frames */);
bool found = false;
while (!found && !sfs.is_done()) {
frame* cur = sfs.current();
sfs.next();
found = cur->id() == fr.id();
}
assert(found, "frame to be deoptimized not found on target thread's stack");
map = sfs.register_map();
}
vframe* vf = vframe::new_vframe(&fr, map, thread);
compiledVFrame* cvf = compiledVFrame::cast(vf);
// Revoke monitors' biases in all scopes
while (!cvf->is_top()) {
collect_monitors(cvf, objects_to_revoke, only_eliminated);
cvf = compiledVFrame::cast(cvf->sender());
}
collect_monitors(cvf, objects_to_revoke, only_eliminated);
}
void Deoptimization::revoke_from_deopt_handler(JavaThread* thread, frame fr, RegisterMap* map) {
if (!UseBiasedLocking) {
return;
}
assert(thread == Thread::current(), "should be");
ResourceMark rm(thread);
HandleMark hm(thread);
GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
get_monitors_from_stack(objects_to_revoke, thread, fr, map, false);
int len = objects_to_revoke->length();
for (int i = 0; i < len; i++) {
oop obj = (objects_to_revoke->at(i))();
BiasedLocking::revoke_own_lock(thread, objects_to_revoke->at(i));
assert(!obj->mark().has_bias_pattern(), "biases should be revoked by now");
}
}
// Revoke the bias of objects with eliminated locking to prepare subsequent relocking.
void Deoptimization::revoke_for_object_deoptimization(JavaThread* deoptee_thread, frame fr,
RegisterMap* map, JavaThread* thread) {
if (!UseBiasedLocking) {
return;
}
GrowableArray<Handle>* objects_to_revoke = new GrowableArray<Handle>();
assert(KeepStackGCProcessedMark::stack_is_kept_gc_processed(deoptee_thread), "must be");
// Collect monitors but only those with eliminated locking.
get_monitors_from_stack(objects_to_revoke, deoptee_thread, fr, map, true);
int len = objects_to_revoke->length();
for (int i = 0; i < len; i++) {
oop obj = (objects_to_revoke->at(i))();
markWord mark = obj->mark();
if (!mark.has_bias_pattern() ||
mark.is_biased_anonymously() || // eliminated locking does not bias an object if it wasn't before
!obj->klass()->prototype_header().has_bias_pattern() || // bulk revoke ignores eliminated monitors
(obj->klass()->prototype_header().bias_epoch() != mark.bias_epoch())) { // bulk rebias ignores eliminated monitors
// We reach here regularly if there's just eliminated locking on obj.
// We must not call BiasedLocking::revoke_own_lock() in this case, as we
// would hit assertions because it is a prerequisite that there has to be
// non-eliminated locking on obj by deoptee_thread.
// Luckily we don't have to revoke here because obj has to be a
// non-escaping obj and can be relocked without revoking the bias. See
// Deoptimization::relock_objects().
continue;
}
BiasedLocking::revoke(thread, objects_to_revoke->at(i));
assert(!objects_to_revoke->at(i)->mark().has_bias_pattern(), "biases should be revoked by now");
}
}
void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deoptimization::DeoptReason reason) {
assert(fr.can_be_deoptimized(), "checking frame type");
@ -1923,12 +1813,11 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr
// decremented at the end of unpack_frames().
current->inc_in_deopt_handler();
// We need to update the map if we have biased locking.
#if INCLUDE_JVMCI
// JVMCI might need to get an exception from the stack, which in turn requires the register map to be valid
RegisterMap reg_map(current, true);
#else
RegisterMap reg_map(current, UseBiasedLocking);
RegisterMap reg_map(current, false);
#endif
frame stub_frame = current->last_frame();
frame fr = stub_frame.sender(&reg_map);