< prev index next >

src/hotspot/share/classfile/systemDictionary.cpp

Print this page
@@ -52,10 +52,12 @@
  #include "memory/metaspaceClosure.hpp"
  #include "memory/oopFactory.hpp"
  #include "memory/resourceArea.hpp"
  #include "memory/universe.hpp"
  #include "oops/access.inline.hpp"
+ #include "oops/fieldStreams.inline.hpp"
+ #include "oops/inlineKlass.inline.hpp"
  #include "oops/instanceKlass.hpp"
  #include "oops/klass.inline.hpp"
  #include "oops/method.inline.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "oops/objArrayOop.inline.hpp"

@@ -69,10 +71,11 @@
  #include "runtime/atomic.hpp"
  #include "runtime/handles.inline.hpp"
  #include "runtime/java.hpp"
  #include "runtime/javaCalls.hpp"
  #include "runtime/mutexLocker.hpp"
+ #include "runtime/os.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/signature.hpp"
  #include "runtime/synchronizer.hpp"
  #include "services/classLoadingService.hpp"
  #include "services/diagnosticCommand.hpp"

@@ -183,17 +186,39 @@
  // Helper function
  inline ClassLoaderData* class_loader_data(Handle class_loader) {
    return ClassLoaderData::class_loader_data(class_loader());
  }
  
+ // These migrated value classes are loaded by the bootstrap class loader but are added to the initiating
+ // loaders automatically so that fields of these types can be found and potentially flattened during
+ // field layout.
+ static void add_migrated_value_classes(ClassLoaderData* cld) {
+   JavaThread* current = JavaThread::current();
+   auto add_klass = [&] (Symbol* classname) {
+     InstanceKlass* ik = SystemDictionary::find_instance_klass(current, classname, Handle(current, nullptr));
+     assert(ik != nullptr, "Must exist");
+     SystemDictionary::add_to_initiating_loader(current, ik, cld);
+   };
+ 
+   MonitorLocker mu1(SystemDictionary_lock);
+   vmSymbols::migrated_class_names_do(add_klass);
+ }
+ 
  ClassLoaderData* SystemDictionary::register_loader(Handle class_loader, bool create_mirror_cld) {
    if (create_mirror_cld) {
      // Add a new class loader data to the graph.
      return ClassLoaderDataGraph::add(class_loader, true);
    } else {
-     return (class_loader() == nullptr) ? ClassLoaderData::the_null_class_loader_data() :
-                                       ClassLoaderDataGraph::find_or_create(class_loader);
+     if (class_loader() == nullptr) {
+       return ClassLoaderData::the_null_class_loader_data();
+     } else {
+       ClassLoaderData* cld = ClassLoaderDataGraph::find_or_create(class_loader);
+       if (EnableValhalla) {
+         add_migrated_value_classes(cld);
+       }
+       return cld;
+     }
    }
  }
  
  void SystemDictionary::set_system_loader(ClassLoaderData *cld) {
    assert(_java_system_loader.is_empty(), "already set!");

@@ -392,11 +417,12 @@
      ls.cr();
    }
  }
  
  // Must be called for any superclass or superinterface resolution
- // during class definition to allow class circularity checking
+ // during class definition, or may be called for inline field layout processing
+ // to detect class circularity errors.
  // superinterface callers:
  //    parse_interfaces - from defineClass
  // superclass callers:
  //   ClassFileParser - from defineClass
  //   load_shared_class - while loading a class from shared archive

@@ -405,14 +431,16 @@
  //      when resolving a class that has an existing placeholder with
  //      a saved superclass [i.e. a defineClass is currently in progress]
  //      If another thread is trying to resolve the class, it must do
  //      superclass checks on its own thread to catch class circularity and
  //      to avoid deadlock.
+ // inline field layout callers:
+ //    The field's class must be loaded to determine layout.
  //
  // resolve_with_circularity_detection adds a DETECT_CIRCULARITY placeholder to the placeholder table before calling
  // resolve_instance_class_or_null. ClassCircularityError is detected when a DETECT_CIRCULARITY or LOAD_INSTANCE
