Skip to content

8348240: Remove SystemDictionaryShared::lookup_super_for_unregistered_class() #1834

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: pr/1833
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 31 additions & 44 deletions src/hotspot/share/cds/classListParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include "jvm.h"
#include "logging/log.hpp"
#include "logging/logTag.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "oops/constantPool.hpp"
#include "runtime/atomic.hpp"
Expand Down Expand Up @@ -97,6 +98,12 @@ ClassListParser::~ClassListParser() {
_instance = nullptr;
}

int ClassListParser::parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS) {
UnregisteredClasses::initialize(CHECK_0);
ClassListParser parser(classlist_path, parse_mode);
return parser.parse(THREAD); // returns the number of classes loaded.
}

int ClassListParser::parse(TRAPS) {
int class_count = 0;

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

objArrayOop ClassListParser::get_specified_interfaces(TRAPS) {
const int n = _interfaces->length();
if (n == 0) {
return nullptr;
} else {
objArrayOop array = oopFactory::new_objArray(vmClasses::Class_klass(), n, CHECK_NULL);
for (int i = 0; i < n; i++) {
array->obj_at_put(i, lookup_class_by_id(_interfaces->at(i))->java_mirror());
}
return array;
}
}

void ClassListParser::print_specified_interfaces() {
const int n = _interfaces->length();
jio_fprintf(defaultStream::error_stream(), "Currently specified interfaces[%d] = {\n", n);
Expand Down Expand Up @@ -474,7 +494,17 @@ InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS

ResourceMark rm;
char * source_path = os::strdup_check_oom(ClassLoader::uri_to_path(_source));
InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path, CHECK_NULL);
InstanceKlass* specified_super = lookup_class_by_id(_super);
Handle super_class(THREAD, specified_super->java_mirror());
objArrayOop r = get_specified_interfaces(CHECK_NULL);
objArrayHandle interfaces(THREAD, r);
InstanceKlass* k = UnregisteredClasses::load_class(class_name, source_path,
super_class, interfaces, CHECK_NULL);
if (k->java_super() != specified_super) {
error("The specified super class %s (id %d) does not match actual super class %s",
specified_super->external_name(), _super,
k->java_super()->external_name());
}
if (k->local_interfaces()->length() != _interfaces->length()) {
print_specified_interfaces();
print_actual_interfaces(k);
Expand Down Expand Up @@ -682,46 +712,3 @@ InstanceKlass* ClassListParser::lookup_class_by_id(int id) {
assert(*klass_ptr != nullptr, "must be");
return *klass_ptr;
}


InstanceKlass* ClassListParser::lookup_super_for_current_class(Symbol* super_name) {
if (!is_loading_from_source()) {
return nullptr;
}

InstanceKlass* k = lookup_class_by_id(super());
if (super_name != k->name()) {
error("The specified super class %s (id %d) does not match actual super class %s",
k->name()->as_klass_external_name(), super(),
super_name->as_klass_external_name());
}
return k;
}

InstanceKlass* ClassListParser::lookup_interface_for_current_class(Symbol* interface_name) {
if (!is_loading_from_source()) {
return nullptr;
}

const int n = _interfaces->length();
if (n == 0) {
error("Class %s implements the interface %s, but no interface has been specified in the input line",
_class_name, interface_name->as_klass_external_name());
ShouldNotReachHere();
}

int i;
for (i=0; i<n; i++) {
InstanceKlass* k = lookup_class_by_id(_interfaces->at(i));
if (interface_name == k->name()) {
return k;
}
}

// interface_name is not specified by the "interfaces:" keyword.
print_specified_interfaces();
error("The interface %s implemented by class %s does not match any of the specified interface IDs",
interface_name->as_klass_external_name(), _class_name);
ShouldNotReachHere();
return nullptr;
}
13 changes: 3 additions & 10 deletions src/hotspot/share/cds/classListParser.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, 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
Expand Down Expand Up @@ -134,12 +134,10 @@ class ClassListParser : public StackObj {

ClassListParser(const char* file, ParseMode _parse_mode);
~ClassListParser();
objArrayOop get_specified_interfaces(TRAPS);

public:
static int parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS) {
ClassListParser parser(classlist_path, parse_mode);
return parser.parse(THREAD); // returns the number of classes loaded.
}
static int parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS);

static bool is_parsing_thread();
static ClassListParser* instance() {
Expand Down Expand Up @@ -192,11 +190,6 @@ class ClassListParser : public StackObj {

bool lambda_form_line() { return _lambda_form_line; }

// Look up the super or interface of the current class being loaded
// (in this->load_current_class()).
InstanceKlass* lookup_super_for_current_class(Symbol* super_name);
InstanceKlass* lookup_interface_for_current_class(Symbol* interface_name);

static void populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS);
};
#endif // SHARE_CDS_CLASSLISTPARSER_HPP
78 changes: 42 additions & 36 deletions src/hotspot/share/cds/unregisteredClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "classfile/classLoaderExt.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
Expand All @@ -39,76 +39,82 @@
#include "runtime/javaCalls.hpp"
#include "services/threadService.hpp"

InstanceKlass* UnregisteredClasses::_UnregisteredClassLoader_klass = nullptr;

void UnregisteredClasses::initialize(TRAPS) {
if (_UnregisteredClassLoader_klass == nullptr) {
// no need for synchronization as this function is called single-threaded.
Symbol* klass_name = SymbolTable::new_symbol("jdk/internal/misc/CDS$UnregisteredClassLoader");
Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK);
_UnregisteredClassLoader_klass = InstanceKlass::cast(k);
}
}

