Skip to content

Commit

Permalink
8261921: ClassListParser::current should be used only by main thread
Browse files Browse the repository at this point in the history
  • Loading branch information
iklam committed Feb 18, 2021
1 parent ea5bf45 commit 9aeb9c1
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 17 deletions.
15 changes: 13 additions & 2 deletions src/hotspot/share/classfile/classListParser.cpp
Expand Up @@ -43,18 +43,18 @@
#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"
#include "utilities/defaultStream.hpp"
#include "utilities/hashtable.inline.hpp"
#include "utilities/macros.hpp"

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()
Expand All @@ -73,12 +73,23 @@ 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() {
Thread* t = Atomic::load(&_parsing_thread);
return (t == Thread::current());
}

ClassListParser::~ClassListParser() {
if (_file) {
fclose(_file);
}
Atomic::store(&_parsing_thread, (Thread*)NULL);
_instance = NULL;
}

Expand Down
7 changes: 7 additions & 0 deletions src/hotspot/share/classfile/classListParser.hpp
Expand Up @@ -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) {}
Expand Down Expand Up @@ -81,6 +83,7 @@ class ClassListParser : public StackObj {
_line_buf_size = _max_allowed_line_len + _line_buf_extra
};

static Thread* _parsing_thread; // the thread that created _instance
static ClassListParser* _instance; // the singleton.
const char* _classlist_file;
FILE* _file;
Expand Down Expand Up @@ -119,9 +122,13 @@ class ClassListParser : public StackObj {
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();
Expand Down
4 changes: 2 additions & 2 deletions src/hotspot/share/classfile/systemDictionary.cpp
Expand Up @@ -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;
}
Expand Down
19 changes: 12 additions & 7 deletions src/hotspot/share/classfile/systemDictionaryShared.cpp
Expand Up @@ -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
// 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) {
Expand Down
8 changes: 2 additions & 6 deletions src/hotspot/share/classfile/systemDictionaryShared.hpp
Expand Up @@ -247,12 +247,8 @@ class SystemDictionaryShared: public SystemDictionary {
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;
Expand Down

0 comments on commit 9aeb9c1

Please sign in to comment.