< prev index next >

src/hotspot/share/cds/cdsConfig.cpp

Print this page
*** 23,45 ***
   */
  
  #include "precompiled.hpp"
  #include "cds/archiveHeapLoader.hpp"
  #include "cds/cdsConfig.hpp"
  #include "cds/classListWriter.hpp"
  #include "cds/heapShared.hpp"
  #include "classfile/classLoaderDataShared.hpp"
  #include "classfile/moduleEntry.hpp"
  #include "include/jvm_io.h"
  #include "logging/log.hpp"
  #include "memory/universe.hpp"
  #include "runtime/arguments.hpp"
  #include "runtime/java.hpp"
  #include "utilities/defaultStream.hpp"
  
  bool CDSConfig::_is_dumping_static_archive = false;
  bool CDSConfig::_is_dumping_dynamic_archive = false;
  bool CDSConfig::_is_using_optimized_module_handling = true;
  bool CDSConfig::_is_dumping_full_module_graph = true;
  bool CDSConfig::_is_using_full_module_graph = true;
  
  char* CDSConfig::_default_archive_path = nullptr;
  char* CDSConfig::_static_archive_path = nullptr;
  char* CDSConfig::_dynamic_archive_path = nullptr;
  
  int CDSConfig::get_status() {
    assert(Universe::is_fully_initialized(), "status is finalized only after Universe is initialized");
    return (is_dumping_archive()              ? IS_DUMPING_ARCHIVE : 0) |
           (is_dumping_static_archive()       ? IS_DUMPING_STATIC_ARCHIVE : 0) |
           (is_logging_lambda_form_invokers() ? IS_LOGGING_LAMBDA_FORM_INVOKERS : 0) |
!          (is_using_archive()                ? IS_USING_ARCHIVE : 0);
  }
  
- 
  void CDSConfig::initialize() {
!   if (is_dumping_static_archive()) {
-     if (RequireSharedSpaces) {
-       warning("Cannot dump shared archive while using shared archive");
-     }
      UseSharedSpaces = false;
    }
  
    // Initialize shared archive paths which could include both base and dynamic archive paths
    // This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly.
--- 23,55 ---
   */
  
  #include "precompiled.hpp"
  #include "cds/archiveHeapLoader.hpp"
  #include "cds/cdsConfig.hpp"
+ #include "cds/cds_globals.hpp"
  #include "cds/classListWriter.hpp"
  #include "cds/heapShared.hpp"
+ #include "cds/metaspaceShared.hpp"
  #include "classfile/classLoaderDataShared.hpp"
  #include "classfile/moduleEntry.hpp"
+ #include "classfile/systemDictionaryShared.hpp"
  #include "include/jvm_io.h"
  #include "logging/log.hpp"
+ #include "prims/jvmtiExport.hpp"
  #include "memory/universe.hpp"
  #include "runtime/arguments.hpp"
+ #include "runtime/globals_extension.hpp"
  #include "runtime/java.hpp"
  #include "utilities/defaultStream.hpp"
  
  bool CDSConfig::_is_dumping_static_archive = false;
  bool CDSConfig::_is_dumping_dynamic_archive = false;
  bool CDSConfig::_is_using_optimized_module_handling = true;
  bool CDSConfig::_is_dumping_full_module_graph = true;
  bool CDSConfig::_is_using_full_module_graph = true;
+ bool CDSConfig::_has_preloaded_classes = false;
+ bool CDSConfig::_is_loading_invokedynamic = false;
+ bool CDSConfig::_is_loading_packages = false;
+ bool CDSConfig::_is_loading_protection_domains = false;
+ bool CDSConfig::_is_security_manager_allowed = false;
  
  char* CDSConfig::_default_archive_path = nullptr;
  char* CDSConfig::_static_archive_path = nullptr;
  char* CDSConfig::_dynamic_archive_path = nullptr;
  
  int CDSConfig::get_status() {
    assert(Universe::is_fully_initialized(), "status is finalized only after Universe is initialized");
    return (is_dumping_archive()              ? IS_DUMPING_ARCHIVE : 0) |
           (is_dumping_static_archive()       ? IS_DUMPING_STATIC_ARCHIVE : 0) |
           (is_logging_lambda_form_invokers() ? IS_LOGGING_LAMBDA_FORM_INVOKERS : 0) |
!          (is_using_archive()                ? IS_USING_ARCHIVE : 0) |
+          (is_dumping_heap()                 ? IS_DUMPING_HEAP : 0) |
+          (is_tracing_dynamic_proxy()        ? IS_LOGGING_DYNAMIC_PROXIES : 0) |
+          (is_dumping_packages()             ? IS_DUMPING_PACKAGES : 0) |
+          (is_dumping_protection_domains()   ? IS_DUMPING_PROTECTION_DOMAINS : 0);
  }
  
  void CDSConfig::initialize() {
!   if (is_dumping_static_archive() && !is_dumping_final_static_archive()) {
      UseSharedSpaces = false;
    }
  
    // Initialize shared archive paths which could include both base and dynamic archive paths
    // This must be after set_ergonomics_flags() called so flag UseCompressedOops is set properly.

*** 132,10 ***
--- 142,17 ---
    cur_path = NEW_C_HEAP_ARRAY(char, len + 1, mtInternal);
    strncpy(cur_path, begin_ptr, len + 1);
    *top_archive_path = cur_path;
  }
  
+ static void set_new_workflow_default_CachedCodeFile() {
+   size_t len = strlen(CacheDataStore) + 6;
+   char* file = AllocateHeap(len, mtArguments);
+   jio_snprintf(file, len, "%s.code", CacheDataStore);
+   FLAG_SET_ERGO(CachedCodeFile, file);
+ }
+ 
  void CDSConfig::init_shared_archive_paths() {
    if (ArchiveClassesAtExit != nullptr) {
      assert(!RecordDynamicDumpInfo, "already checked");
      if (is_dumping_static_archive()) {
        vm_exit_during_initialization("-XX:ArchiveClassesAtExit cannot be used with -Xshare:dump");

*** 157,10 ***
--- 174,14 ---
      if (is_dumping_archive() && archives > 1) {
        vm_exit_during_initialization(
          "Cannot have more than 1 archive file specified in -XX:SharedArchiveFile during CDS dumping");
      }
  
+     if (CDSPreimage != nullptr && archives > 1) {
+       vm_exit_during_initialization("CDSPreimage must point to a single file", CDSPreimage);
+     }
+ 
      if (is_dumping_static_archive()) {
        assert(archives == 1, "must be");
        // Static dump is simple: only one archive is allowed in SharedArchiveFile. This file
        // will be overwritten no matter regardless of its contents
        _static_archive_path = os::strdup_check_oom(SharedArchiveFile, mtArguments);

*** 181,10 ***
--- 202,14 ---
        if (archives == 1) {
          char* base_archive_path = nullptr;
          bool success =
            FileMapInfo::get_base_archive_name_from_header(SharedArchiveFile, &base_archive_path);
          if (!success) {
+           if (CDSPreimage != nullptr) {
+             vm_exit_during_initialization("Unable to map shared spaces from CDSPreimage", CDSPreimage);
+           }
+ 
            // If +AutoCreateSharedArchive and the specified shared archive does not exist,
            // regenerate the dynamic archive base on default archive.
            if (AutoCreateSharedArchive && !os::file_exists(SharedArchiveFile)) {
              enable_dumping_dynamic_archive();
              ArchiveClassesAtExit = const_cast<char *>(SharedArchiveFile);

*** 256,10 ***
--- 281,16 ---
        log_info(cds)("full module graph: disabled due to incompatible property: %s=%s", key, value);
        break;
      }
    }
  
+   // Match the logic in java/lang/System.java, but we need to know this before the System class is initialized.
+   if (strcmp(key, "java.security.manager") == 0) {
+     if (strcmp(value, "disallowed") != 0) {
+       _is_security_manager_allowed = true;
+     }
+   }
  }
  
  // Returns any JVM command-line option, such as "--patch-module", that's not supported by CDS.
  static const char* find_any_unsupported_module_option() {
    // Note that arguments.cpp has translated the command-line options into properties. If we find an

*** 323,13 ***
      return true;
    }
    return false;
  }
  
! bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line) {
    if (is_dumping_static_archive()) {
!     if (!mode_flag_cmd_line) {
        // By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive.
        //
        // If your classlist is large and you don't care about deterministic dumping, you can use
        // -Xshare:dump -Xmixed to improve dumping speed.
        Arguments::set_mode_flags(Arguments::_int);
--- 354,146 ---
      return true;
    }
    return false;
  }
  
! bool CDSConfig::check_vm_args_consistency(bool patch_mod_javabase, bool mode_flag_cmd_line, bool xshare_auto_cmd_line) {
+   if (CacheDataStore != nullptr) {
+     // Leyden temp work-around:
+     //
+     // By default, when using CacheDataStore, use the HeapBasedNarrowOop mode so that
+     // AOT code can be always work regardless of runtime heap range.
+     //
+     // If you are *absolutely sure* that the CompressedOops::mode() will be the same
+     // between training and production runs (e.g., if you specify -Xmx128m
+     // for both training and production runs, and you know the OS will always reserve
+     // the heap under 4GB), you can explicitly disable this with:
+     //     java -XX:-UseCompatibleCompressedOops -XX:CacheDataStore=...
+     // However, this is risky and there's a chance that the production run will be slower
+     // because it is unable to load the AOT code cache.
+     FLAG_SET_ERGO_IF_DEFAULT(UseCompatibleCompressedOops, true);
+ 
+     // Leyden temp: make sure the user knows if CDS archive somehow fails to load.
+     if (UseSharedSpaces && !xshare_auto_cmd_line) {
+       log_info(cds)("Enabled -Xshare:on by default for troubleshooting Leyden prototype");
+       RequireSharedSpaces = true;
+     }
+ 
+     if (FLAG_IS_DEFAULT(PreloadSharedClasses)) {
+       // New workflow - enable PreloadSharedClasses by default.
+       // TODO: make new workflow work, even when PreloadSharedClasses is false.
+       //
+       // NOTE: in old workflow, we cannot enable PreloadSharedClasses by default. That
+       // should be an opt-in option, per JEP nnn.
+       FLAG_SET_ERGO(PreloadSharedClasses, true);
+     }
+ 
+     if (SharedArchiveFile != nullptr) {
+       vm_exit_during_initialization("CacheDataStore and SharedArchiveFile cannot be both specified");
+     }
+     if (!PreloadSharedClasses) {
+       // TODO: in the forked JVM, we should ensure all classes are loaded from the hotspot.cds.preimage.
+       // PreloadSharedClasses only loads the classes for built-in loaders. We need to load the classes
+       // for custom loaders as well.
+       vm_exit_during_initialization("CacheDataStore requires PreloadSharedClasses");
+     }
+ 
+     if (CDSPreimage == nullptr) {
+       if (os::file_exists(CacheDataStore) /* && TODO: CDS file is valid*/) {
+         // The CacheDataStore is already up to date. Use it. Also turn on cached code by default.
+         SharedArchiveFile = CacheDataStore;
+         FLAG_SET_ERGO_IF_DEFAULT(ReplayTraining, true);
+         FLAG_SET_ERGO_IF_DEFAULT(LoadCachedCode, true);
+         if (LoadCachedCode && FLAG_IS_DEFAULT(CachedCodeFile)) {
+           set_new_workflow_default_CachedCodeFile();
+         }
+       } else {
+         // The preimage dumping phase -- run the app and write the preimage file
+         size_t len = strlen(CacheDataStore) + 10;
+         char* preimage = AllocateHeap(len, mtArguments);
+         jio_snprintf(preimage, len, "%s.preimage", CacheDataStore);
+ 
+         UseSharedSpaces = false;
+         enable_dumping_static_archive();
+         SharedArchiveFile = preimage;
+         log_info(cds)("CacheDataStore needs to be updated. Writing %s file", SharedArchiveFile);
+ 
+         // At VM exit, the module graph may be contaminated with program states. We should rebuild the
+         // module graph when dumping the CDS final image.
+         log_info(cds)("full module graph: disabled when writing CDS preimage");
+         HeapShared::disable_writing();
+         stop_dumping_full_module_graph();
+         FLAG_SET_ERGO(ArchivePackages, false);
+         FLAG_SET_ERGO(ArchiveProtectionDomains, false);
+ 
+         FLAG_SET_ERGO_IF_DEFAULT(RecordTraining, true);
+       }
+     } else {
+       // The final image dumping phase -- load the preimage and write the final image file
+       SharedArchiveFile = CDSPreimage;
+       UseSharedSpaces = true;
+       log_info(cds)("Generate CacheDataStore %s from CDSPreimage %s", CacheDataStore, CDSPreimage);
+       // Force -Xbatch for AOT compilation.
+       if (FLAG_SET_CMDLINE(BackgroundCompilation, false) != JVMFlag::SUCCESS) {
+         return false;
+       }
+       RecordTraining = false; // This will be updated inside MetaspaceShared::preload_and_dump()
+ 
+       FLAG_SET_ERGO_IF_DEFAULT(ReplayTraining, true);
+       // Settings for AOT
+       FLAG_SET_ERGO_IF_DEFAULT(StoreCachedCode, true);
+       if (StoreCachedCode && FLAG_IS_DEFAULT(CachedCodeFile)) {
+         set_new_workflow_default_CachedCodeFile();
+         // Cannot dump cached code until metadata and heap are dumped.
+         disable_dumping_cached_code();
+       }
+     }
+   } else {
+     // Old workflow
+     if (CDSPreimage != nullptr) {
+       vm_exit_during_initialization("CDSPreimage must be specified only when CacheDataStore is specified");
+     }
+   }
+ 
+   if (FLAG_IS_DEFAULT(UsePermanentHeapObjects)) {
+     if (StoreCachedCode || PreloadSharedClasses) {
+       FLAG_SET_ERGO(UsePermanentHeapObjects, true);
+     }
+   }
+ 
+   if (LoadCachedCode) {
+     // This must be true. Cached code is hard-wired to use permanent objects.
+     UsePermanentHeapObjects = true;
+   }
+ 
+   if (PreloadSharedClasses) {
+     // If PreloadSharedClasses is specified, enable all these optimizations by default.
+     FLAG_SET_ERGO_IF_DEFAULT(ArchiveDynamicProxies, true);
+     FLAG_SET_ERGO_IF_DEFAULT(ArchiveFieldReferences, true);
+     FLAG_SET_ERGO_IF_DEFAULT(ArchiveInvokeDynamic, true);
+     FLAG_SET_ERGO_IF_DEFAULT(ArchiveLoaderLookupCache, true);
+     FLAG_SET_ERGO_IF_DEFAULT(ArchiveMethodReferences, true);
+     FLAG_SET_ERGO_IF_DEFAULT(ArchivePackages, true);
+     FLAG_SET_ERGO_IF_DEFAULT(ArchiveProtectionDomains, true);
+     FLAG_SET_ERGO_IF_DEFAULT(ArchiveReflectionData, true);
+   } else {
+     // All of these *might* depend on PreloadSharedClasses. Better be safe than sorry.
+     // TODO: more fine-grained handling.
+     FLAG_SET_ERGO(ArchiveDynamicProxies, false);
+     FLAG_SET_ERGO(ArchiveFieldReferences, false);
+     FLAG_SET_ERGO(ArchiveInvokeDynamic, false);
+     FLAG_SET_ERGO(ArchiveLoaderLookupCache, false);
+     FLAG_SET_ERGO(ArchiveMethodReferences, false);
+     FLAG_SET_ERGO(ArchivePackages, false);
+     FLAG_SET_ERGO(ArchiveProtectionDomains, false);
+     FLAG_SET_ERGO(ArchiveReflectionData, false);
+   }
+ 
    if (is_dumping_static_archive()) {
!     if (is_dumping_preimage_static_archive() || is_dumping_final_static_archive()) {
+       // Don't tweak execution mode
+     } else if (!mode_flag_cmd_line) {
        // By default, -Xshare:dump runs in interpreter-only mode, which is required for deterministic archive.
        //
        // If your classlist is large and you don't care about deterministic dumping, you can use
        // -Xshare:dump -Xmixed to improve dumping speed.
        Arguments::set_mode_flags(Arguments::_int);

*** 342,10 ***
--- 506,12 ---
  
      // String deduplication may cause CDS to iterate the strings in different order from one
      // run to another which resulting in non-determinstic CDS archives.
      // Disable UseStringDeduplication while dumping CDS archive.
      UseStringDeduplication = false;
+ 
+     Arguments::PropertyList_add(new SystemProperty("java.lang.invoke.MethodHandle.NO_SOFT_CACHE", "true", false));
    }
  
    // RecordDynamicDumpInfo is not compatible with ArchiveClassesAtExit
    if (ArchiveClassesAtExit != nullptr && RecordDynamicDumpInfo) {
      jio_fprintf(defaultStream::output_stream(),

*** 385,29 ***
      }
    }
  
    return true;
  }
  
  bool CDSConfig::is_using_archive() {
    return UseSharedSpaces;
  }
  
  bool CDSConfig::is_logging_lambda_form_invokers() {
!   return ClassListWriter::is_enabled() || is_dumping_dynamic_archive();
  }
  
  void CDSConfig::stop_using_optimized_module_handling() {
    _is_using_optimized_module_handling = false;
    _is_dumping_full_module_graph = false; // This requires is_using_optimized_module_handling()
    _is_using_full_module_graph = false; // This requires is_using_optimized_module_handling()
  }
  
  #if INCLUDE_CDS_JAVA_HEAP
  bool CDSConfig::is_dumping_heap() {
!   // heap dump is not supported in dynamic dump
!   return is_dumping_static_archive() && HeapShared::can_write();
  }
  
  bool CDSConfig::is_using_full_module_graph() {
    if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
      return true;
--- 551,74 ---
      }
    }
  
    return true;
  }
+ bool CDSConfig::is_dumping_classic_static_archive() {
+   return _is_dumping_static_archive && CacheDataStore == nullptr && CDSPreimage == nullptr;
+ }
+ 
+ bool CDSConfig::is_dumping_preimage_static_archive() {
+   return _is_dumping_static_archive && CacheDataStore != nullptr && CDSPreimage == nullptr;
+ }
+ 
+ bool CDSConfig::is_dumping_final_static_archive() {
+   if (CDSPreimage != nullptr) {
+     assert(CacheDataStore != nullptr, "must be"); // should have been properly initialized by arguments.cpp
+   }
+ 
+   // Note: _is_dumping_static_archive is false! // FIXME -- refactor this so it makes more sense!
+   return CacheDataStore != nullptr && CDSPreimage != nullptr;
+ }
+ 
+ bool CDSConfig::is_dumping_regenerated_lambdaform_invokers() {
+   if (is_dumping_final_static_archive()) {
+     // Not yet supported in new workflow -- the training data may point
+     // to a method in a lambdaform holder class that was not regenerated
+     // due to JDK-8318064.
+     return false;
+   } else {
+     return is_dumping_archive();
+   }
+ }
+ 
+ bool CDSConfig::is_tracing_dynamic_proxy() {
+   return ClassListWriter::is_enabled() || is_dumping_preimage_static_archive();
+ }
+ 
+ // Preserve all states that were examined used during dumptime verification, such
+ // that the verification result (pass or fail) cannot be changed at runtime.
+ //
+ // For example, if the verification of ik requires that class A must be a subtype of B,
+ // then this relationship between A and B cannot be changed at runtime. I.e., the app
+ // cannot load alternative versions of A and B such that A is not a subtype of B.
+ bool CDSConfig::preserve_all_dumptime_verification_states(const InstanceKlass* ik) {
+   return PreloadSharedClasses && SystemDictionaryShared::is_builtin(ik);
+ }
  
  bool CDSConfig::is_using_archive() {
    return UseSharedSpaces;
  }
  
  bool CDSConfig::is_logging_lambda_form_invokers() {
!   return ClassListWriter::is_enabled() || is_dumping_dynamic_archive() || is_dumping_preimage_static_archive();
  }
  
  void CDSConfig::stop_using_optimized_module_handling() {
    _is_using_optimized_module_handling = false;
    _is_dumping_full_module_graph = false; // This requires is_using_optimized_module_handling()
    _is_using_full_module_graph = false; // This requires is_using_optimized_module_handling()
  }
  
  #if INCLUDE_CDS_JAVA_HEAP
  bool CDSConfig::is_dumping_heap() {
!   return is_dumping_static_archive() && !is_dumping_preimage_static_archive()
!     && HeapShared::can_write();
+ }
+ 
+ bool CDSConfig::is_loading_heap() {
+   return ArchiveHeapLoader::is_in_use();
  }
  
  bool CDSConfig::is_using_full_module_graph() {
    if (ClassLoaderDataShared::is_full_module_graph_loaded()) {
      return true;

*** 444,6 ***
--- 655,72 ---
      if (reason != nullptr) {
        log_info(cds)("full module graph cannot be loaded: %s", reason);
      }
    }
  }
+ 
+ bool CDSConfig::is_loading_invokedynamic() {
+   return UseSharedSpaces && is_loading_heap() && _is_loading_invokedynamic;
+ }
+ 
+ bool CDSConfig::is_dumping_dynamic_proxy() {
+   return is_dumping_full_module_graph() && is_dumping_invokedynamic();
+ }
+ 
+ bool CDSConfig::is_initing_classes_at_dump_time() {
+   return is_dumping_heap() && PreloadSharedClasses;
+ }
+ 
+ bool CDSConfig::is_dumping_invokedynamic() {
+   // Requires PreloadSharedClasses, or else the classes of some archived heap
+   // objects used by the archive indy callsites may be replaced at runtime.
+   return ArchiveInvokeDynamic && PreloadSharedClasses && is_dumping_heap();
+ }
+ 
+ bool CDSConfig::is_dumping_packages() {
+   return ArchivePackages && is_dumping_heap();
+ }
+ 
+ bool CDSConfig::is_loading_packages() {
+   return UseSharedSpaces && is_loading_heap() && _is_loading_packages;
+ }
+ 
+ bool CDSConfig::is_dumping_protection_domains() {
+   if (_is_security_manager_allowed) {
+     // For sanity, don't archive PDs. TODO: can this be relaxed?
+     return false;
+   }
+   // Archived PDs for the modules will reference their java.lang.Module, which must
+   // also be archived.
+   return ArchiveProtectionDomains && is_dumping_full_module_graph();
+ }
+ 
+ bool CDSConfig::is_loading_protection_domains() {
+   if (_is_security_manager_allowed) {
+     // For sanity, don't used any archived PDs. TODO: can this be relaxed?
+     return false;
+   }
+   return UseSharedSpaces && is_using_full_module_graph() && _is_loading_protection_domains;
+ }
+ 
+ bool CDSConfig::is_dumping_reflection_data() {
+   // reflection data use LambdaForm classes
+   return ArchiveReflectionData && is_dumping_invokedynamic();
+ }
+ 
  #endif // INCLUDE_CDS_JAVA_HEAP
+ 
+ // This is allowed by default. We disable it only in the final image dump before the
+ // metadata and heap are dumped.
+ static bool _is_dumping_cached_code = true;
+ 
+ bool CDSConfig::is_dumping_cached_code() {
+   return _is_dumping_cached_code;
+ }
+ 
+ void CDSConfig::disable_dumping_cached_code() {
+   _is_dumping_cached_code = false;
+ }
+ 
+ void CDSConfig::enable_dumping_cached_code() {
+   _is_dumping_cached_code = true;
+ }
< prev index next >