< prev index next >

src/hotspot/share/classfile/systemDictionary.cpp

Print this page
@@ -53,10 +53,12 @@
  #include "memory/oopFactory.hpp"
  #include "memory/resourceArea.hpp"
  #include "memory/universe.hpp"
  #include "oops/access.inline.hpp"
  #include "oops/constantPool.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"

@@ -70,10 +72,11 @@
  #include "runtime/atomicAccess.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"

@@ -184,17 +187,48 @@
  // 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 {
+       bool created = false;
+       ClassLoaderData* cld = ClassLoaderDataGraph::find_or_create(class_loader, created);
+       if (created && Arguments::enable_preview()) {
+         if (CDSConfig::is_using_aot_linked_classes() && java_system_loader() == nullptr) {
+           // We are inside AOTLinkedClassBulkLoader::preload_classes().
+           //
+           // AOTLinkedClassBulkLoader will automatically initiate the loading of all archived
+           // public classes from the boot loader into platform/system loaders, so there's
+           // no need to call add_migrated_value_classes().
+         } else {
+           add_migrated_value_classes(cld);
+         }
+       }
+       return cld;
+     }
    }
  }
  
  void SystemDictionary::set_system_loader(ClassLoaderData *cld) {
    if (_java_system_loader.is_empty()) {

@@ -398,11 +432,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

@@ -411,10 +446,12 @@
  //      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, and classloader is found.
  // This can be seen with logging option: -Xlog:class+load+placeholders=debug.

@@ -449,11 +486,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;
      }

@@ -473,11 +510,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);
  

@@ -911,10 +948,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");
  
    // (1) Check if we are loading into the same loader as in dump time.
  

@@ -1008,33 +1046,33 @@
    }
  
    return visible;
  }
  
- bool SystemDictionary::check_shared_class_super_type(InstanceKlass* klass, InstanceKlass* super_type,
+ bool SystemDictionary::check_shared_class_dependency(InstanceKlass* klass, InstanceKlass* dependency,
                                                       Handle class_loader, bool is_superclass, TRAPS) {
-   assert(super_type->in_aot_cache(), "must be");
+   assert(dependency->in_aot_cache(), "must be");
  
-   // Quick check if the super type has been already loaded.
+   // Quick check if the dependency has been already loaded.
    // + Don't do it for unregistered classes -- they can be unloaded so
-   //   super_type->class_loader_data() could be stale.
-   // + Don't check if loader data is null, ie. the super_type isn't fully loaded.
-   if (!super_type->defined_by_other_loaders() && super_type->class_loader_data() != nullptr) {
-     // Check if the superclass is loaded by the current class_loader
-     Symbol* name = super_type->name();
+   //   dependency->class_loader_data() could be stale.
+   // + Don't check if loader data is null, ie. the dependency isn't fully loaded.
+   if (!dependency->defined_by_other_loaders() && dependency->class_loader_data() != nullptr) {
+     // Check if the dependency is loaded by the current class_loader.
+     Symbol* name = dependency->name();
      InstanceKlass* check = find_instance_klass(THREAD, name, class_loader);
-     if (check == super_type) {
+     if (check == dependency) {
        return true;
      }
    }
  
-   Klass *found = resolve_with_circularity_detection(klass->name(), super_type->name(),
+   Klass* found = resolve_with_circularity_detection(klass->name(), dependency->name(),
                                                      class_loader, is_superclass, CHECK_false);
-   if (found == super_type) {
+   if (found == dependency) {
      return true;
    } else {
-     // The dynamically resolved super type is not the same as the one we used during dump time,
+     // The dynamically resolved dependency is not the same as the one we used during dump time,
      // so we cannot use the class.
      return false;
    }
  }
  

@@ -1045,31 +1083,109 @@
    //
    // If unexpected superclass or interfaces are found, we cannot
    // load <ik> from the shared archive.
  
    if (ik->super() != nullptr) {
-     bool check_super = check_shared_class_super_type(ik, ik->super(),
+     bool check_super = check_shared_class_dependency(ik, ik->super(),
                                                       class_loader, true,
                                                       CHECK_false);
      if (!check_super) {
        return false;
      }
    }
  
    Array<InstanceKlass*>* interfaces = ik->local_interfaces();
    int num_interfaces = interfaces->length();
    for (int index = 0; index < num_interfaces; index++) {
-     bool check_interface = check_shared_class_super_type(ik, interfaces->at(index), class_loader, false,
+     bool check_interface = check_shared_class_dependency(ik, interfaces->at(index), class_loader, false,
                                                           CHECK_false);
      if (!check_interface) {
        return false;
      }
    }
  
    return true;
  }
  
+ // Pre-load class referred to in fields with archived inline field metadata. These fields
+ // must be checked against the resolved runtime class before the shared class can be used.
+ bool SystemDictionary::preload_from_required_inline_field(InstanceKlass* ik, Handle class_loader, Symbol* sig, int field_index, TRAPS) {
+   if (log_is_enabled(Info, class, preload)) {
+     TempNewSymbol name = Signature::strip_envelope(sig);
+     log_info(class, preload)("Preloading of class %s during loading of shared class %s. "
+                              "Cause: archived flat/null-restricted field metadata",
+                              name->as_C_string(), ik->name()->as_C_string());
+   }
+ 
+   InstanceKlass* k = ik->get_inline_type_field_klass_or_null(field_index);
+   bool check = check_shared_class_dependency(ik, k, class_loader, false, THREAD);
+   if (!check) {
+     const bool has_pending_exception = HAS_PENDING_EXCEPTION;
+     if (log_is_enabled(Info, class, preload)) {
+       TempNewSymbol name = Signature::strip_envelope(sig);
+       const char* reason = has_pending_exception ?
+                            PENDING_EXCEPTION->klass()->name()->as_C_string() :
+                            "app substituted a different version";
+       log_info(class, preload)("Preloading of class %s during loading of shared class %s "
+                                "(cause: archived flat/null-restricted field metadata) failed : %s",
+                                name->as_C_string(), ik->name()->as_C_string(), reason);
+     }
+     if (has_pending_exception) {
+       CLEAR_PENDING_EXCEPTION;
+     }
+     return false;
+   }
+ 
+   assert(k != nullptr, "Sanity check");
+   if (log_is_enabled(Info, class, preload)) {
+     TempNewSymbol name = Signature::strip_envelope(sig);
+     log_info(class, preload)("Preloading of class %s during loading of shared class %s "
+                              "(cause: archived flat/null-restricted field metadata) succeeded",
+                              name->as_C_string(), ik->name()->as_C_string());
+   }
+   return true;
+ }
+ 
+ // Optionally pre-load classes referred to in instance fields if they are found in the
+ // LoadableDescriptors attribute. This mirrors the speculative preloading in
+ // ClassFileParser::fetch_field_classes() when loading a class outside the archive.
+ // Failures are ignored and do not fail shared class loading.
+ 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)) {
+     return;
+   }
+ 
+   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* k = ik->get_inline_type_field_klass_or_null(field_index);
+   if (k == nullptr) {
+     SystemDictionary::resolve_with_circularity_detection(ik->name(), name, class_loader, false, THREAD);
+     if (HAS_PENDING_EXCEPTION) {
+       CLEAR_PENDING_EXCEPTION;
+     }
+     return;
+   }
+ 
+   bool check = check_shared_class_dependency(ik, k, class_loader, false, THREAD);
+   if (HAS_PENDING_EXCEPTION) {
+     CLEAR_PENDING_EXCEPTION;
+   }
+   if (check) {
+     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());
+   } else {
+     log_info(class, preload)("Preloading of class %s during loading of shared class %s "
+                              "(cause: field type in LoadableDescriptors attribute) failed : "
+                              "app substituted a different version",
+                              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,

@@ -1089,10 +1205,36 @@
    if (!check) {
      ik->set_shared_loading_failed();
      return nullptr;
    }
  
+   if (ik->has_inlined_fields() || ik->has_null_restricted_static_fields()) {
+     for (AllFieldStream fs(ik); !fs.done(); fs.next()) {
+       if (fs.access_flags().is_static() && !fs.is_null_free_inline_type()) {
+         continue;
+       }
+ 
+       Symbol* sig = fs.signature();
+       int field_index = fs.index();
+ 
+       if (!Signature::has_envelope(sig)) {
+         continue;
+       }
+ 
+       if (fs.is_flat() || fs.is_null_free_inline_type()) {
+         bool check = preload_from_required_inline_field(ik, class_loader, sig, field_index, CHECK_NULL);
+         if (!check) {
+           ik->set_shared_loading_failed();
+           return nullptr;
+         }
+       } else {
+         // Optional LoadableDescriptors preloading. Failures are ignored.
+         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(

@@ -1705,27 +1847,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(

@@ -2093,11 +2235,11 @@
  #endif // INCLUDE_CDS
  
  // Helper for unpacking the return value from linkMethod and linkCallSite.
  static Method* unpack_method_and_appendix(Handle mname,
                                            Klass* accessing_klass,
-                                           objArrayHandle appendix_box,
+                                           refArrayHandle appendix_box,
                                            Handle* appendix_result,
                                            TRAPS) {
    if (mname.not_null()) {
      Method* m = java_lang_invoke_MemberName::vmtarget(mname());
      if (m != nullptr) {

@@ -2136,11 +2278,11 @@
      SystemDictionary::find_method_handle_type(signature, accessing_klass, CHECK_NULL);
  
    int ref_kind = JVM_REF_invokeVirtual;
    oop name_oop = StringTable::intern(name, CHECK_NULL);
    Handle name_str (THREAD, name_oop);
-   objArrayHandle appendix_box = oopFactory::new_objArray_handle(vmClasses::Object_klass(), 1, CHECK_NULL);
+   refArrayHandle appendix_box = oopFactory::new_refArray_handle(vmClasses::Object_klass(), 1, CHECK_NULL);
    assert(appendix_box->obj_at(0) == nullptr, "");
  
    // This should not happen.  JDK code should take care of that.
    if (accessing_klass == nullptr || method_type.is_null()) {
      THROW_MSG_NULL(vmSymbols::java_lang_InternalError(), "bad invokehandle");

@@ -2247,11 +2389,11 @@
    if (accessing_klass != nullptr) {
      class_loader      = Handle(THREAD, accessing_klass->class_loader());
    }
    bool can_be_cached = true;
    int npts = ArgumentCount(signature).size();
-   objArrayHandle pts = oopFactory::new_objArray_handle(vmClasses::Class_klass(), npts, CHECK_(empty));
+   refArrayHandle pts = oopFactory::new_refArray_handle(vmClasses::Class_klass(), npts, CHECK_(empty));
    int arg = 0;
    Handle rt; // the return type from the signature
    ResourceMark rm(THREAD);
    for (SignatureStream ss(signature); !ss.is_done(); ss.next()) {
      oop mirror = nullptr;

@@ -2393,14 +2535,14 @@
    if (bootstrap_specifier.caller() == nullptr || bootstrap_specifier.type_arg().is_null()) {
      THROW_MSG(vmSymbols::java_lang_InternalError(), "Invalid bootstrap method invocation with no caller or type argument");
    }
  
    bool is_indy = bootstrap_specifier.is_method_call();
-   objArrayHandle appendix_box;
+   refArrayHandle appendix_box;
    if (is_indy) {
      // Some method calls may require an appendix argument.  Arrange to receive it.
-     appendix_box = oopFactory::new_objArray_handle(vmClasses::Object_klass(), 1, CHECK);
+     appendix_box = oopFactory::new_refArray_handle(vmClasses::Object_klass(), 1, CHECK);
      assert(appendix_box->obj_at(0) == nullptr, "");
    }
  
    // call condy: java.lang.invoke.MethodHandleNatives::linkDynamicConstant(caller, bsm, type, info)
    //       indy: java.lang.invoke.MethodHandleNatives::linkCallSite(caller, bsm, name, mtype, info, &appendix)
< prev index next >