< prev index next >

src/hotspot/share/classfile/systemDictionaryShared.cpp

Print this page
@@ -32,10 +32,11 @@
  #include "cds/classListWriter.hpp"
  #include "cds/dumpTimeClassInfo.inline.hpp"
  #include "cds/dynamicArchive.hpp"
  #include "cds/filemap.hpp"
  #include "cds/heapShared.hpp"
+ #include "cds/lambdaFormInvokers.inline.hpp"
  #include "cds/metaspaceShared.hpp"
  #include "cds/runTimeClassInfo.hpp"
  #include "cds/unregisteredClasses.hpp"
  #include "classfile/classFileStream.hpp"
  #include "classfile/classLoader.hpp"

@@ -62,10 +63,11 @@
  #include "memory/resourceArea.hpp"
  #include "memory/universe.hpp"
  #include "oops/compressedKlass.inline.hpp"
  #include "oops/instanceKlass.hpp"
  #include "oops/klass.inline.hpp"
+ #include "oops/methodData.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "oops/objArrayOop.inline.hpp"
  #include "oops/oop.inline.hpp"
  #include "oops/oopHandle.inline.hpp"
  #include "oops/typeArrayOop.inline.hpp"

@@ -81,10 +83,12 @@
  SystemDictionaryShared::ArchiveInfo SystemDictionaryShared::_dynamic_archive;
  
  DumpTimeSharedClassTable* SystemDictionaryShared::_dumptime_table = nullptr;
  DumpTimeLambdaProxyClassDictionary* SystemDictionaryShared::_dumptime_lambda_proxy_class_dictionary = nullptr;
  
+ static bool _ignore_new_classes = false;
+ 
  // Used by NoClassLoadingMark
  DEBUG_ONLY(bool SystemDictionaryShared::_class_loading_may_happen = true;)
  
  #ifdef ASSERT
  static void check_klass_after_loading(const Klass* k) {

@@ -104,12 +108,15 @@
    if (ik != nullptr && !ik->shared_loading_failed()) {
      if ((SystemDictionary::is_system_class_loader(class_loader()) && ik->is_shared_app_class())  ||
          (SystemDictionary::is_platform_class_loader(class_loader()) && ik->is_shared_platform_class())) {
        SharedClassLoadingMark slm(THREAD, ik);
        PackageEntry* pkg_entry = CDSProtectionDomain::get_package_entry_from_class(ik, class_loader);
-       Handle protection_domain =
-         CDSProtectionDomain::init_security_info(class_loader, ik, pkg_entry, CHECK_NULL);
+       Handle protection_domain;
+       if (!class_name->starts_with("jdk/proxy")) // java/lang/reflect/Proxy$ProxyBuilder defines the proxy classes with a null protection domain.
+       {
+         protection_domain = CDSProtectionDomain::init_security_info(class_loader, ik, pkg_entry, CHECK_NULL);
+       }
        return load_shared_class(ik, class_loader, protection_domain, nullptr, pkg_entry, THREAD);
      }
    }
    return nullptr;
  }

@@ -272,10 +279,15 @@
    } else {
      return false;
    }
  }
  
+ void SystemDictionaryShared::ignore_new_classes() {
+   _ignore_new_classes = true;
+ }
+ 
+ 
  bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
    if (CDSConfig::is_dumping_final_static_archive() && k->is_shared_unregistered_class()
        && k->is_shared()) {
      return false; // Do not exclude: unregistered classes are passed from preimage to final image.
    }

@@ -317,11 +329,13 @@
    if (is_jfr_event_class(k)) {
      // We cannot include JFR event classes because they need runtime-specific
      // instrumentation in order to work with -XX:FlightRecorderOptions:retransform=false.
      // There are only a small number of these classes, so it's not worthwhile to
      // support them and make CDS more complicated.
-     return warn_excluded(k, "JFR event class");
+     if (!CDSConfig::is_dumping_reflection_data()) { // FIXME: !!! HACK !!!
+       return warn_excluded(k, "JFR event class");
+     }
    }
  
    if (!k->is_linked()) {
      if (has_class_failed_verification(k)) {
        return warn_excluded(k, "Failed verification");

@@ -336,11 +350,11 @@
        // When dumping the final static archive, we will unconditionally load and link all
        // classes from tje preimage. We don't want to get a VerifyError when linking this class.
        return warn_excluded(k, "Unlinked class not supported by AOTConfiguration");
      }
    } else {
-     if (!k->can_be_verified_at_dumptime()) {
+     if (!k->can_be_verified_at_dumptime() && !CDSConfig::preserve_all_dumptime_verification_states(k)) {
        // We have an old class that has been linked (e.g., it's been executed during
        // dump time). This class has been verified using the old verifier, which
        // doesn't save the verification constraints, so check_verification_constraints()
        // won't work at runtime.
        // As a result, we cannot store this class. It must be loaded and fully verified

@@ -367,14 +381,21 @@
      }
    }
  
    if (k == UnregisteredClasses::UnregisteredClassLoader_klass()) {
      ResourceMark rm;
-     log_info(cds)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string());
+     log_debug(cds)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string());
+     return true;
+   }
+ 
+   if (k->name()->equals("jdk/internal/misc/CDS$DummyForDynamicArchive") && !CDSConfig::is_dumping_dynamic_archive()) {
+     ResourceMark rm;
+     log_debug(cds)("Skipping %s: used only when dumping dynamic CDS archive", k->name()->as_C_string());
      return true;
    }
  
