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, FakeObjArray, 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 address* buffered_field_addr(int field_offset) {
556 return (address*)(buffered_addr() + field_offset);
557 }
558
559 public:
560 RequestedMetadataAddr metadata_field(int field_offset) {
561 return RequestedMetadataAddr(*(address*)(buffered_field_addr(field_offset)));
562 }
563
564 address buffered_addr() {
565 return _data._buffered_addr;
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 FakeObjArray as_obj_array();
578 FakeString as_string();
579 FakeTypeArray as_type_array();
580
581 RequestedMetadataAddr klass() {
582 address rk = (address)real_klass();
583 if (_is_runtime_logging) {
584 return RequestedMetadataAddr(rk - _requested_to_mapped_metadata_delta);
585 } else {
586 ArchiveBuilder* builder = ArchiveBuilder::current();
587 return builder->to_requested(builder->get_buffered_addr(rk));
588 }
589 }
590
591 Klass* real_klass() {
592 return _data._klass;
593 }
594
595 // in heap words
596 size_t size() {
597 return _data._size;
613 return _data._target_location;
614 }
615
616 address requested_addr() {
617 return _data._requested_addr;
618 }
619
620 uint32_t as_narrow_oop_value() {
621 precond(UseCompressedOops);
622 return _data._narrow_location;
623 }
624
625 FakeOop read_oop_at(narrowOop* addr) { // +UseCompressedOops
626 return FakeOop(_iter, _iter->obj_at(addr));
627 }
628
629 FakeOop read_oop_at(oop* addr) { // -UseCompressedOops
630 return FakeOop(_iter, _iter->obj_at(addr));
631 }
632
633 FakeOop obj_field(int field_offset) {
634 if (UseCompressedOops) {
635 return read_oop_at(raw_oop()->field_addr<narrowOop>(field_offset));
636 } else {
637 return read_oop_at(raw_oop()->field_addr<oop>(field_offset));
638 }
639 }
640
641 void print_non_oop_field(outputStream* st, fieldDescriptor* fd) {
642 // fd->print_on_for() works for non-oop fields in fake oops
643 precond(fd->field_type() != T_ARRAY && fd->field_type() != T_OBJECT);
644 fd->print_on_for(st, raw_oop());
645 }
646 }; // AOTMapLogger::FakeOop
647
648 class AOTMapLogger::FakeMirror : public AOTMapLogger::FakeOop {
649 public:
650 FakeMirror(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
651
652 void print_class_signature_on(outputStream* st);
653
654 Klass* real_mirrored_klass() {
655 RequestedMetadataAddr mirrored_klass = metadata_field(java_lang_Class::klass_offset());
656 return mirrored_klass.to_real_klass();
657 }
658
659 int static_oop_field_count() {
660 return java_lang_Class::static_oop_field_count(raw_oop());
661 }
662 }; // AOTMapLogger::FakeMirror
663
664 class AOTMapLogger::FakeObjArray : public AOTMapLogger::FakeOop {
665 objArrayOop raw_objArrayOop() {
666 return (objArrayOop)raw_oop();
667 }
668
669 public:
670 FakeObjArray(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
671
672 int length() {
673 return raw_objArrayOop()->length();
674 }
675 FakeOop obj_at(int i) {
676 if (UseCompressedOops) {
677 return read_oop_at(raw_objArrayOop()->obj_at_addr<narrowOop>(i));
678 } else {
679 return read_oop_at(raw_objArrayOop()->obj_at_addr<oop>(i));
680 }
681 }
682 }; // AOTMapLogger::FakeObjArray
683
684 class AOTMapLogger::FakeString : public AOTMapLogger::FakeOop {
685 public:
686 FakeString(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
687
688 bool is_latin1() {
689 jbyte coder = raw_oop()->byte_field(java_lang_String::coder_offset());
690 assert(CompactStrings || coder == java_lang_String::CODER_UTF16, "Must be UTF16 without CompactStrings");
691 return coder == java_lang_String::CODER_LATIN1;
692 }
693
694 FakeTypeArray value();
695
696 int length();
697 void print_on(outputStream* st, int max_length = MaxStringPrintSize);
698 }; // AOTMapLogger::FakeString
699
700 class AOTMapLogger::FakeTypeArray : public AOTMapLogger::FakeOop {
701 typeArrayOop raw_typeArrayOop() {
702 return (typeArrayOop)raw_oop();
703 }
704
705 public:
706 FakeTypeArray(OopDataIterator* iter, OopData data) : FakeOop(iter, data) {}
707
708 void print_elements_on(outputStream* st) {
709 TypeArrayKlass::cast(real_klass())->oop_print_elements_on(raw_typeArrayOop(), st);
710 }
711
712 int length() { return raw_typeArrayOop()->length(); }
713 jbyte byte_at(int i) { return raw_typeArrayOop()->byte_at(i); }
714 jchar char_at(int i) { return raw_typeArrayOop()->char_at(i); }
715 }; // AOTMapLogger::FakeTypeArray
716
717 AOTMapLogger::FakeMirror AOTMapLogger::FakeOop::as_mirror() {
718 precond(real_klass() == vmClasses::Class_klass());
719 return FakeMirror(_iter, _data);
720 }
721
722 AOTMapLogger::FakeObjArray AOTMapLogger::FakeOop::as_obj_array() {
723 precond(real_klass()->is_objArray_klass());
724 return FakeObjArray(_iter, _data);
725 }
726
727 AOTMapLogger::FakeTypeArray AOTMapLogger::FakeOop::as_type_array() {
728 precond(real_klass()->is_typeArray_klass());
729 return FakeTypeArray(_iter, _data);
730 }
731
732 AOTMapLogger::FakeString AOTMapLogger::FakeOop::as_string() {
733 precond(real_klass() == vmClasses::String_klass());
734 return FakeString(_iter, _data);
735 }
736
737 void AOTMapLogger::FakeMirror::print_class_signature_on(outputStream* st) {
738 ResourceMark rm;
739 RequestedMetadataAddr requested_klass = metadata_field(java_lang_Class::klass_offset());
740 Klass* real_klass = requested_klass.to_real_klass();
741
742 if (real_klass == nullptr) {
743 // This is a primitive mirror (Java expressions of int.class, long.class, void.class, etc);
744 RequestedMetadataAddr requested_array_klass = metadata_field(java_lang_Class::array_klass_offset());
795 abridge = false; // only do this once
796 }
797 jchar c = (!is_latin1) ? v.char_at(index) :
798 ((jchar) v.byte_at(index)) & 0xff;
799 if (c < ' ') {
800 st->print("\\x%02X", c); // print control characters e.g. \x0A
801 } else {
802 st->print("%c", c);
803 }
804 }
805 st->print("\"");
806
807 if (length > max_length) {
808 st->print(" (abridged) ");
809 }
810 }
811
812 class AOTMapLogger::ArchivedFieldPrinter : public FieldClosure {
813 FakeOop _fake_oop;
814 outputStream* _st;
815 public:
816 ArchivedFieldPrinter(FakeOop fake_oop, outputStream* st) : _fake_oop(fake_oop), _st(st) {}
817
818 void do_field(fieldDescriptor* fd) {
819 _st->print(" - ");
820 BasicType ft = fd->field_type();
821 switch (ft) {
822 case T_ARRAY:
823 case T_OBJECT:
824 {
825 fd->print_on(_st); // print just the name and offset
826 FakeOop field_value = _fake_oop.obj_field(fd->offset());
827 print_oop_info_cr(_st, field_value);
828 }
829 break;
830 default:
831 _fake_oop.print_non_oop_field(_st, fd); // name, offset, value
832 _st->cr();
833 }
834 }
835 }; // AOTMapLogger::ArchivedFieldPrinter
836
837 void AOTMapLogger::dumptime_log_mapped_heap_region(AOTMappedHeapInfo* heap_info) {
838 MemRegion r = heap_info->buffer_region();
839 address buffer_start = address(r.start()); // start of the current oop inside the buffer
840 address buffer_end = address(r.end());
841
842 address requested_base = UseCompressedOops ? AOTMappedHeapWriter::narrow_oop_base() : (address)AOTMappedHeapWriter::NOCOOPS_REQUESTED_BASE;
843 address requested_start = UseCompressedOops ? AOTMappedHeapWriter::buffered_addr_to_requested_addr(buffer_start) : requested_base;
844
845 log_region_range("heap", buffer_start, buffer_end, requested_start);
846 log_archived_objects(AOTMappedHeapWriter::oop_iterator(heap_info));
847 }
848
849 void AOTMapLogger::dumptime_log_streamed_heap_region(AOTStreamedHeapInfo* heap_info) {
850 MemRegion r = heap_info->buffer_region();
851 address buffer_start = address(r.start()); // start of the current oop inside the buffer
949 } else if (real_klass == vmClasses::Class_klass()) {
950 fake_oop.as_mirror().print_class_signature_on(st);
951 }
952
953 st->cr();
954 }
955 }
956 }
957
958 // Print the fields of instanceOops, or the elements of arrayOops
959 void AOTMapLogger::print_oop_details(FakeOop fake_oop, outputStream* st) {
960 Klass* real_klass = fake_oop.real_klass();
961
962 st->print(" - klass: ");
963 real_klass->print_value_on(st);
964 st->print(" " PTR_FORMAT, p2i(fake_oop.klass().raw_addr()));
965 st->cr();
966
967 if (real_klass->is_typeArray_klass()) {
968 fake_oop.as_type_array().print_elements_on(st);
969 } else if (real_klass->is_objArray_klass()) {
970 FakeObjArray fake_obj_array = fake_oop.as_obj_array();
971 bool is_logging_root_segment = fake_oop.is_root_segment();
972
973 for (int i = 0; i < fake_obj_array.length(); i++) {
974 FakeOop elm = fake_obj_array.obj_at(i);
975 if (is_logging_root_segment) {
976 st->print(" root[%4d]: ", _roots->length());
977 _roots->append(elm);
978 } else {
979 st->print(" -%4d: ", i);
980 }
981 print_oop_info_cr(st, elm);
982 }
983 } else {
984 st->print_cr(" - fields (%zu words):", fake_oop.size());
985
986 ArchivedFieldPrinter print_field(fake_oop, st);
987 InstanceKlass::cast(real_klass)->print_nonstatic_fields(&print_field);
988
989 if (real_klass == vmClasses::Class_klass()) {
990 FakeMirror fake_mirror = fake_oop.as_mirror();
|
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;
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());
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
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();
|