< prev index next >

src/hotspot/share/cds/archiveBuilder.cpp

Print this page
@@ -25,16 +25,18 @@
  #include "precompiled.hpp"
  #include "cds/archiveBuilder.hpp"
  #include "cds/archiveHeapWriter.hpp"
  #include "cds/archiveUtils.hpp"
  #include "cds/cdsConfig.hpp"
+ #include "cds/classPrelinker.hpp"
  #include "cds/cppVtables.hpp"
  #include "cds/dumpAllocStats.hpp"
  #include "cds/dynamicArchive.hpp"
  #include "cds/heapShared.hpp"
  #include "cds/metaspaceShared.hpp"
  #include "cds/regeneratedClasses.hpp"
+ #include "classfile/classLoader.hpp"
  #include "classfile/classLoaderDataShared.hpp"
  #include "classfile/javaClasses.hpp"
  #include "classfile/symbolTable.hpp"
  #include "classfile/systemDictionaryShared.hpp"
  #include "classfile/vmClasses.hpp"

@@ -47,10 +49,11 @@
  #include "oops/compressedKlass.inline.hpp"
  #include "oops/instanceKlass.hpp"
  #include "oops/objArrayKlass.hpp"
  #include "oops/objArrayOop.inline.hpp"
  #include "oops/oopHandle.inline.hpp"
+ #include "oops/trainingData.hpp"
  #include "runtime/arguments.hpp"
  #include "runtime/fieldDescriptor.inline.hpp"
  #include "runtime/globals_extension.hpp"
  #include "runtime/javaThread.hpp"
  #include "runtime/sharedRuntime.hpp"

@@ -155,10 +158,11 @@
    _mapped_static_archive_bottom(nullptr),
    _mapped_static_archive_top(nullptr),
    _buffer_to_requested_delta(0),
    _rw_region("rw", MAX_SHARED_DELTA),
    _ro_region("ro", MAX_SHARED_DELTA),
+   _cc_region("cc", MAX_SHARED_DELTA),
    _ptrmap(mtClassShared),
    _rw_src_objs(),
    _ro_src_objs(),
    _src_obj_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),
    _buffered_to_src_table(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE),

@@ -209,10 +213,13 @@
    if (ref->msotype() == MetaspaceObj::ClassType) {
      Klass* klass = (Klass*)ref->obj();
      assert(klass->is_klass(), "must be");
      if (!is_excluded(klass)) {
        _klasses->append(klass);
+       if (klass->is_hidden() && klass->is_instance_klass()) {
+         update_hidden_class_loader_type(InstanceKlass::cast(klass));
+       }
      }
      // See RunTimeClassInfo::get_for()
      _estimated_metaspaceobj_bytes += align_up(BytesPerWord, SharedSpaceObjectAlignment);
    } else if (ref->msotype() == MetaspaceObj::SymbolType) {
      // Make sure the symbol won't be GC'ed while we are dumping the archive.

@@ -267,10 +274,42 @@
      // but this should be enough for now
      _estimated_metaspaceobj_bytes += 200 * 1024 * 1024;
    }
  }
  
