Skip to content

Commit e6b4beb

Browse files
TimPushkinPaul Hohensee
authored andcommitted
8348240: Remove SystemDictionaryShared::lookup_super_for_unregistered_class()
Reviewed-by: iklam Backport-of: 7f16a0875ced8669b9d2131c67496a66e74ea36f
1 parent 6de5133 commit e6b4beb

File tree

10 files changed

+231
-152
lines changed

10 files changed

+231
-152
lines changed

src/hotspot/share/cds/classListParser.cpp

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include "jvm.h"
4343
#include "logging/log.hpp"
4444
#include "logging/logTag.hpp"
45+
#include "memory/oopFactory.hpp"
4546
#include "memory/resourceArea.hpp"
4647
#include "oops/constantPool.hpp"
4748
#include "runtime/atomic.hpp"
@@ -97,6 +98,12 @@ ClassListParser::~ClassListParser() {
9798
_instance = nullptr;
9899
}
99100

101+
int ClassListParser::parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS) {
102+
UnregisteredClasses::initialize(CHECK_0);
103+
ClassListParser parser(classlist_path, parse_mode);
104+
return parser.parse(THREAD); // returns the number of classes loaded.
105+
}
106+
100107
int ClassListParser::parse(TRAPS) {
101108
int class_count = 0;
102109

@@ -390,6 +397,19 @@ bool ClassListParser::parse_uint_option(const char* option_name, int* value) {
390397
return false;
391398
}
392399

400+
objArrayOop ClassListParser::get_specified_interfaces(TRAPS) {
401+
const int n = _interfaces->length();
402+
if (n == 0) {
403+
return nullptr;
404+
} else {
405+
objArrayOop array = oopFactory::new_objArray(vmClasses::Class_klass(), n, CHECK_NULL);
406+
for (int i = 0; i < n; i++) {
407+
array->obj_at_put(i, lookup_class_by_id(_interfaces->at(i))->java_mirror());
408+
}
409+
return array;
410+
}
411+
}
412+
393413
void ClassListParser::print_specified_interfaces() {
394414
const int n = _interfaces->length();
395415
jio_fprintf(defaultStream::error_stream(), "Currently specified interfaces[%d] = {\n", n);
@@ -474,7 +494,17 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS
474494

475495
ResourceMark rm;
476496
char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source));
477-
InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL);
497+
InstanceKlass* specified_super = lookup_class_by_id(_super);
498+
Handle super_class(THREAD, specified_super->java_mirror());
499+
objArrayOop r = get_specified_interfaces(CHECK_NULL);
500+
objArrayHandle interfaces(THREAD, r);
501+
InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path,
502+
super_class, interfaces, CHECK_NULL);
503+
if (k->java_super() != specified_super) {
504+
error("The specified super class %s (id %d) does not match actual super class %s",
505+
specified_super->external_name(), _super,
506+
k->java_super()->external_name());
507+
}
478508
if (k->local_interfaces()->length() != _interfaces->length()) {
479509
print_specified_interfaces();
480510
print_actual_interfaces(k);
@@ -682,46 +712,3 @@ InstanceKlass* ClassListParser::lookup_class_by_id(int id) {
682712
assert(*klass_ptr != nullptr, "must be");
683713
return *klass_ptr;
684714
}
685-
686-
687-
InstanceKlass* ClassListParser::lookup_super_for_current_class(Symbol* super_name) {
688-
if (!is_loading_from_source()) {
689-
return nullptr;
690-
}
691-
692-
InstanceKlass* k = lookup_class_by_id(super());
693-
if (super_name != k->name()) {
694-
error("The specified super class %s (id %d) does not match actual super class %s",
695-
k->name()->as_klass_external_name(), super(),
696-
super_name->as_klass_external_name());
697-
}
698-
return k;
699-
}
700-
701-
InstanceKlass* ClassListParser::lookup_interface_for_current_class(Symbol* interface_name) {
702-
if (!is_loading_from_source()) {
703-
return nullptr;
704-
}
705-
706-
const int n = _interfaces->length();
707-
if (n == 0) {
708-
error("Class %s implements the interface %s, but no interface has been specified in the input line",
709-
_class_name, interface_name->as_klass_external_name());
710-
ShouldNotReachHere();
711-
}
712-
713-
int i;
714-
for (i=0; i<n; i++) {
715-
InstanceKlass* k = lookup_class_by_id(_interfaces->at(i));
716-
if (interface_name == k->name()) {
717-
return k;
718-
}
719-
}
720-
721-
// interface_name is not specified by the "interfaces:" keyword.
722-
print_specified_interfaces();
723-
error("The interface %s implemented by class %s does not match any of the specified interface IDs",
724-
interface_name->as_klass_external_name(), _class_name);
725-
ShouldNotReachHere();
726-
return nullptr;
727-
}

src/hotspot/share/cds/classListParser.hpp

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -134,12 +134,10 @@ class ClassListParser : public StackObj {
134134

135135
ClassListParser(const char* file, ParseMode _parse_mode);
136136
~ClassListParser();
137+
objArrayOop get_specified_interfaces(TRAPS);
137138

138139
public:
139-
static int parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS) {
140-
ClassListParser parser(classlist_path, parse_mode);
141-
return parser.parse(THREAD); // returns the number of classes loaded.
142-
}
140+
static int parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS);
143141

144142
static bool is_parsing_thread();
145143
static ClassListParser* instance() {
@@ -192,11 +190,6 @@ class ClassListParser : public StackObj {
192190

193191
bool lambda_form_line() { return _lambda_form_line; }
194192

195-
// Look up the super or interface of the current class being loaded
196-
// (in this->load_current_class()).
197-
InstanceKlass* lookup_super_for_current_class(Symbol* super_name);
198-
InstanceKlass* lookup_interface_for_current_class(Symbol* interface_name);
199-
200193
static void populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS);
201194
};
202195
#endif // SHARE_CDS_CLASSLISTPARSER_HPP

src/hotspot/share/cds/unregisteredClasses.cpp

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
#include "classfile/classLoaderExt.hpp"
3030
#include "classfile/javaClasses.inline.hpp"
3131
#include "classfile/symbolTable.hpp"
32-
#include "classfile/systemDictionaryShared.hpp"
32+
#include "classfile/systemDictionary.hpp"
3333
#include "classfile/vmSymbols.hpp"
3434
#include "memory/oopFactory.hpp"
3535
#include "memory/resourceArea.hpp"
@@ -39,76 +39,82 @@
3939
#include "runtime/javaCalls.hpp"
4040
#include "services/threadService.hpp"
4141

42+
InstanceKlass* UnregisteredClasses::_UnregisteredClassLoader_klass = nullptr;
43+
44+
void UnregisteredClasses::initialize(TRAPS) {
45+
if (_UnregisteredClassLoader_klass == nullptr) {
46+
// no need for synchronization as this function is called single-threaded.
47+
Symbol* klass_name = SymbolTable::new_symbol("jdk/internal/misc/CDS$UnregisteredClassLoader");
48+
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK);
49+
_UnregisteredClassLoader_klass = InstanceKlass::cast(k);
50+
}
51+
}
52+
4253
// Load the class of the given name from the location given by path. The path is specified by
4354
// the "source:" in the class list file (see classListParser.cpp), and can be a directory or
4455
// a JAR file.
45-
InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, TRAPS) {
56+
InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path,
57+
Handle super_class, objArrayHandle interfaces, TRAPS) {
4658
assert(name != nullptr, "invariant");
4759
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
4860

4961
PerfClassTraceTime vmtimer(ClassLoader::perf_app_classload_time(),
5062
THREAD->get_thread_stat()->perf_timers_addr(),
5163
PerfClassTraceTime::CLASS_LOAD);
5264

65+
// Call CDS$UnregisteredClassLoader::load(String name, Class<?> superClass, Class<?>[] interfaces)
66+
Symbol* methodName = SymbolTable::new_symbol("load");
67+
Symbol* methodSignature = SymbolTable::new_symbol("(Ljava/lang/String;Ljava/lang/Class;[Ljava/lang/Class;)Ljava/lang/Class;");
5368
Symbol* path_symbol = SymbolTable::new_symbol(path);
54-
Handle url_classloader = get_url_classloader(path_symbol, CHECK_NULL);
69+
Handle classloader = get_classloader(path_symbol, CHECK_NULL);
5570
Handle ext_class_name = java_lang_String::externalize_classname(name, CHECK_NULL);
5671

5772
JavaValue result(T_OBJECT);
58-
JavaCallArguments args(2);
59-
args.set_receiver(url_classloader);
73+
JavaCallArguments args(3);
74+
args.set_receiver(classloader);
6075
args.push_oop(ext_class_name);
61-
args.push_int(JNI_FALSE);
76+
args.push_oop(super_class);
77+
args.push_oop(interfaces);
6278
JavaCalls::call_virtual(&result,
63-
vmClasses::URLClassLoader_klass(),
64-
vmSymbols::loadClass_name(),
65-
vmSymbols::string_boolean_class_signature(),
79+
UnregisteredClassLoader_klass(),
80+
methodName,
81+
methodSignature,
6682
&args,
6783
CHECK_NULL);
6884
assert(result.get_type() == T_OBJECT, "just checking");
6985
oop obj = result.get_oop();
7086
return InstanceKlass::cast(java_lang_Class::as_Klass(obj));
7187
}
7288

73-
class URLClassLoaderTable : public ResourceHashtable<
89+
class UnregisteredClasses::ClassLoaderTable : public ResourceHashtable<
7490
Symbol*, OopHandle,
7591
137, // prime number
7692
AnyObj::C_HEAP> {};
7793

78-
static URLClassLoaderTable* _url_classloader_table = nullptr;
94+
static UnregisteredClasses::ClassLoaderTable* _classloader_table = nullptr;
7995

80-
Handle UnregisteredClasses::create_url_classloader(Symbol* path, TRAPS) {
96+
Handle UnregisteredClasses::create_classloader(Symbol* path, TRAPS) {
8197
ResourceMark rm(THREAD);
8298
JavaValue result(T_OBJECT);
8399
Handle path_string = java_lang_String::create_from_str(path->as_C_string(), CHECK_NH);
84-
JavaCalls::call_static(&result,
85-
vmClasses::jdk_internal_loader_ClassLoaders_klass(),
86-
vmSymbols::toFileURL_name(),
87-
vmSymbols::toFileURL_signature(),
88-
path_string, CHECK_NH);
89-
assert(result.get_type() == T_OBJECT, "just checking");
90-
oop url_h = result.get_oop();
91-
objArrayHandle urls = oopFactory::new_objArray_handle(vmClasses::URL_klass(), 1, CHECK_NH);
92-
urls->obj_at_put(0, url_h);
93-
94-
Handle url_classloader = JavaCalls::construct_new_instance(
95-
vmClasses::URLClassLoader_klass(),
96-
vmSymbols::url_array_classloader_void_signature(),
97-
urls, Handle(), CHECK_NH);
98-
return url_classloader;
100+
Handle classloader = JavaCalls::construct_new_instance(
101+
UnregisteredClassLoader_klass(),
102+
vmSymbols::string_void_signature(),
103+
path_string, CHECK_NH);
104+
return classloader;
99105
}
100106

101-
Handle UnregisteredClasses::get_url_classloader(Symbol* path, TRAPS) {
102-
if (_url_classloader_table == nullptr) {
103-
_url_classloader_table = new (mtClass)URLClassLoaderTable();
107+
Handle UnregisteredClasses::get_classloader(Symbol* path, TRAPS) {
108+
if (_classloader_table == nullptr) {
109+
_classloader_table = new (mtClass)ClassLoaderTable();
104110
}
105-
OopHandle* url_classloader_ptr = _url_classloader_table->get(path);
106-
if (url_classloader_ptr != nullptr) {
107-
return Handle(THREAD, (*url_classloader_ptr).resolve());
111+
OopHandle* classloader_ptr = _classloader_table->get(path);
112+
if (classloader_ptr != nullptr) {
113+
return Handle(THREAD, (*classloader_ptr).resolve());
108114
} else {
109-
Handle url_classloader = create_url_classloader(path, CHECK_NH);
110-
_url_classloader_table->put(path, OopHandle(Universe::vm_global(), url_classloader()));
115+
Handle classloader = create_classloader(path, CHECK_NH);
116+
_classloader_table->put(path, OopHandle(Universe::vm_global(), classloader()));
111117
path->increment_refcount();
112-
return url_classloader;
118+
return classloader;
113119
}
114120
}

src/hotspot/share/cds/unregisteredClasses.hpp

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -25,15 +25,30 @@
2525
#ifndef SHARE_CDS_UNREGISTEREDCLASSES_HPP
2626
#define SHARE_CDS_UNREGISTEREDCLASSES_HPP
2727

28+
#include "memory/allStatic.hpp"
2829
#include "runtime/handles.hpp"
2930

31+
class InstanceKlass;
32+
class Symbol;
33+
3034
class UnregisteredClasses: AllStatic {
3135
public:
32-
static InstanceKlass* load_class(Symbol* h_name, const char* path, TRAPS);
36+
static InstanceKlass* load_class(Symbol* h_name, const char* path,
37+
Handle super_class, objArrayHandle interfaces,
38+
TRAPS);
39+
static void initialize(TRAPS);
40+
static InstanceKlass* UnregisteredClassLoader_klass() {
41+
return _UnregisteredClassLoader_klass;
42+
}
43+
44+
class ClassLoaderTable;
3345

3446
private:
35-
static Handle create_url_classloader(Symbol* path, TRAPS);
36-
static Handle get_url_classloader(Symbol* path, TRAPS);
47+
// Don't put this in vmClasses as it's used only with CDS dumping.
48+
static InstanceKlass* _UnregisteredClassLoader_klass;
49+
50+
static Handle create_classloader(Symbol* path, TRAPS);
51+
static Handle get_classloader(Symbol* path, TRAPS);
3752
};
3853

3954
#endif // SHARE_CDS_UNREGISTEREDCLASSES_HPP

src/hotspot/share/classfile/systemDictionary.cpp

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -412,16 +412,6 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
412412

413413
assert(super_name != nullptr, "null superclass for resolving");
414414
assert(!Signature::is_array(super_name), "invalid superclass name");
415-
#if INCLUDE_CDS
416-
if (DumpSharedSpaces) {
417-
// Special processing for handling UNREGISTERED shared classes.
418-
InstanceKlass* k = SystemDictionaryShared::lookup_super_for_unregistered_class(class_name,
419-
super_name, is_superclass);
420-
if (k) {
421-
return k;
422-
}
423-
}
424-
#endif // INCLUDE_CDS
425415

426416
// If klass is already loaded, just return the superclass or superinterface.
427417
// Make sure there's a placeholder for the class_name before resolving.

src/hotspot/share/classfile/systemDictionaryShared.cpp

Lines changed: 7 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "cds/dumpTimeClassInfo.inline.hpp"
3535
#include "cds/metaspaceShared.hpp"
3636
#include "cds/runTimeClassInfo.hpp"
37+
#include "cds/unregisteredClasses.hpp"
3738
#include "classfile/classFileStream.hpp"
3839
#include "classfile/classLoader.hpp"
3940
#include "classfile/classLoaderData.inline.hpp"
@@ -331,6 +332,12 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
331332
}
332333
}
333334

335+
if (k == UnregisteredClasses::UnregisteredClassLoader_klass()) {
336+
ResourceMark rm;
337+
log_info(cds)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string());
338+
return true;
339+
}
340+
334341
return false; // false == k should NOT be excluded
335342
}
336343

@@ -449,45 +456,6 @@ bool SystemDictionaryShared::add_unregistered_class(Thread* current, InstanceKla
449456
return (klass == *v);
450457
}
451458

452-
// This function is called to lookup the super/interfaces of shared classes for
453-
// unregistered loaders. E.g., SharedClass in the below example
454-
// where "super:" (and optionally "interface:") have been specified.
455-
//
456-
// java/lang/Object id: 0
457-
// Interface id: 2 super: 0 source: cust.jar
458-
// SharedClass id: 4 super: 0 interfaces: 2 source: cust.jar
459-
InstanceKlass* SystemDictionaryShared::lookup_super_for_unregistered_class(
460-
Symbol* class_name, Symbol* super_name, bool is_superclass) {
461-
462-
assert(DumpSharedSpaces, "only when static dumping");
463-
464-
if (!ClassListParser::is_parsing_thread()) {
465-
// Unregistered classes can be created only by ClassListParser::_parsing_thread.
466-
467-
return nullptr;
468-
}
469-
470-
ClassListParser* parser = ClassListParser::instance();
471-
if (parser == nullptr) {
472-
// We're still loading the well-known classes, before the ClassListParser is created.
473-
return nullptr;
474-
}
475-
if (class_name->equals(parser->current_class_name())) {
476-
// When this function is called, all the numbered super and interface types
477-
// must have already been loaded. Hence this function is never recursively called.
478-
if (is_superclass) {
479-
return parser->lookup_super_for_current_class(super_name);
480-
} else {
481-
return parser->lookup_interface_for_current_class(super_name);
482-
}
483-
} else {
484-
// The VM is not trying to resolve a super type of parser->current_class_name().
485-
// Instead, it's resolving an error class (because parser->current_class_name() has
486-
// failed parsing or verification). Don't do anything here.
487-
return nullptr;
488-
}
489-
}
490-
491459
void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
492460
Arguments::assert_is_dumping_archive();
493461
assert(!is_builtin(k), "must be unregistered class");

0 commit comments

Comments
 (0)