2019-03-14 09:15:51 +01:00
|
|
|
/*
|
|
|
|
* 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"
|
2019-03-18 15:21:33 +01:00
|
|
|
#include "runtime/mutexLocker.hpp"
|
2019-03-14 09:15:51 +01:00
|
|
|
#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) {
|
2019-03-18 15:19:39 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2019-03-14 09:15:51 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#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),
|
2019-03-18 15:21:33 +01:00
|
|
|
_found(false) {}
|
2019-03-14 09:15:51 +01:00
|
|
|
|
|
|
|
bool found() { return _found; }
|
|
|
|
virtual void do_oop(oop* p) {
|
2019-03-18 15:21:33 +01:00
|
|
|
if (!_found && *p != NULL && _is_scavengable->do_object_b(*p)) {
|
2019-03-14 09:15:51 +01:00
|
|
|
_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.
|
2019-03-18 15:21:33 +01:00
|
|
|
void ScavengableNMethods::nmethods_do_and_prune(CodeBlobToOopClosure* cl) {
|
2019-03-14 09:15:51 +01:00
|
|
|
assert_locked_or_safepoint(CodeCache_lock);
|
|
|
|
|
|
|
|
debug_only(mark_on_list_nmethods());
|
|
|
|
|
|
|
|
nmethod* prev = NULL;
|
|
|
|
nmethod* cur = _head;
|
|
|
|
while (cur != NULL) {
|
2019-03-18 15:21:33 +01:00
|
|
|
assert(cur->is_alive(), "Must be");
|
|
|
|
|
2019-03-14 09:15:51 +01:00
|
|
|
ScavengableNMethodsData data = gc_data(cur);
|
|
|
|
debug_only(data.clear_marked());
|
|
|
|
assert(data.on_list(), "else shouldn't be on this list");
|
|
|
|
|
2019-03-18 15:21:33 +01:00
|
|
|
if (cl != NULL) {
|
|
|
|
cl->do_code_blob(cur);
|
2019-03-14 09:15:51 +01:00
|
|
|
}
|
2019-03-18 15:21:33 +01:00
|
|
|
|
2019-03-14 09:15:51 +01:00
|
|
|
nmethod* const next = data.next();
|
2019-03-18 15:21:33 +01:00
|
|
|
|
|
|
|
if (!has_scavengable_oops(cur)) {
|
|
|
|
unlist_nmethod(cur, prev);
|
|
|
|
} else {
|
|
|
|
prev = cur;
|
2019-03-14 09:15:51 +01:00
|
|
|
}
|
2019-03-18 15:21:33 +01:00
|
|
|
|
2019-03-14 09:15:51 +01:00
|
|
|
cur = next;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for stray marks.
|
|
|
|
debug_only(verify_unlisted_nmethods(NULL));
|
|
|
|
}
|
|
|
|
|
2019-03-18 15:21:33 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2019-03-14 09:15:51 +01:00
|
|
|
#ifndef PRODUCT
|
2019-03-18 15:21:33 +01:00
|
|
|
void ScavengableNMethods::asserted_non_scavengable_nmethods_do(CodeBlobClosure* cl) {
|
2019-03-14 09:15:51 +01:00
|
|
|
// 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();
|
|
|
|
}
|
2019-03-18 15:21:33 +01:00
|
|
|
verify_unlisted_nmethods(cl);
|
2019-03-14 09:15:51 +01:00
|
|
|
}
|
|
|
|
#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.
|
2019-03-18 15:21:33 +01:00
|
|
|
void ScavengableNMethods::verify_unlisted_nmethods(CodeBlobClosure* cl) {
|
2019-03-14 09:15:51 +01:00
|
|
|
NMethodIterator iter(NMethodIterator::only_alive);
|
|
|
|
while(iter.next()) {
|
|
|
|
nmethod* nm = iter.method();
|
|
|
|
|
|
|
|
verify_nmethod(nm);
|
|
|
|
|
2019-03-18 15:21:33 +01:00
|
|
|
if (cl != NULL && !gc_data(nm).on_list()) {
|
|
|
|
cl->do_code_blob(nm);
|
2019-03-14 09:15:51 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif //PRODUCT
|