# HG changeset patch # User coleenp # Date 1354225829 18000 # Node ID 8ec26d2d9339dfec714de71e37bf4f3a85b0b98d # Parent bd4290e6d0a5a533b8fece0a884a4eb8c1a66ed7 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 diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/asm/codeBuffer.cpp --- a/hotspot/src/share/vm/asm/codeBuffer.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -492,6 +492,26 @@ 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* 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 @@ 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 @@ 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 @@ 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 @@ 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(); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/ci/ciReplay.cpp --- a/hotspot/src/share/vm/ci/ciReplay.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/ci/ciReplay.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -31,7 +31,7 @@ #include "memory/resourceArea.hpp" #include "utilities/copy.hpp" -#ifdef ASSERT +#ifndef PRODUCT // ciReplay @@ -939,4 +939,4 @@ ciMethodRecord* rec = replay_state->find_ciMethodRecord(method); return rec != NULL; } -#endif +#endif // PRODUCT diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/ci/ciReplay.hpp --- a/hotspot/src/share/vm/ci/ciReplay.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/ci/ciReplay.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -32,7 +32,7 @@ class ciReplay { CI_PACKAGE_ACCESS -#ifdef ASSERT +#ifndef PRODUCT private: static int replay_impl(TRAPS); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/classFileParser.cpp --- a/hotspot/src/share/vm/classfile/classFileParser.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -2950,7 +2950,7 @@ instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name, - Handle class_loader, + ClassLoaderData* loader_data, Handle protection_domain, KlassHandle host_klass, GrowableArray* cp_patches, @@ -2964,7 +2964,7 @@ // 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 @@ 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 @@ 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); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/classFileParser.hpp --- a/hotspot/src/share/vm/classfile/classFileParser.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -363,16 +363,16 @@ // "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* cp_patches, diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/classLoader.cpp --- a/hotspot/src/share/vm/classfile/classLoader.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/classLoader.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -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 @@ // 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, diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/classLoaderData.cpp --- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -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 @@ } 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 @@ 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 to; + if (to_cld->is_anonymous()) { + // Anonymous class dependencies are through the mirror. + to = k->java_mirror(); + } else { + to = to_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. + // 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()); + // 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); - // 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; + // 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 @@ // 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 @@ 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 @@ 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 @@ 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 @@ } } -#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 @@ 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::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 @@ } } + // GC root of class loader data created. ClassLoaderData* ClassLoaderDataGraph::_head = NULL; ClassLoaderData* ClassLoaderDataGraph::_unloading = NULL; @@ -395,19 +470,25 @@ // 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); + ClassLoaderData* cld = new ClassLoaderData(loader); - // First, Atomically set it. - ClassLoaderData* old = (ClassLoaderData*) Atomic::cmpxchg_ptr(cld, cld_addr, NULL); - if (old != NULL) { - delete cld; - // Returns the data. - return old; + 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* 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::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 @@ } #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 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 @@ } 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) { diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/classLoaderData.hpp --- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -62,13 +62,14 @@ // 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/classLoaderData.inline.hpp --- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -33,7 +33,7 @@ } -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 @@ if (loader_data_id) { return loader_data_id; } - return ClassLoaderDataGraph::add(loader_data_addr, loader); + return ClassLoaderDataGraph::add(loader_data_addr, loader, THREAD); } diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/dictionary.cpp --- a/hotspot/src/share/vm/classfile/dictionary.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/dictionary.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -580,7 +580,7 @@ // 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(); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/javaClasses.cpp --- a/hotspot/src/share/vm/classfile/javaClasses.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -2544,8 +2544,8 @@ 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 @@ 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 @@ 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 @@ 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(_dependencies_offset); - } else { - return (HeapWord*)loader->obj_field_addr(_dependencies_offset); - } -} - void java_lang_ClassLoader::compute_offsets() { assert(!offsets_computed, "offsets should be initialized only once"); offsets_computed = true; diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/javaClasses.hpp --- a/hotspot/src/share/vm/classfile/javaClasses.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -1125,8 +1125,7 @@ // 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 @@ 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 @@ 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); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/loaderConstraints.cpp --- a/hotspot/src/share/vm/classfile/loaderConstraints.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/loaderConstraints.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -118,7 +118,7 @@ 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 @@ 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 @@ 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 @@ 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]"); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/systemDictionary.cpp --- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -106,9 +106,9 @@ } -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 @@ // 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 @@ // 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 @@ 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 @@ // 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 @@ // 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 @@ if (host_klass.not_null() && k.not_null()) { assert(EnableInvokeDynamic, ""); + k->set_host_klass(host_klass()); // 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()); { MutexLocker mu_r(Compile_lock, THREAD); @@ -1002,11 +1011,11 @@ } // 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 @@ 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 @@ // 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 @@ // 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 @@ #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 @@ &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 @@ &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 diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/classfile/systemDictionary.hpp --- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -471,7 +471,7 @@ 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 @@ 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() ? "" : + return (loader_data->class_loader() == NULL ? "" : InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string() ); } diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -269,10 +269,12 @@ 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 @@ _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 @@ _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::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); } diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/compiler/compileBroker.hpp --- a/hotspot/src/share/vm/compiler/compileBroker.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -43,7 +43,7 @@ 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 @@ // 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 diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/memory/metachunk.hpp --- a/hotspot/src/share/vm/memory/metachunk.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/memory/metachunk.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -123,9 +123,7 @@ 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(); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/memory/metaspace.cpp --- a/hotspot/src/share/vm/memory/metaspace.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/memory/metaspace.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -108,7 +108,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ " 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 @@ } } } -#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 @@ // 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 @@ 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() : diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/memory/metaspace.hpp --- a/hotspot/src/share/vm/memory/metaspace.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/memory/metaspace.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -160,25 +160,16 @@ 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(); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/memory/universe.cpp --- a/hotspot/src/share/vm/memory/universe.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/memory/universe.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -407,6 +407,10 @@ 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. diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/oops/constantPool.cpp --- a/hotspot/src/share/vm/oops/constantPool.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/oops/constantPool.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -340,9 +340,7 @@ 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()); } } diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/oops/klass.cpp --- a/hotspot/src/share/vm/oops/klass.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/oops/klass.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -373,29 +373,22 @@ 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 @@ 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 @@ // 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(); - } + } 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 @@ 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); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/oops/klass.hpp --- a/hotspot/src/share/vm/oops/klass.hpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/oops/klass.hpp Thu Nov 29 16:50:29 2012 -0500 @@ -267,7 +267,6 @@ 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 @@ // 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); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/oops/objArrayKlass.cpp --- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -88,11 +88,6 @@ } 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); diff -r bd4290e6d0a5 -r 8ec26d2d9339 hotspot/src/share/vm/prims/unsafe.cpp --- a/hotspot/src/share/vm/prims/unsafe.cpp Tue Nov 27 14:11:37 2012 -0800 +++ b/hotspot/src/share/vm/prims/unsafe.cpp Thu Nov 29 16:50:29 2012 -0500 @@ -996,7 +996,7 @@ // 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 @@ 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