< prev index next >

src/hotspot/share/cds/metaspaceShared.cpp

Print this page
*** 25,10 ***
--- 25,11 ---
  #include "precompiled.hpp"
  #include "cds/archiveBuilder.hpp"
  #include "cds/archiveHeapLoader.hpp"
  #include "cds/archiveHeapWriter.hpp"
  #include "cds/cds_globals.hpp"
+ #include "cds/cdsAccess.hpp"
  #include "cds/cdsConfig.hpp"
  #include "cds/cdsProtectionDomain.hpp"
  #include "cds/cds_globals.hpp"
  #include "cds/classListParser.hpp"
  #include "cds/classListWriter.hpp"

*** 52,10 ***
--- 53,13 ---
  #include "classfile/systemDictionary.hpp"
  #include "classfile/systemDictionaryShared.hpp"
  #include "classfile/vmClasses.hpp"
  #include "classfile/vmSymbols.hpp"
  #include "code/codeCache.hpp"
+ #include "code/SCCache.hpp"
+ #include "compiler/compileBroker.hpp"
+ #include "compiler/precompiler.hpp"
  #include "gc/shared/gcVMOperations.hpp"
  #include "interpreter/bytecodeStream.hpp"
  #include "interpreter/bytecodes.hpp"
  #include "jvm_io.h"
  #include "logging/log.hpp"

*** 67,18 ***
--- 71,22 ---
  #include "memory/universe.hpp"
  #include "nmt/memTracker.hpp"
  #include "oops/compressedKlass.hpp"
  #include "oops/instanceMirrorKlass.hpp"
  #include "oops/klass.inline.hpp"
+ #include "oops/method.inline.hpp"
  #include "oops/objArrayOop.hpp"
  #include "oops/oop.inline.hpp"
  #include "oops/oopHandle.hpp"
+ #include "oops/trainingData.hpp"
  #include "prims/jvmtiExport.hpp"
+ #include "prims/whitebox.hpp"
  #include "runtime/arguments.hpp"
  #include "runtime/globals.hpp"
  #include "runtime/globals_extension.hpp"
  #include "runtime/handles.inline.hpp"
+ #include "runtime/javaCalls.hpp"
  #include "runtime/os.inline.hpp"
  #include "runtime/safepointVerifiers.hpp"
  #include "runtime/sharedRuntime.hpp"
  #include "runtime/vmOperations.hpp"
  #include "runtime/vmThread.hpp"

*** 95,10 ***
--- 103,11 ---
  bool MetaspaceShared::_remapped_readwrite = false;
  void* MetaspaceShared::_shared_metaspace_static_top = nullptr;
  intx MetaspaceShared::_relocation_delta;
  char* MetaspaceShared::_requested_base_address;
  bool MetaspaceShared::_use_optimized_module_handling = true;
+ Array<Method*>* MetaspaceShared::_archived_method_handle_intrinsics = nullptr;
  
  // The CDS archive is divided into the following regions:
  //     rw  - read-write metadata
  //     ro  - read-only metadata and read-only tables
  //     hp  - heap region

*** 297,10 ***
--- 306,11 ---
    }
  }
  
  static GrowableArrayCHeap<OopHandle, mtClassShared>* _extra_interned_strings = nullptr;
  static GrowableArrayCHeap<Symbol*, mtClassShared>* _extra_symbols = nullptr;
+ static GrowableArray<Method*>* _method_handle_intrinsics = nullptr;
  
  void MetaspaceShared::read_extra_data(JavaThread* current, const char* filename) {
    _extra_interned_strings = new GrowableArrayCHeap<OopHandle, mtClassShared>(10000);
    _extra_symbols = new GrowableArrayCHeap<Symbol*, mtClassShared>(1000);
  

*** 347,10 ***
--- 357,29 ---
        }
      }
    }
  }
  
