Path: blob/master/src/hotspot/share/runtime/escapeBarrier.cpp
40951 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "code/scopeDesc.hpp"27#include "memory/allocation.hpp"28#include "prims/jvmtiDeferredUpdates.hpp"29#include "runtime/deoptimization.hpp"30#include "runtime/escapeBarrier.hpp"31#include "runtime/frame.inline.hpp"32#include "runtime/handles.hpp"33#include "runtime/handshake.hpp"34#include "runtime/interfaceSupport.inline.hpp"35#include "runtime/keepStackGCProcessed.hpp"36#include "runtime/mutexLocker.hpp"37#include "runtime/registerMap.hpp"38#include "runtime/stackFrameStream.inline.hpp"39#include "runtime/stackValue.hpp"40#include "runtime/stackValueCollection.hpp"41#include "runtime/threadSMR.hpp"42#include "runtime/vframe.hpp"43#include "runtime/vframe_hp.hpp"44#include "utilities/debug.hpp"45#include "utilities/globalDefinitions.hpp"46#include "utilities/macros.hpp"4748#if COMPILER2_OR_JVMCI4950// Returns true iff objects were reallocated and relocked because of access through JVMTI51bool EscapeBarrier::objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) {52// first/oldest update holds the flag53GrowableArray<jvmtiDeferredLocalVariableSet*>* list = JvmtiDeferredUpdates::deferred_locals(thread);54bool result = false;55if (list != NULL) {56for (int i = 0; i < list->length(); i++) {57if (list->at(i)->matches(fr_id)) {58result = list->at(i)->objects_are_deoptimized();59break;60}61}62}63return result;64}6566// Deoptimize objects of frames of the target thread at depth >= d1 and depth <= d2.67// Deoptimize objects of caller frames if they passed references to ArgEscape objects as arguments.68// Return false in the case of a reallocation failure and true otherwise.69bool EscapeBarrier::deoptimize_objects(int d1, int d2) {70if (!barrier_active()) return true;71if (d1 < deoptee_thread()->frames_to_pop_failed_realloc()) {72// The deoptee thread has frames with reallocation failures on top of its stack.73// These frames are about to be removed. We must not interfere with that and signal failure.74return false;75}76if (deoptee_thread()->has_last_Java_frame()) {77assert(calling_thread() == Thread::current(), "should be");78KeepStackGCProcessedMark ksgcpm(deoptee_thread());79ResourceMark rm(calling_thread());80HandleMark hm(calling_thread());81RegisterMap reg_map(deoptee_thread(), false /* update_map */, false /* process_frames */);82vframe* vf = deoptee_thread()->last_java_vframe(®_map);83int cur_depth = 0;8485// Skip frames at depth < d186while (vf != NULL && cur_depth < d1) {87cur_depth++;88vf = vf->sender();89}9091while (vf != NULL && ((cur_depth <= d2) || !vf->is_entry_frame())) {92if (vf->is_compiled_frame()) {93compiledVFrame* cvf = compiledVFrame::cast(vf);94// Deoptimize frame and local objects if any exist.95// If cvf is deeper than depth, then we deoptimize iff local objects are passed as args.96bool should_deopt = cur_depth <= d2 ? cvf->has_ea_local_in_scope() : cvf->arg_escape();97if (should_deopt && !deoptimize_objects(cvf->fr().id())) {98// reallocation of scalar replaced objects failed because heap is exhausted99return false;100}101102// move to top frame103while(!vf->is_top()) {104cur_depth++;105vf = vf->sender();106}107}108109// move to next physical frame110cur_depth++;111vf = vf->sender();112}113}114return true;115}116117bool EscapeBarrier::deoptimize_objects_all_threads() {118if (!barrier_active()) return true;119ResourceMark rm(calling_thread());120for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {121if (jt->frames_to_pop_failed_realloc() > 0) {122// The deoptee thread jt has frames with reallocation failures on top of its stack.123// These frames are about to be removed. We must not interfere with that and signal failure.124return false;125}126if (jt->has_last_Java_frame()) {127KeepStackGCProcessedMark ksgcpm(jt);128RegisterMap reg_map(jt, false /* update_map */, false /* process_frames */);129vframe* vf = jt->last_java_vframe(®_map);130assert(jt->frame_anchor()->walkable(),131"The stack of JavaThread " PTR_FORMAT " is not walkable. Thread state is %d",132p2i(jt), jt->thread_state());133while (vf != NULL) {134if (vf->is_compiled_frame()) {135compiledVFrame* cvf = compiledVFrame::cast(vf);136if ((cvf->has_ea_local_in_scope() || cvf->arg_escape()) &&137!deoptimize_objects_internal(jt, cvf->fr().id())) {138return false; // reallocation failure139}140// move to top frame141while(!vf->is_top()) {142vf = vf->sender();143}144}145// move to next physical frame146vf = vf->sender();147}148}149}150return true; // success151}152153bool EscapeBarrier::_deoptimizing_objects_for_all_threads = false;154bool EscapeBarrier::_self_deoptimization_in_progress = false;155156class EscapeBarrierSuspendHandshake : public HandshakeClosure {157public:158EscapeBarrierSuspendHandshake(const char* name) :159HandshakeClosure(name) { }160void do_thread(Thread* th) { }161};162163void EscapeBarrier::sync_and_suspend_one() {164assert(_calling_thread != NULL, "calling thread must not be NULL");165assert(_deoptee_thread != NULL, "deoptee thread must not be NULL");166assert(barrier_active(), "should not call");167168// Sync with other threads that might be doing deoptimizations169{170// Need to switch to _thread_blocked for the wait() call171ThreadBlockInVM tbivm(_calling_thread);172MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);173while (_self_deoptimization_in_progress || _deoptee_thread->is_obj_deopt_suspend()) {174ml.wait();175}176177if (self_deopt()) {178_self_deoptimization_in_progress = true;179return;180}181182// set suspend flag for target thread183_deoptee_thread->set_obj_deopt_flag();184}185186// Use a handshake to synchronize with the target thread.187EscapeBarrierSuspendHandshake sh("EscapeBarrierSuspendOne");188Handshake::execute(&sh, _deoptee_thread);189assert(!_deoptee_thread->has_last_Java_frame() || _deoptee_thread->frame_anchor()->walkable(),190"stack should be walkable now");191}192193void EscapeBarrier::sync_and_suspend_all() {194assert(barrier_active(), "should not call");195assert(_calling_thread != NULL, "calling thread must not be NULL");196assert(all_threads(), "sanity");197198// Sync with other threads that might be doing deoptimizations199{200// Need to switch to _thread_blocked for the wait() call201ThreadBlockInVM tbivm(_calling_thread);202MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);203204bool deopt_in_progress;205do {206deopt_in_progress = _self_deoptimization_in_progress;207for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {208deopt_in_progress = (deopt_in_progress || jt->is_obj_deopt_suspend());209if (deopt_in_progress) {210break;211}212}213if (deopt_in_progress) {214ml.wait(); // then check again215}216} while(deopt_in_progress);217218_self_deoptimization_in_progress = true;219_deoptimizing_objects_for_all_threads = true;220221// We set the suspend flags before executing the handshake because then the222// setting will be visible after leaving the _thread_blocked state in223// JavaThread::wait_for_object_deoptimization(). If we set the flags in the224// handshake then the read must happen after the safepoint/handshake poll.225for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {226if (jt->is_Java_thread() && !jt->is_hidden_from_external_view() && (jt != _calling_thread)) {227jt->set_obj_deopt_flag();228}229}230}231232// Use a handshake to synchronize with the other threads.233EscapeBarrierSuspendHandshake sh("EscapeBarrierSuspendAll");234Handshake::execute(&sh);235#ifdef ASSERT236for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {237if (jt->is_hidden_from_external_view()) continue;238assert(!jt->has_last_Java_frame() || jt->frame_anchor()->walkable(),239"The stack of JavaThread " PTR_FORMAT " is not walkable. Thread state is %d",240p2i(jt), jt->thread_state());241}242#endif // ASSERT243}244245void EscapeBarrier::resume_one() {246assert(barrier_active(), "should not call");247assert(!all_threads(), "use resume_all()");248MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);249if (self_deopt()) {250assert(_self_deoptimization_in_progress, "incorrect synchronization");251_self_deoptimization_in_progress = false;252} else {253_deoptee_thread->clear_obj_deopt_flag();254}255ml.notify_all();256}257258void EscapeBarrier::resume_all() {259assert(barrier_active(), "should not call");260assert(all_threads(), "use resume_one()");261MonitorLocker ml(_calling_thread, EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);262assert(_self_deoptimization_in_progress, "incorrect synchronization");263_deoptimizing_objects_for_all_threads = false;264_self_deoptimization_in_progress = false;265for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {266jt->clear_obj_deopt_flag();267}268ml.notify_all();269}270271void EscapeBarrier::thread_added(JavaThread* jt) {272if (!jt->is_hidden_from_external_view()) {273MutexLocker ml(EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);274if (_deoptimizing_objects_for_all_threads) {275jt->set_obj_deopt_flag();276}277}278}279280void EscapeBarrier::thread_removed(JavaThread* jt) {281MonitorLocker ml(EscapeBarrier_lock, Mutex::_no_safepoint_check_flag);282if (jt->is_obj_deopt_suspend()) {283// jt terminated before it self suspended.284// Other threads might be waiting to perform deoptimizations for it.285jt->clear_obj_deopt_flag();286ml.notify_all();287}288}289290// Remember that objects were reallocated and relocked for the compiled frame with the given id291static void set_objs_are_deoptimized(JavaThread* thread, intptr_t* fr_id) {292// set in first/oldest update293GrowableArray<jvmtiDeferredLocalVariableSet*>* list =294JvmtiDeferredUpdates::deferred_locals(thread);295DEBUG_ONLY(bool found = false);296if (list != NULL) {297for (int i = 0; i < list->length(); i++) {298if (list->at(i)->matches(fr_id)) {299DEBUG_ONLY(found = true);300list->at(i)->set_objs_are_deoptimized();301break;302}303}304}305assert(found, "variable set should exist at least for one vframe");306}307308// Deoptimize the given frame and deoptimize objects with optimizations based on309// escape analysis, i.e. reallocate scalar replaced objects on the heap and310// relock objects if locking has been eliminated.311// Deoptimized objects are kept as JVMTI deferred updates until the compiled312// frame is replaced with interpreter frames. Returns false iff at least one313// reallocation failed.314bool EscapeBarrier::deoptimize_objects_internal(JavaThread* deoptee, intptr_t* fr_id) {315assert(barrier_active(), "should not call");316317JavaThread* ct = calling_thread();318bool realloc_failures = false;319320if (!objs_are_deoptimized(deoptee, fr_id)) {321// Make sure the frame identified by fr_id is deoptimized and fetch its last vframe322compiledVFrame* last_cvf;323bool fr_is_deoptimized;324do {325StackFrameStream fst(deoptee, true /* update */, false /* process_frames */);326while (fst.current()->id() != fr_id && !fst.is_done()) {327fst.next();328}329assert(fst.current()->id() == fr_id, "frame not found");330assert(fst.current()->is_compiled_frame(),331"only compiled frames can contain stack allocated objects");332fr_is_deoptimized = fst.current()->is_deoptimized_frame();333if (!fr_is_deoptimized) {334// Execution must not continue in the compiled method, so we deoptimize the frame.335Deoptimization::deoptimize_frame(deoptee, fr_id);336} else {337last_cvf = compiledVFrame::cast(vframe::new_vframe(fst.current(), fst.register_map(), deoptee));338}339} while(!fr_is_deoptimized);340341// collect inlined frames342compiledVFrame* cvf = last_cvf;343GrowableArray<compiledVFrame*>* vfs = new GrowableArray<compiledVFrame*>(10);344while (!cvf->is_top()) {345vfs->push(cvf);346cvf = compiledVFrame::cast(cvf->sender());347}348vfs->push(cvf);349350// reallocate and relock optimized objects351bool deoptimized_objects = Deoptimization::deoptimize_objects_internal(ct, vfs, realloc_failures);352if (!realloc_failures && deoptimized_objects) {353// now do the updates354for (int frame_index = 0; frame_index < vfs->length(); frame_index++) {355cvf = vfs->at(frame_index);356cvf->create_deferred_updates_after_object_deoptimization();357}358set_objs_are_deoptimized(deoptee, fr_id);359}360}361return !realloc_failures;362}363364#endif // COMPILER2_OR_JVMCI365366367