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

Add ClassLoaderData object for each anonymous class with metaspaces to allocate in.

Reviewed-by: twisti, jrose, stefank
This commit is contained in:
Coleen Phillimore 2012-11-29 16:50:29 -05:00
parent c00c803b89
commit 7aa43fc5d8
26 changed files with 365 additions and 249 deletions

View File

@ -492,6 +492,26 @@ void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
dest->verify_section_allocation(); 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) { void CodeBuffer::finalize_oop_references(methodHandle mh) {
No_Safepoint_Verifier nsv; No_Safepoint_Verifier nsv;
@ -509,7 +529,6 @@ void CodeBuffer::finalize_oop_references(methodHandle mh) {
if (md->metadata_is_immediate()) { if (md->metadata_is_immediate()) {
Metadata* m = md->metadata_value(); Metadata* m = md->metadata_value();
if (oop_recorder()->is_real(m)) { if (oop_recorder()->is_real(m)) {
oop o = NULL;
if (m->is_methodData()) { if (m->is_methodData()) {
m = ((MethodData*)m)->method(); m = ((MethodData*)m)->method();
} }
@ -517,16 +536,13 @@ void CodeBuffer::finalize_oop_references(methodHandle mh) {
m = ((Method*)m)->method_holder(); m = ((Method*)m)->method_holder();
} }
if (m->is_klass()) { if (m->is_klass()) {
o = ((Klass*)m)->class_loader(); append_oop_references(&oops, (Klass*)m);
} else { } else {
// XXX This will currently occur for MDO which don't // XXX This will currently occur for MDO which don't
// have a backpointer. This has to be fixed later. // have a backpointer. This has to be fixed later.
m->print(); m->print();
ShouldNotReachHere(); 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++) { for (int i = 0; i < oop_recorder()->metadata_count(); i++) {
Metadata* m = oop_recorder()->metadata_at(i); Metadata* m = oop_recorder()->metadata_at(i);
if (oop_recorder()->is_real(m)) { if (oop_recorder()->is_real(m)) {
oop o = NULL;
if (m->is_methodData()) { if (m->is_methodData()) {
m = ((MethodData*)m)->method(); m = ((MethodData*)m)->method();
} }
@ -545,24 +560,18 @@ void CodeBuffer::finalize_oop_references(methodHandle mh) {
m = ((Method*)m)->method_holder(); m = ((Method*)m)->method_holder();
} }
if (m->is_klass()) { if (m->is_klass()) {
o = ((Klass*)m)->class_loader(); append_oop_references(&oops, (Klass*)m);
} else { } else {
m->print(); m->print();
ShouldNotReachHere(); ShouldNotReachHere();
} }
if (o != NULL && oops.find(o) == -1) {
oops.append(o);
}
} }
} }
} }
// Add the class loader of Method* for the nmethod itself // Add the class loader of Method* for the nmethod itself
oop cl = mh->method_holder()->class_loader(); append_oop_references(&oops, mh->method_holder());
if (cl != NULL) {
oops.append(cl);
}
// Add any oops that we've found // Add any oops that we've found
Thread* thread = Thread::current(); Thread* thread = Thread::current();

View File

@ -31,7 +31,7 @@
#include "memory/resourceArea.hpp" #include "memory/resourceArea.hpp"
#include "utilities/copy.hpp" #include "utilities/copy.hpp"
#ifdef ASSERT #ifndef PRODUCT
// ciReplay // ciReplay
@ -939,4 +939,4 @@ bool ciReplay::is_loaded(Method* method) {
ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); ciMethodRecord* rec = replay_state->find_ciMethodRecord(method);
return rec != NULL; return rec != NULL;
} }
#endif #endif // PRODUCT

View File

@ -32,7 +32,7 @@
class ciReplay { class ciReplay {
CI_PACKAGE_ACCESS CI_PACKAGE_ACCESS
#ifdef ASSERT #ifndef PRODUCT
private: private:
static int replay_impl(TRAPS); static int replay_impl(TRAPS);

View File

@ -2950,7 +2950,7 @@ static void parseAndPrintGenericSignatures(
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
Handle class_loader, ClassLoaderData* loader_data,
Handle protection_domain, Handle protection_domain,
KlassHandle host_klass, KlassHandle host_klass,
GrowableArray<Handle>* cp_patches, GrowableArray<Handle>* cp_patches,
@ -2964,7 +2964,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
// original class bytes. // original class bytes.
unsigned char *cached_class_file_bytes = NULL; unsigned char *cached_class_file_bytes = NULL;
jint cached_class_file_length; 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; bool has_default_methods = false;
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
@ -3005,7 +3005,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
unsigned char* ptr = cfs->buffer(); unsigned char* ptr = cfs->buffer();
unsigned char* end_ptr = cfs->buffer() + cfs->length(); 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, &ptr, &end_ptr,
&cached_class_file_bytes, &cached_class_file_bytes,
&cached_class_file_length); &cached_class_file_length);
@ -4004,8 +4004,7 @@ void ClassFileParser::set_precomputed_flags(instanceKlassHandle k) {
assert(k->size_helper() > 0, "layout_helper is initialized"); assert(k->size_helper() > 0, "layout_helper is initialized");
if ((!RegisterFinalizersAtInit && k->has_finalizer()) if ((!RegisterFinalizersAtInit && k->has_finalizer())
|| k->is_abstract() || k->is_interface() || k->is_abstract() || k->is_interface()
|| (k->name() == vmSymbols::java_lang_Class() || (k->name() == vmSymbols::java_lang_Class() && k->class_loader() == NULL)
&& k->class_loader_data()->is_the_null_class_loader_data())
|| k->size_helper() >= FastAllocateSizeLimit) { || k->size_helper() >= FastAllocateSizeLimit) {
// Forbid fast-path allocation. // Forbid fast-path allocation.
jint lh = Klass::instance_layout_helper(k->size_helper(), true); jint lh = Klass::instance_layout_helper(k->size_helper(), true);

View File

@ -363,16 +363,16 @@ class ClassFileParser VALUE_OBJ_CLASS_SPEC {
// "parsed_name" is updated by this method, and is the name found // "parsed_name" is updated by this method, and is the name found
// while parsing the stream. // while parsing the stream.
instanceKlassHandle parseClassFile(Symbol* name, instanceKlassHandle parseClassFile(Symbol* name,
Handle class_loader, ClassLoaderData* loader_data,
Handle protection_domain, Handle protection_domain,
TempNewSymbol& parsed_name, TempNewSymbol& parsed_name,
bool verify, bool verify,
TRAPS) { TRAPS) {
KlassHandle no_host_klass; 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, instanceKlassHandle parseClassFile(Symbol* name,
Handle class_loader, ClassLoaderData* loader_data,
Handle protection_domain, Handle protection_domain,
KlassHandle host_klass, KlassHandle host_klass,
GrowableArray<Handle>* cp_patches, GrowableArray<Handle>* cp_patches,

View File

@ -26,6 +26,7 @@
#include "classfile/classFileParser.hpp" #include "classfile/classFileParser.hpp"
#include "classfile/classFileStream.hpp" #include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp" #include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.hpp" #include "classfile/javaClasses.hpp"
#include "classfile/systemDictionary.hpp" #include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp" #include "classfile/vmSymbols.hpp"
@ -910,11 +911,11 @@ instanceKlassHandle ClassLoader::load_classfile(Symbol* h_name, TRAPS) {
// class file found, parse it // class file found, parse it
ClassFileParser parser(stream); ClassFileParser parser(stream);
Handle class_loader; ClassLoaderData* loader_data = ClassLoaderData::the_null_class_loader_data();
Handle protection_domain; Handle protection_domain;
TempNewSymbol parsed_name = NULL; TempNewSymbol parsed_name = NULL;
instanceKlassHandle result = parser.parseClassFile(h_name, instanceKlassHandle result = parser.parseClassFile(h_name,
class_loader, loader_data,
protection_domain, protection_domain,
parsed_name, parsed_name,
false, false,

View File

@ -65,13 +65,19 @@
ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL; ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
ClassLoaderData::ClassLoaderData(Handle h_class_loader) : _class_loader(h_class_loader()), ClassLoaderData::ClassLoaderData(Handle h_class_loader) : _class_loader(h_class_loader()),
_metaspace(NULL), _unloading(false), _klasses(NULL), _metaspace(NULL), _unloading(false), _keep_alive(false), _klasses(NULL),
_claimed(0), _jmethod_ids(NULL), _handles(NULL), _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL),
_deallocate_list(NULL), _next(NULL), _next(NULL), _dependencies(NULL),
_metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) {
// empty // 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() { bool ClassLoaderData::claim() {
if (_claimed == 1) { if (_claimed == 1) {
return false; 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(&_class_loader);
f->do_oop(&_dependencies);
_handles->oops_do(f); _handles->oops_do(f);
if (klass_closure != NULL) { if (klass_closure != NULL) {
classes_do(klass_closure); classes_do(klass_closure);
@ -110,69 +117,99 @@ void ClassLoaderData::record_dependency(Klass* k, TRAPS) {
ClassLoaderData * const from_cld = this; ClassLoaderData * const from_cld = this;
ClassLoaderData * const to_cld = k->class_loader_data(); ClassLoaderData * const to_cld = k->class_loader_data();
// Records dependency between non-null class loaders only. // Dependency to the null class loader data doesn't need to be recorded
if (to_cld->is_the_null_class_loader_data() || from_cld->is_the_null_class_loader_data()) { // because the null class loader data never goes away.
if (to_cld->is_the_null_class_loader_data()) {
return; return;
} }
// Check that this dependency isn't from the same or parent class_loader oop to;
oop to = to_cld->class_loader(); if (to_cld->is_anonymous()) {
oop from = from_cld->class_loader(); // Anonymous class dependencies are through the mirror.
to = k->java_mirror();
} else {
to = to_cld->class_loader();
oop curr = from; // If from_cld is anonymous, even if it's class_loader is a parent of 'to'
while (curr != NULL) { // we still have to add it. The class_loader won't keep from_cld alive.
if (curr == to) { if (!from_cld->is_anonymous()) {
return; // this class loader is in the parent list, no need to add it. // 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 // 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 void ClassLoaderData::add_dependency(Handle dependency, TRAPS) {
// is there. Don't safepoint! These are all oops. // Check first if this dependency is already in the list.
// Dependency list is (oop class_loader, objArrayOop next) // Save a pointer to the last to add to under the lock.
objArrayOop ok = (objArrayOop)java_lang_ClassLoader::dependencies(class_loader()); objArrayOop ok = (objArrayOop)_dependencies;
objArrayOop last = NULL;
while (ok != NULL) { while (ok != NULL) {
if (ok->obj_at(0) == loader) { last = ok;
return true; if (ok->obj_at(0) == dependency()) {
// Don't need to add it
return;
} }
ok = (objArrayOop)ok->obj_at(1); ok = (objArrayOop)ok->obj_at(1);
} }
return false;
}
void ClassLoaderData::add_dependency(ClassLoaderData* dependency, TRAPS) { // Create a new dependency node with fields for (class_loader or mirror, next)
// Minimize the number of duplicates in the list.
if (has_dependency(dependency)) {
return;
}
// Create a new dependency node with fields for (class_loader, next)
objArrayOop deps = oopFactory::new_objectArray(2, CHECK); objArrayOop deps = oopFactory::new_objectArray(2, CHECK);
deps->obj_at_put(0, dependency->class_loader()); deps->obj_at_put(0, dependency());
// Add this lock free, using compare and exchange, need barriers for GC // Must handle over more GC points
// Do the barrier first. objArrayHandle new_dependency(THREAD, deps);
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); // Add the dependency under lock
if (newold == old_dependency) { assert (last != NULL, "dependencies should be initialized");
update_barrier_set((void*)addr, (oop)deps); objArrayHandle last_handle(THREAD, last);
// we won the race to add this dependency locked_add_dependency(last_handle, new_dependency);
break;
}
}
} }
void ClassLoaderData::locked_add_dependency(objArrayHandle last_handle,
objArrayHandle new_dependency) {
// 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() { void ClassLoaderDataGraph::clear_claimed_marks() {
for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) { for (ClassLoaderData* cld = _head; cld != NULL; cld = cld->next()) {
@ -187,7 +224,7 @@ void ClassLoaderData::add_class(Klass* k) {
// link the new item into the list // link the new item into the list
_klasses = k; _klasses = k;
if (TraceClassLoaderData && k->class_loader_data() != NULL) { if (TraceClassLoaderData && Verbose && k->class_loader_data() != NULL) {
ResourceMark rm; ResourceMark rm;
tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: " tty->print_cr("[TraceClassLoaderData] Adding k: " PTR_FORMAT " %s to CLD: "
PTR_FORMAT " loader: " PTR_FORMAT " %s", PTR_FORMAT " loader: " PTR_FORMAT " %s",
@ -195,8 +232,7 @@ void ClassLoaderData::add_class(Klass* k) {
k->external_name(), k->external_name(),
k->class_loader_data(), k->class_loader_data(),
k->class_loader(), 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!! 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() { ClassLoaderData::~ClassLoaderData() {
Metaspace *m = _metaspace; Metaspace *m = _metaspace;
if (m != NULL) { if (m != NULL) {
@ -263,8 +331,8 @@ Metaspace* ClassLoaderData::metaspace_non_null() {
if (_metaspace != NULL) { if (_metaspace != NULL) {
return _metaspace; return _metaspace;
} }
if (class_loader() == NULL) { if (this == the_null_class_loader_data()) {
assert(this == the_null_class_loader_data(), "Must be"); assert (class_loader() == NULL, "Must be");
size_t word_size = Metaspace::first_chunk_word_size(); size_t word_size = Metaspace::first_chunk_word_size();
set_metaspace(new Metaspace(_metaspace_lock, word_size)); set_metaspace(new Metaspace(_metaspace_lock, word_size));
} else { } else {
@ -325,12 +393,19 @@ void ClassLoaderData::free_deallocate_list() {
} }
} }
#ifndef PRODUCT // These anonymous class loaders are to contain classes used for JSR292
void ClassLoaderData::print_loader(ClassLoaderData *loader_data, outputStream* out) { ClassLoaderData* ClassLoaderData::anonymous_class_loader_data(oop loader, TRAPS) {
oop class_loader = loader_data->class_loader(); // Add a new class loader data to the graph.
out->print("%s", SystemDictionary::loader_name(class_loader)); 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 // Define to dump klasses
#undef CLD_DUMP_KLASSES #undef CLD_DUMP_KLASSES
@ -338,8 +413,7 @@ void ClassLoaderData::dump(outputStream * const out) {
ResourceMark rm; ResourceMark rm;
out->print("ClassLoaderData CLD: "PTR_FORMAT", loader: "PTR_FORMAT", loader_klass: "PTR_FORMAT" %s {", out->print("ClassLoaderData CLD: "PTR_FORMAT", loader: "PTR_FORMAT", loader_klass: "PTR_FORMAT" %s {",
this, class_loader(), this, class_loader(),
class_loader() != NULL ? class_loader()->klass() : NULL, class_loader() != NULL ? class_loader()->klass() : NULL, loader_name());
class_loader() != NULL ? class_loader()->klass()->external_name() : "NULL");
if (claimed()) out->print(" claimed "); if (claimed()) out->print(" claimed ");
if (is_unloading()) out->print(" unloading "); if (is_unloading()) out->print(" unloading ");
out->print(" handles " INTPTR_FORMAT, handles()); out->print(" handles " INTPTR_FORMAT, handles());
@ -373,8 +447,8 @@ void ClassLoaderData::dump(outputStream * const out) {
void ClassLoaderData::verify() { void ClassLoaderData::verify() {
oop cl = class_loader(); oop cl = class_loader();
guarantee(this == class_loader_data(cl), "Must be the same"); guarantee(this == class_loader_data(cl) || is_anonymous(), "Must be the same");
guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data(), "must be"); guarantee(cl != NULL || this == ClassLoaderData::the_null_class_loader_data() || is_anonymous(), "must be");
// Verify the integrity of the allocated space. // Verify the integrity of the allocated space.
if (metaspace_or_null() != NULL) { if (metaspace_or_null() != NULL) {
@ -387,6 +461,7 @@ void ClassLoaderData::verify() {
} }
} }
// GC root of class loader data created. // GC root of class loader data created.
ClassLoaderData* ClassLoaderDataGraph::_head = NULL; ClassLoaderData* ClassLoaderDataGraph::_head = NULL;
ClassLoaderData* ClassLoaderDataGraph::_unloading = 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 // 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 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. // Not assigned a class loader data yet.
// Create one. // Create one.
ClassLoaderData* *list_head = &_head; ClassLoaderData* *list_head = &_head;
ClassLoaderData* next = _head; ClassLoaderData* next = _head;
ClassLoaderData* cld = new ClassLoaderData(loader_data); ClassLoaderData* cld = new ClassLoaderData(loader);
// First, Atomically set it. if (cld_addr != NULL) {
ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL); // First, Atomically set it
if (old != NULL) { ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL);
delete cld; if (old != NULL) {
// Returns the data. delete cld;
return old; // 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 // 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); ClassLoaderData* exchanged = (ClassLoaderData*)Atomic::cmpxchg_ptr(cld, list_head, next);
if (exchanged == next) { if (exchanged == next) {
if (TraceClassLoaderData) { if (TraceClassLoaderData) {
ResourceMark rm;
tty->print("[ClassLoaderData: "); tty->print("[ClassLoaderData: ");
tty->print("create class loader data "PTR_FORMAT, cld); tty->print("create class loader data "PTR_FORMAT, cld);
tty->print(" for instance "PTR_FORMAT" of ", cld->class_loader()); tty->print(" for instance "PTR_FORMAT" of %s", cld->class_loader(),
loader_data->klass()->name()->print_symbol_on(tty); cld->loader_name());
tty->print_cr("]"); 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; return cld;
} }
next = exchanged; next = exchanged;
} while (true); } while (true);
} }
void ClassLoaderDataGraph::oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) { 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) { void ClassLoaderDataGraph::always_strong_oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim) {
if (ClassUnloading) { if (ClassUnloading) {
ClassLoaderData::the_null_class_loader_data()->oops_do(f, klass_closure, must_claim); 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 { } else {
ClassLoaderDataGraph::oops_do(f, klass_closure, must_claim); ClassLoaderDataGraph::oops_do(f, klass_closure, must_claim);
} }
@ -516,9 +613,10 @@ bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) {
} }
#endif // PRODUCT #endif // PRODUCT
// Move class loader data from main list to the unloaded list for unloading // Move class loader data from main list to the unloaded list for unloading
// and deallocation later. // and deallocation later.
bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive) { bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure) {
ClassLoaderData* data = _head; ClassLoaderData* data = _head;
ClassLoaderData* prev = NULL; ClassLoaderData* prev = NULL;
bool seen_dead_loader = false; 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(); bool has_redefined_a_class = JvmtiExport::has_redefined_a_class();
MetadataOnStackMark md_on_stack; MetadataOnStackMark md_on_stack;
while (data != NULL) { while (data != NULL) {
if (data->class_loader() == NULL || is_alive->do_object_b(data->class_loader())) { if (data->keep_alive() || data->is_alive(is_alive_closure)) {
assert(data->claimed(), "class loader data must have been claimed");
if (has_redefined_a_class) { if (has_redefined_a_class) {
data->classes_do(InstanceKlass::purge_previous_versions); data->classes_do(InstanceKlass::purge_previous_versions);
} }
@ -539,13 +636,7 @@ bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive) {
} }
seen_dead_loader = true; seen_dead_loader = true;
ClassLoaderData* dead = data; ClassLoaderData* dead = data;
dead->mark_for_unload(); dead->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("]");
}
data = data->next(); data = data->next();
// Remove from loader list. // Remove from loader list.
if (prev != NULL) { if (prev != NULL) {

View File

@ -62,13 +62,14 @@ class ClassLoaderDataGraph : public AllStatic {
// CMS support. // CMS support.
static ClassLoaderData* _saved_head; 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: public:
static ClassLoaderData* find_or_create(Handle class_loader); static ClassLoaderData* find_or_create(Handle class_loader, TRAPS);
static void purge(); static void purge();
static void clear_claimed_marks(); static void clear_claimed_marks();
static void oops_do(OopClosure* f, KlassClosure* klass_closure, bool must_claim); 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 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 void classes_do(KlassClosure* klass_closure);
static bool do_unloading(BoolObjectClosure* is_alive); 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 oop _class_loader; // oop used to uniquely identify a class loader
// class loader or a canonical class path // 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 Metaspace * _metaspace; // Meta-space where meta-data defined by the
// classes in the class loader are allocated. // classes in the class loader are allocated.
Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup. Mutex* _metaspace_lock; // Locks the metaspace for allocations and setup.
bool _unloading; // true if this class loader goes away 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. volatile int _claimed; // true if claimed, for example during GC traces.
// To avoid applying oop closure more than once. // To avoid applying oop closure more than once.
// Has to be an int because we cas it. // Has to be an int because we cas it.
@ -129,8 +133,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
static Metaspace* _ro_metaspace; static Metaspace* _ro_metaspace;
static Metaspace* _rw_metaspace; static Metaspace* _rw_metaspace;
bool has_dependency(ClassLoaderData* cld); void add_dependency(Handle dependency, TRAPS);
void add_dependency(ClassLoaderData* to_loader_data, TRAPS); void locked_add_dependency(objArrayHandle last, objArrayHandle new_dependency);
void set_next(ClassLoaderData* next) { _next = next; } void set_next(ClassLoaderData* next) { _next = next; }
ClassLoaderData* next() const { return _next; } ClassLoaderData* next() const { return _next; }
@ -150,7 +154,9 @@ class ClassLoaderData : public CHeapObj<mtClass> {
bool claimed() const { return _claimed == 1; } bool claimed() const { return _claimed == 1; }
bool claim(); 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*)); void classes_do(void f(InstanceKlass*));
@ -168,6 +174,8 @@ class ClassLoaderData : public CHeapObj<mtClass> {
return _the_null_class_loader_data; return _the_null_class_loader_data;
} }
bool is_anonymous() const;
static void init_null_class_loader_data() { static void init_null_class_loader_data() {
assert(_the_null_class_loader_data == NULL, "cannot initialize twice"); assert(_the_null_class_loader_data == NULL, "cannot initialize twice");
assert(ClassLoaderDataGraph::_head == 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"); assert(!(is_the_null_class_loader_data() && _unloading), "The null class loader can never be unloaded");
return _unloading; 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() { unsigned int identity_hash() {
return _class_loader == NULL ? 0 : _class_loader->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 print_value_on(outputStream* out) const PRODUCT_RETURN;
void dump(outputStream * const out) PRODUCT_RETURN; void dump(outputStream * const out) PRODUCT_RETURN;
void verify(); void verify();
const char* loader_name();
jobject add_handle(Handle h); jobject add_handle(Handle h);
void add_class(Klass* k); void add_class(Klass* k);
void remove_class(Klass* k); void remove_class(Klass* k);
void record_dependency(Klass* to, TRAPS); void record_dependency(Klass* to, TRAPS);
void init_dependencies(TRAPS);
void add_to_deallocate_list(Metadata* m); void add_to_deallocate_list(Metadata* m);
static ClassLoaderData* class_loader_data(oop loader); 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); static void print_loader(ClassLoaderData *loader_data, outputStream *out);
// CDS support // CDS support

View File

@ -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"); assert(loader() != NULL,"Must be a class loader");
// Gets the class loader data out of the java/lang/ClassLoader object, if non-null // 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 // 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) { if (loader_data_id) {
return loader_data_id; return loader_data_id;
} }
return ClassLoaderDataGraph::add(loader_data_addr, loader); return ClassLoaderDataGraph::add(loader_data_addr, loader, THREAD);
} }

View File

@ -580,7 +580,7 @@ void Dictionary::verify() {
// class loader must be present; a null class loader is the // class loader must be present; a null class loader is the
// boostrap loader // boostrap loader
guarantee(loader_data != NULL || DumpSharedSpaces || guarantee(loader_data != NULL || DumpSharedSpaces ||
loader_data->is_the_null_class_loader_data() || loader_data->class_loader() == NULL ||
loader_data->class_loader()->is_instance(), loader_data->class_loader()->is_instance(),
"checking type of class_loader"); "checking type of class_loader");
e->verify(); e->verify();

View File

@ -2544,8 +2544,8 @@ Metadata* java_lang_invoke_MemberName::vmtarget(oop mname) {
void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) { void java_lang_invoke_MemberName::set_vmtarget(oop mname, Metadata* ref) {
assert(is_instance(mname), "wrong type"); assert(is_instance(mname), "wrong type");
#ifdef ASSERT
// check the type of the vmtarget // check the type of the vmtarget
oop dependency = NULL;
if (ref != NULL) { if (ref != NULL) {
switch (flags(mname) & (MN_IS_METHOD | switch (flags(mname) & (MN_IS_METHOD |
MN_IS_CONSTRUCTOR | 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_METHOD:
case MN_IS_CONSTRUCTOR: case MN_IS_CONSTRUCTOR:
assert(ref->is_method(), "should be a method"); assert(ref->is_method(), "should be a method");
dependency = ((Method*)ref)->method_holder()->java_mirror();
break; break;
case MN_IS_FIELD: case MN_IS_FIELD:
assert(ref->is_klass(), "should be a class"); assert(ref->is_klass(), "should be a class");
dependency = ((Klass*)ref)->java_mirror();
break; break;
default: default:
ShouldNotReachHere(); ShouldNotReachHere();
} }
} }
#endif //ASSERT
mname->address_field_put(_vmtarget_offset, (address)ref); mname->address_field_put(_vmtarget_offset, (address)ref);
oop loader = NULL; // Add a reference to the loader (actually mirror because anonymous classes will not have
if (ref != NULL) { // distinct loaders) to ensure the metadata is kept alive
if (ref->is_klass()) { // This mirror may be different than the one in clazz field.
loader = ((Klass*)ref)->class_loader(); mname->obj_field_put(_vmloader_offset, dependency);
} 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);
} }
intptr_t java_lang_invoke_MemberName::vmindex(oop mname) { 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; bool java_lang_ClassLoader::offsets_computed = false;
int java_lang_ClassLoader::_loader_data_offset = -1; int java_lang_ClassLoader::_loader_data_offset = -1;
int java_lang_ClassLoader::_dependencies_offset = -1;
int java_lang_ClassLoader::parallelCapable_offset = -1; int java_lang_ClassLoader::parallelCapable_offset = -1;
ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) { 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); 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() { void java_lang_ClassLoader::compute_offsets() {
assert(!offsets_computed, "offsets should be initialized only once"); assert(!offsets_computed, "offsets should be initialized only once");
offsets_computed = true; offsets_computed = true;

View File

@ -1125,8 +1125,7 @@ class java_security_AccessControlContext: AllStatic {
// Interface to java.lang.ClassLoader objects // Interface to java.lang.ClassLoader objects
#define CLASSLOADER_INJECTED_FIELDS(macro) \ #define CLASSLOADER_INJECTED_FIELDS(macro) \
macro(java_lang_ClassLoader, loader_data, intptr_signature, false) \ macro(java_lang_ClassLoader, loader_data, intptr_signature, false)
macro(java_lang_ClassLoader, dependencies, object_signature, false)
class java_lang_ClassLoader : AllStatic { class java_lang_ClassLoader : AllStatic {
private: private:
@ -1135,7 +1134,6 @@ class java_lang_ClassLoader : AllStatic {
hc_parent_offset = 0 hc_parent_offset = 0
}; };
static int _loader_data_offset; static int _loader_data_offset;
static int _dependencies_offset;
static bool offsets_computed; static bool offsets_computed;
static int parent_offset; static int parent_offset;
static int parallelCapable_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_addr(oop loader);
static ClassLoaderData* loader_data(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 oop parent(oop loader);
static bool isAncestor(oop loader, oop cl); static bool isAncestor(oop loader, oop cl);

View File

@ -118,7 +118,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
probe->name()->as_C_string()); probe->name()->as_C_string());
for (int i = 0; i < probe->num_loaders(); i++) { for (int i = 0; i < probe->num_loaders(); i++) {
tty->print_cr("[ [%d]: %s", 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) { if (TraceLoaderConstraints) {
ResourceMark rm; ResourceMark rm;
tty->print_cr("[Purging loader %s from constraint for name %s", 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() probe->name()->as_C_string()
); );
} }
@ -145,7 +145,7 @@ void LoaderConstraintTable::purge_loader_constraints() {
tty->print_cr("[New loader list:"); tty->print_cr("[New loader list:");
for (int i = 0; i < probe->num_loaders(); i++) { for (int i = 0; i < probe->num_loaders(); i++) {
tty->print_cr("[ [%d]: %s", 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++) { for (int i = 0; i < p1->num_loaders(); i++) {
tty->print_cr("[ [%d]: %s", i, tty->print_cr("[ [%d]: %s", i,
SystemDictionary::loader_name(p1->loader_data(i))); p1->loader_data(i)->loader_name());
} }
if (p1->klass() == NULL) { if (p1->klass() == NULL) {
tty->print_cr("[... and setting class object]"); tty->print_cr("[... and setting class object]");

View File

@ -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(); 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 // UseNewReflection
// Fix for 4474172; see evaluation for more details // Fix for 4474172; see evaluation for more details
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); 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 // Do lookup to see if class already exist and the protection domain
// has the right access // has the right access
@ -888,7 +888,7 @@ Klass* SystemDictionary::find(Symbol* class_name,
// of the call to resolve_instance_class_or_null(). // of the call to resolve_instance_class_or_null().
// See evaluation 6790209 and 4474172 for more details. // See evaluation 6790209 and 4474172 for more details.
class_loader = Handle(THREAD, java_lang_ClassLoader::non_reflection_class_loader(class_loader())); 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); unsigned int d_hash = dictionary()->compute_hash(class_name, loader_data);
int d_index = dictionary()->hash_to_index(d_hash); int d_index = dictionary()->hash_to_index(d_hash);
@ -948,6 +948,18 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
TRAPS) { TRAPS) {
TempNewSymbol parsed_name = NULL; 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 // Parse the stream. Note that we do this even though this klass might
// already be present in the SystemDictionary, otherwise we would not // already be present in the SystemDictionary, otherwise we would not
// throw potential ClassFormatErrors. // throw potential ClassFormatErrors.
@ -959,7 +971,7 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
// java.lang.Object through resolve_or_fail, not this path. // java.lang.Object through resolve_or_fail, not this path.
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
class_loader, loader_data,
protection_domain, protection_domain,
host_klass, host_klass,
cp_patches, 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 // 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. // enough along to parse it -- in that case, there is nothing to clean up.
if (parsed_name != NULL) { if (parsed_name != NULL) {
ClassLoaderData* loader_data = class_loader_data(class_loader);
unsigned int p_hash = placeholders()->compute_hash(parsed_name, unsigned int p_hash = placeholders()->compute_hash(parsed_name,
loader_data); loader_data);
int p_index = placeholders()->hash_to_index(p_hash); 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()) { if (host_klass.not_null() && k.not_null()) {
assert(EnableInvokeDynamic, ""); 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()); k->set_host_klass(host_klass());
// If it's anonymous, initialize it now, since nobody else will.
{ {
MutexLocker mu_r(Compile_lock, THREAD); MutexLocker mu_r(Compile_lock, THREAD);
@ -1002,11 +1011,11 @@ Klass* SystemDictionary::parse_stream(Symbol* class_name,
} }
// Rewrite and patch constant pool here. // Rewrite and patch constant pool here.
k->link_class(THREAD); k->link_class(CHECK_NULL);
if (cp_patches != NULL) { if (cp_patches != NULL) {
k->constants()->patch_resolved_references(cp_patches); k->constants()->patch_resolved_references(cp_patches);
} }
k->eager_initialize(THREAD); k->eager_initialize(CHECK_NULL);
// notify jvmti // notify jvmti
if (JvmtiExport::should_post_class_load()) { if (JvmtiExport::should_post_class_load()) {
@ -1039,7 +1048,7 @@ Klass* SystemDictionary::resolve_from_stream(Symbol* class_name,
DoObjectLock = false; 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 // Make sure we are synchronized on the class loader before we proceed
Handle lockObject = compute_loader_lock_object(class_loader, THREAD); 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. // java.lang.Object through resolve_or_fail, not this path.
instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name, instanceKlassHandle k = ClassFileParser(st).parseClassFile(class_name,
class_loader, loader_data,
protection_domain, protection_domain,
parsed_name, parsed_name,
verify, verify,
@ -2343,6 +2352,7 @@ methodHandle SystemDictionary::find_method_handle_intrinsic(vmIntrinsics::ID iid
// Helper for unpacking the return value from linkMethod and linkCallSite. // Helper for unpacking the return value from linkMethod and linkCallSite.
static methodHandle unpack_method_and_appendix(Handle mname, static methodHandle unpack_method_and_appendix(Handle mname,
KlassHandle accessing_klass,
objArrayHandle appendix_box, objArrayHandle appendix_box,
Handle* appendix_result, Handle* appendix_result,
TRAPS) { TRAPS) {
@ -2361,6 +2371,12 @@ static methodHandle unpack_method_and_appendix(Handle mname,
#endif //PRODUCT #endif //PRODUCT
} }
(*appendix_result) = Handle(THREAD, appendix); (*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); return methodHandle(THREAD, m);
} }
} }
@ -2405,7 +2421,7 @@ methodHandle SystemDictionary::find_method_handle_invoker(Symbol* name,
&args, CHECK_(empty)); &args, CHECK_(empty));
Handle mname(THREAD, (oop) result.get_jobject()); Handle mname(THREAD, (oop) result.get_jobject());
(*method_type_result) = method_type; (*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)); &args, CHECK_(empty));
Handle mname(THREAD, (oop) result.get_jobject()); Handle mname(THREAD, (oop) result.get_jobject());
(*method_type_result) = method_type; (*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 // Since the identity hash code for symbols changes when the symbols are

View File

@ -471,7 +471,7 @@ public:
static void compute_java_system_loader(TRAPS); static void compute_java_system_loader(TRAPS);
// Register a new class loader // Register a new class loader
static ClassLoaderData* register_loader(Handle class_loader); static ClassLoaderData* register_loader(Handle class_loader, TRAPS);
private: private:
// Mirrors for primitive classes (created eagerly) // Mirrors for primitive classes (created eagerly)
static oop check_mirror(oop m) { static oop check_mirror(oop m) {
@ -531,7 +531,7 @@ public:
InstanceKlass::cast((loader)->klass())->name()->as_C_string() ); InstanceKlass::cast((loader)->klass())->name()->as_C_string() );
} }
static const char* loader_name(ClassLoaderData* loader_data) { 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() ); InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string() );
} }

View File

@ -269,10 +269,12 @@ void CompileTask::initialize(int compile_id,
const char* comment, const char* comment,
bool is_blocking) { bool is_blocking) {
assert(!_lock->is_locked(), "bad locking"); assert(!_lock->is_locked(), "bad locking");
InstanceKlass* holder = method->method_holder();
_compile_id = compile_id; _compile_id = compile_id;
_method = method(); _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; _osr_bci = osr_bci;
_is_blocking = is_blocking; _is_blocking = is_blocking;
_comp_level = comp_level; _comp_level = comp_level;
@ -283,7 +285,7 @@ void CompileTask::initialize(int compile_id,
_code_handle = NULL; _code_handle = NULL;
_hot_method = NULL; _hot_method = NULL;
_hot_method_loader = NULL; _hot_method_holder = NULL;
_hot_count = hot_count; _hot_count = hot_count;
_time_queued = 0; // tidy _time_queued = 0; // tidy
_comment = comment; _comment = comment;
@ -295,8 +297,12 @@ void CompileTask::initialize(int compile_id,
_hot_method = _method; _hot_method = _method;
} else { } else {
_hot_method = hot_method(); _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() { void CompileTask::free() {
set_code(NULL); set_code(NULL);
assert(!_lock->is_locked(), "Should not be locked when freed"); assert(!_lock->is_locked(), "Should not be locked when freed");
JNIHandles::destroy_global(_method_loader); JNIHandles::destroy_global(_method_holder);
JNIHandles::destroy_global(_hot_method_loader); JNIHandles::destroy_global(_hot_method_holder);
} }

View File

@ -43,7 +43,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
Monitor* _lock; Monitor* _lock;
uint _compile_id; uint _compile_id;
Method* _method; Method* _method;
jobject _method_loader; jobject _method_holder;
int _osr_bci; int _osr_bci;
bool _is_complete; bool _is_complete;
bool _is_success; bool _is_success;
@ -56,7 +56,7 @@ class CompileTask : public CHeapObj<mtCompiler> {
// Fields used for logging why the compilation was initiated: // Fields used for logging why the compilation was initiated:
jlong _time_queued; // in units of os::elapsed_counter() jlong _time_queued; // in units of os::elapsed_counter()
Method* _hot_method; // which method actually triggered this task 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 int _hot_count; // information about its invocation counter
const char* _comment; // more info about the task const char* _comment; // more info about the task

View File

@ -123,9 +123,7 @@ class Metachunk VALUE_OBJ_CLASS_SPEC {
void assert_is_mangled() const {/* Don't check "\*/} void assert_is_mangled() const {/* Don't check "\*/}
#ifdef ASSERT NOT_PRODUCT(void mangle();)
void mangle();
#endif // ASSERT
void print_on(outputStream* st) const; void print_on(outputStream* st) const;
void verify(); void verify();

View File

@ -108,7 +108,6 @@ size_t Metablock::_min_block_byte_size = sizeof(Metablock);
size_t Metablock::_overhead = 0; size_t Metablock::_overhead = 0;
#endif #endif
// Pointer to list of Metachunks. // Pointer to list of Metachunks.
class ChunkList VALUE_OBJ_CLASS_SPEC { class ChunkList VALUE_OBJ_CLASS_SPEC {
// List of free chunks // List of free chunks
@ -325,10 +324,12 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
bool expand_by(size_t words, bool pre_touch = false); bool expand_by(size_t words, bool pre_touch = false);
bool shrink_by(size_t words); bool shrink_by(size_t words);
#ifdef ASSERT
// Debug support // Debug support
static void verify_virtual_space_total(); static void verify_virtual_space_total();
static void verify_virtual_space_count(); static void verify_virtual_space_count();
void mangle(); void mangle();
#endif
void print_on(outputStream* st) const; 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 locked_print_chunks_in_use_on(outputStream* st) const;
void verify(); void verify();
NOT_PRODUCT(void mangle_freed_chunks();)
#ifdef ASSERT #ifdef ASSERT
void mangle_freed_chunks();
void verify_allocation_total(); void verify_allocation_total();
#endif #endif
}; };
@ -711,7 +712,7 @@ void Metachunk::print_on(outputStream* st) const {
bottom(), top(), end(), word_size()); bottom(), top(), end(), word_size());
} }
#ifdef ASSERT #ifndef PRODUCT
void Metachunk::mangle() { void Metachunk::mangle() {
// Mangle the payload of the chunk and not the links that // Mangle the payload of the chunk and not the links that
// maintain list of chunks. // maintain list of chunks.
@ -719,7 +720,7 @@ void Metachunk::mangle() {
size_t word_size = capacity_word_size() - overhead(); size_t word_size = capacity_word_size() - overhead();
Copy::fill_to_words(start, word_size, metadata_chunk_initialize); Copy::fill_to_words(start, word_size, metadata_chunk_initialize);
} }
#endif // ASSERT #endif // PRODUCT
void Metachunk::verify() { void Metachunk::verify() {
#ifdef ASSERT #ifdef ASSERT
@ -917,10 +918,12 @@ void VirtualSpaceNode::print_on(outputStream* st) const {
vs->high_boundary()); vs->high_boundary());
} }
#ifdef ASSERT
void VirtualSpaceNode::mangle() { void VirtualSpaceNode::mangle() {
size_t word_size = capacity_words_in_vs(); size_t word_size = capacity_words_in_vs();
Copy::fill_to_words((HeapWord*) low(), word_size, 0xf1f1f1f1); Copy::fill_to_words((HeapWord*) low(), word_size, 0xf1f1f1f1);
} }
#endif // ASSERT
// VirtualSpaceList methods // VirtualSpaceList methods
// Space allocated from the VirtualSpace // Space allocated from the VirtualSpace
@ -1985,16 +1988,14 @@ SpaceManager::~SpaceManager() {
locked_print_chunks_in_use_on(gclog_or_tty); 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 // Have to update before the chunks_in_use lists are emptied
// below. // below.
chunk_manager->inc_free_chunks_total(sum_capacity_in_chunks_in_use(), chunk_manager->inc_free_chunks_total(sum_capacity_in_chunks_in_use(),
sum_count_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 // Add all the chunks in use by this space manager
// to the global list of free chunks. // 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); " waste " SIZE_FORMAT, curr_total, used, free, capacity, waste);
} }
#ifdef ASSERT #ifndef PRODUCT
void SpaceManager::mangle_freed_chunks() { void SpaceManager::mangle_freed_chunks() {
for (ChunkIndex index = SmallIndex; for (ChunkIndex index = SmallIndex;
index < NumberOfInUseLists; index < NumberOfInUseLists;
@ -2291,11 +2292,16 @@ void SpaceManager::mangle_freed_chunks() {
} }
} }
} }
#endif // ASSERT #endif // PRODUCT
// MetaspaceAux // 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 MetaspaceAux::used_in_bytes(Metaspace::MetadataType mdtype) {
size_t used = 0; size_t used = 0;
ClassLoaderDataGraphMetaspaceIterator iter; ClassLoaderDataGraphMetaspaceIterator iter;
@ -2324,6 +2330,11 @@ size_t MetaspaceAux::free_in_bytes(Metaspace::MetadataType mdtype) {
// The total words available for metadata allocation. This // The total words available for metadata allocation. This
// uses Metaspace capacity_words() which is the total words // uses Metaspace capacity_words() which is the total words
// in chunks allocated for a Metaspace. // 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 MetaspaceAux::capacity_in_bytes(Metaspace::MetadataType mdtype) {
size_t capacity = free_chunks_total(mdtype); size_t capacity = free_chunks_total(mdtype);
ClassLoaderDataGraphMetaspaceIterator iter; ClassLoaderDataGraphMetaspaceIterator iter;
@ -2336,6 +2347,11 @@ size_t MetaspaceAux::capacity_in_bytes(Metaspace::MetadataType mdtype) {
return capacity * BytesPerWord; 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 MetaspaceAux::reserved_in_bytes(Metaspace::MetadataType mdtype) {
size_t reserved = (mdtype == Metaspace::ClassType) ? size_t reserved = (mdtype == Metaspace::ClassType) ?
Metaspace::class_space_list()->virtual_space_total() : Metaspace::class_space_list()->virtual_space_total() :

View File

@ -160,25 +160,16 @@ class MetaspaceAux : AllStatic {
public: public:
// Total of space allocated to metadata in all Metaspaces // Total of space allocated to metadata in all Metaspaces
static size_t used_in_bytes() { static size_t used_in_bytes();
return used_in_bytes(Metaspace::ClassType) +
used_in_bytes(Metaspace::NonClassType);
}
// Total of available space in all Metaspaces // Total of available space in all Metaspaces
// Total of capacity allocated to all Metaspaces. This includes // Total of capacity allocated to all Metaspaces. This includes
// space in Metachunks not yet allocated and in the Metachunk // space in Metachunks not yet allocated and in the Metachunk
// freelist. // freelist.
static size_t capacity_in_bytes() { static size_t capacity_in_bytes();
return capacity_in_bytes(Metaspace::ClassType) +
capacity_in_bytes(Metaspace::NonClassType);
}
// Total space reserved in all Metaspaces // Total space reserved in all Metaspaces
static size_t reserved_in_bytes() { static size_t reserved_in_bytes();
return reserved_in_bytes(Metaspace::ClassType) +
reserved_in_bytes(Metaspace::NonClassType);
}
static size_t min_chunk_size(); static size_t min_chunk_size();

View File

@ -407,6 +407,10 @@ void Universe::genesis(TRAPS) {
assert(i == _fullgc_alot_dummy_array->length(), "just checking"); assert(i == _fullgc_alot_dummy_array->length(), "just checking");
} }
#endif #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. // CDS support for patching vtables in metadata in the shared archive.

View File

@ -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(); do_resolve = this_oop->tag_at(which).is_unresolved_klass();
if (do_resolve) { if (do_resolve) {
ClassLoaderData* this_key = this_oop->pool_holder()->class_loader_data(); 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()); this_oop->klass_at_put(which, k());
} }
} }

View File

@ -373,29 +373,22 @@ void Klass::append_to_sibling_list() {
debug_only(verify();) 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) { bool Klass::is_loader_alive(BoolObjectClosure* is_alive) {
assert(is_metadata(), "p is not meta-data"); assert(is_metadata(), "p is not meta-data");
assert(ClassLoaderDataGraph::contains((address)this), "is in the metaspace"); assert(ClassLoaderDataGraph::contains((address)this), "is in the metaspace");
#ifdef ASSERT
// The class is alive iff the class loader is alive. // The class is alive iff the class loader is alive.
oop loader = class_loader(); 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) { 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(); Klass* sub = current->subklass_oop();
while (sub != NULL && !sub->is_loader_alive(is_alive)) { while (sub != NULL && !sub->is_loader_alive(is_alive)) {
#ifndef PRODUCT #ifndef PRODUCT
if (TraceClassUnloading && WizardMode) { if (TraceClassUnloading && WizardMode) {
ResourceMark rm; ResourceMark rm;
tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name()); tty->print_cr("[Unlinking class (subclass) %s]", sub->external_name());
} }
#endif #endif
sub = sub->next_sibling_oop(); 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 // Find and set the first alive sibling
Klass* sibling = current->next_sibling_oop(); Klass* sibling = current->next_sibling_oop();
while (sibling != NULL && !sibling->is_loader_alive(is_alive)) { while (sibling != NULL && !sibling->is_loader_alive(is_alive)) {
if (TraceClassUnloading && WizardMode) { if (TraceClassUnloading && WizardMode) {
ResourceMark rm; ResourceMark rm;
tty->print_cr("[Unlinking class (sibling) %s]", sibling->external_name()); 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); current->set_next_sibling(sibling);
if (sibling != NULL) { if (sibling != NULL) {
stack.push(sibling); stack.push(sibling);
} }
// Clean the implementors list and method data. // Clean the implementors list and method data.
if (current->oop_is_instance()) { if (current->oop_is_instance()) {
@ -554,7 +547,11 @@ const char* Klass::external_name() const {
InstanceKlass* ik = (InstanceKlass*) this; InstanceKlass* ik = (InstanceKlass*) this;
if (ik->is_anonymous()) { if (ik->is_anonymous()) {
assert(EnableInvokeDynamic, ""); 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]; char hash_buf[40];
sprintf(hash_buf, "/" UINTX_FORMAT, (uintx)hash); sprintf(hash_buf, "/" UINTX_FORMAT, (uintx)hash);
size_t hash_len = strlen(hash_buf); size_t hash_len = strlen(hash_buf);

View File

@ -267,7 +267,6 @@ class Klass : public Metadata {
Klass* subklass() const; Klass* subklass() const;
Klass* next_sibling() const; Klass* next_sibling() const;
void append_to_sibling_list(); // add newly created receiver to superklass' subklass list 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; } void set_next_link(Klass* k) { _next_link = k; }
Klass* next_link() const { return _next_link; } // The next klass defined by the class loader. 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 // garbage collection support
virtual void oops_do(OopClosure* cl); virtual void oops_do(OopClosure* cl);
// Checks if the class loader is alive. // Iff the class loader (or mirror for anonymous classes) is alive the
// Iff the class loader is alive the Klass is considered alive. // Klass is considered alive.
// The is_alive closure passed in depends on the Garbage Collector used. // The is_alive closure passed in depends on the Garbage Collector used.
bool is_loader_alive(BoolObjectClosure* is_alive); bool is_loader_alive(BoolObjectClosure* is_alive);

View File

@ -88,11 +88,6 @@ Klass* ObjArrayKlass::allocate_objArray_klass(ClassLoaderData* loader_data,
} }
if (!supers_exist) { if (!supers_exist) {
// Oops. Not allocated yet. Back out, allocate it, and retry. // 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; KlassHandle ek;
{ {
MutexUnlocker mu(MultiArray_lock); MutexUnlocker mu(MultiArray_lock);

View File

@ -996,7 +996,7 @@ UNSAFE_END
// not just a literal string. For such ldc instructions, the verifier uses the // 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. // type Object instead of String, if the loaded constant is not in fact a String.
static oop static instanceKlassHandle
Unsafe_DefineAnonymousClass_impl(JNIEnv *env, Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
jclass host_class, jbyteArray data, jobjectArray cp_patches_jh, jclass host_class, jbyteArray data, jobjectArray cp_patches_jh,
HeapWord* *temp_alloc, HeapWord* *temp_alloc,
@ -1073,32 +1073,39 @@ Unsafe_DefineAnonymousClass_impl(JNIEnv *env,
anon_klass = instanceKlassHandle(THREAD, anonk); anon_klass = instanceKlassHandle(THREAD, anonk);
} }
// let caller initialize it as needed... return anon_klass;
return anon_klass->java_mirror();
} }
UNSAFE_ENTRY(jclass, Unsafe_DefineAnonymousClass(JNIEnv *env, jobject unsafe, jclass host_class, jbyteArray data, jobjectArray cp_patches_jh)) 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"); UnsafeWrapper("Unsafe_DefineAnonymousClass");
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
HeapWord* temp_alloc = NULL; HeapWord* temp_alloc = NULL;
jobject res_jh = NULL; anon_klass = Unsafe_DefineAnonymousClass_impl(env, host_class, data,
cp_patches_jh,
{ oop res_oop = Unsafe_DefineAnonymousClass_impl(env,
host_class, data, cp_patches_jh,
&temp_alloc, THREAD); &temp_alloc, THREAD);
if (res_oop != NULL) if (anon_klass() != NULL)
res_jh = JNIHandles::make_local(env, res_oop); res_jh = JNIHandles::make_local(env, anon_klass->java_mirror());
}
// try/finally clause: // try/finally clause:
if (temp_alloc != NULL) { if (temp_alloc != NULL) {
FREE_C_HEAP_ARRAY(HeapWord, temp_alloc, mtInternal); 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; return (jclass) res_jh;
} }
UNSAFE_END UNSAFE_END