+ void MetaspaceShared::make_method_handle_intrinsics_shareable() {
+   for (int i = 0; i < _method_handle_intrinsics->length(); i++) {
+     Method* m = ArchiveBuilder::current()->get_buffered_addr(_method_handle_intrinsics->at(i));
+     m->remove_unshareable_info();
+     // Each method has its own constant pool (which is distinct from m->method_holder()->constants());
+     m->constants()->remove_unshareable_info();
+   }
+ }
+ 
+ void MetaspaceShared::write_method_handle_intrinsics() {
+   int len = _method_handle_intrinsics->length();
+   _archived_method_handle_intrinsics = ArchiveBuilder::new_ro_array<Method*>(len);
+   for (int i = 0; i < len; i++) {
+     ArchiveBuilder::current()->write_pointer_in_buffer(_archived_method_handle_intrinsics->adr_at(i),
+                                                        _method_handle_intrinsics->at(i));
+   }
+   log_info(cds)("Archived %d method handle intrinsics", len);
+ }
+ 
  // Read/write a data stream for restoring/preserving metadata pointers and
  // miscellaneous data from/to the shared archive file.
  
  void MetaspaceShared::serialize(SerializeClosure* soc) {
    int tag = 0;

*** 371,10 ***
--- 400,11 ---
    CppVtables::serialize(soc);
    soc->do_tag(--tag);
  
    // Dump/restore miscellaneous metadata.
    JavaClasses::serialize_offsets(soc);
+   HeapShared::serialize_misc_info(soc);
    Universe::serialize(soc);
    soc->do_tag(--tag);
  
    // Dump/restore references to commonly used names and signatures.
    vmSymbols::serialize(soc);

*** 383,19 ***
    // Dump/restore the symbol/string/subgraph_info tables
    SymbolTable::serialize_shared_table_header(soc);
    StringTable::serialize_shared_table_header(soc);
    HeapShared::serialize_tables(soc);
    SystemDictionaryShared::serialize_dictionary_headers(soc);
! 
    InstanceMirrorKlass::serialize_offsets(soc);
  
    // Dump/restore well known classes (pointers)
    SystemDictionaryShared::serialize_vm_classes(soc);
    soc->do_tag(--tag);
  
    CDS_JAVA_HEAP_ONLY(Modules::serialize(soc);)
    CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);)
  
    LambdaFormInvokers::serialize(soc);
    soc->do_tag(666);
  }
  
--- 413,22 ---
    // Dump/restore the symbol/string/subgraph_info tables
    SymbolTable::serialize_shared_table_header(soc);
    StringTable::serialize_shared_table_header(soc);
    HeapShared::serialize_tables(soc);
    SystemDictionaryShared::serialize_dictionary_headers(soc);
!   ClassPrelinker::serialize(soc, true);
+   TrainingData::serialize_training_data(soc);
    InstanceMirrorKlass::serialize_offsets(soc);
  
    // Dump/restore well known classes (pointers)
    SystemDictionaryShared::serialize_vm_classes(soc);
    soc->do_tag(--tag);
  
    CDS_JAVA_HEAP_ONLY(Modules::serialize(soc);)
    CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);)
+   soc->do_ptr((void**)&_archived_method_handle_intrinsics);
+ 
  
    LambdaFormInvokers::serialize(soc);
    soc->do_tag(666);
  }
  

