8261921: ClassListParser::current should be used only by main thread

Reviewed-by: dholmes, ccheung, coleenp
This commit is contained in:
Ioi Lam 2021-02-23 03:11:47 +00:00
parent 991f7c1303
commit 8cfea7c523
5 changed files with 35 additions and 17 deletions

View file

@ -43,6 +43,7 @@
#include "memory/metaspaceShared.hpp"
#include "memory/resourceArea.hpp"
#include "oops/constantPool.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
@ -50,11 +51,10 @@
#include "utilities/hashtable.inline.hpp"
#include "utilities/macros.hpp"
volatile Thread* ClassListParser::_parsing_thread = NULL;
ClassListParser* ClassListParser::_instance = NULL;
ClassListParser::ClassListParser(const char* file) {
assert(_instance == NULL, "must be singleton");
_instance = this;
_classlist_file = file;
_file = NULL;
// Use os::open() because neither fopen() nor os::fopen()
@ -73,12 +73,22 @@ ClassListParser::ClassListParser(const char* file) {
_line_no = 0;
_interfaces = new (ResourceObj::C_HEAP, mtClass) GrowableArray<int>(10, mtClass);
_indy_items = new (ResourceObj::C_HEAP, mtClass) GrowableArray<const char*>(9, mtClass);
// _instance should only be accessed by the thread that created _instance.
assert(_instance == NULL, "must be singleton");
_instance = this;
Atomic::store(&_parsing_thread, Thread::current());
}
bool ClassListParser::is_parsing_thread() {
return Atomic::load(&_parsing_thread) == Thread::current();
}
ClassListParser::~ClassListParser() {
if (_file) {
fclose(_file);
}
Atomic::store(&_parsing_thread, (Thread*)NULL);
_instance = NULL;
}

View file

@ -33,6 +33,8 @@
#define LAMBDA_PROXY_TAG "@lambda-proxy"
#define LAMBDA_FORM_TAG "@lambda-form-invoker"
class Thread;
class ID2KlassTable : public KVHashtable<int, InstanceKlass*, mtInternal> {
public:
ID2KlassTable() : KVHashtable<int, InstanceKlass*, mtInternal>(1987) {}
@ -81,6 +83,7 @@ class ClassListParser : public StackObj {
_line_buf_size = _max_allowed_line_len + _line_buf_extra
};
static volatile Thread* _parsing_thread; // the thread that created _instance
static ClassListParser* _instance; // the singleton.
const char* _classlist_file;
FILE* _file;
@ -119,9 +122,13 @@ public:
ClassListParser(const char* file);
~ClassListParser();
static bool is_parsing_thread();
static ClassListParser* instance() {
assert(is_parsing_thread(), "call this only in the thread that created ClassListParsing::_instance");
assert(_instance != NULL, "must be");
return _instance;
}
bool parse_one_line();
void split_tokens_by_whitespace(int offset);
int split_at_tag_from_line();

View file

@ -369,8 +369,8 @@ InstanceKlass* SystemDictionary::resolve_super_or_fail(Symbol* class_name,
#if INCLUDE_CDS
if (DumpSharedSpaces) {
// Special processing for handling UNREGISTERED shared classes.
InstanceKlass* k = SystemDictionaryShared::dump_time_resolve_super_or_fail(class_name,
super_name, class_loader, protection_domain, is_superclass, CHECK_NULL);
InstanceKlass* k = SystemDictionaryShared::lookup_super_for_unregistered_class(class_name,
super_name, is_superclass);
if (k) {
return k;
}

View file

@ -1196,18 +1196,23 @@ bool SystemDictionaryShared::add_unregistered_class(InstanceKlass* k, TRAPS) {
return created;
}
// This function is called to resolve the super/interfaces of shared classes for
// non-built-in loaders. E.g., SharedClass in the below example
// 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::dump_time_resolve_super_or_fail(
Symbol* class_name, Symbol* super_name, Handle class_loader,
Handle protection_domain, bool is_superclass, TRAPS) {
InstanceKlass* SystemDictionaryShared::lookup_super_for_unregistered_class(
Symbol* class_name, Symbol* super_name, bool is_superclass) {
assert(DumpSharedSpaces, "only when dumping");
assert(DumpSharedSpaces, "only when static dumping");
if (!ClassListParser::is_parsing_thread()) {
// Unregistered classes can be created only by ClassListParser::_parsing_thread.
return NULL;
}
ClassListParser* parser = ClassListParser::instance();
if (parser == NULL) {

View file

@ -247,12 +247,8 @@ public:
static bool is_sharing_possible(ClassLoaderData* loader_data);
static bool add_unregistered_class(InstanceKlass* k, TRAPS);
static InstanceKlass* dump_time_resolve_super_or_fail(Symbol* class_name,
Symbol* super_name,
Handle class_loader,
Handle protection_domain,
bool is_superclass,
TRAPS);
static InstanceKlass* lookup_super_for_unregistered_class(Symbol* class_name,
Symbol* super_name, bool is_superclass);
static void init_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;
static void remove_dumptime_info(InstanceKlass* k) NOT_CDS_RETURN;