< prev index next > src/hotspot/share/cds/metaspaceShared.cpp
Print this page
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
+ #include "cds/aotCacheAccess.hpp"
+ #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 "classfile/systemDictionaryShared.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/aotCodeCache.hpp"
#include "code/codeCache.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 "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/safepointVerifiers.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/vmOperations.hpp"
#include "runtime/vmThread.hpp"
#include "sanitizers/leak.hpp"
+ #include "services/management.hpp"
#include "utilities/align.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
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;
+ jlong MetaspaceShared::_preimage_static_archive_recording_duration = 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
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");
+ }
+ }
+
aot_log_info(aot)("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();
};
// 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;
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;
}
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::preresolve_string_cp_entries(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);
// 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);
+ 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);
- }
+ 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())) {
aot_log_error(aot)("%s: %s", PENDING_EXCEPTION->klass()->external_name(),
message == nullptr ? "(null)" : java_lang_String::as_utf8_string(message));
MetaspaceShared::writing_error(err_msg("Unexpected exception, use -Xlog:aot%s,exceptions=trace for detail",
CDSConfig::new_aot_flags_used() ? "" : ",cds"));
}
+ 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,
// 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;
+ }
+
+ jlong MetaspaceShared::get_preimage_static_archive_recording_duration() {
+ if (CDSConfig::is_dumping_preimage_static_archive()) {
+ if (_preimage_static_archive_recording_duration == 0) {
+ // The recording has not yet finished so return the current elapsed time.
+ return Management::ticks_to_ms(os::elapsed_counter());
+ }
+ return _preimage_static_archive_recording_duration;
+ }
+ return 0;
+ }
+
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;
+ }
+ _preimage_static_archive_recording_duration = Management::ticks_to_ms(os::elapsed_counter());
+ }
+
if (CDSConfig::is_dumping_classic_static_archive()) {
// We are running with -Xshare:dump
preload_classes(CHECK);
if (SharedArchiveConfigFile) {
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);
+ }
+
AOTReferenceObjSupport::initialize(CHECK);
AOTReferenceObjSupport::stabilize_cached_reference_objects(CHECK);
if (CDSConfig::is_initing_classes_at_dump_time()) {
// java.lang.Class::reflectionFactory cannot be archived yet. We set this field
}
#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()) {
+ if (AOTCodeCache::is_caching_enabled()) {
+ if (log_is_enabled(Info, cds, jit)) {
+ AOTCacheAccess::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);
+ }
- if (AOTCodeCache::is_on_for_dump() && CDSConfig::is_dumping_final_static_archive()) {
- CDSConfig::enable_dumping_aot_code();
- {
- builder.start_ac_region();
- // Write the contents to AOT code region and close AOTCodeCache before packing the region
- AOTCodeCache::close();
- builder.end_ac_region();
+ CDSConfig::enable_dumping_aot_code();
+ {
+ builder.start_ac_region();
+ if (AOTCodeCache::is_dumping_code()) {
+ Precompiler::compile_cached_code(&builder, CHECK);
+ }
+ // Write the contents to aot code region and close AOTCodeCache before packing the region
+ AOTCodeCache::close();
+ builder.end_ac_region();
+ }
+ CDSConfig::disable_dumping_aot_code();
}
- CDSConfig::disable_dumping_aot_code();
}
- bool status = write_static_archive(&builder, op.map_info(), op.heap_info());
+ bool status = write_static_archive(&builder, mapinfo, heap_info);
if (status && CDSConfig::is_dumping_preimage_static_archive()) {
- tty->print_cr("%s AOTConfiguration recorded: %s",
- CDSConfig::has_temp_aot_config_file() ? "Temporary" : "", AOTConfiguration);
- if (CDSConfig::is_single_command_training()) {
- fork_and_dump_final_static_archive(CHECK);
+ 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_single_command_training()) {
+ fork_and_dump_final_static_archive(CHECK);
+ }
}
}
if (!status) {
THROW_MSG(vmSymbols::java_io_IOException(), "Encountered error while dumping");
// Note: because we are running in AOTMode=record, JDK_AOT_VM_OPTIONS have not been
// parsed, so they are not in Arguments::jvm_args_array. If JDK_AOT_VM_OPTIONS is in
// the environment, it will be inherited and parsed by the child JVM process
// in Arguments::parse_java_tool_options_environment_variable().
- precond(strcmp(AOTMode, "record") == 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 {
+
+ precond(strcmp(AOTMode, "record") == 0);
+
+ {
// If AOTCacheOutput contains %p, it should have been already substituted with the
// pid of the training process.
stringStream ss;
ss.print("-XX:AOTCacheOutput=");
ss.print_raw(AOTCacheOutput);
append_args(&args, ss.freeze(), CHECK_0);
- }
- {
+ }
+ {
// If AOTCacheConfiguration contains %p, it should have been already substituted with the
// pid of the training process.
// If AOTCacheConfiguration was not explicitly specified, it should have been assigned a
// temporary file name.
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);
+ append_args(&args, "-XX:AOTMode=create", 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");
&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;
}
void VM_PopulateDumpSharedSpace::dump_java_heap_objects() {
if (CDSConfig::is_dumping_heap()) {
HeapShared::write_heap(&_heap_info);
- } else {
+ } 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) {
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* static_mapinfo = FileMapInfo::current_info();
FileMapInfo* dynamic_mapinfo = nullptr;
if (static_mapinfo != nullptr) {
aot_log_info(aot)("Core region alignment: %zu", static_mapinfo->core_region_alignment());
dynamic_mapinfo = open_dynamic_archive();
// The base archive cannot be mapped. We cannot dump the dynamic shared archive.
AutoCreateSharedArchive = false;
CDSConfig::disable_dumping_dynamic_archive();
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();
} else {
- if (RequireSharedSpaces) {
- MetaspaceShared::unrecoverable_loading_error("Unable to map shared spaces");
- } else {
- report_loading_error("Unable to map shared spaces");
- }
+ report_loading_error("Unable to map shared spaces");
}
}
// If mapping failed and -XShare:on, the vm should exit
bool has_failed = false;
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");
}
}
- FileMapInfo* MetaspaceShared::open_static_archive() {
+ // 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);
- return nullptr;
+ } else {
+ FileMapRegion* r = mapinfo->region_at(MetaspaceShared::ac);
+ AOTCacheAccess::set_aot_code_region_size(r->used_aligned());
}
- return mapinfo;
}
FileMapInfo* MetaspaceShared::open_dynamic_archive() {
if (CDSConfig::is_dumping_dynamic_archive()) {
return nullptr;
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()) {
report_loading_error("Unable to map CDS archive -- core_region_alignment() expected: %zu"
" actual: %zu", mapinfo->core_region_alignment(), core_region_alignment());
return MAP_ARCHIVE_OTHER_FAILURE;
< prev index next >