Path: blob/master/src/hotspot/share/cds/classListParser.cpp
41145 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "jvm.h"26#include "jimage.hpp"27#include "cds/archiveUtils.hpp"28#include "cds/classListParser.hpp"29#include "cds/lambdaFormInvokers.hpp"30#include "cds/metaspaceShared.hpp"31#include "classfile/classLoaderExt.hpp"32#include "classfile/javaClasses.inline.hpp"33#include "classfile/symbolTable.hpp"34#include "classfile/systemDictionary.hpp"35#include "classfile/systemDictionaryShared.hpp"36#include "classfile/vmClasses.hpp"37#include "classfile/vmSymbols.hpp"38#include "interpreter/bytecode.hpp"39#include "interpreter/bytecodeStream.hpp"40#include "interpreter/linkResolver.hpp"41#include "logging/log.hpp"42#include "logging/logTag.hpp"43#include "memory/resourceArea.hpp"44#include "oops/constantPool.hpp"45#include "runtime/atomic.hpp"46#include "runtime/handles.inline.hpp"47#include "runtime/java.hpp"48#include "runtime/javaCalls.hpp"49#include "utilities/defaultStream.hpp"50#include "utilities/hashtable.inline.hpp"51#include "utilities/macros.hpp"5253volatile Thread* ClassListParser::_parsing_thread = NULL;54ClassListParser* ClassListParser::_instance = NULL;5556ClassListParser::ClassListParser(const char* file) : _id2klass_table(INITIAL_TABLE_SIZE) {57_classlist_file = file;58_file = NULL;59// Use os::open() because neither fopen() nor os::fopen()60// can handle long path name on Windows.61int fd = os::open(file, O_RDONLY, S_IREAD);62if (fd != -1) {63// Obtain a File* from the file descriptor so that fgets()64// can be used in parse_one_line()65_file = os::open(fd, "r");66}67if (_file == NULL) {68char errmsg[JVM_MAXPATHLEN];69os::lasterror(errmsg, JVM_MAXPATHLEN);70vm_exit_during_initialization("Loading classlist failed", errmsg);71}72_line_no = 0;73_interfaces = new (ResourceObj::C_HEAP, mtClass) GrowableArray<int>(10, mtClass);74_indy_items = new (ResourceObj::C_HEAP, mtClass) GrowableArray<const char*>(9, mtClass);7576// _instance should only be accessed by the thread that created _instance.77assert(_instance == NULL, "must be singleton");78_instance = this;79Atomic::store(&_parsing_thread, Thread::current());80}8182bool ClassListParser::is_parsing_thread() {83return Atomic::load(&_parsing_thread) == Thread::current();84}8586ClassListParser::~ClassListParser() {87if (_file) {88fclose(_file);89}90Atomic::store(&_parsing_thread, (Thread*)NULL);91_instance = NULL;92}9394int ClassListParser::parse(TRAPS) {95int class_count = 0;9697while (parse_one_line()) {98if (lambda_form_line()) {99// The current line is "@lambda-form-invoker ...". It has been recorded in LambdaFormInvokers,100// and will be processed later.101continue;102}103104TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name);105if (_indy_items->length() > 0) {106// The current line is "@lambda-proxy class_name". Load the proxy class.107resolve_indy(THREAD, class_name_symbol);108class_count++;109continue;110}111112Klass* klass = load_current_class(class_name_symbol, THREAD);113if (HAS_PENDING_EXCEPTION) {114if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {115// If we have run out of memory, don't try to load the rest of the classes in116// the classlist. Throw an exception, which will terminate the dumping process.117return 0; // THROW118}119120// We might have an invalid class name or an bad class. Warn about it121// and keep going to the next line.122CLEAR_PENDING_EXCEPTION;123log_warning(cds)("Preload Warning: Cannot find %s", _class_name);124continue;125}126127assert(klass != NULL, "sanity");128if (log_is_enabled(Trace, cds)) {129ResourceMark rm(THREAD);130log_trace(cds)("Shared spaces preloaded: %s", klass->external_name());131}132133if (klass->is_instance_klass()) {134InstanceKlass* ik = InstanceKlass::cast(klass);135136// Link the class to cause the bytecodes to be rewritten and the137// cpcache to be created. The linking is done as soon as classes138// are loaded in order that the related data structures (klass and139// cpCache) are located together.140MetaspaceShared::try_link_class(THREAD, ik);141}142143class_count++;144}145146return class_count;147}148149bool ClassListParser::parse_one_line() {150for (;;) {151if (fgets(_line, sizeof(_line), _file) == NULL) {152return false;153}154++ _line_no;155_line_len = (int)strlen(_line);156if (_line_len > _max_allowed_line_len) {157error("input line too long (must be no longer than %d chars)", _max_allowed_line_len);158}159if (*_line == '#') { // comment160continue;161}162163{164int len = (int)strlen(_line);165int i;166// Replace \t\r\n\f with ' '167for (i=0; i<len; i++) {168if (_line[i] == '\t' || _line[i] == '\r' || _line[i] == '\n' || _line[i] == '\f') {169_line[i] = ' ';170}171}172173// Remove trailing newline/space174while (len > 0) {175if (_line[len-1] == ' ') {176_line[len-1] = '\0';177len --;178} else {179break;180}181}182_line_len = len;183}184185// valid line186break;187}188189_class_name = _line;190_id = _unspecified;191_super = _unspecified;192_interfaces->clear();193_source = NULL;194_interfaces_specified = false;195_indy_items->clear();196_lambda_form_line = false;197198if (_line[0] == '@') {199return parse_at_tags();200}201202if ((_token = strchr(_line, ' ')) == NULL) {203// No optional arguments are specified.204return true;205}206207// Mark the end of the name, and go to the next input char208*_token++ = '\0';209210while (*_token) {211skip_whitespaces();212213if (parse_uint_option("id:", &_id)) {214continue;215} else if (parse_uint_option("super:", &_super)) {216check_already_loaded("Super class", _super);217continue;218} else if (skip_token("interfaces:")) {219int i;220while (try_parse_uint(&i)) {221check_already_loaded("Interface", i);222_interfaces->append(i);223}224} else if (skip_token("source:")) {225skip_whitespaces();226_source = _token;227char* s = strchr(_token, ' ');228if (s == NULL) {229break; // end of input line230} else {231*s = '\0'; // mark the end of _source232_token = s+1;233}234} else {235error("Unknown input");236}237}238239// if src is specified240// id super interfaces must all be specified241// loader may be specified242// else243// # the class is loaded from classpath244// id may be specified245// super, interfaces, loader must not be specified246return true;247}248249void ClassListParser::split_tokens_by_whitespace(int offset) {250int start = offset;251int end;252bool done = false;253while (!done) {254while (_line[start] == ' ' || _line[start] == '\t') start++;255end = start;256while (_line[end] && _line[end] != ' ' && _line[end] != '\t') end++;257if (_line[end] == '\0') {258done = true;259} else {260_line[end] = '\0';261}262_indy_items->append(_line + start);263start = ++end;264}265}266267int ClassListParser::split_at_tag_from_line() {268_token = _line;269char* ptr;270if ((ptr = strchr(_line, ' ')) == NULL) {271error("Too few items following the @ tag \"%s\" line #%d", _line, _line_no);272return 0;273}274*ptr++ = '\0';275while (*ptr == ' ' || *ptr == '\t') ptr++;276return (int)(ptr - _line);277}278279bool ClassListParser::parse_at_tags() {280assert(_line[0] == '@', "must be");281int offset;282if ((offset = split_at_tag_from_line()) == 0) {283return false;284}285286if (strcmp(_token, LAMBDA_PROXY_TAG) == 0) {287split_tokens_by_whitespace(offset);288if (_indy_items->length() < 2) {289error("Line with @ tag has too few items \"%s\" line #%d", _token, _line_no);290return false;291}292// set the class name293_class_name = _indy_items->at(0);294return true;295} else if (strcmp(_token, LAMBDA_FORM_TAG) == 0) {296LambdaFormInvokers::append(os::strdup((const char*)(_line + offset), mtInternal));297_lambda_form_line = true;298return true;299} else {300error("Invalid @ tag at the beginning of line \"%s\" line #%d", _token, _line_no);301return false;302}303}304305void ClassListParser::skip_whitespaces() {306while (*_token == ' ' || *_token == '\t') {307_token ++;308}309}310311void ClassListParser::skip_non_whitespaces() {312while (*_token && *_token != ' ' && *_token != '\t') {313_token ++;314}315}316317void ClassListParser::parse_int(int* value) {318skip_whitespaces();319if (sscanf(_token, "%i", value) == 1) {320skip_non_whitespaces();321} else {322error("Error: expected integer");323}324}325326void ClassListParser::parse_uint(int* value) {327parse_int(value);328if (*value < 0) {329error("Error: negative integers not allowed (%d)", *value);330}331}332333bool ClassListParser::try_parse_uint(int* value) {334skip_whitespaces();335if (sscanf(_token, "%i", value) == 1) {336skip_non_whitespaces();337return true;338}339return false;340}341342bool ClassListParser::skip_token(const char* option_name) {343size_t len = strlen(option_name);344if (strncmp(_token, option_name, len) == 0) {345_token += len;346return true;347} else {348return false;349}350}351352bool ClassListParser::parse_int_option(const char* option_name, int* value) {353if (skip_token(option_name)) {354if (*value != _unspecified) {355error("%s specified twice", option_name);356} else {357parse_int(value);358return true;359}360}361return false;362}363364bool ClassListParser::parse_uint_option(const char* option_name, int* value) {365if (skip_token(option_name)) {366if (*value != _unspecified) {367error("%s specified twice", option_name);368} else {369parse_uint(value);370return true;371}372}373return false;374}375376void ClassListParser::print_specified_interfaces() {377const int n = _interfaces->length();378jio_fprintf(defaultStream::error_stream(), "Currently specified interfaces[%d] = {\n", n);379for (int i=0; i<n; i++) {380InstanceKlass* k = lookup_class_by_id(_interfaces->at(i));381jio_fprintf(defaultStream::error_stream(), " %4d = %s\n", _interfaces->at(i), k->name()->as_klass_external_name());382}383jio_fprintf(defaultStream::error_stream(), "}\n");384}385386void ClassListParser::print_actual_interfaces(InstanceKlass* ik) {387int n = ik->local_interfaces()->length();388jio_fprintf(defaultStream::error_stream(), "Actual interfaces[%d] = {\n", n);389for (int i = 0; i < n; i++) {390InstanceKlass* e = ik->local_interfaces()->at(i);391jio_fprintf(defaultStream::error_stream(), " %s\n", e->name()->as_klass_external_name());392}393jio_fprintf(defaultStream::error_stream(), "}\n");394}395396void ClassListParser::error(const char* msg, ...) {397va_list ap;398va_start(ap, msg);399int error_index = _token - _line;400if (error_index >= _line_len) {401error_index = _line_len - 1;402}403if (error_index < 0) {404error_index = 0;405}406407jio_fprintf(defaultStream::error_stream(),408"An error has occurred while processing class list file %s %d:%d.\n",409_classlist_file, _line_no, (error_index + 1));410jio_vfprintf(defaultStream::error_stream(), msg, ap);411412if (_line_len <= 0) {413jio_fprintf(defaultStream::error_stream(), "\n");414} else {415jio_fprintf(defaultStream::error_stream(), ":\n");416for (int i=0; i<_line_len; i++) {417char c = _line[i];418if (c == '\0') {419jio_fprintf(defaultStream::error_stream(), "%s", " ");420} else {421jio_fprintf(defaultStream::error_stream(), "%c", c);422}423}424jio_fprintf(defaultStream::error_stream(), "\n");425for (int i=0; i<error_index; i++) {426jio_fprintf(defaultStream::error_stream(), "%s", " ");427}428jio_fprintf(defaultStream::error_stream(), "^\n");429}430431vm_exit_during_initialization("class list format error.", NULL);432va_end(ap);433}434435// This function is used for loading classes for customized class loaders436// during archive dumping.437InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS) {438#if !(defined(_LP64) && (defined(LINUX) || defined(__APPLE__)))439// The only supported platforms are: (1) Linux/64-bit and (2) Solaris/64-bit and440// (3) MacOSX/64-bit441// This #if condition should be in sync with the areCustomLoadersSupportedForCDS442// method in test/lib/jdk/test/lib/Platform.java.443error("AppCDS custom class loaders not supported on this platform");444#endif445446if (!is_super_specified()) {447error("If source location is specified, super class must be also specified");448}449if (!is_id_specified()) {450error("If source location is specified, id must be also specified");451}452if (strncmp(_class_name, "java/", 5) == 0) {453log_info(cds)("Prohibited package for non-bootstrap classes: %s.class from %s",454_class_name, _source);455THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());456}457458InstanceKlass* k = ClassLoaderExt::load_class(class_name, _source, CHECK_NULL);459if (k->local_interfaces()->length() != _interfaces->length()) {460print_specified_interfaces();461print_actual_interfaces(k);462error("The number of interfaces (%d) specified in class list does not match the class file (%d)",463_interfaces->length(), k->local_interfaces()->length());464}465466bool added = SystemDictionaryShared::add_unregistered_class(THREAD, k);467if (!added) {468// We allow only a single unregistered class for each unique name.469error("Duplicated class %s", _class_name);470}471472// This tells JVM_FindLoadedClass to not find this class.473k->set_shared_classpath_index(UNREGISTERED_INDEX);474k->clear_shared_class_loader_type();475476return k;477}478479void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPS) {480// Caller needs to allocate ResourceMark.481int type_index = pool->bootstrap_name_and_type_ref_index_at(cp_index);482int name_index = pool->name_ref_index_at(type_index);483cii->add_item(pool->symbol_at(name_index)->as_C_string());484int sig_index = pool->signature_ref_index_at(type_index);485cii->add_item(pool->symbol_at(sig_index)->as_C_string());486int argc = pool->bootstrap_argument_count_at(cp_index);487if (argc > 0) {488for (int arg_i = 0; arg_i < argc; arg_i++) {489int arg = pool->bootstrap_argument_index_at(cp_index, arg_i);490jbyte tag = pool->tag_at(arg).value();491if (tag == JVM_CONSTANT_MethodType) {492cii->add_item(pool->method_type_signature_at(arg)->as_C_string());493} else if (tag == JVM_CONSTANT_MethodHandle) {494cii->add_ref_kind(pool->method_handle_ref_kind_at(arg));495int callee_index = pool->method_handle_klass_index_at(arg);496Klass* callee = pool->klass_at(callee_index, CHECK);497cii->add_item(callee->name()->as_C_string());498cii->add_item(pool->method_handle_name_ref_at(arg)->as_C_string());499cii->add_item(pool->method_handle_signature_ref_at(arg)->as_C_string());500} else {501ShouldNotReachHere();502}503}504}505}506507bool ClassListParser::is_matching_cp_entry(constantPoolHandle &pool, int cp_index, TRAPS) {508ResourceMark rm(THREAD);509CDSIndyInfo cii;510populate_cds_indy_info(pool, cp_index, &cii, CHECK_0);511GrowableArray<const char*>* items = cii.items();512int indy_info_offset = 1;513if (_indy_items->length() - indy_info_offset != items->length()) {514return false;515}516for (int i = 0; i < items->length(); i++) {517if (strcmp(_indy_items->at(i + indy_info_offset), items->at(i)) != 0) {518return false;519}520}521return true;522}523524void ClassListParser::resolve_indy(JavaThread* current, Symbol* class_name_symbol) {525ExceptionMark em(current);526JavaThread* THREAD = current; // For exception macros.527ClassListParser::resolve_indy_impl(class_name_symbol, THREAD);528if (HAS_PENDING_EXCEPTION) {529ResourceMark rm(current);530char* ex_msg = (char*)"";531oop message = java_lang_Throwable::message(PENDING_EXCEPTION);532if (message != NULL) {533ex_msg = java_lang_String::as_utf8_string(message);534}535log_warning(cds)("resolve_indy for class %s has encountered exception: %s %s",536class_name_symbol->as_C_string(),537PENDING_EXCEPTION->klass()->external_name(),538ex_msg);539CLEAR_PENDING_EXCEPTION;540}541}542543void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPS) {544Handle class_loader(THREAD, SystemDictionary::java_system_loader());545Handle protection_domain;546Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, CHECK);547if (klass->is_instance_klass()) {548InstanceKlass* ik = InstanceKlass::cast(klass);549MetaspaceShared::try_link_class(THREAD, ik);550if (!ik->is_linked()) {551// Verification of ik has failed552return;553}554555ConstantPool* cp = ik->constants();556ConstantPoolCache* cpcache = cp->cache();557bool found = false;558for (int cpcindex = 0; cpcindex < cpcache->length(); cpcindex ++) {559int indy_index = ConstantPool::encode_invokedynamic_index(cpcindex);560ConstantPoolCacheEntry* cpce = cpcache->entry_at(cpcindex);561int pool_index = cpce->constant_pool_index();562constantPoolHandle pool(THREAD, cp);563if (pool->tag_at(pool_index).is_invoke_dynamic()) {564BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index);565Handle bsm = bootstrap_specifier.resolve_bsm(CHECK);566if (!SystemDictionaryShared::is_supported_invokedynamic(&bootstrap_specifier)) {567log_debug(cds, lambda)("is_supported_invokedynamic check failed for cp_index %d", pool_index);568continue;569}570bool matched = is_matching_cp_entry(pool, pool_index, CHECK);571if (matched) {572found = true;573CallInfo info;574bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(info, CHECK);575if (!is_done) {576// resolve it577Handle recv;578LinkResolver::resolve_invoke(info, recv, pool, indy_index, Bytecodes::_invokedynamic, CHECK);579break;580}581cpce->set_dynamic_call(pool, info);582}583}584}585if (!found) {586ResourceMark rm(THREAD);587log_warning(cds)("No invoke dynamic constant pool entry can be found for class %s. The classlist is probably out-of-date.",588class_name_symbol->as_C_string());589}590}591}592593Klass* ClassListParser::load_current_class(Symbol* class_name_symbol, TRAPS) {594Klass* klass;595if (!is_loading_from_source()) {596// Load classes for the boot/platform/app loaders only.597if (is_super_specified()) {598error("If source location is not specified, super class must not be specified");599}600if (are_interfaces_specified()) {601error("If source location is not specified, interface(s) must not be specified");602}603604if (Signature::is_array(class_name_symbol)) {605// array classes are not supported in class list.606THROW_NULL(vmSymbols::java_lang_ClassNotFoundException());607}608609JavaValue result(T_OBJECT);610// Call java_system_loader().loadClass() directly, which will611// delegate to the correct loader (boot, platform or app) depending on612// the package name.613614Handle s = java_lang_String::create_from_symbol(class_name_symbol, CHECK_NULL);615// ClassLoader.loadClass() wants external class name format, i.e., convert '/' chars to '.'616Handle ext_class_name = java_lang_String::externalize_classname(s, CHECK_NULL);617Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());618619JavaCalls::call_virtual(&result,620loader, //SystemDictionary::java_system_loader(),621vmClasses::ClassLoader_klass(),622vmSymbols::loadClass_name(),623vmSymbols::string_class_signature(),624ext_class_name,625CHECK_NULL);626627assert(result.get_type() == T_OBJECT, "just checking");628oop obj = result.get_oop();629assert(obj != NULL, "jdk.internal.loader.BuiltinClassLoader::loadClass never returns null");630klass = java_lang_Class::as_Klass(obj);631} else {632// If "source:" tag is specified, all super class and super interfaces must be specified in the633// class list file.634klass = load_class_from_source(class_name_symbol, CHECK_NULL);635}636637assert(klass != NULL, "exception should have been thrown");638assert(klass->is_instance_klass(), "array classes should have been filtered out");639640if (is_id_specified()) {641InstanceKlass* ik = InstanceKlass::cast(klass);642int id = this->id();643SystemDictionaryShared::update_shared_entry(ik, id);644InstanceKlass** old_ptr = table()->lookup(id);645if (old_ptr != NULL) {646error("Duplicated ID %d for class %s", id, _class_name);647}648table()->add(id, ik);649}650651return klass;652}653654bool ClassListParser::is_loading_from_source() {655return (_source != NULL);656}657658InstanceKlass* ClassListParser::lookup_class_by_id(int id) {659InstanceKlass** klass_ptr = table()->lookup(id);660if (klass_ptr == NULL) {661error("Class ID %d has not been defined", id);662}663assert(*klass_ptr != NULL, "must be");664return *klass_ptr;665}666667668InstanceKlass* ClassListParser::lookup_super_for_current_class(Symbol* super_name) {669if (!is_loading_from_source()) {670return NULL;671}672673InstanceKlass* k = lookup_class_by_id(super());674if (super_name != k->name()) {675error("The specified super class %s (id %d) does not match actual super class %s",676k->name()->as_klass_external_name(), super(),677super_name->as_klass_external_name());678}679return k;680}681682InstanceKlass* ClassListParser::lookup_interface_for_current_class(Symbol* interface_name) {683if (!is_loading_from_source()) {684return NULL;685}686687const int n = _interfaces->length();688if (n == 0) {689error("Class %s implements the interface %s, but no interface has been specified in the input line",690_class_name, interface_name->as_klass_external_name());691ShouldNotReachHere();692}693694int i;695for (i=0; i<n; i++) {696InstanceKlass* k = lookup_class_by_id(_interfaces->at(i));697if (interface_name == k->name()) {698return k;699}700}701702// interface_name is not specified by the "interfaces:" keyword.703print_specified_interfaces();704error("The interface %s implemented by class %s does not match any of the specified interface IDs",705interface_name->as_klass_external_name(), _class_name);706ShouldNotReachHere();707return NULL;708}709710711