Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  loaderConstraints.cpp   Sprache: C

 
/*
 * 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.
 *
 */


#include "precompiled.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderDataGraph.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/loaderConstraints.hpp"
#include "classfile/placeholders.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "oops/klass.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbolHandle.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
#include "utilities/resourceHash.hpp"

// Implementation Classes for Loader Constraints

class LoaderConstraint : public CHeapObj<mtClass> {
  InstanceKlass*         _klass;
  // Loader constraints enforce correct linking behavior.
  // Thus, it really operates on ClassLoaderData which represents linking domain,
  // not class loaders.
  GrowableArray<ClassLoaderData*>*  _loaders;                // initiating loaders
 public:
  LoaderConstraint(InstanceKlass* klass, oop class_loader1, oop class_loader2) :
     _klass(klass) {
    _loaders = new (mtClass) GrowableArray<ClassLoaderData*>(10, mtClass);
    add_loader(class_loader1);
    add_loader(class_loader2);
  }
  LoaderConstraint(const LoaderConstraint& src) = delete;
  LoaderConstraint& operator=(const LoaderConstraint&) = delete;

  ~LoaderConstraint() { delete _loaders; }

  InstanceKlass* klass() const     { return _klass; }
  void set_klass(InstanceKlass* k) { _klass = k; }

  void extend_loader_constraint(Symbol* class_name, Handle loader, InstanceKlass* klass);

  int num_loaders() const { return _loaders->length(); }
  ClassLoaderData* loader_data(int i) { return _loaders->at(i); }
  void add_loader_data(ClassLoaderData* p) { _loaders->push(p); }

  void remove_loader_at(int n) {
    assert(_loaders->at(n)->is_unloading(), "should be unloading");
    _loaders->remove_at(n);
  }

  // convenience
  void add_loader(oop p) {
    _loaders->push(ClassLoaderData::class_loader_data(p));
  }
};

// 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.

 public:
  ConstraintSet() : _constraints(nullptr) {}
  ConstraintSet(const ConstraintSet&) = delete;
  ConstraintSet& operator=(const ConstraintSet&) = delete;

  void initialize(LoaderConstraint* constraint) {
    _constraints = new (mtClass) GrowableArray<LoaderConstraint*>(5, mtClass);
    _constraints->push(constraint);
  }

  ~ConstraintSet() {
    delete _constraints;
  }

  int num_constraints() const { return _constraints->length(); }
  LoaderConstraint* constraint_at(int i) const { return _constraints->at(i); }

  void add_constraint(LoaderConstraint* new_constraint) {
    _constraints->push(new_constraint);
  }

  void remove_constraint(LoaderConstraint* constraint) {
    _constraints->remove(constraint);
    delete constraint;
  }
};


ResourceHashtable<SymbolHandle, ConstraintSet, 107, AnyObj::C_HEAP, mtClass, SymbolHandle::compute_hash> _loader_constraint_table;

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.

LoaderConstraint* LoaderConstraintTable::find_loader_constraint(
                                    Symbol* name, Handle loader) {

  assert_lock_strong(SystemDictionary_lock);
  ConstraintSet* set = _loader_constraint_table.get(name);
  if (set == nullptr) {
    return nullptr;
  }

  ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(loader());

  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) {
      return true;
    }
    // Don't unlink this set
    return false;
  }
};

void LoaderConstraintTable::purge_loader_constraints() {
  assert_locked_or_safepoint(SystemDictionary_lock);
  // Remove unloaded entries from constraint table
  PurgeUnloadedConstraints purge;
  _loader_constraint_table.unlink(&purge);
}

void log_ldr_constraint_msg(Symbol* class_name, const char* reason,
                        Handle class_loader1, Handle class_loader2) {
  LogTarget(Info, class, loader, constraints) lt;
  if (lt.is_enabled()) {
    ResourceMark rm;
    lt.print("Failed to add constraint for name: %s, loader[0]: %s,"
                " loader[1]: %s, Reason: %s",
                  class_name->as_C_string(),
                  ClassLoaderData::class_loader_data(class_loader1())->loader_name_and_id(),
                  ClassLoaderData::class_loader_data(class_loader2())->loader_name_and_id(),
                  reason);
  }
}

bool LoaderConstraintTable::add_entry(Symbol* class_name,
                                      InstanceKlass* klass1, Handle class_loader1,
                                      InstanceKlass* klass2, Handle class_loader2) {

  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.
      return true;
    } else {
      log_ldr_constraint_msg(class_name,
                             "The class objects presented by loader[0] and loader[1] "
                             "are different",
                             class_loader1, class_loader2);
      return false;
    }
  }

  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);
        return false;
      }
    } 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);
        return false;
      }
    } else {
      klass = pp2->klass();
    }
  }

  if (pp1 == NULL && pp2 == NULL) {

    add_loader_constraint(class_name, klass, class_loader1(), class_loader2());
    if (lt.is_enabled()) {
      ResourceMark rm;
      lt.print("adding new constraint for name: %s, loader[0]: %s,"
                    " loader[1]: %s",
                    class_name->as_C_string(),
                    ClassLoaderData::class_loader_data(class_loader1())->loader_name_and_id(),
                    ClassLoaderData::class_loader_data(class_loader2())->loader_name_and_id()
                    );
    }
  } else if (pp1 == pp2) {
    /* constraint already imposed */
    if (pp1->klass() == NULL) {
      pp1->set_klass(klass);
      if (lt.is_enabled()) {
        ResourceMark rm;
        lt.print("setting class object in existing constraint for"
                      " name: %s and loader %s",
                      class_name->as_C_string(),
                      ClassLoaderData::class_loader_data(class_loader1())->loader_name_and_id()
                      );
      }
    } else {
      assert(pp1->klass() == klass, "loader constraints corrupted");
    }
  } else if (pp1 == NULL) {
    pp2->extend_loader_constraint(class_name, class_loader1, klass);
  } else if (pp2 == NULL) {
    pp1->extend_loader_constraint(class_name, class_loader2, klass);
  } else {
    merge_loader_constraints(class_name, pp1, pp2, klass);
  }

  return true;
}

// 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());
    }
    return false;
  } 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());
      }
    }
    return true;
  }
}

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;
}

void LoaderConstraintTable::merge_loader_constraints(Symbol* class_name,
                                                     LoaderConstraint* p1,
                                                     LoaderConstraint* p2,
                                                     InstanceKlass* klass) {

  // 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);
}

void LoaderConstraintTable::print() { print_on(tty); }

86%


¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge