< prev index next >

src/hotspot/share/classfile/systemDictionary.cpp

Print this page
@@ -1,7 +1,7 @@
  /*
-  * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved.
+  * Copyright (c) 1997, 2024, 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.

@@ -54,10 +54,11 @@
  #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/instanceKlass.hpp"
  #include "oops/klass.inline.hpp"
  #include "oops/method.inline.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "oops/objArrayOop.inline.hpp"

@@ -65,18 +66,20 @@
  #include "oops/oop.hpp"
  #include "oops/oopHandle.hpp"
  #include "oops/oopHandle.inline.hpp"
  #include "oops/symbol.hpp"
  #include "oops/typeArrayKlass.hpp"
+ #include "oops/inlineKlass.inline.hpp"
  #include "prims/jvmtiExport.hpp"
  #include "prims/methodHandles.hpp"
  #include "runtime/arguments.hpp"
  #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"

@@ -333,11 +336,11 @@
      return resolve_array_class_or_null(class_name, class_loader, protection_domain, THREAD);
    } else {
      assert(class_name != nullptr && !Signature::is_array(class_name), "must be");
      if (Signature::has_envelope(class_name)) {
        ResourceMark rm(THREAD);
-       // Ignore wrapping L and ;.
+       // Ignore wrapping L and ; (and Q and ; for value types).
        TempNewSymbol name = SymbolTable::new_symbol(class_name->as_C_string() + 1,
                                                     class_name->utf8_length() - 2);
        return resolve_instance_class_or_null(name, class_loader, protection_domain, THREAD);
      } else {
        return resolve_instance_class_or_null(class_name, class_loader, protection_domain, THREAD);

@@ -397,29 +400,29 @@
  //      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.
  //
- // resolve_super_or_fail adds a LOAD_SUPER placeholder to the placeholder table before calling
- // resolve_instance_class_or_null. ClassCircularityError is detected when a LOAD_SUPER or LOAD_INSTANCE
+ // resolve_with_circularity_detection_or_fail 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.
  // This can be seen with logging option: -Xlog:class+load+placeholders=debug.
  //
- InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
-                                                        Symbol* super_name,
+ InstanceKlass* SystemDictionary::resolve_with_circularity_detection_or_fail(Symbol* class_name,
+                                                        Symbol* next_name,
                                                         Handle class_loader,
                                                         Handle protection_domain,
                                                         bool is_superclass,
                                                         TRAPS) {
  
-   assert(super_name != nullptr, "null superclass for resolving");
-   assert(!Signature::is_array(super_name), "invalid superclass name");
+   assert(next_name != nullptr, "null superclass for resolving");
+   assert(!Signature::is_array(next_name), "invalid superclass name");
  #if INCLUDE_CDS
    if (CDSConfig::is_dumping_static_archive()) {
      // Special processing for handling UNREGISTERED shared classes.
      InstanceKlass* k = SystemDictionaryShared::lookup_super_for_unregistered_class(class_name,
-                            super_name, is_superclass);
+                            next_name, is_superclass);
      if (k) {
        return k;
      }
    }
  #endif // INCLUDE_CDS

@@ -437,57 +440,57 @@
    {
      MutexLocker mu(THREAD, SystemDictionary_lock);
      InstanceKlass* klassk = dictionary->find_class(THREAD, class_name);
      InstanceKlass* quicksuperk;
      // To support parallel loading: if class is done loading, just return the superclass
-     // if the super_name matches class->super()->name() and if the class loaders match.
+     // if the next_name matches class->super()->name() and if the class loaders match.
      // Otherwise, a LinkageError will be thrown later.
      if (klassk != nullptr && is_superclass &&
          ((quicksuperk = klassk->java_super()) != nullptr) &&
-          ((quicksuperk->name() == super_name) &&
+          ((quicksuperk->name() == next_name) &&
              (quicksuperk->class_loader() == class_loader()))) {
             return quicksuperk;
      } else {
        // Must check ClassCircularity before checking if superclass is already loaded.
        PlaceholderEntry* probe = PlaceholderTable::get_entry(class_name, loader_data);
-       if (probe && probe->check_seen_thread(THREAD, PlaceholderTable::LOAD_SUPER)) {
+       if (probe && probe->check_seen_thread(THREAD, PlaceholderTable::DETECT_CIRCULARITY)) {
            log_circularity_error(class_name, probe);
            throw_circularity_error = true;
        }
      }
  
      if (!throw_circularity_error) {
        // Be careful not to exit resolve_super without removing this placeholder.
        PlaceholderEntry* newprobe = PlaceholderTable::find_and_add(class_name,
                                                                    loader_data,
-                                                                   PlaceholderTable::LOAD_SUPER,
-                                                                   super_name, THREAD);
+                                                                   PlaceholderTable::DETECT_CIRCULARITY,
+                                                                   next_name, THREAD);
      }
    }
  
    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
    InstanceKlass* superk =
-     SystemDictionary::resolve_instance_class_or_null(super_name,
+     SystemDictionary::resolve_instance_class_or_null(next_name,
                                                       class_loader,
                                                       protection_domain,
                                                       THREAD);
  
    // Clean up placeholder entry.
    {
      MutexLocker mu(THREAD, SystemDictionary_lock);
-     PlaceholderTable::find_and_remove(class_name, loader_data, PlaceholderTable::LOAD_SUPER, THREAD);
+     PlaceholderTable::find_and_remove(class_name, loader_data, PlaceholderTable::DETECT_CIRCULARITY, THREAD);
      SystemDictionary_lock->notify_all();
    }
  
    // Check for pending exception or null superk, and throw exception
    if (HAS_PENDING_EXCEPTION || superk == nullptr) {
-     handle_resolution_exception(super_name, true, CHECK_NULL);
+     handle_resolution_exception(next_name, true, CHECK_NULL);
    }
  
    return superk;
  }
  

@@ -501,15 +504,15 @@
                                         Symbol* superclassname,
                                         Handle class_loader,
                                         Handle protection_domain, TRAPS) {
  
    // superk is not used; resolve_super_or_fail is called for circularity check only.
-   Klass* superk = SystemDictionary::resolve_super_or_fail(name,
+   Klass* superk = SystemDictionary::resolve_with_circularity_detection_or_fail(name,
                                                            superclassname,
                                                            class_loader,
                                                            protection_domain,
-                                                           true,
+                                                           false,
                                                            CHECK);
  }
  
  // Bootstrap and non-parallel capable class loaders use the LOAD_INSTANCE placeholder to
  // wait for parallel class loading and/or to check for circularity error for Xcomp when loading.

@@ -534,11 +537,11 @@
        return nullptr;
      } else if (must_wait_for_class_loading) {
        // Wait until the first thread has finished loading this class. Also wait until all the
        // threads trying to load its superclass have removed their placeholders.
        while (oldprobe != nullptr &&
-              (oldprobe->instance_load_in_progress() || oldprobe->super_load_in_progress())) {
+              (oldprobe->instance_load_in_progress() || oldprobe->circularity_detection_in_progress())) {
  
          // LOAD_INSTANCE placeholders are used to implement parallel capable class loading
          // for the bootclass loader.
          SystemDictionary_lock->wait();
  

@@ -574,11 +577,11 @@
                                                                  Handle class_loader,
                                                                  Handle protection_domain,
                                                                  TRAPS) {
    // name must be in the form of "java/lang/Object" -- cannot be "Ljava/lang/Object;"
    assert(name != nullptr && !Signature::is_array(name) &&
-          !Signature::has_envelope(name), "invalid class name");
+          !Signature::has_envelope(name), "invalid class name: %s", name == nullptr ? "nullptr" : name->as_C_string());
  
    EventClassLoad class_load_start_event;
  
    HandleMark hm(THREAD);
  

@@ -605,11 +608,11 @@
    // ParallelCapable class loaders and the bootstrap classloader
    // do not acquire lock here.
    Handle lockObject = get_loader_lock_or_null(class_loader);
    ObjectLocker ol(lockObject, THREAD);
  
-   bool super_load_in_progress  = false;
+   bool circularity_detection_in_progress  = false;
    InstanceKlass* loaded_class = nullptr;
    SymbolHandle superclassname; // Keep alive while loading in parallel thread.
  
    guarantee(THREAD->can_call_java(),
           "can not load classes with compiler thread: class=%s, classloader=%s",

@@ -623,21 +626,21 @@
      if (check != nullptr) {
        // InstanceKlass is already loaded, but we still need to check protection domain below.
        loaded_class = check;
      } else {
        PlaceholderEntry* placeholder = PlaceholderTable::get_entry(name, loader_data);
-       if (placeholder != nullptr && placeholder->super_load_in_progress()) {
-          super_load_in_progress = true;
-          superclassname = placeholder->supername();
+       if (placeholder != nullptr && placeholder->circularity_detection_in_progress()) {
+          circularity_detection_in_progress = true;
+          superclassname = placeholder->next_klass_name();
           assert(superclassname != nullptr, "superclass has to have a name");
        }
      }
    }
  
    // If the class is in the placeholder table with super_class set,
    // handle superclass loading in progress.
-   if (super_load_in_progress) {
+   if (circularity_detection_in_progress) {
      handle_parallel_super_load(name, superclassname,
                                 class_loader,
                                 protection_domain,
                                 CHECK_NULL);
    }

@@ -935,12 +938,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->is_shared_boot_class()) {
      if (class_loader() != nullptr) {

@@ -1012,11 +1014,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;

@@ -1050,11 +1052,11 @@
      if (check == super_type) {
        return true;
      }
    }
  
-   Klass *found = resolve_super_or_fail(klass->name(), super_type->name(),
+   Klass *found = resolve_with_circularity_detection_or_fail(klass->name(), super_type->name(),
                                         class_loader, protection_domain, is_superclass, CHECK_0);
    if (found == super_type) {
      return true;
    } else {
      // The dynamically resolved super type is not the same as the one we used during dump time,

@@ -1139,10 +1141,42 @@
  
    if (!check_shared_class_super_types(ik, class_loader, protection_domain, THREAD)) {
      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();
+       if (fs.is_null_free_inline_type()) {
+         // Pre-load inline class
+         TempNewSymbol name = Signature::strip_envelope(sig);
+         Klass* real_k = SystemDictionary::resolve_with_circularity_detection_or_fail(ik->name(), name,
+           class_loader, protection_domain, false, CHECK_NULL);
+         Klass* k = ik->get_inline_type_field_klass_or_null(fs.index());
+         if (real_k != k) {
+           // oops, the app has substituted a different version of k!
+           return nullptr;
+         }
+       } else if (Signature::has_envelope(sig)) {
+         TempNewSymbol name = Signature::strip_envelope(sig);
+         if (name != ik->name() && ik->is_class_in_preload_attribute(name)) {
+           Klass* real_k = SystemDictionary::resolve_with_circularity_detection_or_fail(ik->name(), name,
+             class_loader, protection_domain, false, THREAD);
+           if (HAS_PENDING_EXCEPTION) {
+             CLEAR_PENDING_EXCEPTION;
+           }
+           Klass* k = ik->get_inline_type_field_klass_or_null(fs.index());
+           if (real_k != k) {
+             // oops, the app has substituted a different version of k!
+             return nullptr;
+           }
+         }
+       }
+     }
+   }
+ 
    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 (!SystemDictionaryShared::is_hidden_lambda_proxy(ik)) {
      new_ik = KlassFactory::check_shared_class_file_load_hook(

@@ -1174,10 +1208,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);
< prev index next >