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 | } |