// Load the class of the given name from the location given by path. The path is specified by
// the "source:" in the class list file (see classListParser.cpp), and can be a directory or
// a JAR file.
InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path, TRAPS) {
InstanceKlass* UnregisteredClasses::load_class(Symbol* name, const char* path,
Handle super_class, objArrayHandle interfaces, TRAPS) {
assert(name != nullptr, "invariant");
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");

PerfClassTraceTime vmtimer(ClassLoader::perf_app_classload_time(),
THREAD->get_thread_stat()->perf_timers_addr(),
PerfClassTraceTime::CLASS_LOAD);

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

JavaValue result(T_OBJECT);
JavaCallArguments args(2);
args.set_receiver(url_classloader);
JavaCallArguments args(3);
args.set_receiver(classloader);
args.push_oop(ext_class_name);
args.push_int(JNI_FALSE);
args.push_oop(super_class);
args.push_oop(interfaces);
JavaCalls::call_virtual(&result,
vmClasses::URLClassLoader_klass(),
vmSymbols::loadClass_name(),
vmSymbols::string_boolean_class_signature(),
UnregisteredClassLoader_klass(),
methodName,
methodSignature,
&args,
CHECK_NULL);
assert(result.get_type() == T_OBJECT, "just checking");
oop obj = result.get_oop();
return InstanceKlass::cast(java_lang_Class::as_Klass(obj));
}

class URLClassLoaderTable : public ResourceHashtable<
class UnregisteredClasses::ClassLoaderTable : public ResourceHashtable<
Symbol*, OopHandle,
137, // prime number
AnyObj::C_HEAP> {};

static URLClassLoaderTable* _url_classloader_table = nullptr;
static UnregisteredClasses::ClassLoaderTable* _classloader_table = nullptr;

Handle UnregisteredClasses::create_url_classloader(Symbol* path, TRAPS) {
Handle UnregisteredClasses::create_classloader(Symbol* path, TRAPS) {
ResourceMark rm(THREAD);
JavaValue result(T_OBJECT);
Handle path_string = java_lang_String::create_from_str(path->as_C_string(), CHECK_NH);
JavaCalls::call_static(&result,
vmClasses::jdk_internal_loader_ClassLoaders_klass(),
vmSymbols::toFileURL_name(),
vmSymbols::toFileURL_signature(),
path_string, CHECK_NH);
assert(result.get_type() == T_OBJECT, "just checking");
oop url_h = result.get_oop();
objArrayHandle urls = oopFactory::new_objArray_handle(vmClasses::URL_klass(), 1, CHECK_NH);
urls->obj_at_put(0, url_h);

Handle url_classloader = JavaCalls::construct_new_instance(
vmClasses::URLClassLoader_klass(),
vmSymbols::url_array_classloader_void_signature(),
urls, Handle(), CHECK_NH);
return url_classloader;
Handle classloader = JavaCalls::construct_new_instance(
UnregisteredClassLoader_klass(),
vmSymbols::string_void_signature(),
path_string, CHECK_NH);
return classloader;
}

Handle UnregisteredClasses::get_url_classloader(Symbol* path, TRAPS) {
if (_url_classloader_table == nullptr) {
_url_classloader_table = new (mtClass)URLClassLoaderTable();
Handle UnregisteredClasses::get_classloader(Symbol* path, TRAPS) {
if (_classloader_table == nullptr) {
_classloader_table = new (mtClass)ClassLoaderTable();
}
OopHandle* url_classloader_ptr = _url_classloader_table->get(path);
if (url_classloader_ptr != nullptr) {
return Handle(THREAD, (*url_classloader_ptr).resolve());
OopHandle* classloader_ptr = _classloader_table->get(path);
if (classloader_ptr != nullptr) {
return Handle(THREAD, (*classloader_ptr).resolve());
} else {
Handle url_classloader = create_url_classloader(path, CHECK_NH);
_url_classloader_table->put(path, OopHandle(Universe::vm_global(), url_classloader()));
Handle classloader = create_classloader(path, CHECK_NH);
_classloader_table->put(path, OopHandle(Universe::vm_global(), classloader()));
path->increment_refcount();
return url_classloader;
return classloader;
}
}
23 changes: 19 additions & 4 deletions src/hotspot/share/cds/unregisteredClasses.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2025, 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
Expand All @@ -25,15 +25,30 @@
#ifndef SHARE_CDS_UNREGISTEREDCLASSES_HPP
#define SHARE_CDS_UNREGISTEREDCLASSES_HPP

#include "memory/allStatic.hpp"
#include "runtime/handles.hpp"

class InstanceKlass;
class Symbol;

class UnregisteredClasses: AllStatic {
public:
static InstanceKlass* load_class(Symbol* h_name, const char* path, TRAPS);
static InstanceKlass* load_class(Symbol* h_name, const char* path,
Handle super_class, objArrayHandle interfaces,
TRAPS);
static void initialize(TRAPS);
static InstanceKlass* UnregisteredClassLoader_klass() {
return _UnregisteredClassLoader_klass;
}

class ClassLoaderTable;

private:
static Handle create_url_classloader(Symbol* path, TRAPS);
static Handle get_url_classloader(Symbol* path, TRAPS);
// Don't put this in vmClasses as it's used only with CDS dumping.
static InstanceKlass* _UnregisteredClassLoader_klass;

static Handle create_classloader(Symbol* path, TRAPS);
static Handle get_classloader(Symbol* path, TRAPS);
};

#endif // SHARE_CDS_UNREGISTEREDCLASSES_HPP
10 changes: 0 additions & 10 deletions src/hotspot/share/classfile/systemDictionary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,16 +412,6 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,

assert(super_name != nullptr, "null superclass for resolving");
assert(!Signature::is_array(super_name), "invalid superclass name");
#if INCLUDE_CDS
if (DumpSharedSpaces) {
// Special processing for handling UNREGISTERED shared classes.
InstanceKlass* k = SystemDictionaryShared::lookup_super_for_unregistered_class(class_name,
super_name, is_superclass);
if (k) {
return k;
}
}
#endif // INCLUDE_CDS

// If klass is already loaded, just return the superclass or superinterface.
// Make sure there's a placeholder for the class_name before resolving.
Expand Down
46 changes: 7 additions & 39 deletions src/hotspot/share/classfile/systemDictionaryShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "cds/dumpTimeClassInfo.inline.hpp"
#include "cds/metaspaceShared.hpp"
#include "cds/runTimeClassInfo.hpp"
#include "cds/unregisteredClasses.hpp"
#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
Expand Down Expand Up @@ -331,6 +332,12 @@ bool SystemDictionaryShared::check_for_exclusion_impl(InstanceKlass* k) {
}
}

if (k == UnregisteredClasses::UnregisteredClassLoader_klass()) {
ResourceMark rm;
log_info(cds)("Skipping %s: used only when dumping CDS archive", k->name()->as_C_string());
return true;
}

return false; // false == k should NOT be excluded
}

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

// This function is called to lookup the super/interfaces of shared classes for
// unregistered loaders. E.g., SharedClass in the below example
// where "super:" (and optionally "interface:") have been specified.
//
// java/lang/Object id: 0
// Interface id: 2 super: 0 source: cust.jar
// SharedClass id: 4 super: 0 interfaces: 2 source: cust.jar
InstanceKlass* SystemDictionaryShared::lookup_super_for_unregistered_class(
Symbol* class_name, Symbol* super_name, bool is_superclass) {

assert(DumpSharedSpaces, "only when static dumping");

if (!ClassListParser::is_parsing_thread()) {
// Unregistered classes can be created only by ClassListParser::_parsing_thread.

return nullptr;
}

ClassListParser* parser = ClassListParser::instance();
if (parser == nullptr) {
// We're still loading the well-known classes, before the ClassListParser is created.
return nullptr;
}
if (class_name->equals(parser->current_class_name())) {
// When this function is called, all the numbered super and interface types
// must have already been loaded. Hence this function is never recursively called.
if (is_superclass) {
return parser->lookup_super_for_current_class(super_name);
} else {
return parser->lookup_interface_for_current_class(super_name);
}
} else {
// The VM is not trying to resolve a super type of parser->current_class_name().
// Instead, it's resolving an error class (because parser->current_class_name() has
// failed parsing or verification). Don't do anything here.
return nullptr;
}
}

void SystemDictionaryShared::set_shared_class_misc_info(InstanceKlass* k, ClassFileStream* cfs) {
Arguments::assert_is_dumping_archive();
assert(!is_builtin(k), "must be unregistered class");
Expand Down
Loading