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