Path: blob/master/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp
40957 views
/*1* Copyright (c) 2017, 2021, Red Hat, Inc. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "code/codeCache.hpp"26#include "code/icBuffer.hpp"27#include "code/nmethod.hpp"28#include "gc/shenandoah/shenandoahClosures.inline.hpp"29#include "gc/shenandoah/shenandoahEvacOOMHandler.inline.hpp"30#include "gc/shenandoah/shenandoahHeap.inline.hpp"31#include "gc/shenandoah/shenandoahNMethod.inline.hpp"32#include "gc/shenandoah/shenandoahUtils.hpp"33#include "memory/resourceArea.hpp"34#include "memory/universe.hpp"35#include "runtime/atomic.hpp"36#include "utilities/powerOfTwo.hpp"3738ShenandoahParallelCodeCacheIterator::ShenandoahParallelCodeCacheIterator(const GrowableArray<CodeHeap*>* heaps) {39_length = heaps->length();40_iters = NEW_C_HEAP_ARRAY(ShenandoahParallelCodeHeapIterator, _length, mtGC);41for (int h = 0; h < _length; h++) {42_iters[h] = ShenandoahParallelCodeHeapIterator(heaps->at(h));43}44}4546ShenandoahParallelCodeCacheIterator::~ShenandoahParallelCodeCacheIterator() {47FREE_C_HEAP_ARRAY(ParallelCodeHeapIterator, _iters);48}4950void ShenandoahParallelCodeCacheIterator::parallel_blobs_do(CodeBlobClosure* f) {51for (int c = 0; c < _length; c++) {52_iters[c].parallel_blobs_do(f);53}54}5556ShenandoahParallelCodeHeapIterator::ShenandoahParallelCodeHeapIterator(CodeHeap* heap) :57_heap(heap), _claimed_idx(0), _finished(false) {58}5960void ShenandoahParallelCodeHeapIterator::parallel_blobs_do(CodeBlobClosure* f) {61assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");6263/*64* Parallel code heap walk.65*66* This code makes all threads scan all code heaps, but only one thread would execute the67* closure on given blob. This is achieved by recording the "claimed" blocks: if a thread68* had claimed the block, it can process all blobs in it. Others have to fast-forward to69* next attempt without processing.70*71* Late threads would return immediately if iterator is finished.72*/7374if (_finished) {75return;76}7778int stride = 256; // educated guess79int stride_mask = stride - 1;80assert (is_power_of_2(stride), "sanity");8182int count = 0;83bool process_block = true;8485for (CodeBlob *cb = CodeCache::first_blob(_heap); cb != NULL; cb = CodeCache::next_blob(_heap, cb)) {86int current = count++;87if ((current & stride_mask) == 0) {88process_block = (current >= _claimed_idx) &&89(Atomic::cmpxchg(&_claimed_idx, current, current + stride) == current);90}91if (process_block) {92if (cb->is_alive()) {93f->do_code_blob(cb);94#ifdef ASSERT95if (cb->is_nmethod())96Universe::heap()->verify_nmethod((nmethod*)cb);97#endif98}99}100}101102_finished = true;103}104105ShenandoahNMethodTable* ShenandoahCodeRoots::_nmethod_table;106int ShenandoahCodeRoots::_disarmed_value = 1;107108void ShenandoahCodeRoots::initialize() {109_nmethod_table = new ShenandoahNMethodTable();110}111112void ShenandoahCodeRoots::register_nmethod(nmethod* nm) {113assert_locked_or_safepoint(CodeCache_lock);114_nmethod_table->register_nmethod(nm);115}116117void ShenandoahCodeRoots::unregister_nmethod(nmethod* nm) {118assert_locked_or_safepoint(CodeCache_lock);119_nmethod_table->unregister_nmethod(nm);120}121122void ShenandoahCodeRoots::flush_nmethod(nmethod* nm) {123assert_locked_or_safepoint(CodeCache_lock);124_nmethod_table->flush_nmethod(nm);125}126127void ShenandoahCodeRoots::arm_nmethods() {128assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");129_disarmed_value ++;130// 0 is reserved for new nmethod131if (_disarmed_value == 0) {132_disarmed_value = 1;133}134135JavaThreadIteratorWithHandle jtiwh;136for (JavaThread *thr = jtiwh.next(); thr != NULL; thr = jtiwh.next()) {137ShenandoahThreadLocalData::set_disarmed_value(thr, _disarmed_value);138}139}140141class ShenandoahDisarmNMethodClosure : public NMethodClosure {142private:143BarrierSetNMethod* const _bs;144145public:146ShenandoahDisarmNMethodClosure() :147_bs(BarrierSet::barrier_set()->barrier_set_nmethod()) {148}149150virtual void do_nmethod(nmethod* nm) {151_bs->disarm(nm);152}153};154155class ShenandoahDisarmNMethodsTask : public AbstractGangTask {156private:157ShenandoahDisarmNMethodClosure _cl;158ShenandoahConcurrentNMethodIterator _iterator;159160public:161ShenandoahDisarmNMethodsTask() :162AbstractGangTask("Shenandoah Disarm NMethods"),163_iterator(ShenandoahCodeRoots::table()) {164assert(SafepointSynchronize::is_at_safepoint(), "Only at a safepoint");165MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);166_iterator.nmethods_do_begin();167}168169~ShenandoahDisarmNMethodsTask() {170MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);171_iterator.nmethods_do_end();172}173174virtual void work(uint worker_id) {175ShenandoahParallelWorkerSession worker_session(worker_id);176_iterator.nmethods_do(&_cl);177}178};179180void ShenandoahCodeRoots::disarm_nmethods() {181if (ShenandoahNMethodBarrier) {182ShenandoahDisarmNMethodsTask task;183ShenandoahHeap::heap()->workers()->run_task(&task);184}185}186187class ShenandoahNMethodUnlinkClosure : public NMethodClosure {188private:189bool _unloading_occurred;190volatile bool _failed;191ShenandoahHeap* const _heap;192BarrierSetNMethod* const _bs;193194void set_failed() {195Atomic::store(&_failed, true);196}197198void unlink(nmethod* nm) {199// Unlinking of the dependencies must happen before the200// handshake separating unlink and purge.201nm->flush_dependencies(false /* delete_immediately */);202203// unlink_from_method will take the CompiledMethod_lock.204// In this case we don't strictly need it when unlinking nmethods from205// the Method, because it is only concurrently unlinked by206// the entry barrier, which acquires the per nmethod lock.207nm->unlink_from_method();208209if (nm->is_osr_method()) {210// Invalidate the osr nmethod only once211nm->invalidate_osr_method();212}213}214public:215ShenandoahNMethodUnlinkClosure(bool unloading_occurred) :216_unloading_occurred(unloading_occurred),217_failed(false),218_heap(ShenandoahHeap::heap()),219_bs(ShenandoahBarrierSet::barrier_set()->barrier_set_nmethod()) {}220221virtual void do_nmethod(nmethod* nm) {222assert(_heap->is_concurrent_weak_root_in_progress(), "Only this phase");223if (failed()) {224return;225}226227ShenandoahNMethod* nm_data = ShenandoahNMethod::gc_data(nm);228assert(!nm_data->is_unregistered(), "Should not see unregistered entry");229230if (!nm->is_alive()) {231return;232}233234if (nm->is_unloading()) {235ShenandoahReentrantLocker locker(nm_data->lock());236unlink(nm);237return;238}239240ShenandoahReentrantLocker locker(nm_data->lock());241242// Heal oops and disarm243if (_bs->is_armed(nm)) {244ShenandoahEvacOOMScope oom_evac_scope;245ShenandoahNMethod::heal_nmethod_metadata(nm_data);246_bs->disarm(nm);247}248249// Clear compiled ICs and exception caches250if (!nm->unload_nmethod_caches(_unloading_occurred)) {251set_failed();252}253}254255bool failed() const {256return Atomic::load(&_failed);257}258};259260class ShenandoahUnlinkTask : public AbstractGangTask {261private:262ShenandoahNMethodUnlinkClosure _cl;263ICRefillVerifier* _verifier;264ShenandoahConcurrentNMethodIterator _iterator;265266public:267ShenandoahUnlinkTask(bool unloading_occurred, ICRefillVerifier* verifier) :268AbstractGangTask("Shenandoah Unlink NMethods"),269_cl(unloading_occurred),270_verifier(verifier),271_iterator(ShenandoahCodeRoots::table()) {272MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);273_iterator.nmethods_do_begin();274}275276~ShenandoahUnlinkTask() {277MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);278_iterator.nmethods_do_end();279}280281virtual void work(uint worker_id) {282ICRefillVerifierMark mark(_verifier);283_iterator.nmethods_do(&_cl);284}285286bool success() const {287return !_cl.failed();288}289};290291void ShenandoahCodeRoots::unlink(WorkGang* workers, bool unloading_occurred) {292assert(ShenandoahHeap::heap()->unload_classes(), "Only when running concurrent class unloading");293294for (;;) {295ICRefillVerifier verifier;296297{298ShenandoahUnlinkTask task(unloading_occurred, &verifier);299workers->run_task(&task);300if (task.success()) {301return;302}303}304305// Cleaning failed because we ran out of transitional IC stubs,306// so we have to refill and try again. Refilling requires taking307// a safepoint, so we temporarily leave the suspendible thread set.308SuspendibleThreadSetLeaver sts;309InlineCacheBuffer::refill_ic_stubs();310}311}312313class ShenandoahNMethodPurgeClosure : public NMethodClosure {314public:315virtual void do_nmethod(nmethod* nm) {316if (nm->is_alive() && nm->is_unloading()) {317nm->make_unloaded();318}319}320};321322class ShenandoahNMethodPurgeTask : public AbstractGangTask {323private:324ShenandoahNMethodPurgeClosure _cl;325ShenandoahConcurrentNMethodIterator _iterator;326327public:328ShenandoahNMethodPurgeTask() :329AbstractGangTask("Shenandoah Purge NMethods"),330_cl(),331_iterator(ShenandoahCodeRoots::table()) {332MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);333_iterator.nmethods_do_begin();334}335336~ShenandoahNMethodPurgeTask() {337MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);338_iterator.nmethods_do_end();339}340341virtual void work(uint worker_id) {342_iterator.nmethods_do(&_cl);343}344};345346void ShenandoahCodeRoots::purge(WorkGang* workers) {347assert(ShenandoahHeap::heap()->unload_classes(), "Only when running concurrent class unloading");348349ShenandoahNMethodPurgeTask task;350workers->run_task(&task);351}352353ShenandoahCodeRootsIterator::ShenandoahCodeRootsIterator() :354_par_iterator(CodeCache::heaps()),355_table_snapshot(NULL) {356assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");357assert(!Thread::current()->is_Worker_thread(), "Should not be acquired by workers");358CodeCache_lock->lock_without_safepoint_check();359_table_snapshot = ShenandoahCodeRoots::table()->snapshot_for_iteration();360}361362ShenandoahCodeRootsIterator::~ShenandoahCodeRootsIterator() {363ShenandoahCodeRoots::table()->finish_iteration(_table_snapshot);364_table_snapshot = NULL;365CodeCache_lock->unlock();366}367368void ShenandoahCodeRootsIterator::possibly_parallel_blobs_do(CodeBlobClosure *f) {369assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");370assert(_table_snapshot != NULL, "Sanity");371_table_snapshot->parallel_blobs_do(f);372}373374375