*** 434,27 ***
  }
  
  class VM_PopulateDumpSharedSpace : public VM_Operation {
  private:
    ArchiveHeapInfo _heap_info;
- 
    void dump_java_heap_objects(GrowableArray<Klass*>* klasses) NOT_CDS_JAVA_HEAP_RETURN;
    void dump_shared_symbol_table(GrowableArray<Symbol*>* symbols) {
      log_info(cds)("Dumping symbol table ...");
      SymbolTable::write_to_archive(symbols);
    }
    char* dump_read_only_tables();
! 
  public:
  
!   VM_PopulateDumpSharedSpace() : VM_Operation(), _heap_info() {}
  
    bool skip_operation() const { return false; }
  
    VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
    void doit();   // outline because gdb sucks
    bool allow_nested_vm_operations() const { return true; }
  }; // class VM_PopulateDumpSharedSpace
  
  class StaticArchiveBuilder : public ArchiveBuilder {
  public:
    StaticArchiveBuilder() : ArchiveBuilder() {}
--- 467,30 ---
  }
  
  class VM_PopulateDumpSharedSpace : public VM_Operation {
  private:
    ArchiveHeapInfo _heap_info;
    void dump_java_heap_objects(GrowableArray<Klass*>* klasses) NOT_CDS_JAVA_HEAP_RETURN;
    void dump_shared_symbol_table(GrowableArray<Symbol*>* symbols) {
      log_info(cds)("Dumping symbol table ...");
      SymbolTable::write_to_archive(symbols);
    }
    char* dump_read_only_tables();
!   StaticArchiveBuilder& _builder;
+   FileMapInfo* _mapinfo;
  public:
  
!   VM_PopulateDumpSharedSpace(StaticArchiveBuilder& b) :
+     VM_Operation(), _heap_info(), _builder(b), _mapinfo(nullptr) {}
  
    bool skip_operation() const { return false; }
  
    VMOp_Type type() const { return VMOp_PopulateDumpSharedSpace; }
    void doit();   // outline because gdb sucks
    bool allow_nested_vm_operations() const { return true; }
+   FileMapInfo* mapinfo() const { return _mapinfo; }
+   ArchiveHeapInfo* heap_info() { return &_heap_info; }
  }; // class VM_PopulateDumpSharedSpace
  
  class StaticArchiveBuilder : public ArchiveBuilder {
  public:
    StaticArchiveBuilder() : ArchiveBuilder() {}

*** 462,10 ***
--- 498,11 ---
    virtual void iterate_roots(MetaspaceClosure* it) {
      FileMapInfo::metaspace_pointers_do(it);
      SystemDictionaryShared::dumptime_classes_do(it);
      Universe::metaspace_pointers_do(it);
      vmSymbols::metaspace_pointers_do(it);
+     TrainingData::iterate_roots(it);
  
      // The above code should find all the symbols that are referenced by the
      // archived classes. We just need to add the extra symbols which
      // may not be used by any of the archived classes -- these are usually
      // symbols that we anticipate to be used at run time, so we can store

*** 473,17 ***
--- 510,25 ---
      if (_extra_symbols != nullptr) {
        for (int i = 0; i < _extra_symbols->length(); i++) {
          it->push(_extra_symbols->adr_at(i));
        }
      }
+ 
+     for (int i = 0; i < _method_handle_intrinsics->length(); i++) {
+       it->push(_method_handle_intrinsics->adr_at(i));
+     }
    }
  };
  
  char* VM_PopulateDumpSharedSpace::dump_read_only_tables() {
    ArchiveBuilder::OtherROAllocMark mark;
  
    SystemDictionaryShared::write_to_archive();
+   ClassPrelinker::record_initiated_klasses(true);
+   ClassPrelinker::record_unregistered_klasses();
+   TrainingData::dump_training_data();
+   MetaspaceShared::write_method_handle_intrinsics();
  
    // Write lambform lines into archive
    LambdaFormInvokers::dump_static_archive_invokers();
    // Write module name into archive
    CDS_JAVA_HEAP_ONLY(Modules::dump_main_module_name();)

*** 505,59 ***
  
    // Block concurrent class unloading from changing the _dumptime_table
    MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
    SystemDictionaryShared::check_excluded_classes();
  
!   StaticArchiveBuilder builder;
!   builder.gather_source_objs();
-   builder.reserve_buffer();
  
!   char* cloned_vtables = CppVtables::dumptime_init(&builder);
  
    // Initialize random for updating the hash of symbols
    os::init_random(0x12345678);
  
!   builder.dump_rw_metadata();
!   builder.dump_ro_metadata();
!   builder.relocate_metaspaceobj_embedded_pointers();
  
!   dump_java_heap_objects(builder.klasses());
!   dump_shared_symbol_table(builder.symbols());
  
    log_info(cds)("Make classes shareable");
!   builder.make_klasses_shareable();
  
    char* serialized_data = dump_read_only_tables();
  
    SystemDictionaryShared::adjust_lambda_proxy_class_dictionary();
  
    // The vtable clones contain addresses of the current process.
    // We don't want to write these addresses into the archive.
    CppVtables::zero_archived_vtables();
  
-   // relocate the data so that it can be mapped to MetaspaceShared::requested_base_address()
-   // without runtime relocation.
-   builder.relocate_to_requested();
- 
    // Write the archive file
!   const char* static_archive = CDSConfig::static_archive_path();
!   assert(static_archive != nullptr, "SharedArchiveFile not set?");
!   FileMapInfo* mapinfo = new FileMapInfo(static_archive, true);
!   mapinfo->populate_header(MetaspaceShared::core_region_alignment());
!   mapinfo->set_serialized_data(serialized_data);
!   mapinfo->set_cloned_vtables(cloned_vtables);
!   mapinfo->open_for_write();
-   builder.write_archive(mapinfo, &_heap_info);
- 
-   if (PrintSystemDictionaryAtExit) {
-     SystemDictionary::print();
-   }
- 
-   if (AllowArchivingWithJavaAgent) {
-     log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used "
-             "for testing purposes only and should not be used in a production environment");
    }
  }
  
  class CollectCLDClosure : public CLDClosure {
    GrowableArray<ClassLoaderData*> _loaded_cld;
    GrowableArray<OopHandle> _loaded_cld_handles; // keep the CLDs alive
--- 550,65 ---
  
    // Block concurrent class unloading from changing the _dumptime_table
    MutexLocker ml(DumpTimeTable_lock, Mutex::_no_safepoint_check_flag);
    SystemDictionaryShared::check_excluded_classes();
  
!   _builder.gather_source_objs();
!   _builder.reserve_buffer();
  
!   char* cloned_vtables = CppVtables::dumptime_init(&_builder);
  
    // Initialize random for updating the hash of symbols
    os::init_random(0x12345678);
  
!   _builder.dump_rw_metadata();
!   _builder.dump_ro_metadata();
!   _builder.relocate_metaspaceobj_embedded_pointers();
+ 
+   dump_java_heap_objects(_builder.klasses());
+   dump_shared_symbol_table(_builder.symbols());
  
!   {
!     ArchiveBuilder::OtherROAllocMark mark;
+     ClassPrelinker::record_preloaded_klasses(true);
+     if (CDSConfig::is_dumping_preimage_static_archive()) {
+       ClassPrelinker::record_final_image_eager_linkage();
+     }
+   }
  
    log_info(cds)("Make classes shareable");
!   _builder.make_klasses_shareable();
+   MetaspaceShared::make_method_handle_intrinsics_shareable();
  
    char* serialized_data = dump_read_only_tables();
  
    SystemDictionaryShared::adjust_lambda_proxy_class_dictionary();
  
+   log_info(cds)("Adjust method info dictionary");
+   SystemDictionaryShared::adjust_method_info_dictionary();
+ 
+   log_info(cds)("Adjust training data dictionary");
+   TrainingData::adjust_training_data_dictionary();
+ 
    // The vtable clones contain addresses of the current process.
    // We don't want to write these addresses into the archive.
    CppVtables::zero_archived_vtables();
  
    // Write the archive file
!   const char* static_archive;
!   if (CDSConfig::is_dumping_final_static_archive()) {
!     static_archive = CacheDataStore;
!     assert(FileMapInfo::current_info() != nullptr, "sanity");
!     delete FileMapInfo::current_info();
!   } else {
!     static_archive = CDSConfig::static_archive_path();
    }
+   assert(static_archive != nullptr, "SharedArchiveFile not set?");
+   _mapinfo = new FileMapInfo(static_archive, true);
+   _mapinfo->populate_header(MetaspaceShared::core_region_alignment());
+   _mapinfo->set_serialized_data(serialized_data);
+   _mapinfo->set_cloned_vtables(cloned_vtables);
  }
  
  class CollectCLDClosure : public CLDClosure {
    GrowableArray<ClassLoaderData*> _loaded_cld;
    GrowableArray<OopHandle> _loaded_cld_handles; // keep the CLDs alive

*** 580,16 ***
--- 631,20 ---
  };
  
  // Check if we can eagerly link this class at dump time, so we can avoid the
  // runtime linking overhead (especially verification)
  bool MetaspaceShared::may_be_eagerly_linked(InstanceKlass* ik) {
+   if (CDSConfig::preserve_all_dumptime_verification_states(ik)) {
+     assert(ik->can_be_verified_at_dumptime(), "sanity");
+   }
    if (!ik->can_be_verified_at_dumptime()) {
      // For old classes, try to leave them in the unlinked state, so
      // we can still store them in the archive. They must be
      // linked/verified at runtime.
      return false;
    }
+ 
    if (CDSConfig::is_dumping_dynamic_archive() && ik->is_shared_unregistered_class()) {
      // Linking of unregistered classes at this stage may cause more
      // classes to be resolved, resulting in calls to ClassLoader.loadClass()
      // that may not be expected by custom class loaders.
      //

*** 598,26 ***
      return false;
    }
    return true;
  }
  
