--- a/hotspot/src/share/vm/asm/codeBuffer.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/asm/codeBuffer.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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<oop>* oops, Klass* k) {
+ if (k->oop_is_instance()) {
+ InstanceKlass* ik = InstanceKlass::cast(k);
+ if (ik->is_anonymous()) {
+ oop o = ik->java_mirror();
+ assert (o != NULL, "should have a mirror");
+ if (!oops->contains(o)) {
+ oops->append(o);
+ }
+ return; // only need the mirror
+ }
+ }
+ oop cl = k->class_loader();
+ if (cl != NULL && !oops->contains(cl)) {
+ oops->append(cl);
+ }
+}
+
void CodeBuffer::finalize_oop_references(methodHandle mh) {
No_Safepoint_Verifier nsv;
@@ -509,7 +529,6 @@
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();
--- a/hotspot/src/share/vm/ci/ciReplay.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciReplay.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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
--- a/hotspot/src/share/vm/ci/ciReplay.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/ci/ciReplay.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -32,7 +32,7 @@
class ciReplay {
CI_PACKAGE_ACCESS
-#ifdef ASSERT
+#ifndef PRODUCT
private:
static int replay_impl(TRAPS);
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -2949,7 +2949,7 @@
instanceKlassHandle ClassFileParser::parseClassFile(Symbol* name,
- Handle class_loader,
+ ClassLoaderData* loader_data,
Handle protection_domain,
KlassHandle host_klass,
GrowableArray<Handle>* cp_patches,
@@ -2963,7 +2963,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);
@@ -3004,7 +3004,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);
@@ -4003,8 +4003,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);
--- a/hotspot/src/share/vm/classfile/classFileParser.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/classFileParser.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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<Handle>* cp_patches,
--- a/hotspot/src/share/vm/classfile/classLoader.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/classLoader.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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,
--- a/hotspot/src/share/vm/classfile/classLoaderData.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/classLoaderData.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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) {
--- a/hotspot/src/share/vm/classfile/classLoaderData.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/classLoaderData.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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
--- a/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/classLoaderData.inline.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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);
}
--- a/hotspot/src/share/vm/classfile/dictionary.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/dictionary.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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();
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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<narrowOop>(_dependencies_offset);
- } else {
- return (HeapWord*)loader->obj_field_addr<oop>(_dependencies_offset);
- }
-}
-
void java_lang_ClassLoader::compute_offsets() {
assert(!offsets_computed, "offsets should be initialized only once");
offsets_computed = true;
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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);
--- a/hotspot/src/share/vm/classfile/loaderConstraints.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/loaderConstraints.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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]");
--- a/hotspot/src/share/vm/classfile/systemDictionary.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/systemDictionary.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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
--- a/hotspot/src/share/vm/classfile/systemDictionary.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/classfile/systemDictionary.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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() ? "<bootloader>" :
+ return (loader_data->class_loader() == NULL ? "<bootloader>" :
InstanceKlass::cast((loader_data->class_loader())->klass())->name()->as_C_string() );
}
--- a/hotspot/src/share/vm/compiler/compileBroker.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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);
}
--- a/hotspot/src/share/vm/compiler/compileBroker.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/compiler/compileBroker.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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
--- a/hotspot/src/share/vm/memory/metachunk.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/memory/metachunk.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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();
--- a/hotspot/src/share/vm/memory/metaspace.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/memory/metaspace.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -109,7 +109,6 @@
size_t Metablock::_overhead = 0;
#endif
-
// Pointer to list of Metachunks.
class ChunkList VALUE_OBJ_CLASS_SPEC {
// List of free chunks
@@ -326,10 +325,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;
};
@@ -622,8 +623,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
};
@@ -712,7 +713,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.
@@ -720,7 +721,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
@@ -918,10 +919,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
@@ -1986,16 +1989,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.
@@ -2274,7 +2275,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;
@@ -2292,11 +2293,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;
@@ -2325,6 +2331,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;
@@ -2337,6 +2348,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() :
--- a/hotspot/src/share/vm/memory/metaspace.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/memory/metaspace.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -156,25 +156,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();
--- a/hotspot/src/share/vm/memory/universe.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/memory/universe.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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.
--- a/hotspot/src/share/vm/oops/constantPool.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/oops/constantPool.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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());
}
}
--- a/hotspot/src/share/vm/oops/klass.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/oops/klass.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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);
--- a/hotspot/src/share/vm/oops/klass.hpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/oops/klass.hpp Fri Nov 30 12:01:34 2012 -0800
@@ -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);
--- a/hotspot/src/share/vm/oops/objArrayKlass.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/oops/objArrayKlass.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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);
--- a/hotspot/src/share/vm/prims/unsafe.cpp Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/src/share/vm/prims/unsafe.cpp Fri Nov 30 12:01:34 2012 -0800
@@ -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
--- a/hotspot/test/runtime/8003720/Asmator.java Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/test/runtime/8003720/Asmator.java Fri Nov 30 12:01:34 2012 -0800
@@ -1,9 +1,34 @@
-import com.sun.xml.internal.ws.org.objectweb.asm.*;
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+import jdk.internal.org.objectweb.asm.*;
class Asmator {
static byte[] fixup(byte[] buf) throws java.io.IOException {
ClassReader cr = new ClassReader(buf);
- ClassWriter cw = new ClassWriter(0) {
+ ClassWriter cw = new ClassWriter(0);
+ ClassVisitor cv = new ClassVisitor(Opcodes.ASM4, cw) {
public MethodVisitor visitMethod(
final int access,
final String name,
@@ -25,7 +50,7 @@
return mv;
}
};
- cr.accept(cw, 0);
+ cr.accept(cv, 0);
return cw.toByteArray();
}
}
--- a/hotspot/test/runtime/8003720/Test8003720.java Thu Nov 29 13:55:49 2012 -0800
+++ b/hotspot/test/runtime/8003720/Test8003720.java Fri Nov 30 12:01:34 2012 -0800
@@ -26,7 +26,7 @@
* @test
* @bug 8003720
* @summary Method in interpreter stack frame can be deallocated
- * @compile -XDignore.symbol.file Victim.java
+ * @compile -XDignore.symbol.file -source 1.7 -target 1.7 Victim.java
* @run main/othervm -Xverify:all -Xint Test8003720
*/