Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/hotspot/share/compiler/compilerOracle.cpp
40930 views
1
/*
2
* Copyright (c) 1998, 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 "classfile/symbolTable.hpp"
28
#include "compiler/compilerDirectives.hpp"
29
#include "compiler/compilerOracle.hpp"
30
#include "compiler/methodMatcher.hpp"
31
#include "memory/allocation.inline.hpp"
32
#include "memory/oopFactory.hpp"
33
#include "memory/resourceArea.hpp"
34
#include "oops/klass.hpp"
35
#include "oops/method.inline.hpp"
36
#include "oops/symbol.hpp"
37
#include "runtime/globals_extension.hpp"
38
#include "runtime/handles.inline.hpp"
39
#include "runtime/jniHandles.hpp"
40
#include "runtime/os.hpp"
41
42
static const char* optiontype_names[] = {
43
#define enum_of_types(type, name) name,
44
OPTION_TYPES(enum_of_types)
45
#undef enum_of_types
46
};
47
48
const char* optiontype2name(enum OptionType type) {
49
return optiontype_names[static_cast<int>(type)];
50
}
51
52
static enum OptionType option_types[] = {
53
#define enum_of_options(option, name, ctype) OptionType::ctype,
54
COMPILECOMMAND_OPTIONS(enum_of_options)
55
#undef enum_of_options
56
};
57
58
enum OptionType option2type(enum CompileCommand option) {
59
return option_types[static_cast<int>(option)];
60
}
61
62
static const char* option_names[] = {
63
#define enum_of_options(option, name, ctype) name,
64
COMPILECOMMAND_OPTIONS(enum_of_options)
65
#undef enum_of_options
66
};
67
68
const char* option2name(enum CompileCommand option) {
69
return option_names[static_cast<int>(option)];
70
}
71
72
/* Methods to map real type names to OptionType */
73
template<typename T>
74
static OptionType get_type_for() {
75
return OptionType::Unknown;
76
};
77
78
template<> OptionType get_type_for<intx>() {
79
return OptionType::Intx;
80
}
81
82
template<> OptionType get_type_for<uintx>() {
83
return OptionType::Uintx;
84
}
85
86
template<> OptionType get_type_for<bool>() {
87
return OptionType::Bool;
88
}
89
90
template<> OptionType get_type_for<ccstr>() {
91
return OptionType::Ccstr;
92
}
93
94
template<> OptionType get_type_for<double>() {
95
return OptionType::Double;
96
}
97
98
class MethodMatcher;
99
class TypedMethodOptionMatcher;
100
101
static TypedMethodOptionMatcher* option_list = NULL;
102
static bool any_set = false;
103
104
// A filter for quick lookup if an option is set
105
static bool option_filter[static_cast<int>(CompileCommand::Unknown) + 1] = { 0 };
106
107
void command_set_in_filter(enum CompileCommand option) {
108
assert(option != CompileCommand::Unknown, "sanity");
109
assert(option2type(option) != OptionType::Unknown, "sanity");
110
111
if ((option != CompileCommand::DontInline) &&
112
(option != CompileCommand::Inline) &&
113
(option != CompileCommand::Log)) {
114
any_set = true;
115
}
116
option_filter[static_cast<int>(option)] = true;
117
}
118
119
bool has_command(enum CompileCommand option) {
120
return option_filter[static_cast<int>(option)];
121
}
122
123
class TypedMethodOptionMatcher : public MethodMatcher {
124
private:
125
TypedMethodOptionMatcher* _next;
126
enum CompileCommand _option;
127
public:
128
129
union {
130
bool bool_value;
131
intx intx_value;
132
uintx uintx_value;
133
double double_value;
134
ccstr ccstr_value;
135
} _u;
136
137
TypedMethodOptionMatcher() : MethodMatcher(),
138
_next(NULL),
139
_option(CompileCommand::Unknown) {
140
memset(&_u, 0, sizeof(_u));
141
}
142
143
~TypedMethodOptionMatcher();
144
static TypedMethodOptionMatcher* parse_method_pattern(char*& line, char* errorbuf, const int buf_size);
145
TypedMethodOptionMatcher* match(const methodHandle &method, enum CompileCommand option);
146
147
void init(enum CompileCommand option, TypedMethodOptionMatcher* next) {
148
_next = next;
149
_option = option;
150
}
151
152
void init_matcher(Symbol* class_name, Mode class_mode,
153
Symbol* method_name, Mode method_mode,
154
Symbol* signature) {
155
MethodMatcher::init(class_name, class_mode, method_name, method_mode, signature);
156
}
157
158
void set_next(TypedMethodOptionMatcher* next) {_next = next; }
159
TypedMethodOptionMatcher* next() { return _next; }
160
enum CompileCommand option() { return _option; }
161
template<typename T> T value();
162
template<typename T> void set_value(T value);
163
void print();
164
void print_all();
165
TypedMethodOptionMatcher* clone();
166
};
167
168
// A few templated accessors instead of a full template class.
169
template<> intx TypedMethodOptionMatcher::value<intx>() {
170
return _u.intx_value;
171
}
172
173
template<> uintx TypedMethodOptionMatcher::value<uintx>() {
174
return _u.uintx_value;
175
}
176
177
template<> bool TypedMethodOptionMatcher::value<bool>() {
178
return _u.bool_value;
179
}
180
181
template<> double TypedMethodOptionMatcher::value<double>() {
182
return _u.double_value;
183
}
184
185
template<> ccstr TypedMethodOptionMatcher::value<ccstr>() {
186
return _u.ccstr_value;
187
}
188
189
template<> void TypedMethodOptionMatcher::set_value(intx value) {
190
_u.intx_value = value;
191
}
192
193
template<> void TypedMethodOptionMatcher::set_value(uintx value) {
194
_u.uintx_value = value;
195
}
196
197
template<> void TypedMethodOptionMatcher::set_value(double value) {
198
_u.double_value = value;
199
}
200
201
template<> void TypedMethodOptionMatcher::set_value(bool value) {
202
_u.bool_value = value;
203
}
204
205
template<> void TypedMethodOptionMatcher::set_value(ccstr value) {
206
_u.ccstr_value = (const ccstr)os::strdup_check_oom(value);
207
}
208
209
void TypedMethodOptionMatcher::print() {
210
ttyLocker ttyl;
211
print_base(tty);
212
const char* name = option2name(_option);
213
enum OptionType type = option2type(_option);
214
switch (type) {
215
case OptionType::Intx:
216
tty->print_cr(" intx %s = " INTX_FORMAT, name, value<intx>());
217
break;
218
case OptionType::Uintx:
219
tty->print_cr(" uintx %s = " UINTX_FORMAT, name, value<uintx>());
220
break;
221
case OptionType::Bool:
222
tty->print_cr(" bool %s = %s", name, value<bool>() ? "true" : "false");
223
break;
224
case OptionType::Double:
225
tty->print_cr(" double %s = %f", name, value<double>());
226
break;
227
case OptionType::Ccstr:
228
case OptionType::Ccstrlist:
229
tty->print_cr(" const char* %s = '%s'", name, value<ccstr>());
230
break;
231
default:
232
ShouldNotReachHere();
233
}
234
}
235
236
void TypedMethodOptionMatcher::print_all() {
237
print();
238
if (_next != NULL) {
239
tty->print(" ");
240
_next->print_all();
241
}
242
}
243
244
TypedMethodOptionMatcher* TypedMethodOptionMatcher::clone() {
245
TypedMethodOptionMatcher* m = new TypedMethodOptionMatcher();
246
m->_class_mode = _class_mode;
247
m->_class_name = _class_name;
248
m->_method_mode = _method_mode;
249
m->_method_name = _method_name;
250
m->_signature = _signature;
251
// Need to ref count the symbols
252
if (_class_name != NULL) {
253
_class_name->increment_refcount();
254
}
255
if (_method_name != NULL) {
256
_method_name->increment_refcount();
257
}
258
if (_signature != NULL) {
259
_signature->increment_refcount();
260
}
261
return m;
262
}
263
264
TypedMethodOptionMatcher::~TypedMethodOptionMatcher() {
265
enum OptionType type = option2type(_option);
266
if (type == OptionType::Ccstr || type == OptionType::Ccstrlist) {
267
ccstr v = value<ccstr>();
268
os::free((void*)v);
269
}
270
}
271
272
TypedMethodOptionMatcher* TypedMethodOptionMatcher::parse_method_pattern(char*& line, char* errorbuf, const int buf_size) {
273
assert(*errorbuf == '\0', "Dont call here with error_msg already set");
274
const char* error_msg = NULL;
275
TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher();
276
MethodMatcher::parse_method_pattern(line, error_msg, tom);
277
if (error_msg != NULL) {
278
jio_snprintf(errorbuf, buf_size, error_msg);
279
delete tom;
280
return NULL;
281
}
282
return tom;
283
}
284
285
TypedMethodOptionMatcher* TypedMethodOptionMatcher::match(const methodHandle& method, enum CompileCommand option) {
286
TypedMethodOptionMatcher* current = this;
287
while (current != NULL) {
288
if (current->_option == option) {
289
if (current->matches(method)) {
290
return current;
291
}
292
}
293
current = current->next();
294
}
295
return NULL;
296
}
297
298
template<typename T>
299
static void register_command(TypedMethodOptionMatcher* matcher,
300
enum CompileCommand option,
301
T value) {
302
assert(matcher != option_list, "No circular lists please");
303
if (option == CompileCommand::Log && !LogCompilation) {
304
tty->print_cr("Warning: +LogCompilation must be enabled in order for individual methods to be logged with ");
305
tty->print_cr(" CompileCommand=log,<method pattern>");
306
}
307
assert(CompilerOracle::option_matches_type(option, value), "Value must match option type");
308
309
if (option == CompileCommand::Blackhole && !UnlockExperimentalVMOptions) {
310
warning("Blackhole compile option is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions");
311
return;
312
}
313
314
matcher->init(option, option_list);
315
matcher->set_value<T>(value);
316
option_list = matcher;
317
command_set_in_filter(option);
318
319
if (!CompilerOracle::be_quiet()) {
320
// Print out the successful registration of a compile command
321
ttyLocker ttyl;
322
tty->print("CompileCommand: %s ", option2name(option));
323
matcher->print();
324
}
325
return;
326
}
327
328
template<typename T>
329
bool CompilerOracle::has_option_value(const methodHandle& method, enum CompileCommand option, T& value) {
330
assert(option_matches_type(option, value), "Value must match option type");
331
if (!has_command(option)) {
332
return false;
333
}
334
if (option_list != NULL) {
335
TypedMethodOptionMatcher* m = option_list->match(method, option);
336
if (m != NULL) {
337
value = m->value<T>();
338
return true;
339
}
340
}
341
return false;
342
}
343
344
static bool check_predicate(enum CompileCommand option, const methodHandle& method) {
345
bool value = false;
346
if (CompilerOracle::has_option_value(method, option, value)) {
347
return value;
348
}
349
return false;
350
}
351
352
bool CompilerOracle::has_any_command_set() {
353
return any_set;
354
}
355
356
// Explicit instantiation for all OptionTypes supported.
357
template bool CompilerOracle::has_option_value<intx>(const methodHandle& method, enum CompileCommand option, intx& value);
358
template bool CompilerOracle::has_option_value<uintx>(const methodHandle& method, enum CompileCommand option, uintx& value);
359
template bool CompilerOracle::has_option_value<bool>(const methodHandle& method, enum CompileCommand option, bool& value);
360
template bool CompilerOracle::has_option_value<ccstr>(const methodHandle& method, enum CompileCommand option, ccstr& value);
361
template bool CompilerOracle::has_option_value<double>(const methodHandle& method, enum CompileCommand option, double& value);
362
363
template<typename T>
364
bool CompilerOracle::option_matches_type(enum CompileCommand option, T& value) {
365
enum OptionType option_type = option2type(option);
366
if (option_type == OptionType::Unknown) {
367
return false; // Can't query options with type Unknown.
368
}
369
if (option_type == OptionType::Ccstrlist) {
370
option_type = OptionType::Ccstr; // CCstrList type options are stored as Ccstr
371
}
372
return (get_type_for<T>() == option_type);
373
}
374
375
template bool CompilerOracle::option_matches_type<intx>(enum CompileCommand option, intx& value);
376
template bool CompilerOracle::option_matches_type<uintx>(enum CompileCommand option, uintx& value);
377
template bool CompilerOracle::option_matches_type<bool>(enum CompileCommand option, bool& value);
378
template bool CompilerOracle::option_matches_type<ccstr>(enum CompileCommand option, ccstr& value);
379
template bool CompilerOracle::option_matches_type<double>(enum CompileCommand option, double& value);
380
381
bool CompilerOracle::has_option(const methodHandle& method, enum CompileCommand option) {
382
bool value = false;
383
has_option_value(method, option, value);
384
return value;
385
}
386
387
bool CompilerOracle::should_exclude(const methodHandle& method) {
388
if (check_predicate(CompileCommand::Exclude, method)) {
389
return true;
390
}
391
if (has_command(CompileCommand::CompileOnly)) {
392
return !check_predicate(CompileCommand::CompileOnly, method);
393
}
394
return false;
395
}
396
397
bool CompilerOracle::should_inline(const methodHandle& method) {
398
return (check_predicate(CompileCommand::Inline, method));
399
}
400
401
bool CompilerOracle::should_not_inline(const methodHandle& method) {
402
return check_predicate(CompileCommand::DontInline, method) || check_predicate(CompileCommand::Exclude, method);
403
}
404
405
bool CompilerOracle::should_print(const methodHandle& method) {
406
return check_predicate(CompileCommand::Print, method);
407
}
408
409
bool CompilerOracle::should_print_methods() {
410
return has_command(CompileCommand::Print);
411
}
412
413
bool CompilerOracle::should_log(const methodHandle& method) {
414
if (!LogCompilation) return false;
415
if (!has_command(CompileCommand::Log)) {
416
return true; // by default, log all
417
}
418
return (check_predicate(CompileCommand::Log, method));
419
}
420
421
bool CompilerOracle::should_break_at(const methodHandle& method) {
422
return check_predicate(CompileCommand::Break, method);
423
}
424
425
void CompilerOracle::tag_blackhole_if_possible(const methodHandle& method) {
426
if (!check_predicate(CompileCommand::Blackhole, method)) {
427
return;
428
}
429
guarantee(UnlockExperimentalVMOptions, "Checked during initial parsing");
430
if (method->result_type() != T_VOID) {
431
warning("Blackhole compile option only works for methods with void type: %s",
432
method->name_and_sig_as_C_string());
433
return;
434
}
435
if (!method->is_empty_method()) {
436
warning("Blackhole compile option only works for empty methods: %s",
437
method->name_and_sig_as_C_string());
438
return;
439
}
440
if (!method->is_static()) {
441
warning("Blackhole compile option only works for static methods: %s",
442
method->name_and_sig_as_C_string());
443
return;
444
}
445
if (method->intrinsic_id() == vmIntrinsics::_blackhole) {
446
return;
447
}
448
if (method->intrinsic_id() != vmIntrinsics::_none) {
449
warning("Blackhole compile option only works for methods that do not have intrinsic set: %s, %s",
450
method->name_and_sig_as_C_string(), vmIntrinsics::name_at(method->intrinsic_id()));
451
return;
452
}
453
method->set_intrinsic_id(vmIntrinsics::_blackhole);
454
}
455
456
static enum CompileCommand match_option_name(const char* line, int* bytes_read, char* errorbuf, int bufsize) {
457
assert(ARRAY_SIZE(option_names) == static_cast<int>(CompileCommand::Count), "option_names size mismatch");
458
459
*bytes_read = 0;
460
char option_buf[256];
461
int matches = sscanf(line, "%255[a-zA-Z0-9]%n", option_buf, bytes_read);
462
if (matches > 0 && strcasecmp(option_buf, "unknown") != 0) {
463
for (uint i = 0; i < ARRAY_SIZE(option_names); i++) {
464
if (strcasecmp(option_buf, option_names[i]) == 0) {
465
return static_cast<enum CompileCommand>(i);
466
}
467
}
468
}
469
jio_snprintf(errorbuf, bufsize, "Unrecognized option '%s'", option_buf);
470
return CompileCommand::Unknown;
471
}
472
473
// match exactly and don't mess with errorbuf
474
enum CompileCommand CompilerOracle::parse_option_name(const char* line) {
475
for (uint i = 0; i < ARRAY_SIZE(option_names); i++) {
476
if (strcasecmp(line, option_names[i]) == 0) {
477
return static_cast<enum CompileCommand>(i);
478
}
479
}
480
return CompileCommand::Unknown;
481
}
482
483
enum OptionType CompilerOracle::parse_option_type(const char* type_str) {
484
for (uint i = 0; i < ARRAY_SIZE(optiontype_names); i++) {
485
if (strcasecmp(type_str, optiontype_names[i]) == 0) {
486
return static_cast<enum OptionType>(i);
487
}
488
}
489
return OptionType::Unknown;
490
}
491
492
void print_tip() { // CMH Update info
493
tty->cr();
494
tty->print_cr("Usage: '-XX:CompileCommand=<option>,<method pattern>' - to set boolean option to true");
495
tty->print_cr("Usage: '-XX:CompileCommand=<option>,<method pattern>,<value>'");
496
tty->print_cr("Use: '-XX:CompileCommand=help' for more information and to list all option.");
497
tty->cr();
498
}
499
500
void print_option(enum CompileCommand option, const char* name, enum OptionType type) {
501
if (type != OptionType::Unknown) {
502
tty->print_cr(" %s (%s)", name, optiontype2name(type));
503
}
504
}
505
506
void print_commands() {
507
tty->cr();
508
tty->print_cr("All available options:");
509
#define enum_of_options(option, name, ctype) print_option(CompileCommand::option, name, OptionType::ctype);
510
COMPILECOMMAND_OPTIONS(enum_of_options)
511
#undef enum_of_options
512
tty->cr();
513
}
514
515
static void usage() {
516
tty->cr();
517
tty->print_cr("The CompileCommand option enables the user of the JVM to control specific");
518
tty->print_cr("behavior of the dynamic compilers.");
519
tty->cr();
520
tty->print_cr("Compile commands has this general form:");
521
tty->print_cr("-XX:CompileCommand=<option><method pattern><value>");
522
tty->print_cr(" Sets <option> to the specified value for methods matching <method pattern>");
523
tty->print_cr(" All options are typed");
524
tty->cr();
525
tty->print_cr("-XX:CompileCommand=<option><method pattern>");
526
tty->print_cr(" Sets <option> to true for methods matching <method pattern>");
527
tty->print_cr(" Only applies to boolean options.");
528
tty->cr();
529
tty->print_cr("-XX:CompileCommand=quiet");
530
tty->print_cr(" Silence the compile command output");
531
tty->cr();
532
tty->print_cr("-XX:CompileCommand=help");
533
tty->print_cr(" Prints this help text");
534
tty->cr();
535
print_commands();
536
tty->cr();
537
tty->print_cr("Method patterns has the format:");
538
tty->print_cr(" package/Class.method()");
539
tty->cr();
540
tty->print_cr("For backward compatibility this form is also allowed:");
541
tty->print_cr(" package.Class::method()");
542
tty->cr();
543
tty->print_cr("The signature can be separated by an optional whitespace or comma:");
544
tty->print_cr(" package/Class.method ()");
545
tty->cr();
546
tty->print_cr("The class and method identifier can be used together with leading or");
547
tty->print_cr("trailing *'s for wildcard matching:");
548
tty->print_cr(" *ackage/Clas*.*etho*()");
549
tty->cr();
550
tty->print_cr("It is possible to use more than one CompileCommand on the command line:");
551
tty->print_cr(" -XX:CompileCommand=exclude,java/*.* -XX:CompileCommand=log,java*.*");
552
tty->cr();
553
tty->print_cr("The CompileCommands can be loaded from a file with the flag");
554
tty->print_cr("-XX:CompileCommandFile=<file> or be added to the file '.hotspot_compiler'");
555
tty->print_cr("Use the same format in the file as the argument to the CompileCommand flag.");
556
tty->print_cr("Add one command on each line.");
557
tty->print_cr(" exclude java/*.*");
558
tty->print_cr(" option java/*.* ReplayInline");
559
tty->cr();
560
tty->print_cr("The following commands have conflicting behavior: 'exclude', 'inline', 'dontinline',");
561
tty->print_cr("and 'compileonly'. There is no priority of commands. Applying (a subset of) these");
562
tty->print_cr("commands to the same method results in undefined behavior.");
563
tty->cr();
564
};
565
566
int skip_whitespace(char* &line) {
567
// Skip any leading spaces
568
int whitespace_read = 0;
569
sscanf(line, "%*[ \t]%n", &whitespace_read);
570
line += whitespace_read;
571
return whitespace_read;
572
}
573
574
void skip_comma(char* &line) {
575
// Skip any leading spaces
576
if (*line == ',') {
577
line++;
578
}
579
}
580
581
static void scan_value(enum OptionType type, char* line, int& total_bytes_read,
582
TypedMethodOptionMatcher* matcher, enum CompileCommand option, char* errorbuf, const int buf_size) {
583
int bytes_read = 0;
584
const char* ccname = option2name(option);
585
const char* type_str = optiontype2name(type);
586
int skipped = skip_whitespace(line);
587
total_bytes_read += skipped;
588
if (type == OptionType::Intx) {
589
intx value;
590
if (sscanf(line, "" INTX_FORMAT "%n", &value, &bytes_read) == 1) {
591
total_bytes_read += bytes_read;
592
line += bytes_read;
593
register_command(matcher, option, value);
594
return;
595
} else {
596
jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
597
}
598
} else if (type == OptionType::Uintx) {
599
uintx value;
600
if (sscanf(line, "" UINTX_FORMAT "%n", &value, &bytes_read) == 1) {
601
total_bytes_read += bytes_read;
602
line += bytes_read;
603
register_command(matcher, option, value);
604
return;
605
} else {
606
jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
607
}
608
} else if (type == OptionType::Ccstr) {
609
ResourceMark rm;
610
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
611
if (sscanf(line, "%255[_a-zA-Z0-9]%n", value, &bytes_read) == 1) {
612
total_bytes_read += bytes_read;
613
line += bytes_read;
614
register_command(matcher, option, (ccstr) value);
615
return;
616
} else {
617
jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
618
}
619
} else if (type == OptionType::Ccstrlist) {
620
// Accumulates several strings into one. The internal type is ccstr.
621
ResourceMark rm;
622
char* value = NEW_RESOURCE_ARRAY(char, strlen(line) + 1);
623
char* next_value = value;
624
if (sscanf(line, "%255[_a-zA-Z0-9+\\-]%n", next_value, &bytes_read) == 1) {
625
total_bytes_read += bytes_read;
626
line += bytes_read;
627
next_value += bytes_read + 1;
628
char* end_value = next_value - 1;
629
while (sscanf(line, "%*[ \t]%255[_a-zA-Z0-9+\\-]%n", next_value, &bytes_read) == 1) {
630
total_bytes_read += bytes_read;
631
line += bytes_read;
632
*end_value = ' '; // override '\0'
633
next_value += bytes_read;
634
end_value = next_value-1;
635
}
636
637
if (option == CompileCommand::ControlIntrinsic || option == CompileCommand::DisableIntrinsic) {
638
ControlIntrinsicValidator validator(value, (option == CompileCommand::DisableIntrinsic));
639
640
if (!validator.is_valid()) {
641
jio_snprintf(errorbuf, buf_size, "Unrecognized intrinsic detected in %s: %s", option2name(option), validator.what());
642
}
643
}
644
645
register_command(matcher, option, (ccstr) value);
646
return;
647
} else {
648
jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
649
}
650
} else if (type == OptionType::Bool) {
651
char value[256];
652
if (*line == '\0') {
653
// Short version of a CompileCommand sets a boolean Option to true
654
// -XXCompileCommand=<Option>,<method pattern>
655
register_command(matcher, option, true);
656
return;
657
}
658
if (sscanf(line, "%255[a-zA-Z]%n", value, &bytes_read) == 1) {
659
if (strcasecmp(value, "true") == 0) {
660
total_bytes_read += bytes_read;
661
line += bytes_read;
662
register_command(matcher, option, true);
663
return;
664
} else if (strcasecmp(value, "false") == 0) {
665
total_bytes_read += bytes_read;
666
line += bytes_read;
667
register_command(matcher, option, false);
668
return;
669
} else {
670
jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
671
}
672
} else {
673
jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
674
}
675
} else if (type == OptionType::Double) {
676
char buffer[2][256];
677
// Decimal separator '.' has been replaced with ' ' or '/' earlier,
678
// so read integer and fraction part of double value separately.
679
if (sscanf(line, "%255[0-9]%*[ /\t]%255[0-9]%n", buffer[0], buffer[1], &bytes_read) == 2) {
680
char value[512] = "";
681
jio_snprintf(value, sizeof(value), "%s.%s", buffer[0], buffer[1]);
682
total_bytes_read += bytes_read;
683
line += bytes_read;
684
register_command(matcher, option, atof(value));
685
return;
686
} else {
687
jio_snprintf(errorbuf, buf_size, "Value cannot be read for option '%s' of type '%s'", ccname, type_str);
688
}
689
} else {
690
jio_snprintf(errorbuf, buf_size, "Type '%s' not supported ", type_str);
691
}
692
}
693
694
// Scan next option and value in line, return MethodMatcher object on success, NULL on failure.
695
// On failure, error_msg contains description for the first error.
696
// For future extensions: set error_msg on first error.
697
static void scan_option_and_value(enum OptionType type, char* line, int& total_bytes_read,
698
TypedMethodOptionMatcher* matcher,
699
char* errorbuf, const int buf_size) {
700
total_bytes_read = 0;
701
int bytes_read = 0;
702
char option_buf[256];
703
704
// Read option name.
705
if (sscanf(line, "%*[ \t]%255[a-zA-Z0-9]%n", option_buf, &bytes_read) == 1) {
706
line += bytes_read;
707
total_bytes_read += bytes_read;
708
int bytes_read2 = 0;
709
total_bytes_read += skip_whitespace(line);
710
enum CompileCommand option = match_option_name(option_buf, &bytes_read2, errorbuf, buf_size);
711
if (option == CompileCommand::Unknown) {
712
assert(*errorbuf != '\0', "error must have been set");
713
return;
714
}
715
enum OptionType optiontype = option2type(option);
716
if (option2type(option) != type) {
717
const char* optiontype_name = optiontype2name(optiontype);
718
const char* type_name = optiontype2name(type);
719
jio_snprintf(errorbuf, buf_size, "Option '%s' with type '%s' doesn't match supplied type '%s'", option_buf, optiontype_name, type_name);
720
return;
721
}
722
scan_value(type, line, total_bytes_read, matcher, option, errorbuf, buf_size);
723
} else {
724
const char* type_str = optiontype2name(type);
725
jio_snprintf(errorbuf, buf_size, "Option name for type '%s' should be alphanumeric ", type_str);
726
}
727
return;
728
}
729
730
void CompilerOracle::print_parse_error(char* error_msg, char* original_line) {
731
assert(*error_msg != '\0', "Must have error_message");
732
ttyLocker ttyl;
733
tty->print_cr("CompileCommand: An error occurred during parsing");
734
tty->print_cr("Error: %s", error_msg);
735
tty->print_cr("Line: '%s'", original_line);
736
print_tip();
737
}
738
739
class LineCopy : StackObj {
740
const char* _copy;
741
public:
742
LineCopy(char* line) {
743
_copy = os::strdup(line, mtInternal);
744
}
745
~LineCopy() {
746
os::free((void*)_copy);
747
}
748
char* get() {
749
return (char*)_copy;
750
}
751
};
752
753
void CompilerOracle::parse_from_line(char* line) {
754
if (line[0] == '\0') return;
755
if (line[0] == '#') return;
756
757
LineCopy original(line);
758
int bytes_read;
759
char error_buf[1024] = {0};
760
761
enum CompileCommand option = match_option_name(line, &bytes_read, error_buf, sizeof(error_buf));
762
line += bytes_read;
763
ResourceMark rm;
764
765
if (option == CompileCommand::Unknown) {
766
print_parse_error(error_buf, original.get());
767
return;
768
}
769
770
if (option == CompileCommand::Quiet) {
771
_quiet = true;
772
return;
773
}
774
775
if (option == CompileCommand::Help) {
776
usage();
777
return;
778
}
779
780
if (option == CompileCommand::Option) {
781
// Look for trailing options.
782
//
783
// Two types of trailing options are
784
// supported:
785
//
786
// (1) CompileCommand=option,Klass::method,option
787
// (2) CompileCommand=option,Klass::method,type,option,value
788
//
789
// Type (1) is used to enable a boolean option for a method.
790
//
791
// Type (2) is used to support options with a value. Values can have the
792
// the following types: intx, uintx, bool, ccstr, ccstrlist, and double.
793
794
char option_type[256]; // stores option for Type (1) and type of Type (2)
795
skip_comma(line);
796
TypedMethodOptionMatcher* archetype = TypedMethodOptionMatcher::parse_method_pattern(line, error_buf, sizeof(error_buf));
797
if (archetype == NULL) {
798
print_parse_error(error_buf, original.get());
799
return;
800
}
801
802
skip_whitespace(line);
803
804
// This is unnecessarily complex. Should retire multi-option lines and skip while loop
805
while (sscanf(line, "%255[a-zA-Z0-9]%n", option_type, &bytes_read) == 1) {
806
line += bytes_read;
807
808
// typed_matcher is used as a blueprint for each option, deleted at the end
809
TypedMethodOptionMatcher* typed_matcher = archetype->clone();
810
enum OptionType type = parse_option_type(option_type);
811
if (type != OptionType::Unknown) {
812
// Type (2) option: parse option name and value.
813
scan_option_and_value(type, line, bytes_read, typed_matcher, error_buf, sizeof(error_buf));
814
if (*error_buf != '\0') {
815
print_parse_error(error_buf, original.get());
816
return;
817
}
818
line += bytes_read;
819
} else {
820
// Type (1) option - option_type contains the option name -> bool value = true is implied
821
int bytes_read;
822
enum CompileCommand option = match_option_name(option_type, &bytes_read, error_buf, sizeof(error_buf));
823
if (option == CompileCommand::Unknown) {
824
print_parse_error(error_buf, original.get());
825
return;
826
}
827
if (option2type(option) == OptionType::Bool) {
828
register_command(typed_matcher, option, true);
829
} else {
830
jio_snprintf(error_buf, sizeof(error_buf), " Missing type '%s' before option '%s'",
831
optiontype2name(option2type(option)), option2name(option));
832
print_parse_error(error_buf, original.get());
833
return;
834
}
835
}
836
assert(typed_matcher != NULL, "sanity");
837
assert(*error_buf == '\0', "No error here");
838
skip_whitespace(line);
839
} // while(
840
delete archetype;
841
} else { // not an OptionCommand
842
// Command has the following form:
843
// CompileCommand=<option>,<method pattern><value>
844
// CompileCommand=<option>,<method pattern> (implies option is bool and value is true)
845
assert(*error_buf == '\0', "Don't call here with error_buf already set");
846
enum OptionType type = option2type(option);
847
int bytes_read = 0;
848
skip_comma(line);
849
TypedMethodOptionMatcher* matcher = TypedMethodOptionMatcher::parse_method_pattern(line, error_buf, sizeof(error_buf));
850
if (matcher == NULL) {
851
print_parse_error(error_buf, original.get());
852
return;
853
}
854
skip_whitespace(line);
855
if (*line == '\0') {
856
// if this is a bool option this implies true
857
if (option2type(option) == OptionType::Bool) {
858
register_command(matcher, option, true);
859
return;
860
} else {
861
jio_snprintf(error_buf, sizeof(error_buf), " Option '%s' is not followed by a value", option2name(option));
862
print_parse_error(error_buf, original.get());
863
return;
864
}
865
}
866
scan_value(type, line, bytes_read, matcher, option, error_buf, sizeof(error_buf));
867
if (*error_buf != '\0') {
868
print_parse_error(error_buf, original.get());
869
return;
870
}
871
assert(matcher != NULL, "consistency");
872
}
873
}
874
875
static const char* default_cc_file = ".hotspot_compiler";
876
877
static const char* cc_file() {
878
#ifdef ASSERT
879
if (CompileCommandFile == NULL)
880
return default_cc_file;
881
#endif
882
return CompileCommandFile;
883
}
884
885
bool CompilerOracle::has_command_file() {
886
return cc_file() != NULL;
887
}
888
889
bool CompilerOracle::_quiet = false;
890
891
void CompilerOracle::parse_from_file() {
892
assert(has_command_file(), "command file must be specified");
893
FILE* stream = fopen(cc_file(), "rt");
894
if (stream == NULL) return;
895
896
char token[1024];
897
int pos = 0;
898
int c = getc(stream);
899
while(c != EOF && pos < (int)(sizeof(token)-1)) {
900
if (c == '\n') {
901
token[pos++] = '\0';
902
parse_from_line(token);
903
pos = 0;
904
} else {
905
token[pos++] = c;
906
}
907
c = getc(stream);
908
}
909
token[pos++] = '\0';
910
parse_from_line(token);
911
912
fclose(stream);
913
}
914
915
void CompilerOracle::parse_from_string(const char* str, void (*parse_line)(char*)) {
916
char token[1024];
917
int pos = 0;
918
const char* sp = str;
919
int c = *sp++;
920
while (c != '\0' && pos < (int)(sizeof(token)-1)) {
921
if (c == '\n') {
922
token[pos++] = '\0';
923
parse_line(token);
924
pos = 0;
925
} else {
926
token[pos++] = c;
927
}
928
c = *sp++;
929
}
930
token[pos++] = '\0';
931
parse_line(token);
932
}
933
934
void compilerOracle_init() {
935
CompilerOracle::parse_from_string(CompileCommand, CompilerOracle::parse_from_line);
936
CompilerOracle::parse_from_string(CompileOnly, CompilerOracle::parse_compile_only);
937
if (CompilerOracle::has_command_file()) {
938
CompilerOracle::parse_from_file();
939
} else {
940
struct stat buf;
941
if (os::stat(default_cc_file, &buf) == 0) {
942
warning("%s file is present but has been ignored. "
943
"Run with -XX:CompileCommandFile=%s to load the file.",
944
default_cc_file, default_cc_file);
945
}
946
}
947
if (has_command(CompileCommand::Print)) {
948
if (PrintAssembly) {
949
warning("CompileCommand and/or %s file contains 'print' commands, but PrintAssembly is also enabled", default_cc_file);
950
}
951
}
952
}
953
954
void CompilerOracle::parse_compile_only(char* line) {
955
int i;
956
char name[1024];
957
const char* className = NULL;
958
const char* methodName = NULL;
959
960
bool have_colon = (strstr(line, "::") != NULL);
961
char method_sep = have_colon ? ':' : '.';
962
963
if (Verbose) {
964
tty->print_cr("%s", line);
965
}
966
967
ResourceMark rm;
968
while (*line != '\0') {
969
MethodMatcher::Mode c_match = MethodMatcher::Exact;
970
MethodMatcher::Mode m_match = MethodMatcher::Exact;
971
972
for (i = 0;
973
i < 1024 && *line != '\0' && *line != method_sep && *line != ',' && !isspace(*line);
974
line++, i++) {
975
name[i] = *line;
976
if (name[i] == '.') name[i] = '/'; // package prefix uses '/'
977
}
978
979
if (i > 0) {
980
char* newName = NEW_RESOURCE_ARRAY( char, i + 1);
981
if (newName == NULL)
982
return;
983
strncpy(newName, name, i);
984
newName[i] = '\0';
985
986
if (className == NULL) {
987
className = newName;
988
} else {
989
methodName = newName;
990
}
991
}
992
993
if (*line == method_sep) {
994
if (className == NULL) {
995
className = "";
996
c_match = MethodMatcher::Any;
997
}
998
} else {
999
// got foo or foo/bar
1000
if (className == NULL) {
1001
ShouldNotReachHere();
1002
} else {
1003
// missing class name handled as "Any" class match
1004
if (className[0] == '\0') {
1005
c_match = MethodMatcher::Any;
1006
}
1007
}
1008
}
1009
1010
// each directive is terminated by , or NUL or . followed by NUL
1011
if (*line == ',' || *line == '\0' || (line[0] == '.' && line[1] == '\0')) {
1012
if (methodName == NULL) {
1013
methodName = "";
1014
if (*line != method_sep) {
1015
m_match = MethodMatcher::Any;
1016
}
1017
}
1018
1019
EXCEPTION_MARK;
1020
Symbol* c_name = SymbolTable::new_symbol(className);
1021
Symbol* m_name = SymbolTable::new_symbol(methodName);
1022
Symbol* signature = NULL;
1023
1024
TypedMethodOptionMatcher* tom = new TypedMethodOptionMatcher();
1025
tom->init_matcher(c_name, c_match, m_name, m_match, signature);
1026
register_command(tom, CompileCommand::CompileOnly, true);
1027
if (PrintVMOptions) {
1028
tty->print("CompileOnly: compileonly ");
1029
tom->print();
1030
}
1031
1032
className = NULL;
1033
methodName = NULL;
1034
}
1035
1036
line = *line == '\0' ? line : line + 1;
1037
}
1038
}
1039
1040
enum CompileCommand CompilerOracle::string_to_option(const char* name) {
1041
int bytes_read = 0;
1042
char errorbuf[1024] = {0};
1043
return match_option_name(name, &bytes_read, errorbuf, sizeof(errorbuf));
1044
}
1045
1046