< prev index next >

src/hotspot/share/cds/cdsHeapVerifier.cpp

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

@@ -21,10 +21,11 @@
   * questions.
   *
   */
  
  #include "precompiled.hpp"
+ #include "cds/aotClassInitializer.hpp"
  #include "cds/archiveBuilder.hpp"
  #include "cds/cdsHeapVerifier.hpp"
  #include "classfile/classLoaderDataGraph.hpp"
  #include "classfile/javaClasses.inline.hpp"
  #include "logging/log.hpp"

@@ -121,10 +122,27 @@
  
    // Integer for 0 and 1 are in java/lang/Integer$IntegerCache and are archived
    ADD_EXCL("sun/invoke/util/ValueConversions",           "ONE_INT",                // E
                                                           "ZERO_INT");              // E
  
+   if (CDSConfig::is_dumping_invokedynamic()) {
+     ADD_EXCL("java/lang/invoke/MethodHandles",            "IMPL_NAMES");           // D
+     ADD_EXCL("java/lang/invoke/MemberName$Factory",       "INSTANCE");             // D
+     ADD_EXCL("java/lang/invoke/InvokerBytecodeGenerator", "MEMBERNAME_FACTORY");   // D
+     ADD_EXCL("java/lang/invoke/SimpleMethodHandle",       "BMH_SPECIES");          // D
+   }
+ 
+   // These are used by BuiltinClassLoader::negativeLookupCache, etc but seem to be
+   // OK. TODO - we should copletely disable the caching unless ArchiveLoaderLookupCache
+   // is enabled
+   ADD_EXCL("java/lang/Boolean",                           "TRUE",                  // E
+                                                           "FALSE");                // E
+   
+   ADD_EXCL("java/lang/Boolean$AOTHolder",                 "TRUE",                  // E
+                                                           "FALSE");                // E
+   
+ 
  # undef ADD_EXCL
  
    ClassLoaderDataGraph::classes_do(this);
  }
  

@@ -136,11 +154,11 @@
    }
  }
  
  class CDSHeapVerifier::CheckStaticFields : public FieldClosure {
    CDSHeapVerifier* _verifier;
-   InstanceKlass* _ik;
+   InstanceKlass* _ik; // The class whose static fields are being checked.
    const char** _exclusions;
  public:
    CheckStaticFields(CDSHeapVerifier* verifier, InstanceKlass* ik)
      : _verifier(verifier), _ik(ik) {
      _exclusions = _verifier->find_exclusion(_ik);

@@ -151,11 +169,11 @@
        return;
      }
  
      oop static_obj_field = _ik->java_mirror()->obj_field(fd->offset());
      if (static_obj_field != nullptr) {
-       Klass* klass = static_obj_field->klass();
+       Klass* klass_of_field = static_obj_field->klass();
        if (_exclusions != nullptr) {
          for (const char** p = _exclusions; *p != nullptr; p++) {
            if (fd->name()->equals(*p)) {
              return;
            }

@@ -171,16 +189,26 @@
        }
        if (fd->is_final() && java_lang_Class::is_instance(static_obj_field)) {
          // This field points to an archived mirror.
          return;
        }
-       if (klass->has_archived_enum_objs()) {
-         // This klass is a subclass of java.lang.Enum. If any instance of this klass
-         // has been archived, we will archive all static fields of this klass.
+       if (klass_of_field->has_archived_enum_objs()) {
+         // This field is an Enum. If any instance of this Enum has been archived, we will archive
+         // all static fields of this Enum as well.
          // See HeapShared::initialize_enum_klass().
          return;
        }
+       if (klass_of_field->is_instance_klass()) {
+         if (InstanceKlass::cast(klass_of_field)->is_initialized() &&
+             AOTClassInitializer::can_archive_initialized_mirror(InstanceKlass::cast(klass_of_field))) {
+           return;
+         }
+       }
+ 
+       if (AOTClassInitializer::can_archive_initialized_mirror(_ik)) {
+         return;
+       }
  
        // This field *may* be initialized to a different value at runtime. Remember it
        // and check later if it appears in the archived object graph.
        _verifier->add_static_obj_field(_ik, static_obj_field, fd->name());
      }

@@ -198,16 +226,33 @@
        // in heapShared.cpp. We assume such classes are programmed to
        // update their static fields correctly at runtime.
        return;
      }
  
+     if (HeapShared::is_lambda_form_klass(ik)) {
+       // Archived lambda forms have preinitialized mirrors, so <clinit> won't run.
+       return;
+     }
+ 
      CheckStaticFields csf(this, ik);
      ik->do_local_static_fields(&csf);
    }
  }
  
  void CDSHeapVerifier::add_static_obj_field(InstanceKlass* ik, oop field, Symbol* name) {
+   if (field->klass() == vmClasses::MethodType_klass()) {
+     // The identity of MethodTypes are preserved between assembly phase and production runs
+     // (by MethodType::AOTHolder::archivedMethodTypes). No need to check.
+     return;
+   }
+   if (field->klass() == vmClasses::LambdaForm_klass()) {
+     // LambdaForms are non-modifiable and are not tested for object equality, so
+     // it's OK if static fields of the LambdaForm type are reinitialized at runtime with
+     // alternative instances. No need to check.
+     return;
+   }
+ 
    StaticFieldInfo info = {ik, name};
    _table.put(field, info);
  }
  
  inline bool CDSHeapVerifier::do_entry(oop& orig_obj, HeapShared::CachedOopInfo& value) {

@@ -219,14 +264,23 @@
        // This string object is not referenced by any of the archived object graphs. It's archived
        // only because it's in the interned string table. So we are not in a condition that
        // should be flagged by CDSHeapVerifier.
        return true; /* keep on iterating */
      }
+     if (info->_holder->is_hidden()) {
+       return true;
+     }
      ResourceMark rm;
+     char* class_name = info->_holder->name()->as_C_string();
+     char* field_name = info->_name->as_C_string();
+     if (strstr(class_name, "java/lang/invoke/BoundMethodHandle$Species_") == class_name &&
+         strcmp(field_name, "BMH_SPECIES") == 0) {
+       return true;
+     }
      LogStream ls(Log(cds, heap)::warning());
      ls.print_cr("Archive heap points to a static field that may be reinitialized at runtime:");
-     ls.print_cr("Field: %s::%s", info->_holder->name()->as_C_string(), info->_name->as_C_string());
+     ls.print_cr("Field: %s::%s", class_name, field_name);
      ls.print("Value: ");
      orig_obj->print_on(&ls);
      ls.print_cr("--- trace begin ---");
      trace_to_root(&ls, orig_obj, nullptr, &value);
      ls.print_cr("--- trace end ---");

@@ -278,10 +332,13 @@
    Klass* k = orig_obj->klass();
    ResourceMark rm;
    st->print("[%2d] ", level);
    orig_obj->print_address_on(st);
    st->print(" %s", k->internal_name());
+   if (java_lang_Class::is_instance(orig_obj)) {
+     st->print(" (%s)", java_lang_Class::as_Klass(orig_obj)->external_name());
+   }
    if (orig_field != nullptr) {
      if (k->is_instance_klass()) {
        TraceFields clo(orig_obj, orig_field, st);
        InstanceKlass::cast(k)->do_nonstatic_fields(&clo);
      } else {
< prev index next >