SSL escapeBarrier.cpp
Interaktion und PortierbarkeitC
/* * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. 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 * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// Returns true iff objects were reallocated and relocked because of access through JVMTI bool EscapeBarrier::objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) { // first/oldest update holds the flag
GrowableArrayView<jvmtiDeferredLocalVariableSet*>* list = JvmtiDeferredUpdates::deferred_locals(thread); bool result = false; if (list != NULL) { for (int i = 0; i < list->length(); i++) { if (list->at(i)->matches(fr_id)) {
result = list->at(i)->objects_are_deoptimized(); break;
}
}
} return result;
}
// Deoptimize objects of frames of the target thread at depth >= d1 and depth <= d2. // Deoptimize objects of caller frames if they passed references to ArgEscape objects as arguments. // Return false in the case of a reallocation failure and true otherwise. bool EscapeBarrier::deoptimize_objects(int d1, int d2) { if (!barrier_active()) returntrue; if (d1 < deoptee_thread()->frames_to_pop_failed_realloc()) { // The deoptee thread has frames with reallocation failures on top of its stack. // These frames are about to be removed. We must not interfere with that and signal failure. returnfalse;
} if (deoptee_thread()->has_last_Java_frame()) {
assert(calling_thread() == Thread::current(), "should be");
KeepStackGCProcessedMark ksgcpm(deoptee_thread());
ResourceMark rm(calling_thread());
HandleMark hm(calling_thread());
RegisterMap reg_map(deoptee_thread(),
RegisterMap::UpdateMap::skip,
RegisterMap::ProcessFrames::skip,
RegisterMap::WalkContinuation::skip);
vframe* vf = deoptee_thread()->last_java_vframe(®_map); int cur_depth = 0;
while (vf != NULL && ((cur_depth <= d2) || !vf->is_entry_frame())) { if (vf->is_compiled_frame()) {
compiledVFrame* cvf = compiledVFrame::cast(vf); // Deoptimize frame and local objects if any exist. // If cvf is deeper than depth, then we deoptimize iff local objects are passed as args. bool should_deopt = cur_depth <= d2 ? cvf->has_ea_local_in_scope() : cvf->arg_escape(); if (should_deopt && !deoptimize_objects(cvf->fr().id())) { // reallocation of scalar replaced objects failed because heap is exhausted returnfalse;
}
// move to top frame while(!vf->is_top()) {
cur_depth++;
vf = vf->sender();
}
}
// move to next physical frame
cur_depth++;
vf = vf->sender();
}
} returntrue;
}
bool EscapeBarrier::deoptimize_objects_all_threads() { if (!barrier_active()) returntrue;
ResourceMark rm(calling_thread()); for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
oop vt_oop = jt->jvmti_vthread(); // Skip virtual threads if (vt_oop != NULL && java_lang_VirtualThread::is_instance(vt_oop)) { continue;
} if (jt->frames_to_pop_failed_realloc() > 0) { // The deoptee thread jt has frames with reallocation failures on top of its stack. // These frames are about to be removed. We must not interfere with that and signal failure. returnfalse;
} if (jt->has_last_Java_frame()) {
KeepStackGCProcessedMark ksgcpm(jt);
RegisterMap reg_map(jt,
RegisterMap::UpdateMap::skip,
RegisterMap::ProcessFrames::skip,
RegisterMap::WalkContinuation::skip);
vframe* vf = jt->last_java_vframe(®_map);
assert(jt->frame_anchor()->walkable(), "The stack of JavaThread " PTR_FORMAT " is not walkable. Thread state is %d",
p2i(jt), jt->thread_state()); while (vf != NULL) { if (vf->is_compiled_frame()) {
compiledVFrame* cvf = compiledVFrame::cast(vf); if ((cvf->has_ea_local_in_scope() || cvf->arg_escape()) &&
!deoptimize_objects_internal(jt, cvf->fr().id())) { returnfalse; // reallocation failure
} // move to top frame while(!vf->is_top()) {
vf = vf->sender();
}
} // move to next physical frame
vf = vf->sender();
}
}
} returntrue; // success
}
class EscapeBarrierSuspendHandshake : public HandshakeClosure { public:
EscapeBarrierSuspendHandshake(constchar* name) :
HandshakeClosure(name) { } void do_thread(Thread* th) { }
};
void EscapeBarrier::sync_and_suspend_one() {
assert(_calling_thread != NULL, "calling thread must not be NULL");
assert(_deoptee_thread != NULL, "deoptee thread must not be NULL");
assert(barrier_active(), "should not call");
// Sync with other threads that might be doing deoptimizations
{ // Need to switch to _thread_blocked for the wait() call
ThreadBlockInVM tbivm(_calling_thread);
MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag); while (_self_deoptimization_in_progress || _deoptee_thread->is_obj_deopt_suspend()) {
ml.wait();
}
if (self_deopt()) {
_self_deoptimization_in_progress = true; return;
}
// set suspend flag for target thread
_deoptee_thread->set_obj_deopt_flag();
}
// Use a handshake to synchronize with the target thread.
EscapeBarrierSuspendHandshake sh("EscapeBarrierSuspendOne");
Handshake::execute(&sh, _deoptee_thread);
assert(!_deoptee_thread->has_last_Java_frame() || _deoptee_thread->frame_anchor()->walkable(), "stack should be walkable now");
}
void EscapeBarrier::sync_and_suspend_all() {
assert(barrier_active(), "should not call");
assert(_calling_thread != NULL, "calling thread must not be NULL");
assert(all_threads(), "sanity");
// Sync with other threads that might be doing deoptimizations
{ // Need to switch to _thread_blocked for the wait() call
ThreadBlockInVM tbivm(_calling_thread);
MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);
bool deopt_in_progress; do {
deopt_in_progress = _self_deoptimization_in_progress; for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
deopt_in_progress = (deopt_in_progress || jt->is_obj_deopt_suspend()); if (deopt_in_progress) { break;
}
} if (deopt_in_progress) {
ml.wait(); // then check again
}
} while(deopt_in_progress);
// We set the suspend flags before executing the handshake because then the // setting will be visible after leaving the _thread_blocked state in // JavaThread::wait_for_object_deoptimization(). If we set the flags in the // handshake then the read must happen after the safepoint/handshake poll. for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { if (jt->is_Java_thread() && !jt->is_hidden_from_external_view() && (jt != _calling_thread)) {
jt->set_obj_deopt_flag();
}
}
}
// Use a handshake to synchronize with the other threads.
EscapeBarrierSuspendHandshake sh("EscapeBarrierSuspendAll");
Handshake::execute(&sh); #ifdef ASSERT for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) { if (jt->is_hidden_from_external_view()) continue;
assert(!jt->has_last_Java_frame() || jt->frame_anchor()->walkable(), "The stack of JavaThread " PTR_FORMAT " is not walkable. Thread state is %d",
p2i(jt), jt->thread_state());
} #endif// ASSERT
}
void EscapeBarrier::thread_added(JavaThread* jt) { if (!jt->is_hidden_from_external_view()) {
MutexLocker ml(EscapeBarrier_lock, Mutex::_no_safepoint_check_flag); if (_deoptimizing_objects_for_all_threads) {
jt->set_obj_deopt_flag();
}
}
}
void EscapeBarrier::thread_removed(JavaThread* jt) {
MonitorLocker ml(EscapeBarrier_lock, Mutex::_no_safepoint_check_flag); if (jt->is_obj_deopt_suspend()) { // jt terminated before it self suspended. // Other threads might be waiting to perform deoptimizations for it.
jt->clear_obj_deopt_flag();
ml.notify_all();
}
}
// Remember that objects were reallocated and relocked for the compiled frame with the given id staticvoid set_objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) { // set in first/oldest update
GrowableArrayView<jvmtiDeferredLocalVariableSet*>* list =
JvmtiDeferredUpdates::deferred_locals(thread);
DEBUG_ONLY(bool found = false); if (list != NULL) { for (int i = 0; i < list->length(); i++) { if (list->at(i)->matches(fr_id)) {
DEBUG_ONLY(found = true);
list->at(i)->set_objs_are_deoptimized(); break;
}
}
}
assert(found, "variable set should exist at least for one vframe");
}
// Deoptimize the given frame and deoptimize objects with optimizations based on // escape analysis, i.e. reallocate scalar replaced objects on the heap and // relock objects if locking has been eliminated. // Deoptimized objects are kept as JVMTI deferred updates until the compiled // frame is replaced with interpreter frames. Returns false iff at least one // reallocation failed. bool EscapeBarrier::deoptimize_objects_internal(JavaThread* deoptee, intptr_t* fr_id) {
assert(barrier_active(), "should not call");
if (!objs_are_deoptimized(deoptee, fr_id)) { // Make sure the frame identified by fr_id is deoptimized and fetch its last vframe
compiledVFrame* last_cvf; bool fr_is_deoptimized; do {
StackFrameStream fst(deoptee, true/* update */, false /* process_frames */); while (fst.current()->id() != fr_id && !fst.is_done()) {
fst.next();
}
assert(fst.current()->id() == fr_id, "frame not found");
assert(fst.current()->is_compiled_frame(), "only compiled frames can contain stack allocated objects");
fr_is_deoptimized = fst.current()->is_deoptimized_frame(); if (!fr_is_deoptimized) { // Execution must not continue in the compiled method, so we deoptimize the frame.
Deoptimization::deoptimize_frame(deoptee, fr_id);
} else {
last_cvf = compiledVFrame::cast(vframe::new_vframe(fst.current(), fst.register_map(), deoptee));
}
} while(!fr_is_deoptimized);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.