/* * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. *
*/
// For this class name, these are the set of LoaderConstraints for classes loaded with this name. class ConstraintSet { // copied into hashtable as value private:
GrowableArray<LoaderConstraint*>* _constraints; // loader constraints for this class name.
void LoaderConstraint::extend_loader_constraint(Symbol* class_name,
Handle loader,
InstanceKlass* klass) {
add_loader(loader());
LogTarget(Info, class, loader, constraints) lt; if (lt.is_enabled()) {
ResourceMark rm;
lt.print("extending constraint for name %s by adding loader: %s %s",
class_name->as_C_string(),
ClassLoaderData::class_loader_data(loader())->loader_name_and_id(),
_klass == NULL ? " and setting class object" : "");
} if (_klass == NULL) {
set_klass(klass);
} else {
assert(klass == NULL || _klass == klass, "constraints corrupted");
}
}
// The loaderConstraintTable must always be accessed with the // SystemDictionary lock held. This is true even for readers as // entries in the table could be being dynamically resized.
for (int i = 0; i < set->num_constraints(); i++) {
LoaderConstraint* p = set->constraint_at(i); for (int i = p->num_loaders() - 1; i >= 0; i--) { if (p->loader_data(i) == loader_data && // skip unloaded klasses
(p->klass() == nullptr ||
p->klass()->is_loader_alive())) { return p;
}
}
} return nullptr;
}
// Either add it to an existing entry in the table or make a new one. void LoaderConstraintTable::add_loader_constraint(Symbol* name, InstanceKlass* klass, oop class_loader1, oop class_loader2) {
assert_lock_strong(SystemDictionary_lock);
LoaderConstraint* constraint = new LoaderConstraint(klass, class_loader1, class_loader2);
// The klass may be null if it hasn't been loaded yet, for instance while checking // a parameter name to a method call. We impose this constraint that the // class that is eventually loaded must match between these two loaders. bool created;
ConstraintSet* set = _loader_constraint_table.put_if_absent(name, &created); if (created) {
set->initialize(constraint);
} else {
set->add_constraint(constraint);
}
}
class PurgeUnloadedConstraints : public StackObj { public: bool do_entry(SymbolHandle& name, ConstraintSet& set) {
LogTarget(Info, class, loader, constraints) lt; int len = set.num_constraints(); for (int i = len - 1; i >= 0; i--) {
LoaderConstraint* probe = set.constraint_at(i);
InstanceKlass* klass = probe->klass(); // Remove klass that is no longer alive if (klass != NULL &&
!klass->is_loader_alive()) {
probe->set_klass(NULL); if (lt.is_enabled()) {
ResourceMark rm;
lt.print("purging class object from constraint for name %s," " loader list:",
name->as_C_string()); for (int i = 0; i < probe->num_loaders(); i++) {
lt.print(" [%d]: %s", i,
probe->loader_data(i)->loader_name_and_id());
}
}
}
// Remove entries no longer alive from loader array for (int n = probe->num_loaders() - 1; n >= 0; n--) { if (probe->loader_data(n)->is_unloading()) { if (lt.is_enabled()) {
ResourceMark rm;
lt.print("purging loader %s from constraint for name %s",
probe->loader_data(n)->loader_name_and_id(),
name->as_C_string());
}
probe->remove_loader_at(n);
if (lt.is_enabled()) {
ResourceMark rm;
lt.print("new loader list:"); for (int i = 0; i < probe->num_loaders(); i++) {
lt.print(" [%d]: %s", i,
probe->loader_data(i)->loader_name_and_id());
}
}
}
} // Check whether the set should be purged if (probe->num_loaders() < 2) { if (lt.is_enabled()) {
ResourceMark rm;
lt.print("purging complete constraint for name %s",
name->as_C_string());
}
set.remove_constraint(probe);
} else { #ifdef ASSERT if (probe->klass() != NULL) {
assert(probe->klass()->is_loader_alive(), "klass should be live");
} #endif
}
} if (set.num_constraints() == 0) { returntrue;
} // Don't unlink this set returnfalse;
}
};
LogTarget(Info, class, loader, constraints) lt; if (klass1 != NULL && klass2 != NULL) { if (klass1 == klass2) { // Same type already loaded in both places. There is no need for any constraint. returntrue;
} else {
log_ldr_constraint_msg(class_name, "The class objects presented by loader[0] and loader[1] " "are different",
class_loader1, class_loader2); returnfalse;
}
}
InstanceKlass* klass = klass1 != NULL ? klass1 : klass2;
LoaderConstraint* pp1 = find_loader_constraint(class_name, class_loader1); if (pp1 != NULL && pp1->klass() != NULL) { if (klass != NULL) { if (klass != pp1->klass()) {
log_ldr_constraint_msg(class_name, "The class object presented by loader[0] does not match " "the stored class object in the constraint",
class_loader1, class_loader2); returnfalse;
}
} else {
klass = pp1->klass();
}
}
LoaderConstraint* pp2 = find_loader_constraint(class_name, class_loader2); if (pp2 != NULL && pp2->klass() != NULL) { if (klass != NULL) { if (klass != pp2->klass()) {
log_ldr_constraint_msg(class_name, "The class object presented by loader[1] does not match " "the stored class object in the constraint",
class_loader1, class_loader2); returnfalse;
}
} else {
klass = pp2->klass();
}
}
// return true if the constraint was updated, false if the constraint is // violated bool LoaderConstraintTable::check_or_update(InstanceKlass* k,
Handle loader,
Symbol* name) {
LogTarget(Info, class, loader, constraints) lt;
LoaderConstraint* p = find_loader_constraint(name, loader); if (p && p->klass() != NULL && p->klass() != k) { if (lt.is_enabled()) {
ResourceMark rm;
lt.print("constraint check failed for name %s, loader %s: " "the presented class object differs from that stored",
name->as_C_string(),
ClassLoaderData::class_loader_data(loader())->loader_name_and_id());
} returnfalse;
} else { if (p && p->klass() == NULL) {
p->set_klass(k); if (lt.is_enabled()) {
ResourceMark rm;
lt.print("updating constraint for name %s, loader %s, " "by setting class object",
name->as_C_string(),
ClassLoaderData::class_loader_data(loader())->loader_name_and_id());
}
} returntrue;
}
}
InstanceKlass* LoaderConstraintTable::find_constrained_klass(Symbol* name,
Handle loader) {
LoaderConstraint *p = find_loader_constraint(name, loader); if (p != NULL && p->klass() != NULL) {
assert(p->klass()->is_instance_klass(), "sanity"); if (!p->klass()->is_loaded()) { // Only return fully loaded classes. Classes found through the // constraints might still be in the process of loading. return NULL;
} return p->klass();
}
// No constraints, or else no klass loaded yet. return NULL;
}
// Copy into the longer of the constraints.
LoaderConstraint* dest = p1->num_loaders() <= p2->num_loaders() ? p2 : p1;
LoaderConstraint* src = dest == p1 ? p2 : p1;
for (int i = 0; i < src->num_loaders(); i++) { // We don't seem to care about duplicates.
dest->add_loader_data(src->loader_data(i));
}
LogTarget(Info, class, loader, constraints) lt; if (lt.is_enabled()) {
ResourceMark rm;
lt.print("merged constraints for name %s, new loader list:", class_name->as_C_string());
for (int i = 0; i < dest->num_loaders(); i++) {
lt.print(" [%d]: %s", i, dest->loader_data(i)->loader_name_and_id());
} if (dest->klass() == NULL) {
lt.print("... and setting class object");
}
}
// dest->klass() will hold NULL if klass, src->klass(), and old // dest->klass() are all NULL. In addition, all three must have // matching non-NULL values, otherwise either the constraints would // have been violated, or the constraints had been corrupted (and an // assertion would fail). if (src->klass() != NULL) {
assert(src->klass() == klass, "constraints corrupted");
} if (dest->klass() == NULL) {
dest->set_klass(klass);
} else {
assert(dest->klass() == klass, "constraints corrupted");
}
// Remove src from set
ConstraintSet* set = _loader_constraint_table.get(class_name);
set->remove_constraint(src);
}
void LoaderConstraintTable::verify() {
Thread* thread = Thread::current(); auto check = [&] (SymbolHandle& key, ConstraintSet& set) { // foreach constraint in the set, check the klass is in the dictionary or placeholder table. int len = set.num_constraints(); for (int i = 0; i < len; i++) {
LoaderConstraint* probe = set.constraint_at(i); if (probe->klass() != NULL) {
InstanceKlass* ik = probe->klass();
guarantee(key == ik->name(), "name should match");
Symbol* name = ik->name();
ClassLoaderData* loader_data = ik->class_loader_data();
Dictionary* dictionary = loader_data->dictionary();
InstanceKlass* k = dictionary->find_class(thread, name); if (k != NULL) { // We found the class in the dictionary, so we should // 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 dictionary, it // has to be in the placeholders table.
PlaceholderEntry* entry = PlaceholderTable::get_entry(name, loader_data);
// 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++) {
assert(ClassLoaderDataGraph::contains_loader_data(probe->loader_data(n)), "The loader is missing");
}
}
};
assert_locked_or_safepoint(SystemDictionary_lock);
_loader_constraint_table.iterate_all(check);
}
void LoaderConstraintTable::print_table_statistics(outputStream* st) { auto size = [&] (SymbolHandle& key, ConstraintSet& set) { // sizeof set is included in the size of the hashtable node int sum = 0; int len = set.num_constraints(); for (int i = 0; i < len; i++) {
LoaderConstraint* probe = set.constraint_at(i);
sum += sizeof(*probe) + (probe->num_loaders() * sizeof(ClassLoaderData*));
} return sum;
};
TableStatistics ts = _loader_constraint_table.statistics_calculate(size);
ts.print(st, "LoaderConstraintTable");
}
// Called with the system dictionary lock held void LoaderConstraintTable::print_on(outputStream* st) { auto printer = [&] (SymbolHandle& key, ConstraintSet& set) { int len = set.num_constraints(); for (int i = 0; i < len; i++) {
LoaderConstraint* probe = set.constraint_at(i);
st->print("Symbol: %s loaders:", key->as_C_string()); for (int n = 0; n < probe->num_loaders(); n++) {
st->cr();
st->print(" ");
probe->loader_data(n)->print_value_on(st);
}
st->cr();
}
};
assert_locked_or_safepoint(SystemDictionary_lock);
ResourceMark rm;
st->print_cr("Java loader constraints (table_size=%d, constraints=%d)",
_loader_constraint_table.table_size(), _loader_constraint_table.number_of_entries());
_loader_constraint_table.iterate_all(printer);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.