< prev index next >

src/hotspot/share/cds/cdsHeapVerifier.cpp

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

@@ -37,10 +37,11 @@
  #include "logging/logStream.hpp"
  #include "memory/resourceArea.hpp"
  #include "oops/fieldStreams.inline.hpp"
  #include "oops/klass.inline.hpp"
  #include "oops/oop.inline.hpp"
+ #include "oops/oopCast.inline.hpp"
  #include "oops/oopHandle.inline.hpp"
  #include "runtime/fieldDescriptor.inline.hpp"
  
  #if INCLUDE_CDS_JAVA_HEAP
  

@@ -91,10 +92,22 @@
  //     its value is deterministic and is always the same string literal.
  // [C] A non-final static string that is assigned a string literal during class
  //     initialization; this string is never changed during -Xshare:dump.
  // [D] Simple caches whose value doesn't matter.
  // [E] Other cases (see comments in-line below).
+ //
+ // LIMITATION:
+ //
+ // CDSHeapVerifier can only check for problems with object identity. In the example above,
+ // if the Bar type has identity, the program's correctness requires that the identity
+ // of Foo.bar and Bar.bar to be equal. This requirement can be checked by CDSHeapVerifier.
+ //
+ // However, if Bar does not have identity (e.g., it's a value class, or is a primitive type),
+ // the program's correctness no longer requires that the identity of Foo.bar and Bar.bar
+ // to be equal (since they don't have an identity anymore). While the program's
+ // correctness may still have certain assumptions about Foo.bar and Bar.bar (such as the
+ // internal fields of these two values), such assumptions cannot be checked by CDSHeapVerifier.
  
  CDSHeapVerifier::CDSHeapVerifier() : _archived_objs(0), _problems(0)
  {
  # define ADD_EXCL(...) { static const char* e[] = {__VA_ARGS__, nullptr}; add_exclusion(e); }
  

@@ -291,10 +304,18 @@
              return;
            }
          }
        }
  
+       if (!field_type->is_identity_class()) {
+         // See comment of LIMITATION above
+         // Any concrete value class will have a field ".null_reset" which holds an
+         // all-zero instance of the value class so it will not change between
+         // dump time and runtime.
+         return;
+       }
+ 
        if (fd->is_final() && java_lang_String::is_instance(static_obj_field) && fd->has_initial_value()) {
          // This field looks like like this in the Java source:
          //    static final SOME_STRING = "a string literal";
          // This string literal has been stored in the shared string table, so it's OK
          // for the archived objects to refer to it.

@@ -482,12 +503,12 @@
    if (orig_field != nullptr) {
      if (k->is_instance_klass()) {
        TraceFields clo(orig_obj, orig_field, st);
        InstanceKlass::cast(k)->do_nonstatic_fields(&clo);
      } else {
-       assert(orig_obj->is_objArray(), "must be");
-       objArrayOop array = (objArrayOop)orig_obj;
+       assert(orig_obj->is_refArray(), "must be");
+       refArrayOop array = oop_cast<refArrayOop>(orig_obj);
        for (int i = 0; i < array->length(); i++) {
          if (array->obj_at(i) == orig_field) {
            st->print(" @[%d]", i);
            break;
          }
< prev index next >