+ 
    return false; // false == k should NOT be excluded
  }
  
  bool SystemDictionaryShared::is_builtin_loader(ClassLoaderData* loader_data) {
    oop class_loader = loader_data->class_loader();

@@ -511,11 +532,19 @@
  }
  
  void SystemDictionaryShared::init_dumptime_info(InstanceKlass* k) {
    MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
    assert(SystemDictionaryShared::class_loading_may_happen(), "sanity");
-   _dumptime_table->allocate_info(k);
+   DumpTimeClassInfo* info = _dumptime_table->allocate_info(k);
+   if (_ignore_new_classes) {
+     if (!LambdaFormInvokers::may_be_regenerated_class(k->name())) {
+       ResourceMark rm;
+       log_debug(cds)("Skipping %s: Class loaded for lambda form invoker regeneration", k->name()->as_C_string());
+       info->set_has_checked_exclusion();
+       info->set_excluded();
+     }
+   }
  }
  
  void SystemDictionaryShared::remove_dumptime_info(InstanceKlass* k) {
    MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
    _dumptime_table->remove(k);

@@ -764,10 +793,21 @@
  }
  
  bool SystemDictionaryShared::add_verification_constraint(InstanceKlass* k, Symbol* name,
           Symbol* from_name, bool from_field_is_protected, bool from_is_array, bool from_is_object) {
    assert(CDSConfig::is_dumping_archive(), "sanity");
+   if (CDSConfig::is_dumping_dynamic_archive() && k->is_shared()) {
+     // k is a new class in the static archive, but one of its supertypes is an old class, so k wasn't
+     // verified during dump time. No need to record constraints as k won't be included in the dynamic archive.
+     return false;
+   }
+   if (CDSConfig::is_dumping_aot_linked_classes() && is_builtin(k)) {
+     // There's no need to save verification constraints
+     // TODO -- double check the logic before integrating into mainline!!
+     return false;
+   }
+ 
    DumpTimeClassInfo* info = get_info(k);
    info->add_verification_constraint(k, name, from_name, from_field_is_protected,
                                      from_is_array, from_is_object);
  
    if (CDSConfig::is_dumping_dynamic_archive()) {

@@ -818,10 +858,11 @@
    if (CDSConfig::is_dumping_invokedynamic()) {
      // The lambda proxy classes will be stored as part of aot-resolved constant pool entries.
      // There's no need to remember them in a separate table.
      return;
    }
+ 
    if (CDSConfig::is_dumping_preimage_static_archive()) {
      // Information about lambda proxies are recorded in FinalImageRecipes.
      return;
    }
  

@@ -928,11 +969,11 @@
        prev_klass->set_next_link(nullptr);
        proxy_klass = curr_klass;
        proxy_klass->clear_lambda_proxy_is_available();
        if (log_is_enabled(Debug, cds)) {
          ResourceMark rm;
-         log_debug(cds)("Loaded lambda proxy: %s ", proxy_klass->external_name());
+         log_debug(cds)("Loaded lambda proxy: " PTR_FORMAT " %s ", p2i(proxy_klass), proxy_klass->external_name());
        }
      }
    }
    return proxy_klass;
  }

