Skip to content

Commit

Permalink
8332176: Refactor ClassListParser::parse()
Browse files Browse the repository at this point in the history
Reviewed-by: matsaave, ccheung
  • Loading branch information
iklam committed May 15, 2024
1 parent 4083255 commit b687aa5
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 120 deletions.
196 changes: 92 additions & 104 deletions src/hotspot/share/cds/classListParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ ClassListParser::ClassListParser(const char* file, ParseMode parse_mode) :
_file_input(do_open(file), /* need_close=*/true),
_input_stream(&_file_input) {
log_info(cds)("Parsing %s%s", file,
(parse_mode == _parse_lambda_forms_invokers_only) ? " (lambda form invokers only)" : "");
parse_lambda_forms_invokers_only() ? " (lambda form invokers only)" : "");
if (!_file_input.is_open()) {
char errmsg[JVM_MAXPATHLEN];
os::lasterror(errmsg, JVM_MAXPATHLEN);
Expand Down Expand Up @@ -102,120 +102,108 @@ ClassListParser::~ClassListParser() {
_instance = nullptr;
}

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

void ClassListParser::parse(TRAPS) {
for (; !_input_stream.done(); _input_stream.next()) {
_line = _input_stream.current_line();
if (*_line == '#') { // comment
continue;
}
if (!parse_one_line()) {
break;
}

if (lambda_form_line()) {
// The current line is "@lambda-form-invoker ...". It has been recorded in LambdaFormInvokers,
// and will be processed later.
continue;
}

if (_parse_mode == _parse_lambda_forms_invokers_only) {
continue;
clean_up_input_line();

// Each line in the classlist can be one of three forms:
if (_line[0] == '#') {
// A comment; ignore it
} else if (_line[0] == '@') {
// @xxx - a tag like @lambda-proxy, to be parsed by parse_at_tags()
parse_at_tags(CHECK);
} else {
// A class name, followed by optional attributes. E.g.
// java/lang/String
// java/lang/Object id: 1
// my/pkg/TestClass id: 5 super: 1 interfaces: 3 4 source: foo.jar
parse_class_name_and_attributes(CHECK);
}
}
}

check_class_name(_class_name);
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
if (_indy_items->length() > 0) {
// The current line is "@lambda-proxy class_name". Load the proxy class.
resolve_indy(THREAD, class_name_symbol);
class_count++;
continue;
}
void ClassListParser::parse_class_name_and_attributes(TRAPS) {
read_class_name_and_attributes();

Klass* klass = load_current_class(class_name_symbol, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
// If we have run out of memory, don't try to load the rest of the classes in
// the classlist. Throw an exception, which will terminate the dumping process.
return 0; // THROW
}
if (parse_lambda_forms_invokers_only()) {
return;
}

ResourceMark rm(THREAD);
char* ex_msg = (char*)"";
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
if (message != nullptr) {
ex_msg = java_lang_String::as_utf8_string(message);
}
log_warning(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), ex_msg);
// We might have an invalid class name or an bad class. Warn about it
// and keep going to the next line.
CLEAR_PENDING_EXCEPTION;
log_warning(cds)("Preload Warning: Cannot find %s", _class_name);
continue;
check_class_name(_class_name);
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
Klass* klass = load_current_class(class_name_symbol, THREAD);
if (HAS_PENDING_EXCEPTION) {
if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
// If we have run out of memory, don't try to load the rest of the classes in
// the classlist. Throw an exception, which will terminate the dumping process.
return; // THROW
}

assert(klass != nullptr, "sanity");
if (log_is_enabled(Trace, cds)) {
ResourceMark rm(THREAD);
log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
ResourceMark rm(THREAD);
char* ex_msg = (char*)"";
oop message = java_lang_Throwable::message(PENDING_EXCEPTION);
if (message != nullptr) {
ex_msg = java_lang_String::as_utf8_string(message);
}
log_warning(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(), ex_msg);
// We might have an invalid class name or an bad class. Warn about it
// and keep going to the next line.
CLEAR_PENDING_EXCEPTION;
log_warning(cds)("Preload Warning: Cannot find %s", _class_name);
return;
}

if (klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass);
assert(klass != nullptr, "sanity");
if (log_is_enabled(Trace, cds)) {
ResourceMark rm(THREAD);
log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());
}

// Link the class to cause the bytecodes to be rewritten and the
// cpcache to be created. The linking is done as soon as classes
// are loaded in order that the related data structures (klass and
// cpCache) are located together.
MetaspaceShared::try_link_class(THREAD, ik);
}
if (klass->is_instance_klass()) {
InstanceKlass* ik = InstanceKlass::cast(klass);

class_count++;
// Link the class to cause the bytecodes to be rewritten and the
// cpcache to be created. The linking is done as soon as classes
// are loaded in order that the related data structures (klass and
// cpCache) are located together.
MetaspaceShared::try_link_class(THREAD, ik);
}

