-
Notifications
You must be signed in to change notification settings - Fork 161
Expand file tree
/
Copy pathcdsConfig.cpp
More file actions
1096 lines (953 loc) · 41.1 KB
/
cdsConfig.cpp
File metadata and controls
1096 lines (953 loc) · 41.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "cds/aotLogging.hpp"
#include "cds/aotMapLogger.hpp"
#include "cds/cdsConfig.hpp"
#include "cds/classListWriter.hpp"
#include "cds/filemap.hpp"
#include "cds/heapShared.inline.hpp"
#include "classfile/classLoaderDataShared.hpp"
#include "classfile/moduleEntry.hpp"
#include "code/aotCodeCache.hpp"
#include "include/jvm_io.h"
#include "logging/log.hpp"
#include "memory/universe.hpp"
#include "prims/jvmtiAgentList.hpp"
#include "runtime/arguments.hpp"
#include "runtime/globals.hpp"
#include "runtime/globals_extension.hpp"
#include "runtime/java.hpp"
#include "runtime/vmThread.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/formatBuffer.hpp"
bool CDSConfig::_is_dumping_static_archive = false;
bool CDSConfig::_is_dumping_preimage_static_archive = false;
bool CDSConfig::_is_dumping_final_static_archive = false;
bool CDSConfig::_is_dumping_dynamic_archive = false;
bool CDSConfig::_is_using_optimized_module_handling = true;
bool CDSConfig::_is_dumping_full_module_graph = true;
bool CDSConfig::_is_using_full_module_graph = true;
bool CDSConfig::_has_aot_linked_classes = false;
bool CDSConfig::_is_single_command_training = false;
bool CDSConfig::_has_temp_aot_config_file = false;
bool CDSConfig::_old_cds_flags_used = false;
bool CDSConfig::_new_aot_flags_used = false;
bool CDSConfig::_disable_heap_dumping = false;
bool CDSConfig::_is_at_aot_safepoint = false;
const char* CDSConfig::_default_archive_path = nullptr;
const char* CDSConfig::_input_static_archive_path = nullptr;
const char* CDSConfig::_input_dynamic_archive_path = nullptr;
const char* CDSConfig::_output_archive_path = nullptr;
JavaThread* CDSConfig::_dumper_thread = nullptr;
int CDSConfig::get_status() {
assert(Universe::is_fully_initialized(), "status is finalized only after Universe is initialized");
return (is_dumping_aot_linked_classes() ? IS_DUMPING_AOT_LINKED_CLASSES : 0) |
(is_dumping_archive() ? IS_DUMPING_ARCHIVE : 0) |
(is_dumping_method_handles() ? IS_DUMPING_METHOD_HANDLES : 0) |
(is_dumping_static_archive() ? IS_DUMPING_STATIC_ARCHIVE : 0) |
(is_logging_lambda_form_invokers() ? IS_LOGGING_LAMBDA_FORM_INVOKERS : 0) |
(is_using_archive() ? IS_USING_ARCHIVE : 0);
}
DEBUG_ONLY(static bool _cds_ergo_initialize_started = false);
void CDSConfig::ergo_initialize() {
DEBUG_ONLY(_cds_ergo_initialize_started = true);
if (is_dumping_static_archive() && !is_dumping_final_static_archive()) {
// Note: -Xshare and -XX:AOTMode flags are mutually exclusive.
// - Classic workflow: -Xshare:on and -Xshare:dump cannot take effect at the same time.
// - JEP 483 workflow: -XX:AOTMode:record and -XX:AOTMode=on cannot take effect at the same time.
// So we can never come to here with RequireSharedSpaces==true.
assert(!RequireSharedSpaces, "sanity");
// If dumping the classic archive, or making an AOT training run (dumping a preimage archive),
// for sanity, parse all classes from classfiles.
// TODO: in the future, if we want to support re-training on top of an existing AOT cache, this
// needs to be changed.
UseSharedSpaces = false;
}
// Initialize shared archive paths which could include both base and dynamic archive paths
// This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly.
if (is_dumping_static_archive() || is_using_archive()) {
if (new_aot_flags_used()) {
ergo_init_aot_paths();
} else {
ergo_init_classic_archive_paths();
}
}
if (!is_dumping_heap()) {
_is_dumping_full_module_graph = false;
}
AOTMapLogger::ergo_initialize();
}
const char* CDSConfig::default_archive_path() {
// The path depends on UseCompressedOops, etc, which are set by GC ergonomics just
// before CDSConfig::ergo_initialize() is called.
assert(_cds_ergo_initialize_started, "sanity");
if (_default_archive_path == nullptr) {
stringStream tmp;
if (is_vm_statically_linked()) {
// It's easier to form the path using JAVA_HOME as os::jvm_path
// gives the path to the launcher executable on static JDK.
const char* subdir = WINDOWS_ONLY("bin") NOT_WINDOWS("lib");
tmp.print("%s%s%s%s%s%sclasses",
Arguments::get_java_home(), os::file_separator(),
subdir, os::file_separator(),
Abstract_VM_Version::vm_variant(), os::file_separator());
} else {
// Assume .jsa is in the same directory where libjvm resides on
// non-static JDK.
char jvm_path[JVM_MAXPATHLEN];
os::jvm_path(jvm_path, sizeof(jvm_path));
char *end = strrchr(jvm_path, *os::file_separator());
if (end != nullptr) *end = '\0';
tmp.print("%s%sclasses", jvm_path, os::file_separator());
}
#ifdef _LP64
if (!UseCompressedOops) {
tmp.print_raw("_nocoops");
}
if (!UseCompactObjectHeaders) {
// Note that generation of xxx_coh.jsa variants require
// --enable-cds-archive-coh at build time
tmp.print_raw("_nocoh");
}
#endif
if (Arguments::is_valhalla_enabled()) {
tmp.print_raw("_preview");
}
tmp.print_raw(".jsa");
_default_archive_path = os::strdup(tmp.base());
}
return _default_archive_path;
}
int CDSConfig::num_archive_paths(const char* path_spec) {
if (path_spec == nullptr) {
return 0;
}
int npaths = 1;
char* p = (char*)path_spec;
while (*p != '\0') {
if (*p == os::path_separator()[0]) {
npaths++;
}
p++;
}
return npaths;
}
void CDSConfig::extract_archive_paths(const char* archive_path,
const char** base_archive_path,
const char** top_archive_path) {
char* begin_ptr = (char*)archive_path;
char* end_ptr = strchr((char*)archive_path, os::path_separator()[0]);
if (end_ptr == nullptr || end_ptr == begin_ptr) {
vm_exit_during_initialization("Base archive was not specified", archive_path);
}
size_t len = end_ptr - begin_ptr;
char* cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
strncpy(cur_path, begin_ptr, len);
cur_path[len] = '\0';
*base_archive_path = cur_path;
begin_ptr = ++end_ptr;
if (*begin_ptr == '\0') {
vm_exit_during_initialization("Top archive was not specified", archive_path);
}
end_ptr = strchr(begin_ptr, '\0');
assert(end_ptr != nullptr, "sanity");
len = end_ptr - begin_ptr;
cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
strncpy(cur_path, begin_ptr, len + 1);
*top_archive_path = cur_path;
}
void CDSConfig::ergo_init_classic_archive_paths() {
assert(_cds_ergo_initialize_started, "sanity");
if (ArchiveClassesAtExit != nullptr) {
assert(!RecordDynamicDumpInfo, "already checked");
if (is_dumping_static_archive()) {
vm_exit_during_initialization("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");
}
check_unsupported_dumping_module_options();
if (os::same_files(default_archive_path(), ArchiveClassesAtExit)) {
vm_exit_during_initialization(
"Cannot specify the default CDS archive for -XX:ArchiveClassesAtExit", default_archive_path());
}
}
if (SharedArchiveFile == nullptr) {
_input_static_archive_path = default_archive_path();
if (is_dumping_static_archive()) {
_output_archive_path = _input_static_archive_path;
}
} else {
int num_archives = num_archive_paths(SharedArchiveFile);
assert(num_archives > 0, "must be");
if (is_dumping_archive() && num_archives > 1) {
vm_exit_during_initialization(
"Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
}
if (is_dumping_static_archive()) {
assert(num_archives == 1, "just checked above");
// Static dump is simple: only one archive is allowed in SharedArchiveFile. This file
// will be overwritten regardless of its contents
_output_archive_path = SharedArchiveFile;
} else {
// SharedArchiveFile may specify one or two files. In case (c), the path for base.jsa
// is read from top.jsa
// (a) 1 file: -XX:SharedArchiveFile=base.jsa
// (b) 2 files: -XX:SharedArchiveFile=base.jsa:top.jsa
// (c) 2 files: -XX:SharedArchiveFile=top.jsa
//
// However, if either RecordDynamicDumpInfo or ArchiveClassesAtExit is used, we do not
// allow cases (b) and (c). Case (b) is already checked above.
if (num_archives > 2) {
vm_exit_during_initialization(
"Cannot have more than 2 archive files specified in the -XX:SharedArchiveFile option");
}
if (num_archives == 1) {
const char* base_archive_path = nullptr;
bool success =
FileMapInfo::get_base_archive_name_from_header(SharedArchiveFile, &base_archive_path);
if (!success) {
// If +AutoCreateSharedArchive and the specified shared archive does not exist,
// regenerate the dynamic archive base on default archive.
if (AutoCreateSharedArchive && !os::file_exists(SharedArchiveFile)) {
enable_dumping_dynamic_archive(SharedArchiveFile);
FLAG_SET_ERGO(ArchiveClassesAtExit, SharedArchiveFile);
_input_static_archive_path = default_archive_path();
FLAG_SET_ERGO(SharedArchiveFile, nullptr);
} else {
if (AutoCreateSharedArchive) {
warning("-XX:+AutoCreateSharedArchive is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info.");
AutoCreateSharedArchive = false;
}
aot_log_error(aot)("Not a valid %s (%s)", type_of_archive_being_loaded(), SharedArchiveFile);
Arguments::no_shared_spaces("invalid archive");
}
} else if (base_archive_path == nullptr) {
// User has specified a single archive, which is a static archive.
_input_static_archive_path = SharedArchiveFile;
} else {
// User has specified a single archive, which is a dynamic archive.
_input_dynamic_archive_path = SharedArchiveFile;
_input_static_archive_path = base_archive_path; // has been c-heap allocated.
}
} else {
extract_archive_paths(SharedArchiveFile,
&_input_static_archive_path, &_input_dynamic_archive_path);
if (_input_static_archive_path == nullptr) {
assert(_input_dynamic_archive_path == nullptr, "must be");
Arguments::no_shared_spaces("invalid archive");
}
}
if (_input_dynamic_archive_path != nullptr) {
// Check for case (c)
if (RecordDynamicDumpInfo) {
vm_exit_during_initialization("-XX:+RecordDynamicDumpInfo is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile",
SharedArchiveFile);
}
if (ArchiveClassesAtExit != nullptr) {
vm_exit_during_initialization("-XX:ArchiveClassesAtExit is unsupported when a dynamic CDS archive is specified in -XX:SharedArchiveFile",
SharedArchiveFile);
}
}
if (ArchiveClassesAtExit != nullptr && os::same_files(SharedArchiveFile, ArchiveClassesAtExit)) {
vm_exit_during_initialization(
"Cannot have the same archive file specified for -XX:SharedArchiveFile and -XX:ArchiveClassesAtExit",
SharedArchiveFile);
}
}
}
}
void CDSConfig::check_internal_module_property(const char* key, const char* value) {
if (Arguments::is_incompatible_cds_internal_module_property(key)) {
stop_using_optimized_module_handling();
aot_log_info(aot)("optimized module handling: disabled due to incompatible property: %s=%s", key, value);
}
}
void CDSConfig::check_incompatible_property(const char* key, const char* value) {
static const char* incompatible_properties[] = {
"java.system.class.loader",
"jdk.module.showModuleResolution",
"jdk.module.validation"
};
for (const char* property : incompatible_properties) {
if (strcmp(key, property) == 0) {
stop_dumping_full_module_graph();
stop_using_full_module_graph();
aot_log_info(aot)("full module graph: disabled due to incompatible property: %s=%s", key, value);
break;
}
}
}
// Returns any JVM command-line option, such as "--patch-module", that's not supported by CDS.
static const char* find_any_unsupported_module_option() {
// Note that arguments.cpp has translated the command-line options into properties. If we find an
// unsupported property, translate it back to its command-line option for better error reporting.
// The following properties are checked by Arguments::is_internal_module_property() and cannot be
// directly specified in the command-line.
static const char* unsupported_module_properties[] = {
"jdk.module.limitmods",
"jdk.module.upgrade.path",
"jdk.module.patch.0"
};
static const char* unsupported_module_options[] = {
"--limit-modules",
"--upgrade-module-path",
"--patch-module"
};
assert(ARRAY_SIZE(unsupported_module_properties) == ARRAY_SIZE(unsupported_module_options), "must be");
SystemProperty* sp = Arguments::system_properties();
while (sp != nullptr) {
for (uint i = 0; i < ARRAY_SIZE(unsupported_module_properties); i++) {
if (strcmp(sp->key(), unsupported_module_properties[i]) == 0) {
return unsupported_module_options[i];
}
}
sp = sp->next();
}
return nullptr; // not found
}
void CDSConfig::check_unsupported_dumping_module_options() {
assert(is_dumping_archive(), "this function is only used with CDS dump time");
const char* option = find_any_unsupported_module_option();
if (option != nullptr) {
vm_exit_during_initialization("Cannot use the following option when dumping the shared archive", option);
}
// Check for an exploded module build in use with -Xshare:dump.
if (!Arguments::has_jimage()) {
vm_exit_during_initialization("Dumping the shared archive is not supported with an exploded module build");
}
}
bool CDSConfig::has_unsupported_runtime_module_options() {
assert(is_using_archive(), "this function is only used with -Xshare:{on,auto}");
if (ArchiveClassesAtExit != nullptr) {
// dynamic dumping, just return false for now.
// check_unsupported_dumping_properties() will be called later to check the same set of
// properties, and will exit the VM with the correct error message if the unsupported properties
// are used.
return false;
}
const char* option = find_any_unsupported_module_option();
if (option != nullptr) {
if (RequireSharedSpaces) {
warning("CDS is disabled when the %s option is specified.", option);
} else {
if (new_aot_flags_used()) {
aot_log_warning(aot)("AOT cache is disabled when the %s option is specified.", option);
} else {
aot_log_info(aot)("CDS is disabled when the %s option is specified.", option);
}
}
return true;
}
return false;
}
#define CHECK_NEW_FLAG(f) check_new_flag(FLAG_IS_DEFAULT(f), #f)
void CDSConfig::check_new_flag(bool new_flag_is_default, const char* new_flag_name) {
if (old_cds_flags_used() && !new_flag_is_default) {
vm_exit_during_initialization(err_msg("Option %s cannot be used at the same time with "
"-Xshare:on, -Xshare:auto, -Xshare:off, -Xshare:dump, "
"DumpLoadedClassList, SharedClassListFile, or SharedArchiveFile",
new_flag_name));
}
}
#define CHECK_SINGLE_PATH(f) check_flag_single_path(#f, f)
void CDSConfig::check_flag_single_path(const char* flag_name, const char* value) {
if (value != nullptr && num_archive_paths(value) != 1) {
vm_exit_during_initialization(err_msg("Option %s must specify a single file name", flag_name));
}
}
void CDSConfig::check_aot_flags() {
if (!FLAG_IS_DEFAULT(DumpLoadedClassList) ||
!FLAG_IS_DEFAULT(SharedClassListFile) ||
!FLAG_IS_DEFAULT(SharedArchiveFile)) {
_old_cds_flags_used = true;
}
// "New" AOT flags must not be mixed with "classic" CDS flags such as -Xshare:dump
CHECK_NEW_FLAG(AOTCache);
CHECK_NEW_FLAG(AOTCacheOutput);
CHECK_NEW_FLAG(AOTConfiguration);
CHECK_NEW_FLAG(AOTMode);
CHECK_SINGLE_PATH(AOTCache);
CHECK_SINGLE_PATH(AOTCacheOutput);
CHECK_SINGLE_PATH(AOTConfiguration);
if (FLAG_IS_DEFAULT(AOTCache) && AOTAdapterCaching) {
log_debug(aot,codecache,init)("AOTCache is not specified - AOTAdapterCaching is ignored");
}
if (FLAG_IS_DEFAULT(AOTCache) && AOTStubCaching) {
log_debug(aot,codecache,init)("AOTCache is not specified - AOTStubCaching is ignored");
}
bool has_cache = !FLAG_IS_DEFAULT(AOTCache);
bool has_cache_output = !FLAG_IS_DEFAULT(AOTCacheOutput);
bool has_config = !FLAG_IS_DEFAULT(AOTConfiguration);
bool has_mode = !FLAG_IS_DEFAULT(AOTMode);
if (!has_cache && !has_cache_output && !has_config && !has_mode) {
// AOT flags are not used. Use classic CDS workflow
return;
}
if (has_cache && has_cache_output) {
vm_exit_during_initialization("Only one of AOTCache or AOTCacheOutput can be specified");
}
if (!has_cache && (!has_mode || strcmp(AOTMode, "auto") == 0)) {
if (has_cache_output) {
// If AOTCacheOutput has been set, effective mode is "record".
// Default value for AOTConfiguration, if necessary, will be assigned in check_aotmode_record().
log_info(aot)("Selected AOTMode=record because AOTCacheOutput is specified");
FLAG_SET_ERGO(AOTMode, "record");
}
}
// At least one AOT flag has been used
_new_aot_flags_used = true;
if (FLAG_IS_DEFAULT(AOTMode) || strcmp(AOTMode, "auto") == 0 || strcmp(AOTMode, "on") == 0) {
check_aotmode_auto_or_on();
} else if (strcmp(AOTMode, "off") == 0) {
check_aotmode_off();
} else if (strcmp(AOTMode, "record") == 0) {
check_aotmode_record();
} else {
assert(strcmp(AOTMode, "create") == 0, "checked by AOTModeConstraintFunc");
check_aotmode_create();
}
}
void CDSConfig::check_aotmode_off() {
UseSharedSpaces = false;
RequireSharedSpaces = false;
}
void CDSConfig::check_aotmode_auto_or_on() {
if (!FLAG_IS_DEFAULT(AOTConfiguration)) {
vm_exit_during_initialization(err_msg("AOTConfiguration can only be used with when AOTMode is record or create (selected AOTMode = %s)",
FLAG_IS_DEFAULT(AOTMode) ? "auto" : AOTMode));
}
UseSharedSpaces = true;
if (FLAG_IS_DEFAULT(AOTMode) || (strcmp(AOTMode, "auto") == 0)) {
RequireSharedSpaces = false;
} else {
assert(strcmp(AOTMode, "on") == 0, "already checked");
RequireSharedSpaces = true;
}
}
// %p substitution in AOTCache, AOTCacheOutput and AOTCacheConfiguration
static void substitute_aot_filename(JVMFlagsEnum flag_enum) {
JVMFlag* flag = JVMFlag::flag_from_enum(flag_enum);
const char* filename = flag->read<const char*>();
assert(filename != nullptr, "must not have default value");
// For simplicity, we don't allow %p/%t to be specified twice, because make_log_name()
// substitutes only the first occurrence. Otherwise, if we run with
// java -XX:AOTCacheOutput=%p%p.aot
// it will end up with both the pid of the training process and the assembly process.
const char* first_p = strstr(filename, "%p");
if (first_p != nullptr && strstr(first_p + 2, "%p") != nullptr) {
vm_exit_during_initialization(err_msg("%s cannot contain more than one %%p", flag->name()));
}
const char* first_t = strstr(filename, "%t");
if (first_t != nullptr && strstr(first_t + 2, "%t") != nullptr) {
vm_exit_during_initialization(err_msg("%s cannot contain more than one %%t", flag->name()));
}
// Note: with single-command training, %p will be the pid of the training process, not the
// assembly process.
const char* new_filename = make_log_name(filename, nullptr);
if (strcmp(filename, new_filename) != 0) {
JVMFlag::Error err = JVMFlagAccess::set_ccstr(flag, &new_filename, JVMFlagOrigin::ERGONOMIC);
assert(err == JVMFlag::SUCCESS, "must never fail");
}
FREE_C_HEAP_ARRAY(char, new_filename);
}
void CDSConfig::check_aotmode_record() {
bool has_config = !FLAG_IS_DEFAULT(AOTConfiguration);
bool has_output = !FLAG_IS_DEFAULT(AOTCacheOutput);
if (!has_output && !has_config) {
vm_exit_during_initialization("At least one of AOTCacheOutput and AOTConfiguration must be specified when using -XX:AOTMode=record");
}
if (has_output) {
_is_single_command_training = true;
substitute_aot_filename(FLAG_MEMBER_ENUM(AOTCacheOutput));
if (!has_config) {
// Too early; can't use resource allocation yet.
size_t len = strlen(AOTCacheOutput) + 10;
char* temp = AllocateHeap(len, mtArguments);
jio_snprintf(temp, len, "%s.config", AOTCacheOutput);
FLAG_SET_ERGO(AOTConfiguration, temp);
FreeHeap(temp);
_has_temp_aot_config_file = true;
}
}
if (!FLAG_IS_DEFAULT(AOTCache)) {
vm_exit_during_initialization("AOTCache must not be specified when using -XX:AOTMode=record");
}
substitute_aot_filename(FLAG_MEMBER_ENUM(AOTConfiguration));
UseSharedSpaces = false;
RequireSharedSpaces = false;
_is_dumping_static_archive = true;
_is_dumping_preimage_static_archive = true;
// At VM exit, the module graph may be contaminated with program states.
// We will rebuild the module graph when dumping the CDS final image.
_is_using_optimized_module_handling = false;
_is_using_full_module_graph = false;
_is_dumping_full_module_graph = false;
}
void CDSConfig::check_aotmode_create() {
if (FLAG_IS_DEFAULT(AOTConfiguration)) {
vm_exit_during_initialization("AOTConfiguration must be specified when using -XX:AOTMode=create");
}
bool has_cache = !FLAG_IS_DEFAULT(AOTCache);
bool has_cache_output = !FLAG_IS_DEFAULT(AOTCacheOutput);
assert(!(has_cache && has_cache_output), "already checked");
if (!has_cache && !has_cache_output) {
vm_exit_during_initialization("AOTCache or AOTCacheOutput must be specified when using -XX:AOTMode=create");
}
if (!has_cache) {
precond(has_cache_output);
FLAG_SET_ERGO(AOTCache, AOTCacheOutput);
}
// No need to check for (!has_cache_output), as we don't look at AOTCacheOutput after here.
substitute_aot_filename(FLAG_MEMBER_ENUM(AOTCache));
_is_dumping_final_static_archive = true;
_is_using_full_module_graph = false;
UseSharedSpaces = true;
RequireSharedSpaces = true;
if (!FileMapInfo::is_preimage_static_archive(AOTConfiguration)) {
vm_exit_during_initialization("Must be a valid AOT configuration generated by the current JVM", AOTConfiguration);
}
CDSConfig::enable_dumping_static_archive();
// We don't load any agents in the assembly phase, so we can ensure that the agents
// cannot affect the contents of the AOT cache. E.g., we don't want the agents to
// redefine any cached classes. We also don't want the agents to modify heap objects that
// are cached.
//
// Since application is not executed in the assembly phase, there's no need to load
// the agents anyway -- no one will notice that the agents are not loaded.
log_info(aot)("Disabled all JVMTI agents during -XX:AOTMode=create");
JvmtiAgentList::disable_agent_list();
}
void CDSConfig::ergo_init_aot_paths() {
assert(_cds_ergo_initialize_started, "sanity");
if (is_dumping_static_archive()) {
if (is_dumping_preimage_static_archive()) {
_output_archive_path = AOTConfiguration;
} else {
assert(is_dumping_final_static_archive(), "must be");
_input_static_archive_path = AOTConfiguration;
_output_archive_path = AOTCache;
}
} else if (is_using_archive()) {
if (FLAG_IS_DEFAULT(AOTCache)) {
// Only -XX:AOTMode={auto,on} is specified
_input_static_archive_path = default_archive_path();
} else {
_input_static_archive_path = AOTCache;
}
}
}
bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) {
assert(!_cds_ergo_initialize_started, "This is called earlier than CDSConfig::ergo_initialize()");
check_aot_flags();
if (!FLAG_IS_DEFAULT(AOTMode)) {
// Using any form of the new AOTMode switch enables enhanced optimizations.
FLAG_SET_ERGO_IF_DEFAULT(AOTClassLinking, true);
}
setup_compiler_args();
if (AOTClassLinking) {
// If AOTClassLinking is specified, enable all AOT optimizations by default.
FLAG_SET_ERGO_IF_DEFAULT(AOTInvokeDynamicLinking, true);
} else {
// AOTInvokeDynamicLinking depends on AOTClassLinking.
FLAG_SET_ERGO(AOTInvokeDynamicLinking, false);
}
if (is_dumping_static_archive()) {
if (is_dumping_preimage_static_archive()) {
// Don't tweak execution mode during AOT training run
} else if (is_dumping_final_static_archive()) {
if (Arguments::mode() == Arguments::_comp) {
// AOT assembly phase submits the non-blocking compilation requests
// for methods collected during training run, then waits for all compilations
// to complete. With -Xcomp, we block for each compilation request, which is
// counter-productive. Switching back to mixed mode improves testing time
// with AOT and -Xcomp.
Arguments::set_mode_flags(Arguments::_mixed);
}
} else if (!mode_flag_cmd_line) {
// By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive.
//
// If your classlist is large and you don't care about deterministic dumping, you can use
// -Xshare:dump -Xmixed to improve dumping speed.
Arguments::set_mode_flags(Arguments::_int);
} else if (Arguments::mode() == Arguments::_comp) {
// -Xcomp may use excessive CPU for the test tiers. Also, -Xshare:dump runs a small and fixed set of
// Java code, so there's not much benefit in running -Xcomp.
aot_log_info(aot)("reduced -Xcomp to -Xmixed for static dumping");
Arguments::set_mode_flags(Arguments::_mixed);
}
// String deduplication may cause CDS to iterate the strings in different order from one
// run to another which resulting in non-determinstic CDS archives.
// Disable UseStringDeduplication while dumping CDS archive.
UseStringDeduplication = false;
}
// RecordDynamicDumpInfo is not compatible with ArchiveClassesAtExit
if (ArchiveClassesAtExit != nullptr && RecordDynamicDumpInfo) {
jio_fprintf(defaultStream::output_stream(),
"-XX:+RecordDynamicDumpInfo cannot be used with -XX:ArchiveClassesAtExit.\n");
return false;
}
if (ArchiveClassesAtExit == nullptr && !RecordDynamicDumpInfo) {
disable_dumping_dynamic_archive();
} else {
enable_dumping_dynamic_archive(ArchiveClassesAtExit);
}
if (AutoCreateSharedArchive) {
if (SharedArchiveFile == nullptr) {
aot_log_warning(aot)("-XX:+AutoCreateSharedArchive requires -XX:SharedArchiveFile");
return false;
}
if (ArchiveClassesAtExit != nullptr) {
aot_log_warning(aot)("-XX:+AutoCreateSharedArchive does not work with ArchiveClassesAtExit");
return false;
}
}
if (is_using_archive() && patch_mod_javabase) {
Arguments::no_shared_spaces("CDS is disabled when " JAVA_BASE_NAME " module is patched.");
}
if (is_using_archive() && has_unsupported_runtime_module_options()) {
UseSharedSpaces = false;
}
if (is_dumping_archive()) {
// Always verify non-system classes during CDS dump
if (!BytecodeVerificationRemote) {
BytecodeVerificationRemote = true;
aot_log_info(aot)("All non-system classes will be verified (-Xverify:remote) during CDS dump time.");
}
}
return true;
}
void CDSConfig::setup_compiler_args() {
// AOT profiles and AOT-compiled code are supported only in the JEP 483 workflow.
bool can_dump_profile_and_compiled_code = AOTClassLinking && new_aot_flags_used();
if (is_dumping_preimage_static_archive() && can_dump_profile_and_compiled_code) {
// JEP 483 workflow -- training
FLAG_SET_ERGO_IF_DEFAULT(AOTRecordTraining, true);
FLAG_SET_ERGO(AOTReplayTraining, false);
AOTCodeCache::disable_caching(); // No AOT code generation during training run
} else if (is_dumping_final_static_archive() && can_dump_profile_and_compiled_code) {
// JEP 483 workflow -- assembly
FLAG_SET_ERGO(AOTRecordTraining, false);
FLAG_SET_ERGO_IF_DEFAULT(AOTReplayTraining, true);
AOTCodeCache::enable_caching(); // Generate AOT code during assembly phase.
disable_dumping_aot_code(); // Don't dump AOT code until metadata and heap are dumped.
} else if (is_using_archive() && new_aot_flags_used()) {
// JEP 483 workflow -- production
FLAG_SET_ERGO(AOTRecordTraining, false);
FLAG_SET_ERGO_IF_DEFAULT(AOTReplayTraining, true);
AOTCodeCache::enable_caching();
} else {
FLAG_SET_ERGO(AOTReplayTraining, false);
FLAG_SET_ERGO(AOTRecordTraining, false);
AOTCodeCache::disable_caching();
}
}
void CDSConfig::prepare_for_dumping() {
assert(CDSConfig::is_dumping_archive(), "sanity");
if (is_dumping_dynamic_archive() && AOTClassLinking) {
if (FLAG_IS_CMDLINE(AOTClassLinking)) {
log_warning(cds)("AOTClassLinking is not supported for dynamic CDS archive");
}
FLAG_SET_ERGO(AOTClassLinking, false);
}
if (is_dumping_dynamic_archive() && !is_using_archive()) {
assert(!is_dumping_static_archive(), "cannot be dumping both static and dynamic archives");
// This could happen if SharedArchiveFile has failed to load:
// - -Xshare:off was specified
// - SharedArchiveFile points to an non-existent file.
// - SharedArchiveFile points to an archive that has failed CRC check
// - SharedArchiveFile is not specified and the VM doesn't have a compatible default archive
#define __THEMSG " is unsupported when base CDS archive is not loaded. Run with -Xlog:cds for more info."
if (RecordDynamicDumpInfo) {
aot_log_error(aot)("-XX:+RecordDynamicDumpInfo%s", __THEMSG);
AOTMetaspace::unrecoverable_loading_error();
} else {
assert(ArchiveClassesAtExit != nullptr, "sanity");
aot_log_warning(aot)("-XX:ArchiveClassesAtExit" __THEMSG);
}
#undef __THEMSG
disable_dumping_dynamic_archive();
return;
}
check_unsupported_dumping_module_options();
}
bool CDSConfig::is_dumping_classic_static_archive() {
return _is_dumping_static_archive &&
!is_dumping_preimage_static_archive() &&
!is_dumping_final_static_archive();
}
bool CDSConfig::is_dumping_preimage_static_archive() {
return _is_dumping_preimage_static_archive;
}
bool CDSConfig::is_dumping_final_static_archive() {
return _is_dumping_final_static_archive;
}
void CDSConfig::enable_dumping_dynamic_archive(const char* output_path) {
_is_dumping_dynamic_archive = true;
if (output_path == nullptr) {
// output_path can be null when the VM is started with -XX:+RecordDynamicDumpInfo
// in anticipation of "jcmd VM.cds dynamic_dump", which will provide the actual
// output path.
_output_archive_path = nullptr;
} else {
_output_archive_path = os::strdup_check_oom(output_path, mtArguments);
}
}
bool CDSConfig::allow_only_single_java_thread() {
// See comments in JVM_StartThread()
return is_dumping_classic_static_archive() || is_dumping_final_static_archive();
}
bool CDSConfig::is_using_archive() {
return UseSharedSpaces;
}
bool CDSConfig::is_using_only_default_archive() {
return is_using_archive() &&
input_static_archive_path() != nullptr &&
default_archive_path() != nullptr &&
strcmp(input_static_archive_path(), default_archive_path()) == 0 &&
input_dynamic_archive_path() == nullptr;
}
bool CDSConfig::is_logging_lambda_form_invokers() {
return ClassListWriter::is_enabled() || is_dumping_dynamic_archive();
}
bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() {
if (is_dumping_final_static_archive()) {
// No need to regenerate -- the lambda form invokers should have been regenerated
// in the preimage archive (if allowed)
return false;
} else if (is_dumping_dynamic_archive() && is_using_aot_linked_classes()) {
// The base archive has aot-linked classes that may have AOT-resolved CP references
// that point to the lambda form invokers in the base archive. Such pointers will
// be invalid if lambda form invokers are regenerated in the dynamic archive.
return false;
} else {
return is_dumping_archive();
}
}
void CDSConfig::stop_using_optimized_module_handling() {
_is_using_optimized_module_handling = false;
_is_dumping_full_module_graph = false; // This requires is_using_optimized_module_handling()
_is_using_full_module_graph = false; // This requires is_using_optimized_module_handling()
}
CDSConfig::DumperThreadMark::DumperThreadMark(JavaThread* current) {
assert(_dumper_thread == nullptr, "sanity");
_dumper_thread = current;
}
CDSConfig::DumperThreadMark::~DumperThreadMark() {
assert(_dumper_thread != nullptr, "sanity");
_dumper_thread = nullptr;
}
bool CDSConfig::current_thread_is_vm_or_dumper() {
Thread* t = Thread::current();
return t->is_VM_thread() || t == _dumper_thread;
}
bool CDSConfig::current_thread_is_dumper() {
return Thread::current() == _dumper_thread;
}
const char* CDSConfig::type_of_archive_being_loaded() {
if (is_dumping_final_static_archive()) {
return "AOT configuration file";
} else if (new_aot_flags_used()) {
return "AOT cache";
} else {
return "shared archive file";
}
}
const char* CDSConfig::type_of_archive_being_written() {
if (is_dumping_preimage_static_archive()) {
return "AOT configuration file";
} else if (new_aot_flags_used()) {
return "AOT cache";
} else {
return "shared archive file";
}
}
// If an incompatible VM options is found, return a text message that explains why
static const char* check_options_incompatible_with_dumping_heap() {
#if INCLUDE_CDS_JAVA_HEAP
if (!UseCompressedClassPointers) {
return "UseCompressedClassPointers must be true";
}
return nullptr;
#else
return "JVM not configured for writing Java heap objects";
#endif
}
void CDSConfig::log_reasons_for_not_dumping_heap() {
const char* reason;
assert(!is_dumping_heap(), "sanity");
if (_disable_heap_dumping) {
reason = "Programmatically disabled";
} else {
reason = check_options_incompatible_with_dumping_heap();
}
assert(reason != nullptr, "sanity");
aot_log_info(aot)("Archived java heap is not supported: %s", reason);
}
// This is *Legacy* optimization for lambdas before JEP 483. May be removed in the future.
bool CDSConfig::is_dumping_lambdas_in_legacy_mode() {
return !is_dumping_method_handles();
}
bool CDSConfig::is_preserving_verification_constraints() {
// Verification dependencies are classes used in assignability checks by the
// bytecode verifier. In the following example, the verification dependencies
// for X are A and B.
//
// class X {
// A getA() { return new B(); }
// }
//
// With the AOT cache, we can ensure that all the verification dependencies
// (A and B in the above example) are unconditionally loaded during the bootstrap
// of the production run. This means that if a class was successfully verified
// in the assembly phase, all of the verifier's assignability checks will remain
// valid in the production run, so we don't need to verify aot-linked classes again.
if (is_dumping_preimage_static_archive()) { // writing AOT config
return AOTClassLinking;
} else if (is_dumping_final_static_archive()) { // writing AOT cache
return is_dumping_aot_linked_classes();
} else if (is_dumping_classic_static_archive()) {
return is_dumping_aot_linked_classes();
} else {
return false;
}
}
bool CDSConfig::is_old_class_for_verifier(const InstanceKlass* ik) {
return ik->major_version() < 50 /*JAVA_6_VERSION*/;
}
#if INCLUDE_CDS_JAVA_HEAP
bool CDSConfig::are_vm_options_incompatible_with_dumping_heap() {
return check_options_incompatible_with_dumping_heap() != nullptr;
}
bool CDSConfig::is_dumping_heap() {
// Note: when dumping preimage static archive, only a very limited set of oops
// are dumped.
if (!is_dumping_static_archive()
|| are_vm_options_incompatible_with_dumping_heap()
|| _disable_heap_dumping) {
return false;
}
return true;
}
bool CDSConfig::is_loading_heap() {
return HeapShared::is_archived_heap_in_use();
}
bool CDSConfig::is_dumping_klass_subgraphs() {
if (is_dumping_classic_static_archive() || is_dumping_final_static_archive()) {
// KlassSubGraphs (see heapShared.cpp) is a legacy mechanism for archiving oops. It
// has been superceded by AOT class linking. This feature is used only when
// AOT class linking is disabled.
//
// KlassSubGraphs are disabled in the preimage static archive, which contains a very
// limited set of oops.
return is_dumping_heap() && !is_dumping_aot_linked_classes();
} else {
return false;
}
}
bool CDSConfig::is_using_klass_subgraphs() {
return (is_loading_heap() &&
!CDSConfig::is_using_aot_linked_classes() &&
!CDSConfig::is_dumping_final_static_archive());
}
bool CDSConfig::is_using_full_module_graph() {
if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
return true;