| File: | jdk/src/hotspot/share/cds/classListParser.cpp |
| Warning: | line 674, column 3 Dereference of null pointer (loaded from variable 'klass_ptr') |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* | |||
| 2 | * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved. | |||
| 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |||
| 4 | * | |||
| 5 | * This code is free software; you can redistribute it and/or modify it | |||
| 6 | * under the terms of the GNU General Public License version 2 only, as | |||
| 7 | * published by the Free Software Foundation. | |||
| 8 | * | |||
| 9 | * This code is distributed in the hope that it will be useful, but WITHOUT | |||
| 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |||
| 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |||
| 12 | * version 2 for more details (a copy is included in the LICENSE file that | |||
| 13 | * accompanied this code). | |||
| 14 | * | |||
| 15 | * You should have received a copy of the GNU General Public License version | |||
| 16 | * 2 along with this work; if not, write to the Free Software Foundation, | |||
| 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
| 18 | * | |||
| 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |||
| 20 | * or visit www.oracle.com if you need additional information or have any | |||
| 21 | * questions. | |||
| 22 | * | |||
| 23 | */ | |||
| 24 | ||||
| 25 | #include "precompiled.hpp" | |||
| 26 | #include "jvm.h" | |||
| 27 | #include "jimage.hpp" | |||
| 28 | #include "cds/archiveUtils.hpp" | |||
| 29 | #include "cds/classListParser.hpp" | |||
| 30 | #include "cds/lambdaFormInvokers.hpp" | |||
| 31 | #include "cds/metaspaceShared.hpp" | |||
| 32 | #include "cds/unregisteredClasses.hpp" | |||
| 33 | #include "classfile/classLoaderExt.hpp" | |||
| 34 | #include "classfile/javaClasses.inline.hpp" | |||
| 35 | #include "classfile/symbolTable.hpp" | |||
| 36 | #include "classfile/systemDictionary.hpp" | |||
| 37 | #include "classfile/systemDictionaryShared.hpp" | |||
| 38 | #include "classfile/vmClasses.hpp" | |||
| 39 | #include "classfile/vmSymbols.hpp" | |||
| 40 | #include "interpreter/bytecode.hpp" | |||
| 41 | #include "interpreter/bytecodeStream.hpp" | |||
| 42 | #include "interpreter/linkResolver.hpp" | |||
| 43 | #include "logging/log.hpp" | |||
| 44 | #include "logging/logTag.hpp" | |||
| 45 | #include "memory/resourceArea.hpp" | |||
| 46 | #include "oops/constantPool.hpp" | |||
| 47 | #include "runtime/atomic.hpp" | |||
| 48 | #include "runtime/handles.inline.hpp" | |||
| 49 | #include "runtime/java.hpp" | |||
| 50 | #include "runtime/javaCalls.hpp" | |||
| 51 | #include "utilities/defaultStream.hpp" | |||
| 52 | #include "utilities/hashtable.inline.hpp" | |||
| 53 | #include "utilities/macros.hpp" | |||
| 54 | ||||
| 55 | volatile Thread* ClassListParser::_parsing_thread = NULL__null; | |||
| 56 | ClassListParser* ClassListParser::_instance = NULL__null; | |||
| 57 | ||||
| 58 | ClassListParser::ClassListParser(const char* file) : _id2klass_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE) { | |||
| 59 | _classlist_file = file; | |||
| 60 | _file = NULL__null; | |||
| 61 | // Use os::open() because neither fopen() nor os::fopen() | |||
| 62 | // can handle long path name on Windows. | |||
| 63 | int fd = os::open(file, O_RDONLY00, S_IREAD0400); | |||
| 64 | if (fd != -1) { | |||
| 65 | // Obtain a File* from the file descriptor so that fgets() | |||
| 66 | // can be used in parse_one_line() | |||
| 67 | _file = os::open(fd, "r"); | |||
| 68 | } | |||
| 69 | if (_file == NULL__null) { | |||
| 70 | char errmsg[JVM_MAXPATHLEN4096 + 1]; | |||
| 71 | os::lasterror(errmsg, JVM_MAXPATHLEN4096 + 1); | |||
| 72 | vm_exit_during_initialization("Loading classlist failed", errmsg); | |||
| 73 | } | |||
| 74 | _line_no = 0; | |||
| 75 | _interfaces = new (ResourceObj::C_HEAP, mtClass) GrowableArray<int>(10, mtClass); | |||
| 76 | _indy_items = new (ResourceObj::C_HEAP, mtClass) GrowableArray<const char*>(9, mtClass); | |||
| 77 | ||||
| 78 | // _instance should only be accessed by the thread that created _instance. | |||
| 79 | assert(_instance == NULL, "must be singleton")do { if (!(_instance == __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 79, "assert(" "_instance == __null" ") failed", "must be singleton" ); ::breakpoint(); } } while (0); | |||
| 80 | _instance = this; | |||
| 81 | Atomic::store(&_parsing_thread, Thread::current()); | |||
| 82 | } | |||
| 83 | ||||
| 84 | bool ClassListParser::is_parsing_thread() { | |||
| 85 | return Atomic::load(&_parsing_thread) == Thread::current(); | |||
| 86 | } | |||
| 87 | ||||
| 88 | ClassListParser::~ClassListParser() { | |||
| 89 | if (_file != NULL__null) { | |||
| 90 | fclose(_file); | |||
| 91 | } | |||
| 92 | Atomic::store(&_parsing_thread, (Thread*)NULL__null); | |||
| 93 | delete _indy_items; | |||
| 94 | delete _interfaces; | |||
| 95 | _instance = NULL__null; | |||
| 96 | } | |||
| 97 | ||||
| 98 | int ClassListParser::parse(TRAPSJavaThread* __the_thread__) { | |||
| 99 | int class_count = 0; | |||
| 100 | ||||
| 101 | while (parse_one_line()) { | |||
| 102 | if (lambda_form_line()) { | |||
| 103 | // The current line is "@lambda-form-invoker ...". It has been recorded in LambdaFormInvokers, | |||
| 104 | // and will be processed later. | |||
| 105 | continue; | |||
| 106 | } | |||
| 107 | ||||
| 108 | TempNewSymbol class_name_symbol = SymbolTable::new_symbol(_class_name); | |||
| 109 | if (_indy_items->length() > 0) { | |||
| 110 | // The current line is "@lambda-proxy class_name". Load the proxy class. | |||
| 111 | resolve_indy(THREAD__the_thread__, class_name_symbol); | |||
| 112 | class_count++; | |||
| 113 | continue; | |||
| 114 | } | |||
| 115 | ||||
| 116 | Klass* klass = load_current_class(class_name_symbol, THREAD__the_thread__); | |||
| 117 | if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { | |||
| 118 | if (PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception())->is_a(vmClasses::OutOfMemoryError_klass())) { | |||
| 119 | // If we have run out of memory, don't try to load the rest of the classes in | |||
| 120 | // the classlist. Throw an exception, which will terminate the dumping process. | |||
| 121 | return 0; // THROW | |||
| 122 | } | |||
| 123 | ||||
| 124 | ResourceMark rm(THREAD__the_thread__); | |||
| 125 | char* ex_msg = (char*)""; | |||
| 126 | oop message = java_lang_Throwable::message(PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception())); | |||
| 127 | if (message != NULL__null) { | |||
| 128 | ex_msg = java_lang_String::as_utf8_string(message); | |||
| 129 | } | |||
| 130 | log_warning(cds)(!(LogImpl<(LogTag::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Warning))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel ::Warning>("%s: %s", PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception())->klass()->external_name(), ex_msg); | |||
| 131 | // We might have an invalid class name or an bad class. Warn about it | |||
| 132 | // and keep going to the next line. | |||
| 133 | CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); | |||
| 134 | log_warning(cds)(!(LogImpl<(LogTag::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Warning))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel ::Warning>("Preload Warning: Cannot find %s", _class_name); | |||
| 135 | continue; | |||
| 136 | } | |||
| 137 | ||||
| 138 | assert(klass != NULL, "sanity")do { if (!(klass != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 138, "assert(" "klass != __null" ") failed", "sanity"); ::breakpoint (); } } while (0); | |||
| 139 | if (log_is_enabled(Trace, cds)(LogImpl<(LogTag::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Trace))) { | |||
| 140 | ResourceMark rm(THREAD__the_thread__); | |||
| 141 | log_trace(cds)(!(LogImpl<(LogTag::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Trace))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel ::Trace>("Shared spaces preloaded: %s", klass->external_name()); | |||
| 142 | } | |||
| 143 | ||||
| 144 | if (klass->is_instance_klass()) { | |||
| 145 | InstanceKlass* ik = InstanceKlass::cast(klass); | |||
| 146 | ||||
| 147 | // Link the class to cause the bytecodes to be rewritten and the | |||
| 148 | // cpcache to be created. The linking is done as soon as classes | |||
| 149 | // are loaded in order that the related data structures (klass and | |||
| 150 | // cpCache) are located together. | |||
| 151 | MetaspaceShared::try_link_class(THREAD__the_thread__, ik); | |||
| 152 | } | |||
| 153 | ||||
| 154 | class_count++; | |||
| 155 | } | |||
| 156 | ||||
| 157 | return class_count; | |||
| 158 | } | |||
| 159 | ||||
| 160 | bool ClassListParser::parse_one_line() { | |||
| 161 | for (;;) { | |||
| 162 | if (fgets(_line, sizeof(_line), _file) == NULL__null) { | |||
| 163 | return false; | |||
| 164 | } | |||
| 165 | ++ _line_no; | |||
| 166 | _line_len = (int)strlen(_line); | |||
| 167 | if (_line_len > _max_allowed_line_len) { | |||
| 168 | error("input line too long (must be no longer than %d chars)", _max_allowed_line_len); | |||
| 169 | } | |||
| 170 | if (*_line == '#') { // comment | |||
| 171 | continue; | |||
| 172 | } | |||
| 173 | ||||
| 174 | { | |||
| 175 | int len = (int)strlen(_line); | |||
| 176 | int i; | |||
| 177 | // Replace \t\r\n\f with ' ' | |||
| 178 | for (i=0; i<len; i++) { | |||
| 179 | if (_line[i] == '\t' || _line[i] == '\r' || _line[i] == '\n' || _line[i] == '\f') { | |||
| 180 | _line[i] = ' '; | |||
| 181 | } | |||
| 182 | } | |||
| 183 | ||||
| 184 | // Remove trailing newline/space | |||
| 185 | while (len > 0) { | |||
| 186 | if (_line[len-1] == ' ') { | |||
| 187 | _line[len-1] = '\0'; | |||
| 188 | len --; | |||
| 189 | } else { | |||
| 190 | break; | |||
| 191 | } | |||
| 192 | } | |||
| 193 | _line_len = len; | |||
| 194 | } | |||
| 195 | ||||
| 196 | // valid line | |||
| 197 | break; | |||
| 198 | } | |||
| 199 | ||||
| 200 | _class_name = _line; | |||
| 201 | _id = _unspecified; | |||
| 202 | _super = _unspecified; | |||
| 203 | _interfaces->clear(); | |||
| 204 | _source = NULL__null; | |||
| 205 | _interfaces_specified = false; | |||
| 206 | _indy_items->clear(); | |||
| 207 | _lambda_form_line = false; | |||
| 208 | ||||
| 209 | if (_line[0] == '@') { | |||
| 210 | return parse_at_tags(); | |||
| 211 | } | |||
| 212 | ||||
| 213 | if ((_token = strchr(_line, ' ')) == NULL__null) { | |||
| 214 | // No optional arguments are specified. | |||
| 215 | return true; | |||
| 216 | } | |||
| 217 | ||||
| 218 | // Mark the end of the name, and go to the next input char | |||
| 219 | *_token++ = '\0'; | |||
| 220 | ||||
| 221 | while (*_token) { | |||
| 222 | skip_whitespaces(); | |||
| 223 | ||||
| 224 | if (parse_uint_option("id:", &_id)) { | |||
| 225 | continue; | |||
| 226 | } else if (parse_uint_option("super:", &_super)) { | |||
| 227 | check_already_loaded("Super class", _super); | |||
| 228 | continue; | |||
| 229 | } else if (skip_token("interfaces:")) { | |||
| 230 | int i; | |||
| 231 | while (try_parse_uint(&i)) { | |||
| 232 | check_already_loaded("Interface", i); | |||
| 233 | _interfaces->append(i); | |||
| 234 | } | |||
| 235 | } else if (skip_token("source:")) { | |||
| 236 | skip_whitespaces(); | |||
| 237 | _source = _token; | |||
| 238 | char* s = strchr(_token, ' '); | |||
| 239 | if (s == NULL__null) { | |||
| 240 | break; // end of input line | |||
| 241 | } else { | |||
| 242 | *s = '\0'; // mark the end of _source | |||
| 243 | _token = s+1; | |||
| 244 | } | |||
| 245 | } else { | |||
| 246 | error("Unknown input"); | |||
| 247 | } | |||
| 248 | } | |||
| 249 | ||||
| 250 | // if src is specified | |||
| 251 | // id super interfaces must all be specified | |||
| 252 | // loader may be specified | |||
| 253 | // else | |||
| 254 | // # the class is loaded from classpath | |||
| 255 | // id may be specified | |||
| 256 | // super, interfaces, loader must not be specified | |||
| 257 | return true; | |||
| 258 | } | |||
| 259 | ||||
| 260 | void ClassListParser::split_tokens_by_whitespace(int offset) { | |||
| 261 | int start = offset; | |||
| 262 | int end; | |||
| 263 | bool done = false; | |||
| 264 | while (!done) { | |||
| 265 | while (_line[start] == ' ' || _line[start] == '\t') start++; | |||
| 266 | end = start; | |||
| 267 | while (_line[end] && _line[end] != ' ' && _line[end] != '\t') end++; | |||
| 268 | if (_line[end] == '\0') { | |||
| 269 | done = true; | |||
| 270 | } else { | |||
| 271 | _line[end] = '\0'; | |||
| 272 | } | |||
| 273 | _indy_items->append(_line + start); | |||
| 274 | start = ++end; | |||
| 275 | } | |||
| 276 | } | |||
| 277 | ||||
| 278 | int ClassListParser::split_at_tag_from_line() { | |||
| 279 | _token = _line; | |||
| 280 | char* ptr; | |||
| 281 | if ((ptr = strchr(_line, ' ')) == NULL__null) { | |||
| 282 | error("Too few items following the @ tag \"%s\" line #%d", _line, _line_no); | |||
| 283 | return 0; | |||
| 284 | } | |||
| 285 | *ptr++ = '\0'; | |||
| 286 | while (*ptr == ' ' || *ptr == '\t') ptr++; | |||
| 287 | return (int)(ptr - _line); | |||
| 288 | } | |||
| 289 | ||||
| 290 | bool ClassListParser::parse_at_tags() { | |||
| 291 | assert(_line[0] == '@', "must be")do { if (!(_line[0] == '@')) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 291, "assert(" "_line[0] == '@'" ") failed", "must be"); :: breakpoint(); } } while (0); | |||
| 292 | int offset; | |||
| 293 | if ((offset = split_at_tag_from_line()) == 0) { | |||
| 294 | return false; | |||
| 295 | } | |||
| 296 | ||||
| 297 | if (strcmp(_token, LAMBDA_PROXY_TAG"@lambda-proxy") == 0) { | |||
| 298 | split_tokens_by_whitespace(offset); | |||
| 299 | if (_indy_items->length() < 2) { | |||
| 300 | error("Line with @ tag has too few items \"%s\" line #%d", _token, _line_no); | |||
| 301 | return false; | |||
| 302 | } | |||
| 303 | // set the class name | |||
| 304 | _class_name = _indy_items->at(0); | |||
| 305 | return true; | |||
| 306 | } else if (strcmp(_token, LAMBDA_FORM_TAG"@lambda-form-invoker") == 0) { | |||
| 307 | LambdaFormInvokers::append(os::strdup((const char*)(_line + offset), mtInternal)); | |||
| 308 | _lambda_form_line = true; | |||
| 309 | return true; | |||
| 310 | } else { | |||
| 311 | error("Invalid @ tag at the beginning of line \"%s\" line #%d", _token, _line_no); | |||
| 312 | return false; | |||
| 313 | } | |||
| 314 | } | |||
| 315 | ||||
| 316 | void ClassListParser::skip_whitespaces() { | |||
| 317 | while (*_token == ' ' || *_token == '\t') { | |||
| 318 | _token ++; | |||
| 319 | } | |||
| 320 | } | |||
| 321 | ||||
| 322 | void ClassListParser::skip_non_whitespaces() { | |||
| 323 | while (*_token && *_token != ' ' && *_token != '\t') { | |||
| 324 | _token ++; | |||
| 325 | } | |||
| 326 | } | |||
| 327 | ||||
| 328 | void ClassListParser::parse_int(int* value) { | |||
| 329 | skip_whitespaces(); | |||
| 330 | if (sscanf(_token, "%i", value) == 1) { | |||
| 331 | skip_non_whitespaces(); | |||
| 332 | } else { | |||
| 333 | error("Error: expected integer"); | |||
| 334 | } | |||
| 335 | } | |||
| 336 | ||||
| 337 | void ClassListParser::parse_uint(int* value) { | |||
| 338 | parse_int(value); | |||
| 339 | if (*value < 0) { | |||
| 340 | error("Error: negative integers not allowed (%d)", *value); | |||
| 341 | } | |||
| 342 | } | |||
| 343 | ||||
| 344 | bool ClassListParser::try_parse_uint(int* value) { | |||
| 345 | skip_whitespaces(); | |||
| 346 | if (sscanf(_token, "%i", value) == 1) { | |||
| 347 | skip_non_whitespaces(); | |||
| 348 | return true; | |||
| 349 | } | |||
| 350 | return false; | |||
| 351 | } | |||
| 352 | ||||
| 353 | bool ClassListParser::skip_token(const char* option_name) { | |||
| 354 | size_t len = strlen(option_name); | |||
| 355 | if (strncmp(_token, option_name, len) == 0) { | |||
| 356 | _token += len; | |||
| 357 | return true; | |||
| 358 | } else { | |||
| 359 | return false; | |||
| 360 | } | |||
| 361 | } | |||
| 362 | ||||
| 363 | bool ClassListParser::parse_int_option(const char* option_name, int* value) { | |||
| 364 | if (skip_token(option_name)) { | |||
| 365 | if (*value != _unspecified) { | |||
| 366 | error("%s specified twice", option_name); | |||
| 367 | } else { | |||
| 368 | parse_int(value); | |||
| 369 | return true; | |||
| 370 | } | |||
| 371 | } | |||
| 372 | return false; | |||
| 373 | } | |||
| 374 | ||||
| 375 | bool ClassListParser::parse_uint_option(const char* option_name, int* value) { | |||
| 376 | if (skip_token(option_name)) { | |||
| 377 | if (*value != _unspecified) { | |||
| 378 | error("%s specified twice", option_name); | |||
| 379 | } else { | |||
| 380 | parse_uint(value); | |||
| 381 | return true; | |||
| 382 | } | |||
| 383 | } | |||
| 384 | return false; | |||
| 385 | } | |||
| 386 | ||||
| 387 | void ClassListParser::print_specified_interfaces() { | |||
| 388 | const int n = _interfaces->length(); | |||
| 389 | jio_fprintf(defaultStream::error_stream(), "Currently specified interfaces[%d] = {\n", n); | |||
| 390 | for (int i=0; i<n; i++) { | |||
| 391 | InstanceKlass* k = lookup_class_by_id(_interfaces->at(i)); | |||
| 392 | jio_fprintf(defaultStream::error_stream(), " %4d = %s\n", _interfaces->at(i), k->name()->as_klass_external_name()); | |||
| 393 | } | |||
| 394 | jio_fprintf(defaultStream::error_stream(), "}\n"); | |||
| 395 | } | |||
| 396 | ||||
| 397 | void ClassListParser::print_actual_interfaces(InstanceKlass* ik) { | |||
| 398 | int n = ik->local_interfaces()->length(); | |||
| 399 | jio_fprintf(defaultStream::error_stream(), "Actual interfaces[%d] = {\n", n); | |||
| 400 | for (int i = 0; i < n; i++) { | |||
| 401 | InstanceKlass* e = ik->local_interfaces()->at(i); | |||
| 402 | jio_fprintf(defaultStream::error_stream(), " %s\n", e->name()->as_klass_external_name()); | |||
| 403 | } | |||
| 404 | jio_fprintf(defaultStream::error_stream(), "}\n"); | |||
| 405 | } | |||
| 406 | ||||
| 407 | void ClassListParser::error(const char* msg, ...) { | |||
| 408 | va_list ap; | |||
| 409 | va_start(ap, msg)__builtin_va_start(ap, msg); | |||
| 410 | int error_index = _token - _line; | |||
| 411 | if (error_index >= _line_len) { | |||
| 412 | error_index = _line_len - 1; | |||
| 413 | } | |||
| 414 | if (error_index < 0) { | |||
| 415 | error_index = 0; | |||
| 416 | } | |||
| 417 | ||||
| 418 | jio_fprintf(defaultStream::error_stream(), | |||
| 419 | "An error has occurred while processing class list file %s %d:%d.\n", | |||
| 420 | _classlist_file, _line_no, (error_index + 1)); | |||
| 421 | jio_vfprintf(defaultStream::error_stream(), msg, ap); | |||
| 422 | ||||
| 423 | if (_line_len <= 0) { | |||
| 424 | jio_fprintf(defaultStream::error_stream(), "\n"); | |||
| 425 | } else { | |||
| 426 | jio_fprintf(defaultStream::error_stream(), ":\n"); | |||
| 427 | for (int i=0; i<_line_len; i++) { | |||
| 428 | char c = _line[i]; | |||
| 429 | if (c == '\0') { | |||
| 430 | jio_fprintf(defaultStream::error_stream(), "%s", " "); | |||
| 431 | } else { | |||
| 432 | jio_fprintf(defaultStream::error_stream(), "%c", c); | |||
| 433 | } | |||
| 434 | } | |||
| 435 | jio_fprintf(defaultStream::error_stream(), "\n"); | |||
| 436 | for (int i=0; i<error_index; i++) { | |||
| 437 | jio_fprintf(defaultStream::error_stream(), "%s", " "); | |||
| 438 | } | |||
| 439 | jio_fprintf(defaultStream::error_stream(), "^\n"); | |||
| 440 | } | |||
| 441 | ||||
| 442 | vm_exit_during_initialization("class list format error.", NULL__null); | |||
| 443 | va_end(ap)__builtin_va_end(ap); | |||
| 444 | } | |||
| 445 | ||||
| 446 | // This function is used for loading classes for customized class loaders | |||
| 447 | // during archive dumping. | |||
| 448 | InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPSJavaThread* __the_thread__) { | |||
| 449 | #if !(defined(_LP641) && (defined(LINUX1) || defined(__APPLE__) || defined(_WINDOWS))) | |||
| 450 | // The only supported platforms are: (1) Linux/64-bit and (2) Solaris/64-bit and | |||
| 451 | // (3) MacOSX/64-bit and (4) Windowss/64-bit | |||
| 452 | // This #if condition should be in sync with the areCustomLoadersSupportedForCDS | |||
| 453 | // method in test/lib/jdk/test/lib/Platform.java. | |||
| 454 | error("AppCDS custom class loaders not supported on this platform"); | |||
| 455 | #endif | |||
| 456 | ||||
| 457 | if (!is_super_specified()) { | |||
| 458 | error("If source location is specified, super class must be also specified"); | |||
| 459 | } | |||
| 460 | if (!is_id_specified()) { | |||
| 461 | error("If source location is specified, id must be also specified"); | |||
| 462 | } | |||
| 463 | if (strncmp(_class_name, "java/", 5) == 0) { | |||
| 464 | log_info(cds)(!(LogImpl<(LogTag::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Info))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel ::Info>("Prohibited package for non-bootstrap classes: %s.class from %s", | |||
| 465 | _class_name, _source); | |||
| 466 | THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 466, vmSymbols::java_lang_ClassNotFoundException(), __null) ; return __null; }; | |||
| 467 | } | |||
| 468 | ||||
| 469 | InstanceKlass* k = UnregisteredClasses::load_class(class_name, _source, CHECK_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); | |||
| 470 | if (k->local_interfaces()->length() != _interfaces->length()) { | |||
| 471 | print_specified_interfaces(); | |||
| 472 | print_actual_interfaces(k); | |||
| 473 | error("The number of interfaces (%d) specified in class list does not match the class file (%d)", | |||
| 474 | _interfaces->length(), k->local_interfaces()->length()); | |||
| 475 | } | |||
| 476 | ||||
| 477 | assert(k->is_shared_unregistered_class(), "must be")do { if (!(k->is_shared_unregistered_class())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 477, "assert(" "k->is_shared_unregistered_class()" ") failed" , "must be"); ::breakpoint(); } } while (0); | |||
| 478 | ||||
| 479 | bool added = SystemDictionaryShared::add_unregistered_class(THREAD__the_thread__, k); | |||
| 480 | if (!added) { | |||
| 481 | // We allow only a single unregistered class for each unique name. | |||
| 482 | error("Duplicated class %s", _class_name); | |||
| 483 | } | |||
| 484 | ||||
| 485 | return k; | |||
| 486 | } | |||
| 487 | ||||
| 488 | void ClassListParser::populate_cds_indy_info(const constantPoolHandle &pool, int cp_index, CDSIndyInfo* cii, TRAPSJavaThread* __the_thread__) { | |||
| 489 | // Caller needs to allocate ResourceMark. | |||
| 490 | int type_index = pool->bootstrap_name_and_type_ref_index_at(cp_index); | |||
| 491 | int name_index = pool->name_ref_index_at(type_index); | |||
| 492 | cii->add_item(pool->symbol_at(name_index)->as_C_string()); | |||
| 493 | int sig_index = pool->signature_ref_index_at(type_index); | |||
| 494 | cii->add_item(pool->symbol_at(sig_index)->as_C_string()); | |||
| 495 | int argc = pool->bootstrap_argument_count_at(cp_index); | |||
| 496 | if (argc > 0) { | |||
| 497 | for (int arg_i = 0; arg_i < argc; arg_i++) { | |||
| 498 | int arg = pool->bootstrap_argument_index_at(cp_index, arg_i); | |||
| 499 | jbyte tag = pool->tag_at(arg).value(); | |||
| 500 | if (tag == JVM_CONSTANT_MethodType) { | |||
| 501 | cii->add_item(pool->method_type_signature_at(arg)->as_C_string()); | |||
| 502 | } else if (tag == JVM_CONSTANT_MethodHandle) { | |||
| 503 | cii->add_ref_kind(pool->method_handle_ref_kind_at(arg)); | |||
| 504 | int callee_index = pool->method_handle_klass_index_at(arg); | |||
| 505 | Klass* callee = pool->klass_at(callee_index, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 506 | cii->add_item(callee->name()->as_C_string()); | |||
| 507 | cii->add_item(pool->method_handle_name_ref_at(arg)->as_C_string()); | |||
| 508 | cii->add_item(pool->method_handle_signature_ref_at(arg)->as_C_string()); | |||
| 509 | } else { | |||
| 510 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 510); ::breakpoint(); } while (0); | |||
| 511 | } | |||
| 512 | } | |||
| 513 | } | |||
| 514 | } | |||
| 515 | ||||
| 516 | bool ClassListParser::is_matching_cp_entry(const constantPoolHandle &pool, int cp_index, TRAPSJavaThread* __the_thread__) { | |||
| 517 | ResourceMark rm(THREAD__the_thread__); | |||
| 518 | CDSIndyInfo cii; | |||
| 519 | populate_cds_indy_info(pool, cp_index, &cii, CHECK_0__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return 0; (void)(0); | |||
| 520 | GrowableArray<const char*>* items = cii.items(); | |||
| 521 | int indy_info_offset = 1; | |||
| 522 | if (_indy_items->length() - indy_info_offset != items->length()) { | |||
| 523 | return false; | |||
| 524 | } | |||
| 525 | for (int i = 0; i < items->length(); i++) { | |||
| 526 | if (strcmp(_indy_items->at(i + indy_info_offset), items->at(i)) != 0) { | |||
| 527 | return false; | |||
| 528 | } | |||
| 529 | } | |||
| 530 | return true; | |||
| 531 | } | |||
| 532 | ||||
| 533 | void ClassListParser::resolve_indy(JavaThread* current, Symbol* class_name_symbol) { | |||
| 534 | ExceptionMark em(current); | |||
| 535 | JavaThread* THREAD__the_thread__ = current; // For exception macros. | |||
| 536 | ClassListParser::resolve_indy_impl(class_name_symbol, THREAD__the_thread__); | |||
| 537 | if (HAS_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->has_pending_exception())) { | |||
| 538 | ResourceMark rm(current); | |||
| 539 | char* ex_msg = (char*)""; | |||
| 540 | oop message = java_lang_Throwable::message(PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception())); | |||
| 541 | if (message != NULL__null) { | |||
| 542 | ex_msg = java_lang_String::as_utf8_string(message); | |||
| 543 | } | |||
| 544 | log_warning(cds)(!(LogImpl<(LogTag::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Warning))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel ::Warning>("resolve_indy for class %s has encountered exception: %s %s", | |||
| 545 | class_name_symbol->as_C_string(), | |||
| 546 | PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->pending_exception())->klass()->external_name(), | |||
| 547 | ex_msg); | |||
| 548 | CLEAR_PENDING_EXCEPTION(((ThreadShadow*)__the_thread__)->clear_pending_exception( )); | |||
| 549 | } | |||
| 550 | } | |||
| 551 | ||||
| 552 | void ClassListParser::resolve_indy_impl(Symbol* class_name_symbol, TRAPSJavaThread* __the_thread__) { | |||
| 553 | Handle class_loader(THREAD__the_thread__, SystemDictionary::java_system_loader()); | |||
| 554 | Handle protection_domain; | |||
| 555 | Klass* klass = SystemDictionary::resolve_or_fail(class_name_symbol, class_loader, protection_domain, true, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 556 | if (klass->is_instance_klass()) { | |||
| 557 | InstanceKlass* ik = InstanceKlass::cast(klass); | |||
| 558 | MetaspaceShared::try_link_class(THREAD__the_thread__, ik); | |||
| 559 | if (!ik->is_linked()) { | |||
| 560 | // Verification of ik has failed | |||
| 561 | return; | |||
| 562 | } | |||
| 563 | ||||
| 564 | ConstantPool* cp = ik->constants(); | |||
| 565 | ConstantPoolCache* cpcache = cp->cache(); | |||
| 566 | bool found = false; | |||
| 567 | for (int cpcindex = 0; cpcindex < cpcache->length(); cpcindex ++) { | |||
| 568 | int indy_index = ConstantPool::encode_invokedynamic_index(cpcindex); | |||
| 569 | ConstantPoolCacheEntry* cpce = cpcache->entry_at(cpcindex); | |||
| 570 | int pool_index = cpce->constant_pool_index(); | |||
| 571 | constantPoolHandle pool(THREAD__the_thread__, cp); | |||
| 572 | if (pool->tag_at(pool_index).is_invoke_dynamic()) { | |||
| 573 | BootstrapInfo bootstrap_specifier(pool, pool_index, indy_index); | |||
| 574 | Handle bsm = bootstrap_specifier.resolve_bsm(CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 575 | if (!SystemDictionaryShared::is_supported_invokedynamic(&bootstrap_specifier)) { | |||
| 576 | log_debug(cds, lambda)(!(LogImpl<(LogTag::_cds), (LogTag::_lambda), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Debug))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::_lambda), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel ::Debug>("is_supported_invokedynamic check failed for cp_index %d", pool_index); | |||
| 577 | continue; | |||
| 578 | } | |||
| 579 | bool matched = is_matching_cp_entry(pool, pool_index, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 580 | if (matched) { | |||
| 581 | found = true; | |||
| 582 | CallInfo info; | |||
| 583 | bool is_done = bootstrap_specifier.resolve_previously_linked_invokedynamic(info, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 584 | if (!is_done) { | |||
| 585 | // resolve it | |||
| 586 | Handle recv; | |||
| 587 | LinkResolver::resolve_invoke(info, recv, pool, indy_index, Bytecodes::_invokedynamic, CHECK__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return ; (void)(0); | |||
| 588 | break; | |||
| 589 | } | |||
| 590 | cpce->set_dynamic_call(pool, info); | |||
| 591 | } | |||
| 592 | } | |||
| 593 | } | |||
| 594 | if (!found) { | |||
| 595 | ResourceMark rm(THREAD__the_thread__); | |||
| 596 | log_warning(cds)(!(LogImpl<(LogTag::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG) >::is_level(LogLevel::Warning))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG ), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write<LogLevel ::Warning>("No invoke dynamic constant pool entry can be found for class %s. The classlist is probably out-of-date.", | |||
| 597 | class_name_symbol->as_C_string()); | |||
| 598 | } | |||
| 599 | } | |||
| 600 | } | |||
| 601 | ||||
| 602 | Klass* ClassListParser::load_current_class(Symbol* class_name_symbol, TRAPSJavaThread* __the_thread__) { | |||
| 603 | Klass* klass; | |||
| 604 | if (!is_loading_from_source()) { | |||
| 605 | // Load classes for the boot/platform/app loaders only. | |||
| 606 | if (is_super_specified()) { | |||
| 607 | error("If source location is not specified, super class must not be specified"); | |||
| 608 | } | |||
| 609 | if (are_interfaces_specified()) { | |||
| 610 | error("If source location is not specified, interface(s) must not be specified"); | |||
| 611 | } | |||
| 612 | ||||
| 613 | if (Signature::is_array(class_name_symbol)) { | |||
| 614 | // array classes are not supported in class list. | |||
| 615 | THROW_NULL(vmSymbols::java_lang_ClassNotFoundException()){ Exceptions::_throw_msg(__the_thread__, "/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 615, vmSymbols::java_lang_ClassNotFoundException(), __null) ; return __null; }; | |||
| 616 | } | |||
| 617 | ||||
| 618 | JavaValue result(T_OBJECT); | |||
| 619 | // Call java_system_loader().loadClass() directly, which will | |||
| 620 | // delegate to the correct loader (boot, platform or app) depending on | |||
| 621 | // the package name. | |||
| 622 | ||||
| 623 | // ClassLoader.loadClass() wants external class name format, i.e., convert '/' chars to '.' | |||
| 624 | Handle ext_class_name = java_lang_String::externalize_classname(class_name_symbol, CHECK_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); | |||
| 625 | Handle loader = Handle(THREAD__the_thread__, SystemDictionary::java_system_loader()); | |||
| 626 | ||||
| 627 | JavaCalls::call_virtual(&result, | |||
| 628 | loader, //SystemDictionary::java_system_loader(), | |||
| 629 | vmClasses::ClassLoader_klass(), | |||
| 630 | vmSymbols::loadClass_name(), | |||
| 631 | vmSymbols::string_class_signature(), | |||
| 632 | ext_class_name, | |||
| 633 | CHECK_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); | |||
| 634 | ||||
| 635 | assert(result.get_type() == T_OBJECT, "just checking")do { if (!(result.get_type() == T_OBJECT)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 635, "assert(" "result.get_type() == T_OBJECT" ") failed", "just checking" ); ::breakpoint(); } } while (0); | |||
| 636 | oop obj = result.get_oop(); | |||
| 637 | assert(obj != NULL, "jdk.internal.loader.BuiltinClassLoader::loadClass never returns null")do { if (!(obj != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 637, "assert(" "obj != __null" ") failed", "jdk.internal.loader.BuiltinClassLoader::loadClass never returns null" ); ::breakpoint(); } } while (0); | |||
| 638 | klass = java_lang_Class::as_Klass(obj); | |||
| 639 | } else { | |||
| 640 | // If "source:" tag is specified, all super class and super interfaces must be specified in the | |||
| 641 | // class list file. | |||
| 642 | klass = load_class_from_source(class_name_symbol, CHECK_NULL__the_thread__); if ((((ThreadShadow*)__the_thread__)->has_pending_exception ())) return __null; (void)(0); | |||
| 643 | } | |||
| 644 | ||||
| 645 | assert(klass != NULL, "exception should have been thrown")do { if (!(klass != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 645, "assert(" "klass != __null" ") failed", "exception should have been thrown" ); ::breakpoint(); } } while (0); | |||
| 646 | assert(klass->is_instance_klass(), "array classes should have been filtered out")do { if (!(klass->is_instance_klass())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 646, "assert(" "klass->is_instance_klass()" ") failed", "array classes should have been filtered out" ); ::breakpoint(); } } while (0); | |||
| 647 | ||||
| 648 | if (is_id_specified()) { | |||
| 649 | InstanceKlass* ik = InstanceKlass::cast(klass); | |||
| 650 | int id = this->id(); | |||
| 651 | SystemDictionaryShared::update_shared_entry(ik, id); | |||
| 652 | bool created; | |||
| 653 | id2klass_table()->put_if_absent(id, ik, &created); | |||
| 654 | if (!created) { | |||
| 655 | error("Duplicated ID %d for class %s", id, _class_name); | |||
| 656 | } | |||
| 657 | if (id2klass_table()->maybe_grow()) { | |||
| 658 | log_info(cds, hashtables)(!(LogImpl<(LogTag::_cds), (LogTag::_hashtables), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG )>::is_level(LogLevel::Info))) ? (void)0 : LogImpl<(LogTag ::_cds), (LogTag::_hashtables), (LogTag::__NO_TAG), (LogTag:: __NO_TAG), (LogTag::__NO_TAG), (LogTag::__NO_TAG)>::write< LogLevel::Info>("Expanded id2klass_table() to %d", id2klass_table()->table_size()); | |||
| 659 | } | |||
| 660 | } | |||
| 661 | ||||
| 662 | return klass; | |||
| 663 | } | |||
| 664 | ||||
| 665 | bool ClassListParser::is_loading_from_source() { | |||
| 666 | return (_source != NULL__null); | |||
| 667 | } | |||
| 668 | ||||
| 669 | InstanceKlass* ClassListParser::lookup_class_by_id(int id) { | |||
| 670 | InstanceKlass** klass_ptr = id2klass_table()->get(id); | |||
| 671 | if (klass_ptr == NULL__null) { | |||
| 672 | error("Class ID %d has not been defined", id); | |||
| 673 | } | |||
| 674 | assert(*klass_ptr != NULL, "must be")do { if (!(*klass_ptr != __null)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 674, "assert(" "*klass_ptr != __null" ") failed", "must be" ); ::breakpoint(); } } while (0); | |||
| ||||
| 675 | return *klass_ptr; | |||
| 676 | } | |||
| 677 | ||||
| 678 | ||||
| 679 | InstanceKlass* ClassListParser::lookup_super_for_current_class(Symbol* super_name) { | |||
| 680 | if (!is_loading_from_source()) { | |||
| 681 | return NULL__null; | |||
| 682 | } | |||
| 683 | ||||
| 684 | InstanceKlass* k = lookup_class_by_id(super()); | |||
| 685 | if (super_name != k->name()) { | |||
| 686 | error("The specified super class %s (id %d) does not match actual super class %s", | |||
| 687 | k->name()->as_klass_external_name(), super(), | |||
| 688 | super_name->as_klass_external_name()); | |||
| 689 | } | |||
| 690 | return k; | |||
| 691 | } | |||
| 692 | ||||
| 693 | InstanceKlass* ClassListParser::lookup_interface_for_current_class(Symbol* interface_name) { | |||
| 694 | if (!is_loading_from_source()) { | |||
| ||||
| 695 | return NULL__null; | |||
| 696 | } | |||
| 697 | ||||
| 698 | const int n = _interfaces->length(); | |||
| 699 | if (n == 0) { | |||
| 700 | error("Class %s implements the interface %s, but no interface has been specified in the input line", | |||
| 701 | _class_name, interface_name->as_klass_external_name()); | |||
| 702 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 702); ::breakpoint(); } while (0); | |||
| 703 | } | |||
| 704 | ||||
| 705 | int i; | |||
| 706 | for (i=0; i<n; i++) { | |||
| 707 | InstanceKlass* k = lookup_class_by_id(_interfaces->at(i)); | |||
| 708 | if (interface_name == k->name()) { | |||
| 709 | return k; | |||
| 710 | } | |||
| 711 | } | |||
| 712 | ||||
| 713 | // interface_name is not specified by the "interfaces:" keyword. | |||
| 714 | print_specified_interfaces(); | |||
| 715 | error("The interface %s implemented by class %s does not match any of the specified interface IDs", | |||
| 716 | interface_name->as_klass_external_name(), _class_name); | |||
| 717 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/cds/classListParser.cpp" , 717); ::breakpoint(); } while (0); | |||
| 718 | return NULL__null; | |||
| 719 | } |