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