- bool MetaspaceShared::link_class_for_cds(InstanceKlass* ik, TRAPS) {
-   // Link the class to cause the bytecodes to be rewritten and the
-   // cpcache to be created. Class verification is done according
-   // to -Xverify setting.
-   bool res = MetaspaceShared::try_link_class(THREAD, ik);
-   ClassPrelinker::dumptime_resolve_constants(ik, CHECK_(false));
-   return res;
- }
- 
  void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) {
    ClassPrelinker::initialize();
  
!   if (!jcmd_request) {
      LambdaFormInvokers::regenerate_holder_classes(CHECK);
    }
  
    // Collect all loaded ClassLoaderData.
    CollectCLDClosure collect_cld(THREAD);
    {
      // ClassLoaderDataGraph::loaded_cld_do requires ClassLoaderDataGraph_lock.
      // We cannot link the classes while holding this lock (or else we may run into deadlock).
--- 653,23 ---
      return false;
    }
    return true;
  }
  
  void MetaspaceShared::link_shared_classes(bool jcmd_request, TRAPS) {
    ClassPrelinker::initialize();
  
!   if (!jcmd_request && !CDSConfig::is_dumping_dynamic_archive()) {
+     // If we have regenerated invoker classes in the dynamic archive,
+     // they will conflict with the resolved CONSTANT_Klass references that are stored
+     // in the static archive. This is not easy to handle. Let's disable
+     // it for dynamic archive for now.
      LambdaFormInvokers::regenerate_holder_classes(CHECK);
    }
  
+   ClassPrelinker::setup_forced_preinit_classes();
+ 
    // Collect all loaded ClassLoaderData.
    CollectCLDClosure collect_cld(THREAD);
    {
      // ClassLoaderDataGraph::loaded_cld_do requires ClassLoaderDataGraph_lock.
      // We cannot link the classes while holding this lock (or else we may run into deadlock).

*** 633,11 ***
        ClassLoaderData* cld = collect_cld.cld_at(i);
        for (Klass* klass = cld->klasses(); klass != nullptr; klass = klass->next_link()) {
          if (klass->is_instance_klass()) {
            InstanceKlass* ik = InstanceKlass::cast(klass);
            if (may_be_eagerly_linked(ik)) {
!             has_linked |= link_class_for_cds(ik, CHECK);
            }
          }
        }
      }
  
--- 685,14 ---
        ClassLoaderData* cld = collect_cld.cld_at(i);
        for (Klass* klass = cld->klasses(); klass != nullptr; klass = klass->next_link()) {
          if (klass->is_instance_klass()) {
            InstanceKlass* ik = InstanceKlass::cast(klass);
            if (may_be_eagerly_linked(ik)) {
!             has_linked |= try_link_class(THREAD, ik);
+           }
+           if (CDSConfig::is_dumping_heap() && ik->is_linked() && !ik->is_initialized()) {
+             ClassPrelinker::maybe_preinit_class(ik, CHECK);
            }
          }
        }
      }
  

*** 645,10 ***
--- 700,28 ---
        break;
      }
      // Class linking includes verification which may load more classes.
      // Keep scanning until we have linked no more classes.
    }
+ 
+   // Resolve constant pool entries -- we don't load any new classes during this stage
+   for (int i = 0; i < collect_cld.nof_cld(); i++) {
+     ClassLoaderData* cld = collect_cld.cld_at(i);
+     for (Klass* klass = cld->klasses(); klass != nullptr; klass = klass->next_link()) {
+       if (klass->is_instance_klass()) {
+         InstanceKlass* ik = InstanceKlass::cast(klass);
+         ClassPrelinker::dumptime_resolve_constants(ik, CHECK);
+         if (CDSConfig::is_dumping_preimage_static_archive()) {
+           ClassPrelinker::record_reflection_data_flags_for_preimage(ik, CHECK);
+         }
+       }
+     }
+   }
+ 
+   if (CDSConfig::is_dumping_final_static_archive()) {
+     ClassPrelinker::apply_final_image_eager_linkage(CHECK);
+   }
  }
  
  void MetaspaceShared::prepare_for_dumping() {
    assert(CDSConfig::is_dumping_archive(), "sanity");
    CDSConfig::check_unsupported_dumping_properties();

*** 658,11 ***
  // Preload classes from a list, populate the shared spaces and dump to a
  // file.
  void MetaspaceShared::preload_and_dump() {
    EXCEPTION_MARK;
    ResourceMark rm(THREAD);
!   preload_and_dump_impl(THREAD);
    if (HAS_PENDING_EXCEPTION) {
      if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
        log_error(cds)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
                       SIZE_FORMAT "M", MaxHeapSize/M);
        MetaspaceShared::unrecoverable_writing_error();
--- 731,19 ---
  // Preload classes from a list, populate the shared spaces and dump to a
  // file.
  void MetaspaceShared::preload_and_dump() {
    EXCEPTION_MARK;
    ResourceMark rm(THREAD);
!   HandleMark hm(THREAD);
+ 
+   if (CDSConfig::is_dumping_final_static_archive() && PrintTrainingInfo) {
+     tty->print_cr("==================== archived_training_data ** before dumping ====================");
+     TrainingData::print_archived_training_data_on(tty);
+   }
+ 
+   StaticArchiveBuilder builder;
+   preload_and_dump_impl(builder, THREAD);
    if (HAS_PENDING_EXCEPTION) {
      if (PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())) {
        log_error(cds)("Out of memory. Please run with a larger Java heap, current MaxHeapSize = "
                       SIZE_FORMAT "M", MaxHeapSize/M);
        MetaspaceShared::unrecoverable_writing_error();

*** 759,29 ***
  
    log_info(cds)("Loading classes to share: done.");
    log_info(cds)("Shared spaces: preloaded %d classes", class_count);
  }
  
! void MetaspaceShared::preload_and_dump_impl(TRAPS) {
!   preload_classes(CHECK);
  
!   if (SharedArchiveConfigFile) {
!     log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
!     read_extra_data(THREAD, SharedArchiveConfigFile);
!     log_info(cds)("Reading extra data: done.");
    }
  
    // Rewrite and link classes
    log_info(cds)("Rewriting and linking classes ...");
- 
    // Link any classes which got missed. This would happen if we have loaded classes that
    // were not explicitly specified in the classlist. E.g., if an interface implemented by class K
    // fails verification, all other interfaces that were not specified in the classlist but
    // are implemented by K are not verified.
    link_shared_classes(false/*not from jcmd*/, CHECK);
    log_info(cds)("Rewriting and linking classes: done");
  
  #if INCLUDE_CDS_JAVA_HEAP
    if (CDSConfig::is_dumping_heap()) {
      if (!HeapShared::is_archived_boot_layer_available(THREAD)) {
        log_info(cds)("archivedBootLayer not available, disabling full module graph");
        CDSConfig::disable_dumping_full_module_graph();
--- 840,53 ---
  
    log_info(cds)("Loading classes to share: done.");
    log_info(cds)("Shared spaces: preloaded %d classes", class_count);
  }
  
! void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) {
!   if (CDSConfig::is_dumping_classic_static_archive()) {
+     // We are running with -Xshare:dump
+     preload_classes(CHECK);
  
!     if (SharedArchiveConfigFile) {
!       log_info(cds)("Reading extra data from %s ...", SharedArchiveConfigFile);
!       read_extra_data(THREAD, SharedArchiveConfigFile);
!       log_info(cds)("Reading extra data: done.");
+     }
    }
  
+ #if INCLUDE_CDS_JAVA_HEAP
+   if (CDSConfig::is_dumping_heap() && ArchiveInvokeDynamic) {
+     // We also assume no other Java threads are running
+     // This makes sure that the MethodType and MethodTypeForm objects are clean.
+     JavaValue result(T_VOID);
+     JavaCalls::call_static(&result, vmClasses::MethodType_klass(),
+                            vmSymbols::dumpSharedArchive(),
+                            vmSymbols::void_method_signature(),
+                            CHECK);
+   }
+ #endif
+ 
    // Rewrite and link classes
    log_info(cds)("Rewriting and linking classes ...");
    // Link any classes which got missed. This would happen if we have loaded classes that
    // were not explicitly specified in the classlist. E.g., if an interface implemented by class K
    // fails verification, all other interfaces that were not specified in the classlist but
    // are implemented by K are not verified.
    link_shared_classes(false/*not from jcmd*/, CHECK);
    log_info(cds)("Rewriting and linking classes: done");
  
+   if (CDSConfig::is_dumping_final_static_archive()) {
+     assert(RecordTraining == false, "must be");
+     RecordTraining = true;
+   }
+ 
+   TrainingData::init_dumptime_table(CHECK); // captures TrainingDataSetLocker
+ 
+   _method_handle_intrinsics = new (mtClassShared) GrowableArray<Method*>(256, mtClassShared);
+   SystemDictionary::get_all_method_handle_intrinsics(_method_handle_intrinsics);
+ 
  #if INCLUDE_CDS_JAVA_HEAP
    if (CDSConfig::is_dumping_heap()) {
      if (!HeapShared::is_archived_boot_layer_available(THREAD)) {
        log_info(cds)("archivedBootLayer not available, disabling full module graph");
        CDSConfig::disable_dumping_full_module_graph();

*** 790,26 ***
      ArchiveHeapWriter::init();
      if (CDSConfig::is_dumping_full_module_graph()) {
        HeapShared::reset_archived_object_states(CHECK);
      }
  
      // Do this at the very end, when no Java code will be executed. Otherwise
      // some new strings may be added to the intern table.
      StringTable::allocate_shared_strings_array(CHECK);
    }
  #endif
  
!   VM_PopulateDumpSharedSpace op;
    VMThread::execute(&op);
  }
  
  // Returns true if the class's status has changed.
  bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) {
    ExceptionMark em(current);
    JavaThread* THREAD = current; // For exception macros.
    assert(CDSConfig::is_dumping_archive(), "sanity");
!   if (!ik->is_shared() && ik->is_loaded() && !ik->is_linked() && ik->can_be_verified_at_dumptime() &&
        !SystemDictionaryShared::has_class_failed_verification(ik)) {
      bool saved = BytecodeVerificationLocal;
      if (ik->is_shared_unregistered_class() && ik->class_loader() == nullptr) {
        // The verification decision is based on BytecodeVerificationRemote
        // for non-system classes. Since we are using the null classloader
--- 895,133 ---
      ArchiveHeapWriter::init();
      if (CDSConfig::is_dumping_full_module_graph()) {
        HeapShared::reset_archived_object_states(CHECK);
      }
  
+     if (ArchiveLoaderLookupCache) {
+       SystemDictionaryShared::create_loader_positive_lookup_cache(CHECK);
+     }
+ 
      // Do this at the very end, when no Java code will be executed. Otherwise
      // some new strings may be added to the intern table.
      StringTable::allocate_shared_strings_array(CHECK);
    }
  #endif
  
!   VM_PopulateDumpSharedSpace op(builder);
    VMThread::execute(&op);
+   FileMapInfo* mapinfo = op.mapinfo();
+   ArchiveHeapInfo* heap_info = op.heap_info();
+ 
+   if (CDSConfig::is_dumping_preimage_static_archive()) {
+     write_static_archive(&builder, mapinfo, heap_info);
+     fork_and_dump_final_static_archive();
+   } else if (CDSConfig::is_dumping_final_static_archive()) {
+     RecordTraining = false;
+     if (StoreCachedCode && CachedCodeFile != nullptr) { // FIXME: new workflow -- remove the CachedCodeFile flag
+       if (log_is_enabled(Info, cds, jit)) {
+         CDSAccess::test_heap_access_api();
+       }
+ 
+       // We have just created the final image. Let's run the AOT compiler
+       if (PrintTrainingInfo) {
+         tty->print_cr("==================== archived_training_data ** after dumping ====================");
+         TrainingData::print_archived_training_data_on(tty);
+       }
+ 
+       CDSConfig::enable_dumping_cached_code();
+       {
+         builder.start_cc_region();
+         Precompiler::compile_cached_code(&builder, CHECK);
+         builder.end_cc_region();
+       }
+       CDSConfig::disable_dumping_cached_code();
+ 
+       SCCache::close(); // Write final data and close archive
+     }
+     write_static_archive(&builder, mapinfo, heap_info);
+   } else {
+     write_static_archive(&builder, mapinfo, heap_info);
+   }
+ }
+ 
+ void MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo *mapinfo, ArchiveHeapInfo* heap_info) {
+   // relocate the data so that it can be mapped to MetaspaceShared::requested_base_address()
+   // without runtime relocation.
+   builder->relocate_to_requested();
+ 
+   mapinfo->open_for_write();
+   builder->write_archive(mapinfo, heap_info);
+ 
+   if (PrintSystemDictionaryAtExit) {
+     SystemDictionary::print();
+   }
+ 
+   if (AllowArchivingWithJavaAgent) {
+     log_warning(cds)("This archive was created with AllowArchivingWithJavaAgent. It should be used "
+             "for testing purposes only and should not be used in a production environment");
+   }
+ }
+ 
+ void MetaspaceShared::fork_and_dump_final_static_archive() {
+   assert(CDSConfig::is_dumping_preimage_static_archive(), "sanity");
+ 
+   ResourceMark rm;
+   stringStream st;
+   st.print("%s%sbin%sjava", Arguments::get_java_home(), os::file_separator(), os::file_separator());
+   const char* cp = Arguments::get_appclasspath();
+   if (cp != nullptr && strlen(cp) > 0 && strcmp(cp, ".") != 0) {
+     st.print(" -cp ");  st.print_raw(cp);
+   }
+   for (int i = 0; i < Arguments::num_jvm_flags(); i++) {
+     st.print(" %s", Arguments::jvm_flags_array()[i]);
+   }
+   for (int i = 0; i < Arguments::num_jvm_args(); i++) {
+     st.print(" %s", Arguments::jvm_args_array()[i]);
+   }
+   st.print(" -XX:CDSPreimage=%s", SharedArchiveFile);
+ 
+   const char* cmd = st.freeze();
+   if (CDSManualFinalImage) {
+     tty->print_cr("-XX:+CDSManualFinalImage is specified");
+     tty->print_cr("Please manually execute the following command to create the final CDS image:");
+     tty->print("    "); tty->print_raw_cr(cmd);
+   } else {
+     log_info(cds)("Launching child process to create final CDS image:");
+     log_info(cds)("    %s", cmd);
+     int status = os::fork_and_exec(cmd);
+     if (status != 0) {
+       log_error(cds)("Child process finished; status = %d", status);
+       log_error(cds)("To reproduce the error");
+       ResourceMark rm;
+       LogStream ls(Log(cds)::error());
+       ls.print("    "); ls.print_raw_cr(cmd);
+       vm_direct_exit(status);
+     } else {
+       log_info(cds)("Child process finished; status = %d", status);
+       status = remove(SharedArchiveFile);
+       if (status != 0) {
+         log_error(cds)("Failed to remove CDSPreimage file %s", SharedArchiveFile);
+       } else {
+         log_info(cds)("Removed CDSPreimage file %s", SharedArchiveFile);
+       }
+     }
+   }
  }
  
  // Returns true if the class's status has changed.
  bool MetaspaceShared::try_link_class(JavaThread* current, InstanceKlass* ik) {
    ExceptionMark em(current);
    JavaThread* THREAD = current; // For exception macros.
    assert(CDSConfig::is_dumping_archive(), "sanity");
! 
+   if (ik->is_shared() && !CDSConfig::is_dumping_final_static_archive()) {
+     assert(CDSConfig::is_dumping_dynamic_archive(), "must be");
+     return false;
+   }
+ 
+   if (ik->is_loaded() && !ik->is_linked() && ik->can_be_verified_at_dumptime() &&
        !SystemDictionaryShared::has_class_failed_verification(ik)) {
      bool saved = BytecodeVerificationLocal;
      if (ik->is_shared_unregistered_class() && ik->class_loader() == nullptr) {
        // The verification decision is based on BytecodeVerificationRemote
        // for non-system classes. Since we are using the null classloader

*** 918,11 ***
  
  void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
    assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled");
    MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
  
!   FileMapInfo* static_mapinfo = open_static_archive();
    FileMapInfo* dynamic_mapinfo = nullptr;
  
    if (static_mapinfo != nullptr) {
      log_info(cds)("Core region alignment: " SIZE_FORMAT, static_mapinfo->core_region_alignment());
      dynamic_mapinfo = open_dynamic_archive();
--- 1130,11 ---
  
  void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
    assert(UseSharedSpaces, "Must be called when UseSharedSpaces is enabled");
    MapArchiveResult result = MAP_ARCHIVE_OTHER_FAILURE;
  
!   FileMapInfo* static_mapinfo = FileMapInfo::current_info();
    FileMapInfo* dynamic_mapinfo = nullptr;
  
    if (static_mapinfo != nullptr) {
      log_info(cds)("Core region alignment: " SIZE_FORMAT, static_mapinfo->core_region_alignment());
      dynamic_mapinfo = open_dynamic_archive();

*** 965,10 ***
--- 1177,14 ---
      log_info(cds)("Unable to map shared spaces");
      if (PrintSharedArchiveAndExit) {
        MetaspaceShared::unrecoverable_loading_error("Unable to use shared archive.");
      } else if (RequireSharedSpaces) {
        MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces");
+     } else if (CDSConfig::is_dumping_final_static_archive()) {
+       assert(CDSPreimage != nullptr, "must be");
+       log_error(cds)("Unable to map shared spaces for CDSPreimage = %s", CDSPreimage);
+       MetaspaceShared::unrecoverable_loading_error();
      }
    }
  
    // If mapping failed and -XShare:on, the vm should exit
    bool has_failed = false;

*** 979,23 ***
    if (dynamic_mapinfo != nullptr && !dynamic_mapinfo->is_mapped()) {
      has_failed = true;
      delete dynamic_mapinfo;
    }
    if (RequireSharedSpaces && has_failed) {
        MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces");
    }
  }
  
! FileMapInfo* MetaspaceShared::open_static_archive() {
    const char* static_archive = CDSConfig::static_archive_path();
    assert(static_archive != nullptr, "sanity");
    FileMapInfo* mapinfo = new FileMapInfo(static_archive, true);
    if (!mapinfo->initialize()) {
      delete(mapinfo);
!     return nullptr;
    }
-   return mapinfo;
  }
  
  FileMapInfo* MetaspaceShared::open_dynamic_archive() {
    if (CDSConfig::is_dumping_dynamic_archive()) {
      return nullptr;
--- 1195,30 ---
    if (dynamic_mapinfo != nullptr && !dynamic_mapinfo->is_mapped()) {
      has_failed = true;
      delete dynamic_mapinfo;
    }
    if (RequireSharedSpaces && has_failed) {
+     // static archive mapped but dynamic archive failed
        MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces");
    }
  }
  
! // This is called very early at VM start up to get the size of the cached_code region, which
+ // is used in CodeCache::initialize_heaps()
+ void MetaspaceShared::open_static_archive() {
+   if (!UseSharedSpaces) {
+     return;
+   }
    const char* static_archive = CDSConfig::static_archive_path();
    assert(static_archive != nullptr, "sanity");
    FileMapInfo* mapinfo = new FileMapInfo(static_archive, true);
    if (!mapinfo->initialize()) {
      delete(mapinfo);
!   } else {
+     FileMapRegion* r = mapinfo->region_at(MetaspaceShared::cc);
+     CDSAccess::set_cached_code_size(r->used());
    }
  }
  
  FileMapInfo* MetaspaceShared::open_dynamic_archive() {
    if (CDSConfig::is_dumping_dynamic_archive()) {
      return nullptr;

*** 1466,10 ***
--- 1689,13 ---
    // done after ReadClosure.
    static_mapinfo->patch_heap_embedded_pointers();
    ArchiveHeapLoader::finish_initialization();
  
    CDS_JAVA_HEAP_ONLY(Universe::update_archived_basic_type_mirrors());
+   CDS_JAVA_HEAP_ONLY(Universe::update_exception_instances());
+ 
+   SCCache::new_workflow_load_cache();
  
    // Close the mapinfo file
    static_mapinfo->close();
  
    static_mapinfo->unmap_region(MetaspaceShared::bm);

*** 1504,10 ***
--- 1730,16 ---
      if (dynamic_mapinfo != nullptr) {
        tty->print_cr("\n\nDynamic archive name: %s", dynamic_mapinfo->full_path());
        tty->print_cr("Dynamic archive version %d", dynamic_mapinfo->version());
        SystemDictionaryShared::print_shared_archive(tty, false/*dynamic*/);
      }
+     TrainingData::print_archived_training_data_on(tty);
+ 
+     if (LoadCachedCode) {
+       tty->print_cr("\n\nCached Code file: %s", CachedCodeFile);
+       SCCache::print_on(tty);
+     }
  
      // collect shared symbols and strings
      CountSharedSymbols cl;
      SymbolTable::shared_symbols_do(&cl);
      tty->print_cr("Number of shared symbols: %d", cl.total());
< prev index next >