return class_count;
}

bool ClassListParser::parse_one_line() {
{
int len = (int)strlen(_line);
int i;
// Replace \t\r\n\f with ' '
for (i=0; i<len; i++) {
if (_line[i] == '\t' || _line[i] == '\r' || _line[i] == '\n' || _line[i] == '\f') {
_line[i] = ' ';
}
void ClassListParser::clean_up_input_line() {
int len = (int)strlen(_line);
int i;
// Replace \t\r\n\f with ' '
for (i=0; i<len; i++) {
if (_line[i] == '\t' || _line[i] == '\r' || _line[i] == '\n' || _line[i] == '\f') {
_line[i] = ' ';
}
}

// Remove trailing newline/space
while (len > 0) {
if (_line[len-1] == ' ') {
_line[len-1] = '\0';
len --;
} else {
break;
}
// Remove trailing newline/space
while (len > 0) {
if (_line[len-1] == ' ') {
_line[len-1] = '\0';
len --;
} else {
break;
}
_line_len = len;
}
_line_len = len;
}

void ClassListParser::read_class_name_and_attributes() {
_class_name = _line;
_id = _unspecified;
_super = _unspecified;
_interfaces->clear();
_source = nullptr;
_interfaces_specified = false;
_indy_items->clear();
_lambda_form_line = false;

if (_line[0] == '@') {
return parse_at_tags();
}

if ((_token = strchr(_line, ' ')) == nullptr) {
// No optional arguments are specified.
return true;
// No optional attributes are specified.
return;
}

// Mark the end of the name, and go to the next input char
Expand Down Expand Up @@ -257,10 +245,9 @@ bool ClassListParser::parse_one_line() {
// # the class is loaded from classpath
// id may be specified
// super, interfaces, loader must not be specified
return true;
}

void ClassListParser::split_tokens_by_whitespace(int offset) {
void ClassListParser::split_tokens_by_whitespace(int offset, GrowableArray<const char*>* items) {
int start = offset;
int end;
bool done = false;
Expand All @@ -273,7 +260,7 @@ void ClassListParser::split_tokens_by_whitespace(int offset) {
} else {
_line[end] = '\0';
}
_indy_items->append(_line + start);
items->append(_line + start);
start = ++end;
}
}
Expand All @@ -290,29 +277,30 @@ int ClassListParser::split_at_tag_from_line() {
return (int)(ptr - _line);
}

bool ClassListParser::parse_at_tags() {
void ClassListParser::parse_at_tags(TRAPS) {
assert(_line[0] == '@', "must be");
int offset;
if ((offset = split_at_tag_from_line()) == 0) {
return false;
}
int offset = split_at_tag_from_line();
assert(offset > 0, "would have exited VM");

if (strcmp(_token, LAMBDA_PROXY_TAG) == 0) {
split_tokens_by_whitespace(offset);
_indy_items->clear();
split_tokens_by_whitespace(offset, _indy_items);
if (_indy_items->length() < 2) {
error("Line with @ tag has too few items \"%s\" line #%zu", _token, lineno());
return false;
}
// set the class name
_class_name = _indy_items->at(0);
return true;
if (!parse_lambda_forms_invokers_only()) {
_class_name = _indy_items->at(0);
check_class_name(_class_name);
TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);
if (_indy_items->length() > 0) {
// The current line is "@lambda-proxy class_name". Load the proxy class.
resolve_indy(THREAD, class_name_symbol);
}
}
} else if (strcmp(_token, LAMBDA_FORM_TAG) == 0) {
LambdaFormInvokers::append(os::strdup((const char*)(_line + offset), mtInternal));
_lambda_form_line = true;
return true;
} else {
error("Invalid @ tag at the beginning of line \"%s\" line #%zu", _token, lineno());
return false;
}
}

Expand Down Expand Up @@ -441,9 +429,9 @@ void ClassListParser::error(const char* msg, ...) {
}
jio_fprintf(defaultStream::error_stream(), "^\n");
}
va_end(ap);

vm_exit_during_initialization("class list format error.", nullptr);
va_end(ap);
}

void ClassListParser::check_class_name(const char* class_name) {
Expand Down
20 changes: 11 additions & 9 deletions src/hotspot/share/cds/classListParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ class ClassListParser : public StackObj {
GrowableArray<int>* _interfaces;
bool _interfaces_specified;
const char* _source;
bool _lambda_form_line;
ParseMode _parse_mode;

bool parse_int_option(const char* option_name, int* value);
Expand All @@ -120,7 +119,9 @@ class ClassListParser : public StackObj {

void resolve_indy(JavaThread* current, Symbol* class_name_symbol);
void resolve_indy_impl(Symbol* class_name_symbol, TRAPS);
bool parse_one_line();
void clean_up_input_line();
void read_class_name_and_attributes();
void parse_class_name_and_attributes(TRAPS);
Klass* load_current_class(Symbol* class_name_symbol, TRAPS);

size_t lineno() { return _input_stream.lineno(); }
Expand All @@ -129,9 +130,9 @@ class ClassListParser : public StackObj {
~ClassListParser();

public:
static int parse_classlist(const char* classlist_path, ParseMode parse_mode, TRAPS) {
static void 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.
parser.parse(THREAD);
}

static bool is_parsing_thread();
Expand All @@ -141,10 +142,10 @@ class ClassListParser : public StackObj {
return _instance;
}

int parse(TRAPS);
void split_tokens_by_whitespace(int offset);
void parse(TRAPS);
void split_tokens_by_whitespace(int offset, GrowableArray<const char*>* items);
int split_at_tag_from_line();
bool parse_at_tags();
void parse_at_tags(TRAPS);
char* _token;
void error(const char* msg, ...);
void parse_int(int* value);
Expand All @@ -154,6 +155,9 @@ class ClassListParser : public StackObj {
void skip_whitespaces();
void skip_non_whitespaces();

bool parse_lambda_forms_invokers_only() {
return _parse_mode == _parse_lambda_forms_invokers_only;
}
bool is_id_specified() {
return _id != _unspecified;
}
Expand Down Expand Up @@ -184,8 +188,6 @@ class ClassListParser : public StackObj {

bool is_loading_from_source();

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);
Expand Down
13 changes: 6 additions & 7 deletions src/hotspot/share/cds/metaspaceShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,18 +737,18 @@ void MetaspaceShared::preload_classes(TRAPS) {
}

log_info(cds)("Loading classes to share ...");
int class_count = ClassListParser::parse_classlist(classlist_path,
ClassListParser::_parse_all, CHECK);
ClassListParser::parse_classlist(classlist_path,
ClassListParser::_parse_all, CHECK);
if (ExtraSharedClassListFile) {
class_count += ClassListParser::parse_classlist(ExtraSharedClassListFile,
ClassListParser::_parse_all, CHECK);
ClassListParser::parse_classlist(ExtraSharedClassListFile,
ClassListParser::_parse_all, CHECK);
}
if (classlist_path != default_classlist) {
struct stat statbuf;
if (os::stat(default_classlist, &statbuf) == 0) {
// File exists, let's use it.
class_count += ClassListParser::parse_classlist(default_classlist,
ClassListParser::_parse_lambda_forms_invokers_only, CHECK);
ClassListParser::parse_classlist(default_classlist,
ClassListParser::_parse_lambda_forms_invokers_only, CHECK);
}
}

Expand All @@ -758,7 +758,6 @@ void MetaspaceShared::preload_classes(TRAPS) {
CDSProtectionDomain::create_jar_manifest(dummy, strlen(dummy), CHECK);

log_info(cds)("Loading classes to share: done.");
log_info(cds)("Shared spaces: preloaded %d classes", class_count);
}

void MetaspaceShared::preload_and_dump_impl(TRAPS) {
Expand Down

1 comment on commit b687aa5

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.