- // placeholder for the same thread, class, classloader is found.
+ // placeholder for the same thread, class, and classloader is found.
  // This can be seen with logging option: -Xlog:class+load+placeholders=debug.
  //
  InstanceKlass* SystemDictionary::resolve_with_circularity_detection(Symbol* class_name,
                                                                      Symbol* next_name,
                                                                      Handle class_loader,

@@ -443,11 +471,11 @@
    // can't throw error holding a lock
    bool throw_circularity_error = false;
    {
      MutexLocker mu(THREAD, SystemDictionary_lock);
  
-     // Must check ClassCircularity before resolving next_name (superclass or interface).
+     // Must check ClassCircularity before resolving next_name (superclass, interface, field types or speculatively preloaded argument types).
      PlaceholderEntry* probe = PlaceholderTable::get_entry(class_name, loader_data);
      if (probe != nullptr && probe->check_seen_thread(THREAD, PlaceholderTable::DETECT_CIRCULARITY)) {
          log_circularity_error(class_name, probe);
          throw_circularity_error = true;
      }

@@ -467,11 +495,11 @@
    if (throw_circularity_error) {
        ResourceMark rm(THREAD);
        THROW_MSG_NULL(vmSymbols::java_lang_ClassCircularityError(), class_name->as_C_string());
    }
  
-   // Resolve the superclass or superinterface, check results on return
+   // Resolve the superclass, superinterface, field type or speculatively preloaded argument types and check results on return.
    InstanceKlass* superk =
      SystemDictionary::resolve_instance_class_or_null(next_name,
                                                       class_loader,
                                                       THREAD);
  

@@ -913,12 +941,11 @@
  // Check if a shared class can be loaded by the specific classloader.
  bool SystemDictionary::is_shared_class_visible(Symbol* class_name,
                                                 InstanceKlass* ik,
                                                 PackageEntry* pkg_entry,
                                                 Handle class_loader) {
-   assert(!ModuleEntryTable::javabase_moduleEntry()->is_patched(),
-          "Cannot use sharing if java.base is patched");
+   assert(!CDSConfig::module_patching_disables_cds(), "Cannot use CDS");
  
    // (1) Check if we are loading into the same loader as in dump time.
  
    if (ik->defined_by_boot_loader()) {
      if (class_loader() != nullptr) {

@@ -990,11 +1017,11 @@
    if (was_archived_from_named_module) {
      if (should_be_in_named_module) {
        // Is the module loaded from the same location as during dump time?
        visible = mod_entry->shared_path_index() == scp_index;
        if (visible) {
-         assert(!mod_entry->is_patched(), "cannot load archived classes for patched module");
+         assert(!CDSConfig::module_patching_disables_cds(), "Cannot use CDS");
        }
      } else {
        // During dump time, this class was in a named module, but at run time, this class should be
        // in an unnamed module.
        visible = false;

@@ -1068,10 +1095,79 @@
    }
  
    return true;
  }
  
+ // Pre-load class referred to in non-static null-free instance field. These fields trigger MANDATORY loading.
+ // Some pre-loading does not fail fatally
+ bool SystemDictionary::preload_from_null_free_field(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS) {
+   TempNewSymbol name = Signature::strip_envelope(sig);
+   log_info(class, preload)("Preloading of class %s during loading of shared class %s. "
+                            "Cause: a null-free non-static field is declared with this type",
+                            name->as_C_string(), ik->name()->as_C_string());
+   InstanceKlass* real_k = SystemDictionary::resolve_with_circularity_detection(ik->name(), name,
+                                                                                class_loader, false, CHECK_false);
+   if (HAS_PENDING_EXCEPTION) {
+     log_warning(class, preload)("Preloading of class %s during loading of class %s "
+                                 "(cause: null-free non-static field) failed: %s",
+                                 name->as_C_string(), ik->name()->as_C_string(),
+                                 PENDING_EXCEPTION->klass()->name()->as_C_string());
+     return false; // Exception is still pending
+   }
+ 
+   InstanceKlass* k = ik->get_inline_type_field_klass_or_null(field_index);
+   if (real_k != k) {
+     // oops, the app has substituted a different version of k! Does not fail fatally
+     log_warning(class, preload)("Preloading of class %s during loading of shared class %s "
+                                 "(cause: null-free non-static field) failed : "
+                                 "app substituted a different version of %s",
+                                 name->as_C_string(), ik->name()->as_C_string(),
+                                 name->as_C_string());
+     return false;
+   }
+   log_info(class, preload)("Preloading of class %s during loading of shared class %s "
+                            "(cause: null-free non-static field) succeeded",
+                            name->as_C_string(), ik->name()->as_C_string());
+ 
+   assert(real_k != nullptr, "Sanity check");
+   InstanceKlass::check_can_be_annotated_with_NullRestricted(real_k, ik->name(), CHECK_false);
+ 
+   return true;
+ }
+ 
+ // Tries to pre-load classes referred to in non-static nullable instance fields if they are found in the
+ // loadable descriptors attribute. If loading fails, we can fail silently.
+ void SystemDictionary::try_preload_from_loadable_descriptors(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS) {
+   TempNewSymbol name = Signature::strip_envelope(sig);
+   if (name != ik->name() && ik->is_class_in_loadable_descriptors_attribute(sig)) {
+     log_info(class, preload)("Preloading of class %s during loading of shared class %s. "
+                              "Cause: field type in LoadableDescriptors attribute",
+                              name->as_C_string(), ik->name()->as_C_string());
+     InstanceKlass* real_k = SystemDictionary::resolve_with_circularity_detection(ik->name(), name,
+                                                                                  class_loader, false, THREAD);
+     if (HAS_PENDING_EXCEPTION) {
+       CLEAR_PENDING_EXCEPTION;
+     }
+ 
+     InstanceKlass* k = ik->get_inline_type_field_klass_or_null(field_index);
+     if (real_k != k) {
+       // oops, the app has substituted a different version of k!
+       log_warning(class, preload)("Preloading of class %s during loading of shared class %s "
+                                   "(cause: field type in LoadableDescriptors attribute) failed : "
+                                   "app substituted a different version of %s",
+                                   name->as_C_string(), ik->name()->as_C_string(),
+                                   k->name()->as_C_string());
+       return;
+     } else if (real_k != nullptr) {
+       log_info(class, preload)("Preloading of class %s during loading of shared class %s "
+                                "(cause: field type in LoadableDescriptors attribute) succeeded",
+                                 name->as_C_string(), ik->name()->as_C_string());
+     }
+   }
+ }
+ 
+ 
  InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik,
                                                     Handle class_loader,
                                                     Handle protection_domain,
                                                     const ClassFileStream *cfs,
                                                     PackageEntry* pkg_entry,

@@ -1091,10 +1187,31 @@
    if (!check) {
      ik->set_shared_loading_failed();
      return nullptr;
    }
  
+   if (ik->has_inline_type_fields()) {
+     for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
+       if (fs.access_flags().is_static()) continue;
+ 
+       Symbol* sig = fs.signature();
+       int field_index = fs.index();
+ 
+       if (fs.is_null_free_inline_type()) {
+         // A false return means that the class didn't load for other reasons than an exception.
+         bool check = preload_from_null_free_field(ik, class_loader, sig, field_index, CHECK_NULL);
+         if (!check) {
+           ik->set_shared_loading_failed();
+           return nullptr;
+         }
+       } else if (Signature::has_envelope(sig)) {
+           // Pending exceptions are cleared so we can fail silently
+           try_preload_from_loadable_descriptors(ik, class_loader, sig, field_index, CHECK_NULL);
+       }
+     }
+   }
+ 
    InstanceKlass* new_ik = nullptr;
    // CFLH check is skipped for VM hidden classes (see KlassFactory::create_from_stream).
    // It will be skipped for shared VM hidden lambda proxy classes.
    if (!ik->is_hidden()) {
      new_ik = KlassFactory::check_shared_class_file_load_hook(

@@ -1126,10 +1243,11 @@
      // restore_unshareable_info which calls ik->set_package()
      ik->restore_unshareable_info(loader_data, protection_domain, pkg_entry, CHECK_NULL);
    }
  
    load_shared_class_misc(ik, loader_data);
+ 
    return ik;
  }
  
  void SystemDictionary::load_shared_class_misc(InstanceKlass* ik, ClassLoaderData* loader_data) {
    ik->print_class_load_logging(loader_data, nullptr, nullptr);

@@ -1648,27 +1766,27 @@
      dictionary->add_klass(current, name, k);
    }
    mu1.notify_all();
  }
  
- #if INCLUDE_CDS
  // Indicate that loader_data has initiated the loading of class k, which
  // has already been defined by a parent loader.
- // This API should be used only by AOTLinkedClassBulkLoader
+ // This API is used by AOTLinkedClassBulkLoader and to register boxing
+ // classes from java.lang in all class loaders to enable more value
+ // classes optimizations
  void SystemDictionary::add_to_initiating_loader(JavaThread* current,
                                                  InstanceKlass* k,
                                                  ClassLoaderData* loader_data) {
-   assert(CDSConfig::is_using_aot_linked_classes(), "must be");
    assert_locked_or_safepoint(SystemDictionary_lock);
    Symbol* name  = k->name();
    Dictionary* dictionary = loader_data->dictionary();
    assert(k->is_loaded(), "must be");
    assert(k->class_loader_data() != loader_data, "only for classes defined by a parent loader");
-   assert(dictionary->find_class(current, name) == nullptr, "sanity");
-   dictionary->add_klass(current, name, k);
+   if (dictionary->find_class(current, name) == nullptr) {
+     dictionary->add_klass(current, name, k);
+   }
  }
- #endif
  
  // Try to find a class name using the loader constraints.  The
  // loader constraints might know about a class that isn't fully loaded
  // yet and these will be ignored.
  Klass* SystemDictionary::find_constrained_instance_or_array_klass(
< prev index next >