1 | /* |
2 | * Copyright (c) 1998, 2019, 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 "classfile/symbolTable.hpp" |
28 | #include "compiler/compilerOracle.hpp" |
29 | #include "compiler/methodMatcher.hpp" |
30 | #include "memory/allocation.inline.hpp" |
31 | #include "memory/oopFactory.hpp" |
32 | #include "memory/resourceArea.hpp" |
33 | #include "oops/klass.hpp" |
34 | #include "oops/method.hpp" |
35 | #include "oops/symbol.hpp" |
36 | #include "runtime/handles.inline.hpp" |
37 | #include "runtime/jniHandles.hpp" |
38 | #include "runtime/os.hpp" |
39 | |
40 | enum OptionType { |
41 | IntxType, |
42 | UintxType, |
43 | BoolType, |
44 | CcstrType, |
45 | DoubleType, |
46 | UnknownType |
47 | }; |
48 | |
49 | /* Methods to map real type names to OptionType */ |
50 | template<typename T> |
51 | static OptionType get_type_for() { |
52 | return UnknownType; |
53 | }; |
54 | |
55 | template<> OptionType get_type_for<intx>() { |
56 | return IntxType; |
57 | } |
58 | |
59 | template<> OptionType get_type_for<uintx>() { |
60 | return UintxType; |
61 | } |
62 | |
63 | template<> OptionType get_type_for<bool>() { |
64 | return BoolType; |
65 | } |
66 | |
67 | template<> OptionType get_type_for<ccstr>() { |
68 | return CcstrType; |
69 | } |
70 | |
71 | template<> OptionType get_type_for<double>() { |
72 | return DoubleType; |
73 | } |
74 | |
75 | // this must parallel the command_names below |
76 | enum OracleCommand { |
77 | UnknownCommand = -1, |
78 | OracleFirstCommand = 0, |
79 | BreakCommand = OracleFirstCommand, |
80 | PrintCommand, |
81 | ExcludeCommand, |
82 | InlineCommand, |
83 | DontInlineCommand, |
84 | CompileOnlyCommand, |
85 | LogCommand, |
86 | OptionCommand, |
87 | QuietCommand, |
88 | HelpCommand, |
89 | OracleCommandCount |
90 | }; |
91 | |
92 | // this must parallel the enum OracleCommand |
93 | static const char * command_names[] = { |
94 | "break" , |
95 | "print" , |
96 | "exclude" , |
97 | "inline" , |
98 | "dontinline" , |
99 | "compileonly" , |
100 | "log" , |
101 | "option" , |
102 | "quiet" , |
103 | "help" |
104 | }; |
105 | |
106 | class MethodMatcher; |
107 | class TypedMethodOptionMatcher; |
108 | |
109 | static BasicMatcher* lists[OracleCommandCount] = { 0, }; |
110 | static TypedMethodOptionMatcher* option_list = NULL; |
111 | static bool any_set = false; |
112 | |
113 | class TypedMethodOptionMatcher : public MethodMatcher { |
114 | private: |
115 | TypedMethodOptionMatcher* _next; |
116 | const char* _option; |
117 | OptionType _type; |
118 | public: |
119 | |
120 | union { |
121 | bool bool_value; |
122 | intx intx_value; |
123 | uintx uintx_value; |
124 | double double_value; |
125 | ccstr ccstr_value; |
126 | } _u; |
127 | |
128 | TypedMethodOptionMatcher() : MethodMatcher(), |
129 | _next(NULL), |
130 | _type(UnknownType) { |
131 | _option = NULL; |
132 | memset(&_u, 0, sizeof(_u)); |
133 | } |
134 | |
135 | static TypedMethodOptionMatcher* parse_method_pattern(char*& line, const char*& error_msg); |
136 | TypedMethodOptionMatcher* match(const methodHandle& method, const char* opt, OptionType type); |
137 | |
138 | void init(const char* opt, OptionType type, TypedMethodOptionMatcher* next) { |
139 | _next = next; |
140 | _type = type; |
141 | _option = os::strdup_check_oom(opt); |
142 | } |
143 | |
144 | void set_next(TypedMethodOptionMatcher* next) {_next = next; } |
145 | TypedMethodOptionMatcher* next() { return _next; } |
146 | OptionType type() { return _type; } |
147 | template<typename T> T value(); |
148 | template<typename T> void set_value(T value); |
149 | void print(); |
150 | void print_all(); |
151 | TypedMethodOptionMatcher* clone(); |
152 | ~TypedMethodOptionMatcher(); |
153 | }; |
154 | |
155 | // A few templated accessors instead of a full template class. |
156 | template<> intx TypedMethodOptionMatcher::value<intx>() { |
157 | return _u.intx_value; |
158 | } |
159 | |
160 | template<> uintx TypedMethodOptionMatcher::value<uintx>() { |
161 | return _u.uintx_value; |
162 | } |
163 | |
164 | template<> bool TypedMethodOptionMatcher::value<bool>() { |
165 | return _u.bool_value; |
166 | } |
167 | |
168 | template<> double TypedMethodOptionMatcher::value<double>() { |
169 | return _u.double_value; |
170 | } |
171 | |
172 | template<> ccstr TypedMethodOptionMatcher::value<ccstr>() { |
173 | return _u.ccstr_value; |
174 | } |
175 | |
176 | template<> void TypedMethodOptionMatcher::set_value(intx value) { |
177 | _u.intx_value = value; |
178 | } |
179 | |
180 | template<> void TypedMethodOptionMatcher::set_value(uintx value) { |
181 | _u.uintx_value = value; |
182 | } |
183 | |
184 | template<> void TypedMethodOptionMatcher::set_value(double value) { |
185 | _u.double_value = value; |
186 | } |
187 | |
188 | template<> void TypedMethodOptionMatcher::set_value(bool value) { |
189 | _u.bool_value = value; |
190 | } |
191 | |
192 | template<> void TypedMethodOptionMatcher::set_value(ccstr value) { |
193 | _u.ccstr_value = (const ccstr)os::strdup_check_oom(value); |
194 | } |
195 | |
196 | void TypedMethodOptionMatcher::print() { |
197 | ttyLocker ttyl; |
198 | print_base(tty); |
199 | switch (_type) { |
200 | case IntxType: |
201 | tty->print_cr(" intx %s = " INTX_FORMAT, _option, value<intx>()); |
202 | break; |
203 | case UintxType: |
204 | tty->print_cr(" uintx %s = " UINTX_FORMAT, _option, value<uintx>()); |
205 | break; |
206 | case BoolType: |
207 | tty->print_cr(" bool %s = %s" , _option, value<bool>() ? "true" : "false" ); |
208 | break; |
209 | case DoubleType: |
210 | tty->print_cr(" double %s = %f" , _option, value<double>()); |
211 | break; |
212 | case CcstrType: |
213 | tty->print_cr(" const char* %s = '%s'" , _option, value<ccstr>()); |
214 | break; |
215 | default: |
216 | ShouldNotReachHere(); |
217 | } |
218 | } |
219 | |
220 | void TypedMethodOptionMatcher::print_all() { |
221 | print(); |
222 | if (_next != NULL) { |
223 | tty->print(" " ); |
224 | _next->print_all(); |
225 | } |
226 | } |
227 | |
228 | TypedMethodOptionMatcher* TypedMethodOptionMatcher::clone() { |
229 | TypedMethodOptionMatcher* m = new TypedMethodOptionMatcher(); |
230 | m->_class_mode = _class_mode; |
231 | m->_class_name = _class_name; |
232 | m->_method_mode = _method_mode; |
233 | m->_method_name = _method_name; |
234 | m->_signature = _signature; |
235 | // Need to ref count the symbols |
236 | if (_class_name != NULL) { |
237 | _class_name->increment_refcount(); |
238 | } |
239 | if (_method_name != NULL) { |
240 | _method_name->increment_refcount(); |
241 | } |
242 | if (_signature != NULL) { |
243 | _signature->increment_refcount(); |
244 | } |
245 | return m; |
246 | } |
247 | |
248 | TypedMethodOptionMatcher::~TypedMethodOptionMatcher() { |
249 | if (_option != NULL) { |
250 | os::free((void*)_option); |
251 | } |
252 | } |
253 | |
254 | TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, const char*& error_msg) { |
255 | assert(error_msg == NULL, "Dont call here with error_msg already set" ); |
256 | TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher(); |
257 | MethodMatcher::parse_method_pattern(line, error_msg, tom); |
258 | if (error_msg != NULL) { |
259 | delete tom; |
260 | return NULL; |
261 | } |
262 | return tom; |
263 | } |
264 | |
265 | TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(const methodHandle& method, const char* opt, OptionType type) { |
266 | TypedMethodOptionMatcher* current = this; |
267 | while (current != NULL) { |
268 | // Fastest compare first. |
269 | if (current->type() == type) { |
270 | if (strcmp(current->_option, opt) == 0) { |
271 | if (current->matches(method)) { |
272 | return current; |
273 | } |
274 | } |
275 | } |
276 | current = current->next(); |
277 | } |
278 | return NULL; |
279 | } |
280 | |
281 | template<typename T> |
282 | static void add_option_string(TypedMethodOptionMatcher* matcher, |
283 | const char* option, |
284 | T value) { |
285 | assert(matcher != option_list, "No circular lists please" ); |
286 | matcher->init(option, get_type_for<T>(), option_list); |
287 | matcher->set_value<T>(value); |
288 | option_list = matcher; |
289 | any_set = true; |
290 | return; |
291 | } |
292 | |
293 | static bool check_predicate(OracleCommand command, const methodHandle& method) { |
294 | return ((lists[command] != NULL) && |
295 | !method.is_null() && |
296 | lists[command]->match(method)); |
297 | } |
298 | |
299 | static void add_predicate(OracleCommand command, BasicMatcher* bm) { |
300 | assert(command != OptionCommand, "must use add_option_string" ); |
301 | if (command == LogCommand && !LogCompilation && lists[LogCommand] == NULL) { |
302 | tty->print_cr("Warning: +LogCompilation must be enabled in order for individual methods to be logged." ); |
303 | } |
304 | bm->set_next(lists[command]); |
305 | lists[command] = bm; |
306 | if ((command != DontInlineCommand) && (command != InlineCommand)) { |
307 | any_set = true; |
308 | } |
309 | return; |
310 | } |
311 | |
312 | template<typename T> |
313 | bool CompilerOracle::has_option_value(const methodHandle& method, const char* option, T& value) { |
314 | if (option_list != NULL) { |
315 | TypedMethodOptionMatcher* m = option_list->match(method, option, get_type_for<T>()); |
316 | if (m != NULL) { |
317 | value = m->value<T>(); |
318 | return true; |
319 | } |
320 | } |
321 | return false; |
322 | } |
323 | |
324 | bool CompilerOracle::has_any_option() { |
325 | return any_set; |
326 | } |
327 | |
328 | // Explicit instantiation for all OptionTypes supported. |
329 | template bool CompilerOracle::has_option_value<intx>(const methodHandle& method, const char* option, intx& value); |
330 | template bool CompilerOracle::has_option_value<uintx>(const methodHandle& method, const char* option, uintx& value); |
331 | template bool CompilerOracle::has_option_value<bool>(const methodHandle& method, const char* option, bool& value); |
332 | template bool CompilerOracle::has_option_value<ccstr>(const methodHandle& method, const char* option, ccstr& value); |
333 | template bool CompilerOracle::has_option_value<double>(const methodHandle& method, const char* option, double& value); |
334 | |
335 | bool CompilerOracle::has_option_string(const methodHandle& method, const char* option) { |
336 | bool value = false; |
337 | has_option_value(method, option, value); |
338 | return value; |
339 | } |
340 | |
341 | bool CompilerOracle::should_exclude(const methodHandle& method) { |
342 | if (check_predicate(ExcludeCommand, method)) { |
343 | return true; |
344 | } |
345 | if (lists[CompileOnlyCommand] != NULL) { |
346 | return !lists[CompileOnlyCommand]->match(method); |
347 | } |
348 | return false; |
349 | } |
350 | |
351 | bool CompilerOracle::should_inline(const methodHandle& method) { |
352 | return (check_predicate(InlineCommand, method)); |
353 | } |
354 | |
355 | bool CompilerOracle::should_not_inline(const methodHandle& method) { |
356 | return check_predicate(DontInlineCommand, method) || check_predicate(ExcludeCommand, method); |
357 | } |
358 | |
359 | bool CompilerOracle::should_print(const methodHandle& method) { |
360 | return check_predicate(PrintCommand, method); |
361 | } |
362 | |
363 | bool CompilerOracle::should_print_methods() { |
364 | return lists[PrintCommand] != NULL; |
365 | } |
366 | |
367 | bool CompilerOracle::should_log(const methodHandle& method) { |
368 | if (!LogCompilation) return false; |
369 | if (lists[LogCommand] == NULL) return true; // by default, log all |
370 | return (check_predicate(LogCommand, method)); |
371 | } |
372 | |
373 | bool CompilerOracle::should_break_at(const methodHandle& method) { |
374 | return check_predicate(BreakCommand, method); |
375 | } |
376 | |
377 | static OracleCommand parse_command_name(const char * line, int* bytes_read) { |
378 | assert(ARRAY_SIZE(command_names) == OracleCommandCount, |
379 | "command_names size mismatch" ); |
380 | |
381 | *bytes_read = 0; |
382 | char command[33]; |
383 | int result = sscanf(line, "%32[a-z]%n" , command, bytes_read); |
384 | for (uint i = 0; i < ARRAY_SIZE(command_names); i++) { |
385 | if (strcmp(command, command_names[i]) == 0) { |
386 | return (OracleCommand)i; |
387 | } |
388 | } |
389 | return UnknownCommand; |
390 | } |
391 | |
392 | static void usage() { |
393 | tty->cr(); |
394 | tty->print_cr("The CompileCommand option enables the user of the JVM to control specific" ); |
395 | tty->print_cr("behavior of the dynamic compilers. Many commands require a pattern that defines" ); |
396 | tty->print_cr("the set of methods the command shall be applied to. The CompileCommand" ); |
397 | tty->print_cr("option provides the following commands:" ); |
398 | tty->cr(); |
399 | tty->print_cr(" break,<pattern> - debug breakpoint in compiler and in generated code" ); |
400 | tty->print_cr(" print,<pattern> - print assembly" ); |
401 | tty->print_cr(" exclude,<pattern> - don't compile or inline" ); |
402 | tty->print_cr(" inline,<pattern> - always inline" ); |
403 | tty->print_cr(" dontinline,<pattern> - don't inline" ); |
404 | tty->print_cr(" compileonly,<pattern> - compile only" ); |
405 | tty->print_cr(" log,<pattern> - log compilation" ); |
406 | tty->print_cr(" option,<pattern>,<option type>,<option name>,<value>" ); |
407 | tty->print_cr(" - set value of custom option" ); |
408 | tty->print_cr(" option,<pattern>,<bool option name>" ); |
409 | tty->print_cr(" - shorthand for setting boolean flag" ); |
410 | tty->print_cr(" quiet - silence the compile command output" ); |
411 | tty->print_cr(" help - print this text" ); |
412 | tty->cr(); |
413 | tty->print_cr("The preferred format for the method matching pattern is:" ); |
414 | tty->print_cr(" package/Class.method()" ); |
415 | tty->cr(); |
416 | tty->print_cr("For backward compatibility this form is also allowed:" ); |
417 | tty->print_cr(" package.Class::method()" ); |
418 | tty->cr(); |
419 | tty->print_cr("The signature can be separated by an optional whitespace or comma:" ); |
420 | tty->print_cr(" package/Class.method ()" ); |
421 | tty->cr(); |
422 | tty->print_cr("The class and method identifier can be used together with leading or" ); |
423 | tty->print_cr("trailing *'s for a small amount of wildcarding:" ); |
424 | tty->print_cr(" *ackage/Clas*.*etho*()" ); |
425 | tty->cr(); |
426 | tty->print_cr("It is possible to use more than one CompileCommand on the command line:" ); |
427 | tty->print_cr(" -XX:CompileCommand=exclude,java/*.* -XX:CompileCommand=log,java*.*" ); |
428 | tty->cr(); |
429 | tty->print_cr("The CompileCommands can be loaded from a file with the flag" ); |
430 | tty->print_cr("-XX:CompileCommandFile=<file> or be added to the file '.hotspot_compiler'" ); |
431 | tty->print_cr("Use the same format in the file as the argument to the CompileCommand flag." ); |
432 | tty->print_cr("Add one command on each line." ); |
433 | tty->print_cr(" exclude java/*.*" ); |
434 | tty->print_cr(" option java/*.* ReplayInline" ); |
435 | tty->cr(); |
436 | tty->print_cr("The following commands have conflicting behavior: 'exclude', 'inline', 'dontinline'," ); |
437 | tty->print_cr("and 'compileonly'. There is no priority of commands. Applying (a subset of) these" ); |
438 | tty->print_cr("commands to the same method results in undefined behavior." ); |
439 | tty->cr(); |
440 | }; |
441 | |
442 | // Scan next flag and value in line, return MethodMatcher object on success, NULL on failure. |
443 | // On failure, error_msg contains description for the first error. |
444 | // For future extensions: set error_msg on first error. |
445 | static void scan_flag_and_value(const char* type, const char* line, int& total_bytes_read, |
446 | TypedMethodOptionMatcher* matcher, |
447 | char* errorbuf, const int buf_size) { |
448 | total_bytes_read = 0; |
449 | int bytes_read = 0; |
450 | char flag[256]; |
451 | |
452 | // Read flag name. |
453 | if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n" , flag, &bytes_read) == 1) { |
454 | line += bytes_read; |
455 | total_bytes_read += bytes_read; |
456 | |
457 | // Read value. |
458 | if (strcmp(type, "intx" ) == 0) { |
459 | intx value; |
460 | if (sscanf(line, "%*[ \t]" INTX_FORMAT "%n" , &value, &bytes_read) == 1) { |
461 | total_bytes_read += bytes_read; |
462 | add_option_string(matcher, flag, value); |
463 | return; |
464 | } else { |
465 | jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s " , flag, type); |
466 | } |
467 | } else if (strcmp(type, "uintx" ) == 0) { |
468 | uintx value; |
469 | if (sscanf(line, "%*[ \t]" UINTX_FORMAT "%n" , &value, &bytes_read) == 1) { |
470 | total_bytes_read += bytes_read; |
471 | add_option_string(matcher, flag, value); |
472 | return; |
473 | } else { |
474 | jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s" , flag, type); |
475 | } |
476 | } else if (strcmp(type, "ccstr" ) == 0) { |
477 | ResourceMark rm; |
478 | char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); |
479 | if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n" , value, &bytes_read) == 1) { |
480 | total_bytes_read += bytes_read; |
481 | add_option_string(matcher, flag, (ccstr)value); |
482 | return; |
483 | } else { |
484 | jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s" , flag, type); |
485 | } |
486 | } else if (strcmp(type, "ccstrlist" ) == 0) { |
487 | // Accumulates several strings into one. The internal type is ccstr. |
488 | ResourceMark rm; |
489 | char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1); |
490 | char* next_value = value; |
491 | if (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n" , next_value, &bytes_read) == 1) { |
492 | total_bytes_read += bytes_read; |
493 | line += bytes_read; |
494 | next_value += bytes_read; |
495 | char* end_value = next_value-1; |
496 | while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9]%n" , next_value, &bytes_read) == 1) { |
497 | total_bytes_read += bytes_read; |
498 | line += bytes_read; |
499 | *end_value = ' '; // override '\0' |
500 | next_value += bytes_read; |
501 | end_value = next_value-1; |
502 | } |
503 | add_option_string(matcher, flag, (ccstr)value); |
504 | return; |
505 | } else { |
506 | jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s" , flag, type); |
507 | } |
508 | } else if (strcmp(type, "bool" ) == 0) { |
509 | char value[256]; |
510 | if (sscanf(line, "%*[ \t]%255[a-zA-Z]%n" , value, &bytes_read) == 1) { |
511 | if (strcmp(value, "true" ) == 0) { |
512 | total_bytes_read += bytes_read; |
513 | add_option_string(matcher, flag, true); |
514 | return; |
515 | } else if (strcmp(value, "false" ) == 0) { |
516 | total_bytes_read += bytes_read; |
517 | add_option_string(matcher, flag, false); |
518 | return; |
519 | } else { |
520 | jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s" , flag, type); |
521 | } |
522 | } else { |
523 | jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s" , flag, type); |
524 | } |
525 | } else if (strcmp(type, "double" ) == 0) { |
526 | char buffer[2][256]; |
527 | // Decimal separator '.' has been replaced with ' ' or '/' earlier, |
528 | // so read integer and fraction part of double value separately. |
529 | if (sscanf(line, "%*[ \t]%255[0-9]%*[ /\t]%255[0-9]%n" , buffer[0], buffer[1], &bytes_read) == 2) { |
530 | char value[512] = "" ; |
531 | jio_snprintf(value, sizeof(value), "%s.%s" , buffer[0], buffer[1]); |
532 | total_bytes_read += bytes_read; |
533 | add_option_string(matcher, flag, atof(value)); |
534 | return; |
535 | } else { |
536 | jio_snprintf(errorbuf, buf_size, " Value cannot be read for flag %s of type %s" , flag, type); |
537 | } |
538 | } else { |
539 | jio_snprintf(errorbuf, buf_size, " Type %s not supported " , type); |
540 | } |
541 | } else { |
542 | jio_snprintf(errorbuf, buf_size, " Flag name for type %s should be alphanumeric " , type); |
543 | } |
544 | return; |
545 | } |
546 | |
547 | int skip_whitespace(char* line) { |
548 | // Skip any leading spaces |
549 | int whitespace_read = 0; |
550 | sscanf(line, "%*[ \t]%n" , &whitespace_read); |
551 | return whitespace_read; |
552 | } |
553 | |
554 | void CompilerOracle::print_parse_error(const char*& error_msg, char* original_line) { |
555 | assert(error_msg != NULL, "Must have error_message" ); |
556 | |
557 | ttyLocker ttyl; |
558 | tty->print_cr("CompileCommand: An error occurred during parsing" ); |
559 | tty->print_cr("Line: %s" , original_line); |
560 | tty->print_cr("Error: %s" , error_msg); |
561 | CompilerOracle::print_tip(); |
562 | } |
563 | |
564 | void CompilerOracle::parse_from_line(char* line) { |
565 | if (line[0] == '\0') return; |
566 | if (line[0] == '#') return; |
567 | |
568 | char* original_line = line; |
569 | int bytes_read; |
570 | OracleCommand command = parse_command_name(line, &bytes_read); |
571 | line += bytes_read; |
572 | ResourceMark rm; |
573 | |
574 | if (command == UnknownCommand) { |
575 | ttyLocker ttyl; |
576 | tty->print_cr("CompileCommand: unrecognized command" ); |
577 | tty->print_cr(" \"%s\"" , original_line); |
578 | CompilerOracle::print_tip(); |
579 | return; |
580 | } |
581 | |
582 | if (command == QuietCommand) { |
583 | _quiet = true; |
584 | return; |
585 | } |
586 | |
587 | if (command == HelpCommand) { |
588 | usage(); |
589 | return; |
590 | } |
591 | |
592 | const char* error_msg = NULL; |
593 | if (command == OptionCommand) { |
594 | // Look for trailing options. |
595 | // |
596 | // Two types of trailing options are |
597 | // supported: |
598 | // |
599 | // (1) CompileCommand=option,Klass::method,flag |
600 | // (2) CompileCommand=option,Klass::method,type,flag,value |
601 | // |
602 | // Type (1) is used to enable a boolean flag for a method. |
603 | // |
604 | // Type (2) is used to support options with a value. Values can have the |
605 | // the following types: intx, uintx, bool, ccstr, ccstrlist, and double. |
606 | // |
607 | // For future extensions: extend scan_flag_and_value() |
608 | |
609 | char option[256]; // stores flag for Type (1) and type of Type (2) |
610 | line++; // skip the ',' |
611 | TypedMethodOptionMatcher* archetype = TypedMethodOptionMatcher::parse_method_pattern(line, error_msg); |
612 | if (archetype == NULL) { |
613 | assert(error_msg != NULL, "Must have error_message" ); |
614 | print_parse_error(error_msg, original_line); |
615 | return; |
616 | } |
617 | |
618 | line += skip_whitespace(line); |
619 | |
620 | // This is unnecessarily complex. Should retire multi-option lines and skip while loop |
621 | while (sscanf(line, "%255[a-zA-Z0-9]%n" , option, &bytes_read) == 1) { |
622 | line += bytes_read; |
623 | |
624 | // typed_matcher is used as a blueprint for each option, deleted at the end |
625 | TypedMethodOptionMatcher* typed_matcher = archetype->clone(); |
626 | if (strcmp(option, "intx" ) == 0 |
627 | || strcmp(option, "uintx" ) == 0 |
628 | || strcmp(option, "bool" ) == 0 |
629 | || strcmp(option, "ccstr" ) == 0 |
630 | || strcmp(option, "ccstrlist" ) == 0 |
631 | || strcmp(option, "double" ) == 0 |
632 | ) { |
633 | char errorbuf[1024] = {0}; |
634 | // Type (2) option: parse flag name and value. |
635 | scan_flag_and_value(option, line, bytes_read, typed_matcher, errorbuf, sizeof(errorbuf)); |
636 | if (*errorbuf != '\0') { |
637 | error_msg = errorbuf; |
638 | print_parse_error(error_msg, original_line); |
639 | return; |
640 | } |
641 | line += bytes_read; |
642 | } else { |
643 | // Type (1) option |
644 | add_option_string(typed_matcher, option, true); |
645 | } |
646 | if (typed_matcher != NULL && !_quiet) { |
647 | // Print out the last match added |
648 | assert(error_msg == NULL, "No error here" ); |
649 | ttyLocker ttyl; |
650 | tty->print("CompileCommand: %s " , command_names[command]); |
651 | typed_matcher->print(); |
652 | } |
653 | line += skip_whitespace(line); |
654 | } // while( |
655 | delete archetype; |
656 | } else { // not an OptionCommand) |
657 | assert(error_msg == NULL, "Don't call here with error_msg already set" ); |
658 | |
659 | BasicMatcher* matcher = BasicMatcher::parse_method_pattern(line, error_msg); |
660 | if (error_msg != NULL) { |
661 | assert(matcher == NULL, "consistency" ); |
662 | print_parse_error(error_msg, original_line); |
663 | return; |
664 | } |
665 | |
666 | add_predicate(command, matcher); |
667 | if (!_quiet) { |
668 | ttyLocker ttyl; |
669 | tty->print("CompileCommand: %s " , command_names[command]); |
670 | matcher->print(tty); |
671 | tty->cr(); |
672 | } |
673 | } |
674 | } |
675 | |
676 | void CompilerOracle::print_tip() { |
677 | tty->cr(); |
678 | tty->print_cr("Usage: '-XX:CompileCommand=command,\"package/Class.method()\"'" ); |
679 | tty->print_cr("Use: '-XX:CompileCommand=help' for more information." ); |
680 | tty->cr(); |
681 | } |
682 | |
683 | static const char* default_cc_file = ".hotspot_compiler" ; |
684 | |
685 | static const char* cc_file() { |
686 | #ifdef ASSERT |
687 | if (CompileCommandFile == NULL) |
688 | return default_cc_file; |
689 | #endif |
690 | return CompileCommandFile; |
691 | } |
692 | |
693 | bool CompilerOracle::has_command_file() { |
694 | return cc_file() != NULL; |
695 | } |
696 | |
697 | bool CompilerOracle::_quiet = false; |
698 | |
699 | void CompilerOracle::parse_from_file() { |
700 | assert(has_command_file(), "command file must be specified" ); |
701 | FILE* stream = fopen(cc_file(), "rt" ); |
702 | if (stream == NULL) return; |
703 | |
704 | char token[1024]; |
705 | int pos = 0; |
706 | int c = getc(stream); |
707 | while(c != EOF && pos < (int)(sizeof(token)-1)) { |
708 | if (c == '\n') { |
709 | token[pos++] = '\0'; |
710 | parse_from_line(token); |
711 | pos = 0; |
712 | } else { |
713 | token[pos++] = c; |
714 | } |
715 | c = getc(stream); |
716 | } |
717 | token[pos++] = '\0'; |
718 | parse_from_line(token); |
719 | |
720 | fclose(stream); |
721 | } |
722 | |
723 | void CompilerOracle::parse_from_string(const char* str, void (*parse_line)(char*)) { |
724 | char token[1024]; |
725 | int pos = 0; |
726 | const char* sp = str; |
727 | int c = *sp++; |
728 | while (c != '\0' && pos < (int)(sizeof(token)-1)) { |
729 | if (c == '\n') { |
730 | token[pos++] = '\0'; |
731 | parse_line(token); |
732 | pos = 0; |
733 | } else { |
734 | token[pos++] = c; |
735 | } |
736 | c = *sp++; |
737 | } |
738 | token[pos++] = '\0'; |
739 | parse_line(token); |
740 | } |
741 | |
742 | void compilerOracle_init() { |
743 | CompilerOracle::parse_from_string(CompileCommand, CompilerOracle::parse_from_line); |
744 | CompilerOracle::parse_from_string(CompileOnly, CompilerOracle::parse_compile_only); |
745 | if (CompilerOracle::has_command_file()) { |
746 | CompilerOracle::parse_from_file(); |
747 | } else { |
748 | struct stat buf; |
749 | if (os::stat(default_cc_file, &buf) == 0) { |
750 | warning("%s file is present but has been ignored. " |
751 | "Run with -XX:CompileCommandFile=%s to load the file." , |
752 | default_cc_file, default_cc_file); |
753 | } |
754 | } |
755 | if (lists[PrintCommand] != NULL) { |
756 | if (PrintAssembly) { |
757 | warning("CompileCommand and/or %s file contains 'print' commands, but PrintAssembly is also enabled" , default_cc_file); |
758 | } else if (FLAG_IS_DEFAULT(DebugNonSafepoints)) { |
759 | warning("printing of assembly code is enabled; turning on DebugNonSafepoints to gain additional output" ); |
760 | DebugNonSafepoints = true; |
761 | } |
762 | } |
763 | } |
764 | |
765 | |
766 | void CompilerOracle::parse_compile_only(char * line) { |
767 | int i; |
768 | char name[1024]; |
769 | const char* className = NULL; |
770 | const char* methodName = NULL; |
771 | |
772 | bool have_colon = (strstr(line, "::" ) != NULL); |
773 | char method_sep = have_colon ? ':' : '.'; |
774 | |
775 | if (Verbose) { |
776 | tty->print_cr("%s" , line); |
777 | } |
778 | |
779 | ResourceMark rm; |
780 | while (*line != '\0') { |
781 | MethodMatcher::Mode c_match = MethodMatcher::Exact; |
782 | MethodMatcher::Mode m_match = MethodMatcher::Exact; |
783 | |
784 | for (i = 0; |
785 | i < 1024 && *line != '\0' && *line != method_sep && *line != ',' && !isspace(*line); |
786 | line++, i++) { |
787 | name[i] = *line; |
788 | if (name[i] == '.') name[i] = '/'; // package prefix uses '/' |
789 | } |
790 | |
791 | if (i > 0) { |
792 | char* newName = NEW_RESOURCE_ARRAY( char, i + 1); |
793 | if (newName == NULL) |
794 | return; |
795 | strncpy(newName, name, i); |
796 | newName[i] = '\0'; |
797 | |
798 | if (className == NULL) { |
799 | className = newName; |
800 | } else { |
801 | methodName = newName; |
802 | } |
803 | } |
804 | |
805 | if (*line == method_sep) { |
806 | if (className == NULL) { |
807 | className = "" ; |
808 | c_match = MethodMatcher::Any; |
809 | } |
810 | } else { |
811 | // got foo or foo/bar |
812 | if (className == NULL) { |
813 | ShouldNotReachHere(); |
814 | } else { |
815 | // missing class name handled as "Any" class match |
816 | if (className[0] == '\0') { |
817 | c_match = MethodMatcher::Any; |
818 | } |
819 | } |
820 | } |
821 | |
822 | // each directive is terminated by , or NUL or . followed by NUL |
823 | if (*line == ',' || *line == '\0' || (line[0] == '.' && line[1] == '\0')) { |
824 | if (methodName == NULL) { |
825 | methodName = "" ; |
826 | if (*line != method_sep) { |
827 | m_match = MethodMatcher::Any; |
828 | } |
829 | } |
830 | |
831 | EXCEPTION_MARK; |
832 | Symbol* c_name = SymbolTable::new_symbol(className); |
833 | Symbol* m_name = SymbolTable::new_symbol(methodName); |
834 | Symbol* signature = NULL; |
835 | |
836 | BasicMatcher* bm = new BasicMatcher(); |
837 | bm->init(c_name, c_match, m_name, m_match, signature); |
838 | add_predicate(CompileOnlyCommand, bm); |
839 | if (PrintVMOptions) { |
840 | tty->print("CompileOnly: compileonly " ); |
841 | lists[CompileOnlyCommand]->print_all(tty); |
842 | } |
843 | |
844 | className = NULL; |
845 | methodName = NULL; |
846 | } |
847 | |
848 | line = *line == '\0' ? line : line + 1; |
849 | } |
850 | } |
851 | |