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