8335583: Avoid using pointers in CDS tables

Reviewed-by: iklam, ccheung
This commit is contained in:
Matias Saavedra Silva 2024-11-06 18:46:06 +00:00
parent 342fe42555
commit d20ccd1aef
11 changed files with 204 additions and 69 deletions

@ -872,6 +872,13 @@ uintx ArchiveBuilder::any_to_offset(address p) const {
return buffer_to_offset(p);
}
address ArchiveBuilder::offset_to_buffered_address(u4 offset) const {
address requested_addr = _requested_static_archive_bottom + offset;
address buffered_addr = requested_addr - _buffer_to_requested_delta;
assert(is_in_buffer_space(buffered_addr), "bad offset");
return buffered_addr;
}
#if INCLUDE_CDS_JAVA_HEAP
narrowKlass ArchiveBuilder::get_requested_narrow_klass(Klass* k) {
assert(CDSConfig::is_dumping_heap(), "sanity");

@ -321,7 +321,7 @@ public:
}
public:
static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF;
static const uintx MAX_SHARED_DELTA = ArchiveUtils::MAX_SHARED_DELTA;;
// The address p points to an object inside the output buffer. When the archive is mapped
// at the requested address, what's the offset of this object from _requested_static_archive_bottom?
@ -331,6 +331,9 @@ public:
// inside the output buffer, or (b), an object in the currently mapped static archive.
uintx any_to_offset(address p) const;
// The reverse of buffer_to_offset()
address offset_to_buffered_address(u4 offset) const;
template <typename T>
u4 buffer_to_offset_u4(T p) const {
uintx offset = buffer_to_offset((address)p);
@ -343,6 +346,11 @@ public:
return to_offset_u4(offset);
}
template <typename T>
T offset_to_buffered(u4 offset) const {
return (T)offset_to_buffered_address(offset);
}
public:
ArchiveBuilder();
~ArchiveBuilder();

