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