提交 1cae2acb 编写于 作者: C coleenp

8000662: NPG: nashorn ant clean test262 out-of-memory with Java heap

Summary: Add ClassLoaderData object for each anonymous class with metaspaces to allocate in.
Reviewed-by: twisti, jrose, stefank
上级 1d1883f5
......@@ -492,6 +492,26 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
dest->verify_section_allocation();
}
// Anonymous classes need mirror to keep the metadata alive but
// for regular classes, the class_loader is sufficient.
static void append_oop_references(GrowableArray<oop>* oops, Klass* k) {
if (k->oop_is_instance()) {
InstanceKlass* ik = InstanceKlass::cast(k);
if (ik->is_anonymous()) {
oop o = ik->java_mirror();
assert (o != NULL, "should have a mirror");
if (!oops->contains(o)) {
oops->append(o);
}
return; // only need the mirror
}
}
oop cl = k->class_loader();
if (cl != NULL && !oops->contains(cl)) {
oops->append(cl);
}
}
void CodeBuffer::finalize_oop_references(methodHandle mh) {
No_Safepoint_Verifier nsv;
......@@ -509,7 +529,6 @@ void CodeBuffer::finalize_oop_references(methodHandle mh) {
if (md->metadata_is_immediate()) {
Metadata* m = md->metadata_value();
if (oop_recorder()->is_real(m)) {
oop o = NULL;
if (m->is_methodData()) {
m = ((MethodData*)m)->method();
}
......@@ -517,16 +536,13 @@ void CodeBuffer::finalize_oop_references(methodHandle mh) {
m = ((Method*)m)->method_holder();
}
if (m->is_klass()) {
o = ((Klass*)m)->class_loader();
append_oop_references(&oops, (Klass*)m);
} else {
// XXX This will currently occur for MDO which don't
// have a backpointer. This has to be fixed later.
m->print();
ShouldNotReachHere();
}
if (o != NULL && oops.find(o) == -1) {
oops.append(o);
}
}
}
}
......@@ -537,7 +553,6 @@ void CodeBuffer::finalize_oop_references(methodHandle mh) {
for (int i = 0; i < oop_recorder()->metadata_count(); i++) {
Metadata* m = oop_recorder()->metadata_at(i);
if (oop_recorder()->is_real(m)) {
oop o = NULL;
if (m->is_methodData()) {
m = ((MethodData*)m)->method();
}
......@@ -545,24 +560,18 @@ void CodeBuffer::finalize_oop_references(methodHandle mh) {
m = ((Method*)m)->method_holder();
}
if (m->is_klass()) {
o = ((Klass*)m)->class_loader();
append_oop_references(&oops, (Klass*)m);
} else {
m->print();
ShouldNotReachHere();
}
if (o != NULL && oops.find(o) == -1) {
oops.append(o);
}
}
}
}
// Add the class loader of Method* for the nmethod itself
oop cl = mh->method_holder()->class_loader();
if (cl != NULL) {
oops.append(cl);
}
append_oop_references(&oops, mh->method_holder());
// Add any oops that we've found
Thread* thread = Thread::current();
......
......@@ -31,7 +31,7 @@
#include "memory/resourceArea.hpp"
#include "utilities/copy.hpp"
#ifdef ASSERT
#ifndef PRODUCT
// ciReplay
......@@ -939,4 +939,4 @@ bool ciReplay::is_loaded(Method* method) {
ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
return rec != NULL;
}
#endif
#endif // PRODUCT
......@@ -32,7 +32,7 @@
class ciReplay {
CI_PACKAGE_ACCESS
#ifdef ASSERT
#ifndef PRODUCT
private:
static int replay_impl(TRAPS);
......
......@@ -2950,7 +2950,7 @@ static void parseAndPrintGenericSignatures(
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
Handle class_loader,
ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
......@@ -2964,7 +2964,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
// original class bytes.
unsigned char *cached_class_file_bytes = NULL;
jint cached_class_file_length;
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
Handle class_loader(THREAD, loader_data->class_loader());
bool has_default_methods = false;
ResourceMark rm(THREAD);
......@@ -3005,7 +3005,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
unsigned char* ptr = cfs->buffer();
unsigned char* end_ptr = cfs->buffer() + cfs->length();
JvmtiExport::post_class_file_load_hook(name, class_loader, protection_domain,
JvmtiExport::post_class_file_load_hook(name, class_loader(), protection_domain,
&ptr, &end_ptr,
&cached_class_file_bytes,
&cached_class_file_length);
......@@ -4004,8 +4004,7 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) {
assert(k->size_helper() > 0, "layout_helper is initialized");
if ((!RegisterFinalizersAtInit && k->has_finalizer())
|| k->is_abstract() || k->is_interface()
|| (k->name() == vmSymbols::java_lang_Class()
&& k->class_loader_data()->is_the_null_class_loader_data())
|| (k->name() == vmSymbols::java_lang_Class() && k->class_loader() == NULL)
|| k->size_helper() >= FastAllocateSizeLimit) {
// Forbid fast-path allocation.
jint lh = Klass::instance_layout_helper(k->size_helper(), true);
......
......@@ -363,16 +363,16 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
// "parsed_name" is updated by this method, and is the name found
// while parsing the stream.
instanceKlassHandle parseClassFile(Symbol* name,
Handle class_loader,
ClassLoaderData* loader_data,
Handle protection_domain,
TempNewSymbol& parsed_name,
bool verify,
TRAPS) {
KlassHandle no_host_klass;
return parseClassFile(name, class_loader, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD);
return parseClassFile(name, loader_data, protection_domain, no_host_klass, NULL, parsed_name, verify, THREAD);
}
instanceKlassHandle parseClassFile(Symbol* name,
Handle class_loader,
ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
......
......@@ -26,6 +26,7 @@
#include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
......@@ -910,11 +911,11 @@ instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
// class file found, parse it
ClassFileParser parser(stream);
Handle class_loader;
ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain;
TempNewSymbol parsed_name = NULL;
instanceKlassHandle result = parser.parseClassFile(h_name,
class_loader,
loader_data,
protection_domain,
parsed_name,
false,
......
......@@ -65,13 +65,19 @@
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
ClassLoaderData::ClassLoaderData(Handle h_class_loader) : _class_loader(h_class_loader()),
_metaspace(NULL), _unloading(false), _klasses(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(NULL),
_deallocate_list(NULL), _next(NULL),
_metaspace(NULL), _unloading(false), _keep_alive(false), _klasses(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
_next(NULL), _dependencies(NULL),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
// empty
}
void ClassLoaderData::init_dependencies(TRAPS) {
// Create empty dependencies array to add to. CMS requires this to be
// an oop so that it can track additions via card marks. We think.
_dependencies = (oop)oopFactory::new_objectArray(2, CHECK);
}
bool ClassLoaderData::claim() {
if (_claimed == 1) {
return false;
......@@ -86,6 +92,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m
}
f->do_oop(&_class_loader);
f->do_oop(&_dependencies);
_handles->oops_do(f);
if (klass_closure != NULL) {
classes_do(klass_closure);
......@@ -110,70 +117,100 @@ void ClassLoaderData::record_dependency(Klass* k, TRAPS) {
ClassLoaderData * const from_cld = this;
ClassLoaderData * const to_cld = k->class_loader_data();
// Records dependency between non-null class loaders only.
if (to_cld->is_the_null_class_loader_data() || from_cld->is_the_null_class_loader_data()) {
// Dependency to the null class loader data doesn't need to be recorded
// because the null class loader data never goes away.
if (to_cld->is_the_null_class_loader_data()) {
return;
}
// Check that this dependency isn't from the same or parent class_loader
oop to = to_cld->class_loader();
oop from = from_cld->class_loader();
oop curr = from;
while (curr != NULL) {
if (curr == to) {
return; // this class loader is in the parent list, no need to add it.
oop to;
if (to_cld->is_anonymous()) {
// Anonymous class dependencies are through the mirror.
to = k->java_mirror();
} else {
to = to_cld->class_loader();
// If from_cld is anonymous, even if it's class_loader is a parent of 'to'
// we still have to add it. The class_loader won't keep from_cld alive.
if (!from_cld->is_anonymous()) {
// Check that this dependency isn't from the same or parent class_loader
oop from = from_cld->class_loader();
oop curr = from;
while (curr != NULL) {
if (curr == to) {
return; // this class loader is in the parent list, no need to add it.
}
curr = java_lang_ClassLoader::parent(curr);
}
}
curr = java_lang_ClassLoader::parent(curr);
}
// It's a dependency we won't find through GC, add it. This is relatively rare
from_cld->add_dependency(to_cld, CHECK);
// Must handle over GC point.
Handle dependency(THREAD, to);
from_cld->add_dependency(dependency, CHECK);
}
bool ClassLoaderData::has_dependency(ClassLoaderData* dependency) {
oop loader = dependency->class_loader();
// Get objArrayOop out of the class_loader oop and see if this dependency
// is there. Don't safepoint! These are all oops.
// Dependency list is (oop class_loader, objArrayOop next)
objArrayOop ok = (objArrayOop)java_lang_ClassLoader::dependencies(class_loader());
void ClassLoaderData::add_dependency(Handle dependency, TRAPS) {
// Check first if this dependency is already in the list.
// Save a pointer to the last to add to under the lock.
objArrayOop ok = (objArrayOop)_dependencies;
objArrayOop last = NULL;
while (ok != NULL) {
if (ok->obj_at(0) == loader) {
return true;
last = ok;
if (ok->obj_at(0) == dependency()) {
// Don't need to add it
return;
}
ok = (objArrayOop)ok->obj_at(1);
}
return false;
// Create a new dependency node with fields for (class_loader or mirror, next)
objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
deps->obj_at_put(0, dependency());
// Must handle over more GC points
objArrayHandle new_dependency(THREAD, deps);
// Add the dependency under lock
assert (last != NULL, "dependencies should be initialized");
objArrayHandle last_handle(THREAD, last);
locked_add_dependency(last_handle, new_dependency);
}
void ClassLoaderData::add_dependency(ClassLoaderData* dependency, TRAPS) {
// Minimize the number of duplicates in the list.
if (has_dependency(dependency)) {
return;
}
void ClassLoaderData::locked_add_dependency(objArrayHandle last_handle,
objArrayHandle new_dependency) {
// Create a new dependency node with fields for (class_loader, next)
objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
deps->obj_at_put(0, dependency->class_loader());
// Add this lock free, using compare and exchange, need barriers for GC
// Do the barrier first.
HeapWord* addr = java_lang_ClassLoader::dependencies_addr(class_loader());
while (true) {
oop old_dependency = java_lang_ClassLoader::dependencies(class_loader());
deps->obj_at_put(1, old_dependency);
oop newold = oopDesc::atomic_compare_exchange_oop((oop)deps, addr, old_dependency, true);
if (newold == old_dependency) {
update_barrier_set((void*)addr, (oop)deps);
// we won the race to add this dependency
break;
// Have to lock and put the new dependency on the end of the dependency
// array so the card mark for CMS sees that this dependency is new.
// Can probably do this lock free with some effort.
MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag);
oop loader_or_mirror = new_dependency->obj_at(0);
// Since the dependencies are only added, add to the end.
objArrayOop end = last_handle();
objArrayOop last = NULL;
while (end != NULL) {
last = end;
// check again if another thread added it to the end.
if (end->obj_at(0) == loader_or_mirror) {
// Don't need to add it
return;
}
end = (objArrayOop)end->obj_at(1);
}
assert (last != NULL, "dependencies should be initialized");
// fill in the first element with the oop in new_dependency.
if (last->obj_at(0) == NULL) {
last->obj_at_put(0, new_dependency->obj_at(0));
} else {
last->obj_at_put(1, new_dependency());
}
}
void ClassLoaderDataGraph::clear_claimed_marks() {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
cld->clear_claimed();
......@@ -187,7 +224,7 @@ void ClassLoaderData::add_class(Klass* k) {
// link the new item into the list
_klasses = k;
if (TraceClassLoaderData && k->class_loader_data() != NULL) {
if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
ResourceMark rm;
tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
PTR_FORMAT " loader: " PTR_FORMAT " %s",
......@@ -195,8 +232,7 @@ void ClassLoaderData::add_class(Klass* k) {
k->external_name(),
k->class_loader_data(),
k->class_loader(),
k->class_loader() != NULL ? k->class_loader()->klass()->external_name() : "NULL"
);
loader_name());
}
}
......@@ -221,6 +257,38 @@ void ClassLoaderData::remove_class(Klass* scratch_class) {
ShouldNotReachHere(); // should have found this class!!
}
bool ClassLoaderData::is_anonymous() const {
Klass* k = _klasses;
return (_keep_alive || (k != NULL && k->oop_is_instance() &&
InstanceKlass::cast(k)->is_anonymous()));
}
void ClassLoaderData::unload() {
_unloading = true;
if (TraceClassLoaderData) {
ResourceMark rm;
tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, this);
tty->print(" for instance "PTR_FORMAT" of %s", class_loader(),
loader_name());
if (is_anonymous()) {
tty->print(" for anonymous class "PTR_FORMAT " ", _klasses);
}
tty->print_cr("]");
}
}
bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
bool alive =
is_anonymous() ?
is_alive_closure->do_object_b(_klasses->java_mirror()) :
class_loader() == NULL || is_alive_closure->do_object_b(class_loader());
assert(!alive || claimed(), "must be claimed");
return alive;
}
ClassLoaderData::~ClassLoaderData() {
Metaspace *m = _metaspace;
if (m != NULL) {
......@@ -263,8 +331,8 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
if (_metaspace != NULL) {
return _metaspace;
}
if (class_loader() == NULL) {
assert(this == the_null_class_loader_data(), "Must be");
if (this == the_null_class_loader_data()) {
assert (class_loader() == NULL, "Must be");
size_t word_size = Metaspace::first_chunk_word_size();
set_metaspace(new Metaspace(_metaspace_lock, word_size));
} else {
......@@ -325,12 +393,19 @@ void ClassLoaderData::free_deallocate_list() {
}
}
#ifndef PRODUCT
void ClassLoaderData::print_loader(ClassLoaderData *loader_data, outputStream* out) {
oop class_loader = loader_data->class_loader();
out->print("%s", SystemDictionary::loader_name(class_loader));
// These anonymous class loaders are to contain classes used for JSR292
ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) {
// Add a new class loader data to the graph.
ClassLoaderData* cld = ClassLoaderDataGraph::add(NULL, loader, CHECK_NULL);
return cld;
}
const char* ClassLoaderData::loader_name() {
// Handles null class loader
return SystemDictionary::loader_name(class_loader());
}
#ifndef PRODUCT
// Define to dump klasses
#undef CLD_DUMP_KLASSES
......@@ -338,8 +413,7 @@ void ClassLoaderData::dump(outputStream * const out) {
ResourceMark rm;
out->print("ClassLoaderData CLD: "PTR_FORMAT", loader: "PTR_FORMAT", loader_klass: "PTR_FORMAT" %s {",
this, class_loader(),
class_loader() != NULL ? class_loader()->klass() : NULL,
class_loader() != NULL ? class_loader()->klass()->external_name() : "NULL");
class_loader() != NULL ? class_loader()->klass() : NULL, loader_name());
if (claimed()) out->print(" claimed ");
if (is_unloading()) out->print(" unloading ");
out->print(" handles " INTPTR_FORMAT, handles());
......@@ -373,8 +447,8 @@ void ClassLoaderData::dump(outputStream * const out) {
void ClassLoaderData::verify() {
oop cl = class_loader();
guarantee(this == class_loader_data(cl), "Must be the same");
guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data(), "must be");
guarantee(this == class_loader_data(cl) || is_anonymous(), "Must be the same");
guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || is_anonymous(), "must be");
// Verify the integrity of the allocated space.
if (metaspace_or_null() != NULL) {
......@@ -387,6 +461,7 @@ void ClassLoaderData::verify() {
}
}
// GC root of class loader data created.
ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL;
......@@ -395,19 +470,25 @@ ClassLoaderData* ClassLoaderDataGraph::_saved_head = NULL;
// Add a new class loader data node to the list. Assign the newly created
// ClassLoaderData into the java/lang/ClassLoader object as a hidden field
ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader_data) {
ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle loader, TRAPS) {
// Not assigned a class loader data yet.
// Create one.
ClassLoaderData* *list_head = &_head;
ClassLoaderData* next = _head;
ClassLoaderData* cld = new ClassLoaderData(loader_data);
// First, Atomically set it.
ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
if (old != NULL) {
delete cld;
// Returns the data.
return old;
ClassLoaderData* cld = new ClassLoaderData(loader);
if (cld_addr != NULL) {
// First, Atomically set it
ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
if (old != NULL) {
delete cld;
// Returns the data.
return old;
}
} else {
// Disallow unloading for this CLD during initialization if there is no
// class_loader oop to link this to.
cld->set_keep_alive(true);
}
// We won the race, and therefore the task of adding the data to the list of
......@@ -417,16 +498,22 @@ ClassLoaderData* ClassLoaderDataGraph::add(ClassLoaderData** cld_addr, Handle lo
ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
if (exchanged == next) {
if (TraceClassLoaderData) {
ResourceMark rm;
tty->print("[ClassLoaderData: ");
tty->print("create class loader data "PTR_FORMAT, cld);
tty->print(" for instance "PTR_FORMAT" of ", cld->class_loader());
loader_data->klass()->name()->print_symbol_on(tty);
tty->print(" for instance "PTR_FORMAT" of %s", cld->class_loader(),
cld->loader_name());
tty->print_cr("]");
}
// Create dependencies after the CLD is added to the list. Otherwise,
// the GC GC will not find the CLD and the _class_loader field will
// not be updated.
cld->init_dependencies(CHECK_NULL);
return cld;
}
next = exchanged;
} while (true);
}
void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
......@@ -435,9 +522,19 @@ void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, b
}
}
void ClassLoaderDataGraph::keep_alive_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
if (cld->keep_alive()) {
cld->oops_do(f, klass_closure, must_claim);
}
}
}
void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
if (ClassUnloading) {
ClassLoaderData::the_null_class_loader_data()->oops_do(f, klass_closure, must_claim);
// keep any special CLDs alive.
ClassLoaderDataGraph::keep_alive_oops_do(f, klass_closure, must_claim);
} else {
ClassLoaderDataGraph::oops_do(f, klass_closure, must_claim);
}
......@@ -516,9 +613,10 @@ bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
}
#endif // PRODUCT
// Move class loader data from main list to the unloaded list for unloading
// and deallocation later.
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive) {
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
ClassLoaderData* data = _head;
ClassLoaderData* prev = NULL;
bool seen_dead_loader = false;
......@@ -527,8 +625,7 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive) {
bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack;
while (data != NULL) {
if (data->class_loader() == NULL || is_alive->do_object_b(data->class_loader())) {
assert(data->claimed(), "class loader data must have been claimed");
if (data->keep_alive() || data->is_alive(is_alive_closure)) {
if (has_redefined_a_class) {
data->classes_do(InstanceKlass::purge_previous_versions);
}
......@@ -539,13 +636,7 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive) {
}
seen_dead_loader = true;
ClassLoaderData* dead = data;
dead->mark_for_unload();
if (TraceClassLoaderData) {
tty->print("[ClassLoaderData: unload loader data "PTR_FORMAT, dead);
tty->print(" for instance "PTR_FORMAT" of ", dead->class_loader());
dead->class_loader()->klass()->name()->print_symbol_on(tty);
tty->print_cr("]");
}
dead->unload();
data = data->next();
// Remove from loader list.
if (prev != NULL) {
......
......@@ -62,13 +62,14 @@ class ClassLoaderDataGraph : public AllStatic {
// CMS support.
static ClassLoaderData* _saved_head;
static ClassLoaderData* add(ClassLoaderData** loader_data_addr, Handle class_loader);
static ClassLoaderData* add(ClassLoaderData** loader_data_addr, Handle class_loader, TRAPS);
public:
static ClassLoaderData* find_or_create(Handle class_loader);
static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge();
static void clear_claimed_marks();
static void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim);
static void always_strong_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
static void keep_alive_oops_do(OopClosure* blk, KlassClosure* klass_closure, bool must_claim);
static void classes_do(KlassClosure* klass_closure);
static bool do_unloading(BoolObjectClosure* is_alive);
......@@ -101,10 +102,13 @@ class ClassLoaderData : public CHeapObj<mtClass> {
oop _class_loader; // oop used to uniquely identify a class loader
// class loader or a canonical class path
oop _dependencies; // oop to hold dependencies from this class loader
// data to others.
Metaspace * _metaspace; // Meta-space where meta-data defined by the
// classes in the class loader are allocated.
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away
bool _keep_alive; // if this CLD can be unloaded for anonymous loaders
volatile int _claimed; // true if claimed, for example during GC traces.
// To avoid applying oop closure more than once.
// Has to be an int because we cas it.
......@@ -129,8 +133,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
static Metaspace* _ro_metaspace;
static Metaspace* _rw_metaspace;
bool has_dependency(ClassLoaderData* cld);
void add_dependency(ClassLoaderData* to_loader_data, TRAPS);
void add_dependency(Handle dependency, TRAPS);
void locked_add_dependency(objArrayHandle last, objArrayHandle new_dependency);
void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return _next; }
......@@ -150,7 +154,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
bool claimed() const { return _claimed == 1; }
bool claim();
void mark_for_unload() { _unloading = true; }
void unload();
bool keep_alive() const { return _keep_alive; }
bool is_alive(BoolObjectClosure* is_alive_closure) const;
void classes_do(void f(InstanceKlass*));
......@@ -168,6 +174,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
return _the_null_class_loader_data;
}
bool is_anonymous() const;
static void init_null_class_loader_data() {
assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
assert(ClassLoaderDataGraph::_head == NULL, "cannot initialize twice");
......@@ -194,6 +202,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
assert(!(is_the_null_class_loader_data() && _unloading), "The null class loader can never be unloaded");
return _unloading;
}
// Anonymous class loader data doesn't have anything to keep them from
// being unloaded during parsing the anonymous class.
void set_keep_alive(bool value) { _keep_alive = value; }
unsigned int identity_hash() {
return _class_loader == NULL ? 0 : _class_loader->identity_hash();
......@@ -211,15 +222,18 @@ class ClassLoaderData : public CHeapObj<mtClass> {
void print_value_on(outputStream* out) const PRODUCT_RETURN;
void dump(outputStream * const out) PRODUCT_RETURN;
void verify();
const char* loader_name();
jobject add_handle(Handle h);
void add_class(Klass* k);
void remove_class(Klass* k);
void record_dependency(Klass* to, TRAPS);
void init_dependencies(TRAPS);
void add_to_deallocate_list(Metadata* m);
static ClassLoaderData* class_loader_data(oop loader);
static ClassLoaderData* anonymous_class_loader_data(oop loader, TRAPS);
static void print_loader(ClassLoaderData *loader_data, outputStream *out);
// CDS support
......
......@@ -33,7 +33,7 @@ inline ClassLoaderData* ClassLoaderData::class_loader_data(oop loader) {
}
inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) {
inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader, TRAPS) {
assert(loader() != NULL,"Must be a class loader");
// Gets the class loader data out of the java/lang/ClassLoader object, if non-null
// it's already in the loader_data, so no need to add
......@@ -42,5 +42,5 @@ inline ClassLoaderData *ClassLoaderDataGraph::find_or_create(Handle loader) {
if (loader_data_id) {
return loader_data_id;
}
return ClassLoaderDataGraph::add(loader_data_addr, loader);
return ClassLoaderDataGraph::add(loader_data_addr, loader, THREAD);
}
......@@ -580,7 +580,7 @@ void Dictionary::verify() {
// class loader must be present; a null class loader is the
// boostrap loader
guarantee(loader_data != NULL || DumpSharedSpaces ||
loader_data->is_the_null_class_loader_data() ||
loader_data->class_loader() == NULL ||
loader_data->class_loader()->is_instance(),
"checking type of class_loader");
e->verify();
......
......@@ -2544,8 +2544,8 @@ Metadata* java_lang_invoke_MemberName::vmtarget(oop mname) {
void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) {
assert(is_instance(mname), "wrong type");
#ifdef ASSERT
// check the type of the vmtarget
oop dependency = NULL;
if (ref != NULL) {
switch (flags(mname) & (MN_IS_METHOD |
MN_IS_CONSTRUCTOR |
......@@ -2553,28 +2553,21 @@ void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) {
case MN_IS_METHOD:
case MN_IS_CONSTRUCTOR:
assert(ref->is_method(), "should be a method");
dependency = ((Method*)ref)->method_holder()->java_mirror();
break;
case MN_IS_FIELD:
assert(ref->is_klass(), "should be a class");
dependency = ((Klass*)ref)->java_mirror();
break;
default:
ShouldNotReachHere();
}
}
#endif //ASSERT
mname->address_field_put(_vmtarget_offset, (address)ref);
oop loader = NULL;
if (ref != NULL) {
if (ref->is_klass()) {
loader = ((Klass*)ref)->class_loader();
} else if (ref->is_method()) {
loader = ((Method*)ref)->method_holder()->class_loader();
} else {
ShouldNotReachHere();
}
}
// Add a reference to the loader to ensure the metadata is kept alive
mname->obj_field_put(_vmloader_offset, loader);
// Add a reference to the loader (actually mirror because anonymous classes will not have
// distinct loaders) to ensure the metadata is kept alive
// This mirror may be different than the one in clazz field.
mname->obj_field_put(_vmloader_offset, dependency);
}
intptr_t java_lang_invoke_MemberName::vmindex(oop mname) {
......@@ -2739,7 +2732,6 @@ oop java_security_AccessControlContext::create(objArrayHandle context, bool isPr
bool java_lang_ClassLoader::offsets_computed = false;
int java_lang_ClassLoader::_loader_data_offset = -1;
int java_lang_ClassLoader::_dependencies_offset = -1;
int java_lang_ClassLoader::parallelCapable_offset = -1;
ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) {
......@@ -2751,18 +2743,6 @@ ClassLoaderData* java_lang_ClassLoader::loader_data(oop loader) {
return *java_lang_ClassLoader::loader_data_addr(loader);
}
oop java_lang_ClassLoader::dependencies(oop loader) {
return loader->obj_field(_dependencies_offset);
}
HeapWord* java_lang_ClassLoader::dependencies_addr(oop loader) {
if (UseCompressedOops) {
return (HeapWord*)loader->obj_field_addr<narrowOop>(_dependencies_offset);
} else {
return (HeapWord*)loader->obj_field_addr<oop>(_dependencies_offset);
}
}
void java_lang_ClassLoader::compute_offsets() {
assert(!offsets_computed, "offsets should be initialized only once");
offsets_computed = true;
......
......@@ -1125,8 +1125,7 @@ class java_security_AccessControlContext: AllStatic {
// Interface to java.lang.ClassLoader objects
#define CLASSLOADER_INJECTED_FIELDS(macro) \
macro(java_lang_ClassLoader, loader_data, intptr_signature, false) \
macro(java_lang_ClassLoader, dependencies, object_signature, false)
macro(java_lang_ClassLoader, loader_data, intptr_signature, false)
class java_lang_ClassLoader : AllStatic {
private:
......@@ -1135,7 +1134,6 @@ class java_lang_ClassLoader : AllStatic {
hc_parent_offset = 0
};
static int _loader_data_offset;
static int _dependencies_offset;
static bool offsets_computed;
static int parent_offset;
static int parallelCapable_offset;
......@@ -1146,9 +1144,6 @@ class java_lang_ClassLoader : AllStatic {
static ClassLoaderData** loader_data_addr(oop loader);
static ClassLoaderData* loader_data(oop loader);
static oop dependencies(oop loader);
static HeapWord* dependencies_addr(oop loader);
static oop parent(oop loader);
static bool isAncestor(oop loader, oop cl);
......
......@@ -118,7 +118,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
probe->name()->as_C_string());
for (int i = 0; i < probe->num_loaders(); i++) {
tty->print_cr("[ [%d]: %s", i,
SystemDictionary::loader_name(probe->loader_data(i)));
probe->loader_data(i)->loader_name());
}
}
}
......@@ -129,7 +129,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
if (TraceLoaderConstraints) {
ResourceMark rm;
tty->print_cr("[Purging loader %s from constraint for name %s",
SystemDictionary::loader_name(probe->loader_data(n)),
probe->loader_data(n)->loader_name(),
probe->name()->as_C_string()
);
}
......@@ -145,7 +145,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
tty->print_cr("[New loader list:");
for (int i = 0; i < probe->num_loaders(); i++) {
tty->print_cr("[ [%d]: %s", i,
SystemDictionary::loader_name(probe->loader_data(i)));
probe->loader_data(i)->loader_name());
}
}
......@@ -400,7 +400,7 @@ void LoaderConstraintTable::merge_loader_constraints(
for (int i = 0; i < p1->num_loaders(); i++) {
tty->print_cr("[ [%d]: %s", i,
SystemDictionary::loader_name(p1->loader_data(i)));
p1->loader_data(i)->loader_name());
}
if (p1->klass() == NULL) {
tty->print_cr("[... and setting class object]");
......
......@@ -106,9 +106,9 @@ void SystemDictionary::compute_java_system_loader(TRAPS) {
}
ClassLoaderData* SystemDictionary::register_loader(Handle class_loader) {
ClassLoaderData* SystemDictionary::register_loader(Handle class_loader, TRAPS) {
if (class_loader() == NULL) return ClassLoaderData::the_null_class_loader_data();
return ClassLoaderDataGraph::find_or_create(class_loader);
return ClassLoaderDataGraph::find_or_create(class_loader, CHECK_NULL);
}
// ----------------------------------------------------------------------------
......@@ -591,7 +591,7 @@ Klass* SystemDictionary::resolve_instance_class_or_null(Symbol* name, Handle cla
// UseNewReflection
// Fix for 4474172; see evaluation for more details
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
ClassLoaderData *loader_data = register_loader(class_loader);
ClassLoaderData *loader_data = register_loader(class_loader, CHECK_NULL);
// Do lookup to see if class already exist and the protection domain
// has the right access
......@@ -888,7 +888,7 @@ Klass* SystemDictionary::find(Symbol* class_name,
// of the call to resolve_instance_class_or_null().
// See evaluation 6790209 and 4474172 for more details.
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader()));
ClassLoaderData* loader_data = register_loader(class_loader);
ClassLoaderData* loader_data = register_loader(class_loader, CHECK_NULL);
unsigned int d_hash = dictionary()->compute_hash(class_name, loader_data);
int d_index = dictionary()->hash_to_index(d_hash);
......@@ -948,6 +948,18 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
TRAPS) {
TempNewSymbol parsed_name = NULL;
ClassLoaderData* loader_data;
if (host_klass.not_null()) {
// Create a new CLD for anonymous class, that uses the same class loader
// as the host_klass
assert(EnableInvokeDynamic, "");
guarantee(host_klass->class_loader() == class_loader(), "should be the same");
loader_data = ClassLoaderData::anonymous_class_loader_data(class_loader(), CHECK_NULL);
loader_data->record_dependency(host_klass(), CHECK_NULL);
} else {
loader_data = ClassLoaderData::class_loader_data(class_loader());
}
// Parse the stream. Note that we do this even though this klass might
// already be present in the SystemDictionary, otherwise we would not
// throw potential ClassFormatErrors.
......@@ -959,7 +971,7 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
// java.lang.Object through resolve_or_fail, not this path.
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
class_loader,
loader_data,
protection_domain,
host_klass,
cp_patches,
......@@ -973,8 +985,6 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
// Parsed name could be null if we threw an error before we got far
// enough along to parse it -- in that case, there is nothing to clean up.
if (parsed_name != NULL) {
ClassLoaderData* loader_data = class_loader_data(class_loader);
unsigned int p_hash = placeholders()->compute_hash(parsed_name,
loader_data);
int p_index = placeholders()->hash_to_index(p_hash);
......@@ -987,9 +997,8 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
if (host_klass.not_null() && k.not_null()) {
assert(EnableInvokeDynamic, "");
// If it's anonymous, initialize it now, since nobody else will.
k->class_loader_data()->record_dependency(host_klass(), CHECK_NULL);
k->set_host_klass(host_klass());
// If it's anonymous, initialize it now, since nobody else will.
{
MutexLocker mu_r(Compile_lock, THREAD);
......@@ -1002,11 +1011,11 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
}
// Rewrite and patch constant pool here.
k->link_class(THREAD);
k->link_class(CHECK_NULL);
if (cp_patches != NULL) {
k->constants()->patch_resolved_references(cp_patches);
}
k->eager_initialize(THREAD);
k->eager_initialize(CHECK_NULL);
// notify jvmti
if (JvmtiExport::should_post_class_load()) {
......@@ -1039,7 +1048,7 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
DoObjectLock = false;
}
ClassLoaderData* loader_data = register_loader(class_loader);
ClassLoaderData* loader_data = register_loader(class_loader, CHECK_NULL);
// Make sure we are synchronized on the class loader before we proceed
Handle lockObject = compute_loader_lock_object(class_loader, THREAD);
......@@ -1059,7 +1068,7 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
// java.lang.Object through resolve_or_fail, not this path.
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
class_loader,
loader_data,
protection_domain,
parsed_name,
verify,
......@@ -2343,6 +2352,7 @@ methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid
// Helper for unpacking the return value from linkMethod and linkCallSite.
static methodHandle unpack_method_and_appendix(Handle mname,
KlassHandle accessing_klass,
objArrayHandle appendix_box,
Handle* appendix_result,
TRAPS) {
......@@ -2361,6 +2371,12 @@ static methodHandle unpack_method_and_appendix(Handle mname,
#endif //PRODUCT
}
(*appendix_result) = Handle(THREAD, appendix);
// the target is stored in the cpCache and if a reference to this
// MethodName is dropped we need a way to make sure the
// class_loader containing this method is kept alive.
// FIXME: the appendix might also preserve this dependency.
ClassLoaderData* this_key = InstanceKlass::cast(accessing_klass())->class_loader_data();
this_key->record_dependency(m->method_holder(), CHECK_NULL); // Can throw OOM
return methodHandle(THREAD, m);
}
}
......@@ -2405,7 +2421,7 @@ methodHandle SystemDictionary::find_method_handle_invoker(Symbol* name,
&args, CHECK_(empty));
Handle mname(THREAD, (oop) result.get_jobject());
(*method_type_result) = method_type;
return unpack_method_and_appendix(mname, appendix_box, appendix_result, THREAD);
return unpack_method_and_appendix(mname, accessing_klass, appendix_box, appendix_result, THREAD);
}
......@@ -2596,7 +2612,7 @@ methodHandle SystemDictionary::find_dynamic_call_site_invoker(KlassHandle caller
&args, CHECK_(empty));
Handle mname(THREAD, (oop) result.get_jobject());
(*method_type_result) = method_type;
return unpack_method_and_appendix(mname, appendix_box, appendix_result, THREAD);
return unpack_method_and_appendix(mname, caller, appendix_box, appendix_result, THREAD);
}
// Since the identity hash code for symbols changes when the symbols are
......
......@@ -471,7 +471,7 @@ public:
static void compute_java_system_loader(TRAPS);
// Register a new class loader
static ClassLoaderData* register_loader(Handle class_loader);
static ClassLoaderData* register_loader(Handle class_loader, TRAPS);
private:
// Mirrors for primitive classes (created eagerly)
static oop check_mirror(oop m) {
......@@ -531,7 +531,7 @@ public:
InstanceKlass::cast((loader)->klass())->name()->as_C_string() );
}
static const char* loader_name(ClassLoaderData* loader_data) {
return (loader_data->is_the_null_class_loader_data() ? "<bootloader>" :
return (loader_data->class_loader() == NULL ? "<bootloader>" :
InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string() );
}
......
......@@ -269,10 +269,12 @@ void CompileTask::initialize(int compile_id,
const char* comment,
bool is_blocking) {
assert(!_lock->is_locked(), "bad locking");
InstanceKlass* holder = method->method_holder();
_compile_id = compile_id;
_method = method();
_method_loader = JNIHandles::make_global(_method->method_holder()->class_loader());
_method_holder = JNIHandles::make_global(
holder->is_anonymous() ? holder->java_mirror(): holder->class_loader());
_osr_bci = osr_bci;
_is_blocking = is_blocking;
_comp_level = comp_level;
......@@ -283,7 +285,7 @@ void CompileTask::initialize(int compile_id,
_code_handle = NULL;
_hot_method = NULL;
_hot_method_loader = NULL;
_hot_method_holder = NULL;
_hot_count = hot_count;
_time_queued = 0; // tidy
_comment = comment;
......@@ -295,8 +297,12 @@ void CompileTask::initialize(int compile_id,
_hot_method = _method;
} else {
_hot_method = hot_method();
// only add loader or mirror if different from _method_holder
InstanceKlass* hot_holder = hot_method->method_holder();
_hot_method_holder = JNIHandles::make_global(
hot_holder->is_anonymous() ? hot_holder->java_mirror() :
hot_holder->class_loader());
}
_hot_method_loader = JNIHandles::make_global(_hot_method->method_holder()->class_loader());
}
}
......@@ -321,8 +327,8 @@ void CompileTask::set_code(nmethod* nm) {
void CompileTask::free() {
set_code(NULL);
assert(!_lock->is_locked(), "Should not be locked when freed");
JNIHandles::destroy_global(_method_loader);
JNIHandles::destroy_global(_hot_method_loader);
JNIHandles::destroy_global(_method_holder);
JNIHandles::destroy_global(_hot_method_holder);
}
......
......@@ -43,7 +43,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
Monitor* _lock;
uint _compile_id;
Method* _method;
jobject _method_loader;
jobject _method_holder;
int _osr_bci;
bool _is_complete;
bool _is_success;
......@@ -56,7 +56,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
// Fields used for logging why the compilation was initiated:
jlong _time_queued; // in units of os::elapsed_counter()
Method* _hot_method; // which method actually triggered this task
jobject _hot_method_loader;
jobject _hot_method_holder;
int _hot_count; // information about its invocation counter
const char* _comment; // more info about the task
......
......@@ -123,9 +123,7 @@ class Metachunk VALUE_OBJ_CLASS_SPEC {
void assert_is_mangled() const {/* Don't check "\*/}
#ifdef ASSERT
void mangle();
#endif // ASSERT
NOT_PRODUCT(void mangle();)
void print_on(outputStream* st) const;
void verify();
......
......@@ -108,7 +108,6 @@ size_t Metablock::_min_block_byte_size = sizeof(Metablock);
size_t Metablock::_overhead = 0;
#endif
// Pointer to list of Metachunks.
class ChunkList VALUE_OBJ_CLASS_SPEC {
// List of free chunks
......@@ -325,10 +324,12 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
bool expand_by(size_t words, bool pre_touch = false);
bool shrink_by(size_t words);
#ifdef ASSERT
// Debug support
static void verify_virtual_space_total();
static void verify_virtual_space_count();
void mangle();
#endif
void print_on(outputStream* st) const;
};
......@@ -621,8 +622,8 @@ class SpaceManager : public CHeapObj<mtClass> {
void locked_print_chunks_in_use_on(outputStream* st) const;
void verify();
NOT_PRODUCT(void mangle_freed_chunks();)
#ifdef ASSERT
void mangle_freed_chunks();
void verify_allocation_total();
#endif
};
......@@ -711,7 +712,7 @@ void Metachunk::print_on(outputStream* st) const {
bottom(), top(), end(), word_size());
}
#ifdef ASSERT
#ifndef PRODUCT
void Metachunk::mangle() {
// Mangle the payload of the chunk and not the links that
// maintain list of chunks.
......@@ -719,7 +720,7 @@ void Metachunk::mangle() {
size_t word_size = capacity_word_size() - overhead();
Copy::fill_to_words(start, word_size, metadata_chunk_initialize);
}
#endif // ASSERT
#endif // PRODUCT
void Metachunk::verify() {
#ifdef ASSERT
......@@ -917,10 +918,12 @@ void VirtualSpaceNode::print_on(outputStream* st) const {
vs->high_boundary());
}
#ifdef ASSERT
void VirtualSpaceNode::mangle() {
size_t word_size = capacity_words_in_vs();
Copy::fill_to_words((HeapWord*) low(), word_size, 0xf1f1f1f1);
}
#endif // ASSERT
// VirtualSpaceList methods
// Space allocated from the VirtualSpace
......@@ -1985,16 +1988,14 @@ SpaceManager::~SpaceManager() {
locked_print_chunks_in_use_on(gclog_or_tty);
}
// Mangle freed memory.
NOT_PRODUCT(mangle_freed_chunks();)
// Have to update before the chunks_in_use lists are emptied
// below.
chunk_manager->inc_free_chunks_total(sum_capacity_in_chunks_in_use(),
sum_count_in_chunks_in_use());
#ifdef ASSERT
// Mangle freed memory.
mangle_freed_chunks();
#endif // ASSERT
// Add all the chunks in use by this space manager
// to the global list of free chunks.
......@@ -2273,7 +2274,7 @@ void SpaceManager::dump(outputStream* const out) const {
" waste " SIZE_FORMAT, curr_total, used, free, capacity, waste);
}
#ifdef ASSERT
#ifndef PRODUCT
void SpaceManager::mangle_freed_chunks() {
for (ChunkIndex index = SmallIndex;
index < NumberOfInUseLists;
......@@ -2291,11 +2292,16 @@ void SpaceManager::mangle_freed_chunks() {
}
}
}
#endif // ASSERT
#endif // PRODUCT
// MetaspaceAux
size_t MetaspaceAux::used_in_bytes() {
return (Metaspace::class_space_list()->used_words_sum() +
Metaspace::space_list()->used_words_sum()) * BytesPerWord;
}
size_t MetaspaceAux::used_in_bytes(Metaspace::MetadataType mdtype) {
size_t used = 0;
ClassLoaderDataGraphMetaspaceIterator iter;
......@@ -2324,6 +2330,11 @@ size_t MetaspaceAux::free_in_bytes(Metaspace::MetadataType mdtype) {
// The total words available for metadata allocation. This
// uses Metaspace capacity_words() which is the total words
// in chunks allocated for a Metaspace.
size_t MetaspaceAux::capacity_in_bytes() {
return (Metaspace::class_space_list()->capacity_words_sum() +
Metaspace::space_list()->capacity_words_sum()) * BytesPerWord;
}
size_t MetaspaceAux::capacity_in_bytes(Metaspace::MetadataType mdtype) {
size_t capacity = free_chunks_total(mdtype);
ClassLoaderDataGraphMetaspaceIterator iter;
......@@ -2336,6 +2347,11 @@ size_t MetaspaceAux::capacity_in_bytes(Metaspace::MetadataType mdtype) {
return capacity * BytesPerWord;
}
size_t MetaspaceAux::reserved_in_bytes() {
return (Metaspace::class_space_list()->virtual_space_total() +
Metaspace::space_list()->virtual_space_total()) * BytesPerWord;
}
size_t MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) {
size_t reserved = (mdtype == Metaspace::ClassType) ?
Metaspace::class_space_list()->virtual_space_total() :
......
......@@ -160,25 +160,16 @@ class MetaspaceAux : AllStatic {
public:
// Total of space allocated to metadata in all Metaspaces
static size_t used_in_bytes() {
return used_in_bytes(Metaspace::ClassType) +
used_in_bytes(Metaspace::NonClassType);
}
static size_t used_in_bytes();
// Total of available space in all Metaspaces
// Total of capacity allocated to all Metaspaces. This includes
// space in Metachunks not yet allocated and in the Metachunk
// freelist.
static size_t capacity_in_bytes() {
return capacity_in_bytes(Metaspace::ClassType) +
capacity_in_bytes(Metaspace::NonClassType);
}
static size_t capacity_in_bytes();
// Total space reserved in all Metaspaces
static size_t reserved_in_bytes() {
return reserved_in_bytes(Metaspace::ClassType) +
reserved_in_bytes(Metaspace::NonClassType);
}
static size_t reserved_in_bytes();
static size_t min_chunk_size();
......
......@@ -407,6 +407,10 @@ void Universe::genesis(TRAPS) {
assert(i == _fullgc_alot_dummy_array->length(), "just checking");
}
#endif
// Initialize dependency array for null class loader
ClassLoaderData::the_null_class_loader_data()->init_dependencies(CHECK);
}
// CDS support for patching vtables in metadata in the shared archive.
......
......@@ -340,9 +340,7 @@ Klass* ConstantPool::klass_at_impl(constantPoolHandle this_oop, int which, TRAPS
do_resolve = this_oop->tag_at(which).is_unresolved_klass();
if (do_resolve) {
ClassLoaderData* this_key = this_oop->pool_holder()->class_loader_data();
if (!this_key->is_the_null_class_loader_data()) {
this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM
}
this_key->record_dependency(k(), CHECK_NULL); // Can throw OOM
this_oop->klass_at_put(which, k());
}
}
......
......@@ -373,29 +373,22 @@ void Klass::append_to_sibling_list() {
debug_only(verify();)
}
void Klass::remove_from_sibling_list() {
// remove receiver from sibling list
InstanceKlass* super = superklass();
assert(super != NULL || this == SystemDictionary::Object_klass(), "should have super");
if (super == NULL) return; // special case: class Object
if (super->subklass() == this) {
// first subklass
super->set_subklass(_next_sibling);
} else {
Klass* sib = super->subklass();
while (sib->next_sibling() != this) {
sib = sib->next_sibling();
};
sib->set_next_sibling(_next_sibling);
}
}
bool Klass::is_loader_alive(BoolObjectClosure* is_alive) {
assert(is_metadata(), "p is not meta-data");
assert(ClassLoaderDataGraph::contains((address)this), "is in the metaspace");
#ifdef ASSERT
// The class is alive iff the class loader is alive.
oop loader = class_loader();
return (loader == NULL) || is_alive->do_object_b(loader);
bool loader_alive = (loader == NULL) || is_alive->do_object_b(loader);
#endif // ASSERT
// The class is alive if it's mirror is alive (which should be marked if the
// loader is alive) unless it's an anoymous class.
bool mirror_alive = is_alive->do_object_b(java_mirror());
assert(!mirror_alive || loader_alive, "loader must be alive if the mirror is"
" but not the other way around with anonymous classes");
return mirror_alive;
}
void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) {
......@@ -416,10 +409,10 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) {
Klass* sub = current->subklass_oop();
while (sub != NULL && !sub->is_loader_alive(is_alive)) {
#ifndef PRODUCT
if (TraceClassUnloading && WizardMode) {
ResourceMark rm;
if (TraceClassUnloading && WizardMode) {
ResourceMark rm;
tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name());
}
}
#endif
sub = sub->next_sibling_oop();
}
......@@ -431,16 +424,16 @@ void Klass::clean_weak_klass_links(BoolObjectClosure* is_alive) {
// Find and set the first alive sibling
Klass* sibling = current->next_sibling_oop();
while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
if (TraceClassUnloading && WizardMode) {
ResourceMark rm;
if (TraceClassUnloading && WizardMode) {
ResourceMark rm;
tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name());
}
sibling = sibling->next_sibling_oop();
}
sibling = sibling->next_sibling_oop();
}
current->set_next_sibling(sibling);
if (sibling != NULL) {
stack.push(sibling);
}
}
// Clean the implementors list and method data.
if (current->oop_is_instance()) {
......@@ -554,7 +547,11 @@ const char* Klass::external_name() const {
InstanceKlass* ik = (InstanceKlass*) this;
if (ik->is_anonymous()) {
assert(EnableInvokeDynamic, "");
intptr_t hash = ik->java_mirror()->identity_hash();
intptr_t hash = 0;
if (ik->java_mirror() != NULL) {
// java_mirror might not be created yet, return 0 as hash.
hash = ik->java_mirror()->identity_hash();
}
char hash_buf[40];
sprintf(hash_buf, "/" UINTX_FORMAT, (uintx)hash);
size_t hash_len = strlen(hash_buf);
......
......@@ -267,7 +267,6 @@ class Klass : public Metadata {
Klass* subklass() const;
Klass* next_sibling() const;
void append_to_sibling_list(); // add newly created receiver to superklass' subklass list
void remove_from_sibling_list(); // remove receiver from sibling list
void set_next_link(Klass* k) { _next_link = k; }
Klass* next_link() const { return _next_link; } // The next klass defined by the class loader.
......@@ -581,8 +580,8 @@ class Klass : public Metadata {
// garbage collection support
virtual void oops_do(OopClosure* cl);
// Checks if the class loader is alive.
// Iff the class loader is alive the Klass is considered alive.
// Iff the class loader (or mirror for anonymous classes) is alive the
// Klass is considered alive.
// The is_alive closure passed in depends on the Garbage Collector used.
bool is_loader_alive(BoolObjectClosure* is_alive);
......
......@@ -88,11 +88,6 @@ Klass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data,
}
if (!supers_exist) {
// Oops. Not allocated yet. Back out, allocate it, and retry.
#ifndef PRODUCT
if (WizardMode) {
tty->print_cr("Must retry array klass creation for depth %d",n);
}
#endif
KlassHandle ek;
{
MutexUnlocker mu(MultiArray_lock);
......
......@@ -996,7 +996,7 @@ UNSAFE_END
// not just a literal string. For such ldc instructions, the verifier uses the
// type Object instead of String, if the loaded constant is not in fact a String.
static oop
static instanceKlassHandle
Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
jclass host_class, jbyteArray data, jobjectArray cp_patches_jh,
HeapWord* *temp_alloc,
......@@ -1073,32 +1073,39 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
anon_klass = instanceKlassHandle(THREAD, anonk);
}
// let caller initialize it as needed...
return anon_klass->java_mirror();
return anon_klass;
}
UNSAFE_ENTRY(jclass, Unsafe_DefineAnonymousClass(JNIEnv *env, jobject unsafe, jclass host_class, jbyteArray data, jobjectArray cp_patches_jh))
{
instanceKlassHandle anon_klass;
jobject res_jh = NULL;
UnsafeWrapper("Unsafe_DefineAnonymousClass");
ResourceMark rm(THREAD);
HeapWord* temp_alloc = NULL;
jobject res_jh = NULL;
{ oop res_oop = Unsafe_DefineAnonymousClass_impl(env,
host_class, data, cp_patches_jh,
anon_klass = Unsafe_DefineAnonymousClass_impl(env, host_class, data,
cp_patches_jh,
&temp_alloc, THREAD);
if (res_oop != NULL)
res_jh = JNIHandles::make_local(env, res_oop);
}
if (anon_klass() != NULL)
res_jh = JNIHandles::make_local(env, anon_klass->java_mirror());
// try/finally clause:
if (temp_alloc != NULL) {
FREE_C_HEAP_ARRAY(HeapWord, temp_alloc, mtInternal);
}
// The anonymous class loader data has been artificially been kept alive to
// this point. The mirror and any instances of this class have to keep
// it alive afterwards.
if (anon_klass() != NULL) {
anon_klass->class_loader_data()->set_keep_alive(false);
}
// let caller initialize it as needed...
return (jclass) res_jh;
}
UNSAFE_END
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册