Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/jdk17u
Path: blob/master/src/hotspot/share/cds/dynamicArchive.cpp
64440 views
1
/*
2
* Copyright (c) 2019, 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 "cds/archiveBuilder.hpp"
28
#include "cds/archiveUtils.inline.hpp"
29
#include "cds/dynamicArchive.hpp"
30
#include "cds/lambdaFormInvokers.hpp"
31
#include "cds/metaspaceShared.hpp"
32
#include "classfile/classLoaderData.inline.hpp"
33
#include "classfile/symbolTable.hpp"
34
#include "classfile/systemDictionaryShared.hpp"
35
#include "classfile/vmSymbols.hpp"
36
#include "gc/shared/collectedHeap.hpp"
37
#include "gc/shared/gcVMOperations.hpp"
38
#include "gc/shared/gc_globals.hpp"
39
#include "logging/log.hpp"
40
#include "memory/metaspaceClosure.hpp"
41
#include "memory/resourceArea.hpp"
42
#include "oops/klass.inline.hpp"
43
#include "runtime/arguments.hpp"
44
#include "runtime/os.hpp"
45
#include "runtime/sharedRuntime.hpp"
46
#include "runtime/vmThread.hpp"
47
#include "runtime/vmOperations.hpp"
48
#include "utilities/align.hpp"
49
#include "utilities/bitMap.inline.hpp"
50
51
52
class DynamicArchiveBuilder : public ArchiveBuilder {
53
public:
54
void mark_pointer(address* ptr_loc) {
55
ArchivePtrMarker::mark_pointer(ptr_loc);
56
}
57
58
template <typename T> T get_dumped_addr(T obj) {
59
return (T)ArchiveBuilder::get_dumped_addr((address)obj);
60
}
61
62
static int dynamic_dump_method_comparator(Method* a, Method* b) {
63
Symbol* a_name = a->name();
64
Symbol* b_name = b->name();
65
66
if (a_name == b_name) {
67
return 0;
68
}
69
70
u4 a_offset = ArchiveBuilder::current()->any_to_offset_u4(a_name);
71
u4 b_offset = ArchiveBuilder::current()->any_to_offset_u4(b_name);
72
73
if (a_offset < b_offset) {
74
return -1;
75
} else {
76
assert(a_offset > b_offset, "must be");
77
return 1;
78
}
79
}
80
81
public:
82
DynamicArchiveHeader *_header;
83
84
void init_header();
85
void release_header();
86
void sort_methods();
87
void sort_methods(InstanceKlass* ik) const;
88
void remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const;
89
void write_archive(char* serialized_data);
90
91
public:
92
DynamicArchiveBuilder() : ArchiveBuilder() { }
93
94
// Do this before and after the archive dump to see if any corruption
95
// is caused by dynamic dumping.
96
void verify_universe(const char* info) {
97
if (VerifyBeforeExit) {
98
log_info(cds)("Verify %s", info);
99
// Among other things, this ensures that Eden top is correct.
100
Universe::heap()->prepare_for_verify();
101
Universe::verify(info);
102
}
103
}
104
105
void doit() {
106
SystemDictionaryShared::start_dumping();
107
108
verify_universe("Before CDS dynamic dump");
109
DEBUG_ONLY(SystemDictionaryShared::NoClassLoadingMark nclm);
110
111
// Block concurrent class unloading from changing the _dumptime_table
112
MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
113
SystemDictionaryShared::check_excluded_classes();
114
SystemDictionaryShared::cleanup_lambda_proxy_class_dictionary();
115
116
init_header();
117
gather_source_objs();
118
reserve_buffer();
119
120
log_info(cds, dynamic)("Copying %d klasses and %d symbols",
121
klasses()->length(), symbols()->length());
122
dump_rw_metadata();
123
dump_ro_metadata();
124
relocate_metaspaceobj_embedded_pointers();
125
relocate_roots();
126
127
verify_estimate_size(_estimated_metaspaceobj_bytes, "MetaspaceObjs");
128
129
char* serialized_data;
130
{
131
// Write the symbol table and system dictionaries to the RO space.
132
// Note that these tables still point to the *original* objects, so
133
// they would need to call DynamicArchive::original_to_target() to
134
// get the correct addresses.
135
assert(current_dump_space() == ro_region(), "Must be RO space");
136
SymbolTable::write_to_archive(symbols());
137
138
ArchiveBuilder::OtherROAllocMark mark;
139
SystemDictionaryShared::write_to_archive(false);
140
141
serialized_data = ro_region()->top();
142
WriteClosure wc(ro_region());
143
SymbolTable::serialize_shared_table_header(&wc, false);
144
SystemDictionaryShared::serialize_dictionary_headers(&wc, false);
145
}
146
147
verify_estimate_size(_estimated_hashtable_bytes, "Hashtables");
148
149
sort_methods();
150
151
log_info(cds)("Make classes shareable");
152
make_klasses_shareable();
153
154
log_info(cds)("Adjust lambda proxy class dictionary");
155
SystemDictionaryShared::adjust_lambda_proxy_class_dictionary();
156
157
relocate_to_requested();
158
159
write_archive(serialized_data);
160
release_header();
161
162
assert(_num_dump_regions_used == _total_dump_regions, "must be");
163
verify_universe("After CDS dynamic dump");
164
}
165
166
virtual void iterate_roots(MetaspaceClosure* it, bool is_relocating_pointers) {
167
FileMapInfo::metaspace_pointers_do(it);
168
SystemDictionaryShared::dumptime_classes_do(it);
169
}
170
};
171
172
void DynamicArchiveBuilder::init_header() {
173
FileMapInfo* mapinfo = new FileMapInfo(false);
174
assert(FileMapInfo::dynamic_info() == mapinfo, "must be");
175
_header = mapinfo->dynamic_header();
176
177
FileMapInfo* base_info = FileMapInfo::current_info();
178
_header->set_base_header_crc(base_info->crc());
179
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
180
_header->set_base_region_crc(i, base_info->space_crc(i));
181
}
182
_header->populate(base_info, base_info->core_region_alignment());
183
}
184
185
void DynamicArchiveBuilder::release_header() {
186
// We temporarily allocated a dynamic FileMapInfo for dumping, which makes it appear we
187
// have mapped a dynamic archive, but we actually have not. We are in a safepoint now.
188
// Let's free it so that if class loading happens after we leave the safepoint, nothing
189
// bad will happen.
190
assert(SafepointSynchronize::is_at_safepoint(), "must be");
191
FileMapInfo *mapinfo = FileMapInfo::dynamic_info();
192
assert(mapinfo != NULL && _header == mapinfo->dynamic_header(), "must be");
193
delete mapinfo;
194
assert(!DynamicArchive::is_mapped(), "must be");
195
_header = NULL;
196
}
197
198
void DynamicArchiveBuilder::sort_methods() {
199
InstanceKlass::disable_method_binary_search();
200
for (int i = 0; i < klasses()->length(); i++) {
201
Klass* k = klasses()->at(i);
202
if (k->is_instance_klass()) {
203
sort_methods(InstanceKlass::cast(k));
204
}
205
}
206
}
207
208
// The address order of the copied Symbols may be different than when the original
209
// klasses were created. Re-sort all the tables. See Method::sort_methods().
210
void DynamicArchiveBuilder::sort_methods(InstanceKlass* ik) const {
211
assert(ik != NULL, "DynamicArchiveBuilder currently doesn't support dumping the base archive");
212
if (MetaspaceShared::is_in_shared_metaspace(ik)) {
213
// We have reached a supertype that's already in the base archive
214
return;
215
}
216
217
if (ik->java_mirror() == NULL) {
218
// NULL mirror means this class has already been visited and methods are already sorted
219
return;
220
}
221
ik->remove_java_mirror();
222
223
if (log_is_enabled(Debug, cds, dynamic)) {
224
ResourceMark rm;
225
log_debug(cds, dynamic)("sorting methods for " PTR_FORMAT " (" PTR_FORMAT ") %s",
226
p2i(ik), p2i(to_requested(ik)), ik->external_name());
227
}
228
229
// Method sorting may re-layout the [iv]tables, which would change the offset(s)
230
// of the locations in an InstanceKlass that would contain pointers. Let's clear
231
// all the existing pointer marking bits, and re-mark the pointers after sorting.
232
remark_pointers_for_instance_klass(ik, false);
233
234
// Make sure all supertypes have been sorted
235
sort_methods(ik->java_super());
236
Array<InstanceKlass*>* interfaces = ik->local_interfaces();
237
int len = interfaces->length();
238
for (int i = 0; i < len; i++) {
239
sort_methods(interfaces->at(i));
240
}
241
242
#ifdef ASSERT
243
if (ik->methods() != NULL) {
244
for (int m = 0; m < ik->methods()->length(); m++) {
245
Symbol* name = ik->methods()->at(m)->name();
246
assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
247
}
248
}
249
if (ik->default_methods() != NULL) {
250
for (int m = 0; m < ik->default_methods()->length(); m++) {
251
Symbol* name = ik->default_methods()->at(m)->name();
252
assert(MetaspaceShared::is_in_shared_metaspace(name) || is_in_buffer_space(name), "must be");
253
}
254
}
255
#endif
256
257
Method::sort_methods(ik->methods(), /*set_idnums=*/true, dynamic_dump_method_comparator);
258
if (ik->default_methods() != NULL) {
259
Method::sort_methods(ik->default_methods(), /*set_idnums=*/false, dynamic_dump_method_comparator);
260
}
261
ik->vtable().initialize_vtable();
262
ik->itable().initialize_itable();
263
264
// Set all the pointer marking bits after sorting.
265
remark_pointers_for_instance_klass(ik, true);
266
}
267
268
template<bool should_mark>
269
class PointerRemarker: public MetaspaceClosure {
270
public:
271
virtual bool do_ref(Ref* ref, bool read_only) {
272
if (should_mark) {
273
ArchivePtrMarker::mark_pointer(ref->addr());
274
} else {
275
ArchivePtrMarker::clear_pointer(ref->addr());
276
}
277
return false; // don't recurse
278
}
279
};
280
281
void DynamicArchiveBuilder::remark_pointers_for_instance_klass(InstanceKlass* k, bool should_mark) const {
282
if (should_mark) {
283
PointerRemarker<true> marker;
284
k->metaspace_pointers_do(&marker);
285
marker.finish();
286
} else {
287
PointerRemarker<false> marker;
288
k->metaspace_pointers_do(&marker);
289
marker.finish();
290
}
291
}
292
293
void DynamicArchiveBuilder::write_archive(char* serialized_data) {
294
Array<u8>* table = FileMapInfo::saved_shared_path_table().table();
295
SharedPathTable runtime_table(table, FileMapInfo::shared_path_table().size());
296
_header->set_shared_path_table(runtime_table);
297
_header->set_serialized_data(serialized_data);
298
299
FileMapInfo* dynamic_info = FileMapInfo::dynamic_info();
300
assert(dynamic_info != NULL, "Sanity");
301
302
dynamic_info->open_for_write(Arguments::GetSharedDynamicArchivePath());
303
ArchiveBuilder::write_archive(dynamic_info, NULL, NULL, NULL, NULL);
304
305
address base = _requested_dynamic_archive_bottom;
306
address top = _requested_dynamic_archive_top;
307
size_t file_size = pointer_delta(top, base, sizeof(char));
308
309
log_info(cds, dynamic)("Written dynamic archive " PTR_FORMAT " - " PTR_FORMAT
310
" [" SIZE_FORMAT " bytes header, " SIZE_FORMAT " bytes total]",
311
p2i(base), p2i(top), _header->header_size(), file_size);
312
313
log_info(cds, dynamic)("%d klasses; %d symbols", klasses()->length(), symbols()->length());
314
}
315
316
class VM_PopulateDynamicDumpSharedSpace: public VM_GC_Sync_Operation {
317
DynamicArchiveBuilder builder;
318
public:
319
VM_PopulateDynamicDumpSharedSpace() : VM_GC_Sync_Operation() {}
320
VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
321
void doit() {
322
ResourceMark rm;
323
if (SystemDictionaryShared::empty_dumptime_table()) {
324
log_warning(cds, dynamic)("There is no class to be included in the dynamic archive.");
325
return;
326
}
327
if (AllowArchivingWithJavaAgent) {
328
warning("This archive was created with AllowArchivingWithJavaAgent. It should be used "
329
"for testing purposes only and should not be used in a production environment");
330
}
331
FileMapInfo::check_nonempty_dir_in_shared_path_table();
332
333
builder.doit();
334
}
335
};
336
337
void DynamicArchive::prepare_for_dynamic_dumping_at_exit() {
338
EXCEPTION_MARK;
339
ResourceMark rm(THREAD);
340
MetaspaceShared::link_and_cleanup_shared_classes(THREAD);
341
if (HAS_PENDING_EXCEPTION) {
342
log_error(cds)("ArchiveClassesAtExit has failed");
343
log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
344
java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
345
// We cannot continue to dump the archive anymore.
346
DynamicDumpSharedSpaces = false;
347
CLEAR_PENDING_EXCEPTION;
348
}
349
}
350
351
bool DynamicArchive::_has_been_dumped_once = false;
352
353
void DynamicArchive::dump(const char* archive_name, TRAPS) {
354
assert(UseSharedSpaces && RecordDynamicDumpInfo, "already checked in arguments.cpp?");
355
assert(ArchiveClassesAtExit == nullptr, "already checked in arguments.cpp?");
356
// During dynamic archive dumping, some of the data structures are overwritten so
357
// we cannot dump the dynamic archive again. TODO: this should be fixed.
358
if (has_been_dumped_once()) {
359
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
360
"Dynamic dump has been done, and should only be done once");
361
} else {
362
// prevent multiple dumps.
363
set_has_been_dumped_once();
364
ArchiveClassesAtExit = archive_name;
365
if (Arguments::init_shared_archive_paths()) {
366
dump();
367
} else {
368
ArchiveClassesAtExit = nullptr;
369
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
370
"Could not setup SharedDynamicArchivePath");
371
}
372
// prevent do dynamic dump at exit.
373
ArchiveClassesAtExit = nullptr;
374
if (!Arguments::init_shared_archive_paths()) {
375
THROW_MSG(vmSymbols::java_lang_RuntimeException(),
376
"Could not restore SharedDynamicArchivePath");
377
}
378
}
379
}
380
381
void DynamicArchive::dump() {
382
if (Arguments::GetSharedDynamicArchivePath() == NULL) {
383
log_warning(cds, dynamic)("SharedDynamicArchivePath is not specified");
384
return;
385
}
386
387
VM_PopulateDynamicDumpSharedSpace op;
388
VMThread::execute(&op);
389
}
390
391
bool DynamicArchive::validate(FileMapInfo* dynamic_info) {
392
assert(!dynamic_info->is_static(), "must be");
393
// Check if the recorded base archive matches with the current one
394
FileMapInfo* base_info = FileMapInfo::current_info();
395
DynamicArchiveHeader* dynamic_header = dynamic_info->dynamic_header();
396
397
// Check the header crc
398
if (dynamic_header->base_header_crc() != base_info->crc()) {
399
FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive header checksum verification failed.");
400
return false;
401
}
402
403
// Check each space's crc
404
for (int i = 0; i < MetaspaceShared::n_regions; i++) {
405
if (dynamic_header->base_region_crc(i) != base_info->space_crc(i)) {
406
FileMapInfo::fail_continue("Dynamic archive cannot be used: static archive region #%d checksum verification failed.", i);
407
return false;
408
}
409
}
410
411
return true;
412
}
413
414