1 /*
2 * Copyright (c) 2025, 2026, 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 "cds/aotMapLogger.hpp"
26 #include "cds/aotMappedHeapLoader.hpp"
27 #include "cds/aotMappedHeapWriter.hpp"
28 #include "cds/aotStreamedHeapLoader.hpp"
29 #include "cds/aotStreamedHeapWriter.hpp"
30 #include "cds/cdsConfig.hpp"
31 #include "cds/filemap.hpp"
32 #include "classfile/moduleEntry.hpp"
33 #include "classfile/packageEntry.hpp"
34 #include "classfile/systemDictionaryShared.hpp"
35 #include "classfile/vmClasses.hpp"
36 #include "logging/log.hpp"
37 #include "logging/logStream.hpp"
38 #include "memory/metaspaceClosure.hpp"
39 #include "memory/resourceArea.hpp"
40 #include "oops/method.hpp"
41 #include "oops/methodCounters.hpp"
42 #include "oops/methodData.hpp"
43 #include "oops/oop.inline.hpp"
44 #include "oops/trainingData.hpp"
45 #include "runtime/fieldDescriptor.inline.hpp"
46 #include "runtime/globals_extension.hpp"
47 #include "utilities/growableArray.hpp"
48
49 bool AOTMapLogger::_is_logging_at_bootstrap;
50 bool AOTMapLogger::_is_runtime_logging;
51 intx AOTMapLogger::_buffer_to_requested_delta;
52 intx AOTMapLogger::_requested_to_mapped_metadata_delta;
53 GrowableArrayCHeap<AOTMapLogger::FakeOop, mtClass>* AOTMapLogger::_roots;
54
55 class AOTMapLogger::RequestedMetadataAddr {
56 address _raw_addr;
57
58 public:
59 RequestedMetadataAddr(address raw_addr) : _raw_addr(raw_addr) {}
60
61 address raw_addr() const { return _raw_addr; }
62
63 Klass* to_real_klass() const {
64 if (_raw_addr == nullptr) {
65 return nullptr;
66 }
67
68 if (_is_runtime_logging) {
69 return (Klass*)(_raw_addr + _requested_to_mapped_metadata_delta);
70 } else {
71 ArchiveBuilder* builder = ArchiveBuilder::current();
72 address buffered_addr = builder->requested_to_buffered(_raw_addr);
73 address klass = builder->get_source_addr(buffered_addr);
74 return (Klass*)klass;
75 }
76 }
77 }; // AOTMapLogger::RequestedMetadataAddr
78
79 void AOTMapLogger::ergo_initialize() {
80 if (!CDSConfig::is_dumping_archive() && CDSConfig::is_using_archive() && log_is_enabled(Info, aot, map)) {
81 _is_logging_at_bootstrap = true;
82 if (FLAG_IS_DEFAULT(ArchiveRelocationMode)) {
83 FLAG_SET_ERGO(ArchiveRelocationMode, 0);
84 } else if (ArchiveRelocationMode != 0) {
85 log_warning(aot, map)("Addresses in the AOT map may be incorrect for -XX:ArchiveRelocationMode=%d.", ArchiveRelocationMode);
86 }
87 }
88 }
89
90 void AOTMapLogger::dumptime_log(ArchiveBuilder* builder, FileMapInfo* mapinfo,
91 AOTMappedHeapInfo* mapped_heap_info, AOTStreamedHeapInfo* streamed_heap_info,
92 char* bitmap, size_t bitmap_size_in_bytes) {
93 _is_runtime_logging = false;
94 _buffer_to_requested_delta = ArchiveBuilder::current()->buffer_to_requested_delta();
95
96 log_file_header(mapinfo);
97
98 DumpRegion* rw_region = &builder->_rw_region;
99 DumpRegion* ro_region = &builder->_ro_region;
100
101 dumptime_log_metaspace_region("rw region", rw_region, &builder->_rw_src_objs);
102 dumptime_log_metaspace_region("ro region", ro_region, &builder->_ro_src_objs);
103
104 address bitmap_end = address(bitmap + bitmap_size_in_bytes);
105 log_region_range("bitmap", address(bitmap), bitmap_end, nullptr);
106 log_as_hex((address)bitmap, bitmap_end, nullptr);
107
108 #if INCLUDE_CDS_JAVA_HEAP
109 if (mapped_heap_info != nullptr && mapped_heap_info->is_used()) {
110 dumptime_log_mapped_heap_region(mapped_heap_info);
111 }
112 if (streamed_heap_info != nullptr && streamed_heap_info->is_used()) {
113 dumptime_log_streamed_heap_region(streamed_heap_info);
114 }
115 #endif
116
117 log_info(aot, map)("[End of AOT cache map]");
118 }
119
120 // This class is used to find the location and type of all the
121 // archived metaspace objects.
122 class AOTMapLogger::RuntimeGatherArchivedMetaspaceObjs : public UniqueMetaspaceClosure {
123 GrowableArrayCHeap<ArchivedObjInfo, mtClass> _objs;
124
125 static int compare_objs_by_addr(ArchivedObjInfo* a, ArchivedObjInfo* b) {
126 intx diff = a->_src_addr - b->_src_addr;
127 if (diff < 0) {
128 return -1;
129 } else if (diff == 0) {
130 return 0;
131 } else {
132 return 1;
133 }
134 }
135
136 public:
137 GrowableArrayCHeap<ArchivedObjInfo, mtClass>* objs() { return &_objs; }
138
139 virtual bool do_unique_ref(Ref* ref, bool read_only) {
140 ArchivedObjInfo info;
141 if (AOTMetaspace::in_aot_cache(ref->obj())) {
142 info._src_addr = ref->obj();
143 info._buffered_addr = ref->obj();
144 info._requested_addr = ref->obj();
145 info._bytes = ref->size() * BytesPerWord;
146 info._type = ref->type();
147 _objs.append(info);
148 }
149
150 return true; // keep iterating
151 }
152
153 void finish() {
154 UniqueMetaspaceClosure::finish();
155 _objs.sort(compare_objs_by_addr);
156 }
157 }; // AOTMapLogger::RuntimeGatherArchivedMetaspaceObjs
158
159 void AOTMapLogger::runtime_log(FileMapInfo* static_mapinfo, FileMapInfo* dynamic_mapinfo) {
160 _is_runtime_logging = true;
161 _requested_to_mapped_metadata_delta = static_mapinfo->relocation_delta();
162
163 ResourceMark rm;
164 RuntimeGatherArchivedMetaspaceObjs gatherer;
165
166 if (log_is_enabled(Debug, aot, map)) {
167 // The metaspace objects in the AOT cache are stored as a stream of bytes. For space
168 // saving, we don't store a complete index that tells us where one object ends and
169 // another object starts. There's also no type information.
170 //
171 // However, we can rebuild our index by iterating over all the objects using
172 // MetaspaceClosure, starting from the dictionary of Klasses in SystemDictionaryShared.
173 GrowableArray<Klass*> klasses;
174 SystemDictionaryShared::get_all_archived_classes(/*is_static*/true, &klasses);
175 if (dynamic_mapinfo != nullptr) {
176 SystemDictionaryShared::get_all_archived_classes(/*is_static*/false, &klasses);
177 }
178
179 for (int i = 0; i < klasses.length(); i++) {
180 gatherer.push(klasses.adr_at(i));
181 }
182 gatherer.finish();
183 }
184
185 runtime_log(static_mapinfo, gatherer.objs());
186 if (dynamic_mapinfo != nullptr) {
187 runtime_log(dynamic_mapinfo, gatherer.objs());
188 }
189 }
190
191 void AOTMapLogger::runtime_log(FileMapInfo* mapinfo, GrowableArrayCHeap<ArchivedObjInfo, mtClass>* objs) {
192 log_file_header(mapinfo);
193
194 runtime_log_metaspace_regions(mapinfo, objs);
195
196 #if INCLUDE_CDS_JAVA_HEAP
197 if (mapinfo->has_heap_region() && CDSConfig::is_loading_heap()) {
198 runtime_log_heap_region(mapinfo);
199 }
200 #endif
201
202 log_info(aot, map)("[End of map]");
203 }
204
205 void AOTMapLogger::dumptime_log_metaspace_region(const char* name, DumpRegion* region,
206 const ArchiveBuilder::SourceObjList* src_objs) {
207 address region_base = address(region->base());
208 address region_top = address(region->top());
209 log_region_range(name, region_base, region_top, region_base + _buffer_to_requested_delta);
210 if (log_is_enabled(Debug, aot, map)) {
211 GrowableArrayCHeap<ArchivedObjInfo, mtClass> objs;
212 for (int i = 0; i < src_objs->objs()->length(); i++) {
213 ArchiveBuilder::SourceObjInfo* src_info = src_objs->at(i);
214 ArchivedObjInfo info;
215 info._src_addr = src_info->source_addr();
216 info._buffered_addr = src_info->buffered_addr();
217 info._requested_addr = info._buffered_addr + _buffer_to_requested_delta;
218 info._bytes = src_info->size_in_bytes();
219 info._type = src_info->type();
220 objs.append(info);
221 }
222
223 log_metaspace_objects_impl(address(region->base()), address(region->end()), &objs, 0, objs.length());
224 }
225 }
226
227 void AOTMapLogger::runtime_log_metaspace_regions(FileMapInfo* mapinfo, GrowableArrayCHeap<ArchivedObjInfo, mtClass>* objs) {
228 FileMapRegion* rw = mapinfo->region_at(AOTMetaspace::rw);
229 FileMapRegion* ro = mapinfo->region_at(AOTMetaspace::ro);
230
231 address rw_base = address(rw->mapped_base());
232 address rw_end = address(rw->mapped_end());
233 address ro_base = address(ro->mapped_base());
234 address ro_end = address(ro->mapped_end());
235
236 int first_rw_index = -1;
237 int first_ro_index = -1;
238 int last_ro_index = -1;
239
240 if (log_is_enabled(Debug, aot, map)) {
241 int i = 0;
242 for (; i < objs->length(); i++) {
243 address p = objs->at(i)._src_addr;
244 if (p < rw_base) {
245 // We are printing the dynamic archive but found an object in the static archive
246 precond(!mapinfo->is_static());
247 continue;
248 }
249 if (first_rw_index < 0) {
250 first_rw_index = i;
251 continue;
252 }
253 if (p < ro_base) {
254 continue;
255 }
256 if (first_ro_index < 0) {
257 first_ro_index = i;
258 continue;
259 }
260 if (p < ro_end) {
261 continue;
262 } else {
263 last_ro_index = i;
264 break;
265 }
266 }
267 }
268
269 if (last_ro_index < 0) {
270 last_ro_index = objs->length();
271 }
272
273 log_region_range("rw", rw_base, rw_end, rw_base - _requested_to_mapped_metadata_delta);
274 if (log_is_enabled(Debug, aot, map)) {
275 log_metaspace_objects_impl(rw_base, rw_end, objs, first_rw_index, first_ro_index);
276 }
277
278 log_region_range("ro", ro_base, ro_end, ro_base - _requested_to_mapped_metadata_delta);
279 if (log_is_enabled(Debug, aot, map)) {
280 log_metaspace_objects_impl(ro_base, ro_end, objs, first_ro_index, last_ro_index);
281 }
282 }
283
284 void AOTMapLogger::log_file_header(FileMapInfo* mapinfo) {
285 const char* type;
286 if (mapinfo->is_static()) {
287 if (CDSConfig::new_aot_flags_used()) {
288 type = "AOT cache";
289 } else {
290 type = "Static CDS archive";
291 }
292 } else {
293 type = "Dynamic CDS archive";
294 }
295
296 log_info(aot, map)("%s map for %s", type, mapinfo->full_path());
297
298 address header = address(mapinfo->header());
299 address header_end = header + mapinfo->header()->header_size();
300
301 log_region_range("header", header, header_end, nullptr);
302 LogStreamHandle(Info, aot, map) lsh;
303 mapinfo->print(&lsh);
304 log_as_hex(header, header_end, nullptr);
305 }
306
307 // Log information about a region, whose address at dump time is [base .. top). At
308 // runtime, this region will be mapped to requested_base. requested_base is nullptr if this
309 // region will be mapped at os-selected addresses (such as the bitmap region), or will
310 // be accessed with os::read (the header).
311 void AOTMapLogger::log_region_range(const char* name, address base, address top, address requested_base) {
312 size_t size = top - base;
313 base = requested_base;
314 if (requested_base == nullptr) {
315 top = (address)size;
316 } else {
317 top = requested_base + size;
318 }
319 log_info(aot, map)("[%-18s " PTR_FORMAT " - " PTR_FORMAT " %9zu bytes]",
320 name, p2i(base), p2i(top), size);
321 }
322
323 #define _LOG_PREFIX PTR_FORMAT ": @@ %-17s %d"
324
325 void AOTMapLogger::log_metaspace_objects_impl(address region_base, address region_end, GrowableArrayCHeap<ArchivedObjInfo, mtClass>* objs,
326 int start_idx, int end_idx) {
327 address last_obj_base = region_base;
328 address last_obj_end = region_base;
329 Thread* current = Thread::current();
330
331 for (int i = start_idx; i < end_idx; i++) {
332 ArchivedObjInfo& info = objs->at(i);
333 address src = info._src_addr;
334 address buffered_addr = info._buffered_addr;
335 address requested_addr = info._requested_addr;
336 int bytes = info._bytes;
337 MetaspaceClosureType type = info._type;
338 const char* type_name = MetaspaceClosure::type_name(type);
339
340 log_as_hex(last_obj_base, buffered_addr, last_obj_base + _buffer_to_requested_delta);
341
342 switch (type) {
343 case MetaspaceClosureType::ClassType:
344 log_klass((Klass*)src, requested_addr, type_name, bytes, current);
345 break;
346 case MetaspaceClosureType::ConstantPoolType:
347 log_constant_pool((ConstantPool*)src, requested_addr, type_name, bytes, current);
348 break;
349 case MetaspaceClosureType::ConstantPoolCacheType:
350 log_constant_pool_cache((ConstantPoolCache*)src, requested_addr, type_name, bytes, current);
351 break;
352 case MetaspaceClosureType::ConstMethodType:
353 log_const_method((ConstMethod*)src, requested_addr, type_name, bytes, current);
354 break;
355 case MetaspaceClosureType::MethodType:
356 log_method((Method*)src, requested_addr, type_name, bytes, current);
357 break;
358 case MetaspaceClosureType::MethodCountersType:
359 log_method_counters((MethodCounters*)src, requested_addr, type_name, bytes, current);
360 break;
361 case MetaspaceClosureType::MethodDataType:
362 log_method_data((MethodData*)src, requested_addr, type_name, bytes, current);
363 break;
364 case MetaspaceClosureType::ModuleEntryType:
365 log_module_entry((ModuleEntry*)src, requested_addr, type_name, bytes, current);
366 break;
367 case MetaspaceClosureType::PackageEntryType:
368 log_package_entry((PackageEntry*)src, requested_addr, type_name, bytes, current);
369 break;
370 case MetaspaceClosureType::GrowableArrayType:
371 log_growable_array((GrowableArrayBase*)src, requested_addr, type_name, bytes, current);
372 break;
373 case MetaspaceClosureType::SymbolType:
374 log_symbol((Symbol*)src, requested_addr, type_name, bytes, current);
375 break;
376 case MetaspaceClosureType::KlassTrainingDataType:
377 log_klass_training_data((KlassTrainingData*)src, requested_addr, type_name, bytes, current);
378 break;
379 case MetaspaceClosureType::MethodTrainingDataType:
380 log_method_training_data((MethodTrainingData*)src, requested_addr, type_name, bytes, current);
381 break;
382 case MetaspaceClosureType::CompileTrainingDataType:
383 log_compile_training_data((CompileTrainingData*)src, requested_addr, type_name, bytes, current);
384 break;
385 default:
386 log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
387 break;
388 }
389
390 last_obj_base = buffered_addr;
391 last_obj_end = buffered_addr + bytes;
392 }
393
394 log_as_hex(last_obj_base, last_obj_end, last_obj_base + _buffer_to_requested_delta);
395 if (last_obj_end < region_end) {
396 log_debug(aot, map)(PTR_FORMAT ": @@ Misc data %zu bytes",
397 p2i(last_obj_end + _buffer_to_requested_delta),
398 size_t(region_end - last_obj_end));
399 log_as_hex(last_obj_end, region_end, last_obj_end + _buffer_to_requested_delta);
400 }
401 }
402
403 void AOTMapLogger::log_constant_pool(ConstantPool* cp, address requested_addr,
404 const char* type_name, int bytes, Thread* current) {
405 ResourceMark rm(current);
406 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
407 cp->pool_holder()->external_name());
408 }
409
410 void AOTMapLogger::log_constant_pool_cache(ConstantPoolCache* cpc, address requested_addr,
411 const char* type_name, int bytes, Thread* current) {
412 ResourceMark rm(current);
413 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
414 cpc->constant_pool()->pool_holder()->external_name());
415 }
416
417 void AOTMapLogger::log_const_method(ConstMethod* cm, address requested_addr, const char* type_name,
418 int bytes, Thread* current) {
419 ResourceMark rm(current);
420 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, cm->method()->external_name());
421 }
422
423 void AOTMapLogger::log_method_counters(MethodCounters* mc, address requested_addr, const char* type_name,
424 int bytes, Thread* current) {
425 ResourceMark rm(current);
426 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, mc->method()->external_name());
427 }
428
429 void AOTMapLogger::log_method_data(MethodData* md, address requested_addr, const char* type_name,
430 int bytes, Thread* current) {
431 ResourceMark rm(current);
432 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, md->method()->external_name());
433 }
434
435 void AOTMapLogger::log_module_entry(ModuleEntry* mod, address requested_addr, const char* type_name,
436 int bytes, Thread* current) {
437 ResourceMark rm(current);
438 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
439 mod->name_as_C_string());
440 }
441
442 void AOTMapLogger::log_package_entry(PackageEntry* pkg, address requested_addr, const char* type_name,
443 int bytes, Thread* current) {
444 ResourceMark rm(current);
445 log_debug(aot, map)(_LOG_PREFIX " %s - %s", p2i(requested_addr), type_name, bytes,
446 pkg->module()->name_as_C_string(), pkg->name_as_C_string());
447 }
448
449 void AOTMapLogger::log_growable_array(GrowableArrayBase* arr, address requested_addr, const char* type_name,
450 int bytes, Thread* current) {
451 ResourceMark rm(current);
452 log_debug(aot, map)(_LOG_PREFIX " %d (%d)", p2i(requested_addr), type_name, bytes,
453 arr->length(), arr->capacity());
454 }
455
456 void AOTMapLogger::log_klass(Klass* k, address requested_addr, const char* type_name,
457 int bytes, Thread* current) {
458 ResourceMark rm(current);
459 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, k->external_name());
460 }
461
462 void AOTMapLogger::log_method(Method* m, address requested_addr, const char* type_name,
463 int bytes, Thread* current) {
464 ResourceMark rm(current);
465 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes, m->external_name());
466 }
467
468 void AOTMapLogger::log_symbol(Symbol* s, address requested_addr, const char* type_name,
469 int bytes, Thread* current) {
470 ResourceMark rm(current);
471 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
472 s->as_quoted_ascii());
473 }
474
475 void AOTMapLogger::log_klass_training_data(KlassTrainingData* ktd, address requested_addr, const char* type_name,
476 int bytes, Thread* current) {
477 ResourceMark rm(current);
478 if (ktd->has_holder()) {
479 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
480 ktd->name()->as_klass_external_name());
481 } else {
482 log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
483 }
484 }
485
486 void AOTMapLogger::log_method_training_data(MethodTrainingData* mtd, address requested_addr, const char* type_name,
487 int bytes, Thread* current) {
488 ResourceMark rm(current);
489 if (mtd->has_holder()) {
490 log_debug(aot, map)(_LOG_PREFIX " %s", p2i(requested_addr), type_name, bytes,
491 mtd->holder()->external_name());
492 } else {
493 log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
494 }
495 }
496
497 void AOTMapLogger::log_compile_training_data(CompileTrainingData* ctd, address requested_addr, const char* type_name,
498 int bytes, Thread* current) {
499 ResourceMark rm(current);
500 if (ctd->method() != nullptr && ctd->method()->has_holder()) {
501 log_debug(aot, map)(_LOG_PREFIX " %d %s", p2i(requested_addr), type_name, bytes,
502 ctd->level(), ctd->method()->holder()->external_name());
503 } else {
504 log_debug(aot, map)(_LOG_PREFIX, p2i(requested_addr), type_name, bytes);
505 }
506 }
507 #undef _LOG_PREFIX
508
509 // Log all the data [base...top). Pretend that the base address
510 // will be mapped to requested_base at run-time.
511 void AOTMapLogger::log_as_hex(address base, address top, address requested_base, bool is_heap) {
512 assert(top >= base, "must be");
513
514 LogStreamHandle(Trace, aot, map) lsh;
515 if (lsh.is_enabled()) {
516 int unitsize = sizeof(address);
517 if (is_heap && UseCompressedOops) {
518 // This makes the compressed oop pointers easier to read, but
519 // longs and doubles will be split into two words.
520 unitsize = sizeof(narrowOop);
521 }
522 os::print_hex_dump(&lsh, base, top, unitsize, /* print_ascii=*/true, /* bytes_per_line=*/32, requested_base);
523 }
524 }
525
526 #if INCLUDE_CDS_JAVA_HEAP
527 // FakeOop (and subclasses FakeMirror, FakeString, FakeObjArray, FakeTypeArray) are used to traverse
528 // and print the (image of) heap objects stored in the AOT cache. These objects are different than regular oops:
529 // - They do not reside inside the range of the heap.
530 // - For +UseCompressedOops: pointers may use a different narrowOop encoding: see FakeOop::read_oop_at(narrowOop*)
531 // - For -UseCompressedOops: pointers are not direct: see FakeOop::read_oop_at(oop*)
532 //
533 // Hence, in general, we cannot use regular oop API (such as oopDesc::obj_field()) on these objects. There
534 // are a few rare case where regular oop API work, but these are all guarded with the raw_oop() method and
535 // should be used with care.
536 //
537 // Each AOT heap reader and writer has its own oop_iterator() API that retrieves all the data required to build
538 // fake oops for logging.
539 class AOTMapLogger::FakeOop {
540 OopDataIterator* _iter;
541 OopData _data;
542
543 address* buffered_field_addr(int field_offset) {
544 return (address*)(buffered_addr() + field_offset);
545 }
546
547 public:
548 RequestedMetadataAddr metadata_field(int field_offset) {
549 return RequestedMetadataAddr(*(address*)(buffered_field_addr(field_offset)));
550 }
551
552 address buffered_addr() {
553 return _data._buffered_addr;
554 }
555
556 // Return an "oop" pointer so we can use APIs that accept regular oops. This
557 // must be used with care, as only a limited number of APIs can work with oops that
558 // live outside of the range of the heap.
559 oop raw_oop() { return _data._raw_oop; }
560
561 FakeOop() : _data() {}
562 FakeOop(OopDataIterator* iter, OopData data) : _iter(iter), _data(data) {}
563
564 FakeMirror as_mirror();
565 FakeObjArray as_obj_array();
566 FakeString as_string();
567 FakeTypeArray as_type_array();
568
569 RequestedMetadataAddr klass() {
570 address rk = (address)real_klass();
571 if (_is_runtime_logging) {
572 return RequestedMetadataAddr(rk - _requested_to_mapped_metadata_delta);
573 } else {
574 ArchiveBuilder* builder = ArchiveBuilder::current();
575 return builder->to_requested(builder->get_buffered_addr(rk));
576 }
577 }
578
579 Klass* real_klass() {
580 assert(UseCompressedClassPointers, "heap archiving requires UseCompressedClassPointers");
581 return _data._klass;
582 }
583
584 // in heap words
585 size_t size() {
586 return _data._size;
587 }
588
589 bool is_root_segment() {
590 return _data._is_root_segment;
591 }
592
593 bool is_array() { return real_klass()->is_array_klass(); }
594 bool is_null() { return buffered_addr() == nullptr; }
595
596 int array_length() {
597 precond(is_array());
598 return arrayOop(raw_oop())->length();
599 }
600
601 intptr_t target_location() {
602 return _data._target_location;
603 }
604
605 address requested_addr() {
606 return _data._requested_addr;
607 }
608
609 uint32_t as_narrow_oop_value() {
610 precond(UseCompressedOops);
611 return _data._narrow_location;
612 }
613
614 FakeOop read_oop_at(narrowOop* addr) { // +UseCompressedOops
615 return FakeOop(_iter, _iter->obj_at(addr));
616 }
617
618 FakeOop read_oop_at(oop* addr) { // -UseCompressedOops
619 return FakeOop(_iter, _iter->obj_at(addr));
620 }
621
622 FakeOop obj_field(int field_offset) {
623 if (UseCompressedOops) {
624 return read_oop_at(raw_oop()->field_addr<narrowOop>(field_offset));
625 } else {
626 return read_oop_at(raw_oop()->field_addr<oop>(field_offset));
627 }
628 }
629
630 void print_non_oop_field(outputStream* st, fieldDescriptor* fd) {
631 // fd->print_on_for() works for non-oop fields in fake oops
632 precond(fd->field_type() != T_ARRAY && fd->field_type() != T_OBJECT);
633 fd->print_on_for(st, raw_oop());
634 }
635 }; // AOTMapLogger::FakeOop
636
637 class AOTMapLogger::FakeMirror : public AOTMapLogger::FakeOop {
638 public:
639 FakeMirror(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
640
641 void print_class_signature_on(outputStream* st);
642
643 Klass* real_mirrored_klass() {
644 RequestedMetadataAddr mirrored_klass = metadata_field(java_lang_Class::klass_offset());
645 return mirrored_klass.to_real_klass();
646 }
647
648 int static_oop_field_count() {
649 return java_lang_Class::static_oop_field_count(raw_oop());
650 }
651 }; // AOTMapLogger::FakeMirror
652
653 class AOTMapLogger::FakeObjArray : public AOTMapLogger::FakeOop {
654 objArrayOop raw_objArrayOop() {
655 return (objArrayOop)raw_oop();
656 }
657
658 public:
659 FakeObjArray(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
660
661 int length() {
662 return raw_objArrayOop()->length();
663 }
664 FakeOop obj_at(int i) {
665 if (UseCompressedOops) {
666 return read_oop_at(raw_objArrayOop()->obj_at_addr<narrowOop>(i));
667 } else {
668 return read_oop_at(raw_objArrayOop()->obj_at_addr<oop>(i));
669 }
670 }
671 }; // AOTMapLogger::FakeObjArray
672
673 class AOTMapLogger::FakeString : public AOTMapLogger::FakeOop {
674 public:
675 FakeString(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
676
677 bool is_latin1() {
678 jbyte coder = raw_oop()->byte_field(java_lang_String::coder_offset());
679 assert(CompactStrings || coder == java_lang_String::CODER_UTF16, "Must be UTF16 without CompactStrings");
680 return coder == java_lang_String::CODER_LATIN1;
681 }
682
683 FakeTypeArray value();
684
685 int length();
686 void print_on(outputStream* st, int max_length = MaxStringPrintSize);
687 }; // AOTMapLogger::FakeString
688
689 class AOTMapLogger::FakeTypeArray : public AOTMapLogger::FakeOop {
690 typeArrayOop raw_typeArrayOop() {
691 return (typeArrayOop)raw_oop();
692 }
693
694 public:
695 FakeTypeArray(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
696
697 void print_elements_on(outputStream* st) {
698 TypeArrayKlass::cast(real_klass())->oop_print_elements_on(raw_typeArrayOop(), st);
699 }
700
701 int length() { return raw_typeArrayOop()->length(); }
702 jbyte byte_at(int i) { return raw_typeArrayOop()->byte_at(i); }
703 jchar char_at(int i) { return raw_typeArrayOop()->char_at(i); }
704 }; // AOTMapLogger::FakeTypeArray
705
706 AOTMapLogger::FakeMirror AOTMapLogger::FakeOop::as_mirror() {
707 precond(real_klass() == vmClasses::Class_klass());
708 return FakeMirror(_iter, _data);
709 }
710
711 AOTMapLogger::FakeObjArray AOTMapLogger::FakeOop::as_obj_array() {
712 precond(real_klass()->is_objArray_klass());
713 return FakeObjArray(_iter, _data);
714 }
715
716 AOTMapLogger::FakeTypeArray AOTMapLogger::FakeOop::as_type_array() {
717 precond(real_klass()->is_typeArray_klass());
718 return FakeTypeArray(_iter, _data);
719 }
720
721 AOTMapLogger::FakeString AOTMapLogger::FakeOop::as_string() {
722 precond(real_klass() == vmClasses::String_klass());
723 return FakeString(_iter, _data);
724 }
725
726 void AOTMapLogger::FakeMirror::print_class_signature_on(outputStream* st) {
727 ResourceMark rm;
728 RequestedMetadataAddr requested_klass = metadata_field(java_lang_Class::klass_offset());
729 Klass* real_klass = requested_klass.to_real_klass();
730
731 if (real_klass == nullptr) {
732 // This is a primitive mirror (Java expressions of int.class, long.class, void.class, etc);
733 RequestedMetadataAddr requested_array_klass = metadata_field(java_lang_Class::array_klass_offset());
734 Klass* real_array_klass = requested_array_klass.to_real_klass();
735 if (real_array_klass == nullptr) {
736 st->print(" V"); // The special mirror for void.class that doesn't have any representation in C++
737 } else {
738 precond(real_array_klass->is_typeArray_klass());
739 st->print(" %c", real_array_klass->name()->char_at(1));
740 }
741 } else {
742 const char* class_name = real_klass->name()->as_C_string();
743 if (real_klass->is_instance_klass()) {
744 st->print(" L%s;", class_name);
745 } else {
746 st->print(" %s", class_name);
747 }
748 if (real_klass->has_aot_initialized_mirror()) {
749 st->print(" (aot-inited)");
750 }
751 }
752 }
753
754 AOTMapLogger::FakeTypeArray AOTMapLogger::FakeString::value() {
755 return obj_field(java_lang_String::value_offset()).as_type_array();
756 }
757
758 int AOTMapLogger::FakeString::length() {
759 FakeTypeArray v = value();
760 if (v.is_null()) {
761 return 0;
762 }
763 int arr_length = v.length();
764 if (!is_latin1()) {
765 assert((arr_length & 1) == 0, "should be even for UTF16 string");
766 arr_length >>= 1; // convert number of bytes to number of elements
767 }
768 return arr_length;
769 }
770
771 void AOTMapLogger::FakeString::print_on(outputStream* st, int max_length) {
772 FakeTypeArray v = value();
773 int length = this->length();
774 bool is_latin1 = this->is_latin1();
775 bool abridge = length > max_length;
776
777 st->print("\"");
778 for (int index = 0; index < length; index++) {
779 // If we need to abridge and we've printed half the allowed characters
780 // then jump to the tail of the string.
781 if (abridge && index >= max_length / 2) {
782 st->print(" ... (%d characters ommitted) ... ", length - 2 * (max_length / 2));
783 index = length - (max_length / 2);
784 abridge = false; // only do this once
785 }
786 jchar c = (!is_latin1) ? v.char_at(index) :
787 ((jchar) v.byte_at(index)) & 0xff;
788 if (c < ' ') {
789 st->print("\\x%02X", c); // print control characters e.g. \x0A
790 } else {
791 st->print("%c", c);
792 }
793 }
794 st->print("\"");
795
796 if (length > max_length) {
797 st->print(" (abridged) ");
798 }
799 }
800
801 class AOTMapLogger::ArchivedFieldPrinter : public FieldClosure {
802 FakeOop _fake_oop;
803 outputStream* _st;
804 public:
805 ArchivedFieldPrinter(FakeOop fake_oop, outputStream* st) : _fake_oop(fake_oop), _st(st) {}
806
807 void do_field(fieldDescriptor* fd) {
808 _st->print(" - ");
809 BasicType ft = fd->field_type();
810 switch (ft) {
811 case T_ARRAY:
812 case T_OBJECT:
813 {
814 fd->print_on(_st); // print just the name and offset
815 FakeOop field_value = _fake_oop.obj_field(fd->offset());
816 print_oop_info_cr(_st, field_value);
817 }
818 break;
819 default:
820 _fake_oop.print_non_oop_field(_st, fd); // name, offset, value
821 _st->cr();
822 }
823 }
824 }; // AOTMapLogger::ArchivedFieldPrinter
825
826 void AOTMapLogger::dumptime_log_mapped_heap_region(AOTMappedHeapInfo* heap_info) {
827 MemRegion r = heap_info->buffer_region();
828 address buffer_start = address(r.start()); // start of the current oop inside the buffer
829 address buffer_end = address(r.end());
830
831 address requested_base = UseCompressedOops ? AOTMappedHeapWriter::narrow_oop_base() : (address)AOTMappedHeapWriter::NOCOOPS_REQUESTED_BASE;
832 address requested_start = UseCompressedOops ? AOTMappedHeapWriter::buffered_addr_to_requested_addr(buffer_start) : requested_base;
833
834 log_region_range("heap", buffer_start, buffer_end, requested_start);
835 log_archived_objects(AOTMappedHeapWriter::oop_iterator(heap_info));
836 }
837
838 void AOTMapLogger::dumptime_log_streamed_heap_region(AOTStreamedHeapInfo* heap_info) {
839 MemRegion r = heap_info->buffer_region();
840 address buffer_start = address(r.start()); // start of the current oop inside the buffer
841 address buffer_end = address(r.end());
842
843 log_region_range("heap", buffer_start, buffer_end, nullptr);
844 log_archived_objects(AOTStreamedHeapWriter::oop_iterator(heap_info));
845 }
846
847 void AOTMapLogger::runtime_log_heap_region(FileMapInfo* mapinfo) {
848 ResourceMark rm;
849
850 int heap_region_index = AOTMetaspace::hp;
851 FileMapRegion* r = mapinfo->region_at(heap_region_index);
852 size_t alignment = (size_t)ObjectAlignmentInBytes;
853
854 if (mapinfo->object_streaming_mode()) {
855 address buffer_start = (address)r->mapped_base();
856 address buffer_end = buffer_start + r->used();
857 log_region_range("heap", buffer_start, buffer_end, nullptr);
858 log_archived_objects(AOTStreamedHeapLoader::oop_iterator(mapinfo, buffer_start, buffer_end));
859 } else {
860 // Allocate a buffer and read the image of the archived heap region. This buffer is outside
861 // of the real Java heap, so we must use FakeOop to access the contents of the archived heap objects.
862 char* buffer = resource_allocate_bytes(r->used() + alignment);
863 address buffer_start = (address)align_up(buffer, alignment);
864 address buffer_end = buffer_start + r->used();
865 if (!mapinfo->read_region(heap_region_index, (char*)buffer_start, r->used(), /* do_commit = */ false)) {
866 log_error(aot)("Cannot read heap region; AOT map logging of heap objects failed");
867 return;
868 }
869
870 address requested_base = UseCompressedOops ? (address)mapinfo->narrow_oop_base() : AOTMappedHeapLoader::heap_region_requested_address(mapinfo);
871 address requested_start = requested_base + r->mapping_offset();
872 log_region_range("heap", buffer_start, buffer_end, requested_start);
873 log_archived_objects(AOTMappedHeapLoader::oop_iterator(mapinfo, buffer_start, buffer_end));
874 }
875 }
876
877 void AOTMapLogger::log_archived_objects(OopDataIterator* iter) {
878 LogStreamHandle(Debug, aot, map) st;
879 if (!st.is_enabled()) {
880 return;
881 }
882
883 _roots = new GrowableArrayCHeap<FakeOop, mtClass>();
884
885 // Roots that are not segmented
886 GrowableArrayCHeap<OopData, mtClass>* normal_roots = iter->roots();
887 for (int i = 0; i < normal_roots->length(); ++i) {
888 OopData data = normal_roots->at(i);
889 FakeOop fop(iter, data);
890 _roots->append(fop);
891 st.print(" root[%4d]: ", i);
892 print_oop_info_cr(&st, fop);
893 }
894
895 while (iter->has_next()) {
896 FakeOop fake_oop(iter, iter->next());
897 st.print(PTR_FORMAT ": @@ Object ", fake_oop.target_location());
898 print_oop_info_cr(&st, fake_oop, /*print_location=*/false);
899
900 LogStreamHandle(Trace, aot, map, oops) trace_st;
901 if (trace_st.is_enabled()) {
902 print_oop_details(fake_oop, &trace_st);
903 }
904
905 address fop = fake_oop.buffered_addr();
906 address end_fop = fop + fake_oop.size() * BytesPerWord;
907 log_as_hex(fop, end_fop, fake_oop.requested_addr(), /*is_heap=*/true);
908 }
909
910 delete _roots;
911 delete iter;
912 delete normal_roots;
913 }
914
915 void AOTMapLogger::print_oop_info_cr(outputStream* st, FakeOop fake_oop, bool print_location) {
916 if (fake_oop.is_null()) {
917 st->print_cr("null");
918 } else {
919 ResourceMark rm;
920 Klass* real_klass = fake_oop.real_klass();
921 intptr_t target_location = fake_oop.target_location();
922 if (print_location) {
923 st->print(PTR_FORMAT " ", target_location);
924 }
925 if (UseCompressedOops) {
926 st->print("(0x%08x) ", fake_oop.as_narrow_oop_value());
927 }
928 if (fake_oop.is_array()) {
929 int array_len = fake_oop.array_length();
930 st->print_cr("%s length: %d", real_klass->external_name(), array_len);
931 } else {
932 st->print("%s", real_klass->external_name());
933
934 if (real_klass == vmClasses::String_klass()) {
935 st->print(" ");
936 FakeString fake_str = fake_oop.as_string();
937 fake_str.print_on(st);
938 } else if (real_klass == vmClasses::Class_klass()) {
939 fake_oop.as_mirror().print_class_signature_on(st);
940 }
941
942 st->cr();
943 }
944 }
945 }
946
947 // Print the fields of instanceOops, or the elements of arrayOops
948 void AOTMapLogger::print_oop_details(FakeOop fake_oop, outputStream* st) {
949 Klass* real_klass = fake_oop.real_klass();
950
951 st->print(" - klass: ");
952 real_klass->print_value_on(st);
953 st->print(" " PTR_FORMAT, p2i(fake_oop.klass().raw_addr()));
954 st->cr();
955
956 if (real_klass->is_typeArray_klass()) {
957 fake_oop.as_type_array().print_elements_on(st);
958 } else if (real_klass->is_objArray_klass()) {
959 FakeObjArray fake_obj_array = fake_oop.as_obj_array();
960 bool is_logging_root_segment = fake_oop.is_root_segment();
961
962 for (int i = 0; i < fake_obj_array.length(); i++) {
963 FakeOop elm = fake_obj_array.obj_at(i);
964 if (is_logging_root_segment) {
965 st->print(" root[%4d]: ", _roots->length());
966 _roots->append(elm);
967 } else {
968 st->print(" -%4d: ", i);
969 }
970 print_oop_info_cr(st, elm);
971 }
972 } else {
973 st->print_cr(" - fields (%zu words):", fake_oop.size());
974
975 ArchivedFieldPrinter print_field(fake_oop, st);
976 InstanceKlass::cast(real_klass)->print_nonstatic_fields(&print_field);
977
978 if (real_klass == vmClasses::Class_klass()) {
979 FakeMirror fake_mirror = fake_oop.as_mirror();
980
981 st->print(" - signature: ");
982 fake_mirror.print_class_signature_on(st);
983 st->cr();
984
985 Klass* real_mirrored_klass = fake_mirror.real_mirrored_klass();
986 if (real_mirrored_klass != nullptr && real_mirrored_klass->is_instance_klass()) {
987 InstanceKlass* real_mirrored_ik = InstanceKlass::cast(real_mirrored_klass);
988
989 ConstantPoolCache* cp_cache = real_mirrored_ik->constants()->cache();
990 if (!_is_runtime_logging) {
991 cp_cache = ArchiveBuilder::current()->get_buffered_addr(cp_cache);
992 }
993 int rr_root_index = cp_cache->archived_references_index();
994 st->print(" - resolved_references: ");
995 if (rr_root_index >= 0) {
996 FakeOop resolved_references = _roots->at(rr_root_index);
997 print_oop_info_cr(st, resolved_references);
998 } else {
999 st->print("null");
1000 }
1001
1002 st->print_cr("- ---- static fields (%d):", fake_mirror.static_oop_field_count());
1003 real_mirrored_ik->do_local_static_fields(&print_field);
1004 }
1005 }
1006 }
1007 }
1008 #endif // INCLUDE_CDS_JAVA_HEAP