@@ -1261,11 +1302,11 @@
  
    return total_size;
  }
  
  unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) {
-   if (ArchiveBuilder::is_active()) {
+   if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space(ptr)) {
      uintx offset = ArchiveBuilder::current()->any_to_offset(ptr);
      unsigned int hash = primitive_hash<uintx>(offset);
      DEBUG_ONLY({
          if (MetaspaceObj::is_shared((const MetaspaceObj*)ptr)) {
            assert(hash == SystemDictionaryShared::hash_for_shared_dictionary_quick(ptr), "must be");

@@ -1419,14 +1460,11 @@
    unsigned int hash = SystemDictionaryShared::hash_for_shared_dictionary_quick(name);
    const RunTimeClassInfo* record = nullptr;
    if (DynamicArchive::is_mapped()) {
      // Use the regenerated holder classes in the dynamic archive as they
      // have more methods than those in the base archive.
-     if (name == vmSymbols::java_lang_invoke_Invokers_Holder() ||
-         name == vmSymbols::java_lang_invoke_DirectMethodHandle_Holder() ||
-         name == vmSymbols::java_lang_invoke_LambdaForm_Holder() ||
-         name == vmSymbols::java_lang_invoke_DelegatingMethodHandle_Holder()) {
+     if (LambdaFormInvokers::may_be_regenerated_class(name)) {
        record = dynamic_dict->lookup(name, hash, 0);
        if (record != nullptr) {
          return record;
        }
      }

@@ -1467,11 +1505,11 @@
    assert(CDSConfig::is_dumping_static_archive(), "class ID is used only for static dump (from classlist)");
    DumpTimeClassInfo* info = get_info(k);
    info->_id = id;
  }
  
- static const char* class_loader_name_for_shared(Klass* k) {
+ const char* SystemDictionaryShared::class_loader_name_for_shared(Klass* k) {
    assert(k != nullptr, "Sanity");
    assert(k->is_shared(), "Must be");
    assert(k->is_instance_klass(), "Must be");
    InstanceKlass* ik = InstanceKlass::cast(k);
    if (ik->is_shared_boot_class()) {

@@ -1494,11 +1532,11 @@
    SharedDictionaryPrinter(outputStream* st) : _st(st), _index(0) {}
  
    void do_value(const RunTimeClassInfo* record) {
      ResourceMark rm;
      _st->print_cr("%4d: %s %s", _index++, record->klass()->external_name(),
-         class_loader_name_for_shared(record->klass()));
+         SystemDictionaryShared::class_loader_name_for_shared(record->klass()));
      if (record->klass()->array_klasses() != nullptr) {
        record->klass()->array_klasses()->cds_print_value_on(_st);
        _st->cr();
      }
    }

@@ -1515,11 +1553,11 @@
      if (record->proxy_klass_head()->lambda_proxy_is_available()) {
        ResourceMark rm;
        Klass* k = record->proxy_klass_head();
        while (k != nullptr) {
          _st->print_cr("%4d: %s %s", _index++, k->external_name(),
-                       class_loader_name_for_shared(k));
+                       SystemDictionaryShared::class_loader_name_for_shared(k));
          k = k->next_link();
        }
      }
    }
  };

@@ -1608,5 +1646,59 @@
  void SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary() {
    assert_lock_strong(DumpTimeTable_lock);
    CleanupDumpTimeLambdaProxyClassTable cleanup_proxy_classes;
    _dumptime_lambda_proxy_class_dictionary->unlink(&cleanup_proxy_classes);
  }
+ 
+ void SystemDictionaryShared::create_loader_positive_lookup_cache(TRAPS) {
+   GrowableArray<InstanceKlass*> shared_classes_list;
+   {
+     // With static dumping, we have only a single Java thread (see JVM_StartThread) so
+     // no no other threads should be loading classes. Otherwise, the code below may miss some
+     // classes that are loaded concurrently.
+     assert(CDSConfig::is_dumping_static_archive(), "no other threads should be loading classes");
+ 
+     MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
+     _dumptime_table->iterate_all_classes_in_builtin_loaders([&](InstanceKlass* k, DumpTimeClassInfo& info) {
+         if (!k->is_hidden() && !check_for_exclusion(k, &info)) {
+           shared_classes_list.append(k);
+         }
+       }
+     );
+   }
+ 
+   InstanceKlass* ik = vmClasses::Class_klass();
+   objArrayOop r = oopFactory::new_objArray(ik, shared_classes_list.length(), CHECK);
+   objArrayHandle array_h(THREAD, r);
+ 
+   for (int i = 0; i < shared_classes_list.length(); i++) {
+     oop mirror = shared_classes_list.at(i)->java_mirror();
+     Handle mirror_h(THREAD, mirror);
+     array_h->obj_at_put(i, mirror_h());
+   }
+ 
+   TempNewSymbol method = SymbolTable::new_symbol("generatePositiveLookupCache");
+   TempNewSymbol signature = SymbolTable::new_symbol("([Ljava/lang/Class;)V");
+ 
+   JavaCallArguments args(Handle(THREAD, SystemDictionary::java_system_loader()));
+   args.push_oop(array_h);
+   JavaValue result(T_VOID);
+   JavaCalls::call_virtual(&result,
+                           vmClasses::jdk_internal_loader_ClassLoaders_AppClassLoader_klass(),
+                           method,
+                           signature,
+                           &args,
+                           CHECK);
+ 
+   if (HAS_PENDING_EXCEPTION) {
+     Handle exc_handle(THREAD, PENDING_EXCEPTION);
+     CLEAR_PENDING_EXCEPTION;
+     ResourceMark rm(THREAD);
+ 
+     log_warning(cds)("Exception during AppClassLoader::generatePositiveLookupCache() call");
+     LogStreamHandle(Debug, cds) log;
+     if (log.is_enabled()) {
+       java_lang_Throwable::print_stack_trace(exc_handle, &log);
+     }
+     return;
+   }
+ }
< prev index next >