@ -25,8 +25,10 @@
#ifndef SHARE_CDS_ARCHIVEUTILS_HPP
#define SHARE_CDS_ARCHIVEUTILS_HPP
#include "cds/cds_globals.hpp"
#include "cds/serializeClosure.hpp"
#include "logging/log.hpp"
#include "memory/metaspace.hpp"
#include "memory/virtualspace.hpp"
#include "utilities/bitMap.hpp"
#include "utilities/exceptions.hpp"
@ -247,7 +249,27 @@ public:
class ArchiveUtils {
public:
static const uintx MAX_SHARED_DELTA = 0x7FFFFFFF;
static void log_to_classlist(BootstrapInfo* bootstrap_specifier, TRAPS) NOT_CDS_RETURN;
// offset must represent an object of type T in the mapped shared space. Return
// a direct pointer to this object.
template <typename T> T static from_offset(u4 offset) {
T p = (T)(SharedBaseAddress + offset);
assert(Metaspace::is_in_shared_metaspace(p), "must be");
return p;
}
// p must be an archived object. Get its offset from SharedBaseAddress
template <typename T> static u4 to_offset(T p) {
uintx pn = (uintx)p;
uintx base = (uintx)SharedBaseAddress;
assert(Metaspace::is_in_shared_metaspace(p), "must be");
assert(pn > base, "sanity"); // No valid object is stored at 0 offset from SharedBaseAddress
uintx offset = pn - base;
assert(offset <= MAX_SHARED_DELTA, "range check");
return static_cast<u4>(offset);
}
};
class HeapRootSegments {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 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
@ -51,7 +51,7 @@
#include "runtime/mutexLocker.hpp"
GrowableArrayCHeap<char*, mtClassShared>* LambdaFormInvokers::_lambdaform_lines = nullptr;
Array<Array<char>*>* LambdaFormInvokers::_static_archive_invokers = nullptr;
Array<u4>* LambdaFormInvokers::_static_archive_invokers = nullptr;
#define NUM_FILTER 4
static const char* filter[NUM_FILTER] = {"java.lang.invoke.Invokers$Holder",
@ -216,7 +216,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
}
}
if (count > 0) {
_static_archive_invokers = ArchiveBuilder::new_ro_array<Array<char>*>(count);
_static_archive_invokers = ArchiveBuilder::new_ro_array<u4>(count);
int index = 0;
for (int i = 0; i < len; i++) {
char* str = _lambdaform_lines->at(i);
@ -225,8 +225,7 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
Array<char>* line = ArchiveBuilder::new_ro_array<char>((int)str_len);
strncpy(line->adr_at(0), str, str_len);
_static_archive_invokers->at_put(index, line);
ArchivePtrMarker::mark_pointer(_static_archive_invokers->adr_at(index));
_static_archive_invokers->at_put(index, ArchiveBuilder::current()->any_to_offset_u4(line));
index++;
}
}
@ -239,7 +238,8 @@ void LambdaFormInvokers::dump_static_archive_invokers() {
void LambdaFormInvokers::read_static_archive_invokers() {
if (_static_archive_invokers != nullptr) {
for (int i = 0; i < _static_archive_invokers->length(); i++) {
Array<char>* line = _static_archive_invokers->at(i);
u4 offset = _static_archive_invokers->at(i);
Array<char>* line = ArchiveUtils::from_offset<Array<char>*>(offset);
char* str = line->adr_at(0);
append(str);
}

@ -38,7 +38,7 @@ class LambdaFormInvokers : public AllStatic {
private:
static GrowableArrayCHeap<char*, mtClassShared>* _lambdaform_lines;
// For storing LF form lines (LF_RESOLVE only) in read only table.
static Array<Array<char>*>* _static_archive_invokers;
static Array<u4>* _static_archive_invokers;
static void regenerate_class(char* name, ClassFileStream& st, TRAPS);
public:
static void append(char* line);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -34,17 +34,6 @@ DumpTimeLambdaProxyClassInfo::~DumpTimeLambdaProxyClassInfo() {
}
}
void LambdaProxyClassKey::init_for_archive(LambdaProxyClassKey& dumptime_key) {
ArchiveBuilder* b = ArchiveBuilder::current();
b->write_pointer_in_buffer(&_caller_ik, dumptime_key._caller_ik);
b->write_pointer_in_buffer(&_instantiated_method_type, dumptime_key._instantiated_method_type);
b->write_pointer_in_buffer(&_invoked_name, dumptime_key._invoked_name);
b->write_pointer_in_buffer(&_invoked_type, dumptime_key._invoked_type);
b->write_pointer_in_buffer(&_member_method, dumptime_key._member_method);
b->write_pointer_in_buffer(&_method_type, dumptime_key._method_type);
}
unsigned int LambdaProxyClassKey::hash() const {
return SystemDictionaryShared::hash_for_shared_dictionary((address)_caller_ik) +
SystemDictionaryShared::hash_for_shared_dictionary((address)_invoked_name) +
@ -53,6 +42,14 @@ unsigned int LambdaProxyClassKey::hash() const {
SystemDictionaryShared::hash_for_shared_dictionary((address)_instantiated_method_type);
}
unsigned int RunTimeLambdaProxyClassKey::hash() const {
return primitive_hash<u4>(_caller_ik) +
primitive_hash<u4>(_invoked_name) +
primitive_hash<u4>(_invoked_type) +
primitive_hash<u4>(_method_type) +
primitive_hash<u4>(_instantiated_method_type);
}
#ifndef PRODUCT
void LambdaProxyClassKey::print_on(outputStream* st) const {
ResourceMark rm;
@ -65,13 +62,24 @@ void LambdaProxyClassKey::print_on(outputStream* st) const {
st->print_cr("_method_type : %s", _method_type->as_C_string());
}
void RunTimeLambdaProxyClassKey::print_on(outputStream* st) const {
ResourceMark rm;
st->print_cr("LambdaProxyClassKey : " INTPTR_FORMAT " hash: %0x08x", p2i(this), hash());
st->print_cr("_caller_ik : %d", _caller_ik);
st->print_cr("_instantiated_method_type : %d", _instantiated_method_type);
st->print_cr("_invoked_name : %d", _invoked_name);
st->print_cr("_invoked_type : %d", _invoked_type);
st->print_cr("_member_method : %d", _member_method);
st->print_cr("_method_type : %d", _method_type);
}
void RunTimeLambdaProxyClassInfo::print_on(outputStream* st) const {
_key.print_on(st);
}
#endif
void RunTimeLambdaProxyClassInfo::init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info) {
_key.init_for_archive(key);
_key = RunTimeLambdaProxyClassKey::init_for_dumptime(key);
ArchiveBuilder::current()->write_pointer_in_buffer(&_proxy_klass_head,
info._proxy_klasses->at(0));
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -101,9 +101,80 @@ public:
return (k1.equals(k2));
}
InstanceKlass* caller_ik() const { return _caller_ik; }
InstanceKlass* caller_ik() const { return _caller_ik; }
Symbol* invoked_name() const { return _invoked_name; }
Symbol* invoked_type() const { return _invoked_type; }
Symbol* method_type() const { return _method_type; }
Method* member_method() const { return _member_method; }
Symbol* instantiated_method_type() const { return _instantiated_method_type; }
void init_for_archive(LambdaProxyClassKey& dumptime_key);
#ifndef PRODUCT
void print_on(outputStream* st) const;
#endif
};
class RunTimeLambdaProxyClassKey {
u4 _caller_ik;
u4 _invoked_name;
u4 _invoked_type;
u4 _method_type;
u4 _member_method;
u4 _instantiated_method_type;
RunTimeLambdaProxyClassKey(u4 caller_ik,
u4 invoked_name,
u4 invoked_type,
u4 method_type,
u4 member_method,
u4 instantiated_method_type) :
_caller_ik(caller_ik),
_invoked_name(invoked_name),
_invoked_type(invoked_type),
_method_type(method_type),
_member_method(member_method),
_instantiated_method_type(instantiated_method_type) {}
public:
static RunTimeLambdaProxyClassKey init_for_dumptime(LambdaProxyClassKey& key) {
assert(ArchiveBuilder::is_active(), "sanity");
ArchiveBuilder* b = ArchiveBuilder::current();
u4 caller_ik = b->any_to_offset_u4(key.caller_ik());
u4 invoked_name = b->any_to_offset_u4(key.invoked_name());
u4 invoked_type = b->any_to_offset_u4(key.invoked_type());
u4 method_type = b->any_to_offset_u4(key.method_type());
u4 member_method = b->any_to_offset_u4(key.member_method());
u4 instantiated_method_type = b->any_to_offset_u4(key.instantiated_method_type());
return RunTimeLambdaProxyClassKey(caller_ik, invoked_name, invoked_type, method_type,
member_method, instantiated_method_type);
}
static RunTimeLambdaProxyClassKey init_for_runtime(InstanceKlass* caller_ik,
Symbol* invoked_name,
Symbol* invoked_type,
Symbol* method_type,
Method* member_method,
Symbol* instantiated_method_type) {
// All parameters must be in shared space, or else you'd get an assert in
// ArchiveUtils::to_offset().
return RunTimeLambdaProxyClassKey(ArchiveUtils::to_offset(caller_ik),
ArchiveUtils::to_offset(invoked_name),
ArchiveUtils::to_offset(invoked_type),
ArchiveUtils::to_offset(method_type),
ArchiveUtils::to_offset(member_method),
ArchiveUtils::to_offset(instantiated_method_type));
}
unsigned int hash() const;
bool equals(RunTimeLambdaProxyClassKey const& other) const {
return _caller_ik == other._caller_ik &&
_invoked_name == other._invoked_name &&
_invoked_type == other._invoked_type &&
_method_type == other._method_type &&
_member_method == other._member_method &&
_instantiated_method_type == other._instantiated_method_type;
}
#ifndef PRODUCT
void print_on(outputStream* st) const;
@ -133,17 +204,17 @@ public:
};
class RunTimeLambdaProxyClassInfo {
LambdaProxyClassKey _key;
RunTimeLambdaProxyClassKey _key;
InstanceKlass* _proxy_klass_head;
public:
RunTimeLambdaProxyClassInfo(LambdaProxyClassKey key, InstanceKlass* proxy_klass_head) :
RunTimeLambdaProxyClassInfo(RunTimeLambdaProxyClassKey key, InstanceKlass* proxy_klass_head) :
_key(key), _proxy_klass_head(proxy_klass_head) {}
InstanceKlass* proxy_klass_head() const { return _proxy_klass_head; }
// Used by LambdaProxyClassDictionary to implement OffsetCompactHashtable::EQUALS
static inline bool EQUALS(
const RunTimeLambdaProxyClassInfo* value, LambdaProxyClassKey* key, int len_unused) {
const RunTimeLambdaProxyClassInfo* value, RunTimeLambdaProxyClassKey* key, int len_unused) {
return (value->_key.equals(*key));
}
void init(LambdaProxyClassKey& key, DumpTimeLambdaProxyClassInfo& info);
@ -151,7 +222,7 @@ public:
unsigned int hash() const {
return _key.hash();
}
LambdaProxyClassKey key() const {
RunTimeLambdaProxyClassKey key() const {
return _key;
}
#ifndef PRODUCT
@ -173,7 +244,7 @@ public:
};
class LambdaProxyClassDictionary : public OffsetCompactHashtable<
LambdaProxyClassKey*,
RunTimeLambdaProxyClassKey*,
const RunTimeLambdaProxyClassInfo*,
RunTimeLambdaProxyClassInfo::EQUALS> {};

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -30,9 +30,10 @@
void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
ArchiveBuilder* builder = ArchiveBuilder::current();
builder->write_pointer_in_buffer(&_klass, info._klass);
InstanceKlass* k = info._klass;
_klass_offset = builder->any_to_offset_u4(k);
if (!SystemDictionaryShared::is_builtin(_klass)) {
if (!SystemDictionaryShared::is_builtin(k)) {
CrcInfo* c = crc();
c->_clsfile_size = info._clsfile_size;
c->_clsfile_crc32 = info._clsfile_crc32;
@ -61,10 +62,10 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
}
}
if (_klass->is_hidden()) {
builder->write_pointer_in_buffer(nest_host_addr(), info.nest_host());
if (k->is_hidden()) {
_nest_host_offset = builder->any_to_offset_u4(info.nest_host());
}
if (_klass->has_archived_enum_objs()) {
if (k->has_archived_enum_objs()) {
int num = info.num_enum_klass_static_fields();
set_num_enum_klass_static_fields(num);
for (int i = 0; i < num; i++) {
@ -74,6 +75,14 @@ void RunTimeClassInfo::init(DumpTimeClassInfo& info) {
}
}
InstanceKlass* RunTimeClassInfo::klass() const {
if (ArchiveBuilder::is_active() && ArchiveBuilder::current()->is_in_buffer_space((address)this)) {
return ArchiveBuilder::current()->offset_to_buffered<InstanceKlass*>(_klass_offset);
} else {
return ArchiveUtils::from_offset<InstanceKlass*>(_klass_offset);
}
}
size_t RunTimeClassInfo::crc_size(InstanceKlass* klass) {
if (!SystemDictionaryShared::is_builtin(klass)) {
return sizeof(CrcInfo);

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 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
@ -52,24 +52,24 @@ public:
struct RTVerifierConstraint {
u4 _name;
u4 _from_name;
Symbol* name() { return (Symbol*)(SharedBaseAddress + _name);}
Symbol* from_name() { return (Symbol*)(SharedBaseAddress + _from_name); }
Symbol* name() { return ArchiveUtils::from_offset<Symbol*>(_name); }
Symbol* from_name() { return ArchiveUtils::from_offset<Symbol*>(_from_name); }
};
struct RTLoaderConstraint {
u4 _name;
char _loader_type1;
char _loader_type2;
Symbol* constraint_name() {
return (Symbol*)(SharedBaseAddress + _name);
}
Symbol* constraint_name() { return ArchiveUtils::from_offset<Symbol*>(_name); }
};
struct RTEnumKlassStaticFields {
int _num;
int _root_indices[1];
};
InstanceKlass* _klass;
private:
u4 _klass_offset;
u4 _nest_host_offset;
int _num_verifier_constraints;
int _num_loader_constraints;
@ -80,7 +80,6 @@ public:
// optional char _verifier_constraint_flags[_num_verifier_constraints]
// optional RTEnumKlassStaticFields _enum_klass_static_fields;
private:
static size_t header_size_size() {
return align_up(sizeof(RunTimeClassInfo), wordSize);
}
@ -108,6 +107,9 @@ private:
static size_t crc_size(InstanceKlass* klass);
public:
InstanceKlass* klass() const;
int num_verifier_constraints() const { return _num_verifier_constraints; }
int num_loader_constraints() const { return _num_loader_constraints; }
static size_t byte_size(InstanceKlass* klass, int num_verifier_constraints, int num_loader_constraints,
int num_enum_klass_static_fields) {
return header_size_size() +
@ -125,11 +127,11 @@ private:
}
size_t nest_host_offset() const {
return crc_offset() + crc_size(_klass);
return crc_offset() + crc_size(klass());
}
size_t loader_constraints_offset() const {
return nest_host_offset() + nest_host_size(_klass);
return nest_host_offset() + nest_host_size(klass());
}
size_t verifier_constraints_offset() const {
return loader_constraints_offset() + loader_constraints_size(_num_loader_constraints);
@ -150,13 +152,13 @@ private:
}
RTEnumKlassStaticFields* enum_klass_static_fields_addr() const {
assert(_klass->has_archived_enum_objs(), "sanity");
assert(klass()->has_archived_enum_objs(), "sanity");
return (RTEnumKlassStaticFields*)(address(this) + enum_klass_static_fields_offset());
}
public:
CrcInfo* crc() const {
assert(crc_size(_klass) > 0, "must be");
assert(crc_size(klass()) > 0, "must be");
return (CrcInfo*)(address(this) + crc_offset());
}
RTVerifierConstraint* verifier_constraints() {
@ -173,12 +175,9 @@ public:
return (char*)(address(this) + verifier_constraint_flags_offset());
}
InstanceKlass** nest_host_addr() {
assert(_klass->is_hidden(), "sanity");
return (InstanceKlass**)(address(this) + nest_host_offset());
}
InstanceKlass* nest_host() {
return *nest_host_addr();
assert(!ArchiveBuilder::is_active(), "not called when dumping archive");
return ArchiveUtils::from_offset<InstanceKlass*>(_nest_host_offset);
}
RTLoaderConstraint* loader_constraints() {
@ -248,7 +247,7 @@ public:
// Used by RunTimeSharedDictionary to implement OffsetCompactHashtable::EQUALS
static inline bool EQUALS(
const RunTimeClassInfo* value, Symbol* key, int len_unused) {
return (value->_klass->name() == key);
return (value->klass()->name() == key);
}
};

@ -134,7 +134,7 @@ InstanceKlass* SystemDictionaryShared::lookup_from_stream(Symbol* class_name,
return nullptr;
}
return acquire_class_for_current_thread(record->_klass, class_loader,
return acquire_class_for_current_thread(record->klass(), class_loader,
protection_domain, cfs,
THREAD);
}
@ -789,9 +789,20 @@ InstanceKlass* SystemDictionaryShared::get_shared_lambda_proxy_class(InstanceKla
Symbol* method_type,
Method* member_method,
Symbol* instantiated_method_type) {
if (!caller_ik->is_shared() ||
!invoked_name->is_shared() ||
!invoked_type->is_shared() ||
!method_type->is_shared() ||
!member_method->is_shared() ||
!instantiated_method_type->is_shared()) {
// These can't be represented as u4 offset, but we wouldn't have archived a lambda proxy in this case anyway.
return nullptr;
}
MutexLocker ml(CDSLambda_lock, Mutex::_no_safepoint_check_flag);
LambdaProxyClassKey key(caller_ik, invoked_name, invoked_type,
method_type, member_method, instantiated_method_type);
RunTimeLambdaProxyClassKey key =
RunTimeLambdaProxyClassKey::init_for_runtime(caller_ik, invoked_name, invoked_type,
method_type, member_method, instantiated_method_type);
// Try to retrieve the lambda proxy class from static archive.
const RunTimeLambdaProxyClassInfo* info = _static_archive.lookup_lambda_proxy_class(&key);
@ -899,7 +910,7 @@ void SystemDictionaryShared::check_verification_constraints(InstanceKlass* klass
assert(!CDSConfig::is_dumping_static_archive() && CDSConfig::is_using_archive(), "called at run time with CDS enabled only");
RunTimeClassInfo* record = RunTimeClassInfo::get_for(klass);
int length = record->_num_verifier_constraints;
int length = record->num_verifier_constraints();
if (length > 0) {
for (int i = 0; i < length; i++) {
RunTimeClassInfo::RTVerifierConstraint* vc = record->verifier_constraint_at(i);
@ -1015,9 +1026,9 @@ bool SystemDictionaryShared::check_linking_constraints(Thread* current, Instance
if (klass->is_shared_platform_class() || klass->is_shared_app_class()) {
RunTimeClassInfo* info = RunTimeClassInfo::get_for(klass);
assert(info != nullptr, "Sanity");
if (info->_num_loader_constraints > 0) {
if (info->num_loader_constraints() > 0) {
HandleMark hm(current);
for (int i = 0; i < info->_num_loader_constraints; i++) {
for (int i = 0; i < info->num_loader_constraints(); i++) {
RunTimeClassInfo::RTLoaderConstraint* lc = info->loader_constraint_at(i);
Symbol* name = lc->constraint_name();
Handle loader1(current, get_class_loader_by(lc->_loader_type1));
@ -1333,14 +1344,14 @@ InstanceKlass* SystemDictionaryShared::find_builtin_class(Symbol* name) {
&_dynamic_archive._builtin_dictionary,
name);
if (record != nullptr) {
assert(!record->_klass->is_hidden(), "hidden class cannot be looked up by name");
assert(check_alignment(record->_klass), "Address not aligned");
assert(!record->klass()->is_hidden(), "hidden class cannot be looked up by name");
assert(check_alignment(record->klass()), "Address not aligned");
// We did not save the classfile data of the generated LambdaForm invoker classes,
// so we cannot support CLFH for such classes.
if (record->_klass->is_generated_shared_class() && JvmtiExport::should_post_class_file_load_hook()) {
if (record->klass()->is_generated_shared_class() && JvmtiExport::should_post_class_file_load_hook()) {
return nullptr;
}
return record->_klass;
return record->klass();
} else {
return nullptr;
}
@ -1378,10 +1389,10 @@ public:
void do_value(const RunTimeClassInfo* record) {
ResourceMark rm;
_st->print_cr("%4d: %s %s", _index++, record->_klass->external_name(),
class_loader_name_for_shared(record->_klass));
if (record->_klass->array_klasses() != nullptr) {
record->_klass->array_klasses()->cds_print_value_on(_st);
_st->print_cr("%4d: %s %s", _index++, record->klass()->external_name(),
class_loader_name_for_shared(record->klass()));
if (record->klass()->array_klasses() != nullptr) {
record->klass()->array_klasses()->cds_print_value_on(_st);
_st->cr();
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 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
@ -145,7 +145,7 @@ class SystemDictionaryShared: public SystemDictionary {
RunTimeSharedDictionary _unregistered_dictionary;
LambdaProxyClassDictionary _lambda_proxy_class_dictionary;
const RunTimeLambdaProxyClassInfo* lookup_lambda_proxy_class(LambdaProxyClassKey* key) {
const RunTimeLambdaProxyClassInfo* lookup_lambda_proxy_class(RunTimeLambdaProxyClassKey* key) {
return _lambda_proxy_class_dictionary.lookup(key, key->hash(), 0);
}