Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahCodeRoots.cpp
38920 views
/*1* Copyright (c) 2017, 2019, Red Hat, Inc. All rights reserved.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation.6*7* This code is distributed in the hope that it will be useful, but WITHOUT8* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or9* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License10* version 2 for more details (a copy is included in the LICENSE file that11* accompanied this code).12*13* You should have received a copy of the GNU General Public License version14* 2 along with this work; if not, write to the Free Software Foundation,15* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.16*17* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA18* or visit www.oracle.com if you need additional information or have any19* questions.20*21*/2223#include "precompiled.hpp"24#include "code/codeCache.hpp"25#include "code/nmethod.hpp"26#include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp"27#include "gc_implementation/shenandoah/shenandoahCodeRoots.hpp"28#include "memory/resourceArea.hpp"29#include "runtime/vmThread.hpp"3031ShenandoahParallelCodeCacheIterator::ShenandoahParallelCodeCacheIterator() :32_claimed_idx(0), _finished(false) {33}3435void ShenandoahParallelCodeCacheIterator::parallel_blobs_do(CodeBlobClosure* f) {36assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");3738/*39* Parallel code heap walk.40*41* This code makes all threads scan all code heaps, but only one thread would execute the42* closure on given blob. This is achieved by recording the "claimed" blocks: if a thread43* had claimed the block, it can process all blobs in it. Others have to fast-forward to44* next attempt without processing.45*46* Late threads would return immediately if iterator is finished.47*/4849if (_finished) {50return;51}5253int stride = 256; // educated guess54int stride_mask = stride - 1;55assert (is_power_of_2(stride), "sanity");5657int count = 0;58bool process_block = true;5960for (CodeBlob *cb = CodeCache::first(); cb != NULL; cb = CodeCache::next(cb)) {61int current = count++;62if ((current & stride_mask) == 0) {63process_block = (current >= _claimed_idx) &&64(Atomic::cmpxchg(current + stride, &_claimed_idx, current) == current);65}66if (process_block) {67if (cb->is_alive()) {68f->do_code_blob(cb);69#ifdef ASSERT70if (cb->is_nmethod())71((nmethod*)cb)->verify_scavenge_root_oops();72#endif73}74}75}7677_finished = true;78}7980class ShenandoahNMethodOopDetector : public OopClosure {81private:82ResourceMark rm; // For growable array allocation below.83GrowableArray<oop*> _oops;8485public:86ShenandoahNMethodOopDetector() : _oops(10) {};8788void do_oop(oop* o) {89_oops.append(o);90}9192void do_oop(narrowOop* o) {93fatal("NMethods should not have compressed oops embedded.");94}9596GrowableArray<oop*>* oops() {97return &_oops;98}99100bool has_oops() {101return !_oops.is_empty();102}103};104105ShenandoahCodeRoots::PaddedLock ShenandoahCodeRoots::_recorded_nms_lock;106GrowableArray<ShenandoahNMethod*>* ShenandoahCodeRoots::_recorded_nms;107108void ShenandoahCodeRoots::initialize() {109_recorded_nms_lock._lock = 0;110_recorded_nms = new (ResourceObj::C_HEAP, mtGC) GrowableArray<ShenandoahNMethod*>(100, true, mtGC);111}112113void ShenandoahCodeRoots::add_nmethod(nmethod* nm) {114switch (ShenandoahCodeRootsStyle) {115case 0:116case 1:117break;118case 2: {119ShenandoahNMethodOopDetector detector;120nm->oops_do(&detector);121122if (detector.has_oops()) {123ShenandoahNMethod* nmr = new ShenandoahNMethod(nm, detector.oops());124nmr->assert_alive_and_correct();125126ShenandoahCodeRootsLock lock(true);127128int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod);129if (idx != -1) {130ShenandoahNMethod* old = _recorded_nms->at(idx);131_recorded_nms->at_put(idx, nmr);132delete old;133} else {134_recorded_nms->append(nmr);135}136}137break;138}139default:140ShouldNotReachHere();141}142};143144void ShenandoahCodeRoots::remove_nmethod(nmethod* nm) {145switch (ShenandoahCodeRootsStyle) {146case 0:147case 1: {148break;149}150case 2: {151ShenandoahNMethodOopDetector detector;152nm->oops_do(&detector, /* allow_zombie = */ true);153154if (detector.has_oops()) {155ShenandoahCodeRootsLock lock(true);156157int idx = _recorded_nms->find(nm, ShenandoahNMethod::find_with_nmethod);158assert(idx != -1, err_msg("nmethod " PTR_FORMAT " should be registered", p2i(nm)));159ShenandoahNMethod* old = _recorded_nms->at(idx);160old->assert_same_oops(detector.oops());161_recorded_nms->delete_at(idx);162delete old;163}164break;165}166default:167ShouldNotReachHere();168}169}170171ShenandoahCodeRootsIterator::ShenandoahCodeRootsIterator() :172_heap(ShenandoahHeap::heap()),173_claimed(0) {174assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");175assert(!Thread::current()->is_Worker_thread(), "Should not be acquired by workers");176switch (ShenandoahCodeRootsStyle) {177case 0:178case 1:179break;180case 2:181ShenandoahCodeRoots::acquire_lock(false);182break;183default:184ShouldNotReachHere();185}186}187188ShenandoahCodeRootsIterator::~ShenandoahCodeRootsIterator() {189switch (ShenandoahCodeRootsStyle) {190case 0:191case 1: {192// No need to do anything here193break;194}195case 2: {196ShenandoahCodeRoots::release_lock(false);197break;198}199default:200ShouldNotReachHere();201}202}203204template<bool CSET_FILTER>205void ShenandoahCodeRootsIterator::dispatch_parallel_blobs_do(CodeBlobClosure *f) {206switch (ShenandoahCodeRootsStyle) {207case 0: {208if (_seq_claimed.try_set()) {209CodeCache::blobs_do(f);210}211break;212}213case 1: {214_par_iterator.parallel_blobs_do(f);215break;216}217case 2: {218ShenandoahCodeRootsIterator::fast_parallel_blobs_do<CSET_FILTER>(f);219break;220}221default:222ShouldNotReachHere();223}224}225226void ShenandoahAllCodeRootsIterator::possibly_parallel_blobs_do(CodeBlobClosure *f) {227ShenandoahCodeRootsIterator::dispatch_parallel_blobs_do<false>(f);228}229230void ShenandoahCsetCodeRootsIterator::possibly_parallel_blobs_do(CodeBlobClosure *f) {231ShenandoahCodeRootsIterator::dispatch_parallel_blobs_do<true>(f);232}233234template <bool CSET_FILTER>235void ShenandoahCodeRootsIterator::fast_parallel_blobs_do(CodeBlobClosure *f) {236assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint");237238size_t stride = 256; // educated guess239240GrowableArray<ShenandoahNMethod*>* list = ShenandoahCodeRoots::_recorded_nms;241242jlong max = list->length();243while (_claimed < max) {244size_t cur = (size_t)Atomic::add(stride, &_claimed); // Note: in JDK 8, add() returns old value245size_t start = cur;246size_t end = MIN2(cur + stride, (size_t) max);247if (start >= (size_t)max) break;248249for (size_t idx = start; idx < end; idx++) {250ShenandoahNMethod* nmr = list->at((int) idx);251nmr->assert_alive_and_correct();252253if (CSET_FILTER && !nmr->has_cset_oops(_heap)) {254continue;255}256257f->do_code_blob(nmr->nm());258}259}260}261262ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray<oop*>* oops) {263_nm = nm;264_oops = NEW_C_HEAP_ARRAY(oop*, oops->length(), mtGC);265_oops_count = oops->length();266for (int c = 0; c < _oops_count; c++) {267_oops[c] = oops->at(c);268}269}270271ShenandoahNMethod::~ShenandoahNMethod() {272if (_oops != NULL) {273FREE_C_HEAP_ARRAY(oop*, _oops, mtGC);274}275}276277bool ShenandoahNMethod::has_cset_oops(ShenandoahHeap *heap) {278for (int c = 0; c < _oops_count; c++) {279oop o = oopDesc::load_heap_oop(_oops[c]);280if (heap->in_collection_set(o)) {281return true;282}283}284return false;285}286287#ifdef ASSERT288void ShenandoahNMethod::assert_alive_and_correct() {289assert(_nm->is_alive(), "only alive nmethods here");290assert(_oops_count > 0, "should have filtered nmethods without oops before");291ShenandoahHeap* heap = ShenandoahHeap::heap();292for (int c = 0; c < _oops_count; c++) {293oop *loc = _oops[c];294assert(_nm->code_contains((address) loc) || _nm->oops_contains(loc), "nmethod should contain the oop*");295oop o = oopDesc::load_heap_oop(loc);296shenandoah_assert_correct_except(loc, o,297o == NULL ||298heap->is_full_gc_move_in_progress() ||299(VMThread::vm_operation() != NULL) && (VMThread::vm_operation()->type() == VM_Operation::VMOp_HeapWalkOperation)300);301}302}303304void ShenandoahNMethod::assert_same_oops(GrowableArray<oop*>* oops) {305assert(_oops_count == oops->length(), "should have the same number of oop*");306for (int c = 0; c < _oops_count; c++) {307assert(_oops[c] == oops->at(c), "should be the same oop*");308}309}310#endif311312313