diff a/src/hotspot/share/cds/aotMappedHeapWriter.cpp b/src/hotspot/share/cds/aotMappedHeapWriter.cpp
--- a/src/hotspot/share/cds/aotMappedHeapWriter.cpp
+++ b/src/hotspot/share/cds/aotMappedHeapWriter.cpp
@@ -62,21 +62,26 @@
 HeapRootSegments AOTMappedHeapWriter::_heap_root_segments;
 
 address AOTMappedHeapWriter::_requested_bottom;
 address AOTMappedHeapWriter::_requested_top;
 
+static size_t _num_strings = 0;
+static size_t _string_bytes = 0; 
+static size_t _num_packages = 0;
+static size_t _num_protection_domains = 0;
+
 GrowableArrayCHeap<AOTMappedHeapWriter::NativePointerInfo, mtClassShared>* AOTMappedHeapWriter::_native_pointers;
 GrowableArrayCHeap<oop, mtClassShared>* AOTMappedHeapWriter::_source_objs;
 GrowableArrayCHeap<AOTMappedHeapWriter::HeapObjOrder, mtClassShared>* AOTMappedHeapWriter::_source_objs_order;
 
 AOTMappedHeapWriter::BufferOffsetToSourceObjectTable*
 AOTMappedHeapWriter::_buffer_offset_to_source_obj_table = nullptr;
 
 DumpedInternedStrings *AOTMappedHeapWriter::_dumped_interned_strings = nullptr;
 
 typedef HashTable<
-      size_t,    // offset of a filler from ArchiveHeapWriter::buffer_bottom()
+      size_t,    // offset of a filler from AOTMappedHeapWriter::buffer_bottom()
       size_t,    // size of this filler (in bytes)
       127,       // prime number
       AnyObj::C_HEAP,
       mtClassShared> FillersTable;
 static FillersTable* _fillers;
@@ -389,10 +394,12 @@
     oop src_obj = _source_objs->at(src_obj_index);
     HeapShared::CachedOopInfo* info = HeapShared::get_cached_oop_info(src_obj);
     assert(info != nullptr, "must be");
     size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj);
     info->set_buffer_offset(buffer_offset);
+    assert(buffer_offset <= 0x7fffffff, "sanity");
+    HeapShared::add_to_permanent_oop_table(src_obj, (int)buffer_offset);
 
     OopHandle handle(Universe::vm_global(), src_obj);
     _buffer_offset_to_source_obj_table->put_when_absent(buffer_offset, handle);
     _buffer_offset_to_source_obj_table->maybe_grow();
 
@@ -401,10 +408,13 @@
     }
   }
 
   log_info(aot)("Size of heap region = %zu bytes, %d objects, %d roots, %d native ptrs",
                 _buffer_used, _source_objs->length() + 1, roots->length(), _num_native_ptrs);
+  log_info(cds)("   strings            = %8zu (%zu bytes)", _num_strings, _string_bytes);
+  log_info(cds)("   packages           = %8zu", _num_packages);
+  log_info(cds)("   protection domains = %8zu", _num_protection_domains);
 }
 
 size_t AOTMappedHeapWriter::filler_array_byte_size(int length) {
   size_t byte_size = objArrayOopDesc::object_size(length) * HeapWordSize;
   return byte_size;
@@ -489,11 +499,29 @@
 void update_buffered_object_field(address buffered_obj, int field_offset, T value) {
   T* field_addr = cast_to_oop(buffered_obj)->field_addr<T>(field_offset);
   *field_addr = value;
 }
 
+void AOTMappedHeapWriter::update_stats(oop src_obj) {
+  if (java_lang_String::is_instance(src_obj)) {
+    _num_strings ++;
+    _string_bytes += src_obj->size() * HeapWordSize;
+    _string_bytes += java_lang_String::value(src_obj)->size() * HeapWordSize;
+  } else {
+    Klass* k = src_obj->klass();
+    Symbol* name = k->name();
+    if (name->equals("java/lang/NamedPackage") || name->equals("java/lang/Package")) {
+      _num_packages ++;
+    } else if (name->equals("java/security/ProtectionDomain")) {
+      _num_protection_domains ++;
+    }
+  }
+}
+
 size_t AOTMappedHeapWriter::copy_one_source_obj_to_buffer(oop src_obj) {
+  update_stats(src_obj);
+
   assert(!is_too_large_to_archive(src_obj), "already checked");
   size_t byte_size = src_obj->size() * HeapWordSize;
   assert(byte_size > 0, "no zero-size objects");
 
   // For region-based collectors such as G1, the archive heap may be mapped into
@@ -810,10 +838,14 @@
     }
 
     guarantee(ArchiveBuilder::current()->has_been_archived((address)native_ptr),
               "Metadata %p should have been archived", native_ptr);
 
+    if (RegeneratedClasses::has_been_regenerated((address)native_ptr)) {
+      native_ptr = (Metadata*)RegeneratedClasses::get_regenerated_object((address)native_ptr);
+    }
+
     address buffered_native_ptr = ArchiveBuilder::current()->get_buffered_addr((address)native_ptr);
     address requested_native_ptr = ArchiveBuilder::current()->to_requested(buffered_native_ptr);
     *buffered_field_addr = (Metadata*)requested_native_ptr;
   }
 
