jdk-24/src/hotspot/share/gc/shared/scavengableNMethods.cpp

244 lines
6.8 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2019, Oracle and/or its affiliates. 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.
*
*/
#include "precompiled.hpp"
#include "code/codeCache.hpp"
#include "code/nmethod.hpp"
#include "gc/shared/scavengableNMethods.hpp"
#include "gc/shared/scavengableNMethodsData.hpp"
#include "runtime/mutexLocker.hpp"
#include "utilities/debug.hpp"
static ScavengableNMethodsData gc_data(nmethod* nm) {
return ScavengableNMethodsData(nm);
}
nmethod* ScavengableNMethods::_head = NULL;
BoolObjectClosure* ScavengableNMethods::_is_scavengable = NULL;
void ScavengableNMethods::initialize(BoolObjectClosure* is_scavengable) {
_is_scavengable = is_scavengable;
}
// Conditionally adds the nmethod to the list if it is
// not already on the list and has a scavengeable root.
void ScavengableNMethods::register_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
ScavengableNMethodsData data = gc_data(nm);
if (data.on_list() || !has_scavengable_oops(nm)) {
return;
}
data.set_on_list();
data.set_next(_head);
_head = nm;
}
void ScavengableNMethods::unregister_nmethod(nmethod* nm) {
assert_locked_or_safepoint(CodeCache_lock);
if (gc_data(nm).on_list()) {
nmethod* prev = NULL;
for (nmethod* cur = _head; cur != NULL; cur = gc_data(cur).next()) {
if (cur == nm) {
unlist_nmethod(cur, prev);
return;
}
prev = cur;
}
}
}
#ifndef PRODUCT
class DebugScavengableOops: public OopClosure {
BoolObjectClosure* _is_scavengable;
nmethod* _nm;
bool _ok;
public:
DebugScavengableOops(BoolObjectClosure* is_scavengable, nmethod* nm) :
_is_scavengable(is_scavengable),
_nm(nm),
_ok(true) { }
bool ok() { return _ok; }
virtual void do_oop(oop* p) {
if (*p == NULL || !_is_scavengable->do_object_b(*p)) {
return;
}
if (_ok) {
_nm->print_nmethod(true);
_ok = false;
}
tty->print_cr("*** scavengable oop " PTR_FORMAT " found at " PTR_FORMAT " (offset %d)",
p2i(*p), p2i(p), (int)((intptr_t)p - (intptr_t)_nm));
(*p)->print();
}
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
};
#endif // PRODUCT
void ScavengableNMethods::verify_nmethod(nmethod* nm) {
#ifndef PRODUCT
if (!gc_data(nm).on_list()) {
// Actually look inside, to verify the claim that it's clean.
DebugScavengableOops cl(_is_scavengable, nm);
nm->oops_do(&cl);
if (!cl.ok())
fatal("found an unadvertised bad scavengable oop in the code cache");
}
assert(gc_data(nm).not_marked(), "");
#endif // PRODUCT
}
class HasScavengableOops: public OopClosure {
BoolObjectClosure* _is_scavengable;
bool _found;
public:
HasScavengableOops(BoolObjectClosure* is_scavengable, nmethod* nm) :
_is_scavengable(is_scavengable),
_found(false) {}
bool found() { return _found; }
virtual void do_oop(oop* p) {
if (!_found && *p != NULL && _is_scavengable->do_object_b(*p)) {
_found = true;
}
}
virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); }
};
bool ScavengableNMethods::has_scavengable_oops(nmethod* nm) {
HasScavengableOops cl(_is_scavengable, nm);
nm->oops_do(&cl);
return cl.found();
}
// Walk the list of methods which might contain oops to the java heap.
void ScavengableNMethods::nmethods_do_and_prune(CodeBlobToOopClosure* cl) {
assert_locked_or_safepoint(CodeCache_lock);
debug_only(mark_on_list_nmethods());
nmethod* prev = NULL;
nmethod* cur = _head;
while (cur != NULL) {
assert(cur->is_alive(), "Must be");
ScavengableNMethodsData data = gc_data(cur);
debug_only(data.clear_marked());
assert(data.on_list(), "else shouldn't be on this list");
if (cl != NULL) {
cl->do_code_blob(cur);
}
nmethod* const next = data.next();
if (!has_scavengable_oops(cur)) {
unlist_nmethod(cur, prev);
} else {
prev = cur;
}
cur = next;
}
// Check for stray marks.
debug_only(verify_unlisted_nmethods(NULL));
}
void ScavengableNMethods::prune_nmethods() {
nmethods_do_and_prune(NULL /* No closure */);
}
// Walk the list of methods which might contain oops to the java heap.
void ScavengableNMethods::nmethods_do(CodeBlobToOopClosure* cl) {
nmethods_do_and_prune(cl);
}
#ifndef PRODUCT
void ScavengableNMethods::asserted_non_scavengable_nmethods_do(CodeBlobClosure* cl) {
// While we are here, verify the integrity of the list.
mark_on_list_nmethods();
for (nmethod* cur = _head; cur != NULL; cur = gc_data(cur).next()) {
assert(gc_data(cur).on_list(), "else shouldn't be on this list");
gc_data(cur).clear_marked();
}
verify_unlisted_nmethods(cl);
}
#endif // PRODUCT
void ScavengableNMethods::unlist_nmethod(nmethod* nm, nmethod* prev) {
assert_locked_or_safepoint(CodeCache_lock);
assert((prev == NULL && _head == nm) ||
(prev != NULL && gc_data(prev).next() == nm), "precondition");
ScavengableNMethodsData data = gc_data(nm);
if (prev == NULL) {
_head = data.next();
} else {
gc_data(prev).set_next(data.next());
}
data.set_next(NULL);
data.clear_on_list();
}
#ifndef PRODUCT
// Temporarily mark nmethods that are claimed to be on the scavenge list.
void ScavengableNMethods::mark_on_list_nmethods() {
NMethodIterator iter(NMethodIterator::only_alive);
while(iter.next()) {
nmethod* nm = iter.method();
ScavengableNMethodsData data = gc_data(nm);
assert(data.not_marked(), "clean state");
if (data.on_list())
data.set_marked();
}
}
// If the closure is given, run it on the unlisted nmethods.
// Also make sure that the effects of mark_on_list_nmethods is gone.
void ScavengableNMethods::verify_unlisted_nmethods(CodeBlobClosure* cl) {
NMethodIterator iter(NMethodIterator::only_alive);
while(iter.next()) {
nmethod* nm = iter.method();
verify_nmethod(nm);
if (cl != NULL && !gc_data(nm).on_list()) {
cl->do_code_blob(nm);
}
}
}
#endif //PRODUCT