< prev index next > src/hotspot/share/cds/cdsHeapVerifier.cpp
Print this page
/*
- * 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.
* 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"
// 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);
}
}
}
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);
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;
}
}
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());
}
// 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) {
// 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 ---");
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 >