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