< prev index next >

src/hotspot/share/cds/metaspaceShared.cpp

Print this page
*** 20,20 ***
--- 20,22 ---
   * or visit www.oracle.com if you need additional information or have any
   * questions.
   *
   */
  
+ #include "cds/aotClassInitializer.hpp"
  #include "cds/aotArtifactFinder.hpp"
  #include "cds/aotClassInitializer.hpp"
  #include "cds/aotClassLinker.hpp"
  #include "cds/aotClassLocation.hpp"
  #include "cds/aotConstantPoolResolver.hpp"
  #include "cds/aotLinkedClassBulkLoader.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/classListParser.hpp"
  #include "cds/classListWriter.hpp"
  #include "cds/cppVtables.hpp"

*** 57,30 ***
--- 59,37 ---
  #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"
  #include "logging/logMessage.hpp"
  #include "logging/logStream.hpp"
  #include "memory/memoryReserver.hpp"
  #include "memory/metaspace.hpp"
  #include "memory/metaspaceClosure.hpp"
+ #include "memory/oopFactory.hpp"
  #include "memory/resourceArea.hpp"
  #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"

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

*** 286,10 ***
--- 296,27 ---
    return aligned_base;
  }
  
  void MetaspaceShared::initialize_for_static_dump() {
    assert(CDSConfig::is_dumping_static_archive(), "sanity");
+ 
+   if (CDSConfig::is_dumping_preimage_static_archive() || CDSConfig::is_dumping_final_static_archive()) {
+     if (!((UseG1GC || UseParallelGC || UseSerialGC || UseEpsilonGC || UseShenandoahGC) && UseCompressedClassPointers)) {
+       const char* error;
+       if (CDSConfig::is_experimental_leyden_workflow()) {
+         error = "Cannot create the CacheDataStore";
+       } else if (CDSConfig::is_dumping_preimage_static_archive()) {
+         error = "Cannot create the AOT configuration file";
+       } else {
+         error = "Cannot create the AOT cache";
+       }
+ 
+       vm_exit_during_initialization(error,
+                                     "UseCompressedClassPointers must be enabled, and collector must be G1, Parallel, Serial, Epsilon, or Shenandoah");
+     }
+   }
+ 
    log_info(cds)("Core region alignment: %zu", core_region_alignment());
    // The max allowed size for CDS archive. We use this to limit SharedBaseAddress
    // to avoid address space wrap around.
    size_t cds_max;
    const size_t reserve_alignment = core_region_alignment();

*** 478,20 ***
--- 505,23 ---
    StringTable::serialize_shared_table_header(soc);
    HeapShared::serialize_tables(soc);
    SystemDictionaryShared::serialize_dictionary_headers(soc);
    AOTLinkedClassBulkLoader::serialize(soc, true);
    FinalImageRecipes::serialize(soc);
+   TrainingData::serialize(soc);
    InstanceMirrorKlass::serialize_offsets(soc);
  
    // Dump/restore well known classes (pointers)
    SystemDictionaryShared::serialize_vm_classes(soc);
    soc->do_tag(--tag);
  
    CDS_JAVA_HEAP_ONLY(ClassLoaderDataShared::serialize(soc);)
    soc->do_ptr((void**)&_archived_method_handle_intrinsics);
  
    LambdaFormInvokers::serialize(soc);
+   AdapterHandlerLibrary::serialize_shared_table_header(soc);
+ 
    soc->do_tag(666);
  }
  
  static void rewrite_nofast_bytecode(const methodHandle& method) {
    BytecodeStream bcs(method);

*** 562,10 ***
--- 592,11 ---
    virtual void iterate_roots(MetaspaceClosure* it) {
      AOTArtifactFinder::all_cached_classes_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

*** 601,15 ***
--- 632,22 ---
    cl_config = AOTClassLocationConfig::dumptime()->write_to_archive();
    AOTClassLinker::write_to_archive();
    if (CDSConfig::is_dumping_preimage_static_archive()) {
      FinalImageRecipes::record_recipes();
    }
+ 
+   TrainingData::dump_training_data();
+ 
    MetaspaceShared::write_method_handle_intrinsics();
  
    // Write lambform lines into archive
    LambdaFormInvokers::dump_static_archive_invokers();
  
+   if (CDSConfig::is_dumping_adapters()) {
+     AdapterHandlerLibrary::archive_adapter_table();
+   }
+ 
    // Write the other data to the output array.
    DumpRegion* ro_region = ArchiveBuilder::current()->ro_region();
    char* start = ro_region->top();
    WriteClosure wc(ro_region);
    MetaspaceShared::serialize(&wc);

*** 671,10 ***
--- 709,13 ---
    if (CDSConfig::is_dumping_lambdas_in_legacy_mode()) {
      log_info(cds)("Adjust lambda proxy class dictionary");
      LambdaProxyClassDictionary::adjust_dumptime_table();
    }
  
+   log_info(cds)("Make training data shareable");
+   _builder.make_training_data_shareable();
+ 
    // 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

*** 725,16 ***
--- 766,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.
      //

*** 758,10 ***
--- 803,13 ---
        OopHandle mirror = mirrors->at(i);
        InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve()));
        if (may_be_eagerly_linked(ik)) {
          has_linked |= try_link_class(THREAD, ik);
        }
