6964458: Reimplement class meta-data storage to use native memory

Remove PermGen, allocate meta-data in metaspace linked to class loaders, rewrite GC walking, rewrite and rename metadata to be C++ classes

Co-authored-by: Stefan Karlsson <stefan.karlsson@oracle.com>
Co-authored-by: Mikael Gerdin <mikael.gerdin@oracle.com>
Co-authored-by: Tom Rodriguez <tom.rodriguez@oracle.com>
Reviewed-by: jmasa, stefank, never, coleenp, kvn, brutisso, mgerdin, dholmes, jrose, twisti, roland
This commit is contained in:
Jon Masamitsu 2012-09-01 13:25:18 -04:00 committed by Coleen Phillimore
parent 36eee7c8c8
commit 5c58d27aac
853 changed files with 26124 additions and 82956 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 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
@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/loaderConstraints.hpp"
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
@ -30,16 +31,20 @@
#include "runtime/safepoint.hpp"
#include "utilities/hashtable.inline.hpp"
void LoaderConstraintEntry::set_loader(int i, oop p) {
set_loader_data(i, ClassLoaderData::class_loader_data(p));
}
LoaderConstraintTable::LoaderConstraintTable(int nof_buckets)
: Hashtable<klassOop, mtClass>(nof_buckets, sizeof(LoaderConstraintEntry)) {};
: Hashtable<Klass*, mtClass>(nof_buckets, sizeof(LoaderConstraintEntry)) {};
LoaderConstraintEntry* LoaderConstraintTable::new_entry(
unsigned int hash, Symbol* name,
klassOop klass, int num_loaders,
Klass* klass, int num_loaders,
int max_loaders) {
LoaderConstraintEntry* entry;
entry = (LoaderConstraintEntry*)Hashtable<klassOop, mtClass>::new_entry(hash, klass);
entry = (LoaderConstraintEntry*)Hashtable<Klass*, mtClass>::new_entry(hash, klass);
entry->set_name(name);
entry->set_num_loaders(num_loaders);
entry->set_max_loaders(max_loaders);
@ -49,27 +54,21 @@ LoaderConstraintEntry* LoaderConstraintTable::new_entry(
void LoaderConstraintTable::free_entry(LoaderConstraintEntry *entry) {
// decrement name refcount before freeing
entry->name()->decrement_refcount();
Hashtable<klassOop, mtClass>::free_entry(entry);
Hashtable<Klass*, mtClass>::free_entry(entry);
}
void LoaderConstraintTable::oops_do(OopClosure* f) {
// Enhanced Class Redefinition support
void LoaderConstraintTable::classes_do(KlassClosure* f) {
for (int index = 0; index < table_size(); index++) {
for (LoaderConstraintEntry* probe = bucket(index);
probe != NULL;
probe = probe->next()) {
if (probe->klass() != NULL) {
f->do_oop((oop*)probe->klass_addr());
f->do_klass(probe->klass());
}
for (int n = 0; n < probe->num_loaders(); n++) {
if (probe->loader(n) != NULL) {
f->do_oop(probe->loader_addr(n));
}
}
}
}
}
// The loaderConstraintTable must always be accessed with the
// SystemDictionary lock held. This is true even for readers as
@ -81,12 +80,14 @@ LoaderConstraintEntry** LoaderConstraintTable::find_loader_constraint(
unsigned int hash = compute_hash(name);
int index = hash_to_index(hash);
LoaderConstraintEntry** pp = bucket_addr(index);
ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(loader());
while (*pp) {
LoaderConstraintEntry* p = *pp;
if (p->hash() == hash) {
if (p->name() == name) {
for (int i = p->num_loaders() - 1; i >= 0; i--) {
if (p->loader(i) == loader()) {
if (p->loader_data(i) == loader_data) {
return pp;
}
}
@ -98,16 +99,17 @@ LoaderConstraintEntry** LoaderConstraintTable::find_loader_constraint(
}
void LoaderConstraintTable::purge_loader_constraints(BoolObjectClosure* is_alive) {
void LoaderConstraintTable::purge_loader_constraints() {
assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
// Remove unloaded entries from constraint table
for (int index = 0; index < table_size(); index++) {
LoaderConstraintEntry** p = bucket_addr(index);
while(*p) {
LoaderConstraintEntry* probe = *p;
klassOop klass = probe->klass();
Klass* klass = probe->klass();
// Remove klass that is no longer alive
if (klass != NULL && !is_alive->do_object_b(klass)) {
if (klass != NULL &&
klass->class_loader_data()->is_unloading()) {
probe->set_klass(NULL);
if (TraceLoaderConstraints) {
ResourceMark rm;
@ -116,19 +118,18 @@ void LoaderConstraintTable::purge_loader_constraints(BoolObjectClosure* is_alive
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(i)));
SystemDictionary::loader_name(probe->loader_data(i)));
}
}
}
// Remove entries no longer alive from loader array
int n = 0;
while (n < probe->num_loaders()) {
if (probe->loader(n) != NULL) {
if (!is_alive->do_object_b(probe->loader(n))) {
if (probe->loader_data(n)->is_unloading()) {
if (TraceLoaderConstraints) {
ResourceMark rm;
tty->print_cr("[Purging loader %s from constraint for name %s",
SystemDictionary::loader_name(probe->loader(n)),
SystemDictionary::loader_name(probe->loader_data(n)),
probe->name()->as_C_string()
);
}
@ -136,22 +137,21 @@ void LoaderConstraintTable::purge_loader_constraints(BoolObjectClosure* is_alive
// Compact array
int num = probe->num_loaders() - 1;
probe->set_num_loaders(num);
probe->set_loader(n, probe->loader(num));
probe->set_loader(num, NULL);
probe->set_loader_data(n, probe->loader_data(num));
probe->set_loader_data(num, NULL);
if (TraceLoaderConstraints) {
ResourceMark rm;
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(i)));
SystemDictionary::loader_name(probe->loader_data(i)));
}
}
continue; // current element replaced, so restart without
// incrementing n
}
}
n++;
}
// Check whether entry should be purged
@ -169,12 +169,9 @@ void LoaderConstraintTable::purge_loader_constraints(BoolObjectClosure* is_alive
} else {
#ifdef ASSERT
if (probe->klass() != NULL) {
assert(is_alive->do_object_b(probe->klass()), "klass should be live");
}
for (n = 0; n < probe->num_loaders(); n++) {
if (probe->loader(n) != NULL) {
assert(is_alive->do_object_b(probe->loader(n)), "loader should be live");
}
ClassLoaderData* loader_data =
probe->klass()->class_loader_data();
assert(!loader_data->is_unloading(), "klass should be live");
}
#endif
// Go to next entry
@ -185,14 +182,14 @@ void LoaderConstraintTable::purge_loader_constraints(BoolObjectClosure* is_alive
}
bool LoaderConstraintTable::add_entry(Symbol* class_name,
klassOop klass1, Handle class_loader1,
klassOop klass2, Handle class_loader2) {
Klass* klass1, Handle class_loader1,
Klass* klass2, Handle class_loader2) {
int failure_code = 0; // encode different reasons for failing
if (klass1 != NULL && klass2 != NULL && klass1 != klass2) {
failure_code = 1;
} else {
klassOop klass = klass1 != NULL ? klass1 : klass2;
Klass* klass = klass1 != NULL ? klass1 : klass2;
LoaderConstraintEntry** pp1 = find_loader_constraint(class_name,
class_loader1);
@ -224,7 +221,7 @@ bool LoaderConstraintTable::add_entry(Symbol* class_name,
int index = hash_to_index(hash);
LoaderConstraintEntry* p;
p = new_entry(hash, class_name, klass, 2, 2);
p->set_loaders(NEW_C_HEAP_ARRAY(oop, 2, mtClass));
p->set_loaders(NEW_C_HEAP_ARRAY(ClassLoaderData*, 2, mtClass));
p->set_loader(0, class_loader1());
p->set_loader(1, class_loader2());
p->set_klass(klass);
@ -319,11 +316,11 @@ bool LoaderConstraintTable::check_or_update(instanceKlassHandle k,
}
}
klassOop LoaderConstraintTable::find_constrained_klass(Symbol* name,
Klass* LoaderConstraintTable::find_constrained_klass(Symbol* name,
Handle loader) {
LoaderConstraintEntry *p = *(find_loader_constraint(name, loader));
if (p != NULL && p->klass() != NULL) {
if (Klass::cast(p->klass())->oop_is_instance() && !instanceKlass::cast(p->klass())->is_loaded()) {
if (Klass::cast(p->klass())->oop_is_instance() && !InstanceKlass::cast(p->klass())->is_loaded()) {
// Only return fully loaded classes. Classes found through the
// constraints might still be in the process of loading.
return NULL;
@ -340,10 +337,10 @@ void LoaderConstraintTable::ensure_loader_constraint_capacity(
int nfree) {
if (p->max_loaders() - p->num_loaders() < nfree) {
int n = nfree + p->num_loaders();
oop* new_loaders = NEW_C_HEAP_ARRAY(oop, n, mtClass);
memcpy(new_loaders, p->loaders(), sizeof(oop) * p->num_loaders());
ClassLoaderData** new_loaders = NEW_C_HEAP_ARRAY(ClassLoaderData*, n, mtClass);
memcpy(new_loaders, p->loaders(), sizeof(ClassLoaderData*) * p->num_loaders());
p->set_max_loaders(n);
FREE_C_HEAP_ARRAY(oop, p->loaders(), mtClass);
FREE_C_HEAP_ARRAY(ClassLoaderData*, p->loaders(), mtClass);
p->set_loaders(new_loaders);
}
}
@ -351,7 +348,7 @@ void LoaderConstraintTable::ensure_loader_constraint_capacity(
void LoaderConstraintTable::extend_loader_constraint(LoaderConstraintEntry* p,
Handle loader,
klassOop klass) {
Klass* klass) {
ensure_loader_constraint_capacity(p, 1);
int num = p->num_loaders();
p->set_loader(num, loader());
@ -376,7 +373,7 @@ void LoaderConstraintTable::extend_loader_constraint(LoaderConstraintEntry* p,
void LoaderConstraintTable::merge_loader_constraints(
LoaderConstraintEntry** pp1,
LoaderConstraintEntry** pp2,
klassOop klass) {
Klass* klass) {
// make sure *pp1 has higher capacity
if ((*pp1)->max_loaders() < (*pp2)->max_loaders()) {
LoaderConstraintEntry** tmp = pp2;
@ -391,7 +388,7 @@ void LoaderConstraintTable::merge_loader_constraints(
for (int i = 0; i < p2->num_loaders(); i++) {
int num = p1->num_loaders();
p1->set_loader(num, p2->loader(i));
p1->set_loader_data(num, p2->loader_data(i));
p1->set_num_loaders(num + 1);
}
@ -403,7 +400,7 @@ void LoaderConstraintTable::merge_loader_constraints(
for (int i = 0; i < p1->num_loaders(); i++) {
tty->print_cr("[ [%d]: %s", i,
SystemDictionary::loader_name(p1->loader(i)));
SystemDictionary::loader_name(p1->loader_data(i)));
}
if (p1->klass() == NULL) {
tty->print_cr("[... and setting class object]");
@ -439,33 +436,33 @@ void LoaderConstraintTable::verify(Dictionary* dictionary,
probe != NULL;
probe = probe->next()) {
if (probe->klass() != NULL) {
instanceKlass* ik = instanceKlass::cast(probe->klass());
InstanceKlass* ik = InstanceKlass::cast(probe->klass());
guarantee(ik->name() == probe->name(), "name should match");
Symbol* name = ik->name();
Handle loader(thread, ik->class_loader());
unsigned int d_hash = dictionary->compute_hash(name, loader);
ClassLoaderData* loader_data = ik->class_loader_data();
unsigned int d_hash = dictionary->compute_hash(name, loader_data);
int d_index = dictionary->hash_to_index(d_hash);
klassOop k = dictionary->find_class(d_index, d_hash, name, loader);
Klass* k = dictionary->find_class(d_index, d_hash, name, loader_data);
if (k != NULL) {
// We found the class in the system dictionary, so we should
// make sure that the klassOop matches what we already have.
// make sure that the Klass* matches what we already have.
guarantee(k == probe->klass(), "klass should be in dictionary");
} else {
// If we don't find the class in the system dictionary, it
// has to be in the placeholders table.
unsigned int p_hash = placeholders->compute_hash(name, loader);
unsigned int p_hash = placeholders->compute_hash(name, loader_data);
int p_index = placeholders->hash_to_index(p_hash);
PlaceholderEntry* entry = placeholders->get_entry(p_index, p_hash,
name, loader);
name, loader_data);
// The instanceKlass might not be on the entry, so the only
// The InstanceKlass might not be on the entry, so the only
// thing we can check here is whether we were successful in
// finding the class in the placeholders table.
guarantee(entry != NULL, "klass should be in the placeholders");
}
}
for (int n = 0; n< probe->num_loaders(); n++) {
guarantee(probe->loader(n)->is_oop_or_null(), "should be oop");
assert(ClassLoaderDataGraph::contains_loader_data(probe->loader_data(n)), "The loader is missing");
}
}
}
@ -487,7 +484,7 @@ void LoaderConstraintTable::print() {
probe->name()->print();
tty->print(" , loaders:");
for (int n = 0; n < probe->num_loaders(); n++) {
probe->loader(n)->print_value();
probe->loader_data(n)->print_value();
tty->print(", ");
}
tty->cr();