+ #if INCLUDE_CDS_JAVA_HEAP
+ 
+ void ArchiveBuilder::update_hidden_class_loader_type(InstanceKlass* ik) {
+   s2 classloader_type;
+   if (HeapShared::is_lambda_form_klass(ik)) {
+     assert(CDSConfig::is_dumping_invokedynamic(), "lambda form classes are archived only if ArchiveInvokeDynamic is true");
+     classloader_type = ClassLoader::BOOT_LOADER;
+   } else if (HeapShared::is_lambda_proxy_klass(ik)) {
+     oop loader = ik->class_loader();
+ 
+     if (loader == nullptr) {
+       classloader_type = ClassLoader::BOOT_LOADER;
+     } else if (SystemDictionary::is_platform_class_loader(loader)) {
+       classloader_type = ClassLoader::PLATFORM_LOADER;
+     } else if (SystemDictionary::is_system_class_loader(loader)) {
+       classloader_type = ClassLoader::APP_LOADER;
+     } else {
+       ShouldNotReachHere();
+     }
+   } else {
+     ShouldNotReachHere();
+   }
+ 
+   ik->set_shared_class_loader_type(classloader_type);
+   if (HeapShared::is_lambda_proxy_klass(ik)) {
+     InstanceKlass* nest_host = ik->nest_host_not_null();
+     ik->set_shared_classpath_index(nest_host->shared_classpath_index());
+   }
+ }
+ 
+ #endif //INCLUDE_CDS_JAVA_HEAP
+ 
  int ArchiveBuilder::compare_symbols_by_address(Symbol** a, Symbol** b) {
    if (a[0] < b[0]) {
      return -1;
    } else {
      assert(a[0] > b[0], "Duplicated symbol %s unexpected", (*a)->as_C_string());

@@ -289,12 +328,21 @@
  
  size_t ArchiveBuilder::estimate_archive_size() {
    // size of the symbol table and two dictionaries, plus the RunTimeClassInfo's
    size_t symbol_table_est = SymbolTable::estimate_size_for_archive();
    size_t dictionary_est = SystemDictionaryShared::estimate_size_for_archive();
-   _estimated_hashtable_bytes = symbol_table_est + dictionary_est;
+   size_t training_data_est = TrainingData::estimate_size_for_archive();
+   _estimated_hashtable_bytes = symbol_table_est + dictionary_est + training_data_est;
  
+   if (CDSConfig::is_dumping_final_static_archive()) {
+     _estimated_hashtable_bytes += 200 * 1024 * 1024; // FIXME -- need to iterate archived symbols??
+   }
+ 
+   if (CDSConfig::is_dumping_dynamic_archive()) {
+     // Some extra space for traning data. Be generous. Unused areas will be trimmed from the archive file.
+     _estimated_hashtable_bytes += 200 * 1024 * 1024;
+   }
    size_t total = 0;
  
    total += _estimated_metaspaceobj_bytes;
    total += _estimated_hashtable_bytes;
  

@@ -409,10 +457,14 @@
    if (RegeneratedClasses::has_been_regenerated(src_obj)) {
      // No need to copy it. We will later relocate it to point to the regenerated klass/method.
      return false;
    }
    remember_embedded_pointer_in_enclosing_obj(ref);
+   if (RegeneratedClasses::has_been_regenerated(src_obj)) {
+     // No need to copy it. We will later relocate it to point to the regenerated klass/method.
+     return false;
+   }
  
    FollowMode follow_mode = get_follow_mode(ref);
    SourceObjInfo src_info(ref, read_only, follow_mode);
    bool created;
    SourceObjInfo* p = _src_obj_table.put_if_absent(src_obj, src_info, &created);

@@ -508,11 +560,11 @@
    if (klass->is_instance_klass()) {
      InstanceKlass* ik = InstanceKlass::cast(klass);
      return SystemDictionaryShared::is_excluded_class(ik);
    } else if (klass->is_objArray_klass()) {
      Klass* bottom = ObjArrayKlass::cast(klass)->bottom_klass();
-     if (MetaspaceShared::is_shared_static(bottom)) {
+     if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_shared_static(bottom)) {
        // The bottom class is in the static archive so it's clearly not excluded.
        assert(CDSConfig::is_dumping_dynamic_archive(), "sanity");
        return false;
      } else if (bottom->is_instance_klass()) {
        return SystemDictionaryShared::is_excluded_class(InstanceKlass::cast(bottom));

@@ -522,16 +574,19 @@
    return false;
  }
  
  ArchiveBuilder::FollowMode ArchiveBuilder::get_follow_mode(MetaspaceClosure::Ref *ref) {
    address obj = ref->obj();
-   if (MetaspaceShared::is_in_shared_metaspace(obj)) {
+   if (CDSConfig::is_dumping_dynamic_archive() && MetaspaceShared::is_in_shared_metaspace(obj)) {
      // Don't dump existing shared metadata again.
      return point_to_it;
    } else if (ref->msotype() == MetaspaceObj::MethodDataType ||
-              ref->msotype() == MetaspaceObj::MethodCountersType) {
-     return set_to_null;
+              ref->msotype() == MetaspaceObj::MethodCountersType ||
+              ref->msotype() == MetaspaceObj::KlassTrainingDataType ||
+              ref->msotype() == MetaspaceObj::MethodTrainingDataType ||
+              ref->msotype() == MetaspaceObj::CompileTrainingDataType) {
+       return TrainingData::need_data() ? make_a_copy : set_to_null;
    } else {
      if (ref->msotype() == MetaspaceObj::ClassType) {
        Klass* klass = (Klass*)ref->obj();
        assert(klass->is_klass(), "must be");
        if (is_excluded(klass)) {

@@ -680,18 +735,31 @@
      *ptr_location = get_buffered_addr(src_addr);
      ArchivePtrMarker::mark_pointer(ptr_location);
    }
  }
  
+ void ArchiveBuilder::mark_and_relocate_to_buffered_addr(address* ptr_location) {
+   assert(*ptr_location != nullptr, "sanity");
+   if (!is_in_mapped_static_archive(*ptr_location)) {
+     *ptr_location = get_buffered_addr(*ptr_location);
+   }
+   ArchivePtrMarker::mark_pointer(ptr_location);
+ }
+ 
  address ArchiveBuilder::get_buffered_addr(address src_addr) const {
    SourceObjInfo* p = _src_obj_table.get(src_addr);
    assert(p != nullptr, "src_addr " INTPTR_FORMAT " is used but has not been archived",
           p2i(src_addr));
  
    return p->buffered_addr();
  }
  
+ bool ArchiveBuilder::has_been_archived(address src_addr) const {
+   SourceObjInfo* p = _src_obj_table.get(src_addr);
+   return (p != nullptr);
+ }
+ 
  address ArchiveBuilder::get_source_addr(address buffered_addr) const {
    assert(is_in_buffer_space(buffered_addr), "must be");
    address* src_p = _buffered_to_src_table.get(buffered_addr);
    assert(src_p != nullptr && *src_p != nullptr, "must be");
    return *src_p;

@@ -707,21 +775,45 @@
    log_info(cds)("Relocating embedded pointers in core regions ... ");
    relocate_embedded_pointers(&_rw_src_objs);
    relocate_embedded_pointers(&_ro_src_objs);
  }
  
+ #define ADD_COUNT(x) \
+   x += 1; \
+   x ## _i += inited;
+ 
+ #define DECLARE_INSTANCE_KLASS_COUNTER(x) \
+   int x = 0; \
+   int x ## _i = 0; \
+ 
  void ArchiveBuilder::make_klasses_shareable() {
-   int num_instance_klasses = 0;
-   int num_boot_klasses = 0;
-   int num_platform_klasses = 0;
-   int num_app_klasses = 0;
-   int num_hidden_klasses = 0;
-   int num_unlinked_klasses = 0;
-   int num_unregistered_klasses = 0;
+   DECLARE_INSTANCE_KLASS_COUNTER(num_instance_klasses);
+   DECLARE_INSTANCE_KLASS_COUNTER(num_boot_klasses);
+   DECLARE_INSTANCE_KLASS_COUNTER(num_vm_klasses);
+   DECLARE_INSTANCE_KLASS_COUNTER(num_platform_klasses);
+   DECLARE_INSTANCE_KLASS_COUNTER(num_app_klasses);
+   DECLARE_INSTANCE_KLASS_COUNTER(num_hidden_klasses);
+   DECLARE_INSTANCE_KLASS_COUNTER(num_unlinked_klasses);
+   DECLARE_INSTANCE_KLASS_COUNTER(num_unregistered_klasses);
    int num_obj_array_klasses = 0;
    int num_type_array_klasses = 0;
  
+   int boot_unlinked = 0;
+   int platform_unlinked = 0;
+   int app_unlinked = 0;
+   int unreg_unlinked = 0;
+ 
+   for (int i = 0; i < klasses()->length(); i++) {
+     // Some of the code in ConstantPool::remove_unshareable_info() requires the classes
+     // to be in linked state, so it must be call here before the next loop, which returns
+     // all classes to unlinked state.
+     Klass* k = get_buffered_addr(klasses()->at(i));
+     if (k->is_instance_klass()) {
+       InstanceKlass::cast(k)->constants()->remove_unshareable_info();
+     }
+   }
+ 
    for (int i = 0; i < klasses()->length(); i++) {
      const char* type;
      const char* unlinked = "";
      const char* hidden = "";
      const char* generated = "";

@@ -736,38 +828,68 @@
        num_type_array_klasses ++;
        type = "array";
        k->remove_unshareable_info();
      } else {
        assert(k->is_instance_klass(), " must be");
-       num_instance_klasses ++;
        InstanceKlass* ik = InstanceKlass::cast(k);
+       InstanceKlass* src_ik = get_source_addr(ik);
+       int inited = ik->has_preinitialized_mirror();
+       ADD_COUNT(num_instance_klasses);
        if (CDSConfig::is_dumping_dynamic_archive()) {
          // For static dump, class loader type are already set.
          ik->assign_class_loader_type();
        }
-       if (ik->is_shared_boot_class()) {
+       if (ik->is_hidden()) {
+         oop loader = k->class_loader();
+         if (loader == nullptr) {
+           type = "boot";
+           ADD_COUNT(num_boot_klasses);
+         } else if (loader == SystemDictionary::java_platform_loader()) {
+           type = "plat";
+           ADD_COUNT(num_platform_klasses);
+         } else if (loader == SystemDictionary::java_system_loader()) {
+           type = "app";
+           ADD_COUNT(num_app_klasses);
+         } else {
+           type = "bad";
+           assert(0, "shouldn't happen");
+         }
+       } else if (ik->is_shared_boot_class()) {
          type = "boot";
-         num_boot_klasses ++;
+         ADD_COUNT(num_boot_klasses);
        } else if (ik->is_shared_platform_class()) {
          type = "plat";
-         num_platform_klasses ++;
+         ADD_COUNT(num_platform_klasses);
        } else if (ik->is_shared_app_class()) {
          type = "app";
-         num_app_klasses ++;
+         ADD_COUNT(num_app_klasses);
        } else {
          assert(ik->is_shared_unregistered_class(), "must be");
          type = "unreg";
-         num_unregistered_klasses ++;
+         ADD_COUNT(num_unregistered_klasses);
+       }
+ 
+       if (ClassPrelinker::is_vm_class(src_ik)) {
+         ADD_COUNT(num_vm_klasses);
        }
  
        if (!ik->is_linked()) {
-         num_unlinked_klasses ++;
+         ADD_COUNT(num_unlinked_klasses);
          unlinked = " ** unlinked";
+         if (ik->is_shared_boot_class()) {
+           boot_unlinked ++;
+         } else if (ik->is_shared_platform_class()) {
+           platform_unlinked ++;
+         } else if (ik->is_shared_app_class()) {
+           app_unlinked ++;
+         } else {
+           unreg_unlinked ++;
+         }
        }
  
        if (ik->is_hidden()) {
-         num_hidden_klasses ++;
+         ADD_COUNT(num_hidden_klasses);
          hidden = " ** hidden";
        }
  
        if (ik->is_generated_shared_class()) {
          generated = " ** generated";

@@ -783,17 +905,21 @@
                              hidden, unlinked, generated);
      }
    }
  
    log_info(cds)("Number of classes %d", num_instance_klasses + num_obj_array_klasses + num_type_array_klasses);
-   log_info(cds)("    instance classes   = %5d", num_instance_klasses);
-   log_info(cds)("      boot             = %5d", num_boot_klasses);
-   log_info(cds)("      app              = %5d", num_app_klasses);
-   log_info(cds)("      platform         = %5d", num_platform_klasses);
-   log_info(cds)("      unregistered     = %5d", num_unregistered_klasses);
-   log_info(cds)("      (hidden)         = %5d", num_hidden_klasses);
-   log_info(cds)("      (unlinked)       = %5d", num_unlinked_klasses);
+   log_info(cds)("    instance classes   = %5d, inited = %5d", num_instance_klasses,     num_instance_klasses_i);
+   log_info(cds)("      boot             = %5d, inited = %5d", num_boot_klasses,         num_boot_klasses_i);
+   log_info(cds)("       vm              = %5d, inited = %5d", num_vm_klasses,           num_vm_klasses_i);
+   log_info(cds)("      platform         = %5d, inited = %5d", num_platform_klasses,     num_platform_klasses_i);
+   log_info(cds)("      app              = %5d, inited = %5d", num_app_klasses,          num_app_klasses_i);
+   log_info(cds)("      unregistered     = %5d, inited = %5d", num_unregistered_klasses, num_unregistered_klasses_i);
+   log_info(cds)("      (hidden)         = %5d, inited = %5d", num_hidden_klasses,       num_hidden_klasses_i);
+   log_info(cds)("      (unlinked)       = %5d, inited = %5d, boot = %d, plat = %d, app = %d, unreg = %d",
+                                                               num_unlinked_klasses,     num_unlinked_klasses_i,
+                                                               boot_unlinked, platform_unlinked,
+                                                               app_unlinked, unreg_unlinked);
    log_info(cds)("    obj array classes  = %5d", num_obj_array_klasses);
    log_info(cds)("    type array classes = %5d", num_type_array_klasses);
    log_info(cds)("               symbols = %5d", _symbols->length());
  
    DynamicArchive::make_array_klasses_shareable();

@@ -801,10 +927,12 @@
  
  void ArchiveBuilder::serialize_dynamic_archivable_items(SerializeClosure* soc) {
    SymbolTable::serialize_shared_table_header(soc, false);
    SystemDictionaryShared::serialize_dictionary_headers(soc, false);
    DynamicArchive::serialize_array_klasses(soc);
+   ClassPrelinker::serialize(soc, false);
+   TrainingData::serialize_training_data(soc);
  }
  
  uintx ArchiveBuilder::buffer_to_offset(address p) const {
    address requested_p = to_requested(p);
    assert(requested_p >= _requested_static_archive_bottom, "must be");

@@ -821,10 +949,19 @@
      p = get_buffered_addr(p);
    }
    return buffer_to_offset(p);
  }
  
+ void ArchiveBuilder::start_cc_region() {
+   ro_region()->pack();
+   start_dump_space(&_cc_region);
+ }
+ 
+ void ArchiveBuilder::end_cc_region() {
+   _cc_region.pack();
+ }
+ 
  #if INCLUDE_CDS_JAVA_HEAP
  narrowKlass ArchiveBuilder::get_requested_narrow_klass(Klass* k) {
    assert(CDSConfig::is_dumping_heap(), "sanity");
    k = get_buffered_klass(k);
    Klass* requested_k = to_requested(k);

@@ -910,11 +1047,13 @@
    }
  };
  
  
  void ArchiveBuilder::relocate_to_requested() {
-   ro_region()->pack();
+   if (!ro_region()->is_packed()) {
+     ro_region()->pack();
+   }
  
    size_t my_archive_size = buffer_top() - buffer_bottom();
  
    if (CDSConfig::is_dumping_static_archive()) {
      _requested_static_archive_top = _requested_static_archive_bottom + my_archive_size;

@@ -1058,10 +1197,12 @@
      while (start < end) {
        size_t byte_size;
        oop source_oop = ArchiveHeapWriter::buffered_addr_to_source_obj(start);
        address requested_start = ArchiveHeapWriter::buffered_addr_to_requested_addr(start);
        st.print(PTR_FORMAT ": @@ Object ", p2i(requested_start));
+       int permobj_segment = -1;
+       int permobj_segment_length = -1;
  
        if (source_oop != nullptr) {
          // This is a regular oop that got archived.
          print_oop_with_requested_addr_cr(&st, source_oop, false);
          byte_size = source_oop->size() * BytesPerWord;

@@ -1072,10 +1213,12 @@
          st.print_cr("HeapShared::roots[%d]", HeapShared::pending_roots()->length());
          byte_size = ArchiveHeapWriter::heap_roots_word_size() * BytesPerWord;
        } else if ((byte_size = ArchiveHeapWriter::get_filler_size_at(start)) > 0) {
          // We have a filler oop, which also does not exist in BufferOffsetToSourceObjectTable.
          st.print_cr("filler " SIZE_FORMAT " bytes", byte_size);
+       } else if ((permobj_segment = ArchiveHeapWriter::get_permobj_segment_at(start, &byte_size, &permobj_segment_length)) >= 0) {
+         st.print_cr("permobj_%d[%d] %zu bytes", permobj_segment, permobj_segment_length, byte_size);
        } else {
          ShouldNotReachHere();
        }
  
        address oop_end = start + byte_size;

@@ -1083,10 +1226,12 @@
  
        if (source_oop != nullptr) {
          log_oop_details(heap_info, source_oop);
        } else if (start == ArchiveHeapWriter::buffered_heap_roots_addr()) {
          log_heap_roots();
+       } else if (permobj_segment >= 0) {
+         log_permobj_segment(permobj_segment, permobj_segment_length);
        }
        start = oop_end;
      }
    }
  

@@ -1182,10 +1327,21 @@
          print_oop_with_requested_addr_cr(&st, HeapShared::pending_roots()->at(i));
        }
      }
    }
  
+   static void log_permobj_segment(int permobj_segment, int permobj_segment_length) {
+     LogStreamHandle(Trace, cds, map, oops) st;
+     if (st.is_enabled()) {
+       for (int i = 0; i < permobj_segment_length; i++) {
+         st.print("permobj_%d[%4d]: ", permobj_segment, i);
+         print_oop_with_requested_addr_cr(&st, ArchiveHeapWriter::get_permobj_source_addr(permobj_segment, i));
+       }
+     }
+   }
+ 
+ 
    // The output looks like this. The first number is the requested address. The second number is
    // the narrowOop version of the requested address.
    //     0x00000007ffc7e840 (0xfff8fd08) java.lang.Class
    //     0x00000007ffc000f8 (0xfff8001f) [B length: 11
    static void print_oop_with_requested_addr_cr(outputStream* st, oop source_oop, bool print_addr = true) {

@@ -1202,11 +1358,16 @@
        }
        if (source_oop->is_array()) {
          int array_len = arrayOop(source_oop)->length();
          st->print_cr("%s length: %d", source_oop->klass()->external_name(), array_len);
        } else {
-         st->print_cr("%s", source_oop->klass()->external_name());
+         st->print("%s", source_oop->klass()->external_name());
+         if (java_lang_invoke_MethodType::is_instance(source_oop)) {
+           st->print(" ");
+           java_lang_invoke_MethodType::print_signature(source_oop, st);
+         }
+         st->cr();
        }
      }
    }
  #endif // INCLUDE_CDS_JAVA_HEAP
  

@@ -1275,10 +1436,11 @@
    // MetaspaceShared::n_regions (internal to hotspot).
    assert(NUM_CDS_REGIONS == MetaspaceShared::n_regions, "sanity");
  
    write_region(mapinfo, MetaspaceShared::rw, &_rw_region, /*read_only=*/false,/*allow_exec=*/false);
    write_region(mapinfo, MetaspaceShared::ro, &_ro_region, /*read_only=*/true, /*allow_exec=*/false);
+   write_region(mapinfo, MetaspaceShared::cc, &_cc_region, /*read_only=*/false,/*allow_exec=*/true);
  
    size_t bitmap_size_in_bytes;
    char* bitmap = mapinfo->write_bitmap_region(ArchivePtrMarker::ptrmap(), heap_info,
                                                bitmap_size_in_bytes);
  

@@ -1323,10 +1485,11 @@
                               _total_heap_region_size;
    const double total_u_perc = percent_of(total_bytes, total_reserved);
  
    _rw_region.print(total_reserved);
    _ro_region.print(total_reserved);
+   _cc_region.print(total_reserved);
  
    print_bitmap_region_stats(bitmap_used, total_reserved);
  
    if (heap_info->is_used()) {
      print_heap_region_stats(heap_info, total_reserved);

@@ -1357,12 +1520,5 @@
    _ro_region.print_out_of_space_msg(name, needed_bytes);
  
    log_error(cds)("Unable to allocate from '%s' region: Please reduce the number of shared classes.", name);
    MetaspaceShared::unrecoverable_writing_error();
  }
- 
- 
- #ifndef PRODUCT
- void ArchiveBuilder::assert_is_vm_thread() {
-   assert(Thread::current()->is_VM_thread(), "ArchiveBuilder should be used only inside the VMThread");
- }
- #endif
< prev index next >