+       if (CDSConfig::is_dumping_heap() && ik->is_linked() && !ik->is_initialized()) {
+         AOTClassInitializer::maybe_preinit_class(ik, CHECK);
+       }
      }
  
      if (!has_linked) {
        break;
      }

*** 776,10 ***
--- 824,13 ---
      const GrowableArray<OopHandle>* mirrors = collect_classes.mirrors();
      for (int i = 0; i < mirrors->length(); i++) {
        OopHandle mirror = mirrors->at(i);
        InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(mirror.resolve()));
        AOTConstantPoolResolver::dumptime_resolve_constants(ik, CHECK);
+       if (CDSConfig::is_dumping_preimage_static_archive()) {
+         FinalImageRecipes::add_reflection_data_flags(ik, CHECK);
+       }
      }
    }
  
    if (CDSConfig::is_dumping_final_static_archive()) {
      FinalImageRecipes::apply_recipes(CHECK);

*** 789,10 ***
--- 840,17 ---
  // Preload classes from a list, populate the shared spaces and dump to a
  // file.
  void MetaspaceShared::preload_and_dump(TRAPS) {
    CDSConfig::DumperThreadMark dumper_thread_mark(THREAD);
    ResourceMark rm(THREAD);
+   HandleMark hm(THREAD);
+ 
+   if (CDSConfig::is_dumping_final_static_archive() && AOTPrintTrainingInfo) {
+     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 = "

*** 801,18 ***
      } else {
        log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
                       java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
        MetaspaceShared::writing_error("Unexpected exception, use -Xlog:cds,exceptions=trace for detail");
      }
    }
  
    if (CDSConfig::new_aot_flags_used()) {
      if (CDSConfig::is_dumping_preimage_static_archive()) {
        // We are in the JVM that runs the training run. Continue execution,
        // so that it can finish all clean-up and return the correct exit
        // code to the OS.
-       tty->print_cr("AOTConfiguration recorded: %s", AOTConfiguration);
      } else {
        // The JLI launcher only recognizes the "old" -Xshare:dump flag.
        // When the new -XX:AOTMode=create flag is used, we can't return
        // to the JLI launcher, as the launcher will fail when trying to
        // run the main class, which is not what we want.
--- 859,20 ---
      } else {
        log_error(cds)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
                       java_lang_String::as_utf8_string(java_lang_Throwable::message(PENDING_EXCEPTION)));
        MetaspaceShared::writing_error("Unexpected exception, use -Xlog:cds,exceptions=trace for detail");
      }
+     if (CDSConfig::is_experimental_leyden_workflow()) {
+       vm_exit(1);
+     }
    }
  
    if (CDSConfig::new_aot_flags_used()) {
      if (CDSConfig::is_dumping_preimage_static_archive()) {
        // We are in the JVM that runs the training run. Continue execution,
        // so that it can finish all clean-up and return the correct exit
        // code to the OS.
      } else {
        // The JLI launcher only recognizes the "old" -Xshare:dump flag.
        // When the new -XX:AOTMode=create flag is used, we can't return
        // to the JLI launcher, as the launcher will fail when trying to
        // run the main class, which is not what we want.

*** 900,11 ***
--- 960,24 ---
  
    // Exercise FileSystem and URL code
    CDSProtectionDomain::to_file_URL("dummy.jar", Handle(), CHECK);
  }
  
+ bool MetaspaceShared::is_recording_preimage_static_archive() {
+   if (CDSConfig::is_dumping_preimage_static_archive()) {
+       return _preimage_static_archive_dumped == 0;
+   }
+   return false;
+ }
+ 
  void MetaspaceShared::preload_and_dump_impl(StaticArchiveBuilder& builder, TRAPS) {
+   if (CDSConfig::is_dumping_preimage_static_archive()) {
+     if (Atomic::cmpxchg(&_preimage_static_archive_dumped, 0, 1) != 0) {
+       return;
+     }
+   }
+ 
    if (CDSConfig::is_dumping_classic_static_archive()) {
      // We are running with -Xshare:dump
      preload_classes(CHECK);
  
      if (SharedArchiveConfigFile) {

*** 953,10 ***
--- 1026,19 ---
    // fails verification, all other interfaces that were not specified in the classlist but
    // are implemented by K are not verified.
    link_shared_classes(CHECK);
    log_info(cds)("Rewriting and linking classes: done");
  
+   if (CDSConfig::is_dumping_final_static_archive()) {
+     assert(!AOTRecordTraining, "must be");
+     if (CDSConfig::is_dumping_aot_linked_classes()) {
+       AOTRecordTraining = true;
+     }
+   }
+ 
+   TrainingData::init_dumptime_table(CHECK); // captures TrainingDataSetLocker
+ 
    if (CDSConfig::is_dumping_regenerated_lambdaform_invokers()) {
      LambdaFormInvokers::regenerate_holder_classes(CHECK);
    }
  
  #if INCLUDE_CDS_JAVA_HEAP

*** 965,20 ***
      if (CDSConfig::is_dumping_full_module_graph()) {
        ClassLoaderDataShared::ensure_module_entry_tables_exist();
        HeapShared::reset_archived_object_states(CHECK);
      }
  
!     if (CDSConfig::is_dumping_method_handles()) {
!       // This assert means that the MethodType and MethodTypeForm tables won't be
-       // updated concurrently when we are saving their contents into a side table.
-       assert(CDSConfig::allow_only_single_java_thread(), "Required");
- 
-       JavaValue result(T_VOID);
-       JavaCalls::call_static(&result, vmClasses::MethodType_klass(),
-                              vmSymbols::createArchivedObjects(),
-                              vmSymbols::void_method_signature(),
-                              CHECK);
      }
  
      if (CDSConfig::is_initing_classes_at_dump_time()) {
        // java.lang.Class::reflectionFactory cannot be archived yet. We set this field
        // to null, and it will be initialized again at runtime.
--- 1047,12 ---
      if (CDSConfig::is_dumping_full_module_graph()) {
        ClassLoaderDataShared::ensure_module_entry_tables_exist();
        HeapShared::reset_archived_object_states(CHECK);
      }
  
!     if (ArchiveLoaderLookupCache) {
!       SystemDictionaryShared::create_loader_positive_lookup_cache(CHECK);
      }
  
      if (CDSConfig::is_initing_classes_at_dump_time()) {
        // java.lang.Class::reflectionFactory cannot be archived yet. We set this field
        // to null, and it will be initialized again at runtime.

*** 1002,12 ***
    }
  #endif
  
    VM_PopulateDumpSharedSpace op(builder);
    VMThread::execute(&op);
  
!   if (!write_static_archive(&builder, op.map_info(), op.heap_info())) {
      THROW_MSG(vmSymbols::java_io_IOException(), "Encountered error while dumping");
    }
  }
  
  bool MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info) {
--- 1076,52 ---
    }
  #endif
  
    VM_PopulateDumpSharedSpace op(builder);
    VMThread::execute(&op);
+   FileMapInfo* mapinfo = op.map_info();
+   ArchiveHeapInfo* heap_info = op.heap_info();
+ 
+   if (CDSConfig::is_dumping_final_static_archive()) {
+     AOTRecordTraining = false;
+     if (StoreCachedCode) {
+       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 (AOTPrintTrainingInfo) {
+         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);
+         // Write the contents to cached code region and close SCCache before packing the region
+         SCCache::close();
+         builder.end_cc_region();
+       }
+       CDSConfig::disable_dumping_cached_code();
+     }
+   }
+ 
+   bool status = write_static_archive(&builder, mapinfo, heap_info);
+   if (status && CDSConfig::is_dumping_preimage_static_archive()) {
+     if (CDSConfig::is_experimental_leyden_workflow()) {
+       fork_and_dump_final_static_archive_experimental_leyden_workflow(CHECK);
+     } else {
+       tty->print_cr("%s AOTConfiguration recorded: %s",
+                     CDSConfig::has_temp_aot_config_file() ? "Temporary" : "", AOTConfiguration);
+       if (CDSConfig::is_one_step_training()) {
+         fork_and_dump_final_static_archive(CHECK);
+       }
+     }
+   }
+ 
+   if (!status) {
      THROW_MSG(vmSymbols::java_io_IOException(), "Encountered error while dumping");
    }
  }
  
  bool MetaspaceShared::write_static_archive(ArchiveBuilder* builder, FileMapInfo* map_info, ArchiveHeapInfo* heap_info) {

*** 1026,10 ***
--- 1140,210 ---
              "for testing purposes only and should not be used in a production environment", CDSConfig::type_of_archive_being_loaded());
    }
    return true;
  }
  
+ static void print_java_launcher(outputStream* st) {
+   st->print("%s%sbin%sjava", Arguments::get_java_home(), os::file_separator(), os::file_separator());
+ }
+ 
+ static void append_args(GrowableArray<Handle>* args, const char* arg, TRAPS) {
+   Handle string = java_lang_String::create_from_str(arg, CHECK);
+   args->append(string);
+ }
+ 
+ // Pass all options in Arguments::jvm_args_array() to a child JVM process
+ // using the JAVA_TOOL_OPTIONS environment variable.
+ static int exec_jvm_with_java_tool_options(const char* java_launcher_path, TRAPS) {
+   ResourceMark rm(THREAD);
+   HandleMark hm(THREAD);
+   GrowableArray<Handle> args;
+ 
+   const char* cp = Arguments::get_appclasspath();
+   if (cp != nullptr && strlen(cp) > 0 && strcmp(cp, ".") != 0) {
+     // We cannot use "-cp", because "-cp" is only interpreted by the java launcher,
+     // and is not interpreter by arguments.cpp when it loads args from JAVA_TOOL_OPTIONS
+     stringStream ss;
+     ss.print("-Djava.class.path=");
+     ss.print_raw(cp);
+     append_args(&args, ss.freeze(), CHECK_0);
+     // CDS$ProcessLauncher::execWithJavaToolOptions() must unset CLASSPATH, which has
+     // a higher priority than -Djava.class.path=
+   }
+ 
+   // Pass all arguments. These include those from JAVA_TOOL_OPTIONS and _JAVA_OPTIONS.
+   for (int i = 0; i < Arguments::num_jvm_args(); i++) {
+     const char* arg = Arguments::jvm_args_array()[i];
+     if (strncmp("-XX:AOTMode", arg, 11) == 0) {
+       // Filter it out. We will set AOTMode=create below.
+     } else {
+       append_args(&args, arg, CHECK_0);
+     }
+   }
+ 
+   // We don't pass Arguments::jvm_flags_array(), as those will be added by
+   // the child process when it loads .hotspotrc
+ 
+   if (CDSConfig::is_experimental_leyden_workflow()) {
+     stringStream ss;
+     ss.print("-XX:CDSPreimage=");
+     ss.print_raw(CDSPreimage);
+     append_args(&args, ss.freeze(), CHECK_0);
+   } else {
+     if (CDSConfig::has_temp_aot_config_file()) {
+       stringStream ss;
+       ss.print("-XX:AOTConfiguration=");
+       ss.print_raw(AOTConfiguration);
+       append_args(&args, ss.freeze(), CHECK_0);
+     }
+     append_args(&args, "-XX:AOTMode=create", CHECK_0);
+   }
+ 
+   GrowableArray<const char*> aot_tool_options;
+   jint code;
+   if ((code = Arguments::parse_aot_tool_options_environment_variable(&aot_tool_options)) != JNI_OK) {
+     THROW_MSG_0(vmSymbols::java_lang_InternalError(), err_msg("failed to parse AOT_TOOL_OPTIONS: %d", code));
+   }
+   for (int i = 0; i < aot_tool_options.length(); i++) {
+     append_args(&args, aot_tool_options.at(i), CHECK_0);
+   }
+ 
+   Symbol* klass_name = SymbolTable::new_symbol("jdk/internal/misc/CDS$ProcessLauncher");
+   Klass* k = SystemDictionary::resolve_or_fail(klass_name, true, CHECK_0);
+   Symbol* methodName = SymbolTable::new_symbol("execWithJavaToolOptions");
+   Symbol* methodSignature = SymbolTable::new_symbol("(Ljava/lang/String;[Ljava/lang/String;)I");
+ 
+   Handle launcher = java_lang_String::create_from_str(java_launcher_path, CHECK_0);
+   objArrayOop array = oopFactory::new_objArray(vmClasses::String_klass(), args.length(), CHECK_0);
+   for (int i = 0; i < args.length(); i++) {
+     array->obj_at_put(i, args.at(i)());
+   }
+   objArrayHandle launcher_args(THREAD, array);
+ 
+   // The following call will pass all options inside the JAVA_TOOL_OPTIONS env variable to
+   // the child process. It will also clear the _JAVA_OPTIONS and CLASSPATH env variables for
+   // the child process.
+   //
+   // Note: the env variables are set only for the child process. They are not changed
+   // for the current process. See java.lang.ProcessBuilder::environment().
+   JavaValue result(T_OBJECT);
+   JavaCallArguments javacall_args(2);
+   javacall_args.push_oop(launcher);
+   javacall_args.push_oop(launcher_args);
+   JavaCalls::call_static(&result,
+                           InstanceKlass::cast(k),
+                           methodName,
+                           methodSignature,
+                           &javacall_args,
+                           CHECK_0);
+   return result.get_jint();
+ }
+ 
+ // This is for debugging purposes only (-XX:+CDSManualFinalImage) so we don't bother
+ // quoating any special characters. The user should avoid using special chars.
+ static void print_vm_arguments(outputStream* st) {
+   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_args(); i++) {
+     st->print(" %s", Arguments::jvm_args_array()[i]);
+   }
+ }
+ 
+ void MetaspaceShared::fork_and_dump_final_static_archive_experimental_leyden_workflow(TRAPS) {
+   assert(CDSConfig::is_dumping_preimage_static_archive(), "sanity");
+ 
+   ResourceMark rm;
+   stringStream ss;
+   print_java_launcher(&ss);
+ 
+   if (CDSManualFinalImage) {
+     print_vm_arguments(&ss);
+     ss.print(" -XX:CDSPreimage=%s", SharedArchiveFile);
+     const char* cmd = ss.freeze();
+ 
+     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);
+ 
+     // The following is useful if the dumping was trigger by a script that builds
+     // a complex command-line.
+     tty->print_cr("Note: to recreate the preimage only:");
+     tty->print_cr("    rm -f %s", CacheDataStore);
+     tty->print("    ");
+     print_java_launcher(tty);
+     print_vm_arguments(tty);
+     if (Arguments::java_command() != nullptr) {
+       tty->print(" %s", Arguments::java_command());
+     }
+     tty->cr();
+   } else {
+     const char* cmd = ss.freeze();
+     log_info(cds)("Launching child process to create final CDS image:");
+     log_info(cds)("    %s", cmd);
+     int status = exec_jvm_with_java_tool_options(cmd, CHECK);
+     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);
+ 
+       // The following is useful if the dumping was trigger by a script that builds
+       // a complex command-line.
+       ls.print_cr("Note: to recreate the preimage only:");
+       ls.print_cr("    rm -f %s", CacheDataStore);
+       ls.print("    ");
+       print_java_launcher(&ls);
+       print_vm_arguments(&ls);
+       ls.print(" -XX:+UnlockDiagnosticVMOptions -XX:+CDSManualFinalImage");
+       if (Arguments::java_command() != nullptr) {
+         ls.print(" %s", Arguments::java_command());
+       }
+       ls.cr();
+ 
+       vm_direct_exit(status);
+     } else {
+       log_info(cds)("Child process finished; status = %d", status);
+       // On Windows, need WRITE permission to remove the file.
+       WINDOWS_ONLY(chmod(CDSPreimage, _S_IREAD | _S_IWRITE));
+       status = remove(CDSPreimage);
+       if (status != 0) {
+         log_error(cds)("Failed to remove CDSPreimage file %s", CDSPreimage);
+       } else {
+         log_info(cds)("Removed CDSPreimage file %s", CDSPreimage);
+       }
+     }
+   }
+ }
+ 
+ void MetaspaceShared::fork_and_dump_final_static_archive(TRAPS) {
+   assert(CDSConfig::is_dumping_preimage_static_archive(), "sanity");
+ 
+   ResourceMark rm;
+   stringStream ss;
+   print_java_launcher(&ss);
+   const char* cmd = ss.freeze();
+   tty->print_cr("Launching child process %s to assemble AOT cache %s using configuration %s", cmd, AOTCacheOutput, AOTConfiguration);
+   int status = exec_jvm_with_java_tool_options(cmd, CHECK);
+   if (status != 0) {
+     log_error(cds)("Child process failed; status = %d", status);
+     // We leave the temp config file for debugging
+   } else if (CDSConfig::has_temp_aot_config_file()) {
+     const char* tmp_config = AOTConfiguration;
+     // On Windows, need WRITE permission to remove the file.
+     WINDOWS_ONLY(chmod(tmp_config, _S_IREAD | _S_IWRITE));
+     status = remove(tmp_config);
+     if (status != 0) {
+       log_error(cds)("Failed to remove temporary AOT configuration file %s", tmp_config);
+     } else {
+       tty->print_cr("Removed temporary AOT configuration file %s", tmp_config);
+     }
+   }
+ }
+ 
  // 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");

*** 1071,11 ***
  }
  
  void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
    if (CDSConfig::is_dumping_heap()) {
      HeapShared::write_heap(&_heap_info);
!   } else {
      CDSConfig::log_reasons_for_not_dumping_heap();
    }
  }
  
  void MetaspaceShared::set_shared_metaspace_range(void* base, void *static_top, void* top) {
--- 1385,11 ---
  }
  
  void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
    if (CDSConfig::is_dumping_heap()) {
      HeapShared::write_heap(&_heap_info);
!   } else if (!CDSConfig::is_dumping_preimage_static_archive()) {
      CDSConfig::log_reasons_for_not_dumping_heap();
    }
  }
  
  void MetaspaceShared::set_shared_metaspace_range(void* base, void *static_top, void* top) {

*** 1139,11 ***
  
  void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
    assert(CDSConfig::is_using_archive(), "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: %zu", static_mapinfo->core_region_alignment());
      dynamic_mapinfo = open_dynamic_archive();
--- 1453,11 ---
  
  void MetaspaceShared::initialize_runtime_shared_and_meta_spaces() {
    assert(CDSConfig::is_using_archive(), "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: %zu", static_mapinfo->core_region_alignment());
      dynamic_mapinfo = open_dynamic_archive();

*** 1185,10 ***
--- 1499,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;

*** 1199,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::input_static_archive_path();
    assert(static_archive != nullptr, "sanity");
    FileMapInfo* mapinfo = new FileMapInfo(static_archive, true);
    if (!mapinfo->open_as_input()) {
      delete(mapinfo);
!     return nullptr;
    }
-   return mapinfo;
  }
  
  FileMapInfo* MetaspaceShared::open_dynamic_archive() {
    if (CDSConfig::is_dumping_dynamic_archive()) {
      return nullptr;
--- 1517,29 ---
    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
+ void MetaspaceShared::open_static_archive() {
+   if (!UseSharedSpaces) { // FIXME -- is this still needed??
+     return;
+   }
    const char* static_archive = CDSConfig::input_static_archive_path();
    assert(static_archive != nullptr, "sanity");
    FileMapInfo* mapinfo = new FileMapInfo(static_archive, true);
    if (!mapinfo->open_as_input()) {
      delete(mapinfo);
!   } else {
+     FileMapRegion* r = mapinfo->region_at(MetaspaceShared::cc);
+     CDSAccess::set_cached_code_size(r->used_aligned());
    }
  }
  
  FileMapInfo* MetaspaceShared::open_dynamic_archive() {
    if (CDSConfig::is_dumping_dynamic_archive()) {
      return nullptr;

*** 1693,10 ***
--- 2017,14 ---
    assert(CDSConfig::is_using_archive(), "must be runtime");
    if (mapinfo == nullptr) {
      return MAP_ARCHIVE_SUCCESS; // The dynamic archive has not been specified. No error has happened -- trivially succeeded.
    }
  
+   if (!mapinfo->validate_aot_class_linking()) {
+     return MAP_ARCHIVE_OTHER_FAILURE;
+   }
+ 
    mapinfo->set_is_mapped(false);
    if (mapinfo->core_region_alignment() != (size_t)core_region_alignment()) {
      log_info(cds)("Unable to map CDS archive -- core_region_alignment() expected: %zu"
                    " actual: %zu", mapinfo->core_region_alignment(), core_region_alignment());
      return MAP_ARCHIVE_OTHER_FAILURE;

*** 1770,10 ***
--- 2098,11 ---
    // Finish up archived heap initialization. These must be
    // done after ReadClosure.
    static_mapinfo->patch_heap_embedded_pointers();
    ArchiveHeapLoader::finish_initialization();
    Universe::load_archived_object_instances();
+   SCCache::initialize();
  
    // Close the mapinfo file
    static_mapinfo->close();
  
    static_mapinfo->unmap_region(MetaspaceShared::bm);

*** 1820,10 ***
--- 